android音视频指南-处理音频输出的变化

2,296 阅读3分钟

翻译自Handling changes in audio output

用户希望能够控制音量的音频应用。标准行为包括使用音量控制的能力(设备上的按钮或旋钮或滑块在UI中),并避免突然大声播放如果外围像耳机断开连接时使用

使用音量控制

当用户在游戏或音乐应用程序中按下音量键时,音量应该会发生变化,即使播放器在歌曲之间暂停,或者当前游戏位置没有音乐。

Android使用单独的音频流来播放音乐、警报、通知、来电铃声、系统声音、来电音量和DTMF音调。这允许用户独立地控制每个流的音量。

默认情况下,按下音量控制将修改活动音频流的音量。如果你的应用程序当前没有播放任何内容,点击音量键可以调整铃声音量。

除非你的应用程序是闹钟,否则你应该使用STREAM_MUSIC流播放音频。

为了确保音量控制调整正确的流,您应该调用传入AudioManager.STREAM_MUSIC的setVolumeControlStream()

setVolumeControlStream(AudioManager.STREAM_MUSIC);

在应用程序的生命周期中进行此调用,通常来自控制媒体的活动或fragment的onResume()方法。这将在目标活动或fragment可见时将volume控制连接到STREAM_MUSIC

以编程方式控制stream volume

在很少的情况下,您可以通过编程方式设置音频流的音量。例如,当应用程序替换现有UI时。这是不推荐的,因为Android AudioManager将所有相同类型的音频流混合在一起。这些方法改变了使用流的每个应用程序的音量。避免使用以下方法:

  • adjustStreamVolume()
  • adjustSuggestedStreamVolume()
  • adjustVolume()
  • setStreamVolume() setStreamVolume()
  • setStreamSolo()
  • setStreamMute()

使用固定容量设备

有些设备(比如Chromebooks)有音量控制,但不允许应用程序使用上面描述的AudioManager方法来改变音频流的级别。这些被称为固定容量设备。通过调用isVolumeFixed(),您可以发现您的应用程序是否在固定容量设备上运行。

一个音频应用程序应该能够平衡它的输出音量和其他可能在同一流上播放的应用程序。在固定容量设备上,应用程序应该将自己的音量控制连接到下表中相应的setVolume()方法:

Player Method
AudioTrack AudioTrack.setVolume()
MediaPlayer MediaPlayer.setVolume()
ExoPlayer 使用SimpleExoPlayer.setVolume(),它可以设置底层AudioTrack的volume。

不要太吵

在享受安卓设备的音频时,用户有很多选择。大多数设备都有内置扬声器、有线耳机插孔,许多设备还具有蓝牙连接功能,并支持A2DP音频。

当耳机拔出或蓝牙设备断开时,音频流自动重新路由到内置扬声器。如果你在高音量下听音乐,这可能是一个嘈杂的惊喜。

幸运的是,当发生这种情况时,系统会广播一个ACTION_AUDIO_BECOMING_NOISY意图。当你播放音频时,你应该创建一个广播接收器来监听这个意图。对于音乐播放器,用户通常希望回放暂停。对于游戏应用程序,你可以选择大幅降低音量。你的接收器应该是这样的:

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()媒体会话回调中。

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