音声出力の変更の処理

ユーザーは、オーディオ アプリの音量を制御できることを期待します。標準的な動作には、音量コントロール(デバイスのボタンまたはノブ、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 など)には音量調節機能がありますが、アプリは上記の AudioManager メソッドを使用して音声ストリームのレベルを変更することはできません。このようなデバイスは、固定音量デバイスと呼ばれます。isVolumeFixed() を呼び出すと、アプリが固定音量デバイスで実行されているかどうかを確認できます。

オーディオ アプリには、同じストリームで再生される他のアプリと出力音量のバランスを取る機能が必要です。固定音量デバイスでは、アプリは独自の音量コントロールを、以下の表に示す適切な setVolume() メソッドに接続する必要があります。

選手 メソッド
音声トラック AudioTrack.setVolume()
MediaPlayer MediaPlayer.setVolume()
ExoPlayer 基礎となる AudioTrack の音量を設定する SimpleExoPlayer.setVolume() を使用します。

突然の大音量再生の防止

Android デバイスでオーディオを楽しむには、いくつかの方法があります。ほとんどのデバイスはスピーカーと有線ヘッドセット用のヘッドフォン端子を内蔵し、その多くが Bluetooth 接続と A2DP オーディオのサポートも備えています。

ヘッドセットが充電器に接続されていないか、Bluetooth デバイスの接続が解除されると、音声ストリームは自動的に内蔵スピーカーに再ルーティングされます。大音量で聴いていると うるさい印象になります

ユーザーは通常、このような場合に、画面上の再生コントロールを備えた音楽プレーヤーで再生が一時停止することを期待します。コントロールのないゲームなど、他のアプリでは引き続きプレイする必要があります。ユーザーは、デバイスのハードウェア コントロールで音量を調整できます。

音声出力が内蔵スピーカーに戻ると、システムは 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);
  }
}