zoukankan      html  css  js  c++  java
  • Android 4.4 音量调节流程分析(一)

      最近在做Android Audio方面的工作,有需求是在调节Volume_Up_Key & Volume_Down_key时,Spearker or Headset每音阶的衰减变为3db左右。所以利用Source Insight分析Android源码中音量控制的流程,如有错误,欢迎指正,谢谢!  

      以下是调节音量的流程:

      Step_1.首先在调节机台Volume_Up_Key & Volume_Down_Key操作时,系统会调用到AudioManager.java中handleKeyUp & handleKeyDown函数,以 handleKeyDown函数为例:

     1 public void handleKeyDown(KeyEvent event, int stream) { 
     2         int keyCode = event.getKeyCode();
     3         switch (keyCode) {
     4             case KeyEvent.KEYCODE_VOLUME_UP:        /*KeyEvent 在KeyEvent.java中定义*/
     5             case KeyEvent.KEYCODE_VOLUME_DOWN:
     6 
     7                 int flags = FLAG_SHOW_UI | FLAG_VIBRATE;
     8 
     9                 if (mUseMasterVolume) {
    10                     adjustMasterVolume(
    11                             keyCode == KeyEvent.KEYCODE_VOLUME_UP
    12                                     ? ADJUST_RAISE
    13                                     : ADJUST_LOWER,
    14                             flags);
    15                 } else {
    16                     adjustSuggestedStreamVolume(
    17                             keyCode == KeyEvent.KEYCODE_VOLUME_UP
    18                                     ? ADJUST_RAISE
    19                                     : ADJUST_LOWER,
    20                             stream,
    21                             flags);
    22                 }
    23                 break;
    24            ... ... 
    25         }
    26     }

      其中是否进入adjustMasterVolume 函数是通过mUseMasterVolume的值判断的,而mUseMasterVolume的值是在AudioManager的构造函数中定义,其值的大小如下:mUseMasterVolume = mContext.getResources().getBoolean(com.android.internal.R.bool.config_useMasterVolume),所以首先从系统的配置文件config.xml中查找config_useMasterVolume值的大小

      <bool name="config_useMasterVolume">false</bool>

      所以handleKeyDown中 switch语句中会选择进入adjustSuggestedStreamVolume函数。

     1     public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
     2         IAudioService service = getService();
     3         try {
     4             if (mUseMasterVolume) {
     5                 service.adjustMasterVolume(direction, flags, mContext.getOpPackageName());
     6             } else {
     7                 service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags,
     8                         mContext.getOpPackageName());
     9             }
    10            ... ...
    11      }
    12 }

      Step_2.在adjustSuggestedStreamVolume函数中首先会通过binder机制得到AudioService,并将音量控制过程转入到AudioService.java中。

     1     public void adjustStreamVolume(int streamType, int direction, int flags,
     2             String callingPackage) {
     3     ... ...
     4     /*音量调大时,若要超过SafeMediaVolume时,系统会弹出对话框给予确认*/
     5             if ((direction == AudioManager.ADJUST_RAISE) &&
     6                     !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
     7                 Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
     8                 mVolumePanel.postDisplaySafeVolumeWarning(flags);
     9             } else if (streamState.adjustIndex(direction * step, device)) {
    10                 sendMsg(mAudioHandler,
    11                         MSG_SET_DEVICE_VOLUME,             /*需要处理的Message值*/
    12                         SENDMSG_QUEUE,
    13                         device,
    14                         0,
    15                         streamState,
    16                         0);
    17             }
    18         }
    19         int index = mStreamStates[streamType].getIndex(device);
    20         sendVolumeUpdate(streamType, oldIndex, index, flags);       /*通知上层更新Volume*/
    21     }

      在adjustStreamVolume 中会通过sendMsg的方式来将调节音量的事件加入到消息列队SENDMSG_QUENE中,当轮寻到该Message时,系统会调用handleMessage函数来处理该Message,此时该处对应的Message为MSG_SET_DEVICE_VOLUME。

     1        public void handleMessage(Message msg) {
     2 
     3             switch (msg.what) {
     4 
     5                 case MSG_SET_DEVICE_VOLUME:
     6                     setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
     7                     break;
     8 
     9                 case MSG_SET_ALL_VOLUMES:
    10                     setAllVolumes((VolumeStreamState) msg.obj);
    11                     break;
    12 
    13               ... ... 
    14             }
    15         }

      可以发现当msg.what =  MSG_SET_DEVICE_VOLUME时,会进到setDeviceVolume函数中,继续往下分析:

     1         private void setDeviceVolume(VolumeStreamState streamState, int device) {
     2 
     3             // Apply volume
     4             streamState.applyDeviceVolume(device);
     5 
     6             // Apply change to all streams using this one as alias
     7          ... ...
     8 
     9             // Post a persist volume msg
    10          ... ...     
    11         }

      applyDeviceVolume就是将音量Volume设置到对应的设备Device上,继续往下分析:

     1         public void applyDeviceVolume(int device) {
     2             int index;
     3             if (isMuted()) {
     4                 index = 0;
     5             } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
     6                        mAvrcpAbsVolSupported) {
     7                 index = (mIndexMax + 5)/10;
     8             } else {
     9                 index = (getIndex(device) + 5)/10;
    10             }
    11             AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
    12         }

      此处VolumeIndex就是对应UI界面调节音量时,音量所处在的位置下标。在AudioService.java中定义了每种音频流对应的Max-Index,在AudioManager.java中定义了每种音频流在第一次刷机后默认的Index。

      Step_3.此时得到音量的下标Index后,会调用AudioSystem.java中的setStreamVolumeIndex函数中来得到此时音量的放大倍数。通过JNI层调用到AudioSystem.cpp文件中的 setStreamVolumeIndex中。

    1 status_t AudioSystem::setStreamVolumeIndex(audio_stream_type_t stream,
    2                                            int index,
    3                                            audio_devices_t device)
    4 {
    5     const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
    6     if (aps == 0) return PERMISSION_DENIED;
    7     return aps->setStreamVolumeIndex(stream, index, device);
    8 }

      setStreamVolumeIndex函数中比较简单,通过StrongPointer来与AudioPolicyService建立联系,将AudioSystem中的setStreamVolumeIndex操作移到aps中完成。下面进入到AudioPolicyService.cpp文件中的setStreamVolumeIndex继续分析:

     1 status_t AudioPolicyService::setStreamVolumeIndex(audio_stream_type_t stream,
     2                                                   int index,
     3                                                   audio_devices_t device)
     4 {
     5     ... ... 
     6     if (mpAudioPolicy->set_stream_volume_index_for_device) {
     7         return mpAudioPolicy->set_stream_volume_index_for_device(mpAudioPolicy,
     8                                                                 stream,
     9                                                                 index,
    10                                                                 device);
    11     } else {
    12         return mpAudioPolicy->set_stream_volume_index(mpAudioPolicy, stream, index);
    13     }
    14 }

      Step_4.AudioPolicyService.cpp作为bn端,其对应的bp端为AudioPolicyManagerBase.cpp。在当前函数的if语句中判断AudioPolicyManagerBase.cpp文件中是否存在setStreamVolumeIndexForDevice函数,条件成立则会选择setStreamVolumeIndexForDevice作为函数入口端;否则选择setStreamVolumeIndex作为函数入口。现在进入AudioPolicyManagerBase.cpp中文件中完成最后的分析:

     1 status_t AudioPolicyManagerBase::setStreamVolumeIndex(AudioSystem::stream_type stream,
     2                                                       int index,
     3                                                       audio_devices_t device)
     4 {
     5     ... ...  
     6     // compute and apply stream volume on all outputs according to connected device
     7     status_t status = NO_ERROR;
     8     for (size_t i = 0; i < mOutputs.size(); i++) {
     9         audio_devices_t curDevice =
    10                 getDeviceForVolume(mOutputs.valueAt(i)->device());
    11         if ((device == AUDIO_DEVICE_OUT_DEFAULT) || (device == curDevice)) {
    12             status_t volStatus = checkAndSetVolume(stream, index, mOutputs.keyAt(i), curDevice);
    13             if (volStatus != NO_ERROR) {
    14                 status = volStatus;
    15             }
    16         }
    17     }
    18     return status;
    19 }

    继续调用checkAndSetVolume函数:

     1 status_t AudioPolicyManagerBase::checkAndSetVolume(int stream,
     2                                                    int index,
     3                                                    audio_io_handle_t output,
     4                                                    audio_devices_t device,
     5                                                    int delayMs,
     6                                                    bool force)
     7 {
     8 
     9     // do not change actual stream volume if the stream is muted
    10     ... ...
    11     // do not change in call volume if bluetooth is connected and vice versa
    12     ... ...
    13     audio_devices_t checkedDevice = (device == AUDIO_DEVICE_NONE) ? mOutputs.valueFor(output)->device() : device;
    14     float volume = computeVolume(stream, index, checkedDevice);
    15 
    16     ... ...
    17   mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);/*将得到的volume应用到对应的output中*/
    18 }

      在checkAndSetVolume中可以知道volume是通过computeVolume得到的。继续向下分析:

    float AudioPolicyManagerBase::computeVolume(int stream,
                                                int index,
                                                audio_devices_t device)
    {
        ... ...
        volume = volIndexToAmpl(device, streamDesc, index);
        ... ...
        return volume;
    }

      终于到了最后volIndexToAmpl,从函数名就可以知道该函数的作用是通过volIndex得到音量放大倍数。

    float AudioPolicyManagerBase::volIndexToAmpl(audio_devices_t device, const StreamDescriptor& streamDesc,
            int indexInUi)
    {
        device_category deviceCategory = getDeviceCategory(device);
        const VolumeCurvePoint *curve = streamDesc.mVolumeCurve[deviceCategory];
    
        // the volume index in the UI is relative to the min and max volume indices for this stream type
        int nbSteps = 1 + curve[VOLMAX].mIndex -
                curve[VOLMIN].mIndex;
        int volIdx = (nbSteps * (indexInUi - streamDesc.mIndexMin)) /
                (streamDesc.mIndexMax - streamDesc.mIndexMin);
    
        // find what part of the curve this index volume belongs to, or if it's out of bounds
        int segment = 0;
        if (volIdx < curve[VOLMIN].mIndex) {         // out of bounds
            return 0.0f;
        } else if (volIdx < curve[VOLKNEE1].mIndex) {
            segment = 0;
        } else if (volIdx < curve[VOLKNEE2].mIndex) {
            segment = 1;
        } else if (volIdx <= curve[VOLMAX].mIndex) {
            segment = 2;
        } else {                                                               // out of bounds
            return 1.0f;
        }
    
        // linear interpolation in the attenuation table in dB
        float decibels = curve[segment].mDBAttenuation +
                ((float)(volIdx - curve[segment].mIndex)) *
                    ( (curve[segment+1].mDBAttenuation -
                            curve[segment].mDBAttenuation) /
                        ((float)(curve[segment+1].mIndex -
                                curve[segment].mIndex)) );
    
        float amplification = exp( decibels * 0.115129f); // exp( dB * ln(10) / 20 )
    
        return amplification;
    }

      其中curve代表在用设备(如SPEAKER、HEADSET & EARPIECE)播放音频流(如SYSTEM、MUSIC、ALARM、RING & TTS等)时的音量曲线,最后decibles & amplification就是我们需要求的值,其中decibles代表某一音节所对应的dB值,而amplification则是由dB值转化得到的音量放大倍数。这样整个音量调节过程到此就算完成了,具体的计算分析会放在后面继续分析。

      

  • 相关阅读:
    Meten Special Activities II
    Meten Special Activities II
    Meten Special Activities II
    Meten Special Activities II
    Meten Special Activities
    Meten Special Activities
    Meten Special Activities
    Meten Special Activities
    Meten Special Activities
    冒泡排序和选择排序
  • 原文地址:https://www.cnblogs.com/Peter-Chen/p/3856411.html
Copyright © 2011-2022 走看看