一、使用音量键控制app的播放音量:
setVolumeControlStream(AudioManager.STREAM_MUSIC);
二、使用耳机的实体按键控制app音频的播放(play,pause,stop,skip,previous):
当用户按下其中一个按键时,系统会发出广播,action为 ACTION_MEDIA_BUTTON,
所以为了让你的app能够相应相应的广播,应该在注册一个广播接收者,如:
<receiver android:name=".RemoteControlReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
广播接收者必须能对不同的按键做出正确的响应,具体是哪个按键按下的信息包含在了广播Intent的 EXTRA_KEY_EVENT键值对中,
可以从该键值对中获取相应信息,如:
public class RemoteControlReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())) {
KeyEvent event = (KeyEvent)intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
if (KeyEvent.KEYCODE_MEDIA_PLAY == event.getKeyCode()) {
// Handle key press.
}
}
}
}
三、注册多媒体按钮接收者:
AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);
...
// Start listening for button presses
am.registerMediaButtonEventReceiver(RemoteControlReceiver);
...
// Stop listening for button presses
am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
为了防止多个音频播放app同时播放音频,Android使用音频焦点(Audio Focus)机制,只有拥有音频焦点的app才能播放音频。
请求音频焦点:
在你的app开始播放前,需要请求对应音频流的音频焦点,可以调用requestAudioFocus()方法,如果返回值为 AUDIOFOCUS_REQUEST_GRANTED,
则请求成功,可以指定请求的音频焦点是暂时的或永久的。如请求永久音频焦点:
AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);
...
// Request audio focus for playback
int result = am.requestAudioFocus(afChangeListener,
// Use the music stream.
AudioManager.STREAM_MUSIC,
// Request permanent focus.
AudioManager.AUDIOFOCUS_GAIN);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
am.registerMediaButtonEventReceiver(RemoteControlReceiver);
// Start playback.
}
当播放结束的时候记得调用abandonAudioFocus()方法,这个方法告诉系统你不在使用音频焦点了,如:
// Abandon audio focus when playback complete
am.abandonAudioFocus(afChangeListener);
注:afChangeListener是 AudioManager.OnAudioFocusChangeListener类.
在请求暂时的音频焦点时,可以选择是否激活"ducking"功能,通常来说,当一个app失去音频焦点时,应该停止音频的播放,
而通过请求允许"ducking"的暂时焦点,可以允许app在失去焦点只时减小音量,如:
// Request audio focus for playback
int result = am.requestAudioFocus(afChangeListener,
// Use the music stream.
AudioManager.STREAM_MUSIC,
// Request permanent focus.
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK);
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
// Start playback.
}
焦点丢失可分为暂时焦点丢失和永久焦点丢失,当只是暂时失去了焦点时,我们应该暂停播放,这样当再次获得焦点时可以继续播放,
如果是永久的失去了焦点,说明用户开启了其他的app进行音频播放,这时就应该取消注册的媒体按钮接受者和音频焦点的监听,如:
AudioManager.OnAudioFocusChangeListener afChangeListener =
new AudioManager.OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT) {
// Pause playback
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
// Resume playback
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
am.abandonAudioFocus(afChangeListener);
// Stop playback
}
}
};
当获得的焦点具有"ducking"功能,则当失去暂时焦点时可以只是降低音量,如:
OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
public void onAudioFocusChange(int focusChange) {
if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
// Lower the volume
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
// Raise it back to normal
}
}
};
六、协调音频输出的硬件(内置扬声器,耳机插孔,蓝牙等):
判断音频输出到哪个硬件上,通过AudioManager,如:
if (isBluetoothA2dpOn()) {
// Adjust output for Bluetooth.
} else if (isSpeakerphoneOn()) {
// Adjust output for Speakerphone.
} else if (isWiredHeadsetOn()) {
// Adjust output for headsets
} else {
// If audio plays and noone can hear it, is it still playing?
}
处理音频输出硬件的改变:当耳机拔出,蓝牙不再连接时,音频自动输出到内置扬声器上,如果
扬声器的音量很大,就可能造成意外的噪音,此时系统会发出action为 ACTION_AUDIO_BECOMING_NOISY
的广播,如果能够注册一个广播接受者对该广播进行处理,如暂停播放,会提高用户体验,如:
private class NoisyAudioStreamReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
// Pause the playback
}
}
}
private IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
private void startPlayback() {
registerReceiver(myNoisyAudioStreamReceiver(), intentFilter);
}
private void stopPlayback() {
unregisterReceiver(myNoisyAudioStreamReceiver);
}