Esta página explica como implementar o rádio nos níveis de hardware e software.
- Os componentes do sistema ilustram e descrevem a pilha de tecnologia de rádio.
- A camada de abstração de hardware de rádio de transmissão fornece estruturas de dados e interfaces para que os OEMs implementem rádio de transmissão como AM/FM e rádio de transmissão de áudio digital (DAB) no nível do hardware.
- A implementação do controle de rádio é baseada em
MediaSession
eMediaBrowse
, que permitem que aplicativos de mídia e assistente de voz controlem o rádio. Além do conteúdo fornecido abaixo, consulte Criar aplicativos de mídia para carros .
Componentes do sistema
A pilha de rádio de transmissão inclui os seguintes componentes.
Aplicativo de referência de rádio
Para obter detalhes sobre como implementar o controle de rádio, consulte Implementação de controle de rádio .
Um aplicativo de rádio Java de amostra ( packages/apps/Car/Radio
) serve como uma implementação de referência. Quando o serviço de aplicativo é iniciado, ele solicita que o Radio Manager abra um sintonizador de rádio. Em seguida, o aplicativo pode enviar solicitações ao sintonizador de rádio, como sintonizar uma estação de rádio específica, frequência ou buscar a próxima estação de rádio disponível. O aplicativo recebe atualizações do Radio Manager e Radio Tuner in Radio, como informações do programa atual, listas de programas de rádio, configurações e parâmetros definidos pelo fornecedor. O aplicativo de rádio de referência suporta apenas rádio AM e FM. Os OEMs podem modificar ou substituir o aplicativo de rádio conforme desejado.
Gerenciador de rádio
Quando o aplicativo solicita que o Radio Manager abra um sintonizador, o Radio Manager ( frameworks/base/core/java/android/hardware/radio/RadioManager.java
) solicita que o Broadcast Radio Service abra uma sessão do Tuner e, em seguida, encerra a sessão em um Radio Tuner ( frameworks/base/core/java/android/hardware/radio/RadioTuner.java
), que é retornado ao aplicativo. O Radio Tuner define APIs (como tune, step e cancel) que podem ser chamadas de aplicativos de rádio e enviar solicitações para Broadcast Radio Service. Os métodos de retorno de chamada ( RadioTuner.Callback
) definidos no Radio Tuner enviam atualizações sobre o HAL de rádio transmitido, como informações do programa atual, listas de programas e parâmetros definidos pelo fornecedor, do Broadcast Radio Service para aplicativos.
Serviço de rádio de transmissão
O Broadcast Radio Service ( frameworks/base/services/core/java/com/android/server/broadcastradio
) é o serviço do cliente para Broadcast Radio HAL. O Broadcast Radio Service coordena vários Radio Managers com Broadcast Radio HALs. O serviço de transmissão de rádio oferece suporte a HAL de linguagem de definição de interface HAL (HIDL) e HALs de rádio de transmissão de linguagem de definição de interface Android (AIDL) . O Serviço de Radiodifusão conecta-se ao AIDL HAL quando existe qualquer serviço AIDL HAL; caso contrário, o serviço será vinculado ao HIDL HAL. O serviço de transmissão de rádio cria um módulo de rádio para cada instância HAL disponível (como AM, FM e DAB).
Cada Gerente de Rádio pode solicitar ao Serviço de Rádio de Transmissão a criação de uma sessão de sintonizador no Módulo de Rádio correspondente, com base no tipo de rádio. Cada sessão do sintonizador pode chamar métodos, como tune, step e cancel (definidos nas interfaces HAL) para executar operações na instância HAL de rádio de transmissão correspondente. Quando uma sessão de sintonizador recebe um retorno de chamada da instância HAL em uma atualização de HAL, como informações do programa atual, lista de programas, sinalizadores de configuração e parâmetros do fornecedor, os retornos de chamada sobre a atualização são enviados para todos os sintonizadores de rádio vinculados ao mesmo módulo de rádio.
Transmissão de rádio HAL
Para saber mais sobre as interfaces HIDL e AIDL de transmissão de rádio e as diferenças entre as duas, consulte Interface HAL de transmissão de rádio .
Camada de abstração de hardware de rádio de transmissão
As seções a seguir descrevem como trabalhar com a camada de hardware para implementar a transmissão de rádio.
Interface HAL de rádio de transmissão
O Broadcast radio HAL fornece estruturas de dados e interfaces no nível do hardware para implementar rádio broadcast, como rádio AM/FM e DAB.
Interfaces HIDL 2.0 e AIDL
A transmissão de rádio HAL usa as interfaces descritas nas seções a seguir.
- Ouvinte de anúncio
- Fechar alça
- Interface de retorno de chamada
- Interface HAL de rádio de transmissão primária
Ouvinte de anúncio
IAnnouncementListener
é a interface de retorno de chamada para o ouvinte de anúncio, que pode ser registrado na transmissão de rádio HAL para receber anúncios. A interface possui os seguintes métodos:
IAnnouncementListener | ||
---|---|---|
Descrição: Chamado sempre que a lista de anúncios é alterada. | ||
HIDL 2.0 | oneway onListUpdated(vec<Announcement> announcements) | |
AIDL | oneway void onListUpdated(in Announcement[] announcements) |
Fechar alça
ICloseHandle
é o identificador de fechamento genérico para remover um retorno de chamada que não precisa de uma interface ativa.
ICloseHandle | ||
---|---|---|
Descrição: Feche a alça. | ||
HIDL 2.0 | close() | |
AIDL | void close() |
Interface de retorno de chamada
ITunerCallback
é a interface de retorno de chamada chamada pelo rádio de transmissão HAL para enviar atualizações ao serviço de cliente HAL.
ITunerCallback | ||
---|---|---|
Descrição: Chamado pelo HAL quando uma operação de ajuste (ajuste, busca (em AIDL) ou varredura (em HIDL) e etapa é bem-sucedida) falha de forma assíncrona. | ||
HIDL 2.0 | oneway onCurrentProgramInfoChanged(ProgramInfo info) | |
AIDL | void onCurrentProgramInfoChanged(in ProgramInfo info) | |
Descrição: Chamado quando o ajuste, a busca (em AIDL) ou a varredura (em HIDL) ou a etapa são bem-sucedidas. | ||
HIDL 2.0 | oneway onTuneFailed(Result result, ProgramSelector selector) | |
AIDL | void onTuneFailed(in Result result, in ProgramSelector selector) | |
Descrição: Chamado quando o ajuste, a busca (em AIDL) ou a varredura (em HIDL) ou a etapa são bem-sucedidas. | ||
HIDL 2.0 | oneway onCurrentProgramInfoChanged(ProgramInfo info) | |
AIDL | void onCurrentProgramInfoChanged(in ProgramInfo info) | |
Descrição: Chamado quando a lista de programas é atualizada; o tamanho de cada pedaço deve ser limitado a 500kiB. | ||
HIDL 2.0 | oneway onProgramListUpdated(ProgramListChunk chunk) | |
AIDL | oneway onProgramListUpdated(ProgramListChunk chunk) | |
Descrição: Chamado quando a antena está conectada ou desconectada. | ||
HIDL 2.0 | oneway onAntennaStateChange(bool connected) | |
AIDL | void onCurrentProgramInfoChanged(in ProgramInfo info) | |
Descrição: Chamado quando os valores de parâmetros específicos do fornecedor são atualizados internamente no HAL (não deve ser invocado após chamar setParameters pelo cliente HAL). | ||
HIDL 2.0 | oneway onParametersUpdated(vec<VendorKeyValue> parameters) | |
AIDL | void onParametersUpdated(in VendorKeyValue[] parameters) | |
Descrição: Novo em AIDL. Chamado quando o sinalizador de configuração é atualizado internamente no HAL (não deve ser invocado após chamar setConfigFlag pelo cliente HAL). | ||
HIDL 2.0 | Não aplicável. | |
AIDL | void onConfigFlagUpdated(in ConfigFlag flag, in boolean value) |
Interface HAL de rádio de transmissão primária
IBroadcastRadio
é a interface principal para a transmissão de rádio HAL. No HIDL 2.0 HAL, use a interface ITunerSession
para o sintonizador para chamar as operações. No entanto, no máximo um sintonizador está ativo por vez (desde que cada instância HAL de rádio de transmissão tenha apenas um chip sintonizador). ITunerSession
foi removido das interfaces AIDL e suas interfaces movidas para IBroadcastRadio
.
IBroadcastRadio | ||
---|---|---|
Descrição: Obtenha a descrição de um módulo e seus recursos. | ||
HIDL 2.0 | getProperties() generates (Properties properties) | |
AIDL | Properties getProperties() | |
Descrição: Busca a configuração atual ou possível da região AM/FM. | ||
HIDL 2.0 | getAmFmRegionConfig(bool full) generates (Result result, AmFmRegionConfig config) | |
AIDL | AmFmRegionConfig getAmFmRegionConfig(bool full) | |
Descrição: Busca a configuração atual da região DAB. | ||
HIDL 2.0 | getDabRegionConfig() generates (Result result, vec<DabTableEntry> config) | |
AIDL | DabTableEntry[] getDabRegionConfig() | |
Descrição: Obtém uma imagem do cache do módulo de rádio. Em AIDL, o tamanho da imagem deve ser inferior a 1 MB devido a um limite rígido no buffer de transação do fichário. | ||
HIDL 2.0 | getImage(uint32_t id) generates (vec<uint8_t> image) | |
AIDL | byte[] getImage(in int id) | |
Descrição: Registra o listener de anúncio. | ||
HIDL 2.0 | registerAnnouncementListener(vec<AnnouncementType> enabled,IAnnouncementListener listener) generates (Result result, ICloseHandle closeHandle) | |
AIDL | ICloseHandle registerAnnouncementListener(in IAnnouncementListener listener, in AnnouncementType[] enabled) | |
Descrição:
| ||
HIDL 2.0 | openSession(ITunerCallback callback) gera (Result result, ITunerSession session) | |
AIDL | void setTunerCallback(in ITunerCallback callback) | |
Descrição:
| ||
HIDL 2.0 | close() | |
AIDL | unsetTunerCallback() | |
Descrição: Sintoniza um programa específico. | ||
HIDL 2.0 | tune(ProgramSelector program) generates (Result result) | |
AIDL | void tune(in ProgramSelector program) | |
Descrição: Busca o próximo programa válido no ar . Para evitar confusão em AIDL, scan foi renomeado para seek . | ||
HIDL 2.0 | scan(bool directionUp, bool skipSubChannel) generates (Result result) | |
AIDL | void seek(in boolean directionUp, in boolean skipSubChannel) | |
Descrição: Passa para o canal adjacente, que não pode ser ocupado por nenhum programa. | ||
HIDL 2.0 | step(bool directionUp) generates (Result result) | |
AIDL | void step(in boolean directionUp) | |
Descrição: Cancela operações pendentes de sintonia, varredura (em HIDL) ou busca (em AIDL) ou etapas. | ||
HIDL 2.0 | cancel() | |
AIDL | void cancel() | |
Descrição: Aplica um filtro à lista de programas e começa a enviar atualizações da lista de programas pelo retorno de chamada onProgramListUpdated . | ||
HIDL 2.0 | startProgramListUpdates(ProgramFilter filter) generates (Result result) | |
AIDL | void startProgramListUpdates(in ProgramFilter filter) | |
Descrição: Interrompe o envio de atualizações da lista de programas. | ||
HIDL 2.0 | stopProgramListUpdates() | |
AIDL | void stopProgramListUpdates() | |
Descrição: Busca a configuração atual de um determinado sinalizador de configuração. | ||
HIDL 2.0 | isConfigFlagSet(ConfigFlag flag) generates (Result result, bool value) | |
AIDL | boolean isConfigFlagSet(in ConfigFlag flag) | |
Descrição: define o sinalizador de configuração fornecido. | ||
HIDL 2.0 | setConfigFlag(ConfigFlag flag, bool value) generates (Result result) | |
AIDL | void setConfigFlag(in ConfigFlag flag, boolean value) | |
Descrição: define valores de parâmetros específicos do fornecedor. | ||
HIDL 2.0 | setParameters(vec<VendorKeyValue> parameters) gera , (vec<VendorKeyValue> results) | |
AIDL | VendorKeyValue[] setParameters(in VendorKeyValue[] parameters) | |
Descrição: recupera valores de parâmetros específicos do fornecedor. | ||
HIDL 2.0 | getParameters(vec<string> keys) generates (vec<VendorKeyValue> parameters) | |
AIDL | VendorKeyValue[] getParameters(in String[] keys) |
Esclarecimentos de interface
Comportamento assíncrono
Como cada operação de ajuste (por exemplo, ajuste, varredura (em HIDL) ou busca (em AIDL) e etapa) pode ser demorada e o encadeamento não deve ser bloqueado por muito tempo, a operação deve agendar operações demoradas para ocorrer mais tarde e retornar rapidamente um status ou resultado. Em detalhes, cada operação deve:
- Cancele todas as operações de ajuste pendentes.
- Verifique se a operação pode ser processada com base nas entradas do método e no status do sintonizador.
- Agende a tarefa de ajuste e retorne o
Result
(em HIDL) oustatus
(em AIDL) imediatamente. SeResult
oustatus
forOK
, o retorno de chamada do sintonizadortuneFailed
oucurrentProgramInfoChanged
deverá ser chamado quando a tarefa de ajuste falhar (por exemplo, devido a um tempo limite) ou for concluída.
Da mesma forma, startProgramListUpdates
também agenda a tarefa demorada de atualizar a lista de programas para ocorrer mais tarde e retornar rapidamente um status ou resultado. O método primeiro cancela as solicitações de atualização pendentes e, em seguida, agenda a tarefa de atualização e retorna rapidamente o resultado.
condição de corrida
Devido ao comportamento assíncrono das operações de ajuste (por exemplo, ajuste, varredura (em HIDL) ou busca (em AIDL) e etapa), existe uma condição de corrida entre o cancelamento da operação e as operações de ajuste. Se cancel
for chamado depois que o HAL concluir uma operação de ajuste e antes que o retorno de chamada seja concluído, o cancelamento poderá ser ignorado e o retorno de chamada deverá ser concluído e recebido pelo cliente HAL.
Da mesma forma, se stopProgramListUpdates
for chamado depois que o HAL concluir uma atualização da lista de programas e antes que o retorno de chamada onCurrentProgramInfoChanged
seja concluído, stopProgramListUpdates
poderá ser ignorado e o retorno de chamada deverá ser concluído.
Limite de tamanho de dados
Como há um limite rígido no buffer de transação do fichário, o limite de dados para alguns métodos de interface que transmitem dados de tamanho potencialmente grande é esclarecido no AIDL HAL.
-
getImage
requer que a imagem retornada tenha menos de 1 MB. -
onProgramListUpdate
requer que cadachunk
seja menor que 500kiB. Listas de programas maiores devem ser divididas pela implementação HAL em vários blocos e enviadas por meio de vários retornos de chamada.
Alterações nas estruturas de dados AIDL HAL
Além das mudanças nas interfaces, essas mudanças foram aplicadas às estruturas de dados definidas na transmissão de rádio AIDL HAL, que aproveita o AIDL.
-
Constant
enum é removido em AIDL e definido como const int emIBroadcastRadio
. Enquanto isso,ANTENNA_DISCONNECTED_TIMEOUT_MS
foi renomeado paraANTENNA_STATE_CHANGE_TIMEOUT_MS
. Um novo int constTUNER_TIMEOUT_MS
é adicionado. Todas as operações de ajuste, busca e etapa devem ser concluídas dentro desse período. - Enum
RDS
eDeemphasis
são removidos em AIDL e definidos como const int emAmFmRegionConfig
. Correspondentemente,fmDeemphasis
efmRds
emProgramInfo
são declarados como int, um resultado de computação de bit dos respectivos sinalizadores. Enquanto isso,D50
eD75
são renomeados paraDEEMPHASIS_D50
eDEEMPHASIS_D75
, respectivamente. - Enum
ProgramInfoFlags
são removidos em AIDL e definidos como const int emProgramInfo
com um prefixoFLAG_
adicionado. Da mesma forma,infoFlags
emProgramInfo
é declarado como int, um resultado de computação de bit de sinalizadores.TUNED
também foi renomeado paraFLAG_TUNABLE
, para melhor descrever sua definição de que a estação pode ser sintonizada. - Em
AmFmBandRange
,scanSpacing
é renomeado paraseekSpacing
, já quescan
é renomeado paraseek
em AIDL. - Uma vez que o conceito de união é introduzido em AIDL,
MetadataKey
eMetadata
definidos em HIDL HAL não são mais usados. UmMetadata
de união AIDL é definido em AIDL HAL. Cada valor de enum anteriormente emMetadataKey
agora é um campo emMetadata
com tipo de string ou int, dependendo de suas definições.
Implementação de controle de rádio
A implementação do controle de rádio é baseada em MediaSession
e MediaBrowse
, que permitem que aplicativos de mídia e assistente de voz controlem o rádio. Para obter mais informações, consulte Criar aplicativos de mídia para carros em developer.android.com.
Uma implementação de árvore de navegação de mídia é fornecida na biblioteca car-broadcastradio-support em packages/apps/Car/libs
. Esta biblioteca também contém extensões de ProgramSelector para converter de e para URI. Recomenda-se que as implementações de rádio usem esta biblioteca para construir a árvore de navegação associada.
Alternador de fonte de mídia
Para fornecer uma transição perfeita entre o rádio e outros aplicativos exibidos na mídia, a biblioteca car-media-common contém classes que devem ser integradas ao aplicativo de rádio. MediaAppSelectorWidget
pode ser incluído no XML para o aplicativo de rádio (o ícone e o menu suspenso usados nos aplicativos de mídia e rádio de referência):
<com.android.car.media.common.MediaAppSelectorWidget android:id="@+id/app_switch_container" android:layout_width="@dimen/app_switch_widget_width" android:layout_height="wrap_content" android:background="@drawable/app_item_background" android:gravity="center" />
Este widget inicia o AppSelectionFragment
, que exibe uma lista de fontes de mídia que podem ser alternadas. Se uma interface do usuário diferente da fornecida for desejada, você poderá criar um widget personalizado para iniciar o AppSelectionFragment
quando o switcher for exibido.
AppSelectionFragment newFragment = AppSelectionFragment.create(widget, packageName, fullScreen); newFragment.show(mActivity.getSupportFragmentManager(), null);
Uma implementação de exemplo é fornecida na implementação do aplicativo de rádio de referência, localizada em packages/apps/Car/Radio
.
Especificações de controle detalhadas
A interface MediaSession
(através de MediaSession.Callback
) fornece mecanismos de controle para o programa de rádio atualmente em execução:
-
onPlay
,onStop
. (Des)mudo reprodução de rádio. -
onPause
. Pausa com deslocamento de tempo (se suportado). -
onPlayFromMediaId
. Reproduza qualquer conteúdo de uma pasta de nível superior. Por exemplo, "Reproduzir FM" ou "Reproduzir rádio". -
onPlayFromUri
. Toque uma frequência específica. Por exemplo, "Reproduzir 88,5 FM". -
onSkipToNext
,onSkipToPrevious
. Sintonize uma estação seguinte ou anterior. -
onSetRating
. Adicione ou remova de ou para Favoritos.
O MediaBrowser expõe um MediaItem ajustável em três tipos de diretórios de nível superior:
- ( Opcional ) Programas (estações). Este modo é normalmente usado por rádios de sintonizador duplo para indicar todas as estações de rádio sintonizáveis disponíveis no local do usuário.
- Favoritos. Programas de rádio adicionados à lista de Favoritos, alguns podem estar indisponíveis (fora do alcance da recepção).
- Canais de banda. Todos os canais fisicamente possíveis na região atual (87.9, 88.1, 88.3, 88.5, 88.7, 88.9, 89.1 e assim por diante). Cada banda tem um diretório de nível superior separado.
Cada elemento em cada uma dessas pastas (AM/FM/Programas) é um MediaItem com um URI que pode ser usado com MediaSession para ajustar. Cada pasta de nível superior (AM/FM/Programas) é um MediaItem com um mediaId que pode ser usado com MediaSession para acionar a reprodução e fica a critério do OEM. Por exemplo, "Reproduzir FM", "Reproduzir AM" e "Reproduzir rádio" são todas consultas de rádio não específicas que usam um mediaId para enviar ao aplicativo de rádio OEM. Cabe ao aplicativo de rádio determinar o que reproduzir a partir da solicitação genérica e do mediaId.
MediaSession
Como não há conceito de pausar um fluxo de transmissão, as ações Reproduzir, Pausar e Parar nem sempre se aplicam ao rádio. Com o rádio, a ação Parar está associada a silenciar o stream enquanto Reproduzir está associada à remoção do mudo.
Alguns sintonizadores de rádio (ou aplicativos) fornecem a capacidade de simular uma pausa no fluxo de transmissão armazenando o conteúdo em cache e reproduzindo-o posteriormente. Nesses casos, use onPause
.
A reprodução das ações mediaId e URI destina-se a sintonizar uma estação buscada na interface MediaBrowser. O mediaId é uma string arbitrária fornecida pelo aplicativo de rádio para impor um valor único (portanto, um determinado ID aponta para apenas um item) e estável (portanto, um determinado item tem o mesmo ID durante toda a sessão) com o qual identificar uma determinada estação . A URI será de um esquema bem definido. Resumindo, uma forma URIizada de ProgramSelector. Embora isso preserve o atributo de unicidade, não precisa ser estável, embora possa mudar quando a estação mudar para uma frequência diferente.
Por design, onPlayFromSearch
não é usado. É responsabilidade do cliente (aplicativo complementar) selecionar um resultado de pesquisa na árvore do MediaBrowser. Transferir essa responsabilidade para o aplicativo de rádio aumentaria a complexidade, exigiria contratos formais sobre como as consultas de string deveriam aparecer e resultaria em uma experiência de usuário desigual em diferentes plataformas de hardware.
Nota: O aplicativo de rádio não contém informações adicionais que seriam úteis para pesquisar um nome de estação não exposto ao cliente por meio da interface do MediaBrowser.
Saltar para a estação seguinte ou anterior depende do contexto atual:
- Quando um aplicativo é sintonizado em uma estação da lista de Favoritos, o aplicativo pode passar para a próxima estação da lista de Favoritos.
- Ouvir uma estação da lista de programas pode resultar na sintonização da próxima estação disponível, classificada de acordo com o número do canal.
- Ouvir um canal arbitrário pode resultar na sintonização do próximo canal físico, mesmo quando não há sinal de transmissão.
O aplicativo de rádio lida com essas ações.
Manipulação de erros
As ações TransportControls
(Reproduzir, Parar e Avançar) não fornecem feedback sobre se a ação foi bem-sucedida ou não. A única maneira de indicar um erro é definir o estado MediaSession como STATE_ERROR
com uma mensagem de erro.
O aplicativo de rádio deve lidar com essas ações e executá-las ou definir um estado de erro. Caso a execução do comando Play não seja imediata, o estado do playback deve ser alterado para STATE_CONNECTING
(no caso de sintonia direta) ou STATE_SKIPPING_TO_PREVIOUS
ou NEXT
enquanto o comando estiver sendo executado.
O cliente deve observar o PlaybackState
e verificar se a sessão alterou o programa atual para o que foi solicitado ou entrou no estado de erro. STATE_CONNECTING
não deve exceder 30s. No entanto, uma sintonia direta para uma determinada frequência AM/FM deve funcionar muito mais rápido.
Adicionando e removendo favoritos
MediaSession tem suporte de classificação, que pode ser usado para controlar Favoritos. onSetRating
chamado com uma classificação do tipo RATING_HEART
adiciona ou remove a estação atualmente sintonizada de ou para a lista de Favoritos.
Ao contrário das predefinições herdadas, este modelo assume uma lista de Favoritos não ordenada e ilimitada, quando cada favorito salvo foi alocado para um slot numérico (normalmente, 1 a 6). Como resultado, os sistemas baseados em predefinições seriam incompatíveis com a operação onSetRating
.
A limitação da API MediaSession é que apenas a estação atualmente sintonizada pode ser adicionada ou removida. Por exemplo, os itens devem ser selecionados antes de serem removidos. Esta é apenas uma limitação do cliente MediaBrowser, como um aplicativo complementar. O aplicativo de rádio não é restrito da mesma forma. Esta parte é opcional quando um aplicativo não suporta Favoritos.
MediaBrowser
Para expressar quais frequências ou nomes de canais físicos (quando sintonizar um canal arbitrário é adequado para uma determinada tecnologia de rádio) são válidos para uma determinada região, todos os canais válidos (frequências) são listados para cada banda. Na região dos EUA, isso equivale a 101 canais FM na faixa de 87,8 a 108,0 MHz (usando espaçamento de 0,2 MHz) e 117 canais AM na faixa de 530 a 1700 kHz (usando espaçamento de 10 kHz). Como o rádio HD usa o mesmo espaço de canal, ele não é apresentado separadamente.
A lista de programas de rádio atualmente disponíveis é plana, pois não permite esquemas de exibição, como agrupamento por conjunto de transmissão direta de áudio (DAB).
As entradas na lista de Favoritos podem não ser ajustáveis. Por exemplo, se um determinado programa estiver fora do intervalo. O aplicativo de rádio pode ou não detectar se a entrada pode ser sintonizada antecipadamente. Nesse caso, pode não marcar a entrada como reproduzível.
Para identificar as pastas de nível superior, é aplicado o mesmo mecanismo usado pelo Bluetooth. Ou seja, um pacote Extras do objeto MediaDescription
contém um campo específico do sintonizador, assim como o Bluetooth faz com EXTRA_BT_FOLDER_TYPE
. No caso de transmissão de rádio, isso leva à definição dos seguintes novos campos na API pública:
-
EXTRA_BCRADIO_FOLDER_TYPE = "android.media.extra.EXTRA_BCRADIO_FOLDER_TYPE"
. Um dos seguintes valores:-
BCRADIO_FOLDER_TYPE_PROGRAMS = 1
. Programas atualmente disponíveis. -
BCRADIO_FOLDER_TYPE_FAVORITES = 2
. Favoritos. -
BCRADIO_FOLDER_TYPE_BAND = 3
. Todos os canais físicos para uma determinada banda.
Não há necessidade de definir campos de metadados personalizados específicos de rádio, pois todos os dados relevantes se encaixam no esquema
MediaBrowser.MediaItem
existente:- Nome do programa (RDS PS, nome do serviço DAB).
MediaDescription.getTitle
. - Frequência FM. URI (consulte ProgramSelector ) ou
MediaDescription.getTitle
(se uma entrada estiver na pastaBROADCASTRADIO_FOLDER_TYPE_BAND
). - Identificadores específicos de rádio (RDS PI, DAB SId).
MediaDescription.getMediaUri
analisado para ProgramSelector.
Normalmente, não há necessidade de buscar a frequência FM para uma entrada no programa atual ou na lista de Favoritos (já que o cliente deve operar em IDs de mídia). No entanto, se tal necessidade surgir (por exemplo, para fins de exibição), ela estará presente no URI e poderá ser analisada para
ProgramSelector
. Dito isso, não é recomendado que o URI seja usado para selecionar itens na sessão atual. Para obter detalhes, consulteProgramSelector
.Para evitar problemas de desempenho ou relacionados ao fichário, o serviço MediaBrowser deve oferecer suporte à paginação:
-
EXTRA_PAGE
-
EXTRA_PAGE_SIZE
- Parâmetros extras para
subscribe()
Nota: Por padrão, a paginação é implementada por padrão na variante
onLoadChildren()
sem manipulação de opções.Entradas relacionadas de todos os tipos de listas (canais brutos, programas encontrados e favoritos) podem ter diferentes mediaIds (depende do aplicativo de rádio; a biblioteca de suporte terá diferentes). Os URIs (no formato ProgramSelector) diferem entre os canais brutos e os programas encontrados na maioria dos casos (exceto para FM sem RDS), mas são praticamente os mesmos entre os programas encontrados e favoritos (exceto, por exemplo, quando o AF foi atualizado).
Ter diferentes mediaIds para entradas de diferentes tipos de listas torna possível executar diferentes ações nelas. Você pode percorrer a lista de Favoritos ou a lista de Todos os Programas em
onSkipToNext
, dependendo da pasta doMediaItem
selecionado recentemente (consulte MediaSession ).Ações especiais de sintonia
A lista de programas permite que os usuários sintonizem uma estação específica, mas não permite que os usuários façam solicitações gerais como "Sintonizar FM", o que pode resultar na sintonização de uma estação ouvida recentemente na banda FM.
Para oferecer suporte a essas ações, alguns diretórios de nível superior têm o sinalizador
FLAG_PLAYABLE
definido (junto comFLAG_BROWSABLE
para pastas).Ação Sintoniza para como emitir Tocar rádio Qualquer canal de rádio startService(ACTION_PLAY_BROADCASTRADIO)
ou,
playFromMediaId(MediaBrowser. getRoot() )
Tocar FM Qualquer canal FM Reproduzir a partir do mediaId
da banda FM.A determinação de qual programa sintonizar depende do aplicativo. Normalmente, é o canal sintonizado mais recentemente na lista fornecida. Para obter detalhes sobre
ACTION_PLAY_BROADCASTRADIO
, consulte Intenções gerais de jogo .Descoberta e conexão de serviço
PackageManager
pode encontrar diretamente a árvore de transmissão de rádio de serviço MediaBrowserService. Para fazer isso, chameresolveService
com a intençãoACTION_PLAY_BROADCASTRADIO
(consulte Intenções gerais de reprodução ) e o sinalizadorMATCH_SYSTEM_ONLY
. Para encontrar todos os serviços que servem rádio (pode haver mais de um; por exemplo, separar AM/FM e satélite), usequeryIntentServices
.O serviço resolvido lida com a intenção de vinculação
android.media.browse.MediaBrowserService
também. Isso é verificado com GTS.Para conectar-se ao MediaBrowserService selecionado, crie uma instância
MediaBrowser
para um determinado componente de serviço econnect
. Depois de estabelecer a conexão, um identificador para MediaSession pode ser obtido viagetSessionToken
.O aplicativo Radio pode restringir os pacotes de clientes com permissão para se conectar em uma implementação
onGetRoot
de seu serviço. O aplicativo deve permitir que os aplicativos do sistema se conectem sem lista de permissões. Para obter detalhes sobre a lista de permissões, consulte Aceitar o pacote e a assinatura do aplicativo Assistente .Se o aplicativo específico da fonte (por exemplo, um aplicativo de rádio) for instalado em um dispositivo sem esse suporte de fonte, ele ainda se anunciará como lidando com a intenção
ACTION_PLAY_BROADCASTRADIO
, mas sua árvore MediaBrowser não conterá tags específicas de rádio. Assim, um cliente que deseja verificar se uma determinada fonte está disponível em um dispositivo, deve:- Descubra o serviço de rádio (chame
resolveService
paraACTION_PLAY_BROADCASTRADIO
). - Crie o
MediaBrowser
e conecte-se a ele. - Determine a presença de
MediaItem
comEXTRA_BCRADIO_FOLDER_TYPE
extra.
Nota: Na maioria dos casos, o cliente deve verificar todas as árvores MediaBrowser disponíveis para detectar todas as fontes disponíveis para um determinado dispositivo.
Nomes de bandas
A lista de bandas é representada por um conjunto de diretórios de nível superior com uma marca de tipo de pasta definida como
BCRADIO_FOLDER_TYPE_BAND
. Os títulos de seusMediaItem
são strings localizadas que representam nomes de bandas. Na maioria dos casos, será o mesmo que a tradução para o inglês, mas o cliente não pode depender dessa suposição.Para fornecer um mecanismo estável para procurar certas bandas, uma tag extra é adicionada para pastas de bandas,
EXTRA_BCRADIO_BAND_NAME_EN
. Este é um nome não localizado da banda e só pode ter um destes valores predefinidos:-
AM
-
FM
-
DAB
Se a banda não estiver nesta lista, a etiqueta de nome da banda não deve ser definida. No entanto, se a banda estiver na lista, ela deve ter um tag definido. O rádio HD não enumera bandas separadas, pois usa o mesmo meio subjacente do AM/FM.
Intenções gerais de jogo
Cada aplicativo dedicado para reproduzir determinada fonte (como rádio ou CD) deve lidar com uma intenção geral de reprodução para iniciar a reprodução de algum conteúdo possivelmente do estado inativo (por exemplo, após a inicialização). Cabe ao aplicativo selecionar o conteúdo a ser reproduzido, mas geralmente é o programa de rádio tocado recentemente ou a faixa do CD. Há uma intenção separada definida para cada fonte de áudio:
-
android.car.intent.action.PLAY_BROADCASTRADIO
-
android.car.intent.action.PLAY_AUDIOCD
: CD-DA ou CD-Texto -
android.car.intent.action.PLAY_DATADISC
: Disco de dados ópticos como CD/DVD, mas não CD-DA (pode ser um CD de modo misto) -
android.car.intent.action.PLAY_AUX
: Sem especificar qual porta AUX -
android.car.intent.action.PLAY_BLUETOOTH
-
android.car.intent.action.PLAY_USB
: Sem especificar qual dispositivo USB -
android.car.intent.action.PLAY_LOCAL
: Armazenamento de mídia local (flash embutido)
Intents foram escolhidos para serem usados para o comando de jogo geral, porque resolvem dois problemas de uma só vez: o próprio comando de jogo geral e a descoberta de serviço. O benefício adicional de ter essa intenção seria a possibilidade de executar essa ação simples sem abrir a sessão do MediaBrowser.
A descoberta de serviço é, na verdade, o problema mais importante resolvido com essas intenções. O procedimento para descoberta de serviço é fácil e inequívoco dessa maneira (consulte Descoberta e conexão de serviço ).
Para facilitar algumas implementações do cliente, existe uma forma alternativa de emitir tal comando Play (que também deve ser implementado pelo aplicativo de rádio): emitir
playFromMediaId
com o rootId do nó raiz (usado como mediaId). Embora o nó raiz não deva ser reproduzido, seu rootId é uma string arbitrária que pode ser consumível como mediaId. No entanto, os clientes não são obrigados a entender essa nuance.Seletor de programa
Embora
mediaId
seja suficiente para selecionar um canal doMediaBrowserService
, ele fica vinculado a uma sessão e não é consistente entre os provedores. Em alguns casos, o cliente pode precisar de um ponteiro absoluto (como uma frequência absoluta) para mantê-lo entre sessões e dispositivos.Na era das transmissões de rádio digital, uma frequência simples não é suficiente para sintonizar uma estação específica. Portanto, use
ProgramSelector
para sintonizar um canal analógico ou digital.ProgramSelector
consiste em duas partes:- Identificador primário. Um identificador exclusivo e estável para uma determinada estação de rádio que não muda, mas pode não ser suficiente para sintonizar essa estação. Por exemplo, o código RDS PI, que pode ser traduzido para o indicativo de chamada nos EUA.
- Identificadores secundários. Identificadores adicionais úteis para sintonizar aquela estação (por exemplo, frequência), possivelmente incluindo identificadores de outras tecnologias de rádio. Por exemplo, uma estação DAB pode ter um fallback de transmissão analógica.
Para permitir que
ProgramSelector
se encaixe na solução baseada emMediaBrowser
ouMediaSession
, defina um esquema de URI para serializá-lo. O esquema é definido da seguinte forma:broadcastradio://program/<primary ID type>/<primary ID>? <secondary ID type>=<secondary ID>&<secondary ID type>=<secondary ID>
Neste exemplo, a parte secundária dos Identificadores (após o ponto de interrogação (
?
)) é opcional e pode ser removida para fornecer um identificador estável para uso comomediaId
. Por exemplo:-
broadcastradio://program/RDS_PI/1234?AMFM_FREQUENCY=88500&AMFM_FREQUENCY=103300
-
broadcastradio://program/AMFM_FREQUENCY/102100
-
broadcastradio://program/DAB_SID_EXT/14895264?RDS_PI=1234
A parte de autoridade (host AKA) do
program
oferece algum espaço para extensão do esquema no futuro. As strings de tipo de identificador são precisamente especificadas como seus nomes na definição HAL 2.x deIdentifierType
e o formato do valor é um número decimal ou hexadecimal (com prefixo0x
).Todos os identificadores específicos do fornecedor são representados pelo prefixo
VENDOR_
. Por exemplo,VENDOR_0
paraVENDOR_START
eVENDOR_1
paraVENDOR_START
mais 1. Esses URIs são específicos do hardware de rádio no qual foram gerados e não podem ser transferidos entre dispositivos fabricados por OEMs diferentes.Esses URIs devem ser atribuídos a cada MediaItem nas pastas de rádio de nível superior. Além disso, o MediaSession deve oferecer suporte a
playFromMediaId
eplayFromUri
. No entanto, o URI destina-se principalmente à extração de metadados de rádio (como frequência FM) e armazenamento persistente. Não há garantia de que o URI estará disponível para todos os itens de mídia (por exemplo, quando o tipo de ID primário ainda não é suportado pela estrutura). Por outro lado, o Media ID sempre funciona. Não é recomendado que os clientes usem URI para selecionar itens da sessão atual do MediaBrowser. Em vez disso, useplayFromMediaId
. Dito isso, não é opcional para o aplicativo servidor e os URIs ausentes são reservados para casos bem justificados.O design inicial usava dois pontos simples em vez da sequência
://
após a parte do esquema. No entanto, o primeiro não é compatível comandroid.net.Uri
para referências de URI hierárquicas absolutas.Outros tipos de fonte
Outras fontes de áudio podem ser tratadas de forma semelhante. Por exemplo, entrada auxiliar e reprodutor de CD de áudio.
Um único aplicativo pode atender a vários tipos de fontes. Nesses casos, é recomendável criar um MediaBrowserService separado para cada tipo de origem. Mesmo em uma configuração com várias fontes servidas/MediaBrowserServices, é altamente recomendável ter uma única MediaSession em um único aplicativo.
CD de áudio
Semelhante ao CD de áudio, pois o aplicativo que atende a esses discos exporia o MediaBrowser com uma única entrada navegável (ou mais, se o sistema tiver uma disqueteira de CD), que por sua vez conteria todas as faixas de um determinado CD. Se o sistema não tiver o conhecimento sobre as faixas de cada CD (por exemplo, quando todos os discos são inseridos em um cartucho de uma vez e ele não os lê todos), o MediaItem para o disco inteiro seria apenas
PLAYABLE
, nãoBROWSABLE
maisPLAYABLE
. Se não houver disco em um determinado slot, o item não seráPLAYABLE
nemBROWSABLE
(mas cada slot deve sempre estar presente na árvore).Essas entradas seriam marcadas de maneira semelhante às pastas de rádio de transmissão; eles conteriam campos extras adicionais definidos na API MediaDescription:
-
EXTRA_CD_TRACK
: Para cadaMediaItem
em CD de áudio, número de faixa baseado em 1. -
EXTRA_CD_DISK
: número de disco baseado em 1.
Para sistema habilitado para CD-Text e disco compatível, o MediaItem de nível superior teria um título do disco. Da mesma forma, os MediaItems para faixas teriam um título da faixa.
Entrada auxiliar
O aplicativo que atende a entrada auxiliar expõe uma árvore MediaBrowser com uma única entrada (ou mais, quando existem várias portas) representando a porta AUX in. A respectiva MediaSession pega seu mediaId e muda para essa fonte depois de receber a solicitação
playFromMediaId
.Cada entrada AUX MediaItem teria um campo extra
EXTRA_AUX_PORT_NAME
definido para o nome não localizado da porta sem a frase "AUX". For example, "AUX 1" would have be set to "1", "AUX front" to "front" and "AUX" to an empty string. In non-English locales, the name tag would remain the same English string. Unlikely as forEXTRA_BCRADIO_BAND_NAME_EN
, the values are OEM-defined and not constrained to a predefined list.If the hardware can detect devices connected to the AUX port, the hardware should mark the MediaItem as
PLAYABLE
, only if input is connected. The hardware should still be enumerated (but notPLAYABLE
) if nothing was connected to this port. If the hardware has no such capability, the MediaItem must always be set toPLAYABLE
.Extra fields
Define the following fields:
-
EXTRA_CD_TRACK = "android.media.extra.CD_TRACK"
-
EXTRA_CD_DISK = "android.media.extra.CD_DISK"
-
EXTRA_AUX_PORT_NAME = "android.media.extra.AUX_PORT_NAME"
Client needs to review the top-level MediaItems for elements having the
EXTRA_CD_DISK
orEXTRA_AUX_PORT_NAME
extra field set.Detailed examples
The following examples address the MediaBrowser tree structure for source types that are part of this design.
Broadcast radio MediaBrowserService (handles
ACTION_PLAY_BROADCASTRADIO
):- Stations (browsable)
EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_PROGRAMS
- BBC One (playable) URI:
broadcastradio://program/RDS_PI/1234?AMFM_FREQUENCY=90500
- ABC 88.1 (playable) URI:
broadcastradio://program/RDS_PI/5678?AMFM_FREQUENCY=88100
- ABC 88.1 HD1 (playable) URI:
broadcastradio://program/HD_STATION_ID_EXT/158241DEADBEEF?AMFM_FREQUENCY=88100&RDS_PI=5678
- ABC 88.1 HD2 (playable) URI:
broadcastradio://program/HD_STATION_ID_EXT/158242DEADBEFE
- 90.5 FM (playable) – FM without RDSURI:
broadcastradio://program/AMFM_FREQUENCY/90500
- 620 AM (playable) URI:
broadcastradio://program/AMFM_FREQUENCY/620
- BBC One (playable) URI:
broadcastradio://program/DAB_SID_EXT/1E24102?RDS_PI=1234
- BBC One (playable) URI:
- Favorites (browsable, playable)
EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_FAVORITES
- BBC One (playable) URI:
broadcastradio://program/RDS_PI/1234?AMFM_FREQUENCY=101300
- BBC Two (not playable)URI:
broadcastradio://program/RDS_PI/1300?AMFM_FREQUENCY=102100
- BBC One (playable) URI:
- AM (browsable, playable):
EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_BANDEXTRA_BCRADIO_BAND_NAME_EN="AM"
- 530 AM (playable) URI:
broadcastradio://program/AMFM_FREQUENCY/530
- 540 AM (playable) URI:
broadcastradio://program/AMFM_FREQUENCY/540
- 550 AM (playable) URI:
broadcastradio://program/AMFM_FREQUENCY/550
- 530 AM (playable) URI:
- FM (browsable, playable):
EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_BANDEXTRA_BCRADIO_BAND_NAME_EN="FM"
- 87.7 FM (playable) URI:
broadcastradio://program/AMFM_FREQUENCY/87700
- 87.9 FM (playable) URI:
broadcastradio://program/AMFM_FREQUENCY/87900
- 88.1 FM (playable) URI:
broadcastradio://program/AMFM_FREQUENCY/88100
- 87.7 FM (playable) URI:
- DAB (playable):
EXTRA_BCRADIO_FOLDER_TYPE=BCRADIO_FOLDER_TYPE_BANDEXTRA_BCRADIO_BAND_NAME_EN="DAB"
Audio CD MediaBrowserService (handles
ACTION_PLAY_AUDIOCD
):- Disc 1 (playable)
EXTRA_CD_DISK=1
- Disc 2 (browsable, playable)
EXTRA_CD_DISK=2
- Track 1 (playable)
EXTRA_CD_TRACK=1
- Track 2 (playable)
EXTRA_CD_TRACK=2
- Track 1 (playable)
- My music CD (browsable, playable)
EXTRA_CD_DISK=3
- All By Myself (playable)
EXTRA_CD_TRACK=1
- Reise, Reise (playable)
EXTRA_CD_TRACK=2
- All By Myself (playable)
- Empty slot 4 (not playable)
EXTRA_CD_DISK=4
AUX MediaBrowserService (handles
ACTION_PLAY_AUX
):- AUX front (playable)
EXTRA_AUX_PORT_NAME="front"
- AUX rear (playable)
EXTRA_AUX_PORT_NAME="rear"
-