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 possui um ou mais grupos de volumes com seus dispositivos associados e cada dispositivo possui os contextos que devem ser roteados dentro dessa zona. É necessário que todos os contextos sejam representados em cada zona.

Configurando o roteamento de áudio

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

Habilitando roteamento AAOS

Para usar o roteamento baseado em AAOS, você deve definir o sinalizador audioUseDynamicRouting como true :

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

Quando false , o roteamento e grande parte do CarAudioService serão desabilitados e o sistema operacional retornará ao comportamento padrão do AudioService .

Zona primária

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

Configuração de amostra

Por exemplo, um veículo pode ter duas zonas – uma zona primária e um sistema de entretenimento no banco traseiro. Com isso, um possível car_audio_configuration.xml ficaria definido da seguinte forma:

<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 primária separou contextos para diferentes dispositivos. 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 passados ​​para o HAL para serem aplicados à saída desses dispositivos.

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

Configuração de áudio da zona de ocupação

No Android 11, car_audio_configuration.xml foi expandido para introduzir dois novos campos, audioZoneId e occupantZoneId . O primeiro, audioZoneId pode ser usado para controlar melhor o gerenciamento de zonas. Por outro lado, occupantZoneId pode ser usado para configurar o roteamento baseado em ID do usuário.

Para usar esses novos campos, é necessária a V2 do car_audio_configuration.xml . Revisitando a configuração de áudio acima, mas utilizando o novo campo para identificação de zona de ocupante e mapeamento de identificação de 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 primária para a zona de ocupação 0 e audioZoneId 1 para occupantZoneId 1. Em geral, qualquer mapeamento entre a zona de ocupação e a zona de áudio pode ser configurado, mas o mapeamento deve ser um para um. Aqui estão as regras que definiram os dois novos campos:

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

Roteamento por meio de um UID de aplicativo

Uma série de APIs ocultas foram introduzidas no CarAudioManager em 10 para permitir que os aplicativos 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 próprio gerenciasse o roteamento de áudio com base no UID de um aplicativo. Como tal, tanto o ID da zona de áudio como o UID da aplicação também são necessários. Com essas informações em mãos, o roteamento de áudio pode ser definido usando a API CarAudioManager#setZoneIdForUid .

Alterando zonas para um aplicativo

Por padrão, todo o áudio é roteado para a zona primária. Para atualizar um aplicativo para ser roteado para uma zona diferente, 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 Nota: Streams e foco não podem alternar zonas dinamicamente. Portanto, a reprodução deve ser interrompida e o foco solicitado novamente para alterar as zonas.

Roteamento com ID de usuário

Embora o roteamento baseado em UID de um aplicativo permita o controle preciso do roteamento de áudio de cada aplicativo, ele também exige que o roteamento de áudio para cada aplicativo seja definido antes que o aplicativo realmente solicite o foco do áudio e reproduza o áudio. Para mitigar esse problema e facilitar ainda mais que aplicativos de terceiros reproduzam áudio sem modificação, CarAudioService usa a zona do ocupante do carro e o mapeamento da zona de áudio para definir o roteamento baseado no ID do usuário. Desta forma, quando um usuário se conecta à zona de ocupação, o serviço de áudio automotivo é notificado. Com este 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 deve ser feito independentemente do roteamento de ID do 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á desabilitado e a tentativa de chamar CarAudioManager#setZoneidForUid gerará um erro.

Embora o roteamento de áudio e o gerenciamento de foco tenham sido simplificados com o gerenciamento de zonas de ocupantes, o usuário ainda deve ser atribuído a uma zona de ocupantes. Isso pode ser feito usando CarOccupantZoneManager#assignProfileUserToOccupantZone . Esta API requer permissão para gerenciar usuários. A expectativa atual é que os OEMs gerenciem a atribuição de zona de usuário a ocupante por meio de algum tipo de UI do sistema. Feito isso, o lançamento do aplicativo, o roteamento de áudio e o gerenciamento de foco serão todos configurados automaticamente para o usuário.

Roteamento com setPreferredDevice

Junto com as 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 para uma zona específica e um uso de atributo de áudio. Dessa maneira, aplicativos próprios podem rotear áudio para zonas diferentes utilizando a API setPreferredDevice do player. A API getOutputDeviceForUsage requer PERMISSION_CAR_CONTROL_AUDIO_SETTINGS e é uma API do sistema. Abaixo está um exemplo de localização do dispositivo de mídia para uma zona específica e roteamento para esse dispositivo usando a API setPreferredDevice .

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