Implementar Radio

Esta página explica cómo implementar la radio a nivel de hardware y software.

Componentes del sistema

La pila de transmisión de radio incluye los siguientes componentes.

Arquitectura de radiodifusión
Figura 1. Arquitectura de radiodifusión

aplicación de referencia de radio

Para obtener detalles sobre cómo implementar el control de radio, consulte Implementación del control de radio .

Una aplicación de radio Java de muestra ( packages/apps/Car/Radio ) sirve como implementación de referencia. Cuando se inicia el servicio de la aplicación, solicita a Radio Manager que abra un sintonizador de radio. Luego, la aplicación puede enviar solicitudes al sintonizador de radio, como sintonizar una estación de radio o frecuencia específicas, o buscar la siguiente estación de radio disponible. La aplicación recibe actualizaciones de Radio Manager y Radio Tuner en Radio, como información actual del programa, listas de programas de radio, configuraciones y parámetros definidos por el proveedor. La aplicación Radio de referencia solo admite radio AM y FM. Los OEM pueden modificar o reemplazar la aplicación Radio según lo deseen.

gerente de radio

Cuando la aplicación solicita a Radio Manager que abra un sintonizador, Radio Manager ( frameworks/base/core/java/android/hardware/radio/RadioManager.java ) solicita al Servicio de radiodifusión que abra una sesión de sintonizador y luego envuelve la sesión en un Sintonizador de radio ( frameworks/base/core/java/android/hardware/radio/RadioTuner.java ), que se devuelve a la aplicación. El Sintonizador de radio define las API (como sintonizar, paso y cancelar) que se pueden llamar desde las aplicaciones de radio y enviar solicitudes al Servicio de radiodifusión. Los métodos de devolución de llamada ( RadioTuner.Callback ) definidos en Radio Tuner envían actualizaciones sobre la transmisión de radio HAL, como información actual del programa, listas de programas y parámetros definidos por el proveedor, desde el Servicio de transmisión de radio a las aplicaciones.

Servicio de radiodifusión

Broadcast Radio Service ( frameworks/base/services/core/java/com/android/server/broadcastradio ) es el servicio de cliente para Broadcast Radio HAL. El Servicio de radiodifusión coordina múltiples administradores de radio con HAL de radiodifusión. El servicio de radiodifusión admite el lenguaje de definición de interfaz HAL (HIDL) y el lenguaje de definición de interfaz Android (AIDL) de radiodifusión HAL. El Servicio de Radiodifusión se vincula con el AIDL HAL cuando existe algún servicio AIDL HAL; de lo contrario, el servicio se vincula a HIDL HAL. El servicio de radiodifusión crea un módulo de radio para cada instancia de HAL disponible (como AM, FM y DAB).

Cada Administrador de Radio puede solicitar al Servicio de Radiodifusión que cree una sesión de sintonizador en el Módulo de Radio correspondiente, según el tipo de radio. Cada sesión del sintonizador puede llamar a métodos, como sintonizar, paso y cancelar (definidos en las interfaces HAL) para realizar operaciones en la instancia HAL de radiodifusión correspondiente. Cuando una sesión de sintonizador recibe una devolución de llamada de la instancia de HAL en una actualización de HAL, como la información del programa actual, la lista de programas, los indicadores de configuración y los parámetros del proveedor, las devoluciones de llamada sobre la actualización se envían a todos los sintonizadores de radio vinculados al mismo módulo de radio.

Difusión de radio HAL

Para obtener más información sobre las interfaces HIDL y AIDL de la radiodifusión y las diferencias entre las dos, consulte Interfaz HAL de radiodifusión .

Capa de abstracción de hardware de radiodifusión

Las siguientes secciones describen cómo trabajar con la capa de hardware para implementar la transmisión de radio.

Interfaz HAL de radiodifusión

La radiodifusión HAL proporciona estructuras de datos e interfaces a nivel de hardware para implementar la radiodifusión, como la radio AM/FM y DAB.

Interfaces HIDL 2.0 y AIDL

La radiodifusión HAL utiliza las interfaces descritas en las siguientes secciones.

Oyente de anuncios

IAnnouncementListener es la interfaz de devolución de llamada para el oyente de anuncios, que se puede registrar en la transmisión de radio HAL para recibir anuncios. La interfaz tiene los siguientes métodos:

IAnnouncementListener
Descripción: Llamado cada vez que la lista de anuncios ha cambiado.
HIDL 2.0 oneway onListUpdated(vec<Announcement> announcements)
AIDL oneway void onListUpdated(in Announcement[] announcements)
Cerrar mango

ICloseHandle es el identificador de cierre genérico para eliminar una devolución de llamada que no necesita una interfaz activa.

ICerrarManejar
Descripción: Cierra el mango.
HIDL 2.0 close()
AIDL void close()

Interfaz de devolución de llamada

ITunerCallback es la interfaz de devolución de llamada llamada por la transmisión de radio HAL para enviar actualizaciones al servicio de cliente de HAL.

ITunerCallback
Descripción: Llamado por HAL cuando una operación de sintonización (sintonización, búsqueda (en AIDL) o exploración (en HIDL) y el paso tiene éxito) falla de forma asíncrona.
HIDL 2.0 oneway onCurrentProgramInfoChanged(ProgramInfo info)
AIDL void onCurrentProgramInfoChanged(in ProgramInfo info)
Descripción: se llama cuando la sintonización, la búsqueda (en AIDL) o la exploración (en HIDL) o el paso se realizan correctamente.
HIDL 2.0 oneway onTuneFailed(Result result, ProgramSelector selector)
AIDL void onTuneFailed(in Result result, in ProgramSelector selector)
Descripción: se llama cuando la sintonización, la búsqueda (en AIDL) o la exploración (en HIDL) o el paso se realizan correctamente.
HIDL 2.0 oneway onCurrentProgramInfoChanged(ProgramInfo info)
AIDL void onCurrentProgramInfoChanged(in ProgramInfo info)
Descripción: Se llama cuando se actualiza la lista de programas; el tamaño de cada fragmento debe limitarse a 500 kiB.
HIDL 2.0 oneway onProgramListUpdated(ProgramListChunk chunk)
AIDL oneway onProgramListUpdated(ProgramListChunk chunk)
Descripción: Se llama cuando la antena está conectada o desconectada.
HIDL 2.0 oneway onAntennaStateChange(bool connected)
AIDL void onCurrentProgramInfoChanged(in ProgramInfo info)
Descripción: se llama cuando los valores de los parámetros específicos del proveedor se actualizan internamente en HAL (no se debe invocar después de llamar setParameters por parte del cliente HAL).
HIDL 2.0 oneway onParametersUpdated(vec<VendorKeyValue> parameters)
AIDL void onParametersUpdated(in VendorKeyValue[] parameters)
Descripción: Nuevo en AIDL. Llamado cuando el indicador de configuración se actualiza internamente en HAL (no debe invocarse después de llamar setConfigFlag por parte del cliente HAL).
HIDL 2.0 No aplica.
AIDL void onConfigFlagUpdated(in ConfigFlag flag, in boolean value)

Interfaz HAL de radio de transmisión primaria

IBroadcastRadio es la interfaz principal para la radiodifusión HAL. En HIDL 2.0 HAL, use la interfaz ITunerSession para el sintonizador para llamar a las operaciones. Sin embargo, como máximo un sintonizador está activo a la vez (siempre que cada instancia de HAL de radiodifusión solo tenga un chip sintonizador). ITunerSession se eliminó de las interfaces AIDL y sus interfaces se trasladaron a IBroadcastRadio .

IBroadcastRadio
Descripción: Obtenga la descripción de un módulo y sus capacidades.
HIDL 2.0 getProperties() generates (Properties properties)
AIDL Properties getProperties()
Descripción: Obtiene la configuración actual o posible de la región AM/FM.
HIDL 2.0 getAmFmRegionConfig(bool full) generates (Result result, AmFmRegionConfig config)
AIDL AmFmRegionConfig getAmFmRegionConfig(bool full)
Descripción: Obtiene la configuración actual de la región DAB.
HIDL 2.0 getDabRegionConfig() generates (Result result, vec<DabTableEntry> config)
AIDL DabTableEntry[] getDabRegionConfig()
Descripción: Obtiene una imagen del caché del módulo de radio. En AIDL, el tamaño de la imagen debe ser inferior a 1 MB debido a un límite estricto en el búfer de transacciones del enlazador.
HIDL 2.0 getImage(uint32_t id) generates (vec<uint8_t> image)
AIDL byte[] getImage(in int id)
Descripción: Registra el oyente de anuncios.
HIDL 2.0 registerAnnouncementListener(vec<AnnouncementType> enabled,IAnnouncementListener listener) generates (Result result, ICloseHandle closeHandle)
AIDL ICloseHandle registerAnnouncementListener(in IAnnouncementListener listener, in AnnouncementType[] enabled)
Descripción:
  • HIDL HAL: cuando se abre una nueva sesión de sintonizador, la sesión anterior debe finalizar.
  • AIDL HAL: dado que no hay ninguna sesión de sintonizador disponible, solo se debe configurar la devolución de llamada del sintonizador. Si existe, la devolución de llamada anterior debe desactivarse.
HIDL 2.0 openSession(ITunerCallback callback) genera (Result result, ITunerSession session)
AIDL void setTunerCallback(in ITunerCallback callback)
Descripción:
  • HIDL HAL: El cierre de una sesión del sintonizador no debe fallar y solo debe emitirse una vez.
  • AIDL HAL: No hay sintonizador y solo se debe desactivar la devolución de llamada del sintonizador.
HIDL 2.0 close()
AIDL unsetTunerCallback()
Descripción: Sintoniza un programa específico.
HIDL 2.0 tune(ProgramSelector program) generates (Result result)
AIDL void tune(in ProgramSelector program)
Descripción: Busca el próximo programa válido en el aire . Para evitar confusiones en AIDL, se cambia el nombre scan a seek .
HIDL 2.0 scan(bool directionUp, bool skipSubChannel) generates (Result result)
AIDL void seek(in boolean directionUp, in boolean skipSubChannel)
Descripción: Pasos al canal contiguo, que no podrán ser ocupados por ningún programa.
HIDL 2.0 step(bool directionUp) generates (Result result)
AIDL void step(in boolean directionUp)
Descripción: Cancela las operaciones de sintonización, exploración (en HIDL) o búsqueda (en AIDL) o pasos pendientes.
HIDL 2.0 cancel()
AIDL void cancel()
Descripción: aplica un filtro a la lista de programas y comienza a enviar actualizaciones de la lista de programas a través de la devolución de llamada onProgramListUpdated .
HIDL 2.0 startProgramListUpdates(ProgramFilter filter) generates (Result result)
AIDL void startProgramListUpdates(in ProgramFilter filter)
Descripción: deja de enviar actualizaciones de la lista de programas.
HIDL 2.0 stopProgramListUpdates()
AIDL void stopProgramListUpdates()
Descripción: Obtiene la configuración actual de un indicador de configuración determinado.
HIDL 2.0 isConfigFlagSet(ConfigFlag flag) generates (Result result, bool value)
AIDL boolean isConfigFlagSet(in ConfigFlag flag)
Descripción: Establece el indicador de configuración dado.
HIDL 2.0 setConfigFlag(ConfigFlag flag, bool value) generates (Result result)
AIDL void setConfigFlag(in ConfigFlag flag, boolean value)
Descripción: Establece valores de parámetros específicos del proveedor.
HIDL 2.0 setParameters(vec<VendorKeyValue> parameters)

genera ,

(vec<VendorKeyValue> results)
AIDL VendorKeyValue[] setParameters(in VendorKeyValue[] parameters)
Descripción: Recupera valores de parámetros específicos del proveedor.
HIDL 2.0 getParameters(vec<string> keys) generates (vec<VendorKeyValue> parameters)
AIDL VendorKeyValue[] getParameters(in String[] keys)

Aclaraciones de la interfaz

Comportamiento asíncrono

Dado que cada operación de ajuste (por ejemplo, sintonizar, escanear (en HIDL) o buscar (en AIDL) y paso) puede llevar mucho tiempo y el subproceso no debe bloquearse durante mucho tiempo, la operación debe programar operaciones que consumen mucho tiempo. ocurrir más tarde y devolver rápidamente un estado o resultado. En detalle, cada operación debe:

  • Cancele todas las operaciones de ajuste pendientes.
  • Compruebe si la operación se puede procesar según las entradas del método y el estado del sintonizador.
  • Programe la tarea de ajuste y luego devuelva el Result (en HIDL) o status (en AIDL) inmediatamente. Si el Result o status es OK , se debe llamar a la devolución de llamada del sintonizador tuneFailed o currentProgramInfoChanged cuando la tarea de ajuste falló (por ejemplo, debido a un tiempo de espera) o se completó.

De manera similar, startProgramListUpdates también programa la tarea de actualizar la lista de programas, que lleva mucho tiempo, para que se realice más tarde y para devolver rápidamente un estado o resultado. El método primero cancela las solicitudes de actualización pendientes y luego programa la tarea de actualización y devuelve rápidamente el resultado.

Condición de carrera

Debido al comportamiento asíncrono de las operaciones de sintonización (por ejemplo, sintonizar, escanear (en HIDL) o buscar (en AIDL) y paso), existe una condición de carrera entre la cancelación de la operación y las operaciones de sintonización. Si se llama cancel después de que HAL complete una operación de sintonización y antes de que se complete la devolución de llamada, se puede ignorar la cancelación y la devolución de llamada debe completarse y ser recibida por el cliente HAL.

De manera similar, si se llama stopProgramListUpdates después de que HAL complete una actualización de la lista de programas y antes de que finalice la devolución de llamada onCurrentProgramInfoChanged , se puede ignorar stopProgramListUpdates y la devolución de llamada debería completarse.

Límite de tamaño de datos

Dado que existe un límite estricto en el búfer de transacciones del enlazador, el límite de datos para algunos métodos de interfaz que pasan datos de un tamaño potencialmente grande se aclara en AIDL HAL.

  • getImage requiere que la imagen devuelta tenga menos de 1 MB.
  • onProgramListUpdate requiere que cada chunk sea inferior a 500 kiB. La implementación de HAL debe dividir las listas de programas más grandes en varios fragmentos y enviarlos a través de varias devoluciones de llamada.

Cambios en las estructuras de datos AIDL HAL

Además de los cambios en las interfaces, estos cambios se han aplicado a las estructuras de datos definidas en la radiodifusión AIDL HAL, que aprovecha el AIDL.

  • La enumeración Constant se elimina en AIDL y se define como const int en IBroadcastRadio . Mientras tanto, ANTENNA_DISCONNECTED_TIMEOUT_MS cambia de nombre a ANTENNA_STATE_CHANGE_TIMEOUT_MS . Se agrega un nuevo const int TUNER_TIMEOUT_MS . Todas las operaciones de sintonización, búsqueda y paso deben completarse dentro de este tiempo.
  • Enum RDS y Deemphasis se eliminan en AIDL y se definen como const int en AmFmRegionConfig . En consecuencia, tanto fmDeemphasis como fmRds en ProgramInfo se declaran como int, un resultado de cálculo de bits de las banderas respectivas. Mientras tanto, D50 y D75 se renombran como DEEMPHASIS_D50 y DEEMPHASIS_D75 , respectivamente.
  • Enum ProgramInfoFlags se eliminan en AIDL y se definen como const int en ProgramInfo con un prefijo FLAG_ agregado. En consecuencia, infoFlags en ProgramInfo se declara como int, un resultado de cálculo de bit de banderas. TUNED también se renombra a FLAG_TUNABLE , para describir mejor su definición de que se puede sintonizar la estación.
  • En AmFmBandRange , scanSpacing se renombra como seekSpacing , ya que scan se renombra como seek en AIDL.
  • Dado que el concepto de unión se introduce en AIDL, MetadataKey y Metadata definidos en HIDL HAL ya no se utilizan. Una unión AIDL Metadata se define en AIDL HAL. Cada valor de enumeración anteriormente en MetadataKey ahora es un campo en Metadata con tipo de cadena o int, según sus definiciones.

Implementación de radio control

La implementación del control de radio se basa en MediaSession y MediaBrowse , que permiten que las aplicaciones de medios y asistentes de voz controlen la radio. Para obtener más información, consulte Crear aplicaciones multimedia para automóviles en developer.android.com.

Se proporciona una implementación del árbol de exploración de medios en la biblioteca car-broadcastradio-support en packages/apps/Car/libs . Esta biblioteca también contiene extensiones de ProgramSelector para convertir hacia y desde URI. Se recomienda que las implementaciones de radio usen esta biblioteca para construir el árbol de navegación asociado.

Conmutador de fuente de medios

Para proporcionar una transición fluida entre la radio y otras aplicaciones que se muestran en los medios, la biblioteca car-media-common contiene clases que deben integrarse en la aplicación de radio. MediaAppSelectorWidget se puede incluir en el XML de la aplicación de radio (el icono y el menú desplegable utilizados en las aplicaciones de radio y medios de referencia):

<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 AppSelectionFragment , que muestra una lista de fuentes de medios a las que se puede cambiar. Si se desea una interfaz de usuario distinta a la proporcionada, puede crear un widget personalizado para iniciar AppSelectionFragment cuando se deba mostrar el conmutador.

AppSelectionFragment newFragment = AppSelectionFragment.create(widget,
            packageName, fullScreen);
    newFragment.show(mActivity.getSupportFragmentManager(), null);

Se proporciona una implementación de muestra en la implementación de la aplicación de radio de referencia, ubicada en packages/apps/Car/Radio .

Especificaciones de control detalladas

La interfaz MediaSession (a través de MediaSession.Callback ) proporciona mecanismos de control para el programa de radio que se está reproduciendo actualmente:

  • onPlay , onStop . (Des) silenciar la reproducción de radio.
  • onPause . Pausa en diferido (si se admite).
  • onPlayFromMediaId . Reproduce cualquier contenido de una carpeta de nivel superior. Por ejemplo, "Reproducir FM" o "Reproducir radio".
  • onPlayFromUri . Reproduce una frecuencia específica. Por ejemplo, "Reproducir 88.5 FM".
  • onSkipToNext , onSkipToPrevious . Sintonice una estación anterior o siguiente.
  • onSetRating . Agregar o quitar a o de Favoritos.

MediaBrowser expone un MediaItem ajustable en tres tipos de directorios de nivel superior:

  • ( Opcional ) Programas (estaciones). Este modo lo suelen utilizar las radios de doble sintonizador para indicar todas las estaciones de radio sintonizables disponibles en la ubicación del usuario.
  • Favoritos. Programas de radio agregados a la lista de Favoritos, algunos pueden no estar disponibles (fuera del rango de recepción).
  • Canales de banda. Todos los canales físicamente posibles en la región actual (87.9, 88.1, 88.3, ​​88.5, 88.7, 88.9, 89.1 y así sucesivamente). Cada banda tiene un directorio de nivel superior separado.
Estructura de árbol de MediaBrowserService
Figura 2. Estructura de árbol de MediaBrowserService

Cada elemento en cada una de estas carpetas (AM/FM/Programas) es un elemento multimedia con un URI que se puede usar con MediaSession para sintonizar. Cada carpeta de nivel superior (AM/FM/Programas) es un MediaItem con un mediaId que se puede usar con MediaSession para activar la reproducción y queda a discreción del OEM. Por ejemplo, "Reproducir FM", "Reproducir AM" y "Reproducir radio" son consultas de radio no específicas que usan un ID de medio para enviar a la aplicación de radio OEM. Depende de la aplicación de radio determinar qué reproducir desde la solicitud genérica y el ID de medios.

MediaSession

Dado que no existe el concepto de pausar una transmisión, las acciones Reproducir, Pausa y Detener no siempre se aplican a la radio. Con la radio, la acción Detener está asociada con silenciar la transmisión, mientras que Reproducir está asociada con eliminar el silenciamiento.

Algunos sintonizadores de radio (o aplicaciones) brindan la capacidad de simular una pausa en la transmisión al almacenar contenido en caché y luego reproducirlo más tarde. En tales casos, use onPause .

Reproducir desde las acciones mediaId y URI está destinado a sintonizar una estación obtenida desde la interfaz de MediaBrowser. El mediaId es una cadena arbitraria proporcionada por la aplicación de radio para imponer un valor único (por lo que una identificación determinada apunta a un solo elemento) y estable (por lo que un elemento determinado tiene la misma identificación durante toda la sesión) con el que identificar una estación determinada . El URI será de un esquema bien definido. En resumen, una forma URI de ProgramSelector. Si bien esto preserva el atributo de unicidad, no necesita ser estable, aunque puede cambiar cuando la estación se mueve a una frecuencia diferente.

Por diseño, onPlayFromSearch no se usa. Es responsabilidad del cliente (aplicación complementaria) seleccionar un resultado de búsqueda del árbol de MediaBrowser. Transferir esa responsabilidad a la aplicación de radio aumentaría la complejidad, requeriría contratos formales sobre cómo deberían aparecer las consultas de cadena y daría como resultado una experiencia de usuario desigual en diferentes plataformas de hardware.

Nota: La aplicación de radio no contiene información adicional que sería útil para buscar el nombre de una estación que no esté expuesta al cliente a través de la interfaz de MediaBrowser.

Saltar a la estación siguiente o anterior depende del contexto actual:

  • Cuando una aplicación se sintoniza en una estación de la lista de Favoritos, la aplicación puede pasar a la siguiente estación de la lista de Favoritos.
  • Escuchar una estación de la lista de programas puede resultar en la sintonización de la próxima estación disponible, ordenada según el número de canal.
  • Escuchar un canal arbitrario puede resultar en sintonizar el siguiente canal físico, incluso cuando no hay señal de transmisión.

La aplicación de radio maneja estas acciones.

Manejo de errores

Las acciones TransportControls (Reproducir, Detener y Siguiente) no proporcionan información sobre si la acción se realizó correctamente o no. La única forma de indicar un error es establecer el estado de MediaSession en STATE_ERROR con un mensaje de error.

La aplicación de radio debe manejar esas acciones y ejecutarlas o establecer un estado de error. Si la ejecución del comando de reproducción no es inmediata, el estado de reproducción debe cambiarse a STATE_CONNECTING (en caso de sintonización directa) o STATE_SKIPPING_TO_PREVIOUS o NEXT mientras se ejecuta el comando.

El cliente debe ver PlaybackState y verificar que la sesión cambió el programa actual a lo que se solicitó o entró en estado de error. STATE_CONNECTING no debe exceder los 30 s. Sin embargo, una sintonización directa a una frecuencia AM/FM dada debería funcionar mucho más rápido.

Adición y eliminación de favoritos

MediaSession tiene soporte de calificación, que se puede usar para controlar los Favoritos. onSetRating llamado con una calificación de tipo RATING_HEART agrega o elimina la estación sintonizada actualmente ao de la lista de Favoritos.

A diferencia de los ajustes preestablecidos heredados, este modelo asume una lista de favoritos desordenada e ilimitada, cuando cada favorito guardado se asigna a una ranura numérica (normalmente, del 1 al 6). Como resultado, los sistemas basados ​​en preajustes serían incompatibles con la operación onSetRating .

La limitación de la API MediaSession es que solo se puede agregar o eliminar la estación sintonizada actualmente. Por ejemplo, los elementos deben seleccionarse primero antes de que puedan eliminarse. Esta es solo una limitación del cliente MediaBrowser, como una aplicación complementaria. La aplicación de radio no está restringida de manera similar. Esta parte es opcional cuando una aplicación no admite Favoritos.

Explorador de medios

Para expresar qué frecuencias o nombres de canales físicos (cuando sintonizar un canal arbitrario es adecuado para una tecnología de radio determinada) son válidos para una región determinada, se enumeran todos los canales válidos (frecuencias) para cada banda. En la región de EE. UU., esto equivale a 101 canales de FM en el rango de 87,8 a 108,0 MHz (con un espaciado de 0,2 MHz) y 117 canales de AM en el rango de 530 a 1700 kHz (con un espaciado de 10 kHz). Debido a que la radio HD usa el mismo espacio de canal, no se presenta por separado.

La lista de programas de radio actualmente disponibles es plana en el sentido de que esto no permite esquemas de visualización como la agrupación por conjunto de transmisión directa de audio (DAB).

Es posible que las entradas de la lista de favoritos no se puedan sintonizar. Por ejemplo, si un programa dado está fuera de rango. La aplicación de radio puede o no detectar si la entrada se puede sintonizar de antemano. Si es así, es posible que no marque la entrada como jugable.

Para identificar las carpetas de nivel superior, se aplica el mismo mecanismo que utiliza Bluetooth. Es decir, un paquete Extras del objeto MediaDescription contiene un campo específico del sintonizador tal como lo hace Bluetooth con EXTRA_BT_FOLDER_TYPE . En el caso de la radiodifusión, esto lleva a definir los siguientes nuevos campos en la API pública:

  • EXTRA_BCRADIO_FOLDER_TYPE = "android.media.extra.EXTRA_BCRADIO_FOLDER_TYPE" . Uno de los siguientes valores:
    • BCRADIO_FOLDER_TYPE_PROGRAMS = 1 . Programas disponibles actualmente.
    • BCRADIO_FOLDER_TYPE_FAVORITES = 2 . Favoritos.
    • BCRADIO_FOLDER_TYPE_BAND = 3 . Todos los canales físicos para una banda determinada.

    No es necesario definir ningún campo de metadatos personalizado específico de radio, ya que todos los datos relevantes se ajustan al esquema MediaBrowser.MediaItem existente:

    • Nombre del programa (RDS PS, nombre del servicio DAB). MediaDescription.getTitle .
    • frecuencia FM. URI (ver ProgramSelector ) o MediaDescription.getTitle (si una entrada está en la carpeta BROADCASTRADIO_FOLDER_TYPE_BAND ).
    • Identificadores específicos de radio (RDS PI, DAB SId). MediaDescription.getMediaUri analizado en ProgramSelector.

    Por lo general, no es necesario buscar la frecuencia FM para una entrada en el programa actual o en la lista de favoritos (ya que el cliente debe operar con ID de medios). Sin embargo, si surgiera tal necesidad (por ejemplo, con fines de visualización), está presente en el URI y se puede analizar en ProgramSelector . Dicho esto, no se recomienda utilizar el URI para seleccionar elementos dentro de la sesión actual. Para obtener más información, consulte ProgramSelector .

    Para evitar problemas relacionados con el rendimiento o el enlazador, el servicio MediaBrowser debe admitir la paginación:

    Nota: De forma predeterminada, la paginación se implementa de forma predeterminada en la variante onLoadChildren() sin manejo de opciones.

    Las entradas relacionadas de todos los tipos de listas (canales sin procesar, programas encontrados y favoritos) pueden tener ID de medios diferentes (depende de la aplicación de radio; la biblioteca de soporte los tendrá diferentes). Los URI (en forma de ProgramSelector) difieren entre los canales sin procesar y los programas encontrados en la mayoría de los casos (excepto FM sin RDS), pero en su mayoría son los mismos entre los programas encontrados y los favoritos (excepto, por ejemplo, cuando se actualizó AF).

    Tener diferentes mediaIds para entradas de diferentes tipos de listas hace posible realizar diferentes acciones en ellas. Puede recorrer la lista de Favoritos o la lista de Todos los programas en onSkipToNext , según la carpeta del MediaItem seleccionado recientemente (consulte MediaSession ).

    Acciones especiales de melodía

    La lista de programas permite a los usuarios sintonizar una estación específica, pero no permite que los usuarios realicen solicitudes generales como "Sintonizar FM", lo que podría resultar en la sintonización de una estación escuchada recientemente en la banda FM.

    Para admitir tales acciones, algunos directorios de nivel superior tienen establecido el indicador FLAG_PLAYABLE (junto con FLAG_BROWSABLE para carpetas).

    Acción Sintoniza a como emitir
    reproducir radio Cualquier canal de radio startService(ACTION_PLAY_BROADCASTRADIO)

    o,

    playFromMediaId(MediaBrowser. getRoot() )
    Reproducir FM Cualquier canal FM Reproducir desde el mediaId de la banda FM.

    La determinación de qué programa sintonizar depende de la aplicación. Este suele ser el canal sintonizado más recientemente de la lista dada. Para obtener detalles sobre ACTION_PLAY_BROADCASTRADIO , consulte Intentos generales de reproducción .

    Descubrimiento y conexión de servicios

    PackageManager puede encontrar directamente el árbol de transmisión de radio MediaBrowserService. Para hacerlo, llame a resolveService con la intención ACTION_PLAY_BROADCASTRADIO (consulte Intentos generales de reproducción ) y el indicador MATCH_SYSTEM_ONLY . Para encontrar todos los servicios que prestan servicios de radio (puede haber más de uno; por ejemplo, AM/FM y satélite por separado), use queryIntentServices .

    El servicio resuelto también maneja la intención de vinculación de android.media.browse.MediaBrowserService . Esto se verifica con GTS.

    Para conectarse al MediaBrowserService seleccionado, cree una instancia MediaBrowser para un componente de servicio determinado y connect . Después de establecer la conexión, se puede obtener un identificador de MediaSession a través de getSessionToken .

    La aplicación Radio puede restringir los paquetes de clientes que pueden conectarse en una implementación onGetRoot de su servicio. La aplicación debe permitir que las aplicaciones del sistema se conecten sin incluirlas en la lista blanca. Para obtener detalles sobre la inclusión en la lista blanca, consulte Aceptar el paquete y la firma de la aplicación Assistant .

    Si la aplicación específica de la fuente (por ejemplo, una aplicación de radio) se instala en un dispositivo sin dicha compatibilidad con la fuente, se anunciaría a sí misma como responsable de la intención ACTION_PLAY_BROADCASTRADIO , pero su árbol MediaBrowser no contendría etiquetas específicas de la radio. Por lo tanto, un cliente que desee verificar si una fuente determinada está disponible en un dispositivo debe:

    1. Descubra el servicio de radio (llame a resolveService para ACTION_PLAY_BROADCASTRADIO ).
    2. Cree MediaBrowser y luego conéctese a él.
    3. Determine la presencia de MediaItem con EXTRA_BCRADIO_FOLDER_TYPE extra.

    Nota: En la mayoría de los casos, el cliente debe escanear todos los árboles de MediaBrowser disponibles para detectar todas las fuentes disponibles para un dispositivo determinado.

    Nombres de bandas

    La lista de bandas está representada por un conjunto de directorios de nivel superior con una etiqueta de tipo de carpeta establecida en BCRADIO_FOLDER_TYPE_BAND . Los títulos de sus MediaItem son cadenas localizadas que representan nombres de bandas. En la mayoría de los casos será lo mismo que la traducción al inglés, pero el cliente no puede depender de esa suposición.

    Para proporcionar un mecanismo estable para buscar ciertas bandas, se agrega una etiqueta adicional para las carpetas de bandas, EXTRA_BCRADIO_BAND_NAME_EN . Este es un nombre no localizado de la banda y solo puede tomar uno de estos valores predefinidos:

    • AM
    • FM
    • DAB

    Si la banda no está en esta lista, la etiqueta de nombre de la banda no debe configurarse. Sin embargo, si la banda está en la lista, debe tener una etiqueta establecida. La radio HD no enumera bandas separadas ya que utiliza el mismo medio subyacente que AM/FM.

    Intenciones generales de juego

    Cada aplicación dedicada a reproducir una fuente dada (como radio o CD) debe manejar una intención de reproducción general para comenzar a reproducir contenido posiblemente desde un estado inactivo (por ejemplo, después del arranque). Depende de la aplicación cómo seleccionar el contenido para reproducir, pero generalmente es el programa de radio o la pista de CD reproducidos recientemente. Hay una intención separada definida para cada fuente de audio:

    • android.car.intent.action.PLAY_BROADCASTRADIO
    • android.car.intent.action.PLAY_AUDIOCD : CD-DA o CD-Text
    • android.car.intent.action.PLAY_DATADISC : disco de datos ópticos como CD/DVD, pero no CD-DA (puede ser un CD de modo mixto)
    • android.car.intent.action.PLAY_AUX : Sin especificar qué puerto AUX
    • android.car.intent.action.PLAY_BLUETOOTH
    • android.car.intent.action.PLAY_USB : sin especificar qué dispositivo USB
    • android.car.intent.action.PLAY_LOCAL : almacenamiento de medios locales (flash incorporado)

    Se eligieron las intenciones para usarlas en el comando de reproducción general, porque resuelven dos problemas a la vez: el comando de reproducción general en sí mismo y el descubrimiento del servicio. El beneficio adicional de tener tal intención sería la posibilidad de ejecutar una acción tan simple sin abrir la sesión de MediaBrowser.

    El descubrimiento de servicios es en realidad el problema más importante resuelto con estos intentos. El procedimiento para el descubrimiento de servicios es fácil e inequívoco de esta manera (ver Descubrimiento y conexión de servicios ).

    Para facilitar algunas implementaciones de clientes, existe una forma alternativa de emitir dicho comando de reproducción (que también debe implementar la aplicación de radio): emitir playFromMediaId con el rootId del nodo raíz (utilizado como mediaId). Si bien el nodo raíz no está destinado a ser reproducible, su rootId es una cadena arbitraria que se puede convertir en consumible como mediaId. Sin embargo, los clientes no están obligados a comprender este matiz.

    Selector de programa

    Si bien mediaId es suficiente para seleccionar un canal de MediaBrowserService , se vincula a una sesión y no es coherente entre los proveedores. En algunos casos, el cliente puede necesitar un puntero absoluto (como una frecuencia absoluta) para mantenerlo entre sesiones y dispositivos.

    En la era de las transmisiones de radio digital, una sola frecuencia no es suficiente para sintonizar una estación específica. Por lo tanto, utilice ProgramSelector para sintonizar un canal analógico o digital. ProgramSelector consta de dos partes:

    • Identificador principal. Un identificador único y estable para una estación de radio determinada que no cambia pero que puede no ser suficiente para sintonizar esa estación. Por ejemplo, el código PI RDS, que puede traducirse al distintivo de llamada en los EE. UU.
    • Identificadores secundarios. Identificadores adicionales útiles para sintonizar esa estación (por ejemplo, frecuencia), posiblemente incluyendo identificadores de otras tecnologías de radio. Por ejemplo, una estación DAB puede tener un respaldo de transmisión analógica.

    Para permitir que ProgramSelector encaje en la solución basada MediaBrowser o MediaSession , defina un esquema de URI para serializarlo. El esquema se define de la siguiente manera:

    broadcastradio://program/<primary ID type>/<primary ID>?
    <secondary ID type>=<secondary ID>&<secondary ID type>=<secondary ID>
    

    En este ejemplo, la parte de los identificadores secundarios (después del signo de interrogación ( ? )) es opcional y se puede eliminar para proporcionar un identificador estable para usar como mediaId . Por ejemplo:

    • 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

    La parte de autoridad (también conocida como host) del program proporciona cierto espacio para la extensión del esquema en el futuro. Las cadenas de tipo de identificador se especifican con precisión como sus nombres en la definición HAL 2.x de IdentifierType y el formato del valor es un número decimal o hexadecimal (con el prefijo 0x ).

    Todos los identificadores específicos del proveedor están representados por el prefijo VENDOR_ . Por ejemplo, VENDOR_0 para VENDOR_START y VENDOR_1 para VENDOR_START más 1. Dichos URI son específicos del hardware de radio en el que se generaron y no se pueden transferir entre dispositivos fabricados por diferentes OEM.

    Estos URI deben asignarse a cada elemento multimedia en las carpetas de radio de nivel superior. Además, MediaSession debe admitir tanto playFromMediaId como playFromUri . Sin embargo, el URI está diseñado principalmente para la extracción de metadatos de radio (como la frecuencia FM) y el almacenamiento persistente. No hay garantía de que el URI esté disponible para todos los elementos multimedia (por ejemplo, cuando el tipo de ID principal aún no es compatible con el marco). Por otro lado, Media ID siempre funciona. No se recomienda que los clientes utilicen URI para seleccionar elementos de la sesión actual de MediaBrowser. En su lugar, usa playFromMediaId . Dicho esto, no es opcional para la aplicación de servicio y los URI faltantes se reservan para casos bien justificados.

    El diseño inicial usaba dos puntos en lugar de la secuencia :// después de la parte del esquema. Sin embargo, el primero no es compatible con android.net.Uri para referencias URI jerárquicas absolutas.

    Otros tipos de fuentes

    Otras fuentes de audio se pueden manejar de manera similar. Por ejemplo, la entrada auxiliar y el reproductor de CD de audio.

    Una sola aplicación puede servir para múltiples tipos de fuentes. En tales casos, se recomienda que cree un MediaBrowserService independiente para cada tipo de fuente. Incluso en una configuración con múltiples fuentes servidas/MediaBrowserServices, se recomienda enfáticamente tener una sola MediaSession dentro de una sola aplicación.

    CD de audio

    Similar a Audio CD en el sentido de que la aplicación que sirve dichos discos expondría MediaBrowser con una sola entrada navegable (o más, si el sistema tiene un cambiador de CD), que a su vez contendría todas las pistas de un CD determinado. Si el sistema no conoce las pistas de cada CD (por ejemplo, cuando se insertan todos los discos en un cartucho a la vez y no los lee todos), MediaItem para todo el disco sería simplemente PLAYABLE , no BROWSABLE más PLAYABLE . Si no hay ningún disco en una ranura determinada, el elemento no se podrá PLAYABLE ni BROWSABLE (pero cada ranura debe estar siempre presente en el árbol).

    Estructura de árbol de CD de audio
    Figura 3. Estructura de árbol de CD de audio

    Estas entradas se marcarían de forma similar a como se marcan las carpetas de radiodifusión; contendrían campos adicionales adicionales definidos en la API MediaDescription:

    • EXTRA_CD_TRACK : para cada MediaItem en CD de audio, número de pista basado en 1.
    • EXTRA_CD_DISK : número de disco basado en 1.

    Para un sistema habilitado para CD-Text y un disco compatible, el MediaItem de nivel superior tendría un título del disco. De manera similar, los MediaItems para pistas tendrían un título de la pista.

    Entrada auxiliar

    La aplicación que sirve la entrada auxiliar expone un árbol de MediaBrowser con una sola entrada (o más, cuando existen varios puertos) que representa el puerto de entrada AUX. La MediaSession respectiva toma su mediaId y cambia a esa fuente después de recibir la solicitud playFromMediaId .

    Estructura de árbol auxiliar
    Figura 4. Estructura de árbol AUX

    Cada entrada AUX MediaItem tendría un campo adicional EXTRA_AUX_PORT_NAME establecido en el nombre no localizado del puerto sin la 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 for EXTRA_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 not PLAYABLE ) if nothing was connected to this port. If the hardware has no such capability, the MediaItem must always be set to PLAYABLE .

    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 or EXTRA_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
    • 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
    • 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
    • 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
    • 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
    • My music CD (browsable, playable) EXTRA_CD_DISK=3
      • All By Myself (playable) EXTRA_CD_TRACK=1
      • Reise, Reise (playable) EXTRA_CD_TRACK=2
    • 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"