Skip to content

Commit

Permalink
Revised check for cast namespace with try/catch rather than deal with…
Browse files Browse the repository at this point in the history
… window.cast / cast namespace intermittent availability.
  • Loading branch information
JulianDomingo committed Nov 23, 2022
1 parent 1dd0722 commit 2b8ecf9
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 40 deletions.
51 changes: 22 additions & 29 deletions lib/polyfill/media_capabilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,30 +105,20 @@ shaka.polyfill.MediaCapabilities = class {
return res;
}
// Use 'MediaSource.isTypeSupported' to check if the stream is supported.
// Cast platforms will additionally check canDisplayType(), which
// accepts extended MIME type parameters.
// See: https://github.com/shaka-project/shaka-player/issues/4726
if (videoConfig) {
const contentType = videoConfig.contentType;
let isSupported = MediaSource.isTypeSupported(contentType);
if (shaka.util.Platform.isChromecast()) {
// Cast platforms will additionally check canDisplayType(), which
// accepts extended MIME type parameters.
// There will be at most 2 calls:
// - The first call determines the stability of
// the API by validating a contentType input limited only to MIME type
// and codecs is identical to MediaSource.isTypeSupported().
// - If the same result is observed, a second call will be executed
// containing resolution, frame rate, and transfer function support.
// See: https://github.com/shaka-project/shaka-player/issues/4726
if (isSupported ===
shaka.polyfill.MediaCapabilities.canCastDisplayType_({
contentType})) {
isSupported = shaka.polyfill.MediaCapabilities.canCastDisplayType_({
contentType,
width: videoConfig.width,
height: videoConfig.height,
frameRate: videoConfig.framerate,
transferFunction: videoConfig.transferFunction,
});
}
isSupported = shaka.polyfill.MediaCapabilities.canCastDisplayType_({
contentType,
width: videoConfig.width,
height: videoConfig.height,
frameRate: videoConfig.framerate,
transferFunction: videoConfig.transferFunction,
});
}
if (!isSupported) {
return res;
Expand Down Expand Up @@ -269,14 +259,6 @@ shaka.polyfill.MediaCapabilities = class {
frameRate = undefined,
transferFunction = undefined,
}) {
if (!(window.cast && cast.__platform__ &&
cast.__platform__.canDisplayType)) {
shaka.log.error('Expected cast namespace to be available!');
throw new shaka.util.Error(
shaka.util.Error.Severity.CRITICAL,
shaka.util.Error.Category.CAST,
shaka.util.Error.Code.CAST_UNEXPECTED_PLATFORM);
}
let displayType = contentType;
if (width && height) {
displayType += `; width=${width}; height=${height}`;
Expand All @@ -290,7 +272,18 @@ shaka.polyfill.MediaCapabilities = class {
// this query is specifically for HDR.
displayType += '; eotf=smpte2084';
}
return cast.__platform__.canDisplayType(displayType);

let canDisplayType;
try {
canDisplayType = cast.__platform__.canDisplayType(displayType);
} catch (e) {
shaka.log.error('Expected cast namespace to be available!');
throw new shaka.util.Error(
shaka.util.Error.Severity.CRITICAL,
shaka.util.Error.Category.CAST,
shaka.util.Error.Code.CAST_UNEXPECTED_PLATFORM);
}
return canDisplayType;
}

/**
Expand Down
20 changes: 9 additions & 11 deletions test/polyfill/media_capabilities_unit.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@

describe('MediaCapabilities', () => {
const Util = shaka.test.Util;
const originalCast = window['cast'];
const originalVendor = navigator.vendor;
const originalUserAgent = navigator.userAgent;
const originalRequestMediaKeySystemAccess =
navigator.requestMediaKeySystemAccess;
const originalMediaCapabilities = navigator.mediaCapabilities;
const originalCast = window['cast'];

/** @type {MediaDecodingConfiguration} */
let mockDecodingConfig;
Expand Down Expand Up @@ -182,9 +182,8 @@ describe('MediaCapabilities', () => {
.toHaveBeenCalledTimes(1);
});

it('fails when the cast namespace is not available', async () => {
// Mock Shaka throwing an error from identifying an unexpected, non-Cast
// platform when performing Cast logic.
it('throws when the cast namespace is not available', async () => {
// We don't set window['cast'] here to signal error.
const isChromecastSpy =
spyOn(shaka['util']['Platform'],
'isChromecast').and.returnValue(true);
Expand All @@ -202,9 +201,9 @@ describe('MediaCapabilities', () => {

// 1 (during install()) + 1 (for video config check).
expect(isChromecastSpy).toHaveBeenCalledTimes(2);
// Called for decodingConfig.audio. This is never reached because of the
// error throw.
expect(isTypeSupportedSpy).not.toHaveBeenCalled();
// Called for decodingConfig.video. decodingConfig.audio is never reached
// due to the error thrown in canCastDisplayType().
expect(isTypeSupportedSpy).toHaveBeenCalledTimes(1);
});

it('should use cast.__platform__.canDisplayType for "supported" field ' +
Expand Down Expand Up @@ -241,10 +240,9 @@ describe('MediaCapabilities', () => {

// 1 (during install()) + 1 (for video config check).
expect(isChromecastSpy).toHaveBeenCalledTimes(2);
// Called once for mockDecodingConfig.audio. Resolution, frame rate, and
// EOTF aren't applicable for audio, so isTypeSupported() is sufficient.
expect(isTypeSupportedSpy).toHaveBeenCalledTimes(1);
// Called once for mockDecodingConfig.video.
// 1 (mockDecodingConfig.video) + 1 (mockDecodingConfig.audio).
expect(isTypeSupportedSpy).toHaveBeenCalledTimes(2);
// Called once in canCastDisplayType.
expect(mockCanDisplayType).toHaveBeenCalledTimes(1);
});
});
Expand Down

0 comments on commit 2b8ecf9

Please sign in to comment.