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 oferują większy realizm. Przez dodanie do aspektu przestrzennego uzyskuje się efekt wydobywania się dźwięku z 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 czatu wideo głosy mogą być rozdzielane i umieszczane wokół użytkownika, co ułatwia identyfikację rozmówców.

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

Zapytanie o możliwości

Użyj klasy Spatializer, aby wysyłać zapytania o możliwości i zachowanie dotyczące aspektu przestrzennego 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 wymagane do odtwarzania dźwięku przestrzennego na urządzeniu:

Kryteria Czek
Czy urządzenie obsługuje dodawanie aspektu przestrzennego? getImmersiveAudioLevel() nie jest równe SPATIALIZER_IMMERSIVE_LEVEL_NONE
Czy opcja dodawania aspektu przestrzennego jest dostępna?
Dostępność zależy od zgodności z bieżącym routingiem wyjścia audio.
isAvailable() jest równe true
Czy opcja dodawania aspektu przestrzennego jest włączona? isEnabled() jest równe true
Czy do ścieżki audio o podanych parametrach można dodać aspekt przestrzenny? canBeSpatialized() jest równe true

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

Śledzenie ruchów głowy

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

Zgodne treści

Spatializer.canBeSpatialized() wskazuje, czy do dźwięku o podanych właściwościach można dodać aspekt przestrzenny 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 użycie strumienia audio (np. dźwięk w grze lub standardowe multimedia) oraz jego zachowania podczas odtwarzania i typ treści.

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

Wyłączanie dźwięku przestrzennego

Wskaż, że do treści już dodano aspekt przestrzenny przez wywołanie funkcji setIsContentSpatialized(true), aby dźwięk nie był przetwarzany podwójnie. Możesz też dostosować zachowanie dotyczące aspektu przestrzennego, aby całkowicie go wyłączyć, wywołując setSpatializationBehavior(AudioAttributes.SPATIALIZATION_BEHAVIOR_NEVER).

AudioFormat

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

Podczas tworzenia instancji AudioFormat do przekazania do canBeSpatialized() ustaw kodowanie na takie samo jak format wyjściowy oczekiwany od dekodera. Trzeba 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 na temat domyślnego zachowania dotyczącego aspektu przestrzennego.

Sprawdzanie zmian w elemencie Spatializer

Aby monitorować zmiany stanu Spatializer, możesz dodać detektor za pomocą Spatializer.addOnSpatializerStateChangedListener(). W celu monitorowania 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 detektora. 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 w celu dopasowania jej 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 ExoPlayer do najnowszej wersji Twoja aplikacja musi tylko zawierać treści, do których można dodać aspekt przestrzenny.

Ograniczenia 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 wybiera ścieżkę stereo. Jeśli właściwości Spatializer ulegną zmianie, ExoPlayer uruchomi nowy wybór ścieżki, aby wybrać ścieżkę audio, która pasuje do bieżących właściwości. Pamiętaj, że ten nowy wybór ścieżki może spowodować krótkie ponowne buforowanie.

Aby wyłączyć ograniczenia 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()
);

Możesz też zaktualizować parametry istniejącego 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 ograniczenia liczby kanałów audio są wyłączone, a treści mają wiele ścieżek audio, ExoPlayer początkowo wybiera ścieżkę, która ma największą liczbę kanałów i może być odtwarzana 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 dostosowywaniu tego zachowania znajdziesz w sekcji Wybór ścieżki audio.

Wybór ścieżki audio

Gdy ograniczenia dotyczące liczby kanałów audio w ExoPlayerze są wyłączone, ExoPlayer nie wybiera automatycznie ścieżki audio, która pasuje do właściwości wtyczki spatializer 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 w ExoPlayerze, użyj Player.setTrackSelectionParameters(). Możesz też pobrać bieżące parametry ExoPlayera za pomocą 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 wyboru ścieżki w dokumentacji ExoPlayera.

Domyślne zachowanie dotyczące aspektu przestrzennego

Domyślne zachowanie dotyczące aspektu przestrzennego w Androidzie obejmuje te zachowania, które oryginalni producenci mogą dostosowywać:

  • Aspekt przestrzenny jest dodawany tylko do treści wielokanałowych, a nie stereofonicznych. Jeśli nie używasz ExoPlayera, w zależności od formatu wielokanałowych treści audio może być konieczne skonfigurowanie dużej wartości dla maksymalnej liczby kanałów, które mogą być przesyłane przez dekoder audio. Dzięki temu dekoder audio będzie generować wielokanałowy format PCM, do którego platforma może dodawać aspekt 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 samodzielnie wyłączyć dodawanie aspektu przestrzenności, niezależnie od dostosowania przez oryginalnego producenta, przeczytaj sekcję Wyłączanie dźwięku przestrzennego.

  • AudioAttributes: dźwięk kwalifikuje się do odtwarzania przestrzennego jeśli usage jest ustawione 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 odtwarzania przestrzennego. 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łu.

    Jeśli dekoder jest skonfigurowany do generowania wielokanałowego formatu 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();

Testowanie dźwięku przestrzennego

Upewnij się, że na urządzeniu testowym włączony jest dźwięk przestrzenny:

  • W przypadku słuchawek przewodowych otwórz 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 obok urządzenia bezprzewodowego > 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 aktywnego odtwarzania w danych wyjściowych powinny się pojawić te parametry:

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