mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-08-28 21:10:14 +03:00
323 lines
9.2 KiB
JavaScript
323 lines
9.2 KiB
JavaScript
/*
|
|
* Copyright (c) 2016 Antoine Martin <antoine@xpra.org>
|
|
* Licensed under MPL 2.0
|
|
*
|
|
*/
|
|
|
|
const MediaSourceConstants = {
|
|
CODEC_DESCRIPTION: {
|
|
mp4a: "mpeg4: aac",
|
|
"aac+mpeg4": "mpeg4: aac",
|
|
mp3: "mp3",
|
|
"mp3+id3v2": "mp3",
|
|
"mp3+mpeg4": "mpeg4: mp3",
|
|
wav: "wav",
|
|
wave: "wave",
|
|
flac: "flac",
|
|
opus: "opus",
|
|
vorbis: "vorbis",
|
|
"opus+mka": "webm: opus",
|
|
"opus+ogg": "ogg: opus",
|
|
"vorbis+mka": "webm: vorbis",
|
|
"vorbis+ogg": "ogg: vorbis",
|
|
"speex+ogg": "ogg: speex",
|
|
"flac+ogg": "ogg: flac",
|
|
},
|
|
|
|
CODEC_STRING: {
|
|
"aac+mpeg4": 'audio/mp4; codecs="mp4a.40.2"',
|
|
mp3: "audio/mpeg",
|
|
"mp3+mpeg4": 'audio/mp4; codecs="mp3"',
|
|
ogg: "audio/ogg",
|
|
wav: "audio/wav",
|
|
flac: "audio/flac",
|
|
"opus+mka": 'audio/webm; codecs="opus"',
|
|
"vorbis+mka": 'audio/webm; codecs="vorbis"',
|
|
"vorbis+ogg": 'audio/ogg; codecs="vorbis"',
|
|
"speex+ogg": 'audio/ogg; codecs="speex"',
|
|
"flac+ogg": 'audio/ogg; codecs="flac"',
|
|
"opus+ogg": 'audio/ogg; codecs="opus"',
|
|
},
|
|
|
|
PREFERRED_CODEC_ORDER: [
|
|
"opus+mka",
|
|
"vorbis+mka",
|
|
"opus+ogg",
|
|
"vorbis+ogg",
|
|
"opus",
|
|
"vorbis",
|
|
"speex+ogg",
|
|
"flac+ogg",
|
|
"aac+mpeg4",
|
|
"mp3+mpeg4",
|
|
"mp3",
|
|
"mp3+id3v2",
|
|
"flac",
|
|
"wav",
|
|
"wave",
|
|
],
|
|
|
|
H264_PROFILE_CODE: {
|
|
baseline: "42C0",
|
|
main: "4D40",
|
|
high: "6400",
|
|
extended: "58A0",
|
|
},
|
|
|
|
H264_LEVEL_CODE: {
|
|
"3.0": "1E",
|
|
3.1: "1F",
|
|
4.1: "29",
|
|
5.1: "33",
|
|
},
|
|
|
|
READY_STATE: {
|
|
0: "NOTHING",
|
|
1: "METADATA",
|
|
2: "CURRENT DATA",
|
|
3: "FUTURE DATA",
|
|
4: "ENOUGH DATA",
|
|
},
|
|
|
|
NETWORK_STATE: {
|
|
0: "EMPTY",
|
|
1: "IDLE",
|
|
2: "LOADING",
|
|
3: "NO_SOURCE",
|
|
},
|
|
|
|
ERROR_CODE: {
|
|
1: "ABORTED: fetching process aborted by user",
|
|
2: "NETWORK: error occurred when downloading",
|
|
3: "DECODE: error occurred when decoding",
|
|
4: "SRC_NOT_SUPPORTED",
|
|
},
|
|
|
|
AURORA_CODECS: {
|
|
wav: "lpcm",
|
|
"mp3+id3v2": "mp3",
|
|
flac: "flac",
|
|
"aac+mpeg4": "mp4a",
|
|
},
|
|
};
|
|
|
|
const MediaSourceUtil = {
|
|
getMediaSourceClass() {
|
|
return window.MediaSource || window.WebKitMediaSource;
|
|
},
|
|
|
|
getMediaSource() {
|
|
const ms = MediaSourceUtil.getMediaSourceClass();
|
|
if (!ms) {
|
|
throw new Error("no MediaSource support!");
|
|
}
|
|
return new ms();
|
|
},
|
|
|
|
getAuroraAudioCodecs() {
|
|
const codecs_supported = new Map();
|
|
const codecs_failed = new Map();
|
|
if (AV && AV.Decoder && AV.Decoder.find) {
|
|
for (const codec_option in MediaSourceConstants.AURORA_CODECS) {
|
|
const codec_string = MediaSourceConstants.AURORA_CODECS[codec_option];
|
|
// eslint-disable-next-line unicorn/no-array-callback-reference
|
|
const decoder = AV.Decoder.find(codec_string);
|
|
if (decoder) {
|
|
codecs_supported[codec_option] = codec_string;
|
|
} else {
|
|
codecs_failed[codec_option] = codec_string;
|
|
}
|
|
}
|
|
}
|
|
Utilities.log("audio aurora codecs supported:", codecs_supported);
|
|
Utilities.log("audio aurora codecs not available:", codecs_failed);
|
|
return codecs_supported;
|
|
},
|
|
|
|
getMediaSourceAudioCodecs(ignore_blacklist) {
|
|
const media_source_class = MediaSourceUtil.getMediaSourceClass();
|
|
if (!media_source_class) {
|
|
Utilities.log("audio forwarding: no media source API support");
|
|
return [];
|
|
}
|
|
const codecs_supported = [];
|
|
const codecs_failed = {};
|
|
for (const codec_option in MediaSourceConstants.CODEC_STRING) {
|
|
const codec_string = MediaSourceConstants.CODEC_STRING[codec_option];
|
|
try {
|
|
if (!media_source_class.isTypeSupported(codec_string)) {
|
|
codecs_failed[codec_option] = codec_string;
|
|
//add whitelisting here?
|
|
continue;
|
|
}
|
|
let blacklist = [];
|
|
if (Utilities.isFirefox() || Utilities.isSafari()) {
|
|
blacklist += ["opus+mka", "vorbis+mka"];
|
|
if (Utilities.isSafari()) {
|
|
//this crashes Safari!
|
|
blacklist += ["wav"];
|
|
}
|
|
} else if (Utilities.isChrome()) {
|
|
blacklist = ["aac+mpeg4"];
|
|
if (Utilities.isMacOS()) {
|
|
blacklist += ["opus+mka"];
|
|
}
|
|
}
|
|
if (blacklist.includes(codec_option)) {
|
|
if (ignore_blacklist) {
|
|
Utilities.log("blacklist overruled!");
|
|
} else {
|
|
codecs_failed[codec_option] = codec_string;
|
|
continue;
|
|
}
|
|
}
|
|
codecs_supported[codec_option] = codec_string;
|
|
} catch (error) {
|
|
Utilities.error(`audio error probing codec '${codec_string}' / '${codec_string}': ${error}`);
|
|
codecs_failed[codec_option] = codec_string;
|
|
}
|
|
}
|
|
Utilities.log("audio codec MediaSource supported:", codecs_supported);
|
|
Utilities.log("audio codec MediaSource not available:", codecs_failed);
|
|
return codecs_supported;
|
|
},
|
|
|
|
getSupportedAudioCodecs() {
|
|
const codecs_supported = MediaSourceUtil.getMediaSourceAudioCodecs();
|
|
const aurora_codecs = MediaSourceUtil.getAuroraAudioCodecs();
|
|
for (const codec_option in aurora_codecs) {
|
|
if (codec_option in codecs_supported) {
|
|
//we already have native MediaSource support!
|
|
continue;
|
|
}
|
|
codecs_supported[codec_option] = aurora_codecs[codec_option];
|
|
}
|
|
return codecs_supported;
|
|
},
|
|
|
|
getDefaultAudioCodec(codecs) {
|
|
if (!codecs) {
|
|
return null;
|
|
}
|
|
const codec_options = Object.keys(codecs);
|
|
for (let codec_option of MediaSourceConstants.PREFERRED_CODEC_ORDER) {
|
|
if (codec_options.includes(codec_option)) {
|
|
return codec_option;
|
|
}
|
|
}
|
|
return Object.keys(codecs)[0];
|
|
},
|
|
|
|
addMediaSourceEventDebugListeners(media_source, source_type) {
|
|
function debug_source_event(event) {
|
|
let message = `${source_type} source ${event}`;
|
|
try {
|
|
message += `: ${media_source.readyState}`;
|
|
} catch {
|
|
//don't care
|
|
}
|
|
console.debug(message);
|
|
}
|
|
media_source.addEventListener("sourceopen", function(e) {
|
|
debug_source_event("open");
|
|
});
|
|
media_source.addEventListener("sourceended", function(e) {
|
|
debug_source_event("ended");
|
|
});
|
|
media_source.addEventListener("sourceclose", function(e) {
|
|
debug_source_event("close");
|
|
});
|
|
media_source.addEventListener("error", function(e) {
|
|
debug_source_event("error");
|
|
});
|
|
},
|
|
|
|
addMediaElementEventDebugListeners(media_element, element_type) {
|
|
function debug_me_event(event) {
|
|
console.debug(`${element_type} ${event}`);
|
|
}
|
|
media_element.addEventListener("waiting", function() {
|
|
debug_me_event("waiting");
|
|
});
|
|
media_element.addEventListener("stalled", function() {
|
|
debug_me_event("stalled");
|
|
});
|
|
media_element.addEventListener("playing", function() {
|
|
debug_me_event("playing");
|
|
});
|
|
media_element.addEventListener("loadstart", function() {
|
|
debug_me_event("loadstart");
|
|
});
|
|
media_element.addEventListener("loadedmetadata", function() {
|
|
debug_me_event("loadedmetadata");
|
|
});
|
|
media_element.addEventListener("loadeddata", function() {
|
|
debug_me_event("loadeddata");
|
|
});
|
|
media_element.addEventListener("error", function() {
|
|
debug_me_event("error");
|
|
});
|
|
media_element.addEventListener("canplay", function() {
|
|
debug_me_event("canplay");
|
|
});
|
|
media_element.addEventListener("play", function() {
|
|
debug_me_event("play");
|
|
});
|
|
},
|
|
|
|
addSourceBufferEventDebugListeners(asb, element_type) {
|
|
function debug_buffer_event(event) {
|
|
const message = `${element_type} buffer ${event}`;
|
|
console.debug(message);
|
|
}
|
|
asb.addEventListener("updatestart", function(e) {
|
|
debug_buffer_event("updatestart");
|
|
});
|
|
asb.addEventListener("updateend", function(e) {
|
|
debug_buffer_event("updateend");
|
|
});
|
|
asb.addEventListener("error", function(e) {
|
|
debug_buffer_event("error");
|
|
});
|
|
asb.addEventListener("abort", function(e) {
|
|
debug_buffer_event("abort");
|
|
});
|
|
},
|
|
|
|
get_supported_codecs(mediasource, aurora, ignore_audio_blacklist) {
|
|
const codecs_supported = {};
|
|
if (mediasource) {
|
|
const mediasource_codecs = MediaSourceUtil.getMediaSourceAudioCodecs(ignore_audio_blacklist);
|
|
for (const codec_option in mediasource_codecs) {
|
|
codecs_supported[`mediasource:${codec_option}`] =
|
|
MediaSourceConstants.CODEC_DESCRIPTION[codec_option];
|
|
}
|
|
}
|
|
if (aurora) {
|
|
const aurora_codecs = MediaSourceUtil.getAuroraAudioCodecs();
|
|
for (const codec_option in aurora_codecs) {
|
|
if (codec_option in codecs_supported) {
|
|
//we already have native MediaSource support!
|
|
continue;
|
|
}
|
|
codecs_supported[`aurora:${codec_option}`] = `legacy: ${MediaSourceConstants.CODEC_DESCRIPTION[codec_option]}`;
|
|
}
|
|
}
|
|
return codecs_supported;
|
|
},
|
|
|
|
get_best_codec(codecs_supported) {
|
|
let best_codec = null;
|
|
let best_distance = MediaSourceConstants.PREFERRED_CODEC_ORDER.length;
|
|
for (const codec_option in codecs_supported) {
|
|
const cs = codec_option.split(":")[1];
|
|
const distance = MediaSourceConstants.PREFERRED_CODEC_ORDER.indexOf(cs);
|
|
if (distance >= 0 && distance < best_distance) {
|
|
best_codec = codec_option;
|
|
best_distance = distance;
|
|
}
|
|
}
|
|
return best_codec;
|
|
},
|
|
};
|