shaka-player 4.3.7 → 4.3.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/.github/workflows/appspot.yaml +39 -0
  2. package/CHANGELOG.md +25 -0
  3. package/CONTRIBUTORS +1 -0
  4. package/demo/custom.js +1 -1
  5. package/dist/demo.compiled.debug.js +2 -2
  6. package/dist/demo.compiled.debug.map +2 -2
  7. package/dist/demo.compiled.js +2 -2
  8. package/dist/demo.compiled.map +2 -2
  9. package/dist/deps.js +1 -1
  10. package/dist/locales.js +31 -31
  11. package/dist/shaka-player.compiled.d.ts +22 -0
  12. package/dist/shaka-player.compiled.debug.d.ts +22 -0
  13. package/dist/shaka-player.compiled.debug.js +215 -213
  14. package/dist/shaka-player.compiled.debug.map +3 -3
  15. package/dist/shaka-player.compiled.js +789 -786
  16. package/dist/shaka-player.compiled.map +4 -4
  17. package/dist/shaka-player.ui.d.ts +22 -0
  18. package/dist/shaka-player.ui.debug.d.ts +22 -0
  19. package/dist/shaka-player.ui.debug.js +253 -252
  20. package/dist/shaka-player.ui.debug.map +3 -3
  21. package/dist/shaka-player.ui.js +823 -820
  22. package/dist/shaka-player.ui.map +4 -4
  23. package/docs/tutorials/drm-config.md +9 -6
  24. package/externs/ima.js +34 -0
  25. package/lib/abr/simple_abr_manager.js +1 -1
  26. package/lib/cea/mp4_cea_parser.js +24 -18
  27. package/lib/dash/dash_parser.js +18 -3
  28. package/lib/hls/hls_parser.js +23 -4
  29. package/lib/media/drm_engine.js +14 -8
  30. package/lib/media/gap_jumping_controller.js +24 -2
  31. package/lib/media/media_source_engine.js +5 -3
  32. package/lib/media/playhead.js +11 -0
  33. package/lib/media/region_observer.js +19 -1
  34. package/lib/media/streaming_engine.js +39 -19
  35. package/lib/media/video_wrapper.js +6 -1
  36. package/lib/player.js +12 -5
  37. package/lib/polyfill/abort_controller.js +7 -0
  38. package/lib/text/vtt_text_parser.js +2 -1
  39. package/lib/util/manifest_parser_utils.js +1 -1
  40. package/lib/util/stream_utils.js +1 -0
  41. package/package.json +2 -2
  42. package/test/cea/mp4_cea_parser_unit.js +28 -5
  43. package/test/dash/dash_parser_manifest_unit.js +120 -0
  44. package/test/hls/hls_parser_unit.js +144 -0
  45. package/test/media/region_observer_unit.js +2 -1
  46. package/test/media/streaming_engine_unit.js +26 -2
  47. package/test/test/assets/multiple-trun-init.mp4 +0 -0
  48. package/test/test/assets/multiple-trun-segment.mp4 +0 -0
  49. package/ui/resolution_selection.js +7 -1
package/lib/player.js CHANGED
@@ -99,7 +99,9 @@ goog.requireType('shaka.routing.Payload');
99
99
 
100
100
  /**
101
101
  * @event shaka.Player.EmsgEvent
102
- * @description Fired when a non-typical emsg is found in a segment.
102
+ * @description Fired when an emsg box is found in a segment.
103
+ * If the application calls preventDefault() on this event, further parsing
104
+ * will not happen, and no 'metadata' event will be raised for ID3 payloads.
103
105
  * @property {string} type
104
106
  * 'emsg'
105
107
  * @property {shaka.extern.EmsgInfo} detail
@@ -2191,7 +2193,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2191
2193
  }
2192
2194
 
2193
2195
  this.playhead_ = this.createPlayhead(has.startTime);
2194
- this.playheadObservers_ = this.createPlayheadObserversForMSE_();
2196
+ this.playheadObservers_ =
2197
+ this.createPlayheadObserversForMSE_(has.startTimeOfLoad);
2195
2198
 
2196
2199
  // We need to start the buffer management code near the end because it will
2197
2200
  // set the initial buffering state and that depends on other components
@@ -2918,17 +2921,21 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
2918
2921
  * Create the observers for MSE playback. These observers are responsible for
2919
2922
  * notifying the app and player of specific events during MSE playback.
2920
2923
  *
2924
+ * @param {number} startTimeOfLoad
2921
2925
  * @return {!shaka.media.PlayheadObserverManager}
2922
2926
  * @private
2923
2927
  */
2924
- createPlayheadObserversForMSE_() {
2928
+ createPlayheadObserversForMSE_(startTimeOfLoad) {
2925
2929
  goog.asserts.assert(this.manifest_, 'Must have manifest');
2926
2930
  goog.asserts.assert(this.regionTimeline_, 'Must have region timeline');
2927
2931
  goog.asserts.assert(this.video_, 'Must have video element');
2928
2932
 
2933
+ const startsPastZero = this.isLive() || startTimeOfLoad > 0;
2934
+
2929
2935
  // Create the region observer. This will allow us to notify the app when we
2930
2936
  // move in and out of timeline regions.
2931
- const regionObserver = new shaka.media.RegionObserver(this.regionTimeline_);
2937
+ const regionObserver = new shaka.media.RegionObserver(
2938
+ this.regionTimeline_, startsPastZero);
2932
2939
 
2933
2940
  regionObserver.addEventListener('enter', (event) => {
2934
2941
  /** @type {shaka.extern.TimelineRegionInfo} */
@@ -7009,7 +7016,7 @@ shaka.Player.TYPICAL_BUFFERING_THRESHOLD_ = 0.5;
7009
7016
  * @define {string} A version number taken from git at compile time.
7010
7017
  * @export
7011
7018
  */
7012
- shaka.Player.version = 'v4.3.7-uncompiled';
7019
+ shaka.Player.version = 'v4.3.8-uncompiled';
7013
7020
 
7014
7021
  // Initialize the deprecation system using the version string we just set
7015
7022
  // on the player.
@@ -86,6 +86,13 @@ class extends shaka.util.FakeEventTarget {
86
86
  return this.reason_;
87
87
  }
88
88
 
89
+ /** @return {void} */
90
+ throwIfAborted() {
91
+ if (this.aborted_) {
92
+ throw this.reason_;
93
+ }
94
+ }
95
+
89
96
  /**
90
97
  * @param {*} reason
91
98
  * @private
@@ -785,7 +785,8 @@ shaka.text.VttTextParser = class {
785
785
  } else if ((results = /^size:([\d.]+)%$/.exec(word))) {
786
786
  cue.size = Number(results[1]);
787
787
  } else if ((results =
788
- /^position:([\d.]+)%(?:,(line-left|line-right|center|start|end))?$/
788
+ // eslint-disable-next-line max-len
789
+ /^position:([\d.]+)%(?:,(line-left|line-right|middle|center|start|end))?$/
789
790
  .exec(word))) {
790
791
  cue.position = Number(results[1]);
791
792
  if (results[2]) {
@@ -168,7 +168,7 @@ shaka.util.ManifestParserUtils.VIDEO_CODEC_REGEXPS_ = [
168
168
  /^hvc/,
169
169
  /^vp0?[89]/,
170
170
  /^av01/,
171
- /^dvhe/,
171
+ /^dvh/,
172
172
  ];
173
173
 
174
174
 
@@ -1068,6 +1068,7 @@ shaka.util.StreamUtils = class {
1068
1068
  track.frameRate = video.frameRate || null;
1069
1069
  track.pixelAspectRatio = video.pixelAspectRatio || null;
1070
1070
  track.videoBandwidth = video.bandwidth || null;
1071
+ track.hdr = video.hdr || null;
1071
1072
  }
1072
1073
 
1073
1074
  if (audio) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "shaka-player",
3
3
  "description": "DASH/EME video player library",
4
- "version": "4.3.7",
4
+ "version": "4.3.8",
5
5
  "homepage": "https://github.com/shaka-project/shaka-player",
6
6
  "author": "Google",
7
7
  "maintainers": [
@@ -42,7 +42,7 @@
42
42
  "karma-coverage": "^2.2.0",
43
43
  "karma-jasmine": "^4.0.1",
44
44
  "karma-jasmine-ajax": "^0.1.13",
45
- "karma-local-wd-launcher": "^1.6.1",
45
+ "karma-local-wd-launcher": "^1.6.2",
46
46
  "karma-opera-launcher": "^1.0.0",
47
47
  "karma-sourcemap-loader": "^0.3.8",
48
48
  "karma-spec-reporter": "^0.0.34",
@@ -9,6 +9,10 @@ describe('Mp4CeaParser', () => {
9
9
  const ceaSegmentUri = '/base/test/test/assets/cea-segment.mp4';
10
10
  const h265ceaInitSegmentUri = '/base/test/test/assets/h265-cea-init.mp4';
11
11
  const h265ceaSegmentUri = '/base/test/test/assets/h265-cea-segment.mp4';
12
+ const multipleTrunInitSegmentUri =
13
+ '/base/test/test/assets/multiple-trun-init.mp4';
14
+ const multipleTrunSegmentUri =
15
+ '/base/test/test/assets/multiple-trun-segment.mp4';
12
16
  const Util = shaka.test.Util;
13
17
 
14
18
  /** @type {!ArrayBuffer} */
@@ -19,18 +23,27 @@ describe('Mp4CeaParser', () => {
19
23
  let h265ceaInitSegment;
20
24
  /** @type {!ArrayBuffer} */
21
25
  let h265ceaSegment;
26
+ /** @type {!ArrayBuffer} */
27
+ let multipleTrunInitSegment;
28
+ /** @type {!ArrayBuffer} */
29
+ let multipleTrunSegment;
22
30
 
23
31
  beforeAll(async () => {
24
- const responses = await Promise.all([
32
+ [
33
+ ceaInitSegment,
34
+ ceaSegment,
35
+ h265ceaInitSegment,
36
+ h265ceaSegment,
37
+ multipleTrunInitSegment,
38
+ multipleTrunSegment,
39
+ ] = await Promise.all([
25
40
  shaka.test.Util.fetch(ceaInitSegmentUri),
26
41
  shaka.test.Util.fetch(ceaSegmentUri),
27
42
  shaka.test.Util.fetch(h265ceaInitSegmentUri),
28
43
  shaka.test.Util.fetch(h265ceaSegmentUri),
44
+ shaka.test.Util.fetch(multipleTrunInitSegmentUri),
45
+ shaka.test.Util.fetch(multipleTrunSegmentUri),
29
46
  ]);
30
- ceaInitSegment = responses[0];
31
- ceaSegment = responses[1];
32
- h265ceaInitSegment = responses[2];
33
- h265ceaSegment = responses[3];
34
47
  });
35
48
 
36
49
  /**
@@ -89,6 +102,16 @@ describe('Mp4CeaParser', () => {
89
102
  expect(ceaPackets.length).toBe(60);
90
103
  });
91
104
 
105
+ it('parses cea data from a segment with multiple trun boxes', () => {
106
+ const ceaParser = new shaka.cea.Mp4CeaParser();
107
+
108
+ ceaParser.init(multipleTrunInitSegment);
109
+ const ceaPackets = ceaParser.parse(multipleTrunSegment);
110
+ // The first trun box references samples with 48 CEA packets.
111
+ // The second trun box references samples with 132 more, for a total of 180.
112
+ expect(ceaPackets.length).toBe(180);
113
+ });
114
+
92
115
  it('parses an invalid init segment', () => {
93
116
  const cea708Parser = new shaka.cea.Mp4CeaParser();
94
117
 
@@ -2023,6 +2023,66 @@ describe('DashParser Manifest', () => {
2023
2023
  expect(stream.hdr).toBe('PQ');
2024
2024
  });
2025
2025
 
2026
+ it('supports SupplementalProperty MatrixCoefficients', async () => {
2027
+ // (DASH-IF IOP v4.3 6.2.5.1.)
2028
+ const scheme = cicpScheme('MatrixCoefficients');
2029
+ const manifestText = [
2030
+ '<MPD minBufferTime="PT75S">',
2031
+ ' <Period id="1" duration="PT30S">',
2032
+ ' <AdaptationSet id="2" mimeType="video/mp4">',
2033
+ ` <SupplementalProperty schemeIdUri="${scheme}" value="9" />`,
2034
+ ' <Representation codecs="hvc1.2.4.L153.B0">',
2035
+ ' <BaseURL>v-sd.mp4</BaseURL>',
2036
+ ' <SegmentBase indexRange="100-200" />',
2037
+ ' </Representation>',
2038
+ ' </AdaptationSet>',
2039
+ ' <AdaptationSet id="3" mimeType="audio/mp4">',
2040
+ ' <Representation id="audio-en">',
2041
+ ' <BaseURL>a-en.mp4</BaseURL>',
2042
+ ' <SegmentBase indexRange="100-200" />',
2043
+ ' </Representation>',
2044
+ ' </AdaptationSet>',
2045
+ ' </Period>',
2046
+ '</MPD>',
2047
+ ].join('\n');
2048
+
2049
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
2050
+
2051
+ /** @type {shaka.extern.Manifest} */
2052
+ const manifest = await parser.start('dummy://foo', playerInterface);
2053
+ expect(manifest.variants.length).toBe(1);
2054
+ });
2055
+
2056
+ it('supports SupplementalProperty ColourPrimaries', async () => {
2057
+ // (DASH-IF IOP v4.3 6.2.5.1.)
2058
+ const scheme = cicpScheme('ColourPrimaries');
2059
+ const manifestText = [
2060
+ '<MPD minBufferTime="PT75S">',
2061
+ ' <Period id="1" duration="PT30S">',
2062
+ ' <AdaptationSet id="2" mimeType="video/mp4">',
2063
+ ` <SupplementalProperty schemeIdUri="${scheme}" value="9" />`,
2064
+ ' <Representation codecs="hvc1.2.4.L153.B0">',
2065
+ ' <BaseURL>v-sd.mp4</BaseURL>',
2066
+ ' <SegmentBase indexRange="100-200" />',
2067
+ ' </Representation>',
2068
+ ' </AdaptationSet>',
2069
+ ' <AdaptationSet id="3" mimeType="audio/mp4">',
2070
+ ' <Representation id="audio-en">',
2071
+ ' <BaseURL>a-en.mp4</BaseURL>',
2072
+ ' <SegmentBase indexRange="100-200" />',
2073
+ ' </Representation>',
2074
+ ' </AdaptationSet>',
2075
+ ' </Period>',
2076
+ '</MPD>',
2077
+ ].join('\n');
2078
+
2079
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
2080
+
2081
+ /** @type {shaka.extern.Manifest} */
2082
+ const manifest = await parser.start('dummy://foo', playerInterface);
2083
+ expect(manifest.variants.length).toBe(1);
2084
+ });
2085
+
2026
2086
  it('supports HDR signaling via EssentialProperty', async () => {
2027
2087
  // (DASH-IF IOP v4.3 6.2.5.1.)
2028
2088
  const hdrScheme = cicpScheme('TransferCharacteristics');
@@ -2056,6 +2116,66 @@ describe('DashParser Manifest', () => {
2056
2116
  expect(stream.hdr).toBe('HLG');
2057
2117
  });
2058
2118
 
2119
+ it('supports EssentialProperty MatrixCoefficients', async () => {
2120
+ // (DASH-IF IOP v4.3 6.2.5.1.)
2121
+ const hdrScheme = cicpScheme('MatrixCoefficients');
2122
+ const manifestText = [
2123
+ '<MPD minBufferTime="PT75S">',
2124
+ ' <Period id="1" duration="PT30S">',
2125
+ ' <AdaptationSet id="2" mimeType="video/mp4">',
2126
+ ` <EssentialProperty schemeIdUri="${hdrScheme}" value="9" />`,
2127
+ ' <Representation codecs="hvc1.2.4.L153.B0">',
2128
+ ' <BaseURL>v-sd.mp4</BaseURL>',
2129
+ ' <SegmentBase indexRange="100-200" />',
2130
+ ' </Representation>',
2131
+ ' </AdaptationSet>',
2132
+ ' <AdaptationSet id="3" mimeType="audio/mp4">',
2133
+ ' <Representation id="audio-en">',
2134
+ ' <BaseURL>a-en.mp4</BaseURL>',
2135
+ ' <SegmentBase indexRange="100-200" />',
2136
+ ' </Representation>',
2137
+ ' </AdaptationSet>',
2138
+ ' </Period>',
2139
+ '</MPD>',
2140
+ ].join('\n');
2141
+
2142
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
2143
+
2144
+ /** @type {shaka.extern.Manifest} */
2145
+ const manifest = await parser.start('dummy://foo', playerInterface);
2146
+ expect(manifest.variants.length).toBe(1);
2147
+ });
2148
+
2149
+ it('supports EssentialProperty ColourPrimaries', async () => {
2150
+ // (DASH-IF IOP v4.3 6.2.5.1.)
2151
+ const hdrScheme = cicpScheme('ColourPrimaries');
2152
+ const manifestText = [
2153
+ '<MPD minBufferTime="PT75S">',
2154
+ ' <Period id="1" duration="PT30S">',
2155
+ ' <AdaptationSet id="2" mimeType="video/mp4">',
2156
+ ` <EssentialProperty schemeIdUri="${hdrScheme}" value="9" />`,
2157
+ ' <Representation codecs="hvc1.2.4.L153.B0">',
2158
+ ' <BaseURL>v-sd.mp4</BaseURL>',
2159
+ ' <SegmentBase indexRange="100-200" />',
2160
+ ' </Representation>',
2161
+ ' </AdaptationSet>',
2162
+ ' <AdaptationSet id="3" mimeType="audio/mp4">',
2163
+ ' <Representation id="audio-en">',
2164
+ ' <BaseURL>a-en.mp4</BaseURL>',
2165
+ ' <SegmentBase indexRange="100-200" />',
2166
+ ' </Representation>',
2167
+ ' </AdaptationSet>',
2168
+ ' </Period>',
2169
+ '</MPD>',
2170
+ ].join('\n');
2171
+
2172
+ fakeNetEngine.setResponseText('dummy://foo', manifestText);
2173
+
2174
+ /** @type {shaka.extern.Manifest} */
2175
+ const manifest = await parser.start('dummy://foo', playerInterface);
2176
+ expect(manifest.variants.length).toBe(1);
2177
+ });
2178
+
2059
2179
  it('supports SDR signalling via EssentialProperty', async () => {
2060
2180
  // (DASH-IF IOP v4.3 6.2.5.1.)
2061
2181
  const scheme = cicpScheme('TransferCharacteristics');
@@ -1150,6 +1150,74 @@ describe('HlsParser', () => {
1150
1150
  await testHlsParser(master, media, manifest);
1151
1151
  });
1152
1152
 
1153
+ it('adds subtitle role when characteristics are empty', async () => {
1154
+ const master = [
1155
+ '#EXTM3U\n',
1156
+ '#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1",',
1157
+ 'RESOLUTION=960x540,FRAME-RATE=60,AUDIO="aud1",SUBTITLES="sub1"\n',
1158
+ 'video\n',
1159
+
1160
+ '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="en",',
1161
+ 'NAME="English",URI="audio"\n',
1162
+
1163
+ '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="en",',
1164
+ 'CHARACTERISTICS="public.accessibility.describes-video,',
1165
+ 'public.accessibility.describes-music-and-sound",',
1166
+ 'NAME="English (describes-video)",URI="audio2"\n',
1167
+
1168
+ '#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="sub1",LANGUAGE="en",',
1169
+ 'NAME="English (subtitle)",DEFAULT=YES,AUTOSELECT=YES,',
1170
+ 'URI="text"\n',
1171
+
1172
+ '#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID="sub1",LANGUAGE="en",',
1173
+ 'NAME="English (caption)",DEFAULT=YES,AUTOSELECT=YES,',
1174
+ 'CHARACTERISTICS="public.accessibility.describes-music-and-sound",',
1175
+ 'URI="text2"\n',
1176
+ ].join('');
1177
+ const manifest = shaka.test.ManifestGenerator.generate((manifest) => {
1178
+ manifest.anyTimeline();
1179
+ manifest.addPartialVariant((variant) => {
1180
+ variant.language = 'en';
1181
+ variant.addPartialStream(ContentType.VIDEO);
1182
+ variant.addPartialStream(ContentType.AUDIO, (stream) => {
1183
+ stream.language = 'en';
1184
+ stream.roles = [];
1185
+ });
1186
+ });
1187
+ manifest.addPartialVariant((variant) => {
1188
+ variant.language = 'en';
1189
+ variant.addPartialStream(ContentType.VIDEO);
1190
+ variant.addPartialStream(ContentType.AUDIO, (stream) => {
1191
+ stream.language = 'en';
1192
+ stream.roles = [
1193
+ 'public.accessibility.describes-video',
1194
+ 'public.accessibility.describes-music-and-sound',
1195
+ ];
1196
+ });
1197
+ });
1198
+ manifest.addPartialTextStream((stream) => {
1199
+ stream.language = 'en';
1200
+ stream.kind = TextStreamKind.SUBTITLE;
1201
+ stream.roles = [
1202
+ 'subtitle',
1203
+ ];
1204
+ });
1205
+ manifest.addPartialTextStream((stream) => {
1206
+ stream.language = 'en';
1207
+ stream.kind = TextStreamKind.SUBTITLE;
1208
+ stream.roles = [
1209
+ 'public.accessibility.describes-music-and-sound',
1210
+ ];
1211
+ });
1212
+ manifest.sequenceMode = true;
1213
+ });
1214
+
1215
+ fakeNetEngine.setResponseText('test:/master', master);
1216
+
1217
+ const actual = await parser.start('test:/master', playerInterface);
1218
+ expect(actual).toEqual(manifest);
1219
+ });
1220
+
1153
1221
  it('parses characteristics from text tags', async () => {
1154
1222
  const master = [
1155
1223
  '#EXTM3U\n',
@@ -1898,6 +1966,82 @@ describe('HlsParser', () => {
1898
1966
  }
1899
1967
  });
1900
1968
 
1969
+ it('ignore segments with #EXTINF:0', async () => {
1970
+ const master = [
1971
+ '#EXTM3U\n',
1972
+ '#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud1",LANGUAGE="eng",',
1973
+ 'CHANNELS="2",URI="audio"\n',
1974
+ '#EXT-X-STREAM-INF:BANDWIDTH=200,CODECS="avc1,mp4a",',
1975
+ 'RESOLUTION=960x540,FRAME-RATE=60,AUDIO="aud1"\n',
1976
+ 'video\n',
1977
+ ].join('');
1978
+
1979
+ const video = [
1980
+ '#EXTM3U\n',
1981
+ '#EXT-X-PLAYLIST-TYPE:VOD\n',
1982
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
1983
+ '#EXTINF:5,\n',
1984
+ 'main.mp4\n',
1985
+ '#EXTINF:0,\n',
1986
+ 'main.mp4\n',
1987
+ '#EXTINF:5,\n',
1988
+ 'main.mp4\n',
1989
+ ].join('');
1990
+
1991
+ const audio = [
1992
+ '#EXTM3U\n',
1993
+ '#EXT-X-PLAYLIST-TYPE:VOD\n',
1994
+ '#EXT-X-MAP:URI="init.mp4",BYTERANGE="616@0"\n',
1995
+ '#EXTINF:5,\n',
1996
+ 'main.mp4\n',
1997
+ '#EXTINF:0,\n',
1998
+ 'main.mp4\n',
1999
+ '#EXTINF:5,\n',
2000
+ 'main.mp4\n',
2001
+ ].join('');
2002
+
2003
+ fakeNetEngine
2004
+ .setResponseText('test:/master', master)
2005
+ .setResponseText('test:/audio', audio)
2006
+ .setResponseText('test:/video', video)
2007
+ .setResponseValue('test:/init.mp4', initSegmentData)
2008
+ .setResponseValue('test:/main.mp4', segmentData);
2009
+
2010
+ const actual = await parser.start('test:/master', playerInterface);
2011
+ await loadAllStreamsFor(actual);
2012
+
2013
+ expect(actual.variants.length).toBe(1);
2014
+
2015
+ const variant = actual.variants[0];
2016
+ expect(variant.video).toBeTruthy();
2017
+ expect(variant.audio).toBeTruthy();
2018
+
2019
+ await variant.video.createSegmentIndex();
2020
+ goog.asserts.assert(variant.video.segmentIndex != null,
2021
+ 'Null segmentIndex!');
2022
+
2023
+ const firstVideoReference = variant.video.segmentIndex.get(0);
2024
+ const secondVideoReference = variant.video.segmentIndex.get(1);
2025
+ const thirdVideoReference = variant.video.segmentIndex.get(2);
2026
+
2027
+ expect(firstVideoReference).not.toBe(null);
2028
+ expect(secondVideoReference).not.toBe(null);
2029
+ expect(thirdVideoReference).toBe(null);
2030
+
2031
+
2032
+ await variant.audio.createSegmentIndex();
2033
+ goog.asserts.assert(variant.audio.segmentIndex != null,
2034
+ 'Null segmentIndex!');
2035
+
2036
+ const firstAudioReference = variant.audio.segmentIndex.get(0);
2037
+ const secondAudioReference = variant.audio.segmentIndex.get(1);
2038
+ const thirdAudioReference = variant.audio.segmentIndex.get(2);
2039
+
2040
+ expect(firstAudioReference).not.toBe(null);
2041
+ expect(secondAudioReference).not.toBe(null);
2042
+ expect(thirdAudioReference).toBe(null);
2043
+ });
2044
+
1901
2045
  it('Disable audio does not create audio streams', async () => {
1902
2046
  const master = [
1903
2047
  '#EXTM3U\n',
@@ -31,7 +31,8 @@ describe('RegionObserver', () => {
31
31
  timeline = new shaka.media.RegionTimeline(
32
32
  shaka.test.Util.spyFunc(onSeekRange));
33
33
 
34
- observer = new shaka.media.RegionObserver(timeline);
34
+ observer = new shaka.media.RegionObserver(
35
+ timeline, /* startsPastZero= */ false);
35
36
  observer.addEventListener('enter', (event) => {
36
37
  shaka.test.Util.spyFunc(onEnterRegion)(event['region'], event['seeking']);
37
38
  });
@@ -2913,10 +2913,14 @@ describe('StreamingEngine', () => {
2913
2913
  expect(onManifestUpdate).toHaveBeenCalled();
2914
2914
  });
2915
2915
 
2916
- it('triggers metadata event', async () => {
2916
+ it('triggers both emsg event and metadata event for ID3', async () => {
2917
2917
  setSegment0(emsgSegmentV0ID3);
2918
2918
  videoStream.emsgSchemeIdUris = [id3SchemeUri];
2919
2919
 
2920
+ onEvent.and.callFake((emsgEvent) => {
2921
+ expect(emsgEvent.type).toBe('emsg');
2922
+ });
2923
+
2920
2924
  // Here we go!
2921
2925
  streamingEngine.switchVariant(variant);
2922
2926
  streamingEngine.switchTextStream(textStream);
@@ -2924,10 +2928,30 @@ describe('StreamingEngine', () => {
2924
2928
  playing = true;
2925
2929
  await runTest();
2926
2930
 
2927
- expect(onEvent).not.toHaveBeenCalled();
2931
+ expect(onEvent).toHaveBeenCalled();
2928
2932
  expect(onMetadata).toHaveBeenCalled();
2929
2933
  });
2930
2934
 
2935
+ it('only triggers emsg event for ID3 if event canceled', async () => {
2936
+ setSegment0(emsgSegmentV0ID3);
2937
+ videoStream.emsgSchemeIdUris = [id3SchemeUri];
2938
+
2939
+ onEvent.and.callFake((emsgEvent) => {
2940
+ expect(emsgEvent.type).toBe('emsg');
2941
+ emsgEvent.preventDefault();
2942
+ });
2943
+
2944
+ // Here we go!
2945
+ streamingEngine.switchVariant(variant);
2946
+ streamingEngine.switchTextStream(textStream);
2947
+ await streamingEngine.start();
2948
+ playing = true;
2949
+ await runTest();
2950
+
2951
+ expect(onEvent).toHaveBeenCalled();
2952
+ expect(onMetadata).not.toHaveBeenCalled();
2953
+ });
2954
+
2931
2955
  it('event start matches presentation time', async () => {
2932
2956
  // This box has a non-zero event time, which doesn't matter.
2933
2957
  setSegment0(emsgSegmentV1NonZeroStart);
@@ -8,6 +8,7 @@
8
8
  goog.provide('shaka.ui.ResolutionSelection');
9
9
 
10
10
  goog.require('goog.asserts');
11
+ goog.require('shaka.Player');
11
12
  goog.require('shaka.ui.Controls');
12
13
  goog.require('shaka.ui.Enums');
13
14
  goog.require('shaka.ui.Locales');
@@ -67,7 +68,12 @@ shaka.ui.ResolutionSelection = class extends shaka.ui.SettingsMenu {
67
68
  /** @private */
68
69
  updateResolutionSelection_() {
69
70
  /** @type {!Array.<shaka.extern.Track>} */
70
- let tracks = this.player.getVariantTracks();
71
+ let tracks = [];
72
+ // When played with src=, the variant tracks available from
73
+ // player.getVariantTracks() represent languages, not resolutions.
74
+ if (this.player.getLoadMode() != shaka.Player.LoadMode.SRC_EQUALS) {
75
+ tracks = this.player.getVariantTracks();
76
+ }
71
77
 
72
78
  // If there is a selected variant track, then we filter out any tracks in
73
79
  // a different language. Then we use those remaining tracks to display the