O áudio espacial é uma experiência de áudio imersiva que coloca os usuários no centro da ação, tornando o som do conteúdo mais realista. O som é "espacializado" para criar um efeito de vários alto-falantes, semelhante a uma configuração de som surround, mas por meio de fones de ouvido.
Por exemplo, em um filme, o som de um carro pode começar atrás do usuário, avançar e se afastar. Em um chat por vídeo, as vozes podem ser separadas e colocadas ao redor do usuário, facilitando a identificação.
Caso o conteúdo use um formato de áudio com suporte, é possível adicionar áudio espacial ao app a partir do Android 13 (nível 33 da API).
Consultar recursos
Use a classe Spatializer
para
consultar os recursos e o comportamento de espacialização do dispositivo. Comece recuperando
uma instância do Spatializer
do
AudioManager
:
Kotlin
val spatializer = audioManager.spatializer
Java
Spatializer spatializer = AudioManager.getSpatializer();
Depois de receber o Spatializer
, verifique as quatro condições que precisam ser
verdadeiras para que o dispositivo gere áudio espacial:
Critérios | Marca de seleção |
---|---|
O dispositivo tem suporte para espacialização? |
getImmersiveAudioLevel() não é SPATIALIZER_IMMERSIVE_LEVEL_NONE
|
A espacialização está disponível? A disponibilidade depende da compatibilidade com o roteamento de saída de áudio atual. |
isAvailable() é true |
A espacialização está ativada? | isEnabled() é true |
É possível espacializar uma faixa de áudio com os parâmetros fornecidos? | canBeSpatialized() é true |
Essas condições podem não ser atendidas, por exemplo, se a espacialização não estiver disponível para a faixa de áudio atual ou estiver totalmente desativada no dispositivo de saída de áudio.
Acompanhamento da cabeça
Com fones de ouvido compatíveis, a plataforma pode ajustar a espacialização
do áudio com base na posição da cabeça do usuário. Para verificar se um monitor de posições está
disponível para o roteamento de saída de áudio atual, chame
isHeadTrackerAvailable()
.
Conteúdo compatível
Spatializer.canBeSpatialized()
indica se o áudio com as propriedades fornecidas pode ser espacializado com o
roteamento atual do dispositivo de saída. Esse método usa um AudioAttributes
e um AudioFormat
, ambos
descritos em mais detalhes abaixo.
AudioAttributes
Um objeto AudioAttributes
descreve o uso de um
stream de áudio, por exemplo, áudio de jogos
ou mídia padrão,
além dos comportamentos de reprodução e do tipo de conteúdo.
Ao chamar canBeSpatialized()
, use a mesma
instância AudioAttributes
que foi definida para Player
. Por exemplo, se
você estiver usando a biblioteca Jetpack Media3 e não tiver personalizado o
AudioAttributes
, use AudioAttributes.DEFAULT
.
Desativando o áudio espacial
Para indicar que o conteúdo já foi espacializado, chame
setIsContentSpatialized(true)
para que o áudio não seja processado duas vezes. Se preferir, ajuste o
comportamento de espacialização para desativar esse recurso chamando
setSpatializationBehavior(AudioAttributes.SPATIALIZATION_BEHAVIOR_NEVER)
.
AudioFormat
Um objeto AudioFormat
descreve
detalhes sobre o formato e a configuração do canal de uma faixa de áudio.
Ao instanciar o AudioFormat
para transmitir canBeSpatialized()
,
defina a codificação
como o mesmo formato de saída esperado do decodificador. Defina também
uma máscara de canal
que corresponda à configuração do canal do seu conteúdo. Consulte a seção
Comportamento de espacialização padrão para conferir orientações sobre
os valores específicos a serem usados.
Detectar mudanças no Spatializer
Para detectar mudanças no estado do Spatializer
, adicione um listener
com Spatializer.addOnSpatializerStateChangedListener()
.
Da mesma forma, para detectar mudanças na disponibilidade de um monitor de posições da cabeça,
chame Spatializer.addOnHeadTrackerAvailableListener()
.
Isso pode ser útil se você quiser ajustar a seleção de faixas durante a reprodução
usando os callbacks do listener. Por exemplo, quando um usuário conecta ou desconecta o
fone de ouvido do dispositivo, o callback onSpatializerAvailableChanged
indica se o efeito espacializador está disponível para o novo
roteamento de saída de áudio. Nesse momento, você pode atualizar a lógica de seleção de faixas
do jogador para corresponder aos novos recursos do dispositivo. Para saber mais sobre
o comportamento de seleção de faixas do ExoPlayer, consulte a seção
ExoPlayer e áudio espacial.
ExoPlayer e áudio espacial
Os lançamentos recentes do ExoPlayer facilitam a adoção do áudio espacial. Se você usar
a biblioteca autônoma do ExoPlayer (nome do pacote com.google.android.exoplayer2
),
a versão 2.17 vai configurar a plataforma para gerar áudio espacial, e a versão
2.18 introduz restrições de contagem de canais de áudio.
Se você usar o módulo ExoPlayer da biblioteca Media3 (nome do pacote
androidx.media3
), as versões 1.0.0-beta01
e mais recentes vão incluir essas mesmas atualizações.
Depois de atualizar a dependência do ExoPlayer para a versão mais recente, seu app só precisa incluir conteúdo que pode ser espacializado.
Restrições de contagem de canais de áudio
Quando todas as quatro condições para áudio espacial são atendidas, o ExoPlayer escolhe
uma faixa de áudio multicanal. Caso contrário, o ExoPlayer vai escolher uma faixa estéreo.
Se as propriedades Spatializer
mudarem, o ExoPlayer
vai acionar uma nova seleção de faixa para escolher uma faixa de áudio que corresponda às
propriedades atuais. Essa nova seleção de faixa pode causar um curto
período de armazenamento em buffer.
Para desativar as restrições de contagem de canais de áudio, defina os parâmetros de seleção de faixa no player, conforme mostrado abaixo:
Kotlin
exoPlayer.trackSelectionParameters = DefaultTrackSelector.Parameters.Builder(context) .setConstrainAudioChannelCountToDeviceCapabilities(false) .build()
Java
exoPlayer.setTrackSelectionParameters( new DefaultTrackSelector.Parameters.Builder(context) .setConstrainAudioChannelCountToDeviceCapabilities(false) .build() );
Da mesma forma, você pode atualizar os parâmetros de um seletor de faixa existente para desativar as restrições de contagem de canais de áudio da seguinte maneira:
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() );
Com as restrições de contagem de canais de áudio desativadas, se o conteúdo tiver várias faixas de áudio, o ExoPlayer selecionará inicialmente a faixa que tiver o maior número de canais e poder ser reproduzida no dispositivo. Por exemplo, se o conteúdo tiver uma faixa de áudio multicanal e uma faixa de áudio estéreo e o dispositivo oferecer suporte à reprodução de ambas, o ExoPlayer selecionará a faixa multicanal. Consulte a seleção de faixa de áudio para ver detalhes sobre como personalizar esse comportamento.
Seleção de faixa de áudio
Quando o comportamento de restrições de contagem de canais de áudio do ExoPlayer é desativado, o ExoPlayer não seleciona automaticamente uma faixa de áudio que corresponda às propriedades do espacializador do dispositivo. Em vez disso, você pode personalizar a lógica de seleção de faixas do ExoPlayer definindo os parâmetros de seleção antes ou durante a reprodução. Por padrão, o ExoPlayer seleciona faixas de áudio que são as mesmas da faixa inicial em relação ao tipo MIME (codificação), à contagem de canais e à taxa de amostragem.
Como alterar os parâmetros de seleção de faixas
Para mudar os parâmetros de seleção de faixa do ExoPlayer, use
Player.setTrackSelectionParameters()
.
Da mesma forma, é possível extrair os parâmetros atuais do ExoPlayer com
Player.getTrackSelectionParameters()
.
Por exemplo, para selecionar uma faixa de áudio estéreo no meio da reprodução:
Kotlin
exoPlayer.trackSelectionParameters = exoPlayer.trackSelectionParameters .buildUpon() .setMaxAudioChannelCount(2) .build()
Java
exoPlayer.setTrackSelectionParameters( exoPlayer.getTrackSelectionParameters() .buildUpon() .setMaxAudioChannelCount(2) .build() );
Mudar os parâmetros de seleção de faixa durante a reprodução pode causar uma interrupção na reprodução. Mais informações sobre como ajustar os parâmetros de seleção de faixas do jogador estão disponíveis na seção de seleção de faixa (link em inglês) dos documentos do ExoPlayer.
Comportamento padrão de espacialização
O comportamento padrão de espacialização no Android inclui os seguintes comportamentos que podem ser personalizados pelos OEMs:
Somente o conteúdo multicanal é espacializado, não estéreo. Se você não usa o ExoPlayer, dependendo do formato do conteúdo de áudio multicanal, pode ser necessário configurar o número máximo de canais que podem ser enviados por um decodificador de áudio para um número grande. Isso garante que o decodificador de áudio gere um PCM multicanal para que a plataforma espacialize.
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 conferir um exemplo na prática, consulte o
MediaCodecAudioRenderer.java
do ExoPlayer. Para desativar a espacialização por conta própria, independentemente da personalização do OEM, consulte Como desativar o áudio espacial.AudioAttributes
: o áudio será qualificado para espacialização se ausage
estiver definida comoUSAGE_MEDIA
ouUSAGE_GAME
.AudioFormat
: use uma máscara de canal que contenha pelo menos os canaisAudioFormat.CHANNEL_OUT_QUAD
(frontal esquerdo, frontal direito, traseira e esquerda e traseira) para que o áudio se qualifique para a espacialização. No exemplo abaixo, usamosAudioFormat.CHANNEL_OUT_5POINT1
para uma faixa de áudio 5.1. Para uma faixa de áudio estéreo, useAudioFormat.CHANNEL_OUT_STEREO
.Se você estiver usando o Media3, poderá utilizar
Util.getAudioTrackChannelConfig(int channelCount)
para converter uma contagem de canais em uma máscara de canais.Além disso, defina a codificação como
AudioFormat.ENCODING_PCM_16BIT
se você tiver configurado o decodificador para gerar 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();
Testar o áudio espacial
Confira se o áudio espacial está ativado no dispositivo de teste:
- Para fones de ouvido com fio, acesse Configurações do sistema > Som e vibração > Áudio espacial.
- Para fones de ouvido sem fio, acesse Configurações do sistema > Dispositivos conectados > ícone de engrenagem do dispositivo sem fio > Áudio espacial.
Para verificar a disponibilidade do áudio espacial no roteamento atual, execute o
comando adb shell dumpsys audio
no dispositivo. Você verá os seguintes
parâmetros na saída enquanto a reprodução estiver ativa:
Spatial audio:
mHasSpatializerEffect:true (effect present)
isSpatializerEnabled:true (routing dependent)