美文网首页我爱编程
《Android优化专题》——音频播放

《Android优化专题》——音频播放

作者: 罗拙呓 | 来源:发表于2018-04-15 15:42 被阅读0次

一、控制app的音量与播放

使用硬件音量键来控制音量

需要在Activity或者Fragment创建的时候就设置音量控制,这样确保不管App是否可见,音频控制功能都正常工作。

setVolumeControlStream(AudioManager.STREAM_MUSIC);

使用硬件的播放控制按键来控制App的音频播放

无论用户通过手机或者线控耳机等按下哪些控制按钮,比如播放、暂停,系统都会广播一个带有ACTION_MEDIA_BUTTON的Intent。

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

Receiver需要判断广播来自哪个按钮

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

二、管理音频焦点

请求获取音频焦点

requestAudioFocus() 来获取到音频流焦点。

  • 短暂的焦点锁定:当期待播放一个短暂的音频时候(比如推送声音)
  • 永久的焦点锁定:当计划播放可预期到的较长的音频时候(比如播放音乐)

我们必须在开始播放前请求音频焦点,比如用户此时点击了播放按钮

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.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
    // Start playback.  
}

一旦结束播放,需要调用abandonAudioFocus()方法,通知系统说不再需要获取焦点并且取消注册AudioManager.OnAudioFocusChangeListener的焦点。

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

当请求短暂音频焦点,我们可以选择是否开启"ducking",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.  
}

处理失去音频焦点

  • 失去短暂焦点:在这种情况下,暂停当前音频的播放或者降低音量,需要准备恢复播放在重新获取到焦点之后。
  • 失去永久焦点:假设另一个程序开始播放音乐,此时我们的程序就应该彻底结束。停止播放,放弃自己的音频焦点。
  • Ducking:降低音量,让其余短暂声音突出,之后恢复原音量。
OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
    public void onAudioFocusChange(int focusChange) {
        if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT
            // Pause playback  
            //失去短暂焦点
        } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
            // Resume playback
            //恢复焦点   
        } else if (focusChange==AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK
            // Lower the volume  
        } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
    am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);
            am.abandonAudioFocus(afChangeListener);
            // Stop playback  
            // 失去永久焦点
        }
    }
};

三、音频设备的相关问题

检测目前正在使用的硬件设备

可以使用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的intent。我们只需要接受这种广播,对其进行处理即可。

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

相关文章

网友评论

    本文标题:《Android优化专题》——音频播放

    本文链接:https://www.haomeiwen.com/subject/qgwdkftx.html