Android系統Audio框架介紹

快樂安卓發表於2014-09-24

音訊基礎知識

聲音有哪些重要屬性呢?

  1. 響度(Loudness)

響度就是人類可以感知到的各種聲音的大小,也就是音量。響度與聲波的振幅有直接關係。

  1. 音調(Pitch)

音調與聲音的頻率有關係,當聲音的頻率越大時,人耳所感知到的音調就越高,否則就越低。

  1. 音色(Quality)

同一種樂器,使用不同的材質來製作,所表現出來的音色效果是不一樣的,這是由物體本身的結構特性所決定的。

如何將各種媒體源數字化呢?

音訊取樣

將聲波波形訊號通過ADC轉換成計算機支援的二進位制的過程叫做音訊取樣(Audio Sampling)。取樣(Sampling)的核心是把連續的模擬訊號轉換成離散的數字訊號。

  1. 樣本(Sample)

這是我們進行取樣的初始資料,比如一段連續的聲音波形。

  1. 取樣器(Sampler)

取樣器是將樣本轉換成終態訊號的關鍵。它可以是一個子系統,也可以指一個操作過程,甚至是一個演算法,取決於不同的訊號處理場景。理想的取樣器要求儘可能不產生訊號失真。

  1. 量化(Quantization)

取樣後的值還需要通過量化,也就是將連續值近似為某個範圍內有限多個離散值的處理過程。因為原始資料是模擬的連續訊號,而數字訊號則是離散的,它的表達範圍是有限的,所以量化是必不可少的一個步驟。

  1. 編碼(Coding)

計算機的世界裡,所有數值都是用二進位制表示的,因而我們還需要把量化值進行二進位制編碼。這一步通常與量化同時進行。

 

奈奎斯特取樣理論

“當對被取樣的模擬訊號進行還原時,其最高頻率只有取樣頻率的一半”。

換句話說,如果我們要完整重構原始的模擬訊號,則取樣頻率就必須是它的兩倍以上。比如人的聲音範圍是2~ 20kHZ,那麼選擇的取樣頻率就應該在40kHZ左右,數值太小則聲音將產生失真現象,而數值太大也無法明顯提升人耳所能感知的音質。

錄製過程

  1. 音訊採集裝置(比如Microphone)捕獲聲音資訊。
  2. 模擬訊號通過模數轉換器(ADC)處理成計算機能接受的二進位制資料。
  3. 根據需求進行必要的渲染處理,比如音效調整、過濾等等。
  4. 處理後的音訊資料理論上已經可以儲存到計算機裝置中了,比如硬碟、USB裝置等等。不過由於這時的音訊資料體積相對龐大,不利於儲存和傳輸,通常還會對其進行壓縮處理。比如我們常見的mp3音樂,實際上就是對原始資料採用相應的壓縮演算法後得到的。壓縮過程根據取樣率、位深等因素的不同,最終得到的音訊檔案可能會有一定程度的失真,另外,音視訊的編解碼既可以由純軟體完成,也同樣可以藉助於專門的硬體晶片來完成。

回放過程

  1. 從儲存裝置中取出相關檔案,並根據錄製過程採用的編碼方式進行相應的解碼。
  2. 音訊系統為這一播放例項選定最終匹配的音訊回放裝置。
  3. 解碼後的資料經過音訊系統設計的路徑傳輸。
  4. 音訊資料訊號通過數模轉換器(DAC)變換成模擬訊號。
  5. 模擬訊號經過回放裝置,還原出原始聲音。

Audio框架

  1. APP

廠商根據特定需求自己寫的一個音樂播放器軟體等等。

  1. Framework

Android也提供了另兩個相似功能的類,即AudioTrack和AudioRecorder,MediaPlayerService內部的實現就是通過它們來完成的,只不過MediaPlayer/MediaRecorder提供了更強大的控制功能,相比前者也更易於使用。除此以外,Android系統還為我們控制音訊系統提供了AudioManager、AudioService及AudioSystem類。這些都是framework為便利上層應用開發所設計的。

  1. Libraries

framework只是嚮應用程式提供訪問Android庫的橋樑,具體功能實現放在庫中完成。比如上面的AudioTrackAudioRecorderMediaPlayerMediaRecorder等等在庫中都能找到相對應的類。

1、frameworks/av/media/libmedia【libmedia.so】

2、frameworks/av/services/audioflinger【libaudioflinger.so】

3、frameworks/av/media/libmediaplayerservice【libmediaplayerservice.so】

    4.   HAL

從設計上來看,硬體抽象層是AudioFlinger直接訪問的物件。這說明了兩個問題,一方面AudioFlinger並不直接呼叫底層的驅動程式;另一方面,AudioFlinger上層模組只需要與它進行互動就可以實現音訊相關的功能了。因而我們可以認為AudioFlinger是Android音訊系統中真正的“隔離板”,無論下面如何變化,上層的實現都可以保持相容。

音訊方面的硬體抽象層主要分為兩部分,即AudioFlinger和AudioPolicyService。實際上後者並不是一個真實的裝置,只是採用虛擬裝置的方式來讓廠商可以方便地定製出自己的策略。抽象層的任務是將AudioFlinger/AudioPolicyService真正地與硬體裝置關聯起來,但又必須提供靈活的結構來應對變化——特別是對於Android這個更新相當頻繁的系統。比如以前Android系統中的Audio系統依賴於ALSA-lib,但後期就變為了tinyalsa,這樣的轉變不應該對上層造成破壞。因而Audio HAL提供了統一的介面來定義它與AudioFlinger/AudioPolicyService之間的通訊方式,這就是audio_hw_device、audio_stream_in及audio_stream_out等等存在的目的,這些Struct資料型別內部大多隻是函式指標的定義,是一些“殼”。當AudioFlinger/AudioPolicyService初始化時,它們會去尋找系統中最匹配的實現(這些實現駐留在以audio.primary.*,audio.a2dp.*為名的各種庫中)來填充這些“殼”。根據產品的不同,音訊裝置存在很大差異,在Android的音訊架構中,這些問題都是由HAL層的audio.primary等等庫來解決的,而不需要大規模地修改上層實現。換句話說,廠商在定製時的重點就是如何提供這部分庫的高效實現了。

AudioRcorder和AudioTrack是Audio系統對外提供API類,AudioRcorder主要用於完成音訊資料的採集,而AudioTrack則是負責音訊資料的輸出。AudioFlinger管理著系統中的輸入輸出音訊流,並承擔著音訊資料的混合,通過讀寫Audio硬體實現音訊資料的輸入輸出功能;AudioPolicyService是Audio系統的策略控制中心,掌管系統中聲音裝置的選擇和切換、音量控制等。

 

Audio 系統程式碼:

(1)Audio 的Java 部分

frameworks/base/media/java/android/media

與Audio 相關的Java包是android.media,主要包含AudioManager和Audio 系統的幾個類。

(2)Audio 的JNI 部分

frameworks/base/core/jni

生成庫libandroid_runtime.so,Audio 的JNI是其中的一個部分。

(3)Audio 的框架部分

frameworks/base/include/media/

frameworks/base/media/libmedia/

這部分內容被編譯成庫libmedia.so,實現Audio系統的核心框架,同時提供了IAudioFlinger 類介面。在這個類中,可以獲得IAudioTrack 和IAudioRecorder 兩個介面,分別用於聲音的播放和錄製。AudioTrack 和AudioRecorder 分別呼叫IAudioTrack 和IAudioRecorder 來實現。IAudioFlinger.h、IAudioTrack.h 和IAudioRecorder.h 這三個介面通過下層來實現。AudioSystem.h、AudioTrack.h 和AudioRecorder.h 是對上層提供的介面,它們既供本地程式呼叫,也可以通過JNI 向Java 層提供介面。從功能上看,AudioSystem 負責的是Audio 系統的綜合管理功能,而AudioTrack 和AudioRecorder 分別負責音訊資料的輸出和輸入,即播放和錄製。另外一個介面是IAudioFlingerClient,它作為向IAudioFlinger中註冊的監聽器,相當於使用回撥函式獲取IAudioFlinger執行時資訊。

(4)Audio Flinger

frameworks/base/libs/audioflinger

這部分內容被編譯成庫libaudioflinger.so,它是Audio系統的本地服務部分。

(5)Audio 的硬體抽象層介面

hardware/libhardware_legacy/include/hardware/

1、Audio使用JNI和Java對上層提供介面,JNI部分通過呼叫libmedia庫提供的介面來實現。

2、 Audio 本地框架類是libmedia.so的一個部分,這些Audio框架類對上層提供介面,由下層的原生程式碼去實現。

3、AudioFlinger繼承libmeida中的介面,提供實現庫libaudiofilnger.so。這部分內容沒有自己的對外標頭檔案,上層呼叫的只是libmedia本部分的介面,但實際呼叫的內容是libaudioflinger.so。

4、Audio的硬體抽象層提供到硬體的介面,供AudioFlinger呼叫。Audio的硬體抽象層實際上是各個平臺開發過程中需要主要關注和獨立完成的部分。

在Android的Audio系統中,無論上層還是下層,都使用一個管理類和輸出輸入兩個類來表示整個Audio系統,輸出輸入兩個類負責資料通道。在各個層次之間具有對應關係:

在libhardware_legacy中定義的音訊相關的硬體抽象層資料結構legacy_audio_device、legacy_stream_out、legacy_stream_in如下:

音訊裝置描述符:

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;
};

通過上表比較可以看出,audio_hw_device和AudioHardwareInterface、audio_stream_out和AudioStreamOut、audio_stream_in和AudioStreamIn定義的介面基本一致,這是為了相容Android先前版本。

AudioHardwareInterface.cpp負責實現基礎類和管理,而AudioHardwareGeneric.cpp、AudioHardwareStub.cpp、AudioDumpInterface.cpp和A2dpAudioInterface.cpp各自代表一種Auido硬體抽象層的實現。

  1. AudioHardwareGeneric.cpp:實現基於特定驅動的通用Audio硬體抽象層,這是一個真正能夠使用的Audio硬體抽象層,但是它需要Android的一種特殊的聲音驅動程式的支援。
  2. AudioHardwareStub.cpp:實現Audio硬體抽象層的一個樁,這個實現不操作實際的硬體和檔案,它所進行的是空操作。
  3.  AudioDumpInterface.cpp:實現輸出到檔案的Audio硬體抽象層,支援Audio的輸出功能,不支援輸入功能。
  4. A2dpAudioInterface.cpp:實現藍芽音訊的Audio硬體抽象層。

相關文章