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 dentro de cada zona.

Configurando o roteamento de áudio

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

Ativando o 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" .

Exemplo de configuração

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 na saída de cada 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 para 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 o único dispositivo e grupo de volumes para manter as coisas simples.

Configuração de áudio da zona ocupante

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 da zona. Por outro lado, occupantZoneId pode ser usado para configurar o roteamento baseado em ID do usuário.

Para usar esses novos campos, a V2 do car_audio_configuration.xml é necessária. Revisitando a configuração de áudio acima, mas utilizando o novo campo para identificação de zona de ocupação 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 para a zona primária é sempre zero
  • os números de 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. Assim, tanto o ID da zona de áudio quanto o UID do aplicativo 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 .

Alterar zonas para um aplicativo

Por padrão, todos os roteamentos de áudio 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: Fluxos e foco não podem alternar zonas dinamicamente. Portanto, a reprodução deve ser interrompida e o foco solicitado novamente para mudar de zona.

Roteamento com ID de 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 requer que o roteamento de áudio para cada aplicativo seja definido antes que o aplicativo realmente solicite foco de áudio e reproduza o áudio. Para atenuar esse problema e facilitar ainda mais que aplicativos de terceiros reproduzam áudio sem modificações, CarAudioService usa a zona de ocupação do carro e o mapeamento da zona de áudio para definir o roteamento baseado na identificação do usuário. Dessa forma, quando um usuário faz login na zona de ocupação, o serviço de áudio do carro é 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 a zona do ocupante para o mapeamento da zona de áudio do carro for definida, 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 zona de ocupação, o usuário ainda deve ser atribuído a uma zona de ocupação. Isso pode ser feito usando o 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 para ocupante por meio de algum tipo de interface do usuário do sistema. Feito isso, 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

Juntamente com as alterações acima, o Android 11 também possui uma nova API para consultar os dispositivos de saída associados a cada zona, CarAudioManager#getOutputDeviceForUsage(int zoneId, int using).

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, os aplicativos originais podem rotear o áudio para diferentes zonas, 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);