Routing audio

W systemie Android 10 car_audio_configuration.xml zastępuje car_volumes_groups.xml i IAudioControl.getBusForContext . W nowym pliku konfiguracyjnym zdefiniowana jest lista wejść. Każda strefa ma co najmniej jedną grupę woluminów z powiązanymi z nią urządzeniami, a każde urządzenie ma konteksty, które powinny być kierowane w obrębie tej strefy. Wymagane jest, aby wszystkie konteksty były reprezentowane w każdej strefie.

Konfiguracja routingu audio

Pliki zasad audio, które zwykle znajdują się na partycji dostawcy, reprezentują konfigurację sprzętową audio płyty. Wszystkie urządzenia wymienione w car_audio_configuration.xml muszą być zdefiniowane w pliku audio_policy_configuration.xml .

Włączanie routingu AAOS

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

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

Jeśli false , routing i większość CarAudioService zostaną wyłączone, a system operacyjny powróci do domyślnego zachowania AudioService .

Strefa podstawowa

Domyślnie cały dźwięk będzie kierowany do strefy podstawowej. Może istnieć tylko jedna strefa podstawowa, co jest wskazywane w konfiguracji atrybutem isPrimary="true" .

Przykładowa konfiguracja

Na przykład pojazd może mieć dwie strefy — strefę główną i system rozrywki dla tylnych siedzeń. Dzięki temu możliwy car_audio_configuration.xml zostanie zdefiniowany w następujący 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 strefa podstawowa oddzieliła konteksty dla różnych urządzeń. Umożliwia to HAL zastosowanie różnych efektów przetwarzania końcowego i miksowanie na wyjściu każdego urządzenia przy użyciu sprzętu pojazdu. Urządzenia zostały podzielone na cztery grupy woluminów: multimedia, nawigacja, połączenia i alarmy. Jeśli system jest skonfigurowany do useFixedVolume , poziomy głośności dla każdej grupy zostaną przesłane do warstwy HAL w celu zastosowania na wyjściu tych urządzeń.

W przypadku strefy dodatkowej oczekiwana moc wyjściowa odbywa się za pośrednictwem pojedynczego urządzenia wyjściowego. W tym przykładzie wszystkie użycia są kierowane do pojedynczego urządzenia i grupy woluminów, aby wszystko było proste.

Konfiguracja dźwięku w strefie obecności

W Androidzie 11 car_audio_configuration.xml został dodatkowo rozszerzony, wprowadzając dwa nowe pola, audioZoneId i occupantZoneId . Pierwszy, audioZoneId może służyć do lepszej kontroli zarządzania strefą. Z drugiej strony occupantZoneId można wykorzystać do skonfigurowania routingu opartego na identyfikatorze użytkownika.

Aby móc korzystać z tych nowych pól, wymagana jest wersja 2 pliku car_audio_configuration.xml . Wracając do powyższej konfiguracji audio, ale wykorzystując nowe pole do mapowania identyfikatora strefy obecności i identyfikatora strefy audio, nową konfigurację bez definicji grup woluminów można skonfigurować jako:

<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ę obecności 0 i audioZoneId 1 na occupantZoneId 1. Ogólnie rzecz biorąc, można skonfigurować dowolne mapowanie pomiędzy strefą obecności a strefą audio, ale mapowanie musi być indywidualne. Oto zasady, które zdefiniowały dwa nowe pola:

  • audioZoneId strefy podstawowej ma zawsze wartość zero
  • Numery audioZoneId i occupantZoneId nie mogą się powtarzać
  • audioZoneId i occupantZoneId mogą mieć tylko mapowanie jeden do jednego

Routing przez UID aplikacji

W wersji 10 do CarAudioManager wprowadzono szereg ukrytych interfejsów API, aby umożliwić aplikacjom wysyłanie zapytań oraz ustawianie stref audio i fokusu.

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

Powyższe interfejsy API umożliwiły aplikacji własnej zarządzanie routingiem audio na podstawie identyfikatora UID aplikacji. W związku z tym potrzebny jest również identyfikator strefy audio i identyfikator UID aplikacji. Mając te informacje, można ustawić routing audio za pomocą interfejsu API CarAudioManager#setZoneIdForUid .

Zmiana stref dla aplikacji

Domyślnie wszystkie audio są kierowane do strefy podstawowej. Aby zaktualizować aplikację tak, 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 przełączać stref. Dlatego w celu zmiany stref należy zatrzymać odtwarzanie i ponownie zażądać ustawienia ostrości.

Routing z identyfikatorem użytkownika

Chociaż routing aplikacji oparty na UID pozwala na precyzyjną kontrolę routingu audio każdej aplikacji, wymaga również zdefiniowania routingu audio dla każdej aplikacji, zanim aplikacja faktycznie zażąda skupienia się na dźwięku i odtworzenia dźwięku. Aby złagodzić ten problem i jeszcze bardziej ułatwić aplikacjom innych firm odtwarzanie dźwięku bez modyfikacji, CarAudioService wykorzystuje mapowanie strefy pasażerów samochodu i strefy audio w celu zdefiniowania routingu na podstawie identyfikatora użytkownika. Dzięki temu, gdy użytkownik zaloguje się w strefie pasażerów, zostanie o tym powiadomiony system car audio. Dzięki temu sygnałowi zarządzanie fokusem audio i routing są automatycznie konfigurowane dla wszystkich stref audio.

Aplikacje Routing oparty na UID może być nadal używany, ale musi być wykonywany niezależnie od routingu identyfikatora użytkownika. Oznacza to, że jeśli zdefiniowano mapowanie strefy pasażerów na strefę car audio, wówczas routing oparty na UID jest wyłączony i próba wywołania CarAudioManager#setZoneidForUid zgłosi błąd.

Chociaż zarządzanie strefą pasażerów zostało uproszczone w zakresie kierowania sygnału audio i skupienia, użytkownik nadal musi być przypisany do strefy obecności. Można to zrobić za pomocą CarOccupantZoneManager#assignProfileUserToOccupantZone . Ten interfejs API wymaga uprawnień do zarządzania użytkownikami. Obecnie oczekuje się, że producenci OEM będą zarządzać przypisywaniem użytkowników do stref za pomocą pewnego rodzaju interfejsu użytkownika. Po zakończeniu uruchamianie aplikacji, kierowanie audio i zarządzanie fokusem zostaną automatycznie skonfigurowane dla użytkownika.

Routing za pomocą setPreferredDevice

Oprócz powyższych zmian w systemie Android 11 dostępny jest także nowy interfejs API umożliwiający wysyłanie zapytań do urządzeń wyjściowych powiązanych z każdą strefą: CarAudioManager#getOutputDeviceForUsage(intzoneId, int use).

Interfejsu API można używać do wysyłania zapytań do urządzenia wyjściowego o konkretną strefę i użycie atrybutu audio. W ten sposób aplikacje własne mogą kierować dźwięk do różnych stref, wykorzystując interfejs API setPreferredDevice odtwarzacza. Interfejs API getOutputDeviceForUsage wymaga PERMISSION_CAR_CONTROL_AUDIO_SETTINGS i jest interfejsem API systemu. Poniżej znajduje się przykład znalezienia urządzenia multimedialnego dla określonej strefy i routingu do tego urządzenia przy użyciu interfejsu API setPreferredDevice .

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