Android_P_Audio_系統(1) — Auido 系統簡介

1 音頻基礎

1.1 聲音的三要素

1. 音量(Volume)

也叫做響度(Loudness),人耳對聲音強弱的主觀感覺就是響度,響度和聲波振動的幅度有關。一般說來,聲波振動幅度越大則響度也越大。當我們用較大的力量敲鼓時,鼓膜振動的幅度大,發出的聲音響;輕輕敲鼓時,鼓膜振動的幅度小,發出的聲音弱。

2. 音調(Pitch)

人耳對聲音高低的感覺稱爲音調(也叫音頻),音調主要與聲波的頻率有關。聲波的頻率高,則音調也高。當我們分別敲擊一個小鼓和一個大鼓時,會感覺它們所發出的聲音不同。小鼓被敲擊後振動頻率快,發出的聲音比較清脆,即音調較高;而大鼓被敲擊後振動頻率較慢,發出的聲音比較低沉,即音調較低。

一般音調:兒童 > 女生 > 男生

人耳聽覺音頻範圍是 20Hz-20000Hz (若音頻壓縮時不在這個範圍內的數據就可以砍掉)。

3. 音色(Quality)

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

音色與聲波的振動波形有關,或者說與聲音的頻譜結構有關。

1.2 音頻的量化與編碼

日常生活中我們聽到的聲波波形信號都是時間連續的,我們稱這種信號爲模擬信號,模擬信號需要量化成數字信號(離散、不連續的)以後才能被我們的計算機識別。音頻的量化過程可以簡單分爲以下 5 個步驟:

image

1) 模擬信號

現實生活中的聲音表現爲連續的、平滑的波形,其橫座標爲時間軸,縱座標表示聲音的強弱。

2) 採樣

按照一定的時間間隔在連續的波上進行採樣取值,如下圖所示取了 10 個樣。

3) 量化

將採樣得到的值進行量化處理,也就是給縱座標定一個刻度,記錄下每個採樣的縱座標的值。

4) 編碼

將每個量化後的樣本值轉換成二進制編碼,可以看到模擬信號經過採樣、量化、編碼後形成的二進制序列就是數字音頻信號。

5) 數字信號

將所有樣本二進制編碼連起來存儲在計算機上就形成了數字信號。

1.3 量化基本概念

1. 採樣位數

每個採樣點能夠表示的數據範圍,用多少個 bit 表示。採樣位數通常有 8 bits 或 16 bits 兩種,採樣位數越大,所能記錄聲音的變化度就越細膩,相應的數據量就越大。8 位字長量化(低品質)和 16 位字長量化(高品質),16 bit 是最常見的採樣精度。

採樣位數也被叫做採樣精度、量化級、量化數據位數等。

2. 採樣率

單位時間內對模擬信號的採樣次數,也就是採樣頻率,採樣頻率越高,聲音的還原就越真實越自然,當然數據量就越大。

我們日常生活中常見的採樣率:

  • 5kHz:僅能滿足人們講話的聲音質量
  • 8KHz:電話所用採樣率, 對於人的說話已經足夠
  • 22.05KHz:達到 FM 廣播的聲音品質(適用於語音和中等品質的音樂)
  • 44.1KHz:最常見的採樣率標準,理論上的 CD 音質界限,可以達到很好的聽覺效果
  • 48KHz:比 CD 音質更加精確一些

對於高於 48KHz 的採樣頻率人耳已無法辨別出來了,所以在電腦上沒有多少使用價值。

3. 聲道數

爲了播放聲音時能夠還原真實的聲場,在錄製聲音時在前後左右幾個不同的方位同時獲取聲音,每個方位的聲音就是一個聲道。聲道數是聲音錄製時的音源數量或回放時相應的揚聲器數量,有單聲道、雙聲道、多聲道。

4. 碼率

也叫比特率,指每秒傳送的數據量,單位爲 bps(Bit Per Second),碼率代表了壓縮質量,碼率越高,每秒傳送的數據就越多,音質就越好。

公式:
    碼率 = 採樣率 * 採樣位數 * 聲道數

例如:
    CD 音質,採樣率 44.1KHz,採樣位數 16 bit,立體聲(雙聲道)
    碼率 = 44.1 * 1000 * 16 * 2 = 1411200 bps = 176400 Bps

根據上面的碼率,錄製一分鐘需要 176400 Bps * 60秒 / 1024 / 1024 = 10.09MB

5. PCM

PCM(Pulse Code Modulation),即脈衝編碼調製,對聲音進行採樣、量化過程,未經過任何編碼和壓縮處理。

PCM 數據是最原始的音頻數據完全無損,所以 PCM 數據雖然音質優秀但體積龐大,爲了解決這個問題先後誕生了一系列的音頻格式,這些音頻格式運用不同的方法對音頻數據進行壓縮,通常分爲無損壓縮(ALAC、APE、FLAC)和有損壓縮(MP3、AAC、OGG、WMA)兩種。

5. 音頻幀

音頻數據是流式的,本身沒有明確的一幀幀的概念,在實際的應用中,爲了音頻算法處理/傳輸的方便,一般約定俗成取 2.5ms~60ms 爲單位的數據量爲一幀音頻。這個時間被稱之爲 “採樣時間”,其長度沒有特別的標準,它是根據編解碼器和具體應用的需求來決定的。

例如最常見的音頻格式 MP3 的數據通常由兩部分組成,一部分爲 “ID3” 用來存儲歌名、演唱者、專輯、音軌數
等信息,另一部分爲音頻數據。音頻數據部分以幀(frame)爲單位存儲,每個音頻都有自己的幀頭,如下圖所示就是一個 MP3 文件幀結構圖。

image

MP3 中的每一幀都有自己的幀頭,其中存儲了採樣率等解碼必須的信息,所以每一個幀都可以獨立於文件存在和播放,這個特性加上高壓縮比使得 MP3 文件成爲了音頻流播放的主流格式。幀頭之後存儲着音頻數據,這些音頻數據是若干個 PCM 數據幀經過壓縮算法壓縮得到的。

1.4 音頻編解碼器

常見的音頻編解碼器包括 OPUS、AAC、Vorbis、Speex、iLBC、AMR、G.711 等。目前泛娛樂化直播系統採用 rtmp 協議,支持 AAC 和 Speex。
性能上來看,OPUS > AAC > Vorbis,其它的逐漸被淘汰。

2 Android Audio 系統框架

image
image

2.1 Application

常見的音頻相關軟件有:音樂播放器、視頻播放器、電話、錄音軟件等等

2.2 Framework

1) framework Java 部分

這部分接口直接提供給 Application 層定製開發 Audio 相關功能,相關代碼主要在:

PATH:frameworks/base/media/java/android/media

可供使用的 API 有

  • AudioTrack & AudioRecorder:提供聲音播放和錄製接口
  • MediaPlayer & MediaRecorder:提供聲音播放和錄製接口,接口更加通用
  • AudioManager、AudioService & AudioSystem:提供聲音控制、通道選擇、音效設置等功能

AudioRcorder 和 MediaRecorder 主要用於完成音視頻數據的採集,而 AudioTrack 和 MediaPlayer 則負責音頻數據的輸出。

MediaPlayer 能夠播放多種格式的聲音文件,比如 MP3、AAC、WAV 等,MediaPlayer 的實現包含了 AudioTrack,而 AudioTrack 因爲不創建解碼器,僅能播放無須解碼的 PCM 流(wav 格式)。

2) framework Native 部分
  1. 客戶端:
    包含 Java API 接口 AudioTrack、AudioRecord、MediaPlayer、MediaRecord、AudioSystem 對應的 native 實現。在 Android 9.0 代碼中,爲了顯式的區分客戶端和服務端, 這部分實現從 libmedia 中分離出來,編譯成一個單獨的庫 libaudioclient.so,代碼路徑:

PATH: frameworks/av/media/libaudioclient

  1. 服務端:
    包含 Audio 系統中最核心的 AudioFlinger & AudioPolicyService 實現代碼,其中 AudioFlinger 是 Audio 系統的工作引擎,管理着系統中的輸入輸出音頻流,並承擔音頻數據的混音以及讀寫 Audio 硬件等工作。而 AudioPolicyService 是 Audio 系統的策略控制中心,掌管系統中聲音設備的選擇和切換、音量控制等功能。兩個功能分別被編譯成 libaudioflinger 和 libaudiopolicyservice 庫,運行在 AudioServer 系統進程中,通過 binder 跨進程向客戶端提供服務。代碼路徑:

PATH: frameworks/av/services/audioflinger(audiopolicy)

2.3 Audio HAL

從整體設計上看,硬件抽象層是 AudioFlinger 直接訪問的對象,廠商會在這一層添加自己的實現,橋接硬件驅動和上層框架。

Android Audio 上層設計框架中與硬件抽象層直接交互的只有 AudioFlinger 和 AudioPolicyService。實際上後者並不是一個真實的設備,只是採用虛擬設備的方式讓廠商可以方便地定製自己的策略。抽象層的任務就是提供統一的接口來定義它與 AudioFlinger/AudioPolicyService 之間的通信方式,不論 Audio 系統依賴 ALSA-lib 還是 tinyalsa,都不應該對上層框架造成破壞。下面來介紹 Android Audio Hal 的統一接口設計。

在 Android Audio 系統設計中,無論是上層還是下層都是用一個管理類和輸入輸出兩個類來表示 Audio 系統,輸入輸出兩個類負責數據通道,在各個層級間對應關係:

Audio 管理類 Audio 輸入 Audio 輸出
Java android.media.AudioSystem android.media.AudioRecord android.media.AudioTrack
native AudioSystem AudioRecord AudioTrack
AudioFlinger IAudioFlinger IAudioRecord IAudioTrack
硬件抽象層 AudioHardwareInterface AudioStreamOut AudioStreamIn

在 Android libhardware_legacy 中定義的音頻相關的參考硬件抽象層數據結構:

音頻設備描述符:

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

音頻輸入描述符

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

音頻輸出描述符:

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

audio_hw_device 和 AudioHardwareInterface、audio_stream_out 和 AudioStreamOut、audio_stream_in 和 AudioStreamIn 定義的接口基本一致,這是爲了兼容 Android 先後版本,下面的分析以 AudioHardwareInterface、AudioStreamIn、AudioStreamOut 作爲硬件抽象層音頻管理和輸入輸出結構體定義。

image

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

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

2.4 驅動

一般情況下用的 ALSA 音頻架構

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章