Kierowanie dźwięku

W Androidzie 10 car_audio_configuration.xml zastępuje car_volumes_groups.xmlIAudioControl.getBusForContext. W nowym pliku konfiguracji zdefiniowana jest lista stref. Każda strefa zawiera co najmniej 1 grupę objętości z powiązanymi urządzeniami, a każde urządzenie ma konteksty, które powinny być kierowane w ramach tej strefy. W każdej strefie muszą być uwzględnione wszystkie konteksty.

Konfigurowanie routingu dźwięku

Pliki zasad dotyczących dźwięku, które zwykle znajdują się w partycji dostawcy, reprezentują konfigurację sprzętu audio na płycie. Wszystkie urządzenia, do których odwołuje się element car_audio_configuration.xml, muszą być zdefiniowane w elemencie audio_policy_configuration.xml.

Włączanie kierowania AAOS

Aby korzystać z routingu na podstawie AAOS, musisz ustawić flagę audioUseDynamicRouting na true:

<resources>
    <bool name="audioUseDynamicRouting">true</bool>
</resources>

Gdy false jest wyłączona, routing i duża część CarAudioService są wyłączone, a system operacyjny stosuje domyślne zachowanie AudioService.

Strefa główna

Domyślnie cały dźwięk będzie kierowany do strefy głównej. Może być tylko jedna strefa główna, którą w konfiguracji wskazuje atrybut isPrimary="true".

Przykładowa konfiguracja

Na przykład pojazd może mieć 2 strefy: strefę główną i system rozrywki na tylnym siedzeniu. W tym przypadku car_audio_configuration.xml byłoby zdefiniowane w ten sposób:

<audioZoneConfiguration version="2.0">
       <zone name="primary zone" isPrimary="true">
           <volumeGroups>
               <group>
                   <device address="bus0_media_out">
                       <context context="music"/>
                       <context context="announcement"/>
                   </device>
                   <device address="bus3_call_ring_out">
                       <context context="call_ring"/>
                   </device>
                   <device address="bus6_notification_out">
                       <context context="notification"/>
                   </device>
                   <device address="bus7_system_sound_out">
                       <context context="system_sound"/>
                       <context context="emergency"/>
                       <context context="safety"/>
                       <context context="vehicle_status"/>
                   </device>
               </group>
               <group>
                   <device address="bus1_navigation_out">
                       <context context="navigation"/>
                   </device>
                   <device address="bus2_voice_command_out">
                       <context context="voice_command"/>
                   </device>
               </group>
               <group>
                   <device address="bus4_call_out">
                       <context context="call"/>
                   </device>
               </group>
               <group>
                   <device address="bus5_alarm_out">
                       <context context="alarm"/>
                   </device>
               </group>
           </volumeGroups>
       </zone>
        <zone name="rear seat zone" audioZoneId="1">
           <volumeGroups>
               <group>
                   <device address="bus100_rear_seat">
                       <context context="music"/>
                       <context context="navigation"/>
                       <context context="voice_command"/>
                       <context context="call_ring"/>
                       <context context="call"/>
                       <context context="alarm"/>
                       <context context="notification"/>
                       <context context="system_sound"/>
                       <context context="emergency"/>
                       <context context="safety"/>
                       <context context="vehicle_status"/>
                       <context context="announcement"/>
                   </device>
               </group>
           </volumeGroups>
    </zones>
</audioZoneConfiguration>

Tutaj główna strefa ma oddzielne konteksty na różnych urządzeniach. Dzięki temu HAL może stosować różne efekty postprodukcji i miksowania na wyjściu z każdego urządzenia, korzystając ze sprzętu pojazdu. Urządzenia zostały podzielone na 4 grupy głośności: multimedia, nawigacja, połączenia i alarmy. Jeśli system jest skonfigurowany na useFixedVolume, poziomy głośności dla każdej grupy zostaną przekazane do HAL, aby zastosować je na wyjściu tych urządzeń.

W przypadku strefy dodatkowej oczekiwane dane wyjściowe są przesyłane przez pojedyncze urządzenie wyjściowe. W tym przykładzie wszystkie zastosowania są kierowane do jednego urządzenia i grupy objętości, aby uprościć proces.

Konfiguracja dźwięku w strefie dla pasażerów

W Androidzie 11 car_audio_configuration.xml zostało rozszerzone o 2 nowe pola: audioZoneIdoccupantZoneId. Pierwszy, audioZoneId, może być używany do lepszego zarządzania strefami. Z drugiej strony, za pomocą occupantZoneId możesz skonfigurować routing na podstawie identyfikatora użytkownika.

Aby korzystać z tych nowych pól, musisz mieć wersję 2.0 pliku car_audio_configuration.xml. Wracając do konfiguracji dźwięku powyżej, ale z wykorzystaniem nowego pola do mapowania identyfikatora strefy pasażera i identyfikatora strefy dźwięku, nową konfigurację bez definicji grupy głośności można skonfigurować w ten sposób:

<audioZoneConfiguration version="2.0">
       <zone name="primary zone" isPrimary="true" occupantZoneId="0">
         ...
       </zone>
       <zone name="rear seat zone" audioZoneId="1" occupantZoneId="1">
         ...
       </zone>
    </zones>
</audioZoneConfiguration>

Powyższa konfiguracja definiuje mapowanie strefy głównej na strefę 0 pasażera oraz audioZoneId 1 na occupantZoneId 1. Ogólnie można skonfigurować dowolne mapowanie pomiędzy strefą pasażera a strefą audio, ale musi to być mapowanie jeden do jednego. Oto reguły, które zdefiniowały 2 nowe pola:

  • Wartość audioZoneId w przypadku głównej strefy czasowej jest zawsze równa 0.
  • Numery audioZoneId i occupantZoneId nie mogą się powtarzać
  • audioZoneId i occupantZoneId mogą mieć tylko mapowanie jeden do jednego

Przekierowywanie za pomocą identyfikatora UID aplikacji

W wersji 10 interfejsu CarAudioManager wprowadzono serię ukrytych interfejsów API, które umożliwiają aplikacjom wysyłanie zapytań i ustawianie stref oraz punktów skupienia dźwięku.

int[] getAudioZoneIds();
int getZoneIdForUid(int uid);
boolean setZoneIdForUid(int zoneId, int uid);
boolean clearZoneIdForUid(int uid);

Opisane wyżej interfejsy API umożliwiały aplikacji własnej zarządzanie kierowaniem dźwięku na podstawie identyfikatora UID aplikacji. Dlatego potrzebny jest też identyfikator strefy audio i identyfikator UID aplikacji. Po uzyskaniu tych informacji możesz skonfigurować kierowanie dźwięku za pomocą interfejsu API CarAudioManager#setZoneIdForUid.

Zmienianie stref dla aplikacji

Domyślnie wszystkie ścieżki audio są kierowane do strefy głównej. Aby zaktualizować aplikację, aby była kierowana do innej strefy, użyj CarAudioManager#setZoneIdForUid:

// Find zone to play
int zoneId = ...

// Find application's uid
Int uid = mContext.getPackageManager()
        .getApplicationInfo(mContext.getPackageName(), 0)
        .uid;

if (mCarAudioManager.setZoneIdForUid(zoneId, info.uid)) {
    Log.d(TAG, "Zone successfully updated");
} else {
    Log.d(TAG, "Failed to change zone");
}

N Uwaga: strumienie i fokus nie mogą dynamicznie zmieniać stref. Dlatego odtwarzanie musi zostać zatrzymane, a fokus musi zostać ponownie przesłany, aby zmienić strefy.

Przekierowywanie za pomocą identyfikatora użytkownika

Kierowanie na podstawie identyfikatora UID aplikacji umożliwia dokładne sterowanie kierowaniem dźwięku w poszczególnych aplikacjach, ale wymaga też zdefiniowania kierowania dźwięku dla każdej aplikacji przed faktycznym przesłaniem prośby o skupienie się na dźwięku i odtworzenie dźwięku. Aby rozwiązać ten problem i ułatwić aplikacjom innych firm odtwarzanie dźwięku bez wprowadzania zmian, CarAudioService używa mapowania strefy dla pasażerów i strefy dźwiękowej w samochodzie w celu zdefiniowania routingu na podstawie identyfikatora użytkownika. Gdy użytkownik zaloguje się w strefie pasażera, usługa audio samochodu zostanie o tym powiadomiona. Dzięki temu sygnałowi zarządzanie skupieniem dźwięku i przekierowywanie są automatycznie konfigurowane dla wszystkich stref dźwięku.

Nadal można używać routingu na podstawie identyfikatora UID aplikacji, ale musi on być niezależny od routingu na podstawie identyfikatora użytkownika. Oznacza to, że jeśli zdefiniowano mapowanie strefy pasażera do strefy dźwięku w samochodzie, kierowanie na podstawie identyfikatora UID jest wyłączone, a próba wywołania funkcji CarAudioManager#setZoneidForUid spowoduje błąd.

Mimo że dzięki zarządzaniu strefą dla pasażera uproszczono przekierowywanie dźwięku i zarządzanie skupieniem, użytkownik nadal musi zostać przypisany do strefy dla pasażera. Aby to zrobić, użyj CarOccupantZoneManager#assignProfileUserToOccupantZone. To API wymaga uprawnień do zarządzania użytkownikami. Obecnie oczekuje się, że OEM będą zarządzać przypisywaniem użytkowników do strefy dla pasażerów za pomocą interfejsu systemu. Gdy to zrobisz, uruchamianie aplikacji, kierowanie dźwięku i zarządzanie punktem skupienia zostaną automatycznie skonfigurowane dla użytkownika.

Routing z setPreferredDevice

Oprócz powyższych zmian Android 11 zawiera też nowy interfejs API do wysyłania zapytań do urządzeń wyjściowych powiązanych z każdą strefą (CarAudioManager#getOutputDeviceForUsage(int zoneId, int usage)).

Interfejs API może służyć do wysyłania zapytań do urządzenia wyjściowego w przypadku określonej strefy i zastosowania atrybutu audio. W ten sposób aplikacje własne mogą kierować dźwięk do różnych stref, korzystając z interfejsu API setPreferredDevice odtwarzacza. Interfejs API getOutputDeviceForUsage wymaga PERMISSION_CAR_CONTROL_AUDIO_SETTINGS i jest interfejsem API systemu. Poniżej znajdziesz przykład znajdowania urządzenia multimedialnego w konkretnej strefie i przekierowywania do niego za pomocą interfejsu API setPreferredDevice.

audioZoneId = ... ;
mediaDeviceInfo = mCarAudioManager
            .getOutputDeviceForUsage(audioZoneId, AudioAttributes.USAGE_MEDIA);
…
mPlayer.setPreferredDevice(mediaDeviceInfo);