Skip to content

Commit 9d1fe4a

Browse files
theodabjoeyparrish
andauthored
fix(preload): Fix error handling (shaka-project#6753)
After a previous bugfix to the preload system, we ended up with a situation where the overall progress in the preload was tracked by two promises: `successPromise_`, which is resolved when the preload finishes successfully. `destroyPromise_`, which is rejected with an error when the preload process trips an error condition. These two promises were confusingly named; it sounds like destroyPromise is related to the destroy process, but really it has more to do with errors. They were also completely redundant, as a single promise can be used to carry both a resolved and rejected state. This PR simply combines the two promises into one. --------- Co-authored-by: Joey Parrish <[email protected]>
1 parent 3b2477f commit 9d1fe4a

File tree

4 files changed

+50
-40
lines changed

4 files changed

+50
-40
lines changed

lib/media/drm_engine.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,6 @@ shaka.media.DrmEngine = class {
393393
this.config_.keySystemsMapping);
394394
}
395395

396-
397396
/** @type {!Map.<string, MediaKeySystemConfiguration>} */
398397
let configsByKeySystem;
399398

@@ -402,6 +401,7 @@ shaka.media.DrmEngine = class {
402401
await shaka.util.StreamUtils.getDecodingInfosForVariants(variants,
403402
this.usePersistentLicenses_, this.srcEquals_,
404403
this.config_.preferredKeySystems);
404+
this.destroyer_.ensureNotDestroyed();
405405

406406
const hasDrmInfo = hadDrmInfo || Object.keys(this.config_.servers).length;
407407
// An unencrypted content is initialized.

lib/media/preload_manager.js

+40-35
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,6 @@ shaka.media.PreloadManager = class extends shaka.util.FakeEventTarget {
134134
/** @private {!shaka.util.PublicPromise} */
135135
this.successPromise_ = new shaka.util.PublicPromise();
136136

137-
/** @private {!shaka.util.PublicPromise} */
138-
this.destroyPromise_ = new shaka.util.PublicPromise();
139-
140-
// Silence promise failures, in case nobody is catching this.destroyPromise_
141-
this.destroyPromise_.catch((error) => {});
142-
143137
/** @private {?shaka.util.FakeEventTarget} */
144138
this.eventHandoffTarget_ = null;
145139

@@ -376,32 +370,30 @@ shaka.media.PreloadManager = class extends shaka.util.FakeEventTarget {
376370

377371
/**
378372
* Starts the process of loading the asset.
379-
* @return {!Promise}
373+
* Success or failure will be measured through waitForFinish()
380374
*/
381-
async start() {
382-
// Force a context switch, to give the player a chance to hook up events
383-
// immediately if desired.
384-
await Promise.resolve();
385-
386-
// Perform the preloading process.
387-
try {
388-
await this.parseManifestInner_();
389-
if (this.isDestroyed()) {
390-
return;
391-
}
392-
await this.initializeDrmInner_();
393-
if (this.isDestroyed()) {
394-
return;
395-
}
396-
await this.chooseInitialVariantInner_();
397-
if (this.isDestroyed()) {
398-
return;
375+
start() {
376+
(async () => {
377+
// Force a context switch, to give the player a chance to hook up events
378+
// immediately if desired.
379+
await Promise.resolve();
380+
381+
// Perform the preloading process.
382+
try {
383+
await this.parseManifestInner_();
384+
this.throwIfDestroyed_();
385+
386+
await this.initializeDrmInner_();
387+
this.throwIfDestroyed_();
388+
389+
await this.chooseInitialVariantInner_();
390+
this.throwIfDestroyed_();
391+
392+
this.successPromise_.resolve();
393+
} catch (error) {
394+
this.successPromise_.reject(error);
399395
}
400-
this.successPromise_.resolve();
401-
} catch (error) {
402-
this.destroyPromise_.reject(error);
403-
throw error;
404-
}
396+
})();
405397
}
406398

407399
/**
@@ -423,7 +415,7 @@ shaka.media.PreloadManager = class extends shaka.util.FakeEventTarget {
423415
onError(error) {
424416
if (error.severity === shaka.util.Error.Severity.CRITICAL) {
425417
// Cancel the loading process.
426-
this.destroyPromise_.reject(error);
418+
this.successPromise_.reject(error);
427419
this.destroy();
428420
}
429421

@@ -435,6 +427,20 @@ shaka.media.PreloadManager = class extends shaka.util.FakeEventTarget {
435427
}
436428
}
437429

430+
/**
431+
* Throw if destroyed, to interrupt processes with a recognizable error.
432+
*
433+
* @private
434+
*/
435+
throwIfDestroyed_() {
436+
if (this.isDestroyed()) {
437+
throw new shaka.util.Error(
438+
shaka.util.Error.Severity.CRITICAL,
439+
shaka.util.Error.Category.PLAYER,
440+
shaka.util.Error.Code.OBJECT_DESTROYED);
441+
}
442+
}
443+
438444
/**
439445
* Makes a fires an event corresponding to entering a state of the loading
440446
* process.
@@ -534,6 +540,7 @@ shaka.media.PreloadManager = class extends shaka.util.FakeEventTarget {
534540
const event = this.makeEvent_(
535541
shaka.util.FakeEvent.EventName.TracksChanged);
536542
await Promise.resolve();
543+
this.throwIfDestroyed_();
537544
this.dispatchEvent(event);
538545
}
539546

@@ -542,6 +549,7 @@ shaka.media.PreloadManager = class extends shaka.util.FakeEventTarget {
542549
await this.drmEngine_.initForPlayback(
543550
playableVariants,
544551
this.manifest_.offlineSessionIds);
552+
this.throwIfDestroyed_();
545553

546554
// Now that we have drm information, filter the manifest (again) so that
547555
// we can ensure we only use variants with the selected key system.
@@ -692,10 +700,7 @@ shaka.media.PreloadManager = class extends shaka.util.FakeEventTarget {
692700
* @export
693701
*/
694702
waitForFinish() {
695-
return Promise.race([
696-
this.successPromise_,
697-
this.destroyPromise_,
698-
]);
703+
return this.successPromise_;
699704
}
700705

701706
/**

lib/player.js

+7-2
Original file line numberDiff line numberDiff line change
@@ -1581,7 +1581,12 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
15811581
if (preloadManager) {
15821582
preloadManager.setEventHandoffTarget(this);
15831583
this.stats_ = preloadManager.getStats();
1584-
await mutexWrapOperation(() => preloadManager.start(), 'preload');
1584+
preloadManager.start();
1585+
// Silence "uncaught error" warnings from this. Unless we are
1586+
// interrupted, we will check the result of this process and respond
1587+
// appropriately. If we are interrupted, we can ignore any error
1588+
// there.
1589+
preloadManager.waitForFinish().catch(() => {});
15851590
} else {
15861591
this.stats_ = new shaka.util.Stats();
15871592
}
@@ -1843,7 +1848,7 @@ shaka.Player = class extends shaka.util.FakeEventTarget {
18431848
shaka.util.Error.Category.PLAYER,
18441849
shaka.util.Error.Code.SRC_EQUALS_PRELOAD_NOT_SUPPORTED));
18451850
} else {
1846-
preloadManager.start().catch((error) => {}); // Catch errors.
1851+
preloadManager.start();
18471852
}
18481853
return preloadManager;
18491854
}

test/player_load_graph_integration.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -150,16 +150,16 @@ describe('Player Load Graph', () => {
150150
'unload',
151151
'manifest-parser',
152152
'manifest',
153-
'drm-engine',
154153
'media-source',
154+
'drm-engine',
155155
'load',
156156

157157
// Load 3
158158
'unload',
159159
'manifest-parser',
160160
'manifest',
161-
'drm-engine',
162161
'media-source',
162+
'drm-engine',
163163
'load',
164164
]);
165165
});

0 commit comments

Comments
 (0)