diff --git a/demo/info_section.js b/demo/info_section.js
index 249da17406..f65ff5102a 100644
--- a/demo/info_section.js
+++ b/demo/info_section.js
@@ -107,17 +107,19 @@ shakaDemo.updateTrackOptions_ = function(list, tracks, language) {
variant: function(track) {
var trackInfo = '';
if (track.language) trackInfo += 'language: ' + track.language + ', ';
+ if (track.label) trackInfo += 'label: ' + track.label + ', ';
if (track.width && track.height)
trackInfo += track.width + 'x' + track.height + ', ';
trackInfo += track.bandwidth + ' bits/s';
return trackInfo;
- },
+ } ,
text: function(track) {
- return 'language: ' + track.language + ' ' +
- '(' + track.kind + ')';
+ var trackInfo = 'language: ' + track.language + ', ';
+ if (track.label) trackInfo += 'label: ' + track.label + ', ';
+ trackInfo += 'kind: ' + track.kind;
+ return trackInfo;
}
};
-
// Remove old tracks
while (list.firstChild) {
list.removeChild(list.firstChild);
diff --git a/externs/shaka/manifest.js b/externs/shaka/manifest.js
index e165893ea7..f9f58c74a1 100644
--- a/externs/shaka/manifest.js
+++ b/externs/shaka/manifest.js
@@ -297,6 +297,7 @@ shakaExtern.GetSegmentReferenceFunction;
* encrypted: boolean,
* keyId: ?string,
* language: string,
+ * label: ?string,
* type: string,
* primary: boolean,
* trickModeVideo: ?shakaExtern.Stream,
@@ -371,6 +372,8 @@ shakaExtern.GetSegmentReferenceFunction;
* The Stream's language, specified as a language code.
* Audio stream's language must be identical to the language of the containing
* Variant.
+ * @property {?string} label
+ * The Stream's label, unique text that should describe the audio/text track.
* @property {string} type
* Required.
* Content type (e.g. 'video', 'audio' or 'text')
diff --git a/externs/shaka/offline.js b/externs/shaka/offline.js
index 0b600a9776..16151ffd7a 100644
--- a/externs/shaka/offline.js
+++ b/externs/shaka/offline.js
@@ -148,6 +148,7 @@ shakaExtern.PeriodDB;
* frameRate: (number|undefined),
* kind: (string|undefined),
* language: string,
+ * label: ?string,
* width: ?number,
* height: ?number,
* initSegmentUri: ?string,
@@ -175,6 +176,8 @@ shakaExtern.PeriodDB;
* The kind of text stream; undefined for audio/video.
* @property {string} language
* The language of the stream; '' for video.
+ * @property {?string} label
+ * The label of the stream; '' for video.
* @property {?number} width
* The width of the stream; null for audio/text.
* @property {?number} height
diff --git a/externs/shaka/player.js b/externs/shaka/player.js
index df0a3597f7..73bc9abcc1 100644
--- a/externs/shaka/player.js
+++ b/externs/shaka/player.js
@@ -130,6 +130,7 @@ shakaExtern.Stats;
* bandwidth: number,
*
* language: string,
+ * label: ?string,
* kind: ?string,
* width: ?number,
* height: ?number,
@@ -161,6 +162,8 @@ shakaExtern.Stats;
* @property {string} language
* The language of the track, or 'und' if not given. This is the exact
* value provided in the manifest; it may need to be normalized.
+ * @property {?string} label
+ * The track label, unique text that should describe the track.
* @property {?string} kind
* (only for text tracks) The kind of text track, either 'caption' or
* 'subtitle'.
diff --git a/lib/dash/dash_parser.js b/lib/dash/dash_parser.js
index ec494c552d..c881808e6f 100644
--- a/lib/dash/dash_parser.js
+++ b/lib/dash/dash_parser.js
@@ -957,11 +957,14 @@ shaka.dash.DashParser.prototype.parseAdaptationSet_ = function(context, elem) {
var language =
shaka.util.LanguageUtils.normalize(elem.getAttribute('lang') || 'und');
+ // non-standard attribute(yet) supported by Kaltura
+ var label = elem.getAttribute('label');
+
// Parse Representations into Streams.
var representations = XmlUtils.findChildren(elem, 'Representation');
var streams = representations
.map(this.parseRepresentation_.bind(
- this, context, contentProtection, kind, language, main))
+ this, context, contentProtection, kind, language, label, main))
.filter(function(s) { return !!s; });
if (streams.length == 0) {
@@ -1018,6 +1021,7 @@ shaka.dash.DashParser.prototype.parseAdaptationSet_ = function(context, elem) {
* @param {shaka.dash.ContentProtection.Context} contentProtection
* @param {(string|undefined)} kind
* @param {string} language
+ * @param {string} label
* @param {boolean} isPrimary
* @param {!Element} node
* @return {?shakaExtern.Stream} The Stream, or null when there is a
@@ -1026,7 +1030,7 @@ shaka.dash.DashParser.prototype.parseAdaptationSet_ = function(context, elem) {
* @private
*/
shaka.dash.DashParser.prototype.parseRepresentation_ = function(
- context, contentProtection, kind, language, isPrimary, node) {
+ context, contentProtection, kind, language, label, isPrimary, node) {
var XmlUtils = shaka.util.XmlUtils;
var ContentType = shaka.util.ManifestParserUtils.ContentType;
@@ -1105,6 +1109,7 @@ shaka.dash.DashParser.prototype.parseRepresentation_ = function(
encrypted: contentProtection.drmInfos.length > 0,
keyId: keyId,
language: language,
+ label: label,
type: context.adaptationSet.contentType,
primary: isPrimary,
trickModeVideo: null,
diff --git a/lib/hls/hls_parser.js b/lib/hls/hls_parser.js
index 044636c7f7..0b99342c2a 100644
--- a/lib/hls/hls_parser.js
+++ b/lib/hls/hls_parser.js
@@ -500,6 +500,9 @@ shaka.hls.HlsParser.prototype.createStreamInfoFromMediaTag_ =
var LanguageUtils = shaka.util.LanguageUtils;
var language = LanguageUtils.normalize(/** @type {string} */(
tag.getAttributeValue('LANGUAGE', 'und')));
+ var labelValue = tag.getAttributeValue('NAME');
+ var label = labelValue ? labelValue.toString() : null;
+
var defaultAttr = tag.getAttribute('DEFAULT');
var autoselectAttr = tag.getAttribute('AUTOSELECT');
@@ -511,7 +514,7 @@ shaka.hls.HlsParser.prototype.createStreamInfoFromMediaTag_ =
var uri = HlsParser.getRequiredAttributeValue_(tag, 'URI');
var primary = !!defaultAttr || !!autoselectAttr;
return this.createStreamInfo_(uri, allCodecs, type, timeOffset, language,
- primary).then(function(streamInfo) {
+ primary, label).then(function(streamInfo) {
this.mediaTagsToStreamInfosMap_[tag.id] = streamInfo;
return streamInfo;
}.bind(this));
@@ -535,7 +538,8 @@ shaka.hls.HlsParser.prototype.createStreamInfoFromVariantTag_ =
var uri = shaka.hls.HlsParser.getRequiredAttributeValue_(tag, 'URI');
return this.createStreamInfo_(uri, allCodecs, type, timeOffset,
- /* language */ 'und', /* primary */ false);
+ /* language */ 'und', /* primary */ false,
+ null);
};
@@ -546,12 +550,13 @@ shaka.hls.HlsParser.prototype.createStreamInfoFromVariantTag_ =
* @param {?number} timeOffset
* @param {!string} language
* @param {boolean} primary
+ * @param {?string} label
* @return {!Promise.}
* @throws shaka.util.Error
* @private
*/
shaka.hls.HlsParser.prototype.createStreamInfo_ =
- function(uri, allCodecs, type, timeOffset, language, primary) {
+ function(uri, allCodecs, type, timeOffset, language, primary, label) {
var Utils = shaka.hls.Utils;
var ContentType = shaka.util.ManifestParserUtils.ContentType;
var HlsParser = shaka.hls.HlsParser;
@@ -663,6 +668,7 @@ shaka.hls.HlsParser.prototype.createStreamInfo_ =
encrypted: encrypted,
keyId: keyId,
language: language,
+ label: label || null,
type: type,
primary: primary,
// TODO: trick mode
diff --git a/lib/offline/offline_utils.js b/lib/offline/offline_utils.js
index 45e4a5b7d3..faa6b2404c 100644
--- a/lib/offline/offline_utils.js
+++ b/lib/offline/offline_utils.js
@@ -251,6 +251,7 @@ shaka.offline.OfflineUtils.createStream_ = function(streamDb) {
encrypted: streamDb.encrypted,
keyId: streamDb.keyId,
language: streamDb.language,
+ label: streamDb.label || null,
type: streamDb.contentType,
primary: streamDb.primary,
trickModeVideo: null,
diff --git a/lib/offline/storage.js b/lib/offline/storage.js
index 0e268de0da..33a86f6a2d 100644
--- a/lib/offline/storage.js
+++ b/lib/offline/storage.js
@@ -883,6 +883,7 @@ shaka.offline.Storage.prototype.createStream_ = function(
frameRate: stream.frameRate,
kind: stream.kind,
language: stream.language,
+ label: stream.label,
width: stream.width || null,
height: stream.height || null,
initSegmentUri: initUri,
diff --git a/lib/player.js b/lib/player.js
index a84d29aaec..076a7d3914 100644
--- a/lib/player.js
+++ b/lib/player.js
@@ -1411,11 +1411,12 @@ shaka.Player.prototype.getStats = function() {
* @param {string} kind
* @param {string} mime
* @param {string=} opt_codec
+ * @param {string=} opt_label
* @return {!Promise.}
* @export
*/
shaka.Player.prototype.addTextTrack = function(
- uri, language, kind, mime, opt_codec) {
+ uri, language, kind, mime, opt_codec, opt_label) {
if (!this.streamingEngine_) {
shaka.log.error(
'Must call load() and wait for it to resolve before adding text ' +
@@ -1466,6 +1467,7 @@ shaka.Player.prototype.addTextTrack = function(
encrypted: false,
keyId: null,
language: language,
+ label: opt_label || null,
type: ContentType.TEXT,
primary: false,
trickModeVideo: null,
@@ -1494,6 +1496,7 @@ shaka.Player.prototype.addTextTrack = function(
type: ContentType.TEXT,
bandwidth: 0,
language: language,
+ label: opt_label || null,
kind: kind,
width: null,
height: null
diff --git a/lib/util/stream_utils.js b/lib/util/stream_utils.js
index 3fc7f47332..cb470d60a7 100644
--- a/lib/util/stream_utils.js
+++ b/lib/util/stream_utils.js
@@ -219,6 +219,7 @@ shaka.util.StreamUtils.getVariantTracks =
function(period, activeAudioId, activeVideoId) {
var StreamUtils = shaka.util.StreamUtils;
var variants = StreamUtils.getPlayableVariants(period.variants);
+ var label = null;
var tracks = variants.map(function(variant) {
var isActive;
if (variant.video && variant.audio) {
@@ -233,6 +234,7 @@ shaka.util.StreamUtils.getVariantTracks =
if (variant.audio) {
if (codecs != '') codecs += ', ';
codecs += variant.audio.codecs;
+ label = variant.audio.label;
}
var audioCodec = variant.audio ? variant.audio.codecs : null;
@@ -251,6 +253,7 @@ shaka.util.StreamUtils.getVariantTracks =
type: 'variant',
bandwidth: variant.bandwidth,
language: variant.language,
+ label: label,
kind: kind || null,
width: variant.video ? variant.video.width : null,
height: variant.video ? variant.video.height : null,
diff --git a/test/dash/dash_parser_manifest_unit.js b/test/dash/dash_parser_manifest_unit.js
index 70c85ce2be..5b9b833ac0 100644
--- a/test/dash/dash_parser_manifest_unit.js
+++ b/test/dash/dash_parser_manifest_unit.js
@@ -119,7 +119,7 @@ describe('DashParser Manifest', function() {
' ',
' ',
' ',
+ ' lang="es" label="spanish">',
' ',
' ',
' ',
@@ -176,6 +176,7 @@ describe('DashParser Manifest', function() {
.primary()
.addTextStream(jasmine.any(Number))
.language('es')
+ .label('spanish')
.primary()
.anySegmentFunctions()
.anyInitSegment()
diff --git a/test/offline/offline_utils_unit.js b/test/offline/offline_utils_unit.js
index 85e3048a0b..bd411bd03a 100644
--- a/test/offline/offline_utils_unit.js
+++ b/test/offline/offline_utils_unit.js
@@ -46,7 +46,6 @@ describe('OfflineUtils', function() {
startTime: 60,
streams: [createVideoStreamDb(1), createAudioStreamDb(2)]
};
-
var period = OfflineUtils.reconstructPeriod(periodDb, drmInfos, timeline);
expect(period).toBeTruthy();
expect(period.startTime).toBe(periodDb.startTime);
@@ -152,6 +151,7 @@ describe('OfflineUtils', function() {
frameRate: 22,
kind: undefined,
language: '',
+ label: null,
width: 250,
height: 100,
initSegmentUri: null,
@@ -183,6 +183,7 @@ describe('OfflineUtils', function() {
frameRate: undefined,
kind: undefined,
language: 'en',
+ label: null,
width: null,
height: null,
initSegmentUri: 'offline:1/' + id + '/0',
@@ -213,6 +214,7 @@ describe('OfflineUtils', function() {
frameRate: undefined,
kind: undefined,
language: 'en',
+ label: null,
width: null,
height: null,
initSegmentUri: 'offline:1/' + id + '/0',
@@ -255,6 +257,7 @@ describe('OfflineUtils', function() {
encrypted: streamDb.encrypted,
keyId: streamDb.keyId,
language: streamDb.language,
+ label: streamDb.label,
type: streamDb.contentType,
primary: streamDb.primary,
trickModeVideo: null,
diff --git a/test/offline/storage_unit.js b/test/offline/storage_unit.js
index 404afd3b83..be13b09b16 100644
--- a/test/offline/storage_unit.js
+++ b/test/offline/storage_unit.js
@@ -133,6 +133,7 @@ describe('Storage', function() {
type: 'variant',
bandwidth: 0,
language: 'en',
+ label: null,
kind: null,
width: 1920,
height: 1080,
diff --git a/test/player_unit.js b/test/player_unit.js
index 3351931c40..4119fa1d33 100644
--- a/test/player_unit.js
+++ b/test/player_unit.js
@@ -784,6 +784,7 @@ describe('Player', function() {
type: 'variant',
bandwidth: 200,
language: 'en',
+ label: null,
kind: null,
width: 100,
height: 200,
@@ -800,6 +801,7 @@ describe('Player', function() {
type: 'variant',
bandwidth: 300,
language: 'en',
+ label: null,
kind: null,
width: 200,
height: 400,
@@ -816,6 +818,7 @@ describe('Player', function() {
type: 'variant',
bandwidth: 200,
language: 'en',
+ label: null,
kind: null,
width: 100,
height: 200,
@@ -832,6 +835,7 @@ describe('Player', function() {
type: 'variant',
bandwidth: 300,
language: 'en',
+ label: null,
kind: null,
width: 200,
height: 400,
@@ -848,6 +852,7 @@ describe('Player', function() {
type: 'variant',
bandwidth: 300,
language: 'es',
+ label: null,
kind: null,
width: 200,
height: 400,
diff --git a/test/test/util/manifest_generator.js b/test/test/util/manifest_generator.js
index 97a15372fa..9dd7ab2d5b 100644
--- a/test/test/util/manifest_generator.js
+++ b/test/test/util/manifest_generator.js
@@ -162,6 +162,18 @@ shaka.test.ManifestGenerator.prototype.language = function(language) {
};
+/**
+ * Sets the label of the language of the most recent variant or text stream.
+ *
+ * @param {string} label
+ * @return {!shaka.test.ManifestGenerator}
+ */
+shaka.test.ManifestGenerator.prototype.label = function(label) {
+ this.currentStream_().label = label;
+ return this;
+};
+
+
/**
* Sets that the most recent variant or text stream is primary.
*
@@ -456,6 +468,7 @@ shaka.test.ManifestGenerator.prototype.createStream_ =
encrypted: false,
keyId: null,
language: language,
+ label: null,
type: type,
primary: false,
trickModeVideo: null,