Dodawanie dźwięku przestrzennego do aplikacji XR

Funkcje dźwięku przestrzennego w Jetpack SceneCore umożliwiają tworzenie immersyjnych doświadczeń dźwiękowych w aplikacjach na Androida XR.

Dźwięk przestrzenny symuluje sposób, w jaki użytkownicy odbierają dźwięk w środowisku 3D. Daje to wrażenie, że dźwięk dochodzi ze wszystkich kierunków, w tym z góry i z dołu. System robi to, symulując co najmniej 1 „wirtualny głośnik” w określonych lokalizacjach w przestrzeni 3D.

W przypadku istniejących aplikacji, które nie zostały zaprojektowane ani zmodyfikowane pod kątem Androida XR, dźwięk jest automatycznie przestrzenny. Gdy użytkownik porusza się po przestrzeni, cały dźwięk aplikacji będzie emitowany z panelu, na którym renderowany jest interfejs aplikacji. Jeśli na przykład w aplikacji zegara włączy się minutnik, dźwięk będzie dobiegać z pozycji panelu aplikacji. Android XR automatycznie zmieni dźwięk, aby uzyskać realistyczne pozycjonowanie. Na przykład odległość między panelem aplikacji a użytkownikiem będzie subtelnie wpływać na głośność dźwięku, co zwiększy realizm.

Więcej informacji o tym, jak istniejące aplikacje renderują dźwięk przestrzenny, znajdziesz na tej stronie w artykule Dodawanie dźwięku stereo i przestrzennego do aplikacji.

Jeśli optymalizujesz aplikację pod kątem XR, Jetpack SceneCore udostępnia narzędzia do zaawansowanego dostosowywania dźwięku przestrzennego. Możesz precyzyjnie pozycjonować dźwięki w środowisku 3D, używać dźwięku ambisonicznego do tworzenia realistycznych pól dźwiękowych i korzystać z wbudowanej integracji dźwięku przestrzennego.

Rodzaje dźwięku przestrzennego dostępne w Androidzie XR

Android XR obsługuje dźwięk pozycyjny, stereo, przestrzenny i ambisoniczny.

Dźwięk przestrzenny

Dźwięk przestrzenny można ustawić tak, aby odtwarzał się z określonego punktu w przestrzeni 3D. Możesz na przykład umieścić model 3D psa szczekającego w rogu Twojego środowiska wirtualnego. Możesz mieć wiele obiektów emitujących dźwięk z różnych pozycji. Aby renderować dźwięk przestrzenny, pliki muszą być mono lub stereo.

Stereo przestrzenne i dźwięk przestrzenny

Wszystkie formaty multimediów na Androida są obsługiwane w przypadku dźwięku pozycyjnego, stereo i przestrzennego.

Dźwięk stereo to formaty audio z 2 kanałami, a dźwięk przestrzenny to formaty audio z więcej niż 2 kanałami, takie jak dźwięk przestrzenny 5.1 lub dźwięk przestrzenny 7.1. Dane dźwiękowe każdego kanału są powiązane z jednym głośnikiem. Na przykład podczas odtwarzania muzyki w stereo lewy kanał głośnika może emitować inne ścieżki instrumentów niż prawy.

Dźwięk przestrzenny jest często używany w filmach i programach telewizyjnych, aby zwiększyć realizm i immersję dzięki wykorzystaniu wielu kanałów głośnikowych. Na przykład dialogi często odtwarzane są z kanału głośnika centralnego, a dźwięk przelatującego helikoptera może wykorzystywać różne kanały w sekwencji, aby sprawiać wrażenie, że helikopter przelatuje w przestrzeni 3D.

Dźwięk ambisoniczny

Dźwięk ambisoniczny (lub ambisonics) jest jak skybox dla dźwięku, zapewniając użytkownikom wciągającą przestrzeń dźwiękową. Używaj ambisonics do odtwarzania dźwięków otoczenia w tle lub w innych sytuacjach, w których chcesz odtworzyć pełne pole dźwiękowe otaczające słuchacza. Android XR obsługuje format dźwięku przestrzennego AmbiX w przypadku dźwięku przestrzennego pierwszego, drugiego i trzeciego rzędu. Zalecamy typy plików Opus (.ogg) i PCM/Wave (.wav).

Używanie dźwięku przestrzennego z Jetpack SceneCore

Wdrażanie dźwięku przestrzennego za pomocą Jetpack SceneCore obejmuje sprawdzanie możliwości przestrzennych i wybieranie interfejsu API do wczytywania dźwięku przestrzennego.

Sprawdzanie możliwości przestrzennych

Zanim zaczniesz korzystać z funkcji dźwięku przestrzennego, sprawdź, czy Session obsługuje dźwięk przestrzenny. We wszystkich fragmentach kodu w kolejnych sekcjach przed próbą odtworzenia dźwięku przestrzennego sprawdzane są możliwości.

Wczytywanie dźwięku przestrzennego

Aby wczytać dźwięk przestrzenny do użycia w Jetpack SceneCore, możesz użyć dowolnego z tych interfejsów API.

  • SoundPool: idealne w przypadku krótkich efektów dźwiękowych o rozmiarze mniejszym niż 1 MB. Są one wczytywane z wyprzedzeniem i można ich używać wielokrotnie. To świetny sposób na wczytanie dźwięku przestrzennego.
  • ExoPlayer: idealny do wczytywania treści stereo i surround, takich jak muzyka i filmy. Umożliwia też odtwarzanie multimediów w tle.
  • MediaPlayer: najprostszy sposób wczytywania dźwięku ambisonicznego.
  • AudioTrack: zapewnia największą kontrolę nad sposobem wczytywania danych audio. Umożliwia bezpośrednie zapisywanie buforów audio, jeśli pliki audio zostały zsyntetyzowane lub zdekodowane.

Dodawanie dźwięku przestrzennego do aplikacji

Pozycyjne źródła dźwięku są definiowane przez PointSourceParams i powiązany z nimi Entity. Położenie i orientacja Entity określają, gdzie PointSourceParams jest renderowany w przestrzeni 3D.

Przykład dźwięku przestrzennego

W poniższym przykładzie plik audio z efektem dźwiękowym jest wczytywany do puli dźwięków i odtwarzany w miejscu symbolu Entity.

// Check spatial capabilities before using spatial audio
if (session.scene.spatialCapabilities
    .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 = PointSourceParams(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 = session,
                soundPool = soundPool,
                soundID = pointSoundId,
                params = pointSource,
                volume = maxVolume,
                priority = lowPriority,
                loop = infiniteLoop,
                rate = normalSpeed
            )
        }
    }
} else {
    // The session does not have spatial audio capabilities
}

Najważniejsze informacje o kodzie

  • Pierwszym krokiem jest sprawdzenie, czy funkcje dźwięku przestrzennego są obecnie dostępne. W tym celu użyj spatialCapabilities.
  • Ustawienie contentType na CONTENT_TYPE_SONIFICATION i usage na USAGE_ASSISTANCE_SONIFICATION sprawia, że system traktuje ten plik audio jako efekt dźwiękowy.
  • W poprzednim przykładzie plik audio jest wczytywany do puli bezpośrednio przed użyciem, aby uprościć kod. Najlepiej jest wczytywać wszystkie efekty dźwiękowe asynchronicznie podczas wczytywania aplikacji, aby wszystkie pliki audio były dostępne w puli, gdy będą potrzebne.

Dodawanie dźwięku stereo i przestrzennego do aplikacji

Zalecanym sposobem dodawania dźwięku stereo i przestrzennego do aplikacji jest użycie Exoplayer. Więcej informacji o korzystaniu z dźwięku przestrzennego z Exoplayer znajdziesz w przewodniku po dźwięku przestrzennym.

Ustawienie głośników stereo i dźwięku przestrzennego

W przypadku pozycjonowania głośników dźwięku przestrzennego wirtualne głośniki dźwięku przestrzennego są umieszczone i zorientowane względem głośnika centralnego wokół użytkownika w standardowej konfiguracji ITU.

Domyślnie głośnik kanału centralnego jest umieszczony na mainPanelEntity aplikacji. Obejmuje to aplikacje mobilne, w których dźwięk jest automatycznie przestrzenny w Androidzie XR.

W przypadku dźwięku stereo głośniki są rozmieszczone podobnie jak w przypadku dźwięku przestrzennego, z tym że tylko kanały lewy i prawy są umieszczone odpowiednio po lewej i prawej stronie panelu.

Jeśli masz kilka paneli i chcesz wybrać, który z nich ma emitować dźwięk, lub jeśli chcesz, aby dźwięk stereo lub przestrzenny był renderowany względem innego Entity, możesz użyć PointSourceAttributes, aby określić lokalizację kanału centralnego. Pozostałe kanały zostaną umieszczone w sposób opisany wcześniej. W takich sytuacjach musisz też użyć MediaPlayer.

Gdy użytkownik porusza się po pomieszczeniu, wirtualne głośniki stereo i surround będą się przesuwać i dostosowywać, aby zawsze znajdować się w optymalnym położeniu.

Jeśli skonfigurujesz MediaPlayer lub ExoPlayer tak, aby odtwarzać dźwięk stereo lub przestrzenny w tle, pozycja wirtualnego głośnika zmieni się, gdy aplikacja będzie działać w tle. Ponieważ nie ma panelu ani innego punktu w przestrzeni, do którego można by przypisać dźwięk, dźwięk przestrzenny porusza się wraz z użytkownikiem (czyli jest „przywiązany do głowy”).

Przykład dźwięku przestrzennego

W tym przykładzie wczytujemy plik audio 5.1 za pomocą MediaPlayer i ustawiamy kanał środkowy pliku jako Entity.

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

    val pointSourceAttributes = PointSourceParams(session.scene.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.setPointSourceParams(
        session,
        mediaPlayer,
        pointSourceAttributes
    )

    mediaPlayer.setAudioAttributes(audioAttributes)
    mediaPlayer.prepare()
    mediaPlayer.start()
} else {
    // The session does not have spatial audio capabilities
}

Najważniejsze informacje o kodzie

Dodawanie do aplikacji pól dźwiękowych ambisonic

Najprostszym sposobem odtwarzania pól dźwiękowych ambisonic jest wczytanie pliku za pomocą MediaPlayer. Dźwięk ambisoniczny dotyczy całej przestrzeni dźwiękowej, więc nie musisz podawać Entity, aby określić pozycję. Zamiast tego tworzysz instancję SoundFieldAttributes z odpowiednim rzędem ambisonicznym określającym liczbę kanałów.

Przykład Ambionics

W przykładzie poniżej odtwarzane jest pole dźwiękowe ambisoniczne za pomocą MediaPlayer.

// Check spatial capabilities before using spatial audio
if (session.scene.spatialCapabilities.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(
        session,
        mediaPlayer,
        soundFieldAttributes
    )

    mediaPlayer.setAudioAttributes(audioAttributes)
    mediaPlayer.prepare()
    mediaPlayer.start()
} else {
    // The session does not have spatial audio capabilities
}

Najważniejsze informacje o kodzie

  • Podobnie jak w przypadku poprzednich fragmentów kodu, pierwszym krokiem jest sprawdzenie, czy funkcje dźwięku przestrzennego są dostępne za pomocą metody hasCapability().
  • Symbol contentType i sposób jego użycia mają charakter wyłącznie informacyjny.
  • Znak AMBISONICS_ORDER_FIRST_ORDER informuje SceneCore, że plik pola dźwiękowego definiuje 4 kanały.