Add audioTracks support for custom manifests

This commit is contained in:
Xaekai 2022-02-12 20:40:48 -08:00 committed by Calvin Montgomery
parent 2cf26cdc4c
commit f185e6c3ea
3 changed files with 64 additions and 8 deletions

View File

@ -46,6 +46,10 @@ hasAnyTextTracks = (data) ->
ntracks = data?.meta?.textTracks?.length ? 0 ntracks = data?.meta?.textTracks?.length ? 0
return ntracks > 0 return ntracks > 0
hasAnyAudioTracks = (data) ->
ntracks = data?.meta?.audioTracks?.length ? 0
return ntracks > 0
window.VideoJSPlayer = class VideoJSPlayer extends Player window.VideoJSPlayer = class VideoJSPlayer extends Player
constructor: (data) -> constructor: (data) ->
if not (this instanceof VideoJSPlayer) if not (this instanceof VideoJSPlayer)
@ -108,13 +112,21 @@ window.VideoJSPlayer = class VideoJSPlayer extends Player
$('<track/>').attr(attrs).appendTo(video) $('<track/>').attr(attrs).appendTo(video)
) )
pluginData =
videoJsResolutionSwitcher:
default: @sources[0].res
if hasAnyAudioTracks(data)
pluginData.audioSwitch =
audioTracks: data.meta.audioTracks,
volume: VOLUME
@player = videojs(video[0], @player = videojs(video[0],
# https://github.com/Dash-Industry-Forum/dash.js/issues/2184 # https://github.com/Dash-Industry-Forum/dash.js/issues/2184
autoplay: @sources[0].type != 'application/dash+xml', autoplay: @sources[0].type != 'application/dash+xml',
controls: true, controls: true,
plugins: plugins: pluginData
videoJsResolutionSwitcher:
default: @sources[0].res
) )
@player.ready(=> @player.ready(=>
# Have to use updateSrc instead of <source> tags # Have to use updateSrc instead of <source> tags

View File

@ -22,8 +22,9 @@ const SOURCE_CONTENT_TYPES = new Set([
'application/dash+xml', 'application/dash+xml',
'application/x-mpegURL', 'application/x-mpegURL',
'audio/aac', 'audio/aac',
'audio/ogg', 'audio/mp4',
'audio/mpeg', 'audio/mpeg',
'audio/ogg',
'audio/opus', 'audio/opus',
'video/mp4', 'video/mp4',
'video/ogg', 'video/ogg',
@ -36,8 +37,9 @@ const LIVE_ONLY_CONTENT_TYPES = new Set([
const AUDIO_ONLY_CONTENT_TYPES = new Set([ const AUDIO_ONLY_CONTENT_TYPES = new Set([
'audio/aac', 'audio/aac',
'audio/ogg', 'audio/mp4',
'audio/mpeg', 'audio/mpeg',
'audio/ogg',
'audio/opus' 'audio/opus'
]); ]);
@ -142,6 +144,7 @@ export function convert(id, data) {
const meta = { const meta = {
direct: sources, direct: sources,
audioTracks: data.audioTracks,
textTracks: data.textTracks, textTracks: data.textTracks,
thumbnail: data.thumbnail, // Currently ignored by Media thumbnail: data.thumbnail, // Currently ignored by Media
live: !!data.live // Currently ignored by Media live: !!data.live // Currently ignored by Media
@ -170,11 +173,12 @@ export function validate(data) {
validateURL(data.thumbnail); validateURL(data.thumbnail);
} }
validateSources(data.sources); validateSources(data.sources, data);
validateAudioTracks(data.audioTracks);
validateTextTracks(data.textTracks); validateTextTracks(data.textTracks);
} }
function validateSources(sources) { function validateSources(sources, data) {
if (!Array.isArray(sources)) if (!Array.isArray(sources))
throw new ValidationError('sources must be a list'); throw new ValidationError('sources must be a list');
if (sources.length === 0) if (sources.length === 0)
@ -210,6 +214,45 @@ function validateSources(sources) {
} }
} }
function validateAudioTracks(audioTracks) {
if (typeof audioTracks === 'undefined') {
return;
}
if (!Array.isArray(audioTracks)){
throw new ValidationError('audioTracks must be a list');
}
for (let track of audioTracks) {
if (typeof track.url !== 'string'){
throw new ValidationError('audio track URL must be a string');
}
validateURL(track.url);
if (!AUDIO_ONLY_CONTENT_TYPES.has(track.contentType)){
throw new ValidationError(
`unacceptable audio track contentType "${track.contentType}"`
);
}
if (typeof track.label !== 'string'){
throw new ValidationError('audio track label must be a string');
}
if (!track.label){
throw new ValidationError('audio track label must be nonempty');
}
if (typeof track.language !== 'string'){
throw new ValidationError('audio track language must be a string');
}
if (!track.language){
throw new ValidationError('audio track language must be nonempty');
}
if (!/^[a-z]{2,3}$/.test(track.language)){
throw new ValidationError('audio track language must be a two or three letter IETF BCP 47 subtag');
}
}
}
function validateTextTracks(textTracks) { function validateTextTracks(textTracks) {
if (typeof textTracks === 'undefined') { if (typeof textTracks === 'undefined') {
return; return;

View File

@ -38,7 +38,8 @@ Media.prototype = {
scuri: this.meta.scuri, scuri: this.meta.scuri,
embed: this.meta.embed, embed: this.meta.embed,
gdrive_subtitles: this.meta.gdrive_subtitles, gdrive_subtitles: this.meta.gdrive_subtitles,
textTracks: this.meta.textTracks textTracks: this.meta.textTracks,
audioTracks: this.meta.audioTracks
} }
}; };