Roteamento de áudio

No Android 10, car_audio_configuration.xml substitui car_volumes_groups.xml e IAudioControl.getBusForContext. No novo arquivo de configuração, uma lista de zonas é definida. Cada zona tem um ou mais grupos de volume com os dispositivos associados, e cada dispositivo tem os contextos que precisam ser roteados dentro dessa zona. É necessário que todos os contextos sejam representados em cada zona.

Como configurar o roteamento de áudio

Os arquivos de política de áudio, que normalmente ficam na partição do fornecedor, representam a configuração de hardware de áudio da placa. Todos os dispositivos referenciados em car_audio_configuration.xml precisam ser definidos no audio_policy_configuration.xml.

Como ativar o roteamento do AAOS

Para usar o roteamento baseado em AAOS, defina a flag audioUseDynamicRouting como true:

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

Quando false, o roteamento e grande parte do CarAudioService serão desativados, e o SO vai voltar ao comportamento padrão do AudioService.

Zona principal

Por padrão, todo o áudio será roteado para a zona principal. Só pode haver uma zona principal, que é indicada na configuração pelo atributo isPrimary="true".

Exemplo de configuração

Por exemplo, um veículo pode ter duas zonas: uma principal e um sistema de entretenimento para o banco de trás. Com isso, um possível car_audio_configuration.xml seria definido da seguinte maneira:

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

Aqui, a zona principal separou os contextos para dispositivos diferentes. Isso permite que o HAL aplique diferentes efeitos de pós-processamento e mixagem em cada saída do dispositivo usando o hardware do veículo. Os dispositivos foram organizados em quatro grupos de volume: mídia, navegação, chamadas e alarmes. Se o sistema estiver configurado para useFixedVolume, os níveis de volume de cada grupo serão transmitidos para o HAL para serem aplicados à saída desses dispositivos.

Para a zona secundária, a saída esperada é por um único dispositivo de saída. Neste exemplo, todos os usos são roteados para o único dispositivo e grupo de volume para simplificar as coisas.

Configuração de áudio da zona do ocupante

No Android 11, o car_audio_configuration.xml foi expandido para apresentar dois novos campos, audioZoneId e occupantZoneId. A primeira, audioZoneId, pode ser usada para controlar melhor o gerenciamento de zonas. Por outro lado, occupantZoneId pode ser usado para configurar o roteamento com base no ID do usuário.

Para usar esses novos campos, é necessário usar a V2 do car_audio_configuration.xml. Voltando à configuração de áudio acima, mas usando o novo campo para o mapeamento de ID da zona do ocupante e do ID da zona de áudio, a nova configuração sem as definições de grupo de volume pode ser configurada como:

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

A configuração acima define um mapeamento da zona principal para a zona do ocupante 0 e audioZoneId 1 para occupantZoneId 1. Em geral, qualquer mapeamento entre a zona do ocupante e a zona de áudio pode ser configurado, mas o mapeamento precisa ser um para um. Confira as regras que definiram os dois novos campos:

  • O audioZoneId da zona principal é sempre zero
  • Os números audioZoneId e occupantZoneId não podem ser repetidos
  • audioZoneId e occupantZoneId só podem ter um mapeamento de um para um

Roteamento por um UID do aplicativo

Uma série de APIs ocultas foi introduzida em CarAudioManager na versão 10 para permitir que os apps consultem e definam zonas e foco de áudio.

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

As APIs acima permitiam que um aplicativo primário gerenciasse o roteamento de áudio com base no UID de um aplicativo. Portanto, o ID da zona de áudio e o UID do aplicativo também são necessários. Com essas informações, o roteamento de áudio pode ser definido usando a API CarAudioManager#setZoneIdForUid.

Como mudar as zonas de um app

Por padrão, todo o áudio é roteado para a zona principal. Para atualizar um aplicativo a ser encaminhado para outra zona, use 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 Observação:os fluxos e o foco não podem alternar dinamicamente as zonas. Portanto, a reprodução precisa ser interrompida e o foco precisa ser solicitado novamente para mudar de zona.

Roteamento com o ID do usuário

Embora o roteamento baseado em UID de um aplicativo permita o controle fino do roteamento de áudio de cada aplicativo, ele também exige que o roteamento de áudio de cada aplicativo seja definido antes de o aplicativo solicitar a seleção de áudio e tocar áudio. Para atenuar esse problema e facilitar ainda mais a reprodução de áudio sem modificações por aplicativos de terceiros, CarAudioService usa o mapeamento da zona de ocupantes do carro e da zona de áudio para definir o roteamento baseado no ID do usuário. Dessa forma, quando um usuário faz login na zona de ocupantes, o serviço de áudio do carro é notificado. Com esse sinal, o gerenciamento e o roteamento do foco de áudio são configurados automaticamente para todas as zonas de áudio.

O roteamento baseado em UID de aplicativos ainda pode ser usado, mas precisa ser feito de forma independente do roteamento de ID de usuário. Isso significa que, se o mapeamento da zona do ocupante para a zona de áudio do carro for definido, o roteamento baseado em UID será desativado e a tentativa de chamar CarAudioManager#setZoneidForUid vai gerar um erro.

Embora o roteamento de áudio e o gerenciamento de foco tenham sido simplificados com o gerenciamento de zona de ocupantes, o usuário ainda precisa ser atribuído a uma zona de ocupantes. Isso pode ser feito usando o CarOccupantZoneManager#assignProfileUserToOccupantZone. Essa API exige permissão para gerenciar usuários. A expectativa atual é que os OEMs gerenciem a atribuição de zonas de usuário a ocupantes por meio de algum tipo de interface do sistema. Depois disso, a inicialização do aplicativo, o roteamento de áudio e o gerenciamento de foco serão configurados automaticamente para o usuário.

Roteamento com setPreferredDevice

Além das mudanças acima, o Android 11 também tem uma nova API para consultar dispositivos de saída associados a cada zona, CarAudioManager#getOutputDeviceForUsage(int zoneId, int usage).

A API pode ser usada para consultar um dispositivo de saída em uma zona específica e um uso de atributo de áudio. Dessa forma, os aplicativos próprios podem encaminhar áudio para diferentes zonas usando a API setPreferredDevice do player. A API getOutputDeviceForUsage requer PERMISSION_CAR_CONTROL_AUDIO_SETTINGS e é uma API do sistema. Confira abaixo um exemplo de como encontrar o dispositivo de mídia de uma zona específica e rotear para esse dispositivo usando a API setPreferredDevice.

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