該小節我們開始講解音量調節,首先我們來回顧一下之前的知識,我們知道android系統可以支援一個或者多個聲霸卡,一般來說,每個聲霸卡有輸出,或者輸入共功能。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TPR1kMjpXT4FkeNBDOsJGcohVYsR2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZwpmL2YTN5EjMxATMxATNwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
對于他的輸出功能,在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手機:
當我按下音量鍵的時候,會出現第一幅圖,可以設定鈴聲音量,媒體音量,以及鬧鐘音量。第三幅圖示接上了藍牙耳機的圖,可以看到媒體音量的标記消失了,變成了一個藍牙音量的标記,此時按下音量鍵,他設定的是藍牙的音量。再比如,第四幅圖,我們在電話的時候,按下音量鍵,其設定的是通話的音量,同時媒體的音量被靜音了。
這些滑動條控制的應該是某一類聲音的音量,這些類就稱為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