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

В 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_configuration.xml был расширен за счет добавления двух новых полей: audioZoneId и occupantZoneId . Во-первых, audioZoneId можно использовать для лучшего управления зонами. С другой стороны, occupantZoneId можно использовать для настройки маршрутизации на основе идентификатора пользователя.

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

<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 приложения

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

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

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

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

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