Dźwięk przestrzenny

Dźwięk przestrzenny to realistyczne doznania dźwiękowe, na podstawie których użytkownicy mogą znaleźć się w centrum akcji. Dźwięk jest „przestrzenny” w celu utworzenia efektu wielu głośników, podobnie jak w przypadku dźwięku przestrzennego, ale przez słuchawki.

Na przykład w filmie dźwięk samochodu może rozpoczynać się z tyłu, przesuwać się do przodu i w oddali. W trakcie czatu wideo głosy można rozdzielić i rozmieścić wokół użytkownika, co ułatwia rozpoznanie mówiących osób.

Jeśli Twoje treści zawierają obsługiwany format audio, na Androidzie 13 (poziom interfejsu API 33) możesz dodać dźwięk przestrzenny do swojej aplikacji.

Zapytanie o możliwości

Użyj klasy Spatializer, aby przesłać zapytanie o możliwości i działanie urządzenia w zakresie przestrzennym. Zacznij od pobrania instancji Spatializer z AudioManager:

Kotlin

val spatializer = audioManager.spatializer

Java

Spatializer spatializer = AudioManager.getSpatializer();

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

Kryteria Sprawdź
Czy urządzenie obsługuje przestrzenność? getImmersiveAudioLevel() nie ma wartości SPATIALIZER_IMMERSIVE_LEVEL_NONE
Czy jest dostępna przestrzenność?
Dostępność zależy od zgodności z aktualnym kierowaniem wyjścia audio.
isAvailable(): true
Czy przestrzenność jest włączona? isEnabled(): true
Czy ścieżka audio z podanymi parametrami może być przestrzenna? canBeSpatialized(): true

Te warunki mogą nie być spełnione, np. gdy funkcja przestrzenna jest niedostępna w przypadku bieżącej ścieżki audio lub 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 dostosować przestrzenność dźwięku w zależności od pozycji głowy użytkownika. Aby sprawdzić, czy urządzenie śledzące jest dostępne na potrzeby bieżącego kierowania dźwięku, wywołaj isHeadTrackerAvailable().

Zgodne treści

Spatializer.canBeSpatialized() wskazuje, czy dźwięk o podanych właściwościach można przekształcić w przestrzenne za pomocą bieżącego routingu urządzenia wyjściowego. Ta metoda wymaga znaczników AudioAttributes i AudioFormat. Oba zostały opisane bardziej szczegółowo poniżej.

AudioAttributes

Obiekt AudioAttributes opisuje użycie strumienia audio (np. dźwięk z gry lub standardowe multimedia), wraz z jego sposobem odtwarzania i typem treści.

Wywołując canBeSpatialized(), użyj instancji AudioAttributes ustawionej dla Player. Jeśli np. korzystasz z biblioteki Jetpack Media3 i nie dostosowałeś AudioAttributes, użyj właściwości AudioAttributes.DEFAULT.

Wyłączanie dźwięku przestrzennego

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

AudioFormat

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

Tworząc instancję AudioFormat, która ma być przekazywana do canBeSpatialized(), ustaw kodowanie na taki sam format wyjściowy, jaki oczekuje dekoder. Ustaw też maską kanału, która pasuje do konfiguracji kanału, w którym znajdują się Twoje treści. Wskazówki dotyczące konkretnych wartości znajdziesz w sekcji Domyślne zachowanie przestrzenne.

Wypatruj zmian w dokumencie Spatializer

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

Jest to przydatne, gdy chcesz zmienić wybór ścieżek podczas odtwarzania, korzystając z wywołań zwrotnych słuchaczy. Jeśli na przykład użytkownik połączy lub odłączy zestaw słuchawkowy od urządzenia, wywołanie zwrotne onSpatializerAvailableChanged wskazuje, czy efekt przestrzenny jest dostępny w przypadku nowego kierowania dźwięku. W tym momencie możesz rozważyć zaktualizowanie logiki wyboru ścieżki odtwarzacza, aby dopasować ją do nowych funkcji urządzenia. Szczegółowe informacje o sposobie wyboru ścieżki odtwarzacza ExoPlayer znajdziesz w sekcji ExoPlayer i 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ę 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.

Gdy zaktualizujesz zależność ExoPlayer do najnowszej wersji, aplikacja musi po prostu zawierać treści, które można wyskalować w sposób przestrzenny.

Ograniczenia liczby kanałów audio

Gdy zostaną spełnione wszystkie 4 warunki dźwięku przestrzennego, ExoPlayer wybierze wielokanałową ścieżkę audio. W przeciwnym razie ExoPlayer wybiera ścieżkę stereo. Jeśli właściwości Spatializer zmienią się, ExoPlayer uruchomi nowy wybór ścieżki, aby wybrać ścieżkę dźwiękową, która odpowiada bieżącym właściwościom. Pamiętaj, że nowy wybór ścieżki 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()
);

Aby w ten sposób wyłączyć ograniczenia liczby kanałów audio, możesz w podobny sposób zaktualizować dotychczasowe parametry selektora ścieżek:

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, ExoPlayer początkowo wybiera ścieżkę z największą liczbą kanałów, którą można odtworzyć na urządzeniu, jeśli dany materiał zawiera wiele ścieżek audio. Jeśli na przykład materiał zawiera wielokanałową i stereofoniczną ścieżkę audio, a urządzenie obsługuje odtwarzanie obu, ExoPlayer wybiera ścieżkę wielokanałową. Aby dowiedzieć się, jak dostosować to działanie, przeczytaj sekcję Wybór ścieżki audio.

Wybór ścieżki audio

Gdy ograniczenie liczby kanałów audio w narzędziu ExoPlayer jest wyłączone, nie wybiera on automatycznie ścieżki audio, która odpowiada właściwościom komponentu przestrzennego urządzenia. Zamiast tego możesz dostosować logikę wyboru utworu przez ExoPlayera, ustawiając parametry wyboru przed odtworzeniem lub w trakcie 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 ExoPlayer, użyj Player.setTrackSelectionParameters(). Bieżące parametry ExoPlayera możesz też uzyskać za pomocą narzędzia 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 zakłócić odtwarzanie. Więcej informacji o dostosowywaniu parametrów wyboru ścieżki odtwarzacza znajdziesz w sekcji wybór ścieżki w dokumentacji ExoPlayer.

Domyślne zachowanie przestrzenne

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

  • Tylko treści wielokanałowe są przestrzenne, a nie 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óre mogą być przesyłane przez dekoder audio dla dużej liczby kanałów. Dzięki temu dekoder dźwięku generuje wielokanałowy format PCM, aby platforma mogła wykorzystać go w przestrzeni.

    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 znajdziesz w dokumentacji ExoPlayer (MediaCodecAudioRenderer.java). Aby samodzielnie wyłączyć stosowanie dźwięku przestrzennego, niezależnie od dostosowania OEM, przeczytaj artykuł Wyłączanie dźwięku przestrzennego.

  • AudioAttributes: dźwięk kwalifikuje się do przestrzennego ustawienia, jeśli element usage ma wartość USAGE_MEDIA lub USAGE_GAME.

  • AudioFormat: użyj maski kanału, która zawiera co najmniej AudioFormat.CHANNEL_OUT_QUAD kanałów (przedni lewy, przedni prawy, tylny lewy i tylny prawy), aby dźwięk kwalifikował się do przestrzennego zastosowania. W poniższym przykładzie używamy AudioFormat.CHANNEL_OUT_5POINT1 w przypadku ścieżki audio 5.1. W przypadku ścieżki stereo użyj AudioFormat.CHANNEL_OUT_STEREO.

    Jeśli korzystasz z Media3, możesz za pomocą narzędzia Util.getAudioTrackChannelConfig(int channelCount) przekonwertować liczbę kanałów na maskę kanału.

    Dodatkowo ustaw kodowanie na AudioFormat.ENCODING_PCM_16BIT, jeśli dekoder został skonfigurowany do odtwarzania 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();
    

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 otwórz 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)