Audio spaziale

L'audio spaziale è un'esperienza sonora immersiva che mette gli utenti al centro dell'azione rendendo i contenuti più realistici. Il suono viene "spazializzato" in modo da creare un effetto multi-altoparlante, simile a una configurazione audio surround, ma tramite le cuffie.

Ad esempio, in un film il suono di un'auto può partire dietro l'utente, andare in avanti e poi scivolare in lontananza. In una videochiamata, le voci possono essere separate e posizionate intorno all'utente, in modo da identificare più facilmente chi parla.

Se i tuoi contenuti utilizzano un formato audio supportato, puoi aggiungere l'audio spaziale alla tua app a partire da Android 13 (livello API 33).

Query sulle funzionalità

Utilizza la classe Spatializer per eseguire query sulle capacità e sul comportamento di spazializzazione del dispositivo. Inizia recuperando un'istanza di Spatializer da AudioManager:

Kotlin

val spatializer = audioManager.spatializer

Java

Spatializer spatializer = AudioManager.getSpatializer();

Dopo aver ottenuto Spatializer, controlla le quattro condizioni che devono essere vere affinché il dispositivo possa emettere audio spazializzato:

Criteri Verifica
Il dispositivo supporta la spazializzazione? getImmersiveAudioLevel() non è SPATIALIZER_IMMERSIVE_LEVEL_NONE
La spazializzazione è disponibile?
La disponibilità dipende dalla compatibilità con il routing dell'uscita audio attuale.
isAvailable() è true
La spazializzazione è abilitata? isEnabled() è true
Una traccia audio con i parametri specificati può essere spazializzata? canBeSpatialized() è true

Queste condizioni potrebbero non essere soddisfatte, ad esempio se la spazializzazione non è disponibile per la traccia audio corrente o se la funzionalità è disattivata del tutto sul dispositivo di output audio.

Rilevamento dei movimenti della testa

Con le cuffie supportate, la piattaforma può regolare la spazializzazione dell'audio in base alla posizione della testa dell'utente. Per controllare se è disponibile un tracker con la testa per il routing dell'uscita audio corrente, chiama il numero isHeadTrackerAvailable().

Contenuti compatibili

Spatializer.canBeSpatialized() indica se l'audio con le proprietà specificate può essere spazializzato con il routing del dispositivo di output corrente. Questo metodo richiede un elemento AudioAttributes e un elemento AudioFormat, entrambi descritti più dettagliatamente di seguito.

AudioAttributes

Un oggetto AudioAttributes descrive l'utilizzo di uno stream audio (ad esempio audio di gioco o contenuti multimediali standard), nonché i suoi comportamenti di riproduzione e il tipo di contenuti.

Quando chiami canBeSpatialized(), utilizza la stessa istanza AudioAttributes impostata per Player. Ad esempio, se utilizzi la libreria Jetpack Media3 e non hai personalizzato l'attributo AudioAttributes, utilizza AudioAttributes.DEFAULT.

Disattivazione dell'audio spaziale

Per indicare che i tuoi contenuti sono già stati spazializzati, chiama setIsContentSpatialized(true) in modo che l'audio non venga elaborato due volte. In alternativa, regola il comportamento di spazializzazione per disattivare del tutto la spazializzazione chiamando setSpatializationBehavior(AudioAttributes.SPATIALIZATION_BEHAVIOR_NEVER).

AudioFormat

Un oggetto AudioFormat descrive i dettagli relativi al formato e alla configurazione del canale di una traccia audio.

Quando crei un'istanza AudioFormat da passare in canBeSpatialized(), imposta la codifica sullo stesso formato di output previsto dal decoder. Dovresti anche impostare una maschera del canale che corrisponda alla configurazione del canale dei tuoi contenuti. Consulta la sezione Comportamento di spazializzazione predefinito per indicazioni sui valori specifici da utilizzare.

Ascolta le modifiche al Spatializer

Per rimanere in ascolto delle modifiche dello stato di Spatializer, puoi aggiungere un listener con Spatializer.addOnSpatializerStateChangedListener(). Analogamente, per ascoltare i cambiamenti nella disponibilità di un tracker head, chiama Spatializer.addOnHeadTrackerAvailableListener().

Questo può essere utile se vuoi modificare la selezione delle tracce durante la riproduzione utilizzando i callback dell'ascoltatore. Ad esempio, quando un utente connette o scollega le cuffie dal dispositivo, la callback onSpatializerAvailableChanged indica se l'effetto spazializzatore è disponibile per il nuovo routing dell'output audio. A questo punto, puoi prendere in considerazione l'aggiornamento della logica di selezione delle tracce del player per adattarla alle nuove funzionalità del dispositivo. Per dettagli sul comportamento di selezione delle tracce di ExoPlayer, consulta la sezione ExoPlayer e audio spaziale.

ExoPlayer e audio spaziale

Le versioni recenti di ExoPlayer semplificano l'adozione dell'audio spaziale. Se utilizzi la libreria autonoma ExoPlayer (nome pacchetto com.google.android.exoplayer2), la versione 2.17 configura la piattaforma per l'output dell'audio spazializzato, mentre la versione 2.18 introduce vincoli per il numero di canali audio. Se utilizzi il modulo ExoPlayer della libreria Media3 (nome del pacchetto androidx.media3), le versioni 1.0.0-beta01 e successive includono questi stessi aggiornamenti.

Dopo aver aggiornato la dipendenza ExoPlayer alla release più recente, l'app deve solo includere contenuti che possono essere spazializzati.

Vincoli del numero di canali audio

Quando vengono soddisfatte tutte e quattro le condizioni dell'audio spaziale, ExoPlayer sceglie una traccia audio multicanale. In caso contrario, ExoPlayer sceglie una traccia stereo. Se le proprietà Spatializer cambiano, ExoPlayer attiva una nuova selezione di tracce per selezionare una traccia audio corrispondente alle proprietà correnti. Tieni presente che questa nuova selezione di tracce potrebbe causare un breve periodo di rebuffering.

Per disattivare i vincoli relativi al numero di canali audio, imposta i parametri per la selezione delle tracce sul player come mostrato di seguito:

Kotlin

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

Java

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

Analogamente, puoi aggiornare i parametri di un selettore di tracce esistente per disabilitare i vincoli relativi al numero di canali audio, come indicato di seguito:

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

Con i vincoli relativi al numero di canali audio disattivati, se i contenuti hanno più tracce audio, ExoPlayer seleziona inizialmente la traccia con il maggior numero di canali che può essere riprodotta dal dispositivo. Ad esempio, se i contenuti contengono una traccia audio multicanale e una traccia audio stereo e il dispositivo supporta la riproduzione di entrambe, ExoPlayer seleziona la traccia multicanale. Per informazioni dettagliate su come personalizzare questo comportamento, consulta la sezione Selezione delle tracce audio.

Selezione della traccia audio

Quando il comportamento dei vincoli di conteggio dei canali audio di ExoPlayer è disattivato, ExoPlayer non seleziona automaticamente una traccia audio che corrisponda alle proprietà dello spazializzatore del dispositivo. Puoi invece personalizzare la logica di selezione delle tracce di ExoPlayer impostando i parametri di selezione delle tracce prima o durante la riproduzione. Per impostazione predefinita, ExoPlayer seleziona tracce audio equivalenti a quella iniziale per quanto riguarda il tipo MIME (codifica), il conteggio dei canali e la frequenza di campionamento.

Modifica dei parametri di selezione della traccia

Per modificare i parametri di selezione delle tracce dell'ExoPlayer, usa Player.setTrackSelectionParameters(). Allo stesso modo, puoi ottenere gli attuali parametri di ExoPlayer con Player.getTrackSelectionParameters(). Ad esempio, per selezionare una traccia audio stereo durante la riproduzione:

Kotlin

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

Java

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

Tieni presente che la modifica dei parametri di selezione delle tracce durante la riproduzione potrebbe causare un'interruzione della riproduzione. Ulteriori informazioni sull'ottimizzazione dei parametri di selezione delle tracce del player sono disponibili nella sezione relativa alla selezione delle tracce della documentazione di ExoPlayer.

Comportamento predefinito di spazializzazione

Il comportamento predefinito di spazializzazione in Android include i seguenti comportamenti che possono essere personalizzati dagli OEM:

  • Solo i contenuti multicanale sono spazializzati, non contenuti stereo. Se non utilizzi ExoPlayer, a seconda del formato dei tuoi contenuti audio multicanale, potrebbe essere necessario configurare il numero massimo di canali che un decoder audio può restituire su un numero elevato. Ciò garantisce che il decodificatore audio generi un PCM multicanale per consentire alla piattaforma di spazializzare.

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

    Per un esempio in azione, vedi MediaCodecAudioRenderer.java di ExoPlayer. Per disattivare autonomamente la spazializzazione, indipendentemente dalla personalizzazione OEM, consulta la pagina Disattivare l'audio spaziale.

  • AudioAttributes: l'audio è idoneo per la spazializzazione se la proprietà usage è impostata su USAGE_MEDIA o USAGE_GAME.

  • AudioFormat: utilizza una maschera del canale che contenga almeno i canali AudioFormat.CHANNEL_OUT_QUAD (anteriore sinistra, anteriore destra, posteriore sinistra e posteriore destra) affinché l'audio sia idoneo per la spazializzazione. Nell'esempio seguente, utilizziamo AudioFormat.CHANNEL_OUT_5POINT1 per una traccia audio 5.1. Per una traccia audio stereo, utilizza AudioFormat.CHANNEL_OUT_STEREO.

    Se usi Media3, puoi utilizzare Util.getAudioTrackChannelConfig(int channelCount) per convertire il conteggio di un canale in una maschera dei canali.

    Inoltre, imposta la codifica su AudioFormat.ENCODING_PCM_16BIT se hai configurato il decoder per l'output di PCM multicanale.

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

Testa l'audio spaziale

Assicurati che l'audio spaziale sia abilitato sul tuo dispositivo di test:

  • Per le cuffie con cavo, vai a Impostazioni di sistema > Suoni e vibrazione > Audio spaziale.
  • Per le cuffie wireless, vai a Impostazioni di sistema > Dispositivi connessi > Icona a forma di ingranaggio per il tuo dispositivo wireless > Audio spaziale.

Per verificare la disponibilità dell'audio spaziale per il routing attuale, esegui il comando adb shell dumpsys audio sul tuo dispositivo. Quando la riproduzione è attiva, nell'output dovresti vedere i seguenti parametri:

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