UNPKG

shaka-player

Version:
258 lines (221 loc) 5.84 kB
/*! @license * Shaka Player * Copyright 2016 Google LLC * SPDX-License-Identifier: Apache-2.0 */ goog.provide('shaka.hls.Attribute'); goog.provide('shaka.hls.Playlist'); goog.provide('shaka.hls.PlaylistType'); goog.provide('shaka.hls.Segment'); goog.provide('shaka.hls.Tag'); goog.require('goog.asserts'); goog.require('shaka.util.Error'); /** * HLS playlist class. */ shaka.hls.Playlist = class { /** * @param {!shaka.hls.PlaylistType} type * @param {!Array<shaka.hls.Tag>} tags * @param {!Array<shaka.hls.Segment>=} segments */ constructor(type, tags, segments) { /** @const {shaka.hls.PlaylistType} */ this.type = type; /** @const {!Array<!shaka.hls.Tag>} */ this.tags = tags; /** @const {Array<!shaka.hls.Segment>} */ this.segments = segments || null; } }; /** * @enum {number} */ shaka.hls.PlaylistType = { MASTER: 0, MEDIA: 1, }; /** * HLS tag class. */ shaka.hls.Tag = class { /** * @param {number} id * @param {string} name * @param {!Array<shaka.hls.Attribute>} attributes * @param {?string=} value */ constructor(id, name, attributes, value = null) { /** @const {number} */ this.id = id; /** @type {string} */ this.name = name; /** @const {!Array<shaka.hls.Attribute>} */ this.attributes = attributes; /** @const {?string} */ this.value = value; } /** * Create the string representation of the tag. * * For the DRM system - the full tag needs to be passed down to the CDM. * There are two ways of doing this (1) save the original tag or (2) recreate * the tag. * As in some cases (like in tests) the tag never existed in string form, it * is far easier to recreate the tag from the parsed form. * * @param {?Set<string>=} attributesToSkip * @return {string} * @override */ toString(attributesToSkip) { /** * @param {shaka.hls.Attribute} attr * @return {string} */ const attrToStr = (attr) => { const isNumericAttr = !isNaN(Number(attr.value)); const value = (isNumericAttr ? attr.value : '"' + attr.value + '"'); return attr.name + '=' + value; }; // A valid tag can only follow 1 of 4 patterns. // 1) <NAME>:<VALUE> // 2) <NAME>:<ATTRIBUTE LIST> // 3) <NAME> // 4) <NAME>:<VALUE>,<ATTRIBUTE_LIST> let tagStr = '#' + this.name; const appendages = this.attributes ? this.attributes.filter((attr) => { if (!attributesToSkip) { return true; } return !attributesToSkip.has(attr.name); }).map(attrToStr) : []; if (this.value) { appendages.unshift(this.value); } if (appendages.length > 0) { tagStr += ':' + appendages.join(','); } return tagStr; } /** * Create the string key of the tag. * * @param {boolean} keepAllAttributes * @return {string} */ getTagKey(keepAllAttributes) { if (keepAllAttributes) { return this.toString(); } const attributesToSkip = new Set() .add('AUDIO') .add('VIDEO') .add('SUBTITLES') .add('PATHWAY-ID') .add('GROUP-ID') .add('URI'); return this.toString(attributesToSkip); } /** * Adds an attribute to an HLS Tag. * * @param {!shaka.hls.Attribute} attribute */ addAttribute(attribute) { this.attributes.push(attribute); } /** * Gets the first attribute of the tag with a specified name. * * @param {string} name * @return {?shaka.hls.Attribute} attribute */ getAttribute(name) { const attributes = this.attributes.filter((attr) => { return attr.name == name; }); goog.asserts.assert(attributes.length < 2, 'A tag should not have multiple attributes ' + 'with the same name!'); if (attributes.length) { return attributes[0]; } else { return null; } } /** * Gets the value of the first attribute of the tag with a specified name. * If not found, returns an optional default value. * * @param {string} name * @param {string=} defaultValue * @return {?string} */ getAttributeValue(name, defaultValue) { const attribute = this.getAttribute(name); return attribute ? attribute.value : (defaultValue || null); } /** * Finds the attribute and returns its value. * Throws an error if attribute was not found. * * @param {string} name * @return {string} */ getRequiredAttrValue(name) { const attribute = this.getAttribute(name); if (!attribute) { throw new shaka.util.Error( shaka.util.Error.Severity.CRITICAL, shaka.util.Error.Category.MANIFEST, shaka.util.Error.Code.HLS_REQUIRED_ATTRIBUTE_MISSING, name); } return attribute.value; } /** * Set the name of the tag. Used only for Preload hinted MAP tag. * @param {string} name */ setName(name) { this.name = name; } }; /** * HLS segment class. */ shaka.hls.Segment = class { /** * Creates an HLS segment object. * * @param {string} verbatimSegmentUri verbatim segment URI. * @param {!Array<shaka.hls.Tag>} tags * @param {!Array<shaka.hls.Tag>=} partialSegments */ constructor(verbatimSegmentUri, tags, partialSegments=[]) { /** @const {!Array<shaka.hls.Tag>} */ this.tags = tags; /** @const {?string} */ this.verbatimSegmentUri = verbatimSegmentUri; /** @type {!Array<shaka.hls.Tag>} */ this.partialSegments = partialSegments; } }; /** * HLS Attribute class. */ shaka.hls.Attribute = class { /** * Creates an HLS attribute object. * * @param {string} name * @param {string} value */ constructor(name, value) { /** @const {string} */ this.name = name; /** @const {string} */ this.value = value; } };