Skip to content

Commit b0cd08b

Browse files
srikieonlinepeddisriavelad
authoredApr 4, 2025··
feat: provide option to disable usage of source elements in MSE (#8386)
Some platforms may have some issues around load api. Provide apps to configure using load API or setting src to mediasource. Defaults to using load API. --------- Co-authored-by: Srikanth Peddibhotla <peddisri@amazon.com> Co-authored-by: Álvaro Velad Galván <ladvan91@hotmail.com>
1 parent ea07907 commit b0cd08b

10 files changed

+68
-44
lines changed
 

‎demo/config.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,9 @@ shakaDemo.Config = class {
697697
strategyOptions,
698698
strategyOptionsNames)
699699
.addBoolInput_('Dispatch all emsg boxes',
700-
'mediaSource.dispatchAllEmsgBoxes');
700+
'mediaSource.dispatchAllEmsgBoxes')
701+
.addBoolInput_('Uses source elements',
702+
'mediaSource.useSourceElements');
701703
}
702704

703705
/** @private */

‎externs/shaka/player.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -2134,7 +2134,8 @@ shaka.extern.NetworkingConfiguration;
21342134
* forceTransmux: boolean,
21352135
* insertFakeEncryptionInInit: boolean,
21362136
* modifyCueCallback: shaka.extern.TextParser.ModifyCueCallback,
2137-
* dispatchAllEmsgBoxes: boolean
2137+
* dispatchAllEmsgBoxes: boolean,
2138+
* useSourceElements: boolean
21382139
* }}
21392140
*
21402141
* @description
@@ -2177,6 +2178,12 @@ shaka.extern.NetworkingConfiguration;
21772178
* If true, all emsg boxes are parsed and dispatched.
21782179
* <br>
21792180
* Defaults to <code>false</code>.
2181+
* @property {boolean} useSourceElements
2182+
* If true, uses <source> element. Otherwise,
2183+
* sets the mediaSource url blob to src attribute.
2184+
* Disabling it will prevent using AirPlay on MSE.
2185+
* <br>
2186+
* Defaults to <code>true</code>.
21802187
* @exportDoc
21812188
*/
21822189
shaka.extern.MediaSourceConfiguration;

‎lib/media/media_source_engine.js

+22-15
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,18 @@ shaka.media.MediaSourceEngine = class {
5757
* MediaSourceEngine is destroyed, it will destroy the displayer.
5858
* @param {!shaka.media.MediaSourceEngine.PlayerInterface} playerInterface
5959
* Interface for common player methods.
60+
* @param {shaka.extern.MediaSourceConfiguration} config
6061
* @param {?shaka.lcevc.Dec} [lcevcDec] Optional - LCEVC Decoder Object
6162
*/
62-
constructor(video, textDisplayer, playerInterface, lcevcDec) {
63+
constructor(video, textDisplayer, playerInterface, config, lcevcDec) {
6364
/** @private {HTMLMediaElement} */
6465
this.video_ = video;
6566

6667
/** @private {?shaka.media.MediaSourceEngine.PlayerInterface} */
6768
this.playerInterface_ = playerInterface;
6869

6970
/** @private {?shaka.extern.MediaSourceConfiguration} */
70-
this.config_ = null;
71+
this.config_ = config;
7172

7273
/** @private {shaka.extern.TextDisplayer} */
7374
this.textDisplayer_ = textDisplayer;
@@ -258,20 +259,23 @@ shaka.media.MediaSourceEngine = class {
258259

259260
// Store the object URL for releasing it later.
260261
this.url_ = shaka.media.MediaSourceEngine.createObjectURL(mediaSource);
261-
262-
this.video_.removeAttribute('src');
263-
if (this.source_) {
264-
this.video_.removeChild(this.source_);
265-
}
266-
if (this.secondarySource_) {
267-
this.video_.removeChild(this.secondarySource_);
268-
}
269-
this.source_ = shaka.util.Dom.createSourceElement(this.url_);
270-
this.video_.appendChild(this.source_);
271-
if (this.secondarySource_) {
272-
this.video_.appendChild(this.secondarySource_);
262+
if (this.config_.useSourceElements) {
263+
this.video_.removeAttribute('src');
264+
if (this.source_) {
265+
this.video_.removeChild(this.source_);
266+
}
267+
if (this.secondarySource_) {
268+
this.video_.removeChild(this.secondarySource_);
269+
}
270+
this.source_ = shaka.util.Dom.createSourceElement(this.url_);
271+
this.video_.appendChild(this.source_);
272+
if (this.secondarySource_) {
273+
this.video_.appendChild(this.secondarySource_);
274+
}
275+
this.video_.load();
276+
} else {
277+
this.video_.src = this.url_;
273278
}
274-
this.video_.load();
275279

276280
return mediaSource;
277281
}
@@ -286,6 +290,9 @@ shaka.media.MediaSourceEngine = class {
286290
'Secondary source is used only with ManagedMediaSource');
287291
return;
288292
}
293+
if (!this.config_.useSourceElements) {
294+
return;
295+
}
289296
if (this.secondarySource_) {
290297
this.video_.removeChild(this.secondarySource_);
291298
}

‎lib/player.js

+9-5
Original file line numberDiff line numberDiff line change
@@ -2506,8 +2506,10 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
25062506
this.makeStateChangeEvent_('media-source');
25072507

25082508
// Remove children if we had any, i.e. from previously used src= mode.
2509-
this.video_.removeAttribute('src');
2510-
shaka.util.Dom.removeAllChildren(this.video_);
2509+
if (this.config_.mediaSource.useSourceElements) {
2510+
this.video_.removeAttribute('src');
2511+
shaka.util.Dom.removeAllChildren(this.video_);
2512+
}
25112513

25122514
this.createTextDisplayer_();
25132515
goog.asserts.assert(this.textDisplayer_,
@@ -2526,8 +2528,8 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
25262528
onEvent: (event) => this.dispatchEvent(event),
25272529
onManifestUpdate: () => this.onManifestUpdate_(),
25282530
},
2529-
this.lcevcDec_);
2530-
mediaSourceEngine.configure(this.config_.mediaSource);
2531+
this.lcevcDec_,
2532+
this.config_.mediaSource);
25312533
const {segmentRelativeVttTiming} = this.config_.manifest;
25322534
mediaSourceEngine.setSegmentRelativeVttTiming(segmentRelativeVttTiming);
25332535

@@ -3993,15 +3995,17 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
39933995
* @param {!shaka.extern.TextDisplayer} textDisplayer
39943996
* @param {!shaka.media.MediaSourceEngine.PlayerInterface} playerInterface
39953997
* @param {shaka.lcevc.Dec} lcevcDec
3998+
* @param {shaka.extern.MediaSourceConfiguration} config
39963999
*
39974000
* @return {!shaka.media.MediaSourceEngine}
39984001
*/
39994002
createMediaSourceEngine(mediaElement, textDisplayer, playerInterface,
4000-
lcevcDec) {
4003+
lcevcDec, config) {
40014004
return new shaka.media.MediaSourceEngine(
40024005
mediaElement,
40034006
textDisplayer,
40044007
playerInterface,
4008+
config,
40054009
lcevcDec);
40064010
}
40074011

‎lib/util/player_configuration.js

+1
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@ shaka.util.PlayerConfiguration = class {
428428
undefined);
429429
},
430430
dispatchAllEmsgBoxes: false,
431+
useSourceElements: true,
431432
};
432433

433434
let customPlayheadTracker = false;

‎test/cast/cast_utils_unit.js

+4-5
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,8 @@ describe('CastUtils', () => {
223223
function onError() {
224224
fail('Error code ' + (video.error ? video.error.code : 0));
225225
}
226-
226+
const config =
227+
shaka.util.PlayerConfiguration.createDefault().mediaSource;
227228
mediaSourceEngine = new shaka.media.MediaSourceEngine(
228229
video,
229230
new shaka.test.FakeTextDisplayer(),
@@ -233,10 +234,8 @@ describe('CastUtils', () => {
233234
onEmsg: () => {},
234235
onEvent: () => {},
235236
onManifestUpdate: () => {},
236-
});
237-
const config =
238-
shaka.util.PlayerConfiguration.createDefault().mediaSource;
239-
mediaSourceEngine.configure(config);
237+
},
238+
config);
240239

241240
const ContentType = shaka.util.ManifestParserUtils.ContentType;
242241
const initObject = new Map();

‎test/drm/drm_engine_integration.js

+4-5
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ describe('DrmEngine', () => {
115115
const audioStream = manifest.variants[0].audio;
116116

117117
eventManager = new shaka.util.EventManager();
118-
118+
const mediaSourceConfig =
119+
shaka.util.PlayerConfiguration.createDefault().mediaSource;
119120
mediaSourceEngine = new shaka.media.MediaSourceEngine(
120121
video,
121122
new shaka.test.FakeTextDisplayer(),
@@ -125,10 +126,8 @@ describe('DrmEngine', () => {
125126
onEmsg: () => {},
126127
onEvent: () => {},
127128
onManifestUpdate: () => {},
128-
});
129-
const mediaSourceConfig =
130-
shaka.util.PlayerConfiguration.createDefault().mediaSource;
131-
mediaSourceEngine.configure(mediaSourceConfig);
129+
},
130+
mediaSourceConfig);
132131

133132
const expectedObject = new Map();
134133
expectedObject.set(ContentType.AUDIO, audioStream);

‎test/media/media_source_engine_integration.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ describe('MediaSourceEngine', () => {
178178
onEmsg = jasmine.createSpy('onEmsg');
179179
onEvent = jasmine.createSpy('onEvent');
180180
onManifestUpdate = jasmine.createSpy('onManifestUpdate');
181+
const config = shaka.util.PlayerConfiguration.createDefault().mediaSource;
181182

182183
mediaSourceEngine = new shaka.media.MediaSourceEngine(
183184
video,
@@ -188,9 +189,8 @@ describe('MediaSourceEngine', () => {
188189
onEmsg: Util.spyFunc(onEmsg),
189190
onEvent: Util.spyFunc(onEvent),
190191
onManifestUpdate: Util.spyFunc(onManifestUpdate),
191-
});
192-
const config = shaka.util.PlayerConfiguration.createDefault().mediaSource;
193-
mediaSourceEngine.configure(config);
192+
},
193+
config);
194194

195195
mediaSource = /** @type {?} */(mediaSourceEngine)['mediaSource_'];
196196
expect(video.getElementsByTagName('source').length).toBe(1);

‎test/media/media_source_engine_unit.js

+10-5
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,8 @@ describe('MediaSourceEngine', () => {
251251
video = /** @type {HTMLMediaElement} */(mockVideo);
252252
mockClosedCaptionParser = new shaka.test.FakeClosedCaptionParser();
253253
mockTextDisplayer = new shaka.test.FakeTextDisplayer();
254+
const config = shaka.util.PlayerConfiguration.createDefault().mediaSource;
255+
254256
mediaSourceEngine = new shaka.media.MediaSourceEngine(
255257
video,
256258
mockTextDisplayer,
@@ -260,12 +262,11 @@ describe('MediaSourceEngine', () => {
260262
onEmsg: () => {},
261263
onEvent: () => {},
262264
onManifestUpdate: () => {},
263-
});
265+
},
266+
config);
264267
mediaSourceEngine.getCaptionParser = () => {
265268
return mockClosedCaptionParser;
266269
};
267-
const config = shaka.util.PlayerConfiguration.createDefault().mediaSource;
268-
mediaSourceEngine.configure(config);
269270
});
270271

271272
afterEach(() => {
@@ -326,6 +327,7 @@ describe('MediaSourceEngine', () => {
326327
window.ManagedMediaSource = originalManagedMediaSource;
327328
window.URL.revokeObjectURL = originalRevokeObjectURL;
328329
});
330+
const config = shaka.util.PlayerConfiguration.createDefault().mediaSource;
329331

330332
it('creates a MediaSource object and sets video.src', () => {
331333
mediaSourceEngine = new shaka.media.MediaSourceEngine(
@@ -337,7 +339,8 @@ describe('MediaSourceEngine', () => {
337339
onEmsg: () => {},
338340
onEvent: () => {},
339341
onManifestUpdate: () => {},
340-
});
342+
},
343+
config);
341344

342345
expect(createMediaSourceSpy).toHaveBeenCalled();
343346
expect(createObjectURLSpy).toHaveBeenCalled();
@@ -352,6 +355,7 @@ describe('MediaSourceEngine', () => {
352355
onSourceOpenListener = callback;
353356
}
354357
});
358+
const config = shaka.util.PlayerConfiguration.createDefault().mediaSource;
355359

356360
mediaSourceEngine = new shaka.media.MediaSourceEngine(
357361
video,
@@ -362,7 +366,8 @@ describe('MediaSourceEngine', () => {
362366
onEmsg: () => {},
363367
onEvent: () => {},
364368
onManifestUpdate: () => {},
365-
});
369+
},
370+
config);
366371

367372
if (window.ManagedMediaSource) {
368373
expect(mockMediaSource.addEventListener).toHaveBeenCalledTimes(3);

‎test/media/streaming_engine_integration.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ describe('StreamingEngine', () => {
6767
eventManager = new shaka.util.EventManager();
6868
waiter = new shaka.test.Waiter(eventManager);
6969

70+
const mediaSourceConfig =
71+
shaka.util.PlayerConfiguration.createDefault().mediaSource;
7072
mediaSourceEngine = new shaka.media.MediaSourceEngine(
7173
video,
7274
new shaka.test.FakeTextDisplayer(),
@@ -76,10 +78,8 @@ describe('StreamingEngine', () => {
7678
onEmsg: () => {},
7779
onEvent: () => {},
7880
onManifestUpdate: () => {},
79-
});
80-
const mediaSourceConfig =
81-
shaka.util.PlayerConfiguration.createDefault().mediaSource;
82-
mediaSourceEngine.configure(mediaSourceConfig);
81+
},
82+
mediaSourceConfig);
8383
waiter.setMediaSourceEngine(mediaSourceEngine);
8484
});
8585

0 commit comments

Comments
 (0)
Please sign in to comment.