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值转化得到的音量放大倍数。这样整个音量调节过程到此就算完成了,具体的计算分析会放在后面继续分析。

      

  • 相关阅读:
    kafka 启动失败
    spring boot 集成 hbase
    Spring Boot Restful 乱码
    自动化工具selenium
    spring boot mssqlserver
    pyqt5
    python bytes to string
    jQuery获取Select选择的Text和 Value(转)
    第二周读书笔记《构建之法》
    第三周读书笔记《程序员修炼之道》
  • 原文地址:https://www.cnblogs.com/Peter-Chen/p/3856411.html
Copyright © 2011-2022 走看看