Аудио маршрутизация

В Android 10 car_audio_configuration.xml заменяет car_volumes_groups.xml и IAudioControl.getBusForContext . В новом конфигурационном файле определен список зон. Каждая зона имеет одну или несколько групп томов со связанными с ними устройствами, и у каждого устройства есть контексты, которые должны маршрутизироваться в пределах этой зоны. Необходимо, чтобы все контексты были представлены в каждой зоне.

Настройка маршрутизации аудио

Файлы политики аудио, которые обычно находятся в разделе поставщика, представляют собой конфигурацию аудиооборудования платы. Все устройства, указанные в car_audio_configuration.xml , должны быть определены в audio_policy_configuration.xml .

Включение маршрутизации AAOS

Чтобы использовать маршрутизацию на основе AAOS, вы должны установить для флага audioUseDynamicRouting значение true :

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

При false маршрутизация и большая часть CarAudioService будут отключены, а ОС вернется к поведению AudioService по умолчанию.

Основная зона

По умолчанию все аудио будет направляться в основную зону. Основная зона может быть только одна, что указывается в конфигурации атрибутом isPrimary="true" .

Пример конфигурации

Например, в автомобиле может быть две зоны — основная зона и развлекательная система для пассажиров задних сидений. При этом возможный car_audio_configuration.xml будет определен следующим образом:

<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>

Здесь основная зона разделила контексты на разные устройства. Это позволяет HAL применять различные эффекты постобработки и микширования на выходе каждого устройства, используя аппаратное обеспечение автомобиля. Устройства разбиты на четыре группы громкости: мультимедиа, навигация, вызовы и будильники. Если система настроена на useFixedVolume , то уровни громкости для каждой группы будут переданы в HAL для применения к выходным данным этих устройств.

Для вторичной зоны ожидаемый вывод осуществляется через одно устройство вывода. В этом примере для простоты все использования направляются на одно устройство и группу томов.

Аудио конфигурация зоны присутствия

В Android 11 car_audio_configuraton.xml был расширен за счет добавления двух новых полей: audioZoneId и occupantZoneId . Во-первых, audioZoneId можно использовать для лучшего контроля управления зонами. С другой стороны, occupantZoneId можно использовать для настройки маршрутизации на основе идентификатора пользователя.

Чтобы использовать эти новые поля, требуется V2 car_audio_configuration.xml . Возвращаясь к приведенной выше конфигурации аудио, но используя новое поле для идентификатора зоны присутствия и сопоставления идентификатора аудиозоны, новую конфигурацию без определений группы громкости можно настроить как:

<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>

Приведенная выше конфигурация определяет сопоставление основной зоны с зоной агента 0 и audioZoneId 1 с occupantZoneId 1. В общем случае можно настроить любое сопоставление между зоной агента и аудиозоной, но сопоставление должно быть взаимно однозначным. Вот правила, определяющие два новых поля:

  • audioZoneId для основной зоны всегда равен нулю
  • audioZoneId и occupantZoneId не могут повторяться
  • audioZoneId и occupantZoneId могут иметь только сопоставление один к одному

Маршрутизация через UID приложения

В версии 10 для CarAudioManager был представлен ряд скрытых API-интерфейсов, позволяющих приложениям запрашивать и устанавливать звуковые зоны и фокус.

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

Вышеупомянутые API-интерфейсы позволяли стороннему приложению управлять маршрутизацией звука на основе UID приложения. Таким образом, также необходимы как идентификатор аудиозоны, так и UID приложения. Имея эту информацию, маршрутизацию звука можно настроить с помощью CarAudioManager#setZoneIdForUid API.

Изменение зон для приложения

По умолчанию все аудио направляются в основную зону. Чтобы обновить приложение для маршрутизации в другую зону, используйте 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 Примечание. Потоки и фокус не могут динамически переключать зоны. Поэтому воспроизведение необходимо остановить и повторно запросить фокус для смены зон.

Маршрутизация с идентификатором пользователя

Хотя маршрутизация на основе UID приложения позволяет точно управлять маршрутизацией звука каждого приложения, она также требует, чтобы маршрутизация звука для каждого приложения была определена до того, как приложение фактически запросит аудиофокус и воспроизведет звук. Чтобы смягчить эту проблему и еще больше упростить воспроизведение звука сторонними приложениями без изменений, CarAudioService использует сопоставление зоны пассажира и аудиозоны для определения маршрутизации на основе идентификатора пользователя. Таким образом, когда пользователь входит в зону присутствия, служба автомобильной аудиосистемы получает уведомление. С помощью этого сигнала управление аудиофокусом и маршрутизация автоматически настраиваются для всех аудиозон.

Маршрутизация приложений на основе UID по-прежнему может использоваться, но должна выполняться независимо от маршрутизации идентификатора пользователя. Это означает, что если определено сопоставление зоны пассажира с зоной автомобильной аудиосистемы, то маршрутизация на основе UID отключена, и попытка вызова CarAudioManager#setZoneidForUid вызовет ошибку.

Хотя маршрутизация звука и управление фокусом были упрощены с помощью управления зоной присутствия, пользователь по-прежнему должен быть назначен зоне присутствия. Это можно сделать с помощью CarOccupantZoneManager#assignProfileUserToOccupantZone . Для этого API требуется разрешение на управление пользователями. В настоящее время ожидается, что OEM-производители будут управлять назначением пользователя для зоны пребывания через какой-то системный пользовательский интерфейс. Как только это будет сделано, запуск приложения, маршрутизация звука, управление фокусом будут автоматически настроены для пользователя.

Маршрутизация с помощью setPreferredDevice

Наряду с вышеуказанными изменениями в Android 11 также есть новый API для запроса устройств вывода, связанных с каждой зоной, CarAudioManager#getOutputDeviceForUsage(int zoneId, int Usage).

API можно использовать для запроса устройства вывода для конкретной зоны и использования атрибута звука. Таким образом, сторонние приложения могут направлять звук в разные зоны, используя API проигрывателя setPreferredDevice . API getOutputDeviceForUsage требует PERMISSION_CAR_CONTROL_AUDIO_SETTINGS и является системным API. Ниже приведен пример поиска мультимедийного устройства для определенной зоны и маршрутизации к этому устройству с помощью API setPreferredDevice .

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