Source: media-groups.js

import videojs from 'video.js';
import PlaylistLoader from './playlist-loader';

/**
 * Convert the properties of an HLS track into an audioTrackKind.
 *
 * @private
 */
const audioTrackKind_ = (properties) => {
  let kind = properties.default ? 'main' : 'alternative';

  if (properties.characteristics &&
      properties.characteristics.indexOf('public.accessibility.describes-video') >= 0) {
    kind = 'main-desc';
  }

  return kind;
};

const setupListeners = {
  /**
   * Setup event listeners for audio playlist loader
   */
  AUDIO: (playlistLoader, masterPlaylistController) => {
    if (!playlistLoader) {
      // no playlist loader means audio will be muxed with the video
      return;
    }

    const segmentLoader = masterPlaylistController.audioSegmentLoader_;
    const tech = masterPlaylistController.tech_;
    const options = masterPlaylistController.requestOptions_;

    playlistLoader.on('loadedmetadata', () => {
      const media = playlistLoader.media();

      segmentLoader.playlist(media, options);

      // if the video is already playing, or if this isn't a live video and preload
      // permits, start downloading segments
      if (!tech.paused() || (media.endList && tech.preload() !== 'none')) {
        segmentLoader.load();
      }
    });

    playlistLoader.on('loadedplaylist', () => {
      segmentLoader.playlist(playlistLoader.media(), options);
    });

    playlistLoader.on('error', () => {
      videojs.log.warn('Problem encountered loading the alternate audio track' +
                         '. Switching back to default.');
      segmentLoader.abort();
    });
  },
  /**
   * Setup event listeners for subtitle playlist loader
   */
  SUBTITLES: (playlistLoader, masterPlaylistController) => {
    const segmentLoader = masterPlaylistController.subtitleSegmentLoader_;
    const tech = masterPlaylistController.tech_;
    const options = masterPlaylistController.requestOptions_;

    playlistLoader.on('loadedmetadata', () => {
      const media = playlistLoader.media();

      segmentLoader.playlist(media, options);
      segmentLoader.track(masterPlaylistController.activeSubtitleTrack_());

      // if the video is already playing, or if this isn't a live video and preload
      // permits, start downloading segments
      if (!tech.paused() || (media.endList && tech.preload() !== 'none')) {
        segmentLoader.load();
      }
    });

    playlistLoader.on('loadedplaylist', () => {
      segmentLoader.playlist(playlistLoader.media(), options);
    });

    playlistLoader.on('error', () => {
      masterPlaylistController.handleSubtitleError_();
    });
  }
};

const initialize = {
  /**
   * Setup playlist loaders and tracks for audio groups
   */
  AUDIO: (masterGroups, groups, tracks, masterPlaylistController) => {
    // force a default if we have none or we are not
    // in html5 mode (the only mode to support more than one
    // audio track)
    if (!masterGroups.AUDIO ||
        Object.keys(masterGroups.AUDIO).length === 0 ||
        masterPlaylistController.mode_ !== 'html5') {
      masterGroups.AUDIO = { main: { default: { defualt: true } } };
    }

    for (let masterGroup in masterGroups.AUDIO) {
      if (!groups[masterGroup]) {
        groups[masterGroup] = [];
      }

      for (let label in masterGroups.AUDIO[masterGroup]) {
        let properties = masterGroups.AUDIO[masterGroup][label];
        let playlistLoader;

        if (properties.resolvedUri) {
          playlistLoader = new PlaylistLoader(properties.resolvedUri,
                                              masterPlaylistController.hls_,
                                              masterPlaylistController.withCredentials);
        } else {
          // no resolvedUri means the audio is muxed with the video when using this
          // audio track
          playlistLoader = null;
        }

        properties = videojs.mergeOptions({ id: label, playlistLoader }, properties);

        setupListeners.AUDIO(properties.playlistLoader, masterPlaylistController);

        groups[masterGroup].push(properties);

        if (typeof tracks[label] === 'undefined') {
          const track = new videojs.AudioTrack({
            id: label,
            kind: audioTrackKind_(properties),
            enabled: false,
            language: properties.language,
            default: properties.default,
            label
          });

          tracks[label] = track;
        }
      }
    }
  },
  /**
   * Setup playlist loaders and tracks for subtitle groups
   */
  SUBTITLES: (masterGroups, groups, tracks, masterPlaylistController) => {
    for (let masterGroup in masterGroups.SUBTITLES) {
      if (!groups[masterGroup]) {
        groups[masterGroup] = [];
      }

      for (let label in masterGroups.SUBTITLES[masterGroup]) {
        if (masterGroups.SUBTITLES[masterGroup][label].forced) {
          continue;
        }

        let properties = masterGroups.SUBTITLES[masterGroup][label];

        properties = videojs.mergeOptions({
          id: label,
          playlistLoader: new PlaylistLoader(properties.resolvedUri,
                                             masterPlaylistController.hls_,
                                             masterPlaylistController.withCredentials)
        }, properties);

        setupListeners.SUBTITLES(properties.playlistLoader, masterPlaylistController);

        groups[masterGroup].push(properties);

        if (typeof tracks[label] === 'undefined') {
          const track = masterPlaylistController.tech_.addRemoteTextTrack({
            id: label,
            kind: 'subtitles',
            enabled: false,
            language: properties.language,
            label
          }, false).track;

          tracks[label] = track;
        }
      }
    }
  },
  /**
   * Setup tracks for closed-caption groups
   */
  'CLOSED-CAPTIONS': (masterGroups, groups, tracks, masterPlaylistController) => {
    for (let masterGroup in masterGroups['CLOSED-CAPTIONS']) {
      if (!groups[masterGroup]) {
        groups[masterGroup] = [];
      }

      for (let label in masterGroups['CLOSED-CAPTIONS'][masterGroup]) {
        let properties = masterGroups['CLOSED-CAPTIONS'][masterGroup][label];

        // We only support CEA608 captions for now, so ignore anything that
        // doesn't use a CCx INSTREAM-ID
        if (properties.instreamId.match(/CC\d/)) {
          continue;
        }

        groups[masterGroup].push(videojs.mergeOptions({ id: label }, properties));

        if (typeof tracks[label] === 'undefined') {
          const track = masterPlaylistController.tech_.addRemoteTextTrack({
            id: properties.instreamId,
            kind: 'captions',
            enabled: false,
            language: properties.language,
            label
          }, false).track;

          tracks[label] = track;
        }
      }
    }
  }
};

const initializeMediaGroup = (
  type,
  master,
  mediaGroup,
  masterPlaylistController
) => {
  const masterGroups = master.mediaGroups || {};

  return initialize[type](masterGroups,
                          mediaGroup.groups,
                          mediaGroup.tracks,
                          masterPlaylistController);
};

export default initializeMediaGroup;