Skip to content

Commit

Permalink
Cover iOS in isBrowserSupported and probeSupport
Browse files Browse the repository at this point in the history
Now iOS is supported for HLS through src=, so isBrowserSupported
needs to reflect that.  This makes MediaSource optional for any
browser with src= playback of HLS.

This also fixes probeSupport() to reflect the capabilities of non-MSE
platforms such as iOS, which is critical for our demo app to be able
to show the correct set of playable assets.

Issue #997
Closes #1857

Change-Id: Ic6e18587db90fff2b097a2038c16cc928e2b9438
  • Loading branch information
joeyparrish committed Apr 12, 2019
1 parent 4334f19 commit 4854d36
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 37 deletions.
57 changes: 39 additions & 18 deletions lib/media/manifest_parser.js
Expand Up @@ -22,6 +22,7 @@ goog.require('goog.asserts');
goog.require('shaka.log');
goog.require('shaka.net.NetworkingEngine');
goog.require('shaka.util.Error');
goog.require('shaka.util.Platform');


/**
Expand Down Expand Up @@ -81,18 +82,23 @@ shaka.media.ManifestParser.registerParserByMime = function(
* @return {!Object.<string, boolean>}
*/
shaka.media.ManifestParser.probeSupport = function() {
// Make sure all registered parsers are shown.
const ManifestParser = shaka.media.ManifestParser;
let support = {};
for (let type in shaka.media.ManifestParser.parsersByMime) {
support[type] = true;
}
for (let type in shaka.media.ManifestParser.parsersByExtension) {
support[type] = true;

// Make sure all registered parsers are shown, but only for MSE-enabled
// platforms where our parsers matter.
if (shaka.util.Platform.supportsMediaSource()) {
for (let type in ManifestParser.parsersByMime) {
support[type] = true;
}
for (let type in ManifestParser.parsersByExtension) {
support[type] = true;
}
}

// Make sure all well-known types are tested as well, just to show an explicit
// false for things people might be expecting.
let testMimeTypes = [
const testMimeTypes = [
// DASH
'application/dash+xml',
// HLS
Expand All @@ -101,21 +107,36 @@ shaka.media.ManifestParser.probeSupport = function() {
// SmoothStreaming
'application/vnd.ms-sstr+xml',
];
let testExtensions = [
const testExtensions = {
// DASH
'mpd',
'mpd': 'application/dash+xml',
// HLS
'm3u8',
'm3u8': 'application/x-mpegurl',
// SmoothStreaming
'ism',
];
'ism': 'application/vnd.ms-sstr+xml',
};

for (let type of testMimeTypes) {
// Only query our parsers for MSE-enabled platforms. Otherwise, query a
// temporary media element for native support for these types.
if (shaka.util.Platform.supportsMediaSource()) {
support[type] = !!ManifestParser.parsersByMime[type];
} else {
support[type] = shaka.util.Platform.supportsMediaType(type);
}
}

testMimeTypes.forEach(function(type) {
support[type] = !!shaka.media.ManifestParser.parsersByMime[type];
});
testExtensions.forEach(function(type) {
support[type] = !!shaka.media.ManifestParser.parsersByExtension[type];
});
for (let extension in testExtensions) {
// Only query our parsers for MSE-enabled platforms. Otherwise, query a
// temporary media element for native support for these MIME type for the
// extension.
if (shaka.util.Platform.supportsMediaSource()) {
support[extension] = !!ManifestParser.parsersByExtension[extension];
} else {
const type = testExtensions[extension];
support[extension] = shaka.util.Platform.supportsMediaType(type);
}
}

return support;
};
Expand Down
29 changes: 17 additions & 12 deletions lib/media/media_source_engine.js
Expand Up @@ -161,12 +161,7 @@ shaka.media.MediaSourceEngine.isStreamSupported = function(stream) {
* @return {!Object.<string, boolean>}
*/
shaka.media.MediaSourceEngine.probeSupport = function() {
goog.asserts.assert(
shaka.util.Platform.supportsMediaSource(),
'Requires basic support');

let support = {};
let testMimeTypes = [
const testMimeTypes = [
// MP4 types
'video/mp4; codecs="avc1.42E01E"',
'video/mp4; codecs="avc3.42E01E"',
Expand Down Expand Up @@ -202,13 +197,23 @@ shaka.media.MediaSourceEngine.probeSupport = function() {
'application/mp4; codecs="stpp"',
];

testMimeTypes.forEach(function(type) {
support[type] = shaka.text.TextEngine.isTypeSupported(type) ||
MediaSource.isTypeSupported(type) ||
shaka.media.Transmuxer.isSupported(type);
let basicType = type.split(';')[0];
let support = {};
for (let type of testMimeTypes) {
if (shaka.util.Platform.supportsMediaSource()) {
// Our TextEngine is only effective for MSE platforms at the moment.
if (shaka.text.TextEngine.isTypeSupported(type)) {
support[type] = true;
} else {
support[type] = MediaSource.isTypeSupported(type) ||
shaka.media.Transmuxer.isSupported(type);
}
} else {
support[type] = shaka.util.Platform.supportsMediaType(type);
}

const basicType = type.split(';')[0];
support[basicType] = support[basicType] || support[type];
});
}

return support;
};
Expand Down
23 changes: 17 additions & 6 deletions lib/player.js
Expand Up @@ -50,6 +50,7 @@ goog.require('shaka.util.ManifestParserUtils');
goog.require('shaka.util.MimeUtils');
goog.require('shaka.util.MultiMap');
goog.require('shaka.util.Periods');
goog.require('shaka.util.Platform');
goog.require('shaka.util.PlayerConfiguration');
goog.require('shaka.util.Stats');
goog.require('shaka.util.StreamUtils');
Expand Down Expand Up @@ -679,12 +680,22 @@ shaka.Player.registerSupportPlugin = function(name, callback) {
*/
shaka.Player.isBrowserSupported = function() {
// Basic features needed for the library to be usable.
let basic = !!window.Promise && !!window.Uint8Array &&
!!Array.prototype.forEach;

return basic &&
shaka.util.Platform.supportsMediaSource() &&
shaka.media.DrmEngine.isBrowserSupported();
const basicSupport = !!window.Promise && !!window.Uint8Array &&
!!Array.prototype.forEach;
if (!basicSupport) return false;

// DRM support is not strictly necessary, but the APIs at least need to be
// there. Our no-op DRM polyfill should handle that.
// TODO(#1017): Consider making even DrmEngine optional.
const drmSupport = shaka.media.DrmEngine.isBrowserSupported();
if (!drmSupport) return false;

// If we have MediaSource (MSE) support, we should be able to use Shaka.
if (shaka.util.Platform.supportsMediaSource()) return true;

// If we don't have MSE, we _may_ be able to use Shaka. Look for native HLS
// support, and call this platform usable if we have it.
return shaka.util.Platform.supportsMediaType('application/x-mpegurl');
};


Expand Down
56 changes: 55 additions & 1 deletion lib/util/platform.js
Expand Up @@ -17,6 +17,8 @@

goog.provide('shaka.util.Platform');

goog.require('shaka.util.Timer');


/**
* A wrapper for platform-specific functions.
Expand All @@ -39,14 +41,25 @@ shaka.util.Platform = class {
return false;
}

// TODO: Document when |isTypeSupported| would be missing.
// Some very old MediaSource implementations didn't have isTypeSupported.
if (!MediaSource.isTypeSupported) {
return false;
}

return true;
}

/**
* Returns true if the media type is supported natively by the platform.
*
* @param {string} mimeType
* @return {boolean}
*/
static supportsMediaType(mimeType) {
const video = shaka.util.Platform.anyMediaElement_();
return video.canPlayType(mimeType) != '';
}

/**
* Check if the current platform is MS Edge.
*
Expand Down Expand Up @@ -126,4 +139,45 @@ shaka.util.Platform = class {
const userAgent = navigator.userAgent || '';
return userAgent.includes(key);
}

/**
* For canPlayType queries, we just need any instance.
*
* First, use a cached element from a previous query.
* Second, search the page for one.
* Third, create a temporary one.
*
* Cached elements expire in one second so that they can be GC'd or removed.
*
* @return {!HTMLMediaElement}
*/
static anyMediaElement_() {
const Platform = shaka.util.Platform;
if (Platform.cachedMediaElement_) {
return Platform.cachedMediaElement_;
}

if (!Platform.cacheExpirationTimer_) {
Platform.cacheExpirationTimer_ = new shaka.util.Timer(() => {
Platform.cachedMediaElement_ = null;
});
}

Platform.cachedMediaElement_ = /** @type {HTMLMediaElement} */(
document.querySelector('video') || document.querySelector('audio'));

if (!Platform.cachedMediaElement_) {
Platform.cachedMediaElement_ = /** @type {!HTMLMediaElement} */(
document.createElement('video'));
}

Platform.cacheExpirationTimer_.tickAfter(/* seconds= */ 1);
return Platform.cachedMediaElement_;
}
};

/** @private {shaka.util.Timer} */
shaka.util.Platform.cacheExpirationTimer_ = null;

/** @private {HTMLMediaElement} */
shaka.util.Platform.cachedMediaElement_ = null;

0 comments on commit 4854d36

Please sign in to comment.