Embed: player switching

This commit is contained in:
Cat 2016-12-08 16:57:40 +01:00 committed by Thulinma
parent d5c526173b
commit b3c6aedf5b
5 changed files with 158 additions and 57 deletions

View file

@ -544,7 +544,54 @@ MistPlayer.prototype.buildMistControls = function(){
return true; return true;
} }
MistPlayer.prototype.askNextCombo = function(){
var me = this;
me.errorstate = true;
var err = document.createElement('div');
var msgnode = document.createTextNode('Player or stream error detected');
err.appendChild(msgnode);
err.className = 'error';
var button = document.createElement('button');
var t = document.createTextNode('Try next source/player');
button.appendChild(t);
err.appendChild(button);
button.onclick = function(){
me.nextCombo();
}
var button = document.createElement('button');
var t = document.createTextNode('Reload this player');
button.appendChild(t);
err.appendChild(button);
button.onclick = function(){
me.reload();
}
err.style.position = 'absolute';
err.style.top = 0;
err.style.width = '100%';
err.style['margin-left'] = 0;
this.target.appendChild(err);
this.element.style.opacity = '0.2';
};
MistPlayer.prototype.cancelAskNextCombo = function(){
if (this.errorstate) {
this.element.style.opacity = 1;
var err = this.target.querySelector('.error');
if (err) {
this.target.removeChild(err);
}
this.errorstate = false;
}
};
MistPlayer.prototype.reload = function(){
mistPlay(this.mistplaySettings.streamname,this.mistplaySettings.options);
};
MistPlayer.prototype.nextCombo = function(){
var opts = this.mistplaySettings.options;
opts.startCombo = this.mistplaySettings.startCombo;
mistPlay(this.mistplaySettings.streamname,opts);
};
///////////////////////////////////////////////// /////////////////////////////////////////////////
// SELECT AND ADD A VIDEO PLAYER TO THE TARGET // // SELECT AND ADD A VIDEO PLAYER TO THE TARGET //
@ -557,7 +604,8 @@ function mistPlay(streamName,options) {
protoplay.sendEvent('log',msg,options.target); protoplay.sendEvent('log',msg,options.target);
} }
function mistError(msg) { function mistError(msg) {
var info = mistvideo[streamName]; var info = {};
if ((typeof mistvideo != 'undefined') && ('streamName' in mistvideo)) { info = mistvideo[streamName]; }
var displaymsg = msg; var displaymsg = msg;
if ('on_error' in info) { displaymsg = info.on_error; } if ('on_error' in info) { displaymsg = info.on_error; }
@ -570,6 +618,7 @@ function mistPlay(streamName,options) {
err.appendChild(button); err.appendChild(button);
button.onclick = function(){ button.onclick = function(){
options.target.removeChild(err); options.target.removeChild(err);
delete options.startCombo;
mistPlay(streamName,options); mistPlay(streamName,options);
} }
@ -625,10 +674,12 @@ function mistPlay(streamName,options) {
embedLog('Retrieving stream info from '+info.src); embedLog('Retrieving stream info from '+info.src);
document.head.appendChild(info); document.head.appendChild(info);
info.onerror = function(){ info.onerror = function(){
options.target.innerHTML = '';
options.target.removeAttribute('data-loading'); options.target.removeAttribute('data-loading');
mistError('Error while loading stream info.'); mistError('Error while loading stream info.');
} }
info.onload = function(){ info.onload = function(){
options.target.innerHTML = '';
options.target.removeAttribute('data-loading'); options.target.removeAttribute('data-loading');
embedLog('Stream info was loaded succesfully'); embedLog('Stream info was loaded succesfully');
@ -640,6 +691,11 @@ function mistPlay(streamName,options) {
//embedLog('Stream info contents: '+JSON.stringify(streaminfo)); //embedLog('Stream info contents: '+JSON.stringify(streaminfo));
streaminfo.initTime = new Date(); streaminfo.initTime = new Date();
if (!('source' in streaminfo)) {
mistError('Error while loading stream info.');
return;
}
//sort the sources by priority and mime, but prefer HTTPS //sort the sources by priority and mime, but prefer HTTPS
streaminfo.source.sort(function(a,b){ streaminfo.source.sort(function(a,b){
return (b.priority - a.priority) || a.type.localeCompare(b.type) || b.url.localeCompare(a.url); return (b.priority - a.priority) || a.type.localeCompare(b.type) || b.url.localeCompare(a.url);
@ -673,6 +729,15 @@ function mistPlay(streamName,options) {
embedLog('The forced player ('+options.forcePlayer+') isn\'t known, ignoring. Possible values are: '+Object.keys(mistplayers).join(', ')); embedLog('The forced player ('+options.forcePlayer+') isn\'t known, ignoring. Possible values are: '+Object.keys(mistplayers).join(', '));
} }
} }
var startCombo = false;
if ('startCombo' in options) {
startCombo = options.startCombo;
startCombo.started = {
player: false,
source: false
};
embedLog('Selecting a new player/source combo, starting after '+mistplayers[startCombo.player].name+' with '+streaminfo.source[startCombo.source].type+' @ '+streaminfo.source[startCombo.source].url);
}
embedLog('Checking available players..'); embedLog('Checking available players..');
@ -680,6 +745,12 @@ function mistPlay(streamName,options) {
var mistPlayer = false; var mistPlayer = false;
function checkPlayer(p_shortname) { function checkPlayer(p_shortname) {
if ((startCombo) && (!startCombo.started.player)) {
if (p_shortname != startCombo.player) { return false; }
else {
startCombo.started.player = true;
}
}
embedLog('Checking '+mistplayers[p_shortname].name+' (priority: '+mistplayers[p_shortname].priority+') ..'); embedLog('Checking '+mistplayers[p_shortname].name+' (priority: '+mistplayers[p_shortname].priority+') ..');
streaminfo.working[p_shortname] = []; streaminfo.working[p_shortname] = [];
@ -706,22 +777,39 @@ function mistPlay(streamName,options) {
else { else {
loop = streaminfo.source; loop = streaminfo.source;
} }
var broadcast = false;
for (var s in loop) { for (var s in loop) {
if (loop[s].type == mime) { if (loop[s].type == mime) {
if (mistplayers[p_shortname].isBrowserSupported(mime,loop[s],options)) { broadcast = true;
if ((startCombo) && (!startCombo.started.source)) {
if (s == startCombo.source) {
startCombo.started.source = true;
}
continue;
}
if (mistplayers[p_shortname].isBrowserSupported(mime,loop[s],options,streaminfo)) {
embedLog('Found a working combo: '+mistplayers[p_shortname].name+' with '+mime+' @ '+loop[s].url); embedLog('Found a working combo: '+mistplayers[p_shortname].name+' with '+mime+' @ '+loop[s].url);
streaminfo.working[p_shortname].push(mime); streaminfo.working[p_shortname].push(mime);
if (!source) { if (!source) {
mistPlayer = p_shortname; mistPlayer = p_shortname;
source = loop[s]; source = loop[s];
source.index = s;
} }
if (!forceSupportCheck) { if (!forceSupportCheck) {
return source; return source;
} }
} }
else {
embedLog('This browser does not support '+mime);
}
} }
}
if (!broadcast) {
embedLog('Mist doesn\'t broadcast '+mime);
} }
embedLog('Mist doesn\'t broadcast '+mime+' or there is no browser support.');
return false; return false;
} }
@ -742,7 +830,6 @@ function mistPlay(streamName,options) {
} }
} }
options.target.innerHTML = '';
if (mistPlayer) { if (mistPlayer) {
//create the options to send to the player //create the options to send to the player
var playerOpts = { var playerOpts = {
@ -870,8 +957,25 @@ function mistPlay(streamName,options) {
} }
//build the player //build the player
player.mistplaySettings = {
streamname: streamName,
options: local,
startCombo: {
player: mistPlayer,
source: source.index
}
};
player.options = playerOpts; player.options = playerOpts;
var element = player.build(playerOpts); try {
var element = player.build(playerOpts);
}
catch (e) {
//show the next player/reload buttons if there is an error in the player build code
options.target.appendChild(player.element);
player.askNextCombo();
throw e;
return;
}
options.target.appendChild(element); options.target.appendChild(element);
element.setAttribute('data-player',mistPlayer); element.setAttribute('data-player',mistPlayer);
element.setAttribute('data-mime',source.type); element.setAttribute('data-mime',source.type);
@ -884,7 +988,28 @@ function mistPlay(streamName,options) {
} }
//monitor for errors //monitor for errors
//TODO player.checkPlayingTimeout = false;
element.addEventListener('error',function(e){
player.askNextCombo();
},true);
var stalled = function(e){
if (player.checkPlayingTimeout) { return; }
player.checkPlayingTimeout = setTimeout(function(){
if (player.element.readyState >= 2) { return; }
player.askNextCombo();
},5e3);
};
element.addEventListener('stalled',stalled,true);
element.addEventListener('waiting',stalled,true);
var progress = function(e){
if (player.checkPlayingTimeout) {
clearTimeout(player.checkPlayingTimeout);
player.checkPlayingTimeout = false;
player.cancelAskNextCombo();
}
};
element.addEventListener('progress',progress,true);
element.addEventListener('playing',progress,true);
if (player.resize) { if (player.resize) {
//monitor for resizes and fire if needed //monitor for resizes and fire if needed

View file

@ -9,6 +9,8 @@
color: white; color: white;
font-family: sans-serif; font-family: sans-serif;
text-align: center; text-align: center;
position: relative;
text-shadow: 0 0 1px black, 0 0 1px black;
} }
.mistvideo[data-loading] { .mistvideo[data-loading] {
background-image: none; background-image: none;
@ -35,11 +37,16 @@
} }
.mistvideo .error { .mistvideo .error {
margin: 225px 20px 20px; margin: 225px 20px 20px;
min-width: 300px;
z-index: 69;
} }
.mistvideo .error button { .mistvideo .error button {
margin: 5px auto; margin: 5px auto;
display: block; display: block;
} }
.mistvideo .vjs-error-display:before {
content: '' !important;
}
.mistplayer { .mistplayer {
position: relative; position: relative;
overflow: hidden; overflow: hidden;

View file

@ -15,9 +15,9 @@
<script> <script>
// global options can be set here // global options can be set here
var mistoptions = { var mistoptions = {
//host: 'http://cat.mistserver.org:8080' host: 'http://cat.mistserver.org:8080'
//host: 'https://cat.mistserver.org:4433' //host: 'https://cat.mistserver.org:4433'
host: 'http://localhost:8080' //host: 'http://localhost:8080'
}; };
</script> </script>
@ -76,9 +76,10 @@
//tryplayers = Object.keys(mistplayers); //tryplayers = Object.keys(mistplayers);
tryplayers = []; tryplayers = [];
tryplayers.push('derp');
//tryplayers.push('html5'); //tryplayers.push('html5');
//tryplayers.push('dashjs'); //tryplayers.push('dashjs');
tryplayers.push('videojs'); //tryplayers.push('videojs');
//tryplayers.push('flash_strobe'); //tryplayers.push('flash_strobe');
//tryplayers.push('silverlight'); //tryplayers.push('silverlight');
streams = []; streams = [];
@ -86,8 +87,9 @@
//streams.push('subtel'); //streams.push('subtel');
//streams.push('ogg'); //streams.push('ogg');
//streams.push('vids+mist.mp4'); //streams.push('vids+mist.mp4');
streams.push('vids+hahalol.mp3');
//streams.push('lama'); //streams.push('lama');
streams.push('bunny'); //streams.push('bunny');
for (var j in streams) { for (var j in streams) {
for (var i in tryplayers) { for (var i in tryplayers) {
@ -100,7 +102,7 @@
maxwidth: 800, maxwidth: 800,
forcePlayer: tryplayers[i], forcePlayer: tryplayers[i],
//forceType: 'html5/video/mp4', //forceType: 'html5/video/mp4',
forceType: 'html5/application/vnd.apple.mpegurl', //forceType: 'html5/application/vnd.apple.mpegurl',
//forceType: 'dash/video/mp4', //forceType: 'dash/video/mp4',
//forceSource: 5, //forceSource: 5,
loop: true, loop: true,

View file

@ -5,11 +5,18 @@ mistplayers.html5 = {
isMimeSupported: function (mimetype) { isMimeSupported: function (mimetype) {
return (this.mimes.indexOf(mimetype) == -1 ? false : true); return (this.mimes.indexOf(mimetype) == -1 ? false : true);
}, },
isBrowserSupported: function (mimetype) { isBrowserSupported: function (mimetype,source,options,streaminfo) {
if ((['iPad','iPhone','iPod','MacIntel'].indexOf(navigator.platform) != -1) && (mimetype == 'html5/video/mp4')) { return false; } if ((['iPad','iPhone','iPod','MacIntel'].indexOf(navigator.platform) != -1) && (mimetype == 'html5/video/mp4')) { return false; }
var support = false; var support = false;
var shortmime = mimetype.split('/'); var shortmime = mimetype.split('/');
shortmime.shift(); shortmime.shift();
if ((shortmime[0] == 'audio') && (streaminfo.height)) {
//claim you don't support audio only playback if there is video data
return false;
}
try { try {
var v = document.createElement((shortmime[0] == 'audio' ? 'audio' : 'video')); var v = document.createElement((shortmime[0] == 'audio' ? 'audio' : 'video'));
shortmime = shortmime.join('/') shortmime = shortmime.join('/')
@ -35,9 +42,9 @@ p.prototype.build = function (options) {
var ele = this.element((shortmime[0] == 'audio' ? 'audio' : 'video')); var ele = this.element((shortmime[0] == 'audio' ? 'audio' : 'video'));
ele.className = ''; ele.className = '';
cont.appendChild(ele); cont.appendChild(ele);
//ele.crossOrigin = 'anonymous'; ele.crossOrigin = 'anonymous'; //required for subtitles
if (shortmime[0] == 'audio') { if (shortmime[0] == 'audio') {
this.setTracks = false; this.setTracks = function() { return false; }
this.fullscreen = false; this.fullscreen = false;
cont.className += ' audio'; cont.className += ' audio';
} }
@ -92,51 +99,10 @@ p.prototype.build = function (options) {
ele.addEventListener('error',function(e){ ele.addEventListener('error',function(e){
if ((ele.error) && (ele.error.code == 3)) { if ((ele.error) && (ele.error.code == 3)) {
ele.load(); ele.load();
me.cancelAskNextCombo();
me.addlog('Decoding error: reloading..'); me.addlog('Decoding error: reloading..');
} }
},true); },true);
var errorstate = false;
function dced(e) {
if (errorstate) { return; }
errorstate = true;
me.adderror('Connection lost..');
var err = document.createElement('div');
var msgnode = document.createTextNode('Connection lost..');
err.appendChild(msgnode);
err.className = 'error';
var button = document.createElement('button');
var t = document.createTextNode('Reload');
button.appendChild(t);
err.appendChild(button);
button.onclick = function(){
errorstate = false;
ele.parentNode.removeChild(err);
ele.load();
ele.style.opacity = '';
}
err.style.position = 'absolute';
err.style.top = 0;
err.style.width = '100%';
err.style['margin-left'] = 0;
ele.parentNode.appendChild(err);
ele.style.opacity = '0.2';
function nolongerdced(){
ele.removeEventListener('progress',nolongerdced);
errorstate = false;
ele.parentNode.removeChild(err);
ele.style.opacity = '';
}
ele.addEventListener('progress',nolongerdced);
}
ele.addEventListener('stalled',dced,true);
ele.addEventListener('ended',dced,true);
ele.addEventListener('pause',dced,true);
} }
this.addlog('Built html'); this.addlog('Built html');

View file

@ -25,6 +25,7 @@ p.prototype.build = function (options) {
var ele = this.element('video'); var ele = this.element('video');
cont.appendChild(ele); cont.appendChild(ele);
ele.className = ''; ele.className = '';
ele.crossOrigin = 'anonymous'; //required for subtitles
var shortmime = options.source.type.split('/'); var shortmime = options.source.type.split('/');
shortmime.shift(); shortmime.shift();