当按键按下时,底层上报事件给KeyguardUpdateMonitor,窗口管理器WindowManager,从KeyguardUpdateMonitor获取具体按键信息,如果是Volume +/- 则直接由AudioManager.java处理,调用方法adjustSuggestedStreamVolume,其参数direction包括ADJUST_LOWER(- 键)、ADJUST_RAISE(+ 键)、ADJUST_SAME(不调整),suggestedStreamType为音频流类型,flags为特殊标志位,下面会讲到。
adjustSuggestedStreamVolume方法内直接通过IAudioService获取framework层的AudioService服务,AudioService针对强制使用某种音频,通过AudioSystem的JNI从HAL层获取状态,并进行切换,再执行adjustMasterVolume / adjustSuggestedStreamVolume方法,方法内部处理了STREAM_REMOTE_MUSIC和非REMOTE_MUSIC的音量调整,STREAM_REMOTE_MUSIC是在当后台播放音乐时,不在前台运行的情况。adjustSuggestedStreamVolume先对当前stream获取在执行的streamtype类型,包括通话状态收音机播放,音乐播放等,此处需要hal层获取streamtype,得到streamtype后如果是STREAM_REMOTE_MUSIC,将清楚flags中的标志FLAG_PLAY_SOUND、FLAG_FIXED_VOLUME等。
STREAM_REMOTE_MUSIC类型继续执行adjustRemoteVolume,否则执行adjustStreamVolume,这里主要进入adjustStreamVolume方法。在adjustStreamVolume方法内检查SafeMedaiVolume在插耳机情况下需提示,如果streamtypealias为STREAM_MUSIC,且设备类型包括DEVICE_OUT_AUX_DIGITAL ,将添加flags 标志位:
flags |= AudioManager.FLAG_FIXED_VOLUME
固定不能调节音量的设备包括:
final int mFixedVolumeDevices =
AudioSystem.DEVICE_OUT_AUX_DIGITAL |
AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET | AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_ALL_USB;
DEVICE_OUT_AUX_DIGITAL 是针对HDMI类型。
最后,sendVolumeUpdate直接调用mVolumePanel.postVolumeChanged(streamType, flags) 设定并显示进度条,VolumePanel内部会根据flags 标志是否包含 FLAG_FIXED_VOLUME,设定进度条sc.seekbarView.setEnabled(false / true),VolumePanel内会有个dialog显示。至此,上层的调用过程结束。
在HAL策略上只需修改一处,AudioPolicyManager的computeVolume方法,修改如下: 修改前:
if (stream == AudioSystem::MUSIC &&
index != mStreams[stream].mIndexMin && (device == AUDIO_DEVICE_OUT_AUX_DIGITAL ||
device == AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET || device == AUDIO_DEVICE_OUT_USB_ACCESSORY || device == AUDIO_DEVICE_OUT_USB_DEVICE)) { return 1.0; }
修改后:
if (stream == AudioSystem::MUSIC &&
index != mStreams[stream].mIndexMin && (//device == AUDIO_DEVICE_OUT_AUX_DIGITAL ||
device == AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET || device == AUDIO_DEVICE_OUT_USB_ACCESSORY || device == AUDIO_DEVICE_OUT_USB_DEVICE)) { return 1.0; }
具体流程如何走到这里。
对输出策略的管理上,在插HDMI时于桌面调整音量,默认不使用HDMI输出,因为在输出设备判断上有操作:
if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) {// no sonification on aux digital (e.g. HDMI)
device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL; }
STRATEGY_SONIFICATION为在桌面时调整的声音所使用的类型,每当调整音量时,通过ToneGenerator初始化构造对应音频流的ToneGenerator桂香,借助AudioFlinger建立AudioTrack实例,在AudioFlinger内部会对音频流类型设置AudioTrack的参数。建立AudioTrack后设置优先级为1并调度运行该线程(叫线程是因为AudioTrack继承thread本分,可查看类继承)。一旦调度startTone时,AudioTrack start,经过AudioFlinger start 进行数据处理,最后通过AudioService调用AudioPolicyManager,从startoutput --> getNewDevice --> setOutputDevice --> setOutputDevice --> checkAndSetVolume --> getNewDevice --> getNewDevice 等,具体可查看log:
ToneGenerator: ToneGenerator constructor: streamType=2, volume=0.011220
AudioTrack: audiotrack 0x58ba9540 set Type 2, rate 0, fmt 1, chn 1, fcnt 0, flag 4 AudioFlinger: createTrack() sessionId: 0 AudioFlinger: createTrack() lSessionId: 26
AudioFlinger: AUDIO_OUTPUT_FLAG_FAST denied: isTimed=0 sharedBuffer=0x0 frameCount=0 mFrameCount=2048 format=1 isLinear=1 channelMask=0x1 sampleRate=44100 mSampleRate=44100 hasFastMixer=0 tid=2176 fastTrackAvailMask=0xfe dalvikvm: threadid=81: interp stack at 0x566c5000 AudioTrack: sched_setscheduler to rt, priority: 1
AudioFlinger: Track constructor name 4099, calling pid 519 AudioFlinger: acquiring 26 from 519 AudioFlinger: added new entry for 26 ToneGenerator: startTone AudioTrack: start 0x58ba9540
AudioFlinger: start(4099), calling pid 519 session 26
AudioFlinger: ? => ACTIVE (4099) on thread 0x417afb70
AudioPolicyManager: startOutput() output 2, stream 2, session 26
AudioPolicyManager: getNewDevice() STRATEGY_SONIFICATION selected device 2 output= 2
AudioPolicyManager: getNewDevice() selected device 2 output= 2
AudioPolicyManager: setOutputDevice() output 2 device 0002 delayMs 0
AudioPolicyManager: checkDeviceMuteStrategies outputDesc = 0x41630950 prevDevice = 2 delayMs = 0
AudioPolicyManager: setOutputDevice() setting same device 0002 or null device for output 2
AudioPolicyManager: checkAndSetVolume stream = 2 index = 7 output = 2 device = 0x2 delayMs = 0 force = 0
AudioPolicyManager: getNewDevice() STRATEGY_SONIFICATION selected device 2 output= 2
AudioPolicyManager: getNewDevice() selected device 2 output= 2 AudioFlinger: mWaitWorkCV.broadcast
AudioFlinger: thread 0x4179f050 type 0 TID 447 waking up
这里会在getNewDevice时获取输出设备,会进入策略方法进行判断,需要去掉STRATEGY_SONIFICATION部分限制,如下:
if ((device2 == AUDIO_DEVICE_NONE))// && (strategy != STRATEGY_SONIFICATION)) {// no sonification on aux digital (e.g. HDMI)
device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL; }
以上从策略层进行修改,另一种方法是从framework进行修改,从VolumePanle中修改StreamResources中的值:
VoiceStream(AudioManager.STREAM_VOICE_CALL, R.string.volume_icon_description_incall, R.drawable.ic_audio_phone, R.drawable.ic_audio_phone, false) 为,
VoiceStream(AudioManager.STREAM_MEDIA,
R.string.volume_icon_description_incall, R.drawable.ic_audio_phone, R.drawable.ic_audio_phone, false)
但第二种修改不适合带modem功能的设备,第二种修改也就是直接将通话改为多媒体类型。