處理音訊輸出的變化

使用者預期能夠控制音訊應用程式的音量。標準行為包括使用音量控制選項 (裝置上的按鈕或旋鈕,或 UI 中的滑桿),以及避免在使用時,耳機等周邊裝置突然斷開連線而突然播放出聲。

使用音量控制

當使用者在遊戲或音樂應用程式中按下音量鍵時,音量應會變更,即使播放器在歌曲之間暫停,或是目前遊戲位置沒有音樂,也一樣。

Android 會使用不同的音訊串流播放音樂、鬧鐘、通知、來電鈴聲、系統音效、通話音量和 DTMF 音效。這樣一來,使用者就能個別控制各個串流的音量。

根據預設,按下音量控制鍵會修改有效音訊串流的音量。如果應用程式目前沒有播放任何內容,按下音量鍵會調整音樂音量 (或在 Android 9 之前調整鈴聲音量)。

除非您的應用程式是鬧鐘,否則應使用 AudioAttributes.USAGE_MEDIA 播放音訊。

為確保音量控制項調整正確的串流,您應呼叫 setVolumeControlStream(),並傳入與您從 AudioAttributes.getVolumeControlStream 擷取的屬性相符的串流類型。

Kotlin

setVolumeControlStream(AudioManager.STREAM_MUSIC)

Java

setVolumeControlStream(AudioManager.STREAM_MUSIC);

請在應用程式的生命週期中發出這個呼叫,通常是從控制媒體的活動或片段的 onResume() 方法中發出。這樣一來,只要目標活動或片段可見,系統就會將音量控制項連結至 STREAM_MUSIC

以程式輔助的方式控制串流音量

在極少數情況下,您可以透過程式設定音訊串流的音量。例如,當應用程式取代現有的 UI 時。我們不建議這麼做,因為 Android AudioManager 會將所有相同類型的音訊串流混合在一起。這些方法會變更使用串流的每個應用程式音量。請避免使用以下字詞:

使用固定音量裝置

部分裝置 (例如 Chromebook 和 Android Automotive OS 汽車) 具有音量控制選項,但不允許應用程式使用前述的 AudioManager 方法來變更音訊串流的音量。這類裝置稱為固定音量裝置。您可以呼叫 isVolumeFixed(),瞭解應用程式是否在固定音量的裝置上執行。

音訊應用程式應提供平衡功能,讓使用者調整輸出音量,以便與可能在同一串流中播放的其他應用程式保持平衡。在固定音量裝置上,應用程式應將其自身的音量控制項連結至適當的 setVolume() 方法:

球員 方法
AudioTrack AudioTrack.setVolume()
MediaPlayer MediaPlayer.setVolume()
ExoPlayer 使用 SimpleExoPlayer.setVolume() 設定基礎 AudioTrack 的音量。
網路 設定 HTMLMediaElementvolume 屬性

請勿製造噪音

使用者可以透過多種方式,透過 Android 裝置享受音訊。大多數裝置都內建喇叭,並提供可連接有線耳機的耳機插孔,許多裝置也支援藍牙連線和 A2DP 音訊。

當耳機拔除或藍牙裝置連線中斷時,音訊串流會自動重新導向至內建喇叭。如果你以高音量聆聽音樂,可能會聽到噪音。

在這種情況下,使用者通常會預期應用程式會暫停播放音樂,並提供螢幕上的播放控制項。其他應用程式 (例如不含控制項的遊戲) 應可繼續播放。使用者可以使用裝置的硬體控制項調整音量。

當音訊輸出切換回內建喇叭時,系統會廣播 ACTION_AUDIO_BECOMING_NOISY 意圖。您應建立 BroadcastReceiver,在播放音訊時監聽此意圖。接收器應如下所示:

Kotlin

private class BecomingNoisyReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        if (intent.action == AudioManager.ACTION_AUDIO_BECOMING_NOISY) {
            // Pause the playback
        }
    }
}

Java

private class BecomingNoisyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
      if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
          // Pause the playback
      }
    }
}

開始播放時註冊接收器,停止播放時取消註冊。如果您按照本指南的說明設計應用程式,這些呼叫應會顯示在 onPlay()onStop() 媒體工作階段回呼中。

Kotlin

private val intentFilter = IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY)
private val myNoisyAudioStreamReceiver = BecomingNoisyReceiver()

private val callback = object : MediaSessionCompat.Callback() {

    override fun onPlay() {
        registerReceiver(myNoisyAudioStreamReceiver, intentFilter)
    }

    override fun onStop() {
        unregisterReceiver(myNoisyAudioStreamReceiver)
    }
}

Java

private IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
private BecomingNoisyReceiver myNoisyAudioStreamReceiver = new BecomingNoisyReceiver();

MediaSessionCompat.Callback callback = new
MediaSessionCompat.Callback() {
  @Override
  public void onPlay() {
    registerReceiver(myNoisyAudioStreamReceiver, intentFilter);
  }

  @Override
  public void onStop() {
    unregisterReceiver(myNoisyAudioStreamReceiver);
  }
}