Android Audio Architecture

Android Audio Architecture

Android Audio Framework Architecture

Android Audio框架介紹

Android Audio System(1):Linux && Android Audio 系統(tǒng)框架

音頻基礎(chǔ)知識(shí)

聲音有哪些重要屬性呢涤垫?

1. 響度(Loudness)
響度就是人類可以感知到的各種聲音的大小,也就是音量竟终。響度與聲波的振幅有直接關(guān)系蝠猬。

2. 音調(diào)(Pitch)
音調(diào)與聲音的頻率有關(guān)系,當(dāng)聲音的頻率越大時(shí)统捶,人耳所感知到的音調(diào)就越高榆芦,否則就越低柄粹。

3. 音色(Quality)
同一種樂(lè)器,使用不同的材質(zhì)來(lái)制作匆绣,所表現(xiàn)出來(lái)的音色效果是不一樣的驻右,這是由物體本身的結(jié)構(gòu)特性所決定的。

如何將各種媒體源數(shù)字化呢崎淳?

image

音頻采樣

將聲波波形信號(hào)通過(guò)ADC轉(zhuǎn)換成計(jì)算機(jī)支持的二進(jìn)制的過(guò)程叫做音頻采樣(Audio Sampling)堪夭。采樣(Sampling)的核心是把連續(xù)的模擬信號(hào)轉(zhuǎn)換成離散的數(shù)字信號(hào)。

圖一:

image

圖二:

image

樣本(Sample)

這是我們進(jìn)行采樣的初始資料拣凹,比如一段連續(xù)的聲音波形森爽。

  • 聲道數(shù)(channels)

由于音頻的采集和播放是可以疊加的,因此咐鹤,可以同時(shí)從多個(gè)音頻源采集聲音拗秘,并分別輸出到不同的揚(yáng)聲器,故聲道數(shù)一般表示聲音錄制時(shí)的音源數(shù)量或回放時(shí)相應(yīng)的揚(yáng)聲器數(shù)量祈惶。

單聲道(Mono)和雙聲道(Stereo)比較常見(jiàn)雕旨,顧名思義,前者的聲道數(shù)為1捧请,后者為2

  • 音頻幀(frame)

這個(gè)概念在應(yīng)用開(kāi)發(fā)中非常重要凡涩,網(wǎng)上很多文章都沒(méi)有專門介紹這個(gè)概念。

音頻跟視頻很不一樣疹蛉,視頻每一幀就是一張圖像活箕,而從上面的正玄波可以看出,音頻數(shù)據(jù)是流式的可款,本身沒(méi)有明確的一幀幀的概念育韩,在實(shí)際的應(yīng)用中,為了音頻算法處理/傳輸?shù)姆奖愎刖ǎ话慵s定俗成取2.5ms~60ms為單位的數(shù)據(jù)量為一幀音頻筋讨。(視頻和音頻應(yīng)該差不多吧?摸恍?悉罕?)

這個(gè)時(shí)間被稱之為“采樣時(shí)間”,其長(zhǎng)度沒(méi)有特別的標(biāo)準(zhǔn)立镶,它是根據(jù)編解碼器和具體應(yīng)用的需求來(lái)決定的壁袄,我們可以計(jì)算一下一幀音頻幀的大小:

假設(shè)某音頻信號(hào)是采樣率為8kHz媚媒、雙通道嗜逻、位寬為16bit,20ms一幀缭召,則一幀音頻數(shù)據(jù)的大小為:

int size = 8000 x 2 x 16bit x 0.02s = 5120 bit = 640 byte

采樣器(Sampler)

采樣器是將樣本轉(zhuǎn)換成終態(tài)信號(hào)的關(guān)鍵变泄。它可以是一個(gè)子系統(tǒng)令哟,也可以指一個(gè)操作過(guò)程,甚至是一個(gè)算法妨蛹,取決于不同的信號(hào)處理場(chǎng)景屏富。理想的采樣器要求盡可能不產(chǎn)生信號(hào)失真。

  • 采樣率(samplerate)

采樣就是把模擬信號(hào)數(shù)字化的過(guò)程蛙卤,不僅僅是音頻需要采樣狠半,所有的模擬信號(hào)都需要通過(guò)采樣轉(zhuǎn)換為可以用0101來(lái)表示的數(shù)字信號(hào),示意圖如下所示:

圖三:

image

藍(lán)色代表模擬音頻信號(hào)颤难,紅色的點(diǎn)代表采樣得到的量化數(shù)值神年。

采樣頻率越高,紅色的間隔就越密集行嗤,記錄這一段音頻信號(hào)所用的數(shù)據(jù)量就越大已日,同時(shí)音頻質(zhì)量也就越高。

根據(jù)奈奎斯特理論栅屏,采樣頻率只要不低于音頻信號(hào)最高頻率的兩倍飘千,就可以無(wú)損失地還原原始的聲音。

通常人耳能聽(tīng)到頻率范圍大約在20Hz~20kHz之間的聲音栈雳,為了保證聲音不失真护奈,采樣頻率應(yīng)在40kHz以上。常用的音頻采樣頻率有:8kHz哥纫、11.025kHz霉旗、22.05kHz、16kHz蛀骇、37.8kHz厌秒、44.1kHz、48kHz擅憔、96kHz鸵闪、192kHz等。

  • 奈奎斯特采樣理論

“當(dāng)對(duì)被采樣的模擬信號(hào)進(jìn)行還原時(shí)雕欺,其最高頻率只有采樣頻率的一半”岛马。
換句話說(shuō)棉姐,如果我們要完整重構(gòu)原始的模擬信號(hào)屠列,則采樣頻率就必須是它的兩倍以上。

比如人的聲音范圍是2~ 20kHZ,那么選擇的采樣頻率就應(yīng)該在40kHZ左右伞矩,數(shù)值太小則聲音將產(chǎn)生失真現(xiàn)象笛洛,而數(shù)值太大也無(wú)法明顯提升人耳所能感知的音質(zhì)。

量化(Quantization)

采樣后的值還需要通過(guò)量化乃坤,也就是將連續(xù)值近似為某個(gè)范圍內(nèi)有限多個(gè)離散值的處理過(guò)程苛让。因?yàn)樵紨?shù)據(jù)是模擬的連續(xù)信號(hào)沟蔑,而數(shù)字信號(hào)則是離散的,它的表達(dá)范圍是有限的狱杰,所以量化是必不可少的一個(gè)步驟瘦材。

  • 量化精度(位寬)

上圖三中,每一個(gè)紅色的采樣點(diǎn)仿畸,都需要用一個(gè)數(shù)值來(lái)表示大小食棕,這個(gè)數(shù)值的數(shù)據(jù)類型大小可以是:4bit、8bit错沽、16bit簿晓、32bit等等,位數(shù)越多千埃,表示得就越精細(xì)憔儿,聲音質(zhì)量自然就越好,當(dāng)然放可,數(shù)據(jù)量也會(huì)成倍增大谒臼。

常見(jiàn)的位寬是:8bit 或者 16bit

編碼(Coding)

計(jì)算機(jī)的世界里,所有數(shù)值都是用二進(jìn)制表示的吴侦,因而我們還需要把量化值進(jìn)行二進(jìn)制編碼屋休。這一步通常與量化同時(shí)進(jìn)行备韧。

  • 常見(jiàn)的音頻編碼方式有哪些劫樟?

上面提到過(guò),模擬的音頻信號(hào)轉(zhuǎn)換為數(shù)字信號(hào)需要經(jīng)過(guò)采樣和量化织堂,量化的過(guò)程被稱之為編碼叠艳,根據(jù)不同的量化策略,產(chǎn)生了許多不同的編碼方式易阳,常見(jiàn)的編碼方式有:PCM 和 ADPCM附较,這些數(shù)據(jù)代表著無(wú)損的原始數(shù)字音頻信號(hào),添加一些文件頭信息潦俺,就可以存儲(chǔ)為WAV文件了拒课,它是一種由微軟和IBM聯(lián)合開(kāi)發(fā)的用于音頻數(shù)字存儲(chǔ)的標(biāo)準(zhǔn),可以很容易地被解析和播放事示。

我們?cè)谝纛l開(kāi)發(fā)過(guò)程中早像,會(huì)經(jīng)常涉及到WAV文件的讀寫,以驗(yàn)證采集肖爵、傳輸卢鹦、接收的音頻數(shù)據(jù)的正確性。

  • 常見(jiàn)的音頻壓縮格式有哪些劝堪?

首先簡(jiǎn)單介紹一下音頻數(shù)據(jù)壓縮的最基本的原理:因?yàn)橛腥哂嘈畔⒓阶裕钥梢詨嚎s揉稚。

(1) 頻譜掩蔽效應(yīng): 人耳所能察覺(jué)的聲音信號(hào)的頻率范圍為20Hz~20KHz,在這個(gè)頻率范圍以外的音頻信號(hào)屬于冗余信號(hào)熬粗。

(2) 時(shí)域掩蔽效應(yīng): 當(dāng)強(qiáng)音信號(hào)和弱音信號(hào)同時(shí)出現(xiàn)時(shí)搀玖,弱信號(hào)會(huì)聽(tīng)不到,因此驻呐,弱音信號(hào)也屬于冗余信號(hào)巷怜。

下面簡(jiǎn)單列出常見(jiàn)的音頻壓縮格式:

MP3,AAC暴氏,OGG延塑,WMA,Opus答渔,F(xiàn)LAC关带,APE,M4A沼撕,AMR宋雏,等等

錄制過(guò)程

  1. 音頻采集設(shè)備(比如Microphone)捕獲聲音信息。
  2. 模擬信號(hào)通過(guò)模數(shù)轉(zhuǎn)換器(ADC)處理成計(jì)算機(jī)能接受的二進(jìn)制數(shù)據(jù)务豺。
  3. 根據(jù)需求進(jìn)行必要的渲染處理磨总,比如音效調(diào)整、過(guò)濾等等笼沥。
  4. 處理后的音頻數(shù)據(jù)理論上已經(jīng)可以存儲(chǔ)到計(jì)算機(jī)設(shè)備中了蚪燕,比如硬盤、USB設(shè)備等等奔浅。不過(guò)由于這時(shí)的音頻數(shù)據(jù)體積相對(duì)龐大馆纳,不利于保存和傳輸,通常還會(huì)對(duì)其進(jìn)行壓縮處理汹桦。比如我們常見(jiàn)的mp3音樂(lè)鲁驶,實(shí)際上就是對(duì)原始數(shù)據(jù)采用相應(yīng)的壓縮算法后得到的。壓縮過(guò)程根據(jù)采樣率舞骆、位深等因素的不同钥弯,最終得到的音頻文件可能會(huì)有一定程度的失真,另外督禽,音視頻的編解碼既可以由純軟件完成脆霎,也同樣可以借助于專門的硬件芯片來(lái)完成。

回放過(guò)程

  1. 從存儲(chǔ)設(shè)備中取出相關(guān)文件赂蠢,并根據(jù)錄制過(guò)程采用的編碼方式進(jìn)行相應(yīng)的解碼绪穆。
  2. 音頻系統(tǒng)為這一播放實(shí)例選定最終匹配的音頻回放設(shè)備辨泳。
  3. 解碼后的數(shù)據(jù)經(jīng)過(guò)音頻系統(tǒng)設(shè)計(jì)的路徑傳輸虱岂。
  4. 音頻數(shù)據(jù)信號(hào)通過(guò)數(shù)模轉(zhuǎn)換器(DAC)變換成模擬信號(hào)玖院。
  5. 模擬信號(hào)經(jīng)過(guò)回放設(shè)備,還原出原始聲音第岖。

總結(jié)(音頻處理和播放過(guò)程):

圖四:

image

Android Audio 系統(tǒng)架構(gòu)圖

圖一:

image

圖二:

[圖片上傳失敗...(image-5d41d5-1565571781143)]

圖二:

image

圖三:

[圖片上傳失敗...(image-244252-1565571781143)]

APP

音樂(lè)播放器軟件等等难菌。

Java Framework

frameworks/base/media/java/android/media

該層使用 android.media API提供的功能開(kāi)實(shí)現(xiàn)與audio硬件設(shè)備的交互

Android提供了兩個(gè)功能相似的類,即AudioTrack和AudioRecorder蔑滓,MediaPlayerService內(nèi)部的實(shí)現(xiàn)就是通過(guò)它們來(lái)完成的, 只不過(guò)MediaPlayer/MediaRecorder提供了更強(qiáng)大的控制功能郊酒,相比前者也更易于使用。

除此以外键袱,Android系統(tǒng)還為我們控制音頻系統(tǒng)提供了AudioManager燎窘、AudioService及AudioSystem類。這些都是framework為便利上層應(yīng)用開(kāi)發(fā)所設(shè)計(jì)的蹄咖。在內(nèi)部褐健,此代碼調(diào)用JNI層與Audio相關(guān)的native代碼來(lái)訪問(wèn)音頻硬件。

JNI

frameworks/base/core/jni
frameworks/base/media/jni

生成庫(kù)libandroid_runtime.so澜汤,Audio 的JNI是其中的一個(gè)部分

Libraries

framework只是向應(yīng)用程序提供訪問(wèn)Android庫(kù)的橋梁蚜迅,具體功能實(shí)現(xiàn)放在庫(kù)中完成。

比如上面的AudioTrack俊抵、AudioRecorder谁不、MediaPlayer和MediaRecorder等等在庫(kù)中都能找到相對(duì)應(yīng)的類。

1徽诲、frameworks/av/media/libmedia【libmedia.so】
2刹帕、frameworks/av/services/audioflinger【libaudioflinger.so】
3、frameworks/av/media/libmediaplayerservice【libmediaplayerservice.so】

+ Native framework

frameworks/base/include/media/
frameworks/base/media/libmedia/

提供了與android.media*包同樣的功能的底層實(shí)現(xiàn)谎替,該模塊使用Binder IPC代理來(lái)獲取media server與audio相關(guān)的具體服務(wù)

這部分內(nèi)容被編譯成庫(kù)libmedia.so轩拨,實(shí)現(xiàn)Audio系統(tǒng)的核心框架,同時(shí)提供了IAudioFlinger 類接口院喜。

在這個(gè)類中亡蓉,可以獲得IAudioTrack 和IAudioRecorder 兩個(gè)接口,分別用于聲音的播放和錄制喷舀。AudioTrack 和AudioRecorder 分別調(diào)用IAudioTrack 和IAudioRecorder 來(lái)實(shí)現(xiàn)砍濒。IAudioFlinger.hIAudioTrack.hIAudioRecorder.h這三個(gè)接口通過(guò)下層來(lái)實(shí)現(xiàn)硫麻。AudioSystem.h爸邢、AudioTrack.hAudioRecorder.h 是對(duì)上層提供的接口,它們既供本地程序調(diào)用拿愧,也可以通過(guò)JNI 向Java 層提供接口杠河。

從功能上看
AudioSystem負(fù)責(zé)的是Audio系統(tǒng)的綜合管理功能
AudioTrack 和AudioRecorder 分別負(fù)責(zé)音頻數(shù)據(jù)的輸出和輸入,即播放和錄制
另外一個(gè)接口是IAudioFlingerClient,它作為向IAudioFlinger中注冊(cè)的監(jiān)聽(tīng)器券敌,相當(dāng)于使用回調(diào)函數(shù)獲取IAudioFlinger運(yùn)行時(shí)信息唾戚。

+ Binder IPC

frameworks/av/media/libmedia

Binder IPC代理提供了不同進(jìn)程間的通信功能, 位于frameworks/av/media/libmedia, 以I字母開(kāi)頭

+ Android Audio Manager(Audio管理策略待诅,AudioPolicyService)

Audio policy service is a service responsible for all actions that require a policy decision to be made first, such as opening a new I/O audio stream, re-routing after a change, and stream volume management. This audio policy source code is located in the below path.

  • frameworks/av/services/audiopolicy

The main roles of audio policy service are,

  • keep track of current system state (removable device connections, phone state, user requests etc.,
  • System state changes and user actions are notified to audio policy manager with methods of the audio_policy.

This service loads the audio_policy.conf file from system/etc/ during start which is used to declare the audio devices present on your product. Below is an example of audio_policy.conf file with different supported devices.

global_configuration {
  attached_output_devices AUDIO_DEVICE_OUT_AUX_DIGITAL|AUDIO_DEVICE_OUT_SPEAKER
  default_output_device AUDIO_DEVICE_OUT_AUX_DIGITAL
  attached_input_devices AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_REMOTE_SUBMIX
}

audio_hw_modules {
  primary {
    outputs {
      primary {
        sampling_rates 48000
        channel_masks AUDIO_CHANNEL_OUT_STEREO
        formats AUDIO_FORMAT_PCM_16_BIT
        devices AUDIO_DEVICE_OUT_SPEAKER|AUDIO_DEVICE_OUT_WIRED_HEADSET|AUDIO_DEVICE_OUT_WIRED_HEADPHONE|AUDIO_DEVICE_OUT_AUX_DIGITAL|AUDIO_DEVICE_OUT_ALL_SCO
        flags AUDIO_OUTPUT_FLAG_PRIMARY
      }
      hdmi {
        sampling_rates dynamic
        channel_masks dynamic
        formats AUDIO_FORMAT_PCM_16_BIT
        devices AUDIO_DEVICE_OUT_AUX_DIGITAL
        flags AUDIO_OUTPUT_FLAG_DIRECT
      }
    }
    inputs {
      primary {
        sampling_rates 8000|11025|16000|22050|24000|32000|44100|48000
        channel_masks AUDIO_CHANNEL_IN_MONO|AUDIO_CHANNEL_IN_STEREO
        formats AUDIO_FORMAT_PCM_16_BIT
        devices AUDIO_DEVICE_IN_USB_DEVICE|AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_ALL_SCO
      }
    }
  }
}

From Android 7.0, ASOP introduces a new audio policy configuration file format (XML) for describing the audio topology. Refer this link audio_config.xml file for example XML format config file. Note: Android 7.0 preserves support for using audio_policy.conf; this legacy format is used by default. To use the XML file format, include the build option USE_XML_AUDIO_POLICY_CONF := 1 in device makefile.

+ Media Server & The Audio Flinger

frameworks/av/servers/audioflinger

media server里面包含audio services, 這里包含與HAL層實(shí)現(xiàn)實(shí)際交互的代碼叹坦, 這部分內(nèi)容被編譯成庫(kù)libaudioflinger.so,它是Audio系統(tǒng)的本地服務(wù)部分

可以使用以下命令從init.rc文件中啟動(dòng)Media service

service media /system/bin/mediaserver

HAL

hardware/libhardware/include/hardware
hardware/libhardware_legacy/include/hardware_legacy

HAL定義了音頻服務(wù)調(diào)用的標(biāo)準(zhǔn)接口卑雁,您必須實(shí)現(xiàn)該接口才能使您的音頻硬件正常運(yùn)行募书。

Android’s audio Hardware Abstraction Layer (HAL) connects the higher-level, audio-specific framework APIs in android.media to the underlying audio driver and hardware.The audio HAL interfaces are located inhardware/libhardware/include/hardware. This section explains how to implement the audio Hardware Abstraction Layer (HAL) for different hard wares.The audio HAL mainly contain two interfaces,

  1. hardware/libhardware/include/hardware/audio.h. Represents the main functions of an audio device.
  2. hardware/libhardware/include/hardware/audio_effect.h. Represents effects that can be applied to audio such as downmixing, echo cancellation, or noise suppression.

Device vendor must implement all interfaces to support audio HAL. Audio Hardware mainly contains basic functionality for:

  • Opening/closing audio input/output streams
  • Audio devices enabling/disabling, like EARPIECE, SPEAKER, and BLUETOOTH_SCO, etc.
  • Set volume for voice call and Mute Mic.
  • Change audio modes including AUDIO_MODE_NORMAL for standard audio playback, AUDIO_MODE_IN_CALL when a call is in progress, AUDIO_MODE_RINGTONE when a ringtone is playing.

Each input/output stream should provide function for

  • data write/read.
  • Get/set Sample rate.
  • Get channels, buffer size information of current stream.
  • Get/set current format, eg. AUDIO_FORMAT_PCM_16_BIT.
  • Put stream into standby mode.
  • Add/remove audio effect on the stream.
  • Get/set parameter to switch audio path.

The audio HAL should implement all the below represented function callbacks.

static int adev_open(const hw_module_t* module, const char* name, hw_device_t** device)
{
    struct audio_device *adev;
    int ret = 0;
    int i,j,k;
    bool found;

    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
        return -EINVAL;

    adev = calloc(1, sizeof(struct udio_device));
    if (!adev)
        return -ENOMEM;

    /* Set HAL API Version*/

    adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
    adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
    adev->hw_device.common.module = (struct hw_module_t *) module;
    adev->hw_device.common.close = adev_close;

    /* Function callbacks*/

    adev->hw_device.init_check = adev_init_check;
    adev->hw_device.set_voice_volume = adev_set_voice_volume;
    adev->hw_device.set_master_volume = adev_set_master_volume;
    adev->hw_device.set_mode = adev_set_mode;
    adev->hw_device.set_mic_mute = adev_set_mic_mute;
    adev->hw_device.get_mic_mute = adev_get_mic_mute;
    adev->hw_device.set_parameters = adev_set_parameters;
    adev->hw_device.get_parameters = adev_get_parameters;
    adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
    adev->hw_device.open_output_stream = adev_open_output_stream;
    adev->hw_device.close_output_stream = adev_close_output_stream;
    adev->hw_device.open_input_stream = adev_open_input_stream;
    adev->hw_device.close_input_stream = adev_close_input_stream;
    adev->hw_device.dump = adev_dump;

    /* Sampling rate */
    adev->default_rate = adev->mm_rate;
    pcm_config_mm_out.rate = adev->mm_rate;
    pcm_config_mm_in.rate = adev->mm_rate;
    pcm_config_hdmi_multi.rate = adev->mm_rate;
    pcm_config_esai_multi.rate = adev->mm_rate;

    *device = &adev->hw_device.common;

    return 0;
}

從設(shè)計(jì)上來(lái)看,硬件抽象層是AudioFlinger直接訪問(wèn)的對(duì)象测蹲。

這說(shuō)明了兩個(gè)問(wèn)題莹捡,
AudioFlinger并不直接調(diào)用底層的驅(qū)動(dòng)程序;
AudioFlinger上層模塊只需要與它進(jìn)行交互就可以實(shí)現(xiàn)音頻相關(guān)的功能了。

因而我們可以認(rèn)為AudioFlinger是Android音頻系統(tǒng)中真正的“隔離板”扣甲,無(wú)論下面如何變化道盏,上層的實(shí)現(xiàn)都可以保持兼容。

音頻方面的硬件抽象層主要分為兩部分文捶,即AudioFlinger和AudioPolicyService荷逞。

實(shí)際上后者并不是一個(gè)真實(shí)的設(shè)備,只是采用虛擬設(shè)備的方式來(lái)讓廠商可以方便地定制出自己的策略粹排。抽象層的任務(wù)是將AudioFlinger/AudioPolicyService真正地與硬件設(shè)備關(guān)聯(lián)起來(lái)种远,但又必須提供靈活的結(jié)構(gòu)來(lái)應(yīng)對(duì)變化——特別是對(duì)于Android這個(gè)更新相當(dāng)頻繁的系統(tǒng)。

比如以前Android系統(tǒng)中的Audio系統(tǒng)依賴于ALSA- lib顽耳,但后期就變?yōu)榱藅inyalsa坠敷,這樣的轉(zhuǎn)變不應(yīng)該對(duì)上層造成破壞。

因而Audio HAL提供了統(tǒng)一的接口來(lái)定義它與AudioFlinger/AudioPolicyService之間的通信方式射富,這就是audio_hw_device膝迎、audio_stream_inaudio_stream*out等等存在的目的,這些Struct數(shù)據(jù)類型內(nèi)部大多只是函數(shù)指針的定義胰耗,是一些“殼”限次。

當(dāng)AudioFlinger/AudioPolicyService初始化時(shí),它們會(huì)去尋找系統(tǒng)中最匹配的實(shí)現(xiàn)(這些實(shí)現(xiàn)駐留在以audio.primary.*,audio.a2dp._為名的各種庫(kù)中)來(lái)填充這些“殼”柴灯。

根據(jù)產(chǎn)品的不同卖漫,音頻設(shè)備存在很大差異,在Android的音頻架構(gòu)中赠群,這些問(wèn)題都是由HAL層的audio.primary等等庫(kù)來(lái)解決的羊始,而不需要大規(guī)模地修改上層實(shí)現(xiàn)。換句話說(shuō)查描,廠商在定制時(shí)的重點(diǎn)就是如何提供這部分庫(kù)的高效實(shí)現(xiàn)了突委。

AudioRcorder和AudioTrack是Audio系統(tǒng)對(duì)外提供API類;
AudioRcorder主要用于完成音頻數(shù)據(jù)的采集;
AudioTrack則是負(fù)責(zé)音頻數(shù)據(jù)的輸出;
AudioFlinger管理著系統(tǒng)中的輸入輸出音頻流柏卤,并承擔(dān)著音頻數(shù)據(jù)的混合,通過(guò)讀寫Audio硬件實(shí)現(xiàn)音頻數(shù)據(jù)的輸入輸出功能匀油;
AudioPolicyService是Audio系統(tǒng)的策略控制中心缘缚,掌管系統(tǒng)中聲音設(shè)備的選擇和切換、音量控制等钧唐。

Tinyalsa

源碼在external/tinyalsa目錄下
Tinyalsa:tinyplay/tinycap/tinymix,這些用戶程序直接調(diào)用 alsa 用戶庫(kù)接口來(lái)實(shí)現(xiàn)放音匠襟、錄音钝侠、控制

Kernel Driver

Audio驅(qū)動(dòng)與硬件以及HAL層實(shí)現(xiàn)的交互。你可以選擇在此級(jí)別使用ALSA, OSS, 或者自定義的驅(qū)動(dòng)程序酸舍。HAL是與驅(qū)動(dòng)程序無(wú)關(guān)的帅韧。

注意:如果您選擇ALSA,我們建議使用external / tinyalsa作為驅(qū)動(dòng)程序的用戶部分啃勉,因?yàn)樗哂屑嫒莸脑S可(標(biāo)準(zhǔn)用戶模式庫(kù)是GPL許可的)忽舟。

+ ALSA 和 ASoC

Native ALSA Application:tinyplay/tinycap/tinymix,這些用戶程序直接調(diào)用 alsa 用戶庫(kù)接口來(lái)實(shí)現(xiàn)放音淮阐、錄音叮阅、控制
ALSA Library API:alsa 用戶庫(kù)接口,常見(jiàn)有 tinyalsa泣特、alsa-lib
ALSA CORE:alsa 核心層浩姥,向上提供邏輯設(shè)備(PCM/CTL/MIDI/TIMER/…)系統(tǒng)調(diào)用,向下驅(qū)動(dòng)硬件設(shè)備(Machine/I2S/DMA/CODEC)
ASoC CORE:asoc 是建立在標(biāo)準(zhǔn) alsa core 基礎(chǔ)上状您,為了更好支持嵌入式系統(tǒng)和應(yīng)用于移動(dòng)設(shè)備的音頻 codec 的一套軟件體系
Hardware Driver:音頻硬件設(shè)備驅(qū)動(dòng)勒叠,由三大部分組成,分別是 Machine膏孟、Platform眯分、Codec

+ ASoC

ASoC被分為Machine、Platform和Codec三大部分柒桑。

其中的Machine驅(qū)動(dòng)負(fù)責(zé)Platform和Codec之間的耦合和設(shè)備或板子特定的代碼弊决。

Platform驅(qū)動(dòng)的主要作用是完成音頻數(shù)據(jù)的管理,最終通過(guò)CPU的數(shù)字音頻接口(DAI)把音頻數(shù)據(jù)傳送給Codec進(jìn)行處理魁淳,最終由Codec輸出驅(qū)動(dòng)耳機(jī)或者是喇叭的音信信號(hào)丢氢。

  • Machine

用于描述設(shè)備組件信息和特定的控制如耳機(jī)/外放等。

是指某一款機(jī)器先改,可以是某款設(shè)備疚察,某款開(kāi)發(fā)板,又或者是某款智能手機(jī)仇奶,由此可以看出Machine幾乎是不可重用的循诉,每個(gè)Machine上的硬件實(shí)現(xiàn)可能都不一樣,CPU不一樣浪规,Codec不一樣礁遵,音頻的輸入、輸出設(shè)備也不一樣允趟,Machine為CPU、Codec、輸入輸出設(shè)備提供了一個(gè)載體掸掸。

這一部分將平臺(tái)驅(qū)動(dòng)和Codec驅(qū)動(dòng)綁定在一起,描述了板級(jí)的硬件特征蹭秋。

主要負(fù)責(zé)Platform和Codec之間的耦合以及部分和設(shè)備或板子特定的代碼扰付。

Machine驅(qū)動(dòng)負(fù)責(zé)處理機(jī)器特有的一些控件和音頻事件(例如,當(dāng)播放音頻時(shí)仁讨,需要先行打開(kāi)一個(gè)放大器)羽莺;單獨(dú)的Platform和Codec驅(qū)動(dòng)是不能工作的,它必須由Machine驅(qū)動(dòng)把它們結(jié)合在一起才能完成整個(gè)設(shè)備的音頻處理工作洞豁。ASoC的一切都從Machine驅(qū)動(dòng)開(kāi)始盐固,包括聲卡的注冊(cè),綁定Platform和Codec驅(qū)動(dòng)等等

  • Playtfrom

用于實(shí)現(xiàn)平臺(tái)相關(guān)的DMA驅(qū)動(dòng)和音頻接口等丈挟。

一般是指某一個(gè)SoC平臺(tái)刁卜,比如pxaxxx,s3cxxxx,omapxxx等等,與音頻相關(guān)的通常包含該SoC中的時(shí)鐘曙咽、DMA长酗、I2S、PCM等等桐绒,只要指定了SoC夺脾,那么我們可以認(rèn)為它會(huì)有一個(gè)對(duì)應(yīng)的Platform,它只與SoC相關(guān)茉继,與Machine無(wú)關(guān)咧叭,這樣我們就可以把Platform抽象出來(lái),使得同一款SoC不用做任何的改動(dòng)烁竭,就可以用在不同的Machine中菲茬。實(shí)際上,把Platform認(rèn)為是某個(gè)SoC更好理解派撕。

這一部分只關(guān)心CPU本身婉弹,不關(guān)心Codec。主要處理兩個(gè)問(wèn)題:DMA引擎和SoC集成的PCM终吼、I2S或AC ‘97數(shù)字接口控制镀赌。主要作用是完成音頻數(shù)據(jù)的管理,最終通過(guò)CPU的數(shù)字音頻接口(DAI)把音頻數(shù)據(jù)傳送給Codec進(jìn)行處理际跪,最終由Codec輸出驅(qū)動(dòng)耳機(jī)或者是喇叭的音信信號(hào)商佛。在具體實(shí)現(xiàn)上喉钢,ASoC有把Platform驅(qū)動(dòng)分為兩個(gè)部分:snd_soc_platform_driver和snd_soc_dai_driver。其中良姆,platform_driver負(fù)責(zé)管理音頻數(shù)據(jù)肠虽,把音頻數(shù)據(jù)通過(guò)dma或其他操作傳送至cpu dai中,dai_driver則主要完成cpu一側(cè)的dai的參數(shù)配置玛追,同時(shí)也會(huì)通過(guò)一定的途徑把必要的dma等參數(shù)與snd_soc_platform_driver進(jìn)行交互税课。

  • Codec

用于實(shí)現(xiàn)平臺(tái)無(wú)關(guān)的功能,如寄存器讀寫接口痊剖,音頻接口韩玩,各widgets的控制接口和DAPM的實(shí)現(xiàn)等

字面上的意思就是編解碼器,Codec里面包含了I2S接口邢笙、D/A啸如、A/D侍匙、Mixer氮惯、PA(功放),通常包含多種輸入(Mic想暗、Line- in妇汗、I2S、PCM)和多個(gè)輸出(耳機(jī)说莫、喇叭杨箭、聽(tīng)筒,Line- out)储狭,Codec和Platform一樣互婿,是可重用的部件,同一個(gè)Codec可以被不同的Machine使用辽狈。嵌入式Codec通常通過(guò)I2C對(duì)內(nèi)部的寄存器進(jìn)行控制慈参。

這一部分只關(guān)心Codec本身,與CPU平臺(tái)相關(guān)的特性不由此部分操作刮萌。在移動(dòng)設(shè)備中驮配,Codec的作用可以歸結(jié)為4種,分別是:

1着茸、對(duì)PCM等信號(hào)進(jìn)行D/A轉(zhuǎn)換壮锻,把數(shù)字的音頻信號(hào)轉(zhuǎn)換為模擬信號(hào)。
2涮阔、對(duì)Mic猜绣、Linein或者其他輸入源的模擬信號(hào)進(jìn)行A/D轉(zhuǎn)換,把模擬的聲音信號(hào)轉(zhuǎn)變CPU能夠處理的數(shù)字信號(hào)敬特。
3途事、對(duì)音頻通路進(jìn)行控制验懊,比如播放音樂(lè),收聽(tīng)調(diào)頻收音機(jī)尸变,又或者接聽(tīng)電話時(shí)义图,音頻信號(hào)在codec內(nèi)的流通路線是不一樣的。
4召烂、對(duì)音頻信號(hào)做出相應(yīng)的處理碱工,例如音量控制,功率放大奏夫,EQ控制等等怕篷。

ASoC對(duì)Codec的這些功能都定義好了一些列相應(yīng)的接口,以方便地對(duì)Codec進(jìn)行控制酗昼。ASoC對(duì)Codec驅(qū)動(dòng)的一個(gè)基本要求是:驅(qū)動(dòng)程序的代碼必須要做到平臺(tái)無(wú)關(guān)性廊谓,以方便同一個(gè)Codec的代碼不經(jīng)修改即可用在不同的平臺(tái)上。

image

ASoC對(duì)于Alsa來(lái)說(shuō)麻削,就是分別注冊(cè)PCM/CONTROL類型的snd_device設(shè)備蒸痹,并實(shí)現(xiàn)相應(yīng)的操作方法集。圖中DAI是數(shù)字音頻接口呛哟,用于配置音頻數(shù)據(jù)格式等叠荠。

? Codec驅(qū)動(dòng)向ASoC注冊(cè)snd_soc_codec和snd_soc_dai設(shè)備。
? Platform驅(qū)動(dòng)向ASoC注冊(cè)snd_soc_platform和snd_soc_dai設(shè)備扫责。
? Machine驅(qū)動(dòng)通過(guò)snd_soc_dai_link綁定codec/dai/platform榛鼎。

Widget是各個(gè)組件內(nèi)部的小單元。處在活動(dòng)通路上電鳖孤,不在活動(dòng)通路下電者娱。ASoC的DAPM正是通過(guò)控制這些Widget的上下電達(dá)到動(dòng)態(tài)電源管理的效果。

? path描述與其它widget的連接關(guān)系苏揣。
? event用于通知該widget的上下電狀態(tài)黄鳍。
? power指示當(dāng)前的上電狀態(tài)。
? control實(shí)現(xiàn)空間用戶接口用于控制widget的音量/通路切換等腿准。

對(duì)驅(qū)動(dòng)開(kāi)者來(lái)說(shuō)际起,就可以很好的解耦了:

? codec驅(qū)動(dòng)的開(kāi)發(fā)者,實(shí)現(xiàn)codec的IO讀寫方法吐葱,描述DAI支持的數(shù)據(jù)格式/操作方法和Widget的連接關(guān)系就可以了;
? soc芯片的驅(qū)動(dòng)開(kāi)發(fā)者街望,Platform實(shí)現(xiàn)snd_pcm的操作方法集和DAI的配置如操作 DMA,I2S/AC97/PCM的設(shè)定等;
? 板級(jí)的開(kāi)發(fā)者弟跑,描述Machine上codec與platform之間的總線連接灾前, earphone/Speaker的布線情況就可以了。

+ DAPM

DAPM是Dynamic Audio Power Management的縮寫孟辑,直譯過(guò)來(lái)就是動(dòng)態(tài)音頻電源管理的意思哎甲,DAPM是為了使基于linux的移動(dòng)設(shè)備上的音頻子系統(tǒng)蔫敲,在任何時(shí)候都工作在最小功耗狀態(tài)下。

DAPM對(duì)用戶空間的應(yīng)用程序來(lái)說(shuō)是透明的炭玫,所有與電源相關(guān)的開(kāi)關(guān)都在ASoc core中完成奈嘿。

用戶空間的應(yīng)用程序無(wú)需對(duì)代碼做出修改,也無(wú)需重新編譯吞加,DAPM根據(jù)當(dāng)前激活的音頻流(playback/capture)和聲卡中的mixer等的配置來(lái)決定那些音頻控件的電源開(kāi)關(guān)被打開(kāi)或關(guān)閉裙犹。

+ DPCM

Dynamic PCM

Audio devices

具體的Audio硬件設(shè)備。

總結(jié)

1衔憨、Audio使用JNI和Java對(duì)上層提供接口叶圃,JNI部分通過(guò)調(diào)用libmedia庫(kù)提供的接口來(lái)實(shí)現(xiàn)。
2践图、 Audio 本地框架類是libmedia.so的一個(gè)部分掺冠,這些Audio框架類對(duì)上層提供接口,由下層的本地代碼去實(shí)現(xiàn)码党。
3德崭、AudioFlinger繼承l(wèi)ibmeida中的接口,提供實(shí)現(xiàn)庫(kù)libaudiofilnger.so闽瓢。這部分內(nèi)容沒(méi)有自己的對(duì)外頭文件接癌,上層調(diào)用的只是libmedia本部分的接口心赶,但實(shí)際調(diào)用的內(nèi)容是libaudioflinger.so扣讼。
4、Audio的硬件抽象層提供到硬件的接口缨叫,供AudioFlinger調(diào)用椭符。Audio的硬件抽象層實(shí)際上是各個(gè)平臺(tái)開(kāi)發(fā)過(guò)程中需要主要關(guān)注和獨(dú)立完成的部分。

在Android的Audio系統(tǒng)中耻姥,無(wú)論上層還是下層销钝,都使用一個(gè)管理類和輸出輸入兩個(gè)類來(lái)表示整個(gè)Audio系統(tǒng),輸出輸入兩個(gè)類負(fù)責(zé)數(shù)據(jù)通道琐簇。在各個(gè)層次之間具有對(duì)應(yīng)關(guān)系:

image

在libhardware_legacy中定義的音頻相關(guān)的硬件抽象層數(shù)據(jù)結(jié)構(gòu)legacy_audio_device蒸健、legacy_stream_out、legacy_stream_in如下:

音頻設(shè)備描述符:

struct legacy_audio_device {
    struct audio_hw_device device;
    struct AudioHardwareInterface *hwif;
};

音頻輸出描述符:

struct legacy_stream_out {
    struct audio_stream_out stream;
    AudioStreamOut *legacy_out;
};

音頻輸入描述符:

struct legacy_stream_in {
    struct audio_stream_in stream;
    AudioStreamIn *legacy_in;
};
image

通過(guò)上表比較可以看出婉商,audio_hw_device和AudioHardwareInterface似忧、audio_stream_out和AudioStreamOut、audio_stream_in和AudioStreamIn定義的接口基本一致丈秩,這是為了兼容Android先前版本盯捌。

AudioHardwareInterface.cpp負(fù)責(zé)實(shí)現(xiàn)基礎(chǔ)類和管理,而AudioHardwareGeneric.cpp蘑秽、AudioHardwareStub.cpp饺著、AudioDumpInterface.cpp和A2dpAudioInterface.cpp各自代表一種Auido硬件抽象層的實(shí)現(xiàn)箫攀。

  1. AudioHardwareGeneric.cpp:實(shí)現(xiàn)基于特定驅(qū)動(dòng)的通用Audio硬件抽象層,這是一個(gè)真正能夠使用的Audio硬件抽象層幼衰,但是它需要Android的一種特殊的聲音驅(qū)動(dòng)程序的支持靴跛。
  2. AudioHardwareStub.cpp:實(shí)現(xiàn)Audio硬件抽象層的一個(gè)樁,這個(gè)實(shí)現(xiàn)不操作實(shí)際的硬件和文件渡嚣,它所進(jìn)行的是空操作汤求。
  3. AudioDumpInterface.cpp:實(shí)現(xiàn)輸出到文件的Audio硬件抽象層,支持Audio的輸出功能严拒,不支持輸入功能扬绪。
  4. A2dpAudioInterface.cpp:實(shí)現(xiàn)藍(lán)牙音頻的Audio硬件抽象層。

Qualcomm平臺(tái) - Audio系統(tǒng)框架

由于接下來(lái)的一系列Android && kernel 源碼分析都是基于Qualcomm 平臺(tái)的裤唠,十分有必要介紹Qualcomm 平臺(tái)的Audio 系統(tǒng)框架挤牛。硬件平臺(tái)及軟件版本:
? Kernel - 3.18
? SoC - Qualcomm snapdragon
? CODEC - WCD9335
? Machine - msm8996
? Userspace - tinyalsa

Qualcomm Audio系統(tǒng)總體框架圖

image

ASoC driver

ALSA 片上系統(tǒng) (ASoC) 驅(qū)動(dòng)程序?qū)⒁纛l系統(tǒng)分為四個(gè)組成部分Machine driver、Platform driver种蘸、CPU driver墓赴、Codec driver。

Machine driver

將平臺(tái)航瞭、CPU 和編解碼驅(qū)動(dòng)程序整合在一起
kernel/sound/soc/msm/.c
定義Frontend (FE) and Backend (BE), Digital Audio Interface (DAI) links

Platform driver

包含用于流數(shù)據(jù)傳輸與路由的平臺(tái)特定的控件(control)诫硕, 細(xì)分為 FE 和 BE 平臺(tái)驅(qū)動(dòng)程序

  • FE

Audio – 實(shí)例化 PCM 播放和錄制會(huì)話;借助 ASM 接口刊侯,將 PCM 數(shù)據(jù)從用戶空間傳輸?shù)?DSP 進(jìn)行播放
以及從 DSP 傳輸?shù)接脩艨臻g進(jìn)行錄制 – 在 kernel/sound/soc/msm-pcm-q6-v2.c 中實(shí)現(xiàn)
Voice – 初始化/取消初始化語(yǔ)音呼叫設(shè)置 – 在 kernel/sound/soc/msm-pcm-voice-v2.c 中實(shí)現(xiàn)
VoIP – 初始化/取消初始化 MVS 接口以傳輸自/至 DSP 的 PCM 數(shù)據(jù) – 在kernel/sound/soc/msm- pcmvoip-v2.c中實(shí)現(xiàn)
Compressed offload – 支持將壓縮數(shù)據(jù)發(fā)送到 DSP 進(jìn)行壓縮分流播放 – 在 kernel/sound/soc/msm- compress-q6-v2.c 中實(shí)現(xiàn)

  • BE

路由 – 執(zhí)行音頻路由任務(wù) – 在 /kernel/sound/soc/msm-pcm-routing-v2.c 中實(shí)現(xiàn)

CPU driver

  • FE

向 ASoC 框架提供關(guān)于 FE PCM 設(shè)備的信息
ASoC 框架與平臺(tái)驅(qū)動(dòng)程序提供的路由表共同將 PCM 播放/捕獲從 FE 傳遞至 BE
沒(méi)有針對(duì)播放和錄制的內(nèi)置邏輯
定義 FE CPU DAI – 在 kernel/sound/soc/msm/msm-dai-fe.c 中實(shí)現(xiàn)

  • BE

要在初始化 PCM 播放/捕獲時(shí)激活所需音頻硬件端口章办,則配置 DSP AFE 模塊
定義 BE CPU DAI – 在 kernel/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c 中實(shí)現(xiàn)

Codec driver

與平臺(tái)無(wú)關(guān),其中包含音頻控制滨彻、音頻接口功能藕届、編解碼器 DAPM 定義以及編解碼器輸入輸出功能
此外,實(shí)現(xiàn) MBHC 狀態(tài)機(jī)亭饵,用于檢測(cè)有線耳機(jī)插入/拔出休偶、附件類型、連接器類型和多按鈕檢測(cè)

DSP driver

image

ASM(Audio Stream Manager)

? 用于與 DSP ASM 模塊通信的接口
? 提供將 PCM 數(shù)據(jù)路由至 DSP 的機(jī)制辜羊,支持按數(shù)據(jù)流進(jìn)行后期處理/預(yù)處理

ADM(Audio Device Manager)

? 允許在 DSP 中使用 ADM 服務(wù)
? 配置 COPP 和路由矩陣
? 與音頻校準(zhǔn)數(shù)據(jù)庫(kù) (ACDB) 進(jìn)行通信踏兜,使用正確的校準(zhǔn)數(shù)據(jù)配置 COPP
? 將 ASM 會(huì)話 ID 路由至 ADM 會(huì)話

AFE(Audio Front-End)

? 允許在 DSP 中使用 AFE 服務(wù)
? 激活/禁用音頻硬件端口
? 子系統(tǒng)管理器 – 發(fā)生 MDSP 復(fù)位事件時(shí),通知音頻和語(yǔ)音驅(qū)動(dòng)程序關(guān)閉待處理
會(huì)話八秃、執(zhí)行清理操作并等待一個(gè)指示 MDSP 已啟動(dòng)的事件

APR(Asynchronous Packet Router)

? 為處理器間通信提供異步框架
? 用于與 Hexagon 和調(diào)制解調(diào)器處理器進(jìn)行通信
? Image loader PIL – 載入 MDSP 圖像

User Space

Audio Hardware Abstraction Layer (AHAL)

? 通過(guò) tinyALSA 將 AudioFlinger調(diào)用映射至ASoC 驅(qū)動(dòng)程序的硬件抽象層碱妆。

ACDB loader

? 檢索特定設(shè)備的校準(zhǔn)信息,并寫入 PMEM喜德。ACDB 驅(qū)動(dòng)程序在啟動(dòng)過(guò)程中分配該 PMEM山橄。在設(shè)備切換時(shí),此校準(zhǔn)將被發(fā)送到 DSP。

tinyALSA

? 連接至內(nèi)核 ASoC 驅(qū)動(dòng)程序的接口航棱,供音頻 HAL 使用睡雇。提供用于音頻流和設(shè)備管理的基本 PCM 和混音控件 API。

Audio route

? 此模塊會(huì)從一個(gè) .xml 文件讀取 ALSA 混音控件饮醇,并根據(jù)音頻HAL 所選的設(shè)備設(shè)置混音控件它抱。

Concurrency Manager

? 在MSM8x10中,視頻解碼和編碼在DSP中完成; 因此朴艰,有對(duì)可支持的并發(fā)性有一些限制观蓄。
? MSM8x10中引入的并發(fā)管理器管理并發(fā)性可以支持涉及語(yǔ)音和音頻的不同用例

Multimedia framework – Stagefright

? 支持標(biāo)準(zhǔn)音頻格式的播放/錄制
? 與解碼器/編碼器庫(kù)以及 OpenMAX IL 組件通信,以便進(jìn)行解碼和編碼

Audio service

? 由系統(tǒng)服務(wù)器啟動(dòng)并由服務(wù)管理器管理的運(yùn)行時(shí)服務(wù)之一
? 意圖注冊(cè)祠墅;當(dāng)從各種應(yīng)用程序(HDMI侮穿、藍(lán)牙等)接收到這些意圖時(shí),通知音頻系統(tǒng)

AudioFlinger

? 通過(guò) libaudio 接口毁嗦、藍(lán)牙 A2DP 接口管理所有音頻輸出/輸入設(shè)備
? 將多個(gè)音頻流處理為單一的 PCM 音頻亲茅;混合后的輸出被傳送到輸出設(shè)備
? 播放音樂(lè)流時(shí)的音量

Audio Policy Manager (APM)

? 定義多個(gè)音頻用例之間的并發(fā)規(guī)則
? 用例示例 – 電話通話、音樂(lè)播放狗准、系統(tǒng)聲音和通知
? 定義播放的音頻(例如:語(yǔ)音克锣、播放、鈴聲)以及播放的設(shè)備(藍(lán)牙腔长、揚(yáng)聲器
和耳機(jī))
APM 用途
? 管理各種輸入輸出設(shè)備接口
? 管理各種輸入輸出設(shè)備袭祟,例如:麥克風(fēng)、揚(yáng)聲器捞附、耳機(jī)巾乳、聽(tīng)筒、A2DP故俐、藍(lán)牙 SCO
? 基于音頻流想鹰、模式和方法選擇和定義適當(dāng)?shù)穆酚刹呗?br> ? 管理每個(gè)音頻流的音量/靜音設(shè)置(在它們激活或禁用時(shí))

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末紊婉,一起剝皮案震驚了整個(gè)濱河市药版,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌喻犁,老刑警劉巖槽片,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異肢础,居然都是意外死亡还栓,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門传轰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)剩盒,“玉大人,你說(shuō)我怎么就攤上這事慨蛙×闪模” “怎么了纪挎?”我有些...
    開(kāi)封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)跟匆。 經(jīng)常有香客問(wèn)我异袄,道長(zhǎng),這世上最難降的妖魔是什么玛臂? 我笑而不...
    開(kāi)封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任烤蜕,我火速辦了婚禮,結(jié)果婚禮上迹冤,老公的妹妹穿的比我還像新娘讽营。我一直安慰自己,他們只是感情好泡徙,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布斑匪。 她就那樣靜靜地躺著,像睡著了一般锋勺。 火紅的嫁衣襯著肌膚如雪蚀瘸。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天庶橱,我揣著相機(jī)與錄音贮勃,去河邊找鬼。 笑死苏章,一個(gè)胖子當(dāng)著我的面吹牛寂嘉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播枫绅,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼泉孩,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了并淋?” 一聲冷哼從身側(cè)響起寓搬,我...
    開(kāi)封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎县耽,沒(méi)想到半個(gè)月后句喷,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡兔毙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年唾琼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片澎剥。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡锡溯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情祭饭,我是刑警寧澤涌乳,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站甜癞,受9級(jí)特大地震影響夕晓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜悠咱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一蒸辆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧析既,春花似錦躬贡、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至宰译,卻和暖如春檐蚜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背沿侈。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工闯第, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人缀拭。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓咳短,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蛛淋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子咙好,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 在移動(dòng)設(shè)備中,Codec的作用可以歸結(jié)為4種褐荷,分別是: 1.對(duì)PCM等信號(hào)進(jìn)行D/A轉(zhuǎn)換勾效,把數(shù)字的音頻信號(hào)轉(zhuǎn)換為模...
    gbmaotai閱讀 17,644評(píng)論 4 3
  • 前言 今天跟王總聊天,他狠狠地(形容詞)叼了我诚卸,他說(shuō)你為什么不寫一些比較牛逼的文章葵第,為什么總是寫一些教別人如何安裝...
    da4ac7fb9bd5閱讀 4,920評(píng)論 0 49
  • 教程一:視頻截圖(Tutorial 01: Making Screencaps) 首先我們需要了解視頻文件的一些基...
    90后的思維閱讀 4,654評(píng)論 0 3
  • Core Audio Core Audio提供了數(shù)字音頻服務(wù)為iOS與OS X, 它提供了一系列框架去處理音頻. ...
    小東邪啊閱讀 5,116評(píng)論 0 6
  • 前位(early position)是較差的位置,包括槍口位UTG(under the gun)合溺、UTG后面的兩個(gè)...
    云落霓裳閱讀 1,977評(píng)論 0 0