Skip to content

Commit

Permalink
Changed cast namespace check to include both window.cast and cast. Fa…
Browse files Browse the repository at this point in the history
…llback to isTypeSupported() if 'cast' is available, but canDisplayType() isn't.
  • Loading branch information
JulianDomingo committed Nov 23, 2022
1 parent 1dd0722 commit f625b35
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 33 deletions.
39 changes: 17 additions & 22 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,19 @@ shaka.polyfill.MediaCapabilities = class {
frameRate = undefined,
transferFunction = undefined,
}) {
if (!(window.cast && cast.__platform__ &&
cast.__platform__.canDisplayType)) {
if (!window.cast || !cast) {
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);
}
if (!(cast.__platform__ && cast.__platform__.canDisplayType)) {
shaka.log.warning('Expected canDisplayType() API to be available!');
// We don't have access to the required API, so fallback to
// MediaSource.isTypeSupported().
return MediaSource.isTypeSupported(contentType);
}
let displayType = contentType;
if (width && height) {
displayType += `; width=${width}; height=${height}`;
Expand Down
43 changes: 32 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,11 +201,34 @@ 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.
expect(isTypeSupportedSpy).toHaveBeenCalledTimes(1);
});

it('falls back to isTypeSupported() when canDisplayType() missing',
async () => {
// Only set window['cast'], not cast.__platform__ or
// cast.__platform__.canDisplayType().
window['cast'] = {};
const isChromecastSpy =
spyOn(shaka['util']['Platform'],
'isChromecast').and.returnValue(true);
const isTypeSupportedSpy =
spyOn(window['MediaSource'], 'isTypeSupported')
.and.returnValue(true);

shaka.polyfill.MediaCapabilities.install();
await navigator.mediaCapabilities.decodingInfo(mockDecodingConfig);

expect(mockCanDisplayType).not.toHaveBeenCalled();
// 1 (during install()) + 1 (for video config check).
expect(isChromecastSpy).toHaveBeenCalledTimes(2);
// 1 (mockDecodingConfig.video) + 1 (canCastDisplayType() fallback)
// + 1 (mockDecodingConfig.audio).
expect(isTypeSupportedSpy).toHaveBeenCalledTimes(3);
});

it('should use cast.__platform__.canDisplayType for "supported" field ' +
'when platform is Cast', async () => {
// We're using quotes to access window.cast because the compiler
Expand Down Expand Up @@ -241,10 +263,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 f625b35

Please sign in to comment.