天天看點

08.音頻系統:第006課_音頻系統HAL分析:第001節_音量相關概念

該小節我們開始講解音量調節,首先我們來回顧一下之前的知識,我們知道android系統可以支援一個或者多個聲霸卡,一般來說,每個聲霸卡有輸出,或者輸入共功能。

08.音頻系統:第006課_音頻系統HAL分析:第001節_音量相關概念

對于他的輸出功能,在AudioFlinger中有一個線程與他對應,這個線程一般來說是MixerThread。這個線程的資料來源有多個APP,該線程最終會把多個APP提供的資料混合在一起,然後發送給聲霸卡,之前我們分析過,應用程式APP中會建立一個AudioTrack,在MixerThread中存在與APP對應的Track,應用 程式吧資料寫給AudioTrack,線程通過Track利用共享記憶體就獲得哪些資料,線程混合這些資料之後,進行播放。

這裡就會引入一個問題了,一個的APP調節音量,會不會導緻硬體的音量被調節,答案是不會:

a. 對于MixerThread
   APP對音量的設定不會影響到聲霸卡的硬體音量,
   而隻會影響APP的音頻資料的幅值(變小或放大),
   這些音頻資料最終被混合後傳給聲霸卡
   
   多個APP本身的音量設定互不影響
   
   
b. 對于DirectOutputThread
   同一時間裡隻有一個APP、隻有一個AudioTrack使用它,
   是以該AudioTrack的音量可以被DirectOutputThread直接用來設定硬體音量
           

再前面的小節中,我們一直講解的都是MixerThread,沒有過多的涉及到DirectOutputThread,在/system/etc/audio_policy.conf中可以看到如下:

hdmi {
        sampling_rates 44100|48000|192000
        channel_masks AUDIO_CHANNEL_OUT_5POINT1|AUDIO_CHANNEL_OUT_STEREO|AUDIO_CHANNEL_OUT_7POINT1
        formats AUDIO_FORMAT_PCM_16_BIT
        devices AUDIO_DEVICE_OUT_AUX_DIGITAL
        flags AUDIO_OUTPUT_FLAG_DIRECT
      }
           

其中的flags AUDIO_OUTPUT_FLAG_DIRECT代表該聲音可以被某個應用程式獨占。如果我們的應用程式傳入AUDIO_OUTPUT_FLAG_DIRECT,表示他需要尋找到一個可以獨自控制的聲霸卡,如果找個了對應的聲霸卡,其中flags AUDIO_OUTPUT_FLAG_DIRECT,之後這個應用程式可以獨占這個聲霸卡通道,不需要和其他的應用程式進行混音。在大部分android系統中,DirectOutputThread的應用并不多,大部分我們使用的是MixerThread。

在這裡我們得到了一個小小的結論,應用程式設定音量時,對音量隻是一個軟體值,其并不會影響到聲霸卡,我們可以把這個結論繼續推廣一下,下面是android手機:

08.音頻系統:第006課_音頻系統HAL分析:第001節_音量相關概念

當我按下音量鍵的時候,會出現第一幅圖,可以設定鈴聲音量,媒體音量,以及鬧鐘音量。第三幅圖示接上了藍牙耳機的圖,可以看到媒體音量的标記消失了,變成了一個藍牙音量的标記,此時按下音量鍵,他設定的是藍牙的音量。再比如,第四幅圖,我們在電話的時候,按下音量鍵,其設定的是通話的音量,同時媒體的音量被靜音了。

這些滑動條控制的應該是某一類聲音的音量,這些類就稱為Stream,從圖中可以看到,在android系統中有十幾種Stream。當我們想去調節某一個Stream音量的時候,android系統隻會出現幾個滑動條,對于手機其會有5類滑動條,對于機頂盒,所有的Stream都歸為一類(這裡利用分組的概念)。

我們知道APP應用建立AudioTrack的時候,會指定StreamType,StreamType分組為strategy,然後獲得device再找到output或者說一個播放線程。對Stream進行分類之後稱為alias(别名),一個alias包含了多個Stream,對應一個滑動條。當我們設定滑動條的時候,該alias中包含的Stream都會受到影響。

下面是對這些知識的一些總結:

a. APP設定音量時互不影響, 這是AudioTrack volume

b. stream volume
	可以引申出來: 各種stream的音量也可以單獨設定、互不影響。
	比如"音樂音量"不應該影響到"來電振鈴"、"鬧鐘"、"通話"的音量。
	
	手機音量控制界面有5種滑動條, 用于設定某種類型的聲音音量,
	但是Android系統建立AudioTrack時可以指定10種stream,
	這5種滑動條如何控制10種stream?
	必須分組!在Android源碼中稱之為"别名", 即alias
	比如在電話中, 以下5種stream的alias都是STREAM_RING,
	那麼對應的滑動條即可控制這5種stream的音量
	STREAM_SYSTEM
	STREAM_RING
	STREAM_NOTIFICATION
	STREAM_SYSTEM_ENFORCED
	STREAM_DTMF
           

APP設定的是AudioTrack的音量,使用滑動條控制的音量是stream音量。下面是APP音量的關系:

APP1音量 = AudioTrack1音量 * stream音量

APP2音量 = AudioTrack2音量 * stream音量

可以看出如果stream音量為0,則所有stream對應的APP都為零。

我們調節音量的時候,隻能通過AudioTrack與stream進行控制,那麼有沒有辦法設定有所有的stream與所有的AudioTrack呢?是有的,術語稱為master,其會把音量寫入到聲霸卡中,這樣就設定了所有的音量。當然,一可以和上面的公式一樣,再多上一個系數乘積。

以上的公式是簡化的(隻為大家友善了解),下面是複雜的:

c. 無論是AudioTrack volume、stream volume, 都是單獨設定.
   能否通過某個變量影響到所有stream、所有AudioTrack的音量?
   有!這就是 master volume, 這個值是可以直接用來控制聲霸卡的
   
d. 混音:
app1: 
data1_mix = data1_in * master_volume * stream1_volume * AudioTrack1_volume

app2: 
data2_mix = data2_in * master_volume * stream2_volume * AudioTrack2_volume

混合在一起:
data_mix = data1_mix + data2_mix
           

繼續閱讀