Audio espacial

El audio espacial es una experiencia de audio envolvente que pone a los usuarios en el centro de la acción y hace que el contenido suene más realista. El sonido se "espacializa" para crear un efecto de varios altavoces, similar a una configuración de sonido envolvente, pero con auriculares.

Por ejemplo, en una película, el sonido de un automóvil puede comenzar detrás del usuario, avanzar y avanzar en la distancia. En un videochat, las voces se pueden separar y colocar alrededor del usuario, lo que facilita la identificación de los interlocutores.

Si tu contenido usa un formato de audio compatible, puedes agregar audio espacial a tu app a partir de Android 13 (nivel de API 33).

Cómo consultar las funciones

Usa la clase Spatializer para consultar las capacidades y el comportamiento de espacialización del dispositivo. Para comenzar, recupera una instancia de Spatializer desde AudioManager:

Kotlin

val spatializer = audioManager.spatializer

Java

Spatializer spatializer = AudioManager.getSpatializer();

Después de obtener el Spatializer, comprueba si se cumplen las cuatro condiciones que deben ser verdaderas para que el dispositivo genere audio espacial:

Criterios Marcar
¿El dispositivo admite la espacialización? getImmersiveAudioLevel() no es SPATIALIZER_IMMERSIVE_LEVEL_NONE
¿Está disponible la espacialización?
La disponibilidad depende de la compatibilidad con el enrutamiento actual de salida de audio.
isAvailable() es true
¿La espacialización está habilitada? isEnabled() es true
¿Se puede espacializar una pista de audio con los parámetros dados? canBeSpatialized() es true

Es posible que no se cumplan estas condiciones, por ejemplo, si la espacialización no está disponible para la pista de audio actual o si está inhabilitada en el dispositivo de salida de audio por completo.

Seguimiento de cabeza

Con auriculares compatibles, la plataforma puede ajustar la espacialización del audio en función de la posición de la cabeza del usuario. A fin de comprobar si hay un dispositivo de seguimiento de cabeza disponible para el enrutamiento de salida de audio actual, llama a isHeadTrackerAvailable().

Contenido compatible

Spatializer.canBeSpatialized() indica si el audio con las propiedades determinadas se puede espacializar con el enrutamiento actual del dispositivo de salida. Este método toma un AudioAttributes y un AudioFormat, que se describen en más detalle a continuación.

AudioAttributes

Un objeto AudioAttributes describe el uso de una transmisión de audio (por ejemplo, audio de juegos o contenido multimedia estándar), junto con sus comportamientos de reproducción y el tipo de contenido.

Cuando llames a canBeSpatialized(), usa la misma instancia de AudioAttributes establecida en tu Player. Por ejemplo, si usas la biblioteca de Jetpack Media3 y no personalizaste el AudioAttributes, usa AudioAttributes.DEFAULT.

Cómo inhabilitar el audio espacial

Para indicar que tu contenido ya se espacial, llama a setIsContentSpatialized(true) para que el audio no se procese dos veces. Como alternativa, llama a setSpatializationBehavior(AudioAttributes.SPATIALIZATION_BEHAVIOR_NEVER) a fin de ajustar el comportamiento de la espacialización para inhabilitarla por completo.

AudioFormat

Un objeto AudioFormat describe detalles sobre el formato y la configuración del canal de una pista de audio.

Cuando crees una instancia de AudioFormat para pasar a canBeSpatialized(), configura la codificación con el mismo formato de salida que se espera del decodificador. También debes configurar una máscara de canal que coincida con la configuración del canal de tu contenido. Consulta la sección Comportamiento de espacialización predeterminado para obtener orientación sobre los valores específicos que debes usar.

Escucha cambios en Spatializer

Para escuchar los cambios en el estado de Spatializer, puedes agregar un objeto de escucha con Spatializer.addOnSpatializerStateChangedListener(). Del mismo modo, para escuchar cambios en la disponibilidad de un dispositivo de seguimiento de cabeza, llama a Spatializer.addOnHeadTrackerAvailableListener().

Esto puede ser útil si deseas ajustar la selección de pistas durante la reproducción mediante las devoluciones de llamada del objeto de escucha. Por ejemplo, cuando un usuario conecta o desconecta los auriculares del dispositivo, la devolución de llamada onSpatializerAvailableChanged indica si el efecto espacial está disponible para el nuevo enrutamiento de salida de audio. En este punto, puedes considerar actualizar la lógica de selección de pista del reproductor para que coincida con las nuevas capacidades del dispositivo. Para obtener detalles sobre el comportamiento de selección de pistas de ExoPlayer, consulta la sección ExoPlayer y audio espacial.

ExoPlayer y audio espacial

Las versiones recientes de ExoPlayer facilitan la adopción del audio espacial. Si usas la biblioteca independiente de ExoPlayer (nombre del paquete com.google.android.exoplayer2), la versión 2.17 configura la plataforma para que emita audio espacial, y la versión 2.18 incluye restricciones de recuento de canales de audio. Si usas el módulo de ExoPlayer de la biblioteca Media3 (nombre de paquete androidx.media3), las versiones 1.0.0-beta01 y las posteriores incluyen estas mismas actualizaciones.

Después de actualizar tu dependencia de ExoPlayer a la versión más reciente, tu app solo debe incluir contenido que se pueda espacializar.

Restricciones del recuento de canales de audio

Cuando se cumplen las cuatro condiciones para el audio espacial, ExoPlayer elige una pista de audio multicanal. De lo contrario, ExoPlayer elige una pista estéreo. Si cambian las propiedades de Spatializer, ExoPlayer activará una nueva selección de pista para seleccionar una pista de audio que coincida con las propiedades actuales. Ten en cuenta que esta selección de pista nueva puede generar un corto período de almacenamiento en búfer.

Para inhabilitar las restricciones del recuento de canales de audio, establece los parámetros de selección de pistas en el reproductor como se muestra a continuación:

Kotlin

exoPlayer.trackSelectionParameters = DefaultTrackSelector.Parameters.Builder(context)
  .setConstrainAudioChannelCountToDeviceCapabilities(false)
  .build()

Java

exoPlayer.setTrackSelectionParameters(
  new DefaultTrackSelector.Parameters.Builder(context)
    .setConstrainAudioChannelCountToDeviceCapabilities(false)
    .build()
);

Del mismo modo, puedes actualizar los parámetros de un selector de pistas existente para inhabilitar las restricciones del recuento de canales de audio de la siguiente manera:

Kotlin

val trackSelector = DefaultTrackSelector(context)
...
trackSelector.parameters = trackSelector.buildUponParameters()
  .setConstrainAudioChannelCountToDeviceCapabilities(false)
  .build()

Java

DefaultTrackSelector trackSelector = new DefaultTrackSelector(context);
...
trackSelector.setParameters(
  trackSelector
    .buildUponParameters()
    .setConstrainAudioChannelCountToDeviceCapabilities(false)
    .build()
);

Cuando las restricciones del recuento de canales de audio están inhabilitadas, si el contenido tiene varias pistas de audio, ExoPlayer selecciona inicialmente la pista que tiene la mayor cantidad de canales y se puede reproducir desde el dispositivo. Por ejemplo, si el contenido incluye una pista de audio multicanal y una pista de audio estéreo, y el dispositivo admite la reproducción de ambas, ExoPlayer selecciona la pista multicanal. Consulta Selección de pistas de audio para obtener detalles sobre cómo personalizar este comportamiento.

Selección de pistas de audio

Cuando se inhabilita el comportamiento de las restricciones de recuento de canales de audio de ExoPlayer, no se selecciona automáticamente una pista de audio que coincide con las propiedades del espacializador del dispositivo. En su lugar, puedes personalizar la lógica de selección de pistas de ExoPlayer estableciendo parámetros de selección de pistas antes de la reproducción o durante ella. De forma predeterminada, ExoPlayer selecciona pistas de audio que son iguales a la pista inicial con respecto al tipo de MIME (codificación), el recuento de canales y la tasa de muestreo.

Cómo cambiar los parámetros de selección de pistas

Para cambiar los parámetros de selección de pistas de ExoPlayer, usa Player.setTrackSelectionParameters(). Del mismo modo, puedes obtener los parámetros actuales de ExoPlayer con Player.getTrackSelectionParameters(). Por ejemplo, para seleccionar una pista de audio estéreo en medio de la reproducción, haz lo siguiente:

Kotlin

exoPlayer.trackSelectionParameters = exoPlayer.trackSelectionParameters
  .buildUpon()
  .setMaxAudioChannelCount(2)
  .build()

Java

exoPlayer.setTrackSelectionParameters(
  exoPlayer.getTrackSelectionParameters()
    .buildUpon()
    .setMaxAudioChannelCount(2)
    .build()
);

Ten en cuenta que, si cambias los parámetros de selección de pistas durante la reproducción, esta se podría interrumpir. Puedes encontrar más información sobre el ajuste de los parámetros de selección de pistas del jugador en la sección de selección de la pista de los documentos de ExoPlayer.

Comportamiento de espacialización predeterminado

El comportamiento de espacialización predeterminado en Android incluye los siguientes comportamientos que los OEMs pueden personalizar:

  • Solo el contenido de varios canales está espacializado, no el contenido estéreo. Si no usas ExoPlayer, según el formato de tu contenido de audio multicanal, es posible que debas configurar la cantidad máxima de canales que un decodificador de audio puede generar a un número grande. Esto garantiza que el decodificador de audio genere una salida PCM multicanal para que la plataforma realice la espacialización.

    Kotlin

    val mediaFormat = MediaFormat()
    mediaFormat.setInteger(MediaFormat.KEY_MAX_OUTPUT_CHANNEL_COUNT, 99)
    

    Java

    MediaFormat mediaFormat = new MediaFormat();
    mediaFormat.setInteger(MediaFormat.KEY_MAX_OUTPUT_CHANNEL_COUNT, 99);
    

    Para ver un ejemplo en acción, consulta MediaCodecAudioRenderer.java de ExoPlayer. Para desactivar la espacialización, sin importar la personalización del OEM, consulta Cómo inhabilitar el audio espacial.

  • AudioAttributes: El audio es apto para la espacialización si usage está configurado en USAGE_MEDIA o USAGE_GAME.

  • AudioFormat: Usa una máscara de canal que contenga, al menos, los canales AudioFormat.CHANNEL_OUT_QUAD (delantero izquierdo, frontal derecho, posterior izquierdo y derecho posterior) a fin de que el audio sea apto para la espacialización. En el siguiente ejemplo, usamos AudioFormat.CHANNEL_OUT_5POINT1 para una pista de audio 5.1. Para una pista de audio estéreo, usa AudioFormat.CHANNEL_OUT_STEREO.

    Si usas Media3, puedes usar Util.getAudioTrackChannelConfig(int channelCount) para convertir un recuento de canales en una máscara de canal.

    Además, establece la codificación en AudioFormat.ENCODING_PCM_16BIT si configuraste el decodificador para que genere PCM multicanal.

    Kotlin

    val audioFormat = AudioFormat.Builder()
      .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
      .setChannelMask(AudioFormat.CHANNEL_OUT_5POINT1)
      .build()
    

    Java

    AudioFormat audioFormat = new AudioFormat.Builder()
      .setEncoding(AudioFormat.ENCODING_PCM_16BIT)
      .setChannelMask(AudioFormat.CHANNEL_OUT_5POINT1)
      .build();
    

Prueba el audio espacial

Asegúrate de que el audio espacial esté habilitado en tu dispositivo de prueba:

  • En el caso de los auriculares con cable, ve a Configuración del sistema > Sonido y vibración > Audio espacial.
  • En el caso de los auriculares inalámbricos, ve a Configuración del sistema > Dispositivos conectados > Ícono de ajustes para tu dispositivo inalámbrico > Audio espacial.

Para verificar la disponibilidad del audio espacial para el enrutamiento actual, ejecuta el comando adb shell dumpsys audio en tu dispositivo. Mientras la reproducción está activa, deberías ver los siguientes parámetros en el resultado:

Spatial audio:
mHasSpatializerEffect:true (effect present)
isSpatializerEnabled:true (routing dependent)