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. Dźwięk jest „uprzestrzenniony”, aby uzyskać efekt wielu głośników, podobny do konfiguracji dźwięku przestrzennego, ale w słuchawkach.

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

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

Zapytanie o możliwości

Użyj klasy Spatializer, aby wysyłać zapytania o możliwości i zachowanie przestrzenne urządzenia. Zacznij od pobrania instancji SpatializerAudioManager:

Kotlin

val spatializer = audioManager.spatializer

Java

Spatializer spatializer = AudioManager.getSpatializer();

Gdy pojawi się Spatializer, sprawdź, czy spełnione są 4 warunki, które muszą być spełnione, aby urządzenie odtwarzało dźwięk przestrzenny:

Kryteria Sprawdź
Czy urządzenie obsługuje przestrzenność? getImmersiveAudioLevel() nie jest równe SPATIALIZER_IMMERSIVE_LEVEL_NONE
Czy jest dostępna przestrzenność?
Dostępność zależy od zgodności z bieżącym routingiem wyjścia audio.
isAvailable() to true
Czy aspekt przestrzenny jest włączony? isEnabled() to true
Czy ścieżkę audio o podanych parametrach można przestrzennie zlokalizować? canBeSpatialized() to true

Te warunki mogą nie być spełnione np. wtedy, gdy przestrzenność jest niedostępna w przypadku bieżącej ścieżki audio lub jest całkowicie wyłączona na urządzeniu wyjściowym audio.

Monitorowanie ruchów głowy

W przypadku obsługiwanych zestawów słuchawkowych platforma może dostosowywać przestrzenność dźwięku na podstawie pozycji głowy użytkownika. Aby sprawdzić, czy monitorowanie ruchów głowy jest dostępne w przypadku bieżącego routingu wyjścia audio, wywołaj funkcję isHeadTrackerAvailable().

Odpowiednie treści

Spatializer.canBeSpatialized() Wskazuje, czy dźwięk o podanych właściwościach można przestrzenizować za pomocą bieżącego routingu urządzenia wyjściowego. Ta metoda przyjmuje argumenty AudioAttributesAudioFormat, które zostały opisane bardziej szczegółowo poniżej.

AudioAttributes

Obiekt AudioAttributes opisuje sposób użycia strumienia audio (np. dźwięk w grze lub standardowe multimedia), a także jego zachowania podczas odtwarzania i typ treści.

Podczas wywoływania canBeSpatialized() używaj tej samej instancji AudioAttributes, która jest ustawiona dla Player. Jeśli na przykład używasz biblioteki Jetpack Media3 i nie masz dostosowanego elementu AudioAttributes, użyj AudioAttributes.DEFAULT.

Wyłączanie dźwięku przestrzennego

Aby wskazać, że treści zostały już przestrzenne, wywołaj funkcję setIsContentSpatialized(true) tak, aby dźwięk nie był przetwarzany podwójnie. Możesz też dostosować zachowanie przestrzenne, aby całkowicie wyłączyć przestrzenność, wywołując funkcję setSpatializationBehavior(AudioAttributes.SPATIALIZATION_BEHAVIOR_NEVER).

AudioFormat

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

Podczas tworzenia instancji AudioFormat do przekazania do canBeSpatialized() ustaw kodowanie na takie samo jak format wyjściowy oczekiwany od dekodera. Powinieneś też ustawić maskę kanału, która pasuje do konfiguracji kanału Twoich treści. Wskazówki dotyczące konkretnych wartości znajdziesz w sekcji Domyślne zachowanie przestrzenne.

Nasłuchiwanie zmian w Spatializer

Aby nasłuchiwać zmian stanu Spatializer, możesz dodać odbiornik za pomocą Spatializer.addOnSpatializerStateChangedListener(). Podobnie, aby nasłuchiwać zmian w dostępności śledzenia ruchu głowy, wywołaj funkcję Spatializer.addOnHeadTrackerAvailableListener().

Może to być przydatne, jeśli chcesz dostosować wybór ścieżki podczas odtwarzania za pomocą wywołań zwrotnych słuchacza. Na przykład gdy użytkownik podłączy lub odłączy słuchawki od urządzenia, wywołanie zwrotne onSpatializerAvailableChanged wskazuje, czy efekt przestrzenny jest dostępny w przypadku nowego routingu wyjścia audio. W tym momencie możesz rozważyć zaktualizowanie logiki wyboru ścieżki odtwarzacza, aby dopasować ją do nowych możliwości urządzenia. Więcej informacji o wybieraniu ścieżek przez ExoPlayer znajdziesz w sekcji ExoPlayer i dźwięk przestrzenny.

ExoPlayer i dźwięk przestrzenny

Najnowsze wersje ExoPlayera ułatwiają wdrożenie dźwięku przestrzennego. Jeśli używasz samodzielnej biblioteki ExoPlayer (nazwa pakietu com.google.android.exoplayer2), wersja 2.17 konfiguruje platformę do odtwarzania 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 ExoPlayera do najnowszej wersji aplikacja musi tylko zawierać treści, które można przestrzennie odtwarzać.

Ograniczenia dotyczące liczby kanałów audio

Gdy wszystkie 4 warunki dźwięku przestrzennego są spełnione, ExoPlayer wybiera wielokanałową ścieżkę audio. W przeciwnym razie ExoPlayer wybierze ścieżkę stereo. Jeśli zmienią się właściwości Spatializer, ExoPlayer wywoła nowy wybór ścieżki, aby wybrać ścieżkę audio pasującą do bieżących właściwości. Pamiętaj, że wybranie nowej ścieżki może spowodować krótkie ponowne buforowanie.

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

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 istniejącego selektora ścieżek, aby wyłączyć ograniczenia 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 ograniczenia dotyczące liczby kanałów audio są wyłączone, a treści mają wiele ścieżek audio, ExoPlayer początkowo wybiera ścieżkę z największą liczbą kanałów, którą można odtworzyć na urządzeniu. Jeśli na przykład treść zawiera ścieżkę audio wielokanałową i ścieżkę audio stereo, a urządzenie obsługuje odtwarzanie obu tych ścieżek, ExoPlayer wybierze ścieżkę wielokanałową. Więcej informacji o tym, jak dostosować to działanie, znajdziesz w sekcji Wybór ścieżki audio.

Wybór ścieżki audio

Gdy zachowanie ograniczeń liczby kanałów audio ExoPlayera jest wyłączone, ExoPlayer nie wybiera automatycznie ścieżki audio, która pasuje do właściwości przestrzennego procesora urządzenia. Zamiast tego możesz dostosować logikę wyboru ścieżki w ExoPlayerze, ustawiając parametry wyboru ścieżki przed odtwarzaniem lub w jego trakcie. 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 ścieżki

Aby zmienić parametry wyboru ścieżki ExoPlayera, użyj metody Player.setTrackSelectionParameters(). Podobnie możesz pobrać bieżące parametry ExoPlayera za pomocą kodu 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ć przerwę w odtwarzaniu. Więcej informacji o dostrajaniu parametrów wyboru ścieżki odtwarzacza znajdziesz w sekcji wybór ścieżki w dokumentacji ExoPlayera.

Domyślne zachowanie przestrzenne

Domyślne zachowanie przestrzenne w Androidzie obejmuje te zachowania, które producenci OEM mogą dostosowywać:

  • Przestrzenne są tylko treści wielokanałowe, a nie stereofoniczne. Jeśli nie używasz ExoPlayera, w zależności od formatu wielokanałowych treści audio może być konieczne skonfigurowanie maksymalnej liczby kanałów, które mogą być przesyłane przez dekoder audio, na dużą liczbę. Dzięki temu dekoder audio będzie generować wielokanałowy format PCM, który platforma może uprzestrzennić.

    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 samodzielnie wyłączyć przestrzenność, niezależnie od dostosowania przez producenta OEM, przeczytaj artykuł Wyłączanie dźwięku przestrzennego.

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

  • AudioFormat: użyj maski kanału, która zawiera co najmniej kanały AudioFormat.CHANNEL_OUT_QUAD (przedni lewy, przedni prawy, tylny lewy i tylny prawy), aby dźwięk kwalifikował się do przestrzennego odtwarzania. W przykładzie poniżej używamy AudioFormat.CHANNEL_OUT_5POINT1 w przypadku ś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ć Util.getAudioTrackChannelConfig(int channelCount), aby przekonwertować liczbę kanałów na maskę kanałów.

    Dodatkowo ustaw kodowanie na AudioFormat.ENCODING_PCM_16BIT, jeśli dekoder jest skonfigurowany do generowania wielokanałowego PCM.

    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 na urządzeniu testowym jest włączony dźwięk przestrzenny:

  • W przypadku słuchawek przewodowych wybierz Ustawienia systemu > Dźwięk i wibracje > Dźwięk przestrzenny.
  • W przypadku słuchawek bezprzewodowych otwórz Ustawienia systemu > Połączone urządzenia > Ikona koła zębatego przy urządzeniu bezprzewodowym > Dźwięk przestrzenny.

Aby sprawdzić dostępność dźwięku przestrzennego w przypadku bieżącego routingu, uruchom na urządzeniu polecenie adb shell dumpsys audio. Podczas odtwarzania w danych wyjściowych powinny być widoczne te parametry:

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