Adicionar áudio espacial ao seu app de XR

Os recursos de áudio espacial no Jetpack SceneCore permitem criar experiências de áudio imersivas nos seus aplicativos Android XR.

O áudio espacial simula como os usuários percebem o som em um ambiente 3D. Ele cria a sensação de som que emana de todas as direções, incluindo acima e abaixo do usuário. O sistema faz isso simulando um ou mais "alto-falantes virtuais" em locais específicos no espaço 3D.

Os apps que não foram projetados ou modificados para o Android XR têm o áudio espacializado automaticamente no Android XR. À medida que o usuário se move pelo espaço, todo o áudio do app é emitido pelo painel em que a interface do app é renderizada. Por exemplo, se um timer de um app de relógio for acionado, o áudio vai parecer que está vindo da posição do painel do app. O Android XR altera automaticamente o som para realismo posicional. Por exemplo, a distância percebida entre o painel do app e o usuário vai afetar sutilmente o volume do áudio para uma maior sensação de realismo.

Para mais informações sobre como os apps atuais renderizam áudio espacial, leia Adicionar som estéreo e surround ao seu app nesta página.

Se você estiver otimizando seu app para XR, o Jetpack SceneCore oferece ferramentas para personalização avançada de áudio espacial. É possível posicionar sons com precisão no ambiente 3D, usar áudio ambisônico para campos de som realistas e aproveitar a integração de som surround integrada.

Tipos de áudio espacial disponíveis no Android XR

O Android XR oferece suporte a áudio posicional, estéreo, surround e ambisônico.

Áudio posicional

Um áudio posicional pode ser posicionado para ser reproduzido em um ponto específico no espaço 3D. Por exemplo, você pode ter um modelo 3D de um cachorro latindo no canto do seu ambiente virtual. É possível ter várias entidades emitindo som de cada uma das respectivas posições. Para renderizar áudio posicional, os arquivos precisam ser mono ou estéreo.

Som estéreo e surround espacializado

Todos os formatos de mídia do Android têm suporte para som posicional, estéreo e surround.

O áudio estéreo se refere a formatos de áudio com dois canais, e o som surround se refere a formatos de áudio com mais de dois canais, como som surround 5.1 ou som surround 7.1. Os dados de som de cada canal são associados a um alto-falante. Por exemplo, ao tocar música em estéreo, o canal do alto-falante esquerdo pode emitir faixas de instrumentos diferentes do direito.

O som surround é usado com frequência em filmes e programas de TV para melhorar o realismo e a imersão usando vários canais de alto-falantes. Por exemplo, o diálogo geralmente é reproduzido em um canal de alto-falante central, enquanto o som de um helicóptero em voo pode usar canais diferentes em sequência para dar a sensação de que o helicóptero está voando ao redor do seu espaço 3D.

Áudio ambisônico

O áudio ambisônico (ou ambisônicos) é como um skybox para áudio, oferecendo um ambiente sonoro imersivo para seus usuários. Use ambisônicos para sons de fundo ambientais ou outros cenários em que você quer replicar um campo de som esférico que envolve o ouvinte. O Android XR oferece suporte ao formato de áudio ambissônico AmbiX em ambissônicos de primeira, segunda e terceira ordem. Recomendamos os tipos de arquivo Opus (.ogg) e PCM/Wave (.wav).

Usar áudio espacial com o Jetpack SceneCore

A implementação do áudio espacial com o Jetpack SceneCore envolve a verificação de recursos espaciais e a escolha de uma API para carregar áudio espacial.

Verificar os recursos espaciais

Antes de usar os recursos de áudio espacial, verifique se o Session oferece suporte a esse recurso. Em todos os snippets de código nas seções a seguir, os recursos são verificados antes de tentar reproduzir o áudio espacializado.

Carregar áudio espacial

Você pode usar qualquer uma das APIs abaixo para carregar áudio espacial para uso no Jetpack SceneCore.

  • SoundPool: ideal para efeitos sonoros curtos com menos de 1 MB de tamanho, que são carregados com antecedência e podem ser usados repetidamente. Essa é uma ótima maneira de carregar áudio para áudio posicional.
  • ExoPlayer: ideal para carregar conteúdo estéreo e de som surround, como música e vídeo. Também permite a reprodução de mídia em segundo plano.
  • MediaPlayer: oferece a maneira mais simples de carregar áudio ambisônico.
  • AudioTrack: oferece o maior controle sobre como carregar dados de áudio. Permite gravar buffers de áudio diretamente ou se você sintetizou ou decodou seus próprios arquivos de áudio.

Adicionar áudio posicional ao app

As fontes de som posicional são definidas por PointSourceAttributes e uma Entity associada. A posição e a orientação do Entity determinam onde o PointSourceAttribute é renderizado no espaço 3D.

Exemplo de áudio posicional

O exemplo a seguir carrega um arquivo de áudio de efeito sonoro em um conjunto de sons e o reproduz na posição do Entity.

// Check spatial capabilities before using spatial audio
if (xrSession.getSpatialCapabilities().hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_SPATIAL_AUDIO)) {
    // The session has spatial audio capabilities

    val maxVolume = 1F
    val lowPriority = 0
    val infiniteLoop = -1
    val normalSpeed = 1F

    val soundPool = SoundPool.Builder()
        .setAudioAttributes(
            AudioAttributes.Builder()
                .setContentType(CONTENT_TYPE_SONIFICATION)
                .setUsage(USAGE_ASSISTANCE_SONIFICATION)
                .build()
        )
        .build()

    val pointSource = PointSourceAttributes(entity)

    val soundEffect = appContext.assets.openFd("sounds/tiger_16db.mp3")
    val pointSoundId = soundPool.load(soundEffect, lowPriority)

    soundPool.setOnLoadCompleteListener{ soundPool, sampleId, status ->
        //wait for the sound file to be loaded into the soundPool
        if (status == 0){

            SpatialSoundPool.play(
                session = xrSession,
                soundPool = soundPool,
                soundID = pointSoundId,
                attributes = pointSource,
                volume = maxVolume,
                priority = lowPriority,
                loop = infiniteLoop,
                rate = normalSpeed
            )
        }
    }
} else {
    // The session does not have spatial audio capabilities
}

Pontos principais sobre o código

  • A primeira etapa é verificar se os recursos de áudio espacial estão disponíveis usando getSpatialCapabilities().
  • Definir contentType como CONTENT_TYPE_SONIFICATION e usage como USAGE_ASSISTANCE_SONIFICATION permite que o sistema trate esse arquivo de áudio como um efeito sonoro.
  • O exemplo anterior carrega o arquivo de áudio no pool imediatamente antes de usá-lo para manter o código junto para simplificar. O ideal é carregar todos os efeitos sonoros de forma assíncrona ao carregar o app para que todos os arquivos de áudio estejam disponíveis no pool quando você precisar.

Adicionar som estéreo e surround ao app

A maneira recomendada de adicionar som estéreo e surround ao seu app é usando Exoplayer. Para mais informações sobre como usar o áudio espacial com Exoplayer, consulte o guia de áudio espacial.

Posicionamento de alto-falantes estéreo e de som surround

Com o posicionamento de alto-falantes de som surround, os alto-falantes de som surround virtual são posicionados e orientados em relação a um alto-falante central, ao redor do usuário em uma configuração ITU padrão.

Por padrão, o alto-falante do canal central é colocado no mainPanelEntity do app. Isso inclui apps para dispositivos móveis que têm o áudio espacializado automaticamente pelo Android XR.

Para o estéreo, a colocação dos alto-falantes é semelhante ao som surround, exceto com apenas os canais esquerdo e direito posicionados no lado esquerdo e direito do painel, respectivamente.

Se você tiver vários painéis e quiser escolher qual deles emite áudio ou se quiser que o áudio estéreo ou surround seja renderizado em relação a outro Entity, use o PointSourceAttributes para definir o local do canal central. Os canais restantes serão colocados como mencionado anteriormente. Nessas situações, também é necessário usar MediaPlayer.

À medida que o usuário se move pelo espaço, os alto-falantes virtuais de som estéreo e surround se movem e se ajustam para garantir que estejam sempre na posição ideal.

Se você tiver configurado o MediaPlayer ou o ExoPlayer para continuar reproduzindo som estéreo ou surround em segundo plano, o posicionamento do alto-falante virtual será alterado quando o app estiver em segundo plano. Como não há painel ou outro ponto no espaço para ancorar o som, o áudio espacial se move com o usuário. Em outras palavras, ele é "travado na cabeça".

Exemplo de som surround

O exemplo a seguir carrega um arquivo de áudio 5.1 usando MediaPlayer e define o canal central do arquivo como um Entity.

// Check spatial capabilities before using spatial audio
if (xrSession.getSpatialCapabilities().hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_SPATIAL_AUDIO)) {
    // The session has spatial audio capabilities

    val pointSourceAttributes = PointSourceAttributes(xrSession.mainPanelEntity)

    val mediaPlayer = MediaPlayer()

    val fivePointOneAudio = appContext.assets.openFd("sounds/aac_51.ogg")
    mediaPlayer.reset()
    mediaPlayer.setDataSource(fivePointOneAudio)

    val audioAttributes =
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()

    SpatialMediaPlayer.setPointSourceAttributes(
        xrSession,
        mediaPlayer,
        pointSourceAttributes)

    mediaPlayer.setAudioAttributes(audioAttributes)
    mediaPlayer.prepare()
    mediaPlayer.start()

} else {
    // The session does not have spatial audio capabilities
}

Pontos principais sobre o código

Adicionar campos de som ambisônico ao app

A maneira mais simples de reproduzir campos de som ambisônico é carregando o arquivo com um MediaPlayer. Como o som ambisônico se aplica a todo o som ambiente, não é necessário especificar um Entity para fornecer uma posição. Em vez disso, crie uma instância do SoundFieldAttributes com a ordem ambisônica adequada especificando o número de canais.

Exemplo de ambionics

O exemplo a seguir reproduz um campo de som ambisônico usando MediaPlayer.

// Check spatial capabilities before using spatial audio
if (xrSession.getSpatialCapabilities().hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_SPATIAL_AUDIO)) {
    // The session has spatial audio capabilities

    val soundFieldAttributes =
        SoundFieldAttributes(SpatializerConstants.AMBISONICS_ORDER_FIRST_ORDER)

    val mediaPlayer = MediaPlayer()

    val soundFieldAudio = appContext.assets.openFd("sounds/foa_basketball_16bit.wav")

    mediaPlayer.reset()
    mediaPlayer.setDataSource(soundFieldAudio)

    val audioAttributes =
        AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
            .setUsage(AudioAttributes.USAGE_MEDIA)
            .build()

    SpatialMediaPlayer.setSoundFieldAttributes(
        xrSession,
        mediaPlayer,
        soundFieldAttributes)

    mediaPlayer.setAudioAttributes(audioAttributes)
    mediaPlayer.prepare()
    mediaPlayer.start()

} else {
    // The session does not have spatial audio capabilities
}

Pontos principais sobre o código

  • Assim como nos snippets anteriores, a primeira etapa é verificar se os recursos de áudio espacial estão disponíveis usando getSpatialCapabilities().
  • O contentType e o usage são puramente informativos.
  • O AMBISONICS_ORDER_FIRST_ORDER sinaliza para o SceneCore que o arquivo de campo de som define quatro canais.