Skip to content

Commit 5102f54

Browse files
committed
Make Player.support synchronous and add support plugin system.
Now there is a new synchronous method Player.isBrowserSupported. This will detect basic support and return a boolean. The support() method has been renamed to probeSupport() and should only be used for diagnostics. Also added a plugin system to Player support testing. Now a plugin (e.g. offline) can add extra info to the output of probeSupport(). Closes #388 Closes #389 Change-Id: I313a41d9f123871272f1395aeb99c980df1f4bae
1 parent 0acc6de commit 5102f54

File tree

12 files changed

+244
-196
lines changed

12 files changed

+244
-196
lines changed

demo/main.js

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -80,27 +80,27 @@ shakaDemo.init = function() {
8080

8181
shaka.polyfill.installAll();
8282

83-
shaka.Player.support().then(function(support) {
84-
shakaDemo.support_ = support;
85-
86-
if (shakaDemo.support_.supported == false) {
87-
var errorDisplay = document.getElementById('errorDisplay');
88-
var error = 'Your browser is not supported!';
89-
90-
// IE8 and other very old browsers don't have textContent.
91-
if (errorDisplay.textContent === undefined) {
92-
errorDisplay.innerText = error;
93-
} else {
94-
errorDisplay.textContent = error;
95-
}
96-
97-
// Disable the load button.
98-
var loadButton = document.getElementById('loadButton');
99-
loadButton.disabled = true;
83+
if (!shaka.Player.isBrowserSupported()) {
84+
var errorDisplay = document.getElementById('errorDisplay');
85+
var error = 'Your browser is not supported!';
10086

101-
// Make sure the error is seen.
102-
errorDisplay.style.fontSize = '250%';
87+
// IE8 and other very old browsers don't have textContent.
88+
if (errorDisplay.textContent === undefined) {
89+
errorDisplay.innerText = error;
10390
} else {
91+
errorDisplay.textContent = error;
92+
}
93+
94+
// Disable the load button.
95+
var loadButton = document.getElementById('loadButton');
96+
loadButton.disabled = true;
97+
98+
// Make sure the error is seen.
99+
errorDisplay.style.fontSize = '250%';
100+
} else {
101+
shaka.Player.probeSupport().then(function(support) {
102+
shakaDemo.support_ = support;
103+
104104
shakaDemo.video_ =
105105
/** @type {!HTMLVideoElement} */(document.getElementById('video'));
106106
shakaDemo.player_ = new shaka.Player(shakaDemo.video_);
@@ -124,8 +124,8 @@ shakaDemo.init = function() {
124124
if ('play' in params) {
125125
shakaDemo.load();
126126
}
127-
}
128-
});
127+
});
128+
}
129129
};
130130

131131

docs/tutorials/upgrade.md

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -571,29 +571,32 @@ if (!shaka.player.Player.isBrowserSupported()) {
571571
}
572572
```
573573

574-
The check in v1 was not very detailed and only did a surface examination of
575-
browser APIs. In v2, the check is much more detailed:
574+
In v2, the same method exists to detect support. For diagnostics there is a new
575+
method that will get more detailed information about the browser. This will
576+
involve making a number of queries to EME which may result in user prompts,
577+
so it is suggested this only be used for diagnostics:
576578

577579
```js
578580
// v2:
579-
shaka.Player.support().then(function(support) {
580-
// The check is asynchronous because the EME API is asynchronous.
581-
if (!support.supported) {
582-
// Show an error and abort.
583-
} else {
581+
if (!shaka.Player.isBrowserSupported()) {
582+
// Show an error and abort.
583+
} else {
584+
// Only call this method if the browser is supported.
585+
shaka.Player.probeSupport().then(function(support) {
586+
// The check is asynchronous because the EME API is asynchronous.
584587
// The support object contains much more information about what the browser
585588
// offers, if you need it. For example, if you require both Widevine and
586589
// WebM/VP9:
587590
if (!support.drm['com.widevine.alpha'] ||
588591
!support.media['video/webm; codecs="vp9"']) {
589592
// Show an error and abort.
590593
}
591-
}
592-
});
594+
});
595+
}
593596
```
594597

595598
For more on the support object, check out {@link shakaExtern.SupportType}.
596-
You can also see the full `support()` report for your browser at:
599+
You can also see the full `probeSupport()` report for your browser at:
597600
{@link http://shaka-player-demo.appspot.com/support.html}
598601

599602

externs/shaka/player.js

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -191,26 +191,35 @@ shakaExtern.Restrictions;
191191

192192
/**
193193
* @typedef {{
194-
* manifest: Object.<string, boolean>,
195-
* media: Object.<string, boolean>,
196-
* drm: Object.<string, boolean>,
197-
* supported: boolean
194+
* persistentState: boolean
195+
* }}
196+
*
197+
* @property {boolean} persistentState
198+
* Whether this key system supports persistent state.
199+
*/
200+
shakaExtern.DrmSupportType;
201+
202+
203+
/**
204+
* @typedef {{
205+
* manifest: !Object.<string, boolean>,
206+
* media: !Object.<string, boolean>,
207+
* drm: !Object.<string, ?shakaExtern.DrmSupportType>
198208
* }}
199209
*
200210
* @description
201211
* An object detailing browser support for various features.
202212
*
203-
* @property {Object.<string, boolean>} manifest
213+
* @property {!Object.<string, boolean>} manifest
204214
* A map of supported manifest types.
205215
* The keys are manifest MIME types and file extensions.
206-
* @property {Object.<string, boolean>} media
216+
* @property {!Object.<string, boolean>} media
207217
* A map of supported media types.
208218
* The keys are media MIME types.
209-
* @property {Object.<string, boolean>} drm
210-
* A map of DRM support.
211-
* The keys are well-known key system IDs.
212-
* @property {boolean} supported
213-
* True if the library is usable at all.
219+
* @property {!Object.<string, ?shakaExtern.DrmSupportType>} drm
220+
* A map of supported key systems.
221+
* The keys are the key system names. The value is null if it is not
222+
* supported. Key systems not probed will not be in this dictionary.
214223
*
215224
* @exportDoc
216225
*/

lib/media/drm_engine.js

Lines changed: 58 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ shaka.media.DrmEngine.prototype.prepareMediaKeyConfigs_ =
322322
var config = configsByKeySystem[drmInfo.keySystem];
323323
if (!config) {
324324
config = {
325-
initDataTypes: undefined, // don't care.
325+
// ignore initDataTypes
326326
audioCapabilities: [],
327327
videoCapabilities: [],
328328
distinctiveIdentifier: 'optional',
@@ -405,13 +405,13 @@ shaka.media.DrmEngine.prototype.queryMediaKeys_ =
405405
if (!hasLicenseServer)
406406
return;
407407

408-
// If there are no tracks of a type, these should be undefined, not empty.
408+
// If there are no tracks of a type, these should be not present.
409409
// Otherwise the query will fail.
410410
if (config.audioCapabilities.length == 0) {
411-
config.audioCapabilities = undefined;
411+
delete config.audioCapabilities;
412412
}
413413
if (config.videoCapabilities.length == 0) {
414-
config.videoCapabilities = undefined;
414+
delete config.videoCapabilities;
415415
}
416416

417417
p = p.catch(function() {
@@ -439,6 +439,7 @@ shaka.media.DrmEngine.prototype.queryMediaKeys_ =
439439
// Edge 13 does not report capabilities. To work around this, set the
440440
// supported types to null, which Player will use as a signal that the
441441
// information is not available.
442+
// See: https://goo.gl/0cSuT2
442443
this.supportedTypes_ = null;
443444
}
444445

@@ -966,51 +967,70 @@ shaka.media.DrmEngine.prototype.onKeyStatusesChange_ = function(event) {
966967

967968

968969
/**
969-
* Returns a Promise to a map of EME support for well-known key systems.
970+
* Returns true if the browser has recent EME APIs.
970971
*
971-
* @param {boolean} persistentStateRequired
972-
* @return {!Promise.<!Object.<string, boolean>>}
972+
* @return {boolean}
973973
*/
974-
shaka.media.DrmEngine.support = function(persistentStateRequired) {
975-
// Every object in the support hierarchy has a "basic" member.
976-
// All "basic" members must be true for the library to be usable.
974+
shaka.media.DrmEngine.isBrowserSupported = function() {
977975
var basic =
978976
!!window.MediaKeys &&
979977
!!window.navigator &&
980978
!!window.navigator.requestMediaKeySystemAccess &&
981979
!!window.MediaKeySystemAccess &&
982980
!!window.MediaKeySystemAccess.prototype.getConfiguration;
983981

984-
var support = {'basic': basic};
982+
return basic;
983+
};
985984

986-
var tests = [];
987-
if (support['basic']) {
988-
var testKeySystems = [
989-
'org.w3.clearkey',
990-
'com.widevine.alpha',
991-
'com.microsoft.playready',
992-
'com.apple.fps.2_0',
993-
'com.apple.fps.1_0',
994-
'com.apple.fps',
995-
'com.adobe.primetime'
996-
];
997-
998-
var config = {};
999-
if (persistentStateRequired) {
1000-
config.persistentState = 'required';
1001-
config.sessionTypes = ['persistent-license'];
1002-
}
1003985

1004-
testKeySystems.forEach(function(keySystem) {
1005-
var p = navigator.requestMediaKeySystemAccess(keySystem, [config])
1006-
.then(function() {
1007-
support[keySystem] = true;
1008-
}, function() {
1009-
support[keySystem] = false;
1010-
});
1011-
tests.push(p);
1012-
});
1013-
}
986+
/**
987+
* Returns a Promise to a map of EME support for well-known key systems.
988+
*
989+
* @return {!Promise.<!Object.<string, ?shakaExtern.DrmSupportType>>}
990+
*/
991+
shaka.media.DrmEngine.probeSupport = function() {
992+
goog.asserts.assert(shaka.media.DrmEngine.isBrowserSupported(),
993+
'Must have basic EME support');
994+
995+
var tests = [];
996+
var testKeySystems = [
997+
'org.w3.clearkey',
998+
'com.widevine.alpha',
999+
'com.microsoft.playready',
1000+
'com.apple.fps.2_0',
1001+
'com.apple.fps.1_0',
1002+
'com.apple.fps',
1003+
'com.adobe.primetime'
1004+
];
1005+
1006+
var config = {
1007+
persistentState: 'required',
1008+
sessionTypes: ['persistent-license']
1009+
};
1010+
var support = {};
1011+
testKeySystems.forEach(function(keySystem) {
1012+
var p = navigator.requestMediaKeySystemAccess(keySystem, [config, {}])
1013+
.then(function(access) {
1014+
// Create a media keys object and try to create an offline session.
1015+
// This is used to detect offline license support for browsers that
1016+
// do not correctly report it in the configuration.
1017+
// https://goo.gl/gtYT3z, https://goo.gl/rvnB1g, https://goo.gl/z0URJ0
1018+
return access.createMediaKeys();
1019+
})
1020+
.then(function(mediaKeys) {
1021+
var persistentState = false;
1022+
try {
1023+
// This will throw if persistent licenses are not supported.
1024+
mediaKeys.createSession('persistent-license');
1025+
persistentState = true;
1026+
} catch (e) {}
1027+
1028+
support[keySystem] = {persistentState: persistentState};
1029+
}, function() {
1030+
support[keySystem] = null;
1031+
});
1032+
tests.push(p);
1033+
});
10141034

10151035
return Promise.all(tests).then(function() {
10161036
return support;

lib/media/manifest_parser.js

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,9 @@ shaka.media.ManifestParser.registerParserByMime = function(
7878
*
7979
* @return {!Object.<string, boolean>}
8080
*/
81-
shaka.media.ManifestParser.support = function() {
82-
// Every object in the support hierarchy has a "basic" member.
83-
// All "basic" members must be true for the library to be usable.
84-
var support = {'basic': true};
85-
81+
shaka.media.ManifestParser.probeSupport = function() {
8682
// Make sure all registered parsers are shown.
83+
var support = {};
8784
for (var type in shaka.media.ManifestParser.parsersByMime) {
8885
support[type] = true;
8986
}

lib/media/media_source_engine.js

Lines changed: 42 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -105,15 +105,11 @@ shaka.media.MediaSourceEngine.isTypeSupported = function(mimeType) {
105105

106106

107107
/**
108-
* Returns a map of MediaSource support for well-known types.
108+
* Returns true if the browser has the basic APIs we need.
109109
*
110-
* @return {!Object.<string, boolean>}
110+
* @return {boolean}
111111
*/
112-
shaka.media.MediaSourceEngine.support = function() {
113-
// Every object in the support hierarchy has a "basic" member.
114-
// All "basic" members must be true for the library to be usable.
115-
var support = {'basic': !!window.MediaSource};
116-
112+
shaka.media.MediaSourceEngine.isBrowserSupported = function() {
117113
// This is ugly, but Safari 8 does not implement appendWindowEnd.
118114
// Detecting this missing feature directly is too complex, since that would
119115
// involve creating a video element, MediaSource, and a SourceBuffer.
@@ -124,36 +120,47 @@ shaka.media.MediaSourceEngine.support = function() {
124120
var version = navigator.appVersion;
125121
if (vendor && vendor.indexOf('Apple') >= 0 &&
126122
version && version.indexOf('Version/8') >= 0) {
127-
support['basic'] = false;
123+
return false;
128124
}
129125

130-
if (support['basic']) {
131-
var testMimeTypes = [
132-
// MP4 types
133-
'video/mp4; codecs="avc1.42E01E"',
134-
'audio/mp4; codecs="mp4a.40.2"',
135-
// WebM types
136-
'video/webm; codecs="vp8"',
137-
'video/webm; codecs="vp9"',
138-
'audio/webm; codecs="vorbis"',
139-
'audio/webm; codecs="opus"',
140-
// MPEG2 TS types (video/ is also used for audio: http://goo.gl/tYHXiS)
141-
'video/mp2t; codecs="avc1.42E01E"',
142-
'video/mp2t; codecs="mp4a.40.2"',
143-
// WebVTT types
144-
'text/vtt',
145-
'application/mp4; codecs="wvtt"',
146-
// TTML types
147-
'application/ttml+xml',
148-
'application/mp4; codecs="stpp"'
149-
];
150-
151-
testMimeTypes.forEach(function(type) {
152-
support[type] = shaka.media.MediaSourceEngine.isTypeSupported(type);
153-
var basicType = type.split(';')[0];
154-
support[basicType] = support[basicType] || support[type];
155-
});
156-
}
126+
return !!window.MediaSource;
127+
};
128+
129+
130+
/**
131+
* Returns a map of MediaSource support for well-known types.
132+
*
133+
* @return {!Object.<string, boolean>}
134+
*/
135+
shaka.media.MediaSourceEngine.probeSupport = function() {
136+
goog.asserts.assert(shaka.media.MediaSourceEngine.isBrowserSupported(),
137+
'Requires basic support');
138+
var support = {};
139+
var testMimeTypes = [
140+
// MP4 types
141+
'video/mp4; codecs="avc1.42E01E"',
142+
'audio/mp4; codecs="mp4a.40.2"',
143+
// WebM types
144+
'video/webm; codecs="vp8"',
145+
'video/webm; codecs="vp9"',
146+
'audio/webm; codecs="vorbis"',
147+
'audio/webm; codecs="opus"',
148+
// MPEG2 TS types (video/ is also used for audio: http://goo.gl/tYHXiS)
149+
'video/mp2t; codecs="avc1.42E01E"',
150+
'video/mp2t; codecs="mp4a.40.2"',
151+
// WebVTT types
152+
'text/vtt',
153+
'application/mp4; codecs="wvtt"',
154+
// TTML types
155+
'application/ttml+xml',
156+
'application/mp4; codecs="stpp"'
157+
];
158+
159+
testMimeTypes.forEach(function(type) {
160+
support[type] = shaka.media.MediaSourceEngine.isTypeSupported(type);
161+
var basicType = type.split(';')[0];
162+
support[basicType] = support[basicType] || support[type];
163+
});
157164

158165
return support;
159166
};

0 commit comments

Comments
 (0)