# Tracks

## Audio tracks

For audio track selection, the Web Receiver SDK provides a
[`AudioTracksManager`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.AudioTracksManager)
class that simplifies and streamlines track selection, giving you more control
and better access to properties, such as name, URL, and language. This class is
best used in the event handler for the
[`cast.framework.events.EventType.PLAYER_LOAD_COMPLETE`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.events#.EventType)
event.

The API provides various ways to query and select the active audio tracks. Here
is an example of how to select a track to be active by specifying its ID:

    const context = cast.framework.CastReceiverContext.getInstance();
    const playerManager = context.getPlayerManager();

    playerManager.addEventListener(
      cast.framework.events.EventType.PLAYER_LOAD_COMPLETE, () => {
        const audioTracksManager = playerManager.getAudioTracksManager();

        // Get all audio tracks
        const tracks = audioTracksManager.getTracks();

        // Choose the first audio track to be active by specifying its ID
        audioTracksManager.setActiveById(tracks[0].trackId);
      });
    context.start();

The `AudioTracksManager` class also provides a method
[`getActiveTrack()`](https://developers.google.com/cast/docs/reference/web_receiver/cast.framework.AudioTracksManager#getActiveTrack).

Here is an example of how to select the first audio track for a specified
language, in this case English:

    const context = cast.framework.CastReceiverContext.getInstance();
    const playerManager = context.getPlayerManager();

    playerManager.addEventListener(
      cast.framework.events.EventType.PLAYER_LOAD_COMPLETE, () => {
        const audioTracksManager = playerManager.getAudioTracksManager();

        // Set the first matching language audio track to be active
        audioTracksManager.setActiveByLanguage('en');
      });
    context.start();

The `AudioTracksManager` class also provides a method
[`getTracksByLanguage(language)`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.AudioTracksManager#getTracksByLanguage)
that returns all tracks for the specified language.

The audio language code is retrieved from the media manifest and should follow
RFC 5646. Language codes can be presented in 2-character nomenclature (such as
"es", "en" or "de"), or 4 character nomenclature (such as "en-us", "es-es" or
"fr-ca").

If the media manifest follows a different language code standard, the Web
Receiver app needs to convert it into an RFC 5646 conforming language code. Web
Receiver SDK provides an interceptor `EDIT_AUDIO_TRACKS` to perform
modifications:

    const context = cast.framework.CastReceiverContext.getInstance();
    const playerManager = context.getPlayerManager();
    // Intercept the EDIT_AUDIO_TRACKS request
    playerManager.setMessageInterceptor(cast.framework.messages.MessageType.EDIT_AUDIO_TRACKS, request => {
      // write logic to convert language codes here
    });
    context.start();

When playing through ad breaks, any audio track selection, such as language,
made before a break will persist after the break for the same content, even if
the ads are in a different language.

## Closed captions (subtitles)

For closed caption track selection, the Web Receiver SDK provides the
[`TextTracksManager`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.TextTracksManager)
class that simplifies and streamlines track selection, giving you more control
and better access to properties, such as name, URL and language.

The `TextTracksManager` class is best used in the event handler for the
[`cast.framework.events.EventType.PLAYER_LOAD_COMPLETE`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.events#.EventType)
event.

Closed captions selection in the Web Receiver SDK is simplified and streamlined
with other parts of the SDK.

The API supports controlling WebVTT, TTML and CEA-608.

The `TextTracksManager` class provides various ways to query and select a closed
caption track to be active. Here is an example of how to select the first track
to be active by specifying its ID:

> [!NOTE]
> **Note:** Although [`setActiveByIds(ids)`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.TextTracksManager#setActiveByIds) takes an array of ID numbers, for now the Web Receiver SDK supports only one active text track at a time.

    const context = cast.framework.CastReceiverContext.getInstance();
    const playerManager = context.getPlayerManager();

    playerManager.addEventListener(
      cast.framework.events.EventType.PLAYER_LOAD_COMPLETE, () => {
        const textTracksManager = playerManager.getTextTracksManager();

        // Get all text tracks
        const tracks = textTracksManager.getTracks();

        // Choose the first text track to be active by its ID
        textTracksManager.setActiveByIds([tracks[0].trackId]);
      });
    context.start();

The `TextTracksManager` class also provides a method
[`getActiveTracks()`](https://developers.google.com/cast/docs/reference/web_receiver/cast.framework.TextTracksManager#getActiveTracks).

Here is an example of how to select the first text track for a specific
language:

    const context = cast.framework.CastReceiverContext.getInstance();
    const playerManager = context.getPlayerManager();

    playerManager.addEventListener(
      cast.framework.events.EventType.PLAYER_LOAD_COMPLETE, () => {
        const textTracksManager = playerManager.getTextTracksManager();

        // Set the first matching language text track to be active
        textTracksManager.setActiveByLanguage('en');
      });
    context.start();

The `TextTracksManager` class also provides a method
[`getTracksByLanguage(language)`](https://developers.google.com/cast/docs/reference/caf_receiver/cast.framework.TextTracksManager#getTracksByLanguage)
that returns all tracks for the specified language.

The text language code is retrieved from the media manifest and should follow
RFC 5646. Language codes can be presented in 2-character nomenclature (such as
"es", "en" or "de"), or 4-character nomenclature (such as "en-us", "es-es" or
"fr-ca").

If the media manifest follows a different language code standard, the Web
Receiver app needs to convert any incoming requests to that standard. These
requests, such as voice commands, use RFC 5646 language codes. The Web Receiver
SDK provides an interceptor `EDIT_TRACKS_INFO` to translate the requests to your
manifest's standard:

    const context = cast.framework.CastReceiverContext.getInstance();
    const playerManager = context.getPlayerManager();
    // intercept the EDIT_TRACKS_INFO request
    playerManager.setMessageInterceptor(cast.framework.messages.MessageType.EDIT_TRACKS_INFO, request => {
      // write logic to convert language codes here
    });
    context.start();

The API allows a developer to dynamically add new closed caption tracks, in this
case for different languages and out-of-band tracks, and then select a track to
be the new active track:

    const context = cast.framework.CastReceiverContext.getInstance();
    const playerManager = context.getPlayerManager();

    playerManager.addEventListener(
      cast.framework.events.EventType.PLAYER_LOAD_COMPLETE, () => {

        // Create text tracks object
        const textTracksManager = playerManager.getTextTracksManager();

        // Create track 1 for English text
        const track1 = textTracksManager.createTrack();
        track1.trackContentType = 'text/vtt';
        track1.trackContentId = 'http://example.com/en.vtt';
        track1.language = 'en';

        // Create track 2 for Spanish text
        const track2 = textTracksManager.createTrack();
        const track2Id = track2.trackId;
        track2.trackContentType = 'text/vtt';
        track2.trackContentId = 'http://example.com/spa.vtt';
        track2.language = 'spa';

        // Add tracks
        textTracksManager.addTracks([track1, track2]);

        // Set the first matching language text track to be active
        textTracksManager.setActiveByLanguage('en');
      });
    context.start();

When playing through ad breaks, any text track selection, such as language, made
before a break will persist after the break for the same content, even if the
ads are in a different language.

## Forced captions

Forced captions or forced narrative is text overlay that is displayed so the
viewer can understand when alternative language is used or to clarify audio.
Unlike closed captions, a viewer does not need to enable forced captions as they
are auto-selected based on the viewer's audio preferences.

To add forced captions to your Cast application, you will need to include it as
part of your manifest. In your manifest, set the role of the track to be
`forced-subtitle`. When the Cask SDK picks up these tracks, it will identify
them as forced captions. There is no sender work needed as the Cast SDK will
separate out forced captions and closed captions. This means a viewer will not
be able to select a forced caption.

When closed captions are enabled, forced captions are disabled to prevent
overlap of captions. When closed captions are turned off and if forced captions
are provided in the manifest, then forced captions are displayed based on
the viewer's audio language preference.