Cómo controlar cambios en la salida de audio

Los usuarios esperan poder controlar el volumen de una app de audio. El comportamiento estándar incluye la posibilidad de usar los controles de volumen (ya sea botones o perillas del dispositivo o los controles deslizantes de la IU) y evitar que se reproduzca en voz alta repentinamente si un periférico, como los auriculares, se desconecta mientras está en uso.

Cómo usar los controles de volumen

Cuando un usuario presiona una tecla de volumen en un juego o una app de música, el volumen debería cambiar, incluso si el reproductor está pausado entre canciones o no hay música para la ubicación actual del juego.

Android usa transmisiones de audio independientes para reproducir música, alarmas, notificaciones, timbres de llamadas entrantes, sonidos del sistema, volumen de las llamadas y tonos DTMF. Esto permite a los usuarios controlar el volumen de cada transmisión de forma independiente.

De forma predeterminada, cuando se presiona el control de volumen, se modifica el volumen de la transmisión de audio activa. Si la app no está reproduciendo nada, cuando presionas las teclas de volumen, se ajusta el volumen de la música (o el del timbre en versiones anteriores a Android 9).

A menos que tu app sea de alarma, debes reproducir audio con el uso AudioAttributes.USAGE_MEDIA.

Para asegurarte de que los controles de volumen ajusten la transmisión correcta, debes llamar a setVolumeControlStream() y pasar el tipo de transmisión que coincida con tus atributos, que puedes recuperar desde AudioAttributes.getVolumeControlStream.

Kotlin

setVolumeControlStream(AudioManager.STREAM_MUSIC)

Java

setVolumeControlStream(AudioManager.STREAM_MUSIC);

Realiza esta llamada en el ciclo de vida de tu app, por lo general, desde el método onResume() de la actividad o el fragmento que controla el contenido multimedia. De esta manera, se conectan los controles de volumen a STREAM_MUSIC siempre que la actividad o el fragmento objetivo sean visibles.

Cómo controlar el volumen de transmisión de manera programática

En casos excepcionales, puedes establecer el volumen de una transmisión de audio de manera programática. Por ejemplo, cuando tu app reemplaza una IU existente. Esto no se recomienda, ya que el AudioManager de Android mezcla todas las transmisiones de audio del mismo tipo juntas. Los siguientes métodos cambian el volumen de cada app que usa la transmisión Evita usarlos:

Cómo trabajar con dispositivos que tienen el volumen fijo

Algunos dispositivos (como las Chromebooks) tienen controles de volumen, pero no permiten que las apps usen los métodos AudioManager descritos anteriormente para cambiar el nivel de una transmisión de audio. Estos se denominan dispositivos de volumen fijo. Puedes llamar a isVolumeFixed() para descubrir si la app se ejecuta en un dispositivo de volumen fijo.

Una app de audio debe proporcionar la capacidad de equilibrar su volumen de salida con otras apps que podrían estar reproduciendo contenido en la misma transmisión. En los dispositivos de volumen fijo, la app debe conectar sus propios controles de volumen al método setVolume() apropiado en la siguiente tabla:

Jugador Método
AudioTrack AudioTrack.setVolume()
MediaPlayer MediaPlayer.setVolume()
ExoPlayer Utiliza SimpleExoPlayer.setVolume(), que establece el volumen del método AudioTrack subyacente.

Evita el volumen demasiado alto

Los usuarios tienen varias alternativas a la hora de disfrutar del audio de sus dispositivos Android. La mayoría de los dispositivos tienen una bocina integrada, conectores para auriculares con cable y muchos también cuentan con conectividad Bluetooth y compatibilidad con audio A2DP.

Cuando se desconectan los auriculares o se desconecta un dispositivo Bluetooth, la transmisión de audio se redirecciona automáticamente a la bocina integrada. Si escuchas música a un volumen alto, puede ser una sorpresa ruidosa.

En general, los usuarios esperan que las apps que incluyen un reproductor de música con controles de reproducción en pantalla pausen la reproducción. Otras apps, como los juegos que no incluyen controles, deberían seguir jugando. El usuario puede ajustar el volumen con los controles de hardware del dispositivo.

Cuando la salida de audio cambia de nuevo a la bocina integrada, el sistema transmite un intent ACTION_AUDIO_BECOMING_NOISY. Debes crear un BroadcastReceiver que escuche este intent cada vez que reproduzcas audio. El receptor debe verse de esta manera:

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

Registra el receptor cuando comience la reproducción y anula el registro cuando se detenga. Si diseñas tu app como se describe en esta guía, estas llamadas deberían aparecer en las devoluciones de llamada de la sesión multimedia onPlay() y 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);
  }
}