《Android優(yōu)化專題》——音頻播放

一、控制app的音量與播放

使用硬件音量鍵來控制音量

需要在Activity或者Fragment創(chuàng)建的時(shí)候就設(shè)置音量控制,這樣確保不管App是否可見,音頻控制功能都正常工作。

setVolumeControlStream(AudioManager.STREAM_MUSIC);

使用硬件的播放控制按鍵來控制App的音頻播放

無論用戶通過手機(jī)或者線控耳機(jī)等按下哪些控制按鈕,比如播放、暫停,系統(tǒng)都會(huì)廣播一個(gè)帶有ACTION_MEDIA_BUTTON的Intent。

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

Receiver需要判斷廣播來自哪個(gè)按鈕

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

如何注冊監(jiān)聽和取消監(jiān)聽

AudioManager am = mContext.getSystemService(Context.AUDIO_SERVICE);
...

// Start listening for button presses
am.registerMediaButtonEventReceiver(RemoteControlReceiver);
...

// Stop listening for button presses
am.unregisterMediaButtonEventReceiver(RemoteControlReceiver);

二、管理音頻焦點(diǎn)

請求獲取音頻焦點(diǎn)

requestAudioFocus() 來獲取到音頻流焦點(diǎn)。

  • 短暫的焦點(diǎn)鎖定:當(dāng)期待播放一個(gè)短暫的音頻時(shí)候(比如推送聲音)
  • 永久的焦點(diǎn)鎖定:當(dāng)計(jì)劃播放可預(yù)期到的較長的音頻時(shí)候(比如播放音樂)

我們必須在開始播放前請求音頻焦點(diǎn),比如用戶此時(shí)點(diǎn)擊了播放按鈕

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

一旦結(jié)束播放,需要調(diào)用abandonAudioFocus()方法,通知系統(tǒng)說不再需要獲取焦點(diǎn)并且取消注冊AudioManager.OnAudioFocusChangeListener的焦點(diǎn)。

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

當(dāng)請求短暫音頻焦點(diǎn),我們可以選擇是否開啟"ducking",Ducking機(jī)制可以允許音頻間歇性短暫播放??梢宰屍渌鸄pp繼續(xù)播放,僅在短暫的時(shí)間內(nèi)降低自己的音量。

// 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.  
}

處理失去音頻焦點(diǎn)

  • 失去短暫焦點(diǎn):在這種情況下,暫停當(dāng)前音頻的播放或者降低音量,需要準(zhǔn)備恢復(fù)播放在重新獲取到焦點(diǎn)之后。
  • 失去永久焦點(diǎn):假設(shè)另一個(gè)程序開始播放音樂,此時(shí)我們的程序就應(yīng)該徹底結(jié)束。停止播放,放棄自己的音頻焦點(diǎn)。
  • Ducking:降低音量,讓其余短暫聲音突出,之后恢復(fù)原音量。
OnAudioFocusChangeListener afChangeListener = new OnAudioFocusChangeListener() {
    public void onAudioFocusChange(int focusChange) {
        if (focusChange == AUDIOFOCUS_LOSS_TRANSIENT
            // Pause playback  
            //失去短暫焦點(diǎn)
        } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
            // Resume playback
            //恢復(fù)焦點(diǎn)   
        } 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  
            // 失去永久焦點(diǎn)
        }
    }
};

三、音頻設(shè)備的相關(guān)問題

檢測目前正在使用的硬件設(shè)備

可以使用AudioManager來查詢某個(gè)音頻是否輸出到揚(yáng)聲器,有線耳機(jī)還是藍(lán)牙上。

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

處理音頻輸出設(shè)備的改變

當(dāng)耳機(jī)線被拔出,或者藍(lán)牙耳機(jī)連接斷開時(shí),如果在播放音樂/視頻,為了用戶體驗(yàn),避免突如其來的揚(yáng)聲器播放,我們通常做法是暫停此時(shí)正在播放的音樂/視頻。

在這種情況下,系統(tǒng)會(huì)廣播帶有ACTION_AUDIO_BECOMING_NOISY的intent。我們只需要接受這種廣播,對(duì)其進(jìn)行處理即可。

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容