Dźwięk przestrzenny

Dźwięk przestrzenny to niezwykłe doznania dźwiękowe, które przenoszą użytkowników w sam środek akcji i zapewniają większy realizm. „Uprzestrzennienie” dźwięku pozwala uzyskać efekt wielu głośników (podobny do konfiguracji dźwięku przestrzennego), ale zamiast głośników wykorzystuje słuchawki.

Na przykład w filmie dźwięk samochodu może zaczynać się za użytkownikiem, przesuwać do przodu i zanikać w oddali. Podczas czatu wideo głosy mogą być rozdzielone i umieszczone wokół użytkownika, co ułatwia identyfikację rozmówców.

Jeśli Twoje treści korzystają z obsługiwanego formatu audio, możesz dodać dźwięk przestrzenny do aplikacji od Androida w wersji 13 (poziom API 33).

Zapytanie o możliwości

Użyj klasy Spatializer, aby zapytać o możliwości i zachowanie lokalizacji przestrzennej urządzenia. Najpierw pobierz instancję Spatializer z poziomu bazy danych AudioManager:

Kotlin

val spatializer = audioManager.spatializer

Java

Spatializer spatializer = AudioManager.getSpatializer();

Po uzyskaniu Spatializer sprawdź, czy urządzenie spełnia 4 kryteria, które muszą być spełnione, aby można było na nim odtwarzać dźwięk przestrzenny:

Kryteria Sprawdź
Czy urządzenie obsługuje lokalizację przestrzenną? getImmersiveAudioLevel() nie jest SPATIALIZER_IMMERSIVE_LEVEL_NONE
Czy dostępna jest lokalizacja przestrzenna?
Dostępność zależy od zgodności z bieżącym kierowaniem wyjścia audio.
isAvailable() to true
Czy przestrzenność jest włączona? isEnabled() to true
Czy ścieżka audio z podanymi parametrami może zostać zmapowana przestrzennie? canBeSpatialized() to true

Te warunki mogą nie być spełnione, na przykład jeśli przestrzenność jest niedostępna dla bieżącej ścieżki audio lub jest całkowicie wyłączona na urządzeniu wyjściowym.

Monitorowanie ruchów głowy

W przypadku obsługiwanych słuchawek platforma może dostosować przestrzenność dźwięku na podstawie pozycji głowy użytkownika. Aby sprawdzić, czy urządzenie do śledzenia ruchów głowy jest dostępne dla bieżącego przekierowywania wyjścia audio, zadzwoń pod numer isHeadTrackerAvailable().

Zgodne treści

Spatializer.canBeSpatialized() wskazuje, czy dźwięk z danymi właściwościami może być przestrzenny przy użyciu bieżącego przekierowywania urządzenia wyjściowego. Ta metoda przyjmuje argumenty AudioAttributesAudioFormat, które są opisane bardziej szczegółowo poniżej.

AudioAttributes

Obiekt AudioAttributes opisuje użytkowanie strumienia audio (np. dźwięk z gry lub standardowe media), a także jego zachowanie podczas odtwarzania i typ treści.

Podczas wywoływania canBeSpatialized() użyj tej samej instancji AudioAttributes, która została skonfigurowana dla Player. Jeśli na przykład używasz biblioteki Jetpack Media3 i nie dostosowujesz wartości AudioAttributes, użyj wartości AudioAttributes.DEFAULT.

Wyłączanie dźwięku przestrzennego

Aby wskazać, że Twoje treści zostały już zmapowane przestrzennie, zadzwoń do setIsContentSpatialized(true), aby nie przetwarzać dźwięku dwukrotnie. Możesz też zmienić zachowanie funkcji dźwięku przestrzennego, aby całkowicie ją wyłączyć, wywołując funkcję setSpatializationBehavior(AudioAttributes.SPATIALIZATION_BEHAVIOR_NEVER).

AudioFormat

Obiekt AudioFormat zawiera informacje o formacie i konfiguracji kanałów ścieżki audio.

Podczas tworzenia instancji AudioFormat, która ma być przekazana do canBeSpatialized(), ustaw kodowanie na takie samo jak format wyjściowy oczekiwany od dekodera. Musisz też ustawić maskę kanału, która odpowiada konfiguracji kanału Twoich treści. Więcej informacji o używanych wartościach znajdziesz w sekcji Domyślne zachowanie przestrzenne.

Sprawdź, czy w pliku Spatializer zaszły jakieś zmiany

Aby nasłuchiwać zmian w stanie Spatializer, możesz dodać słuchacza za pomocą Spatializer.addOnSpatializerStateChangedListener(). Aby nasłuchiwać zmiany dostępności lokalizatora ruchów głowy, zadzwoń pod numer Spatializer.addOnHeadTrackerAvailableListener().

Może to być przydatne, jeśli chcesz dostosować wybór utworu podczas odtwarzania, używając wywołań zwrotnych listenera. Gdy na przykład użytkownik podłącza lub odłącza zestaw słuchawkowy od urządzenia, wywołanie onSpatializerAvailableChanged wskazuje, czy efekt przestrzenny jest dostępny dla nowego routingu wyjścia audio. W tym momencie możesz rozważyć zaktualizowanie logiki wyboru ścieżki przez odtwarzacz, aby dopasować ją do nowych możliwości urządzenia. Szczegółowe informacje o zachowaniu ExoPlayera podczas wybierania utworów znajdziesz w sekcji ExoPlayer i dźwięk przestrzenny.

ExoPlayer i dźwięk przestrzenny

Najnowsze wersje ExoPlayer ułatwiają stosowanie dźwięku przestrzennego. Jeśli używasz samodzielnej biblioteki ExoPlayer (nazwa pakietu com.google.android.exoplayer2), wersja 2.17 konfiguruje platformę do generowania dźwięku przestrzennego, a wersja 2.18 wprowadza ograniczenia liczby kanałów audio. Jeśli używasz modułu ExoPlayer z biblioteki Media3 (nazwa pakietu androidx.media3), wersje 1.0.0-beta01 i nowsze zawierają te same aktualizacje.

Po zaktualizowaniu zależności ExoPlayer do najnowszej wersji aplikacja musi zawierać treści, które można przestrzennie zlokalizować.

Ograniczenia dotyczące liczby kanałów audio

Gdy spełnione są wszystkie 4 warunki dotyczące dźwięku przestrzennego, ExoPlayer wybiera ścieżkę audio wielokanałową. W przeciwnym razie ExoPlayer wybierze ścieżkę stereo. Jeśli właściwości Spatializer ulegną zmianie, ExoPlayer wywoła nowy wybór ścieżki, aby wybrać ścieżkę audio odpowiadającą bieżącym właściwościom. Pamiętaj, że wybór nowego utworu może spowodować krótkie przeładowanie.

Aby wyłączyć ograniczenia dotyczące liczby kanałów audio, ustaw parametry wyboru ścieżki w odtwarzaczu w ten sposób:

Kotlin

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

Java

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

Podobnie możesz zaktualizować parametry dotychczasowego selektora utworów, aby wyłączyć ograniczenia dotyczące liczby kanałów audio:

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

Jeśli ograniczenie liczby kanałów audio jest wyłączone, a treści zawierają wiele ścieżek audio, ExoPlayer początkowo wybiera ścieżkę, która ma największą liczbę kanałów i można ją odtworzyć na urządzeniu. Jeśli na przykład treści zawierają ścieżkę audio wielokanałową i ścieżkę audio stereo, a urządzenie obsługuje odtwarzanie obu, ExoPlayer wybierze ścieżkę wielokanałową. Więcej informacji o tym, jak dostosować to zachowanie, znajdziesz w sekcji Wybór ścieżki audio.

Wybór ścieżki audio

Gdy zachowanie ograniczeń liczby kanałów audio w ExoPlayerze jest wyłączone, ExoPlayer nie wybiera automatycznie ścieżki audio, która pasuje do właściwości procesora dźwięku przestrzennego urządzenia. Zamiast tego możesz dostosować logikę wyboru ścieżki ExoPlayera, ustawiając parametry wyboru ścieżki przed odtworzeniem lub podczas odtwarzania. Domyślnie ExoPlayer wybiera ścieżki audio, które są takie same jak ścieżka początkowa pod względem typu MIME (kodowania), liczby kanałów i częstotliwości próbkowania.

Zmiana parametrów wyboru utworu

Aby zmienić parametry wyboru utworu w ExoPlayerze, użyj metody Player.setTrackSelectionParameters(). Możesz też uzyskać bieżące parametry ExoPlayera za pomocą funkcji Player.getTrackSelectionParameters(). Aby na przykład wybrać ścieżkę audio stereo w trakcie odtwarzania:

Kotlin

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

Java

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

Pamiętaj, że zmiana parametrów wyboru ścieżki w trakcie odtwarzania może spowodować przerwanie odtwarzania. Więcej informacji o dostosowywaniu parametrów wyboru utworów przez odtwarzacz znajdziesz w sekcji wyboru utworów w dokumentach ExoPlayer.

Domyślne zachowanie przestrzenne

Domyślne zachowanie przestrzenne na Androidzie obejmuje te zachowania, które mogą być dostosowywane przez producentów OEM:

  • Stereofonicznie są kodowane tylko treści wielokanałowe, a nie stereo. Jeśli nie używasz ExoPlayera, w zależności od formatu treści audio wielokanałowych może być konieczne skonfigurowanie maksymalnej liczby kanałów, które dekoder audio może wygenerować. Dzięki temu dekoder audio może wygenerować PCM wielokanałowy, który platforma przetworzy na dźwięk przestrzenny.

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

    Przykład działania znajdziesz w MediaCodecAudioRenderer.java ExoPlayera. Aby wyłączyć dźwięk przestrzenny, niezależnie od tego, czy producent OEM wprowadził jakieś zmiany, zapoznaj się z artykułem Wyłączanie dźwięku przestrzennego.

  • AudioAttributes: dźwięk można przestrzennie zmapować, jeśli parametr usage jest ustawiony na USAGE_MEDIA lub USAGE_GAME.

  • AudioFormat: użyj maski kanału, która zawiera co najmniej te kanały: AudioFormat.CHANNEL_OUT_QUAD (przedni lewy, przedni prawy, tylny lewy i tylny prawy), aby dźwięk mógł zostać przestrzennie zobrazowany. W przykładzie poniżej użyliśmy AudioFormat.CHANNEL_OUT_5POINT1 do ścieżki audio 5.1. W przypadku ścieżki audio stereo użyj AudioFormat.CHANNEL_OUT_STEREO.

    Jeśli używasz Media3, możesz użyć funkcji Util.getAudioTrackChannelConfig(int channelCount), aby przekształcić liczbę kanałów w maskę kanału.

    Jeśli dekoder jest skonfigurowany tak, aby generować PCM wielokanałowy, ustaw kodowanie na AudioFormat.ENCODING_PCM_16BIT.

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

Testowanie dźwięku przestrzennego

Sprawdź, czy dźwięk przestrzenny jest włączony na urządzeniu testowym:

  • W przypadku zestawów słuchawkowych przewodowych wybierz Ustawienia systemowe > Dźwięk i wibracje > Dźwięk przestrzenny.
  • W przypadku słuchawek bezprzewodowych kliknij Ustawienia systemowe > Połączone urządzenia > Ikona koła zębatego (dla urządzenia bezprzewodowego) > Dźwięk przestrzenny.

Aby sprawdzić dostępność dźwięku przestrzennego dla bieżącego routingu, uruchom na urządzeniu polecenie adb shell dumpsys audio. Podczas odtwarzania w wyniku powinny się pojawiać te parametry:

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