Android开发者需要利用不同的接口来进行音频资源的播放,AudioManager通过音频服务,为上层提供了音量和铃声模式控制的接口,铃声模式控制包括扬声器、耳机、蓝牙等是否打开,麦克风是否静音等。在开发多媒体应用时会经常用到AudioManager。
利用AudioManager来管理音量和铃声模式控制,通过和MediaPlayer、MediaRecorder等协同即可完成多媒体的播放,AudioManager是与UI层之间交互的接口。AudioManager是AudioService和Audio System的上层封装。
AudioManager常用的方法如下:
getService() //获取音频服务
isSpeakerphoneOn() //判断扬声器是否打开
adjustStreamVolume() //调节流的音量,需要指定流的类型
setRingerMode() //设置铃声模式,铃声模式分正常、静音、振动3种模式
isBluetoothScoOn() //判断蓝牙SCO是否打开
isBluetoothA2dpOn() //判断蓝牙A2DP是否打开
isWiredHeadsetOn() //判断有线耳机是否打开
isMicrophoneMute() //判断麦克风是否静音
AudioManager与Audio Service的关系如下图所示:
Audio Manager与Audio Service的关系图]
为了进行音频的管理,首先需要获得音频服务,获得音频服务的方法为:
private static IAudioService getService()
{
if (sService !=null) {
return sService;
}
IBinder b=ServiceManager.getService(Context.AUDIO_SERVICE);
sService=IAudioService.Stub.asInterface(b);
return sService;
}
当音频信息发生变化时,AudioManager会广播特定的Intent给上层,具体策略如下:
当音频输出设备发生变化,如有线耳机被拔出、A2DP的音频槽被断开,或者底层的音频系统(Audio System)自动将音频切换到扬声器上时,AudioManager会向上层发送ACTION_AUDIO_BECOMING_NOISY消息,此时应用应采用暂停、降低音量或者其他策略来减小用户体验上感受到的噪音。
当铃音模式被改变时,AudioManager会向上层发送RINGER_MODE_ CHANGED_ACTION消息。
AudioManager为上层提供的铃声包括:静音(RINGER_MODE_SILENT)、振动(RINGER_MODE_VIBRATE)、标准(RINGER_MODE_NORMAL)等模式。
AudioManager为上层提供的音频类型包括:呼叫(STREAM_VOICE_CALL)、系统音(STREAM_SYSTEM)、电话铃声(STREAM_RING)、音乐播放(STREAM_MUSIC)、闹钟(STREAM_ALARM)、提示音(STREAM_ NOTIFICATION)、蓝牙接听电话(STREAM_BLUETOOTH_SCO)、部分如和日本所需的增强型系统音(STREAM_SYSTEM_ENFORCED)、DTMF音(STREAM_DTMF)、TTS音(STREAM_TTS)。这些音频类型均是AudioManager对底层音频系统的封装。
当多个音频资源并发、冲突时,Android支持排他性播放,方法为:AudioManager::setStreamSolo(int streamType, boolean state)和AudioManager:: setStreamMute(int streamType, boolean state)。其中AudioManager::setStreamSolo()表示将其他音频流静音,AudioManager::setStreamMute()表示将某一音频流静音。
在AudioManager中还定义了与有线耳机、蓝牙耳机、麦克风的交互和状态判断。以PhoneApp.java为例,当收到ACTION_HEADSET_PLUG消息时,PhoneAppBroadcastReceiver会发送EVENT_WIRED_HEADSET_PLUG 给处理函数,处理过程如下:
代码10-1 PhoneApp对ACTION_HEADSET_PLUG的处理
case EVENT_WIRED_HEADSET_PLUG:
Phone.State phoneState=phone.getState();
if (phoneState==Phone.State.OFFHOOK) {
if (!isShowingCallScreen() &&
(mBtHandsfree==null||!mBtHandsfree.isAudioOn())) {
if (!isHeadsetPlugged()) {
SpeakerMode(getApplicationContext());
} else {
PhoneUtils.turnOnSpeaker(getApplicationContext(), false, false);
}
}
}
updateProximitySensorMode(phoneState);
if (mTtyEnabled) {
sendMessage(obtainMessage(EVENT_TTY_PREFERRED_MODE_CHANGED, 0));
}
break;