Develop -- Training(十二) -- 管理音频播放

来源:互联网 发布:网络攻防平台 编辑:程序博客网 时间:2024/05/29 04:38

控制应用程序的音量和播放

一个好的用户体验是可以遇见的。如果你的应用正在播放媒体,用户能够控制音量,你的应用程序通过使用硬件或者软件来控制设备、蓝牙耳机、耳机上的声音,这是很重要的。

同样的,在适当的情况下可用,播放、停止、暂停、跳过,前一步播放媒体键应该可以执行,在你的应用程序中他们各自对视频流使用的行为可以随时执行的。

确定哪个音频流使用

第一步创建一个可预见的音频流体验是明白你的应用将要使用哪一个音频流。

Android 维持着可以区分播放音乐、闹钟、通知。来电铃声、系统声音、在呼叫的声音、DTMF音调。这么做这要是让用户可以控制每一个独立的音频流的声音。

大部分流都被系统时间给限制了,所以除非你能代替闹钟,你将能够使用 STREAM_MUSIC 流来播放音频。

使用硬件音量键来控制你应用程序的音频音量

默认的,按住音量键能够主动修改音频音量。如果你的应用当前没有播放任何东西,按住音量键只是修改了铃声大小。

如果你进入了一个游戏或者音乐 App,这是一个很好的机会,你可以按住音量键来控制游戏或者音乐声音的大小,即使他们在当前的歌曲和没有音乐的游戏位置。

你可能会试图尝试通过按住音量键来修改当前正在听的音乐的方式。抵制冲动,Android 提供了一个方便的方法 setVolumeControlStream() 直接按住音量键来修改你指定视频流的声音。

你的应用程序确定使用音频流,你应该设置它作为声音流的目标。你应该在应用程序生命周期的早期就制作它,因为它在 Activity的生命周期只需要被唤醒一次,通常在 onCreate()方法唤醒它。这样可以确保无论何时你的应用程序总是可用的,用户期望控制声音的功能是有效的。

setVolumeControlStream(AudioManager.STREAM_MUSIC);

从这一点起,无论何时按住设备上音量键可以影响你指定的Activity 或者 Fragment的音频流总是有效的。

使用硬件播放控制键来控制应用程序的媒体播放

媒体播放按钮像是播放、暂停、停止、跳过、前进在一些手机和有线或者无限耳机中总是可用的。无论何时,用户按住硬件上的一个键,系统将会发出一个广播:ACTION_MEDIA_BUTTON

为了回应这个媒体按钮键的点击事件,你需要在清单文件中注册一个BroadcastReceiver,并且监听这个广播的 Action。

<receiver android:name=".RemoteControlReceiver">    <intent-filter>        <action android:name="android.intent.action.MEDIA_BUTTON" />    </intent-filter></receiver>

这个广播接收者要实现无论哪个键被按下所获取到的广播事件。这个Intent 包含着 EXTRA_KEY_EVENT 键,KeyEvent 类有一系列的KEYCODE_MEDIA_* 静态常量,代表着每一个被按下的媒体按钮。像KEYCODE_MEDIA_PLAY_PAUSE 和 KEYCODE_MEDIA_NEXT。

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 注册媒体按钮事件接收器。当被注册了,,你的广播接收器是所有媒体按钮广播的独家接收器。

AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);...// Start listening for button pressesam.registerMediaButtonEventReceiver(RemoteControlReceiver);...// Stop listening for button pressesam.unregisterMediaButtonEventReceiver(RemoteControlReceiver);

通常的,应用程序应该取消注册接收器,当它们变得不活跃或者看不见的时候(onStop()被回调的时候) 然而,这不是简单的媒体播放应用程序,实际上,响应媒体播放按钮是最重要的,当你的应用程序看不见因此不能通过屏幕上的UI 来控制它。

管理音频焦点

在多个应用程序可能播放音频的时候,思考怎样让他们之间互动是很重要的。为了避免和每个音乐播放器在同一时间播放,Android 使用音频焦点来中度音频播放-只有一个应用程序能够持有音频焦点来播放音频。

在你播放音频之前,它应该要求接收到音频焦点。同样的,它应该知道如何监听音频焦点的丢失,并适当的给出回应当它发生时。

请求音频焦点

在你的应用程序播放任何一个音频之前,它应该持有音频焦点,它作为一个流来使用。可以这样做的,调用 requestAudioFocus() 方法返回 AUDIOFOCUS_REQUEST_GRANTED,代表你请求成功。

你必须指定你要使用哪个流,你是否期望请求获得临时的音频焦点或者是永久的音频焦点。当你播放一个短时间音频的时候可以请求临时的焦点(例如播放一个导航语音的时候)。当你播放一个预言未来的音频的时候可以使用请求永久焦点(例如,播放音乐)。

下面代码片段音乐播放流请求永久焦点。在你播放之前,你应该立即获取焦点,如当用户按下播放或下一个游戏关卡背景音乐开始。

AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);...// Request audio focus for playbackint 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()。当你不再有焦点和取消注册 AudioManager.OnAudioFocusChangeListener 的关联,系统会收到一个通知。在这样的情况下,放弃短期焦点可以中断应用程序播放音频。

// Abandon audio focus when playback completeam.abandonAudioFocus(afChangeListener);

当你请求临时焦点时,你要增加一些附加选项:你是否想开启“ducking”。通常地,当一个在多种机体播放的音频播放程序在播放音频的时候丢失焦点,它会立即静音的。通过获取临时焦点,你可以告诉其他音频应用程序可以接收它们保持正常播放,提供给它们较低的声音,一直到它们恢复焦点。

// Request audio focus for playbackint 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.}

喇叭特别适合于应用程序使用的音频流,断断续续地,如声音驱动方向。

无论何时另一个应用程序请求音频焦点,它有一个选择通过监听你请求时的注册回调,来确定是接收临时焦点还是永久焦点。

处理丢失音频焦点

如果你的应用程序能够请求音频焦点,当另一个应用程序请求时是它会丢失焦点。你的应用程序怎样回应丢失焦点依赖于丢失焦点的方式。

只要你注册了音频焦点改变的监听,当焦点被改变时,onAudioFocusChange() 会被回调,它有一个参数是描述焦点改变事件的。具体地,这个焦点丢失事件可能反映前面焦点请求类型-永久、临时、短暂的回避允许。

一般来说,一个正在播放视频流的应用程序,失去了临时焦点会立马静音。然而在别的方面要维护相同的状态。你应该继续监听焦点的变化,一旦它从暂停恢复到拥有焦点,你应该准备继续播放。

如果焦点永久丢失,它就认为有其他应用程序开始使用音频,你的应用程序实际上就应该结束自己了。在实际的情况中,这就意味着停止播放,移除媒体按钮的监听,允许新的播放者来独自处理其他事件,放弃你的音频焦点。在这一点上,我=我们希望你在恢复播放之前要求用户发出一个动作。

监听焦点改变的代码:

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            }        }    };

Duck !

监听音量被调低

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        }    }};

处理音频被输出到硬件

用户有大量可供选择的东西,当他想从 Android 设备享受音频的时候。大部分设备都有内置扬声器、耳机孔来供有线耳机使用,但是也有许多的蓝牙耳机和支持 A2DP的音频设备。

检查硬件被使用

你的应用程序的行为可能会影响到硬件输出到哪个路由上。

如果音频当前正在被设备调用说话,你可以通过查询 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_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);}
0 0
原创粉丝点击