/**
* @license
* Copyright 2016 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
goog.provide('shaka.media.ManifestParser');
goog.require('goog.Uri');
goog.require('goog.asserts');
goog.require('shaka.log');
goog.require('shaka.net.NetworkingEngine');
goog.require('shaka.util.Error');
/**
* @namespace shaka.media.ManifestParser
* @summary An interface to register manifest parsers.
* @exportDoc
*/
/**
* Contains the parser factory functions indexed by MIME type.
*
* @type {!Object.<string, shakaExtern.ManifestParser.Factory>}
*/
shaka.media.ManifestParser.parsersByMime = {};
/**
* Contains the parser factory functions indexed by file extension.
*
* @type {!Object.<string, shakaExtern.ManifestParser.Factory>}
*/
shaka.media.ManifestParser.parsersByExtension = {};
/**
* Registers a manifest parser by file extension.
*
* @param {string} extension The file extension of the manifest.
* @param {shakaExtern.ManifestParser.Factory} parserFactory The factory
* used to create parser instances.
* @export
*/
shaka.media.ManifestParser.registerParserByExtension = function(
extension, parserFactory) {
shaka.media.ManifestParser.parsersByExtension[extension] = parserFactory;
};
/**
* Registers a manifest parser by MIME type.
*
* @param {string} mimeType The MIME type of the manifest.
* @param {shakaExtern.ManifestParser.Factory} parserFactory The factory
* used to create parser instances.
* @export
*/
shaka.media.ManifestParser.registerParserByMime = function(
mimeType, parserFactory) {
shaka.media.ManifestParser.parsersByMime[mimeType] = parserFactory;
};
/**
* Returns a map of manifest support for well-known types.
*
* @return {!Object.<string, boolean>}
*/
shaka.media.ManifestParser.probeSupport = function() {
// Make sure all registered parsers are shown.
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 well-known types are tested as well, just to show an explicit
// false for things people might be expecting.
let testMimeTypes = [
// DASH
'application/dash+xml',
// HLS
'application/x-mpegurl',
'application/vnd.apple.mpegurl',
// SmoothStreaming
'application/vnd.ms-sstr+xml'
];
let testExtensions = [
// DASH
'mpd',
// HLS
'm3u8',
// SmoothStreaming
'ism'
];
testMimeTypes.forEach(function(type) {
support[type] = !!shaka.media.ManifestParser.parsersByMime[type];
});
testExtensions.forEach(function(type) {
support[type] = !!shaka.media.ManifestParser.parsersByExtension[type];
});
return support;
};
/**
* Finds a manifest parser factory to parse the given manifest.
*
* @param {string} manifestUri
* @param {!shaka.net.NetworkingEngine} netEngine
* @param {shakaExtern.RetryParameters} retryParams
* @param {shakaExtern.ManifestParser.Factory=} opt_manifestParserFactory
* @return {!Promise.<shakaExtern.ManifestParser.Factory>}
*/
shaka.media.ManifestParser.getFactory = function(
manifestUri, netEngine, retryParams, opt_manifestParserFactory) {
let factory = opt_manifestParserFactory;
let extension;
if (!factory) {
// Try to choose a manifest parser by file extension.
let uriObj = new goog.Uri(manifestUri);
let uriPieces = uriObj.getPath().split('/');
let uriFilename = uriPieces.pop();
let filenamePieces = uriFilename.split('.');
// Only one piece means there is no extension.
if (filenamePieces.length > 1) {
extension = filenamePieces.pop().toLowerCase();
factory = shaka.media.ManifestParser.parsersByExtension[extension];
}
}
if (factory) {
return Promise.resolve(factory);
}
// Try to choose a manifest parser by MIME type.
let headRequest =
shaka.net.NetworkingEngine.makeRequest([manifestUri], retryParams);
headRequest.method = 'HEAD';
const type = shaka.net.NetworkingEngine.RequestType.MANIFEST;
return netEngine.request(type, headRequest).promise.then(
function(response) {
let mimeType = response.headers['content-type'];
// https://goo.gl/yzKDRx says this header should always be available,
// but just to be safe:
if (mimeType) {
mimeType = mimeType.toLowerCase();
}
factory = shaka.media.ManifestParser.parsersByMime[mimeType];
if (!factory) {
shaka.log.error(
'Unable to guess manifest type by file extension ' +
'or by MIME type.', extension, mimeType);
return Promise.reject(new shaka.util.Error(
shaka.util.Error.Severity.CRITICAL,
shaka.util.Error.Category.MANIFEST,
shaka.util.Error.Code.UNABLE_TO_GUESS_MANIFEST_TYPE,
manifestUri));
}
return factory;
}, function(error) {
goog.asserts.assert(error instanceof shaka.util.Error,
'Incorrect error type');
shaka.log.error('HEAD request to guess manifest type failed!', error);
error.severity = shaka.util.Error.Severity.CRITICAL;
return Promise.reject(error);
});
};