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 sprawiają, że treści brzmią bardziej realistycznie. „Uprzestrzennienie” dźwięku pozwala 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 rozpoczynać się za plecami użytkownika, a potem przesuwać się do przodu i zanikać w oddali. Na czacie wideo głosy można rozdzielić i rozmieścić wokół użytkownika, co ułatwia rozpoznawanie osób mówiących.

Jeśli Twoje treści korzystają z obsługiwanego formatu dźwięku, dźwięk przestrzenny możesz dodawać do aplikacji już na Androidzie 13 (poziom API 33).

Zapytanie o możliwości

Użyj klasy Spatializer, aby wysłać zapytanie dotyczące możliwości i działania urządzenia w zakresie przestrzennego działania urządzenia. Zacznij od pobrania instancji Spatializer z AudioManager:

Kotlin

val spatializer = audioManager.spatializer

Java

Spatializer spatializer = AudioManager.getSpatializer();

Po uzyskaniu Spatializer sprawdź 4 warunki, które muszą zostać spełnione, by urządzenie mogło odtwarzać dźwięk przestrzenny:

Kryteria Czek
Czy urządzenie obsługuje stosowanie przestrzeni przestrzennej? getImmersiveAudioLevel() nie jest SPATIALIZER_IMMERSIVE_LEVEL_NONE
Czy jest dostępna analiza przestrzenna? Dostępność funkcji
zależy od zgodności z bieżącym kierowaniem wyjścia audio.
isAvailable() to true
Czy przestrzennia jest włączona? isEnabled() to true
Czy ścieżkę audio z podanymi parametrami można zastosować w przestrzeni przestrzennej? canBeSpatialized() to true

Te warunki mogą nie zostać spełnione, np. jeśli nie można zastosować przekształcenia przestrzennego w przypadku bieżącej ścieżki audio lub jest całkowicie wyłączone 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 tracker jest dostępny przy bieżącym kierowaniu wyjścia audio, wywołaj isHeadTrackerAvailable().

Zgodne treści

Spatializer.canBeSpatialized() wskazuje, czy dźwięk o podanych właściwościach może zostać przestrzenny z obecnym kierowaniem urządzenia wyjściowego. Ta metoda korzysta z obiektów AudioAttributes i AudioFormat. Oba te metody zostały szczegółowo opisane poniżej.

AudioAttributes

Obiekt AudioAttributes opisuje użycie strumienia audio (na przykład dźwięk z gry lub standardowe multimedia), a także sposób jego odtwarzania i typ treści.

Wywołując metodę canBeSpatialized(), użyj takiej samej instancji AudioAttributes jak w przypadku instancji Player. Jeśli na przykład używasz biblioteki Jetpack Media3 bez dostosowania AudioAttributes, użyj AudioAttributes.DEFAULT.

Wyłączanie dźwięku przestrzennego

Aby wskazać, że treści zostały już przekształcone w przestrzeni, wywołaj metodę setIsContentSpatialized(true), aby dźwięk nie był przetworzony podwójnie. Możesz też dostosować działanie przestrzenne, aby całkowicie wyłączyć przekształcanie przestrzenne, wywołując metodę setSpatializationBehavior(AudioAttributes.SPATIALIZATION_BEHAVIOR_NEVER).

AudioFormat

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

Podczas tworzenia instancji AudioFormat przekazywanej do canBeSpatialized() ustaw kodowanie na taki sam format jak format wyjściowy oczekiwany od dekodera. Ustaw maskę kanału, która pasuje do konfiguracji Twojego kanału. Wskazówki dotyczące konkretnych wartości, których należy użyć, znajdziesz w sekcji Domyślne zachowanie przestrzenny.

Wykrywaj zmiany w: Spatializer

Aby nasłuchiwać zmian stanu obiektu Spatializer, możesz dodać detektor za pomocą funkcji Spatializer.addOnSpatializerStateChangedListener(). Aby wykryć zmiany w dostępności trackera, wywołaj Spatializer.addOnHeadTrackerAvailableListener().

Jest to przydatne, gdy chcesz dostosować wybór ścieżki podczas odtwarzania za pomocą wywołań zwrotnych słuchacza. Na przykład, gdy użytkownik podłącza lub odłącza swój zestaw słuchawkowy od urządzenia, wywołanie zwrotne onSpatializerAvailableChanged wskazuje, czy w przypadku nowego routingu wyjścia audio jest dostępny efekt przestrzenny. W tym momencie możesz zaktualizować logikę wyboru ścieżki w odtwarzaczu, aby dostosować ją do nowych możliwości urządzenia. Szczegółowe informacje o tym, jak ExoPlayer wybiera ścieżki, znajdziesz w sekcji ExoPlayer a dźwięk przestrzenny.

ExoPlayer i dźwięk przestrzenny

Najnowsze wersje ExoPlayer ułatwiają korzystanie z dźwięku przestrzennego. Jeśli używasz samodzielnej biblioteki ExoPlayer (nazwa pakietu com.google.android.exoplayer2), wersja 2.17 konfiguruje platformę tak, aby wydawał dźwięk przestrzenny, 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 tylko zawierać treści, które można umieścić w przestrzeni przestrzennej.

Ograniczenia liczby kanałów audio

Gdy zostaną spełnione wszystkie 4 warunki dotyczące dźwięku przestrzennego, ExoPlayer wybiera wielokanałową ścieżkę audio. W przeciwnym razie ExoPlayer wybiera ścieżkę stereo. Jeśli właściwości Spatializer ulegną zmianie, ExoPlayer wybierze nową ścieżkę audio, która pasuje do bieżących właściwości. Pamiętaj, że wybór nowej ścieżki audio może spowodować krótki okres ponownego buforowania.

Aby wyłączyć ograniczenia liczby kanałów audio, ustaw parametry wyboru ścieżki w odtwarzaczu w następujący 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ć istniejące parametry selektora ścieżki, aby wyłączyć ograniczenia liczby kanałów audio w ten sposób:

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

Gdy ograniczenie liczby kanałów audio jest wyłączone, to jeśli treści zawierają wiele ścieżek audio, ExoPlayer początkowo wybiera utwór z największą liczbą kanałów i można go odtworzyć na urządzeniu. Jeśli np. materiał zawiera wielokanałową i stereofoniczną ścieżkę audio, a urządzenie obsługuje odtwarzanie obu, ExoPlayer wybierze ścieżkę wielokanałową. Szczegółowe informacje o tym, jak dostosować ten sposób działania, znajdziesz w sekcji Wybór ścieżki dźwiękowej.

Wybór ścieżki audio

Gdy działanie ograniczeń liczby kanałów audio w oprogramowaniu ExoPlayer jest wyłączone, ExoPlayer nie wybiera automatycznie ścieżki audio, która pasuje do właściwości rozmieszczenia przestrzennego urządzenia. Zamiast tego możesz dostosować logikę wyboru ścieżki ExoPlayer przez ustawienie parametrów wyboru ścieżki przed odtwarzaniem lub w jego trakcie. Domyślnie ExoPlayer wybiera ścieżki audio takie same jak ścieżka początkowa, jeśli chodzi o typ MIME (kodowanie), liczbę kanałów i częstotliwość próbkowania.

Zmiana parametrów wyboru ścieżki

Aby zmienić parametry wyboru ścieżki w odtwarzaczu ExoPlayer, użyj polecenia Player.setTrackSelectionParameters(). Bieżące parametry ExoPlayer możesz też uzyskać za pomocą Player.getTrackSelectionParameters(). Aby na przykład wybrać stereofoniczną ścieżkę dźwiękową 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 utworu w trakcie odtwarzania może spowodować przerwanie odtwarzania. Więcej informacji o dostrajaniu parametrów wyboru ścieżki odtwarzacza znajdziesz w sekcji Wybór ścieżki w dokumentacji ExoPlayer.

Domyślne zachowanie przestrzeni

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

  • Przestrzenne są tylko treści wielokanałowe, a nie materiały stereo. Jeśli nie używasz ExoPlayer, to w zależności od formatu wielokanałowych treści audio może być konieczne skonfigurowanie maksymalnej liczby kanałów, którą dekoder audio może wysłać na dużą liczbę. Dzięki temu dekoder dźwięku wysyła wielokanałowy PCM, aby platforma stała się przestrzenna.

    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 przewodniku firmy ExoPlayer MediaCodecAudioRenderer.java. Aby samodzielnie wyłączyć stosowanie dźwięku przestrzennego bez względu na dostosowanie OEM, przeczytaj artykuł Wyłączanie dźwięku przestrzennego.

  • AudioAttributes: dźwięk może być przestrzenny, jeśli usage ma ustawienie 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, lewy i tylny prawy), aby dźwięk kwalifikował się do przekształcenia w przestrzeni. W przykładzie poniżej używamy słowa AudioFormat.CHANNEL_OUT_5POINT1 w przypadku ścieżki audio 5.1. W przypadku stereofonicznej ścieżki audio użyj AudioFormat.CHANNEL_OUT_STEREO.

    Jeśli korzystasz z Media3, możesz użyć parametru Util.getAudioTrackChannelConfig(int channelCount), aby przekonwertować liczbę kanałów na maskę kanału.

    Dodatkowo, jeśli dekoder został skonfigurowany tak, by wyjścić wielokanałowy PCM, 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();
    

Przetestuj dźwięk przestrzenny

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

  • W przypadku przewodowych zestawów słuchawkowych kliknij Ustawienia systemu > Dźwięk i wibracje > Dźwięk przestrzenny.
  • W przypadku bezprzewodowych zestawów słuchawkowych kliknij Ustawienia systemu > Połączone urządzenia > Ikona koła zębatego 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. Gdy odtwarzanie jest aktywne, w danych wyjściowych powinny być widoczne te parametry:

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