调节音量的流程

以下是调节音量的流程:

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

时间: 2024-10-12 07:08:46

调节音量的流程的相关文章

XAudio2学习之调节音量

XAudio2音量调节分为全局和声道调节以及连接音量调节.所谓全局就是说设置了音量后会影响整个音频流的声音大小:声道调节就是说只调节某一个声道的音量大小:连接音量设置是说设置voice与其输出voice之间的声道映射音量.举个例子来说明: IXAudio2SourceVoice->IXAudio2SubmixVoice->IXAudio2MasteringVoice 由三个voice组成的音频图.IXAudio2SourceVoice为2声道,IXAudio2SubmixVoice和IXAud

【VC++技术杂谈001】音频技术之调节音量及设置静音

本文主要介绍如何使用混音器Mixer API函数实现系统音量调节,以及设置静音. 1.混音器的作用及结构 1.1混音器的作用 声卡(音频卡)是计算机进行声音处理的适配器,具有三个基本功能: (1)音乐合成发音功能 (2)混音器(Mixer)功能和数字声音效果处理器(DSP)功能 (3)模拟声音信号的输入和输出功能 混音器的作用是将来自音乐合成器.CD-ROM.话筒输入(MIC)等不同来源的声音组合在一起再输出. 1.2混音器的结构 混音器由多个目的单元(Destination)组成,如回放(Pl

android开发之GestureDetector手势识别(调节音量、亮度、快进和后退)

写UI布局: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" andr

解决Cocos2d-x进入游戏后,调节音量键不管用,要按一下返回键,音量键才可用的Bug

我们知道 处理按钮事件都是在view里做的, 而我们游戏的主界面继承了Cocos2dxGLSurfaceView 所以 应该是这个文件里对按钮的处理有问题,于是我们找到这个文件, 这个显然是2d-x的源文件,但我们抱着试一试的心理 加上自己写的按钮处理事件. 结果加上之后没有任何效果,跟没加一样,所以我们知道 不是这里的问题. 于是 我们再思考,根据那些错误提示. 具体我们也看不懂为什么,但是在进入游戏后点击调节音量键,就会出现这一行代码,从上往下看 不是 EditText就是 Cocos2dx

一键调节音量

一键调节音量 Ctrl+→:增大音量并显示当前音量: Ctrl+←:减小音量并显示当前音量. Ctrl+小键盘*:静音 ^Right:: Goto, vol+ return ^Left:: ;还可以这样:>^left::SoundSet -5 Goto, vol- return ^NumpadMult::Send {Volume_mute} vol+: vol-: GUI_W=700 ;设置gui的宽度; GUI_H=80 ;设置gui的高度(包括上下文字在内了) Gui_X :=(A_Scre

ffplay调节音量大小

在 SDL 音频回调函数里面用 SDL_MixAudio 来进行音量调节,但ffplay里没有用这个函数,如果有调节音量的需求,可以使用下面方法: ffplay.c里面将这句memcpy(stream, (uint8_t * )ivs.audio_buf + ivs.audio_buf_index, len1); 改成 SDL_MixAudio(stream, (uint8_t * )ivs.audio_buf + ivs.audio_buf_index, len1, volume); volu

Android声音焦点----从音乐回到Luncher调节音量显示的是Music的音量

声音的类型有:定义在AudioSystem.java文件中 /* The default audio stream */ public static final int STREAM_DEFAULT = -1; /* The audio stream for phone calls */ public static final int STREAM_VOICE_CALL = 0; /* The audio stream for system sounds */ public static fin

Android audioManager解决MediaPlayer AudioTrack 调节音量问

在听筒模式下 am.setSpeakerphoneOn(false); setVolumeControlStream(AudioManager.STREAM_VOICE_CALL); am.setMode(AudioManager.MODE_IN_CALL); 我用Mediaplayer AudioTrack调节音量总是失败 at.setStereoVolume(vol, vol); player.setVolume(vol,vol); 后来 决定用AudioManager来调节音量 Audio

Android音量设置流程干货版

1.     音量级数定义 在AudioService.java中定义了最大音量MAX_STREAM_VOLUME,手机的设置property可以覆盖它. 2.     音量初始化 initStreamVolume传入AudioPolicyManagerBase里的StreamDescriptor mStreams[AudioSystem::NUM_STREAM_TYPES]; 3.     设置主音量 主音量怎么起作用? 最终音量=主音量*流音量 4.     设置流音量 setStreamV