# Use Media Tracks

[`MediaTrack`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/MediaTrack)
represents a media track, which can be an audio stream, a video stream, or text
(such as subtitles or closed caption). Your app can group, style and activate
media tracks.

> [!NOTE]
> **Note:** Currently, the [Styled Media Receiver](https://developers.google.com/cast/docs/receiver_apps#Styled) and [Default Media Receiver](https://developers.google.com/cast/docs/receiver_apps#default) allow you to use only the text tracks with the API. To work with the audio and video tracks, you must develop a Custom Receiver.

## Configure a track

You can configure a track and assign a unique ID to it. The following code
creates an English text track, a French text track and a French audio track,
each with their own ID:
Kotlin

```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

```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();
```

## Group tracks

You can group multiple tracks into a media item, which is represented by
[`MediaInfo`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/MediaInfo).
An instance of `MediaInfo`
takes an array of tracks and aggregates other information about the media item.
Building on the example, your app can add those three media tracks to a media
item by passing a list of those three tracks into
[`MediaInfo.Builder.setMediaTracks(List)`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/MediaInfo.Builder#setMediaTracks(java.util.List%3Ccom.google.android.gms.cast.MediaTrack%3E)).
Your app needs to associate tracks in a `MediaInfo` in this way before it loads
the media to the receiver.
Kotlin

```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

```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();
```

## Remove tracks

To remove all the tracks from the current media (such as turning off the three
subtitles in the example), call
[`MediaInfo.Builder.setMediaTracks(List)`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/MediaInfo.Builder#setMediaTracks(java.util.List%3Ccom.google.android.gms.cast.MediaTrack%3E))
and pass an empty list of IDs.

## Update tracks

Your app can activate one or more tracks that were associated with the media
item (after the media is loaded), by calling
[`RemoteMediaClient.setActiveMediaTracks(long[])`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/media/RemoteMediaClient#setActiveMediaTracks(long%5B%5D))
and passing the IDs of the tracks to be activated. This example activates the
French subtitle and French audio:
Kotlin

```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

```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());
        }
    });
```

## Style text tracks

[`TextTrackStyle`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/TextTrackStyle)
encapsulates the styling information of a text track. After creating or updating
an existing TextTrackStyle, you can apply that style to the currently playing
media item by calling
[`RemoteMediaClient.setTextTrackStyle`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/media/RemoteMediaClient#setTextTrackStyle(com.google.android.gms.cast.TextTrackStyle)),
like this:
Kotlin

```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

```java
remoteMediaClient.setTextTrackStyle(style)
    .setResultCallback(mediaChannelResult -> {
        if (!mediaChannelResult.getStatus().isSuccess()) {
            Log.e(TAG, "Failed to set the style, status code: " +
                    mediaChannelResult.getStatus().getStatusCode());
        }
    });
```

Your app should allow users to update the style for text tracks, either using
the settings provided by the system or by the app itself. **In Android KitKat
and later**, you can use the system-wide closed caption settings provided by the
framework:
Kotlin

```kotlin
val textTrackStyle = TextTrackStyle.fromSystemSettings(context)
```
Java

```java
TextTrackStyle textTrackStyle = TextTrackStyle.fromSystemSettings(context);
```

**For versions prior to KitKat**, the above call will return an object whose
fields are undefined, so you need to populate those fields in your app, based
on user selections and some default values. You can style the following text
track style elements:

- Foreground (text) color and opacity
- Background color and opacity
- Edge type
- Edge Color
- Font Scale
- Font Family
- Font Style

For example, set the text color to red (FF) with 50% opacity (80) as follows:
Kotlin

```kotlin
textTrackStyle.foregroundColor = Color.parseColor("#80FF0000")
```
Java

```java
textTrackStyle.setForegroundColor(Color.parseColor("#80FF0000"));
```

**In KitKat and later versions** , you should register your app to be notified
when system-wide closed caption settings are updated. To this end, you need to
implement
[`CaptioningManager.CaptioningChangeListener`](https://developer.android.com/reference/android/view/accessibility/CaptioningManager.CaptioningChangeListener.html)
in your app and register this listener by calling:
Kotlin

```kotlin
CaptioningManager.addCaptioningChangeListener(yourChangeListener)
```
Java

```java
CaptioningManager.addCaptioningChangeListener(yourChangeListener);
```

When your app receives a call back that the caption settings have changed, you
would then need to extract the new settings and update the style of the text
caption for the media that is currently playing by calling
[`RemoteMediaClient.setTextTrackStyle`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/media/RemoteMediaClient#setTextTrackStyle(com.google.android.gms.cast.TextTrackStyle))
and passing in the new style.

## Receive status updates

When multiple senders are connected to the same receiver, it is important for
each sender to be aware of the changes in the receiver even if those changes
were initiated from other senders.

> [!NOTE]
> **Note:** This is important for all apps, not only those that explicitly support multiple senders, because some Cast devices have control inputs (remotes, buttons) that behave as virtual senders, affecting the status on the receiver.

To this end, your app should register a
[`RemoteMediaClient.Listener`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/media/RemoteMediaClient.Listener)
and a
[`RemoteMediaClient.ProgressListener`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/framework/media/RemoteMediaClient.ProgressListener).

If the
[`TextTrackStyle`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/TextTrackStyle)
of the current media changes, then all of the connected senders will be notified
through both of the above registered listeners. In this case, the receiver SDK
does not verify whether the new style is different from the previous one and
notifies all of the connected senders regardless. If, however, the status of
active tracks changes, only the `RemoteMediaClient.ProgressListener` in
connected senders will be notified.

> [!NOTE]
> **Note:** The list of tracks associated with the currently loaded media cannot be changed. If needed, you have to update the tracks information on the [`MediaInfo`](https://developers.google.com/cast/docs/reference/android/com/google/android/gms/cast/MediaInfo) object and reload the media.

## Satisfy CORS requirements

For adaptive media streaming, Google Cast requires the presence of
[CORS](http://www.html5rocks.com/en/tutorials/cors) headers, but even simple mp4
media streams require CORS if they include Tracks. If you want to enable Tracks
for any media, you must enable CORS for both your track streams and your media
streams. So, if you do not have CORS headers available for your simple mp4 media
on your server, and you then add a simple subtitle track, you will not be able
to stream your media unless you update your server to include the appropriate
CORS header. In addition, you need to allow at least the following headers:
Content-Type, Accept-Encoding, and Range. Note that the last two headers are
additional headers that you may not have been needed previously.