Cómo usar pistas multimedia

MediaTrack representa una pista multimedia, que puede ser una transmisión de audio o video, o texto (como subtítulos). Tu app puede agrupar, diseñar y activar pistas multimedia.

Cómo configurar un segmento

Puedes configurar un segmento y asignarle un ID único. Con el siguiente código, se crea una pista de texto en inglés, una en francés y una en francés, cada una con su propio ID:

Kotlin
val englishSubtitle = MediaTrack.Builder(1 /* ID */, MediaTrack.TYPE_TEXT)
    .setName("English Subtitle")
    .setSubtype(MediaTrack.SUBTYPE_SUBTITLES)
    .setContentId("https://some-url/caption_en.vtt")
    /* language is required for subtitle type but optional otherwise */
    .setLanguage("en-US")
    .build()

val frenchSubtitle = MediaTrack.Builder(2, MediaTrack.TYPE_TEXT)
    .setName("French Subtitle")
    .setSubtype(MediaTrack.SUBTYPE_SUBTITLES)
    .setContentId("https://some-url/caption_fr.vtt")
    .setLanguage("fr")
    .build()

val frenchAudio = MediaTrack.Builder(3, MediaTrack.TYPE_AUDIO)
    .setName("French Audio")
    .setContentId("trk0001")
    .setLanguage("fr")
    .build()
Java
MediaTrack englishSubtitle = new MediaTrack.Builder(1 /* ID */,
MediaTrack.TYPE_TEXT)
  .setName("English Subtitle")
  .setSubtype(MediaTrack.SUBTYPE_SUBTITLES)
  .setContentId("https://some-url/caption_en.vtt")
  /* language is required for subtitle type but optional otherwise */
  .setLanguage("en-US")
  .build();

MediaTrack frenchSubtitle = new MediaTrack.Builder(2, MediaTrack.TYPE_TEXT)
  .setName("French Subtitle")
  .setSubtype(MediaTrack.SUBTYPE_SUBTITLES)
  .setContentId("https://some-url/caption_fr.vtt")
  .setLanguage("fr")
  .build();

MediaTrack frenchAudio = new MediaTrack.Builder(3, MediaTrack.TYPE_AUDIO)
  .setName("French Audio")
  .setContentId("trk0001")
  .setLanguage("fr")
  .build();

Segmentos del grupo

Puedes agrupar varias pistas en un elemento multimedia, que se representa con MediaInfo. Una instancia de MediaInfo toma un array de pistas y agrega otra información sobre el elemento multimedia. En función del ejemplo, tu app puede agregar esas tres pistas multimedia a un elemento multimedia pasando una lista de esas tres pistas a MediaInfo.Builder.setMediaTracks(List). Tu app necesita asociar pistas en un MediaInfo de esta manera antes de cargar el contenido multimedia en la app receptora.

Kotlin
val tracks: MutableList<MediaTrack> = ArrayList<MediaTrack>()
tracks.add(englishSubtitle)
tracks.add(frenchSubtitle)
tracks.add(frenchAudio)
val mediaInfo = MediaInfo.Builder(url)
    .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
    .setContentType(getContentType())
    .setMetadata(getMetadata())
    .setMediaTracks(tracks)
    .build()
Java
List tracks = new ArrayList();
tracks.add(englishSubtitle);
tracks.add(frenchSubtitle);
tracks.add(frenchAudio);
MediaInfo mediaInfo = MediaInfo.Builder(url)
  .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
  .setContentType(getContentType())
  .setMetadata(getMetadata())
  .setMediaTracks(tracks)
  .build();

Quitar segmentos

Para quitar todas las pistas del contenido multimedia actual (como desactivar los tres subtítulos en el ejemplo), llama a MediaInfo.Builder.setMediaTracks(List) y pasa una lista vacía de IDs.

Actualizar segmentos

Tu app puede activar una o más pistas asociadas con el elemento multimedia (después de cargar el contenido multimedia). Para ello, llama a RemoteMediaClient.setActiveMediaTracks(long[]) y pasa los IDs de las pistas que se activarán. En este ejemplo, se activa el subtítulo y el audio en francés:

Kotlin
// the ID for the French subtitle is '2' and for the French audio '3'
remoteMediaClient.setActiveMediaTracks(longArrayOf(2, 3))
    .setResultCallback(ResultCallback {
            mediaChannelResult: RemoteMediaClient.MediaChannelResult ->
                if (!mediaChannelResult.status.isSuccess) {
                    Log.e(TAG, "Failed with status code:" +
                            mediaChannelResult.status.statusCode
                    )
                }
    })
Java
// the ID for the French subtitle is '2' and for the French audio '3'
remoteMediaClient.setActiveMediaTracks(new long[]{2, 3})
    .setResultCallback(mediaChannelResult -> {
        if (!mediaChannelResult.getStatus().isSuccess()) {
            Log.e(TAG, "Failed with status code:" +
                    mediaChannelResult.getStatus().getStatusCode());
        }
    });

Aplica diseño a pistas de texto

TextTrackStyle encapsula la información de estilo de una pista de texto. Después de crear o actualizar un TextTrackStyle existente, puedes aplicar ese estilo al elemento multimedia que se está reproduciendo actualmente llamando a RemoteMediaClient.setTextTrackStyle de la siguiente manera:

Kotlin
// the ID for the French subtitle is '2' and for the French audio '3'
remoteMediaClient.setTextTrackStyle(style)
    .setResultCallback(ResultCallback {
            mediaChannelResult: RemoteMediaClient.MediaChannelResult ->
                if (!mediaChannelResult.status.isSuccess) {
                    Log.e(TAG, "Failed to set the style, status code: " +
                            mediaChannelResult.status.statusCode
                    )
                }
    })
Java
remoteMediaClient.setTextTrackStyle(style)
    .setResultCallback(mediaChannelResult -> {
        if (!mediaChannelResult.getStatus().isSuccess()) {
            Log.e(TAG, "Failed to set the style, status code: " +
                    mediaChannelResult.getStatus().getStatusCode());
        }
    });

Tu app debe permitir que los usuarios actualicen el estilo de los segmentos de texto, ya sea mediante la configuración proporcionada por el sistema o la propia app. En Android KitKat y versiones posteriores, puedes usar la configuración de subtítulos para todo el sistema que proporciona el framework:

Kotlin
val textTrackStyle = TextTrackStyle.fromSystemSettings(context)
Java
TextTrackStyle textTrackStyle = TextTrackStyle.fromSystemSettings(context);

En el caso de las versiones anteriores a KitKat, la llamada anterior mostrará un objeto cuyos campos no estén definidos, por lo que deberás propagar esos campos en la app en función de las selecciones de los usuarios y algunos valores predeterminados. Puedes aplicar ajustes de estilo a los siguientes elementos de estilo de seguimiento de texto:

  • Color y opacidad del primer plano (texto)
  • Color de fondo y opacidad
  • Tipo de borde
  • Color de borde
  • Escala de la fuente
  • Familia de fuentes
  • Estilo de fuente

Por ejemplo, configura el color de texto en rojo (FF) con un 50% de opacidad (80) de la siguiente manera:

Kotlin
textTrackStyle.foregroundColor = Color.parseColor("#80FF0000")
Java
textTrackStyle.setForegroundColor(Color.parseColor("#80FF0000"));

En KitKat y versiones posteriores, debes registrar la app para recibir una notificación cuando se actualice la configuración de subtítulos en todo el sistema. Para ello, debes implementar CaptioningManager.CaptioningChangeListener en tu app y registrar este objeto de escucha llamando al siguiente comando:

Kotlin
CaptioningManager.addCaptioningChangeListener(yourChangeListener)
Java
CaptioningManager.addCaptioningChangeListener(yourChangeListener);

Cuando tu app recibe una devolución de llamada en la que se indica que se modificó la configuración de los subtítulos, deberás extraer la nueva configuración y actualizar el estilo de la leyenda de texto para el contenido multimedia que se está reproduciendo en ese momento llamando a RemoteMediaClient.setTextTrackStyle y pasando el estilo nuevo.

Recibir actualizaciones de estado

Cuando varios remitentes están conectados al mismo receptor, es importante que cada uno esté al tanto de los cambios en el receptor, incluso si esos cambios se iniciaron desde otros remitentes.

Para ello, tu app debe registrar un RemoteMediaClient.Listener y un RemoteMediaClient.ProgressListener.

Si cambia el TextTrackStyle del contenido multimedia actual, todos los remitentes conectados recibirán una notificación a través de los dos objetos de escucha registrados antes. En este caso, el SDK del receptor no verifica si el diseño nuevo es diferente del anterior y notifica a todos los remitentes conectados de todos modos. Sin embargo, si cambia el estado de los segmentos activos, solo se notificará a los RemoteMediaClient.ProgressListener de los remitentes conectados.

Cumple con los requisitos de CORS

Para la transmisión de contenido multimedia adaptable, Google Cast requiere la presencia de encabezados CORS, pero incluso las transmisiones de contenido multimedia en MP4 simples lo requieren si incluyen pistas. Si quieres habilitar pistas para cualquier contenido multimedia, debes habilitar CORS para las transmisiones de pistas y de medios. Por lo tanto, si no tienes encabezados CORS disponibles para tu contenido multimedia mp4 simple en tu servidor y luego agregas una pista de subtítulos simple, no podrás transmitir tu contenido multimedia a menos que actualices el servidor para que incluya el encabezado CORS adecuado. Además, debes permitir al menos los siguientes encabezados: Content-Type, Accept-Encoding y Range. Ten en cuenta que los últimos dos encabezados son encabezados adicionales que quizás no hayas necesitado antes.