Android 4.4 音量調節流程分析(二)

 之前在Android 4.4 音量調節流程分析(一)裏已經有簡單的分析音量控制的流程,今天想接着繼續分析下音量大小計算的方法。對於任一播放文件而言其本身都有着固定大小的音量Volume_Max,而在AudioPolicyManagerBase.cpp文件中音量調節可以理解爲在Volume_Max的基礎上乘以係數κ(0≤κ≤1)。

  現在對AudioPolicyManagerBase.cpp中volIndexToAmpl函數做具體分析,volIndexToAmpl的函數定義如下:

 1 float AudioPolicyManagerBase::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
 2         int indexInUi)
 3 {
 4     device_category deviceCategory = getDeviceCategory(device);
 5     const VolumeCurvePoint *curve = streamDesc.mVolumeCurve[deviceCategory];
 6   
 7     // the volume index in the UI is relative to the min and max volume indices for this stream type
 8     int nbSteps = 1 + curve[VOLMAX].mIndex -
 9             curve[VOLMIN].mIndex;
10     int volIdx = (nbSteps * (indexInUi - streamDesc.mIndexMin)) /
11             (streamDesc.mIndexMax - streamDesc.mIndexMin);
12 
13     // find what part of the curve this index volume belongs to, or if it's out of bounds
14     int segment = 0;
15     if (volIdx < curve[VOLMIN].mIndex) {         // out of bounds
16         return 0.0f;
17     } else if (volIdx < curve[VOLKNEE1].mIndex) {
18         segment = 0;
19     } else if (volIdx < curve[VOLKNEE2].mIndex) {
20         segment = 1;
21     } else if (volIdx <= curve[VOLMAX].mIndex) {
22         segment = 2;
23     } else {                                                               // out of bounds
24         return 1.0f;
25     }
26 
27     // linear interpolation in the attenuation table in dB
28     float decibels = curve[segment].mDBAttenuation +
29             ((float)(volIdx - curve[segment].mIndex)) *
30                 ( (curve[segment+1].mDBAttenuation -
31                         curve[segment].mDBAttenuation) /
32                     ((float)(curve[segment+1].mIndex -
33                             curve[segment].mIndex)) );
34 
35     float amplification = exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 )
36 
37     return amplification;
38 }

  在該段代碼內,主要是獲取以下的7個變量值:

  1.deviceCategory:Android系統中設備種類有如下三種,即DEVICE_CATEGORY_HEADSET,DEVICE_CATEGORY_SPEAKER & DEVICE_CATEGORY_EARPIECE。若當前使用Speaker播放音頻流時,則deviceCategory即對應DEVICE_CATEGORY_SPEAKER;

  

  2.curve:音量曲線是由Audio_Stream & device_Category兩者共同決定,所有匹配類型都可以在sVolumeProfiles矩陣中獲得,以Audio_Stream = AUDIO_STREAM_MUSIC & device_Category = DEVICE_CATEGORY_SPEAKER爲例,則其對應的音量曲線爲 sSpeakerMediaVolumeCurve;

sSpeakerMediaVolumeCurve:(以該音量曲線爲例作數值計算)

1 const AudioPolicyManagerBase::VolumeCurvePoint
2     AudioPolicyManagerBase::sSpeakerMediaVolumeCurve[AudioPolicyManagerBase::VOLCNT] = {
3     {1, -59.1f}, {20, -48.3f}, {60, -24.4f}, {100, 0.0f}
4 };

  從sSpeakerMediaVolumeCurve數組可以知道是由4個點來將音量曲線分爲4個部分,分別爲1~20、20~60、60~100。其中每個點中參數含義爲:

class VolumeCurvePoint
{
public:
    int mIndex;//百分制下標
    float mDBAttenuation;//衰減
}; 

  3.nbSteps:爲了避免計算時出現循環小數,系統中將UI界面VolumeIndex轉化爲0~100,以sSpeakerMediaVolumeCurve爲例,curve[VOLMAX].mIndex = 100,curve[VOLMIN].mIndex = 1,所以nbSteps = 1 + 100 -1 = 100;

 

  4.volIdx:volIdx的求解過程其實就是將UI界面的音量Index轉化爲百進制的過程,其中AudioStream對應的indexInUi_Max可以在AudioService.java中獲得,STREAM_MUSIC對應數值爲15,故streamDesc.mIndexMax = 15,streamDesc.mIndexMin = 0,則volIdx = (20/3)*indexInUi。

//AudioService.java
/** @hide Maximum volume index values for audio streams */
private static final int[] MAX_STREAM_VOLUME = new int[] {
     5,  // STREAM_VOICE_CALL
     7,  // STREAM_SYSTEM
     7,  // STREAM_RING
     15, // STREAM_MUSIC
     7,  // STREAM_ALARM
     7,  // STREAM_NOTIFICATION
     15, // STREAM_BLUETOOTH_SCO
     7,  // STREAM_SYSTEM_ENFORCED
     15, // STREAM_DTMF
     15  // STREAM_TTS
}; 

  5.segment:是用來確定UI音量界面上的VolumeIndex轉化爲百進制處於哪一個區間內。

 

  6.decibels:VolumeIndex對應的音量衰減,單位爲dB。其計算公式如下圖所示:

                    

  若想實現speaker每音階之間的衰減差爲M(dB),其計算方法就是計算decibels_Index_N & decibels_Index_(N+1)之間的差值。爲了方便計算,可以默認N & N+1屬於同一segment,這樣

                                                      

  因爲curve[VOLMAX].mDBAttenuation一般爲0,即不衰減狀態(當然也有可能爲負數,但不管怎樣,curve[VOLMAX].mDBAttenuation是最容易確定的值),所以一般計算是從segment = 2開始計算,這樣在60~100區間內Δdecibels的值就爲:

  Δdecibels = (20/3)*((0 - curve[2].mDBAttenuation)/(100 - 60)) = -(curve[2].mDBAttenuation/6)

  令Δdecibels = M,則curve[2].mDBAttenuation = -6M,依次類推curve[1].mDBAttenuation = -12M,curve[0].mDBAttenuation = -15M。

 

  7.amplification:放大/縮小倍數。將求得的decibels帶入公式就可以直接求到,沒有什麼特別要說的。

  總結:該篇文章以sSpeakerMediaVolumeCurve爲例,描述了音量衰減值的計算過程。其它音量曲線調節可以按照該方法同樣實現。

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