Serviço de plug-in de áudio do carro

Os novos serviços de plug-in OEM de carros no Android 14 permitem que alguns componentes do carro sejam configurados. Para áudio especificamente, três novos serviços de plug-in foram introduzidos, permitindo que os OEMs configurem flexivelmente o gerenciamento de áudio em dispositivos AAOS:

  • Controle de seleção de áudio
  • Controle de volume e mudo de áudio
  • Controle de redução de áudio

Arquitetura do serviço de plug-in do carro

A figura abaixo mostra uma visão geral dos serviços de carro e a relação deles com o serviço de carro OEM. Assim como os processos de app e de serviço de carro, o processo de serviço de carro OEM ocupa o próprio espaço de processo.

imagem

O serviço de carro inicia o serviço de carro OEM encontrando o componente definido em config_oemCarService. Se a configuração estiver vazia, o serviço OEM não existirá e nenhum serviço será iniciado. O componente precisa estender OemCarService. O serviço de áudio do carro precisa substituir as APIs para adquirir o serviço OEM de áudio do carro:

public final class OemCarServiceImp extends OemCarService {
    @Override
    public OemCarAudioFocusService getOemAudioFocusService();

    @Override
    public OemCarAudioDuckingService getOemAudioDuckingService();

    @Override
    public OemCarAudioVolumeService getOemAudioVolumeService();
}

Como exemplo, consulte o app de teste de referência definido em packages/services/Car/tests/OemCarServiceTestApp.

Mesmo que o serviço seja iniciado pelo serviço de carro, ele não herda automaticamente as permissões disponíveis para o serviço de áudio do carro. Portanto, qualquer permissão exigida pelos serviços OEM precisa ser adquirida com o mecanismo adequado. Por exemplo, consulte packages/services/Car/data/etc/com.android.car.oemcarservice.testapp.xml.

Serviço de áudio de carro com arquitetura de serviço OEM

No AAOS, o serviço de áudio do carro gerencia estas ações:

  • Roteamento de áudio
  • Seleção de áudio
  • Redução de áudio
  • Volume e desativar som

Antes do Android 14, esse comportamento era bastante estático e só podia ser modificado por configurações, embora em um conjunto muito limitado de casos. O Android 14 introduziu um mecanismo para que o serviço de áudio do carro se comunique com um componente definido pelo OEM que gerencia:

  • Seleção de áudio
  • Redução de áudio
  • Volume e desativar som

A figura abaixo mostra uma arquitetura simplificada para o serviço de áudio do carro e o serviço OEM do carro. O serviço de áudio do carro define diferentes hooks que podem chamar o serviço de áudio OEM do carro para gerenciar o comportamento de áudio. O último ocorre apenas se o componente de serviço de áudio do carro OEM correspondente estiver definido. Caso contrário, o serviço de áudio do carro vai usar o comportamento padrão.

imagem

Para garantir que o serviço de áudio do carro e o serviço de áudio do OEM do carro estejam sempre em sincronia, em cada chamada, o serviço de áudio do carro transmite as partes necessárias do estado atual da pilha de áudio para o serviço de áudio do OEM do carro. Por exemplo, quando o serviço de áudio do carro intercepta uma solicitação para avaliar o foco de áudio, ele transmite o estado atual da pilha para o serviço de áudio OEM do carro. O estado atual inclui o detentor de foco atual e os perdedores de foco atuais. Os perdedores de foco são solicitações de foco que ainda fazem parte da pilha, mas que perderam temporariamente o foco.

O serviço de áudio do carro precisa gerenciar todas as atividades de áudio no carro. Se o serviço de áudio do carro não gerenciar algumas partes do comportamento do áudio, as informações expostas ao serviço de áudio OEM do carro serão incompletas. Por exemplo, se um OEM substituir o processamento de foco de áudio no serviço de carro registrando a própria política de foco de áudio, o serviço de áudio do carro não poderá fornecer informações completas ao serviço de áudio OEM do carro. Isso pode afetar a capacidade do serviço de áudio OEM do carro de tomar decisões, já que pode faltar informações não visíveis para o serviço de áudio do carro.

Para realizar ações, o serviço de áudio do carro chama os serviços de carro OEM. Essas chamadas são feitas entre processos, o que exige comunicação interprocesso (IPC). O IPC adiciona latência a cada chamada. É importante minimizar a latência no serviço OEM.

Como as chamadas do serviço de áudio do carro para o serviço OEM estão bloqueadas, o serviço OEM não pode chamar o serviço de áudio do carro em avaliações diretas de API. Em vez disso, o serviço de áudio do carro fornece as informações necessárias para que as chamadas entre os dois processos precisem viajar apenas em uma direção.

Definições de serviços de áudio de carro OEM

Serviço de seleção de áudio do carro OEM

O serviço de áudio do carro gerencia solicitações de foco de áudio de apps registrando um listener de foco de política de áudio. O serviço de áudio do carro tem um mecanismo para gerenciar o comportamento de foco com base em uma matriz de interação estática. A matriz define três tipos diferentes de interações:

  • Interação simultânea. Os detentores de foco podem manter o foco ao mesmo tempo.

  • Interações exclusivas. A solicitação de foco recebida tira o foco do detentor de foco atual.

  • Recusar interação. A solicitação de foco recebida foi rejeitada com base no detentor de foco atual.

Embora isso seja suficiente para alguns casos de uso automotivo, ele não atende a todas as necessidades de interação que podem ser diferentes devido aos requisitos do OEM. Para isso, apresentamos o OemCarAudioFocusService:

public interface OEmCarAudioFocusService {
    OemCarAuddioFocusResults evaluateAudioFocusRequest(
        OemCarAudioFocusEvaluationRequest request);
    
    void notifyAudioFocusChange(
        List<AudioFocusEntry> holder,
        List<AudioFocusEntry> losers, int zoneId);
}

A API evaluateAudioFocusRequest é chamada pelo serviço de áudio do carro sempre que há uma solicitação de foco de áudio que precisa ser avaliada. Ela é uma API bidirecional que bloqueia os resultados para que eles sejam retornados. A solicitação contém informações sobre o estado atual da pilha de áudio:

Essas informações podem ser usadas para avaliar o newFocusRequest em comparação com os detentores de foco atuais em focusHolders e os perdedores de foco atuais em focusLosers. A API precisa retornar os resultados:

class OemCarAudioFocusResult {
    int audioZoneId;
    int audioFocusEvaluationResults;
    AudioFocusEntry focusResult;
    List<AudioFocusEntry> newLosers;
    List<AudioFocusEntry> newlyBlocked;
}

Ele contém as informações sobre os resultados reais da avaliação em audioFocusEvaluationResults, que indicam se a solicitação atual foi concedida, adiada ou falhou. Qualquer mudança na pilha de foco atual precisa ser definida nas entradas newLosers e newlyBlocked, dependendo da natureza da mudança da pilha.

Onde newLosers contém entradas que antes mantinham o foco, mas agora precisam perdê-lo, seja permanentemente ou temporariamente. Os perdedores de foco permanentes serão removidos da pilha de foco de áudio, e os perdedores de foco temporários serão movidos para a pilha de perdedores de foco atual até que recuperem o foco ou sejam abandonados pelo solicitante de foco original. De qualquer forma, o listener de foco para as solicitações vai receber uma perda de foco correspondente.

A lista newlyBlocked contém entradas que estavam na lista de perdedores de foco, mas agora estão bloqueadas pela nova entrada. O bloqueio pode ser permanente ou transitório. No caso de bloqueio permanente, a entrada será removida da pilha e a perda de foco será enviada aos listeners de foco. Para perda de foco temporária, a entrada vai permanecer na pilha de perdas de foco, mas um novo bloqueador de foco será adicionado à lista de bloqueadores. Nenhuma perda de foco será enviada, já que uma foi enviada quando o bloqueio foi feito pela primeira vez. A solicitação será desbloqueada quando todos os bloqueadores atuais forem removidos ou será removida da pilha se o foco for abandonado.

A segunda API, notifyAudioFocusChange, é uma via que é chamada em cada solicitação ou abandono de foco de áudio. A API é usada principalmente para informar ao serviço OEM sobre mudanças de foco, o que pode afetar o comportamento do serviço de áudio do carro OEM.

Diretrizes para a avaliação de foco

No AAOS, o foco de áudio é usado para gerenciar a reprodução de áudio e determinar qual app precisa aderir para oferecer uma experiência ideal ao usuário. Portanto, o serviço de plug-in OEM precisa levar em consideração o seguinte ao gerenciar uma solicitação de foco de áudio:

  • Sem nenhum foco de áudio de alta prioridade (como uma ligação, emergência ou segurança), os apps precisam conseguir o foco de áudio temporariamente ou permanentemente.

  • Enquanto o foco de mídia estiver ativo, os apps que solicitarem:

    • O foco de uso de chamada precisa ser capaz de receber foco simultaneamente ou exclusivamente.

    • O foco de uso da navegação precisa ser capaz de receber foco simultaneamente ou exclusivamente.

    • O foco de uso do Google Assistente precisa ser capaz de receber foco simultaneamente ou exclusivamente.

  • Enquanto os apps de foco de áudio de alta prioridade (como uma ligação, um alerta de emergência ou de segurança) estiverem ativos, qualquer solicitação de foco de áudio atrasada recebida precisa ser concedida ou adiada conforme necessário.

As sugestões acima não são exaustivas, mas podem ajudar a garantir que os apps que solicitam o foco possam receber o foco quando não há sons de alta prioridade ativos. Mesmo quando os sons de alta prioridade estão ativos, as solicitações de foco atrasadas ainda precisam ser respeitadas e precisam ser capazes de receber o foco quando o som de alta prioridade parar.

Serviço de volume do carro OEM

O serviço de áudio do carro gerencia eventos de tecla de volume detectando ajustes de volume do sistema de áudio ou eventos de tecla de volume diretamente do serviço de entrada do carro. Em cada caso, o comportamento padrão do serviço de áudio do carro é determinar qual grupo de volume mudar com base nos reprodutores de áudio ativos e em uma lista de prioridade de contexto de áudio.

Oferecemos duas listas de prioridade de volume. A primeira lista considera todos os contextos de áudio nesta ordem. A lista é apresentada em ordem decrescente, com a prioridade mais alta no topo e a mais baixa na parte de baixo. Por exemplo, se o áudio de navegação e o áudio da música estiverem ativos ao mesmo tempo, o volume de navegação será alterado durante um evento de tecla de volume.

  1. Navegação
  2. Ligar
  3. Música
  4. Aviso
  5. Comando de voz
  6. Toque da chamada
  7. Som do sistema
  8. Segurança
  9. Alarme
  10. Notificação
  11. Status do veículo
  12. Emergência

Para tornar o gerenciamento de eventos de tecla de volume menos complexo, o serviço de áudio do carro tem uma segunda lista de prioridade de contexto de áudio:

  1. Ligar
  2. Mídia
  3. Aviso
  4. Comando de voz

Essa lista também é apresentada em ordem decrescente. O objetivo dessa segunda lista é permitir que sons mais comuns sejam alterados por eventos principais. Sons incomuns, talvez de duração mais curta, podem ser gerenciados apenas pela interface de configurações de áudio.

A versão real do volume pode ser definida com a configuração audioVolumeAdjustmentContextsVersion. A configuração pode ser definida como 1 ou 2 (2 é o padrão).

Para oferecer mais flexibilidade ao gerenciamento de volume, OemCarAudioVolumeService foi introduzido no Android 14:

public interface OemCarAudioVolumeService {
    OemCarvolumeChangeInfo getSuggestedGroupForVolumeChange(
OemCarAudioVolumeRequest request, int volumeAdjustment);
}

O serviço de volume de áudio do carro OEM tem um único método, que recebe um volumeAdjustment e um OemCarAudioVolumeRequest:

class OemCarAudioVolumeRequest {
    int audioZoneId;
    int callState;
    List<AudioAttributes> activePlaybackAttributes;
    List<AudioAttributes> duckedAttributes;
    List<CarVolumeGroupInfo> volumeGroupState;
}

O activePlaybackAttributes da solicitação tem os atributos de áudio ativos. Os duckedAttributes são todos os atributos de áudio atualmente ocultos. O volumeGroupState tem o estado atual do grupo de volumes. A solicitação representa o estado atual da pilha de áudio e pode ser usada para determinar qual grupo de volume precisa ser alterado. Os resultados precisam ser retornados em OemCarVolumeChangeInfo:

class OemCarVolumeChangeInfo {
    boolean change;
    CarVolumeGroupInfo volumeGroupChanged;
}

O booleano change indica se algum volume foi alterado. true indica que há uma mudança e que o grupo de volume precisa ser atualizado. O volumeGroupChanged é o grupo de volume real que precisa ser alterado. Esse grupo precisa ser alterado de acordo com o parâmetro volumeAdjustment original transmitido para a API. Por exemplo, se os resultados indicarem que o grupo de volume de navegação precisa ser silenciado, o booleano será true e o grupo de volume retornado será o da navegação.

Serviço de redução de volume de carro OEM

O serviço de áudio do carro gerencia o abatimento de áudio monitorando as mudanças de foco de áudio e enviando um sinal para a HAL AudioControl sobre quais dispositivos de áudio devem ser abafados. Quando o foco muda, todos os detentores de foco ativos são avaliados para determinar qual deles precisa ser reduzido com base neste conjunto de regras de redução estática:

  • Os sons de emergência silenciam tudo, exceto os sons de chamada
  • A segurança silencia tudo, exceto os sons de emergência
  • A navegação silencia tudo, exceto sons de segurança e emergência
  • O Call ducks silencia tudo, exceto sons de segurança, emergência e navegação
  • O Voice ignora os sons de toque de ligação
  • A música e os avisos precisam ser abafados por tudo

Essas regras não são exaustivas, e os OEMs continuam sendo responsáveis por determinar como os sons devem ser abafados com base nessas diretrizes. Os OEMs podem controlar essas recomendações de forma mais ativa com base nos requisitos disponíveis. O OemCarDuckingService foi introduzido no Android 14:

class OemCarAudioDuckingService {
List<AudioAttributes>   evaluateAttributesToDuck(
        OemCarAudioVolumeRequest request);
}

Essa API é chamada pelo serviço de áudio do carro quando o foco de áudio muda. Ele reutiliza o OemCarAudioVolumeRequest introduzido no serviço de volume de carro OEM e contém as informações relevantes para tomar a decisão sobre quais atributos evitar. A lista de atributos de áudio para pular da API é comparada ao estado de áudio atual:

  • Atributo de áudio atualmente silenciado:

    • Na lista, continua sendo ignorado
    • Não está na lista, o recurso de abatimento está desativado
  • Atributo de áudio não silenciado no momento:

    • Na lista, abaixado
    • Não está na lista, o recurso de abatimento está desativado

O serviço de áudio do carro determina a quais dispositivos de saída de áudio os atributos de áudio pertencem e os adiciona à lista de dispositivos de saída de áudio com ruído ou à lista de dispositivos de áudio sem ruído, respectivamente. Isso é enviado ao HAL AudioControl para realizar o ducking necessário no nível do hardware.

A figura abaixo mostra um diagrama de sequência simplificado do controle de abatimento de áudio para uma solicitação de foco quando o serviço de abatimento do OEM é usado:

imagem

A sequência começa quando um app solicita Gerenciar seleção de áudio por APIs públicas de gerenciamento de áudio. A solicitação é encaminhada ao serviço de áudio do carro para determinar os resultados. Quando o foco do áudio é decidido, o abatimento de áudio é avaliado pelo serviço de áudio do carro que chama OemCarAudioDuckingService para avaliar quais atributos de áudio precisam ser abafados. Depois que os resultados são retornados da API evaluateAttributesToDuck, os dispositivos de áudio para redução de volume são calculados e, finalmente, as informações são enviadas para o AudioControl para aplicar a redução de volume ao hardware de áudio.

Implementação de referência do serviço de áudio de carro OEM

O AAOS fornece uma implementação de referência do serviço de carro OEM em packages/services/Car/tests/OemCarServiceTestApp, que implementa o OemCarService, junto com OemCarAudioFocusService, OemCarAudioDuckingService e OemCarAudioVolumeService. Para o último, cada serviço usa um arquivo XML para carregar um comportamento estático. Por exemplo, OemCarAudioFocusServiceImp carrega o oem_focus_config.xml, que contém uma matriz de interação. A matriz é usada para avaliar a solicitação de foco quando a evaluateAudioFocusRequest é chamada.

Depuração de referência do app de teste

O app de teste de serviço de carro OEM faz parte do código-fonte do AOSP. Os OEMs podem fazer mudanças de acordo com as necessidades. Para depurar, use a configuração config_oemCarService para ativar o app de teste.

<!-- This is the component name for the OEM customization service. OEM can choose to implement
this service to customize car service behavior for different policies. If OEMs choose to
implement it, they have to implement a service extending OemCarService exposed by car-lib,
and implement the required component services.
If the component name is invalid, CarService would not connect to any OEM service.
Component name can not be a third party package. It should be pre-installed -->
<string name="config_oemCarService" translatable="false">
com.android.car.oemcarservice.testapp/.OemCarServiceImpl
</string>

Para verificar se o serviço de carro OEM usa o comando dump do serviço de carro para o serviço OEM:

adb shell dumpsys car_service --oem-service

Os resultados podem ser semelhantes à saída abaixo:

***CarOemProxyService dump***
  mIsFeatureEnabled: true
  mIsOemServiceBound: true
  mIsOemServiceReady: true
  mIsOemServiceConnected: true
  mInitComplete: true
  OEM_CAR_SERVICE_CONNECTED_TIMEOUT_MS: 5000
  OEM_CAR_SERVICE_READY_TIMEOUT_MS: 5000
  mComponentName: com.android.car.oemcarservice.testapp/.OemCarServiceImpl

Cada booleano em cada lote de informações dump determina o estado do recurso e do serviço. Por exemplo, as informações de despejo mIsOemServiceReady especificam se o serviço está pronto para uso, em que true indica que ele está pronto e false indica que ele não está pronto.