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 capacidad de usar los controles de volumen (ya sea botones o perillas en el dispositivo o controles deslizantes en la IU) y evitar que se reproduzca de forma repentina si se desconecta un periférico, como auriculares, mientras se usa.

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 cambia, 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 separadas para reproducir música, alarmas, notificaciones, timbres de llamadas entrantes, sonidos del sistema, volumen en 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 tu app no está reproduciendo contenido, cuando se presionan las teclas de volumen, se ajusta el volumen de la música (o el del timbre en versiones previas 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 pasarle el tipo de transmisión que coincida con tus atributos, que puedes recuperar de 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 controlan tu contenido multimedia. Esto conecta los controles de volumen a STREAM_MUSIC cuando la actividad o el fragmento de destino son 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 de forma conjunta todas las transmisiones de audio del mismo tipo. 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 y los vehículos con el SO Android Automotive) tienen controles de volumen, pero no permiten que las apps usen los métodos de AudioManager que se describieron anteriormente para cambiar el nivel de una transmisión de audio. Se trata de los dispositivos de volumen fijo. Puedes llamar a isVolumeFixed() para averiguar si tu app se ejecuta en un dispositivo de volumen fijo.

Una app de audio debe brindar 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:

Jugador Método
AudioTrack AudioTrack.setVolume()
MediaPlayer MediaPlayer.setVolume()
ExoPlayer Utiliza SimpleExoPlayer.setVolume(), que establece el volumen del método AudioTrack subyacente.
Web Establece la propiedad volume del HTMLMediaElement.

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 incorporada y conectores para auriculares con cable. Además, muchos cuentan con conectividad Bluetooth y compatibilidad con el perfil A2DP.

Cuando se desenchufan los auriculares o se desconecta un dispositivo Bluetooth, la transmisión de audio se redirecciona automáticamente a la bocina incorporada. Si escuchas música a un volumen alto, puedes llevarte una sorpresa muy ruidosa.

En general, en un caso así, 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 reproduciendo el contenido. El usuario puede ajustar el volumen con los controles de hardware del dispositivo.

Cuando la salida de audio vuelve a la bocina incorporada, el sistema transmite un intent ACTION_AUDIO_BECOMING_NOISY. Debes crear un BroadcastReceiver que escuche este intent cada vez que estés reproduciendo 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 onPlay() y onStop() de la sesión multimedia.

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