mirror of
https://github.com/eliasstepanik/vdo.ninja.git
synced 2026-01-11 13:48:38 +00:00
Add files via upload
This commit is contained in:
parent
260ca2f770
commit
366ab39fb6
382
CodecsHandler.js
Normal file
382
CodecsHandler.js
Normal file
@ -0,0 +1,382 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012-2020 [Muaz Khan](https://github.com/muaz-khan)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
// Sourced from: https://cdn.webrtc-experiment.com/CodecsHandler.js
|
||||
var CodecsHandler = (function() {
|
||||
function preferCodec(sdp, codecName) {
|
||||
var info = splitLines(sdp);
|
||||
|
||||
if (!info.videoCodecNumbers) {
|
||||
return sdp;
|
||||
}
|
||||
|
||||
if (codecName === 'vp8' && info.vp8LineNumber === info.videoCodecNumbers[0]) {
|
||||
return sdp;
|
||||
}
|
||||
|
||||
if (codecName === 'vp9' && info.vp9LineNumber === info.videoCodecNumbers[0]) {
|
||||
return sdp;
|
||||
}
|
||||
|
||||
if (codecName === 'h264' && info.h264LineNumber === info.videoCodecNumbers[0]) {
|
||||
return sdp;
|
||||
}
|
||||
|
||||
sdp = preferCodecHelper(sdp, codecName, info);
|
||||
|
||||
return sdp;
|
||||
}
|
||||
|
||||
function preferCodecHelper(sdp, codec, info, ignore) {
|
||||
var preferCodecNumber = '';
|
||||
|
||||
if (codec === 'vp8') {
|
||||
if (!info.vp8LineNumber) {
|
||||
return sdp;
|
||||
}
|
||||
preferCodecNumber = info.vp8LineNumber;
|
||||
}
|
||||
|
||||
if (codec === 'vp9') {
|
||||
if (!info.vp9LineNumber) {
|
||||
return sdp;
|
||||
}
|
||||
preferCodecNumber = info.vp9LineNumber;
|
||||
}
|
||||
|
||||
if (codec === 'h264') {
|
||||
if (!info.h264LineNumber) {
|
||||
return sdp;
|
||||
}
|
||||
|
||||
preferCodecNumber = info.h264LineNumber;
|
||||
}
|
||||
|
||||
var newLine = info.videoCodecNumbersOriginal.split('SAVPF')[0] + 'SAVPF ';
|
||||
|
||||
var newOrder = [preferCodecNumber];
|
||||
|
||||
if (ignore) {
|
||||
newOrder = [];
|
||||
}
|
||||
|
||||
info.videoCodecNumbers.forEach(function(codecNumber) {
|
||||
if (codecNumber === preferCodecNumber) return;
|
||||
newOrder.push(codecNumber);
|
||||
});
|
||||
|
||||
newLine += newOrder.join(' ');
|
||||
|
||||
sdp = sdp.replace(info.videoCodecNumbersOriginal, newLine);
|
||||
return sdp;
|
||||
}
|
||||
|
||||
function splitLines(sdp) {
|
||||
var info = {};
|
||||
sdp.split('\n').forEach(function(line) {
|
||||
if (line.indexOf('m=video') === 0) {
|
||||
info.videoCodecNumbers = [];
|
||||
line.split('SAVPF')[1].split(' ').forEach(function(codecNumber) {
|
||||
codecNumber = codecNumber.trim();
|
||||
if (!codecNumber || !codecNumber.length) return;
|
||||
info.videoCodecNumbers.push(codecNumber);
|
||||
info.videoCodecNumbersOriginal = line;
|
||||
});
|
||||
}
|
||||
|
||||
if (line.indexOf('VP8/90000') !== -1 && !info.vp8LineNumber) {
|
||||
info.vp8LineNumber = line.replace('a=rtpmap:', '').split(' ')[0];
|
||||
}
|
||||
|
||||
if (line.indexOf('VP9/90000') !== -1 && !info.vp9LineNumber) {
|
||||
info.vp9LineNumber = line.replace('a=rtpmap:', '').split(' ')[0];
|
||||
}
|
||||
|
||||
if (line.indexOf('H264/90000') !== -1 && !info.h264LineNumber) {
|
||||
info.h264LineNumber = line.replace('a=rtpmap:', '').split(' ')[0];
|
||||
}
|
||||
});
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
function removeVPX(sdp) {
|
||||
var info = splitLines(sdp);
|
||||
|
||||
// last parameter below means: ignore these codecs
|
||||
sdp = preferCodecHelper(sdp, 'vp9', info, true);
|
||||
sdp = preferCodecHelper(sdp, 'vp8', info, true);
|
||||
|
||||
return sdp;
|
||||
}
|
||||
|
||||
function disableNACK(sdp) {
|
||||
if (!sdp || typeof sdp !== 'string') {
|
||||
throw 'Invalid arguments.';
|
||||
}
|
||||
|
||||
sdp = sdp.replace('a=rtcp-fb:126 nack\r\n', '');
|
||||
sdp = sdp.replace('a=rtcp-fb:126 nack pli\r\n', 'a=rtcp-fb:126 pli\r\n');
|
||||
sdp = sdp.replace('a=rtcp-fb:97 nack\r\n', '');
|
||||
sdp = sdp.replace('a=rtcp-fb:97 nack pli\r\n', 'a=rtcp-fb:97 pli\r\n');
|
||||
|
||||
return sdp;
|
||||
}
|
||||
|
||||
function prioritize(codecMimeType, peer) {
|
||||
if (!peer || !peer.getSenders || !peer.getSenders().length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!codecMimeType || typeof codecMimeType !== 'string') {
|
||||
throw 'Invalid arguments.';
|
||||
}
|
||||
|
||||
peer.getSenders().forEach(function(sender) {
|
||||
var params = sender.getParameters();
|
||||
for (var i = 0; i < params.codecs.length; i++) {
|
||||
if (params.codecs[i].mimeType == codecMimeType) {
|
||||
params.codecs.unshift(params.codecs.splice(i, 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
sender.setParameters(params);
|
||||
});
|
||||
}
|
||||
|
||||
function removeNonG722(sdp) {
|
||||
return sdp.replace(/m=audio ([0-9]+) RTP\/SAVPF ([0-9 ]*)/g, 'm=audio $1 RTP\/SAVPF 9');
|
||||
}
|
||||
|
||||
function setBAS(sdp, bandwidth, isScreen) {
|
||||
if (!bandwidth) {
|
||||
return sdp;
|
||||
}
|
||||
|
||||
if (typeof isFirefox !== 'undefined' && isFirefox) {
|
||||
return sdp;
|
||||
}
|
||||
|
||||
if (isScreen) {
|
||||
if (!bandwidth.screen) {
|
||||
console.warn('It seems that you are not using bandwidth for screen. Screen sharing is expected to fail.');
|
||||
} else if (bandwidth.screen < 300) {
|
||||
console.warn('It seems that you are using wrong bandwidth value for screen. Screen sharing is expected to fail.');
|
||||
}
|
||||
}
|
||||
|
||||
// if screen; must use at least 300kbs
|
||||
if (bandwidth.screen && isScreen) {
|
||||
sdp = sdp.replace(/b=AS([^\r\n]+\r\n)/g, '');
|
||||
sdp = sdp.replace(/a=mid:video\r\n/g, 'a=mid:video\r\nb=AS:' + bandwidth.screen + '\r\n');
|
||||
}
|
||||
|
||||
// remove existing bandwidth lines
|
||||
if (bandwidth.audio || bandwidth.video) {
|
||||
sdp = sdp.replace(/b=AS([^\r\n]+\r\n)/g, '');
|
||||
}
|
||||
|
||||
if (bandwidth.audio) {
|
||||
sdp = sdp.replace(/a=mid:audio\r\n/g, 'a=mid:audio\r\nb=AS:' + bandwidth.audio + '\r\n');
|
||||
}
|
||||
|
||||
if (bandwidth.screen) {
|
||||
sdp = sdp.replace(/a=mid:video\r\n/g, 'a=mid:video\r\nb=AS:' + bandwidth.screen + '\r\n');
|
||||
} else if (bandwidth.video) {
|
||||
sdp = sdp.replace(/a=mid:video\r\n/g, 'a=mid:video\r\nb=AS:' + bandwidth.video + '\r\n');
|
||||
}
|
||||
|
||||
return sdp;
|
||||
}
|
||||
|
||||
// Find the line in sdpLines that starts with |prefix|, and, if specified,
|
||||
// contains |substr| (case-insensitive search).
|
||||
function findLine(sdpLines, prefix, substr) {
|
||||
return findLineInRange(sdpLines, 0, -1, prefix, substr);
|
||||
}
|
||||
|
||||
// Find the line in sdpLines[startLine...endLine - 1] that starts with |prefix|
|
||||
// and, if specified, contains |substr| (case-insensitive search).
|
||||
function findLineInRange(sdpLines, startLine, endLine, prefix, substr) {
|
||||
var realEndLine = endLine !== -1 ? endLine : sdpLines.length;
|
||||
for (var i = startLine; i < realEndLine; ++i) {
|
||||
if (sdpLines[i].indexOf(prefix) === 0) {
|
||||
if (!substr ||
|
||||
sdpLines[i].toLowerCase().indexOf(substr.toLowerCase()) !== -1) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Gets the codec payload type from an a=rtpmap:X line.
|
||||
function getCodecPayloadType(sdpLine) {
|
||||
var pattern = new RegExp('a=rtpmap:(\\d+) \\w+\\/\\d+');
|
||||
var result = sdpLine.match(pattern);
|
||||
return (result && result.length === 2) ? result[1] : null;
|
||||
}
|
||||
|
||||
function setVideoBitrates(sdp, params) {
|
||||
params = params || {};
|
||||
var xgoogle_min_bitrate = params.min;
|
||||
var xgoogle_max_bitrate = params.max;
|
||||
|
||||
var sdpLines = sdp.split('\r\n');
|
||||
|
||||
// VP8
|
||||
var vp8Index = findLine(sdpLines, 'a=rtpmap', 'VP8/90000');
|
||||
var vp8Payload;
|
||||
if (vp8Index) {
|
||||
vp8Payload = getCodecPayloadType(sdpLines[vp8Index]);
|
||||
}
|
||||
|
||||
if (!vp8Payload) {
|
||||
return sdp;
|
||||
}
|
||||
|
||||
var rtxIndex = findLine(sdpLines, 'a=rtpmap', 'rtx/90000');
|
||||
var rtxPayload;
|
||||
if (rtxIndex) {
|
||||
rtxPayload = getCodecPayloadType(sdpLines[rtxIndex]);
|
||||
}
|
||||
|
||||
if (!rtxIndex) {
|
||||
return sdp;
|
||||
}
|
||||
|
||||
var rtxFmtpLineIndex = findLine(sdpLines, 'a=fmtp:' + rtxPayload.toString());
|
||||
if (rtxFmtpLineIndex !== null) {
|
||||
var appendrtxNext = '\r\n';
|
||||
appendrtxNext += 'a=fmtp:' + vp8Payload + ' x-google-min-bitrate=' + (xgoogle_min_bitrate || '228') + '; x-google-max-bitrate=' + (xgoogle_max_bitrate || '228');
|
||||
sdpLines[rtxFmtpLineIndex] = sdpLines[rtxFmtpLineIndex].concat(appendrtxNext);
|
||||
sdp = sdpLines.join('\r\n');
|
||||
}
|
||||
|
||||
return sdp;
|
||||
}
|
||||
|
||||
function setOpusAttributes(sdp, params) {
|
||||
params = params || {};
|
||||
|
||||
var sdpLines = sdp.split('\r\n');
|
||||
|
||||
// Opus
|
||||
var opusIndex = findLine(sdpLines, 'a=rtpmap', 'opus/48000');
|
||||
var opusPayload;
|
||||
if (opusIndex) {
|
||||
opusPayload = getCodecPayloadType(sdpLines[opusIndex]);
|
||||
}
|
||||
|
||||
if (!opusPayload) {
|
||||
return sdp;
|
||||
}
|
||||
|
||||
var opusFmtpLineIndex = findLine(sdpLines, 'a=fmtp:' + opusPayload.toString());
|
||||
if (opusFmtpLineIndex === null) {
|
||||
return sdp;
|
||||
}
|
||||
|
||||
var appendOpusNext = '';
|
||||
appendOpusNext += '; stereo=' + (typeof params.stereo != 'undefined' ? params.stereo : '1');
|
||||
appendOpusNext += '; sprop-stereo=' + (typeof params['sprop-stereo'] != 'undefined' ? params['sprop-stereo'] : '1');
|
||||
|
||||
if (typeof params.maxaveragebitrate != 'undefined') {
|
||||
appendOpusNext += '; maxaveragebitrate=' + (params.maxaveragebitrate || 128 * 1024 * 8);
|
||||
}
|
||||
|
||||
if (typeof params.maxplaybackrate != 'undefined') {
|
||||
appendOpusNext += '; maxplaybackrate=' + (params.maxplaybackrate || 128 * 1024 * 8);
|
||||
}
|
||||
|
||||
if (typeof params.cbr != 'undefined') {
|
||||
appendOpusNext += '; cbr=' + (typeof params.cbr != 'undefined' ? params.cbr : '1');
|
||||
}
|
||||
|
||||
if (typeof params.useinbandfec != 'undefined') {
|
||||
appendOpusNext += '; useinbandfec=' + params.useinbandfec;
|
||||
}
|
||||
|
||||
if (typeof params.usedtx != 'undefined') {
|
||||
appendOpusNext += '; usedtx=' + params.usedtx;
|
||||
}
|
||||
|
||||
if (typeof params.maxptime != 'undefined') {
|
||||
appendOpusNext += '\r\na=maxptime:' + params.maxptime;
|
||||
}
|
||||
|
||||
sdpLines[opusFmtpLineIndex] = sdpLines[opusFmtpLineIndex].concat(appendOpusNext);
|
||||
|
||||
sdp = sdpLines.join('\r\n');
|
||||
return sdp;
|
||||
}
|
||||
|
||||
// forceStereoAudio => via webrtcexample.com
|
||||
// requires getUserMedia => echoCancellation:false
|
||||
function forceStereoAudio(sdp) {
|
||||
var sdpLines = sdp.split('\r\n');
|
||||
var fmtpLineIndex = null;
|
||||
for (var i = 0; i < sdpLines.length; i++) {
|
||||
if (sdpLines[i].search('opus/48000') !== -1) {
|
||||
var opusPayload = extractSdp(sdpLines[i], /:(\d+) opus\/48000/i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < sdpLines.length; i++) {
|
||||
if (sdpLines[i].search('a=fmtp') !== -1) {
|
||||
var payload = extractSdp(sdpLines[i], /a=fmtp:(\d+)/);
|
||||
if (payload === opusPayload) {
|
||||
fmtpLineIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fmtpLineIndex === null) return sdp;
|
||||
sdpLines[fmtpLineIndex] = sdpLines[fmtpLineIndex].concat('; stereo=1; sprop-stereo=1');
|
||||
sdp = sdpLines.join('\r\n');
|
||||
return sdp;
|
||||
}
|
||||
|
||||
return {
|
||||
removeVPX: removeVPX,
|
||||
disableNACK: disableNACK,
|
||||
prioritize: prioritize,
|
||||
removeNonG722: removeNonG722,
|
||||
setApplicationSpecificBandwidth: function(sdp, bandwidth, isScreen) {
|
||||
return setBAS(sdp, bandwidth, isScreen);
|
||||
},
|
||||
setVideoBitrates: function(sdp, params) {
|
||||
return setVideoBitrates(sdp, params);
|
||||
},
|
||||
setOpusAttributes: function(sdp, params) {
|
||||
return setOpusAttributes(sdp, params);
|
||||
},
|
||||
preferVP9: function(sdp) {
|
||||
return preferCodec(sdp, 'vp9');
|
||||
},
|
||||
preferCodec: preferCodec,
|
||||
forceStereoAudio: forceStereoAudio
|
||||
};
|
||||
})();
|
||||
|
||||
// backward compatibility
|
||||
window.BandwidthHandler = CodecsHandler;
|
||||
455
index.html
455
index.html
@ -4,9 +4,11 @@
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
|
||||
<meta content="utf-8" http-equiv="encoding">
|
||||
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon">
|
||||
<link rel="stylesheet" href="font-awesome.min.css">
|
||||
<script type="text/javascript" src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
|
||||
|
||||
<script type="text/javascript" src="qrcode.min.js"></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
|
||||
<style type="text/css">
|
||||
#mynetwork {
|
||||
width: 600px;
|
||||
@ -60,8 +62,8 @@
|
||||
max-width:100%;
|
||||
max-height:100%
|
||||
}
|
||||
.vidcon:nth-of-type(3n) { grid-column: span 2; }
|
||||
.vidcon:nth-of-type(5n) { grid-row: span 2; }
|
||||
.vidcon:nth-of-type(3n) { grid-column: 2; }
|
||||
.vidcon:nth-of-type(3n) { grid-row: span ; }
|
||||
|
||||
.tile {
|
||||
object-fit: contain;
|
||||
@ -73,7 +75,7 @@
|
||||
margin:0;
|
||||
}
|
||||
|
||||
.gridlayout {
|
||||
#gridlayout {
|
||||
display: grid;
|
||||
width:100%;
|
||||
height:100%;
|
||||
@ -81,10 +83,34 @@
|
||||
overflow: hidden;
|
||||
justify-items: stretch;
|
||||
grid-auto-flow: dense;
|
||||
grid-auto-columns:minmax(50%, auto);
|
||||
grid-auto-rows: minmax(50%, auto);
|
||||
}
|
||||
|
||||
.directorsgrid {
|
||||
justify-items: normal;
|
||||
grid-auto-columns: minmax(100px,300px);
|
||||
grid-auto-rows: minmax(100px, 300px);
|
||||
display:block ! important;
|
||||
|
||||
}
|
||||
.directorsgrid video {
|
||||
max-width: 300px;
|
||||
max-height: 300px;
|
||||
padding:10px 10px 0px 10px !important;
|
||||
}
|
||||
.directorsgrid .vidcon {
|
||||
display: inline-block !important;
|
||||
max-width: 300px !important;
|
||||
max-height: 300px !important;
|
||||
background: #E3E4EF;
|
||||
}
|
||||
.directorsgrid .tile {
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
@ -384,7 +410,7 @@ img {
|
||||
|
||||
video {
|
||||
flex: 1 1 auto;
|
||||
background-color: black;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
|
||||
@ -414,8 +440,10 @@ video {
|
||||
}
|
||||
|
||||
</style>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
|
||||
</head>
|
||||
<body id="main">
|
||||
<script language="javascript" type="text/javascript" src="./CodecsHandler.js"></script>
|
||||
<script language="javascript" type="text/javascript" src="./webrtc.js"></script>
|
||||
|
||||
<div id="header">
|
||||
@ -430,7 +458,7 @@ video {
|
||||
</div>
|
||||
|
||||
<div id="head4" style="display:inline-block" class='advanced'>
|
||||
<font style="font-size:60%">   You are in a director's view   </font>
|
||||
<font style="font-size:60%">   You are in the director's view for room:  <div id="dirroomid" style="font-size:140%;color:#99C;display:inline-block"></div></font>
|
||||
</div>
|
||||
|
||||
|
||||
@ -450,14 +478,14 @@ video {
|
||||
</div>
|
||||
|
||||
<div id="mainmenu" class="row" style="align:center;">
|
||||
<div id="container-1" class="column columnfade" onclick="alert('THIS FEATURE IS COMING SOON\n\nProgress Update 3/30/20: Fixed a lot of priority issues, re-wrote the server to support group chat, and am aiming to have group-chat ready by Wednesday.');" style="background-color:#ddd;">
|
||||
<div id="container-1" class="column columnfade" style="background-color:#ddd;">
|
||||
<h2>Add Group Video Chat to OBS</h2>
|
||||
(COMING VERY SOON)
|
||||
<div class="container-inner">
|
||||
<br /><br />
|
||||
<p><input id="videoname1" placeholder="Enter a ROOM NAME here" size=35 maxlength=50 style="padding:5px;" /></br ><br /></p>
|
||||
<li>Anyone can enter a room if they know the name, so keep it unique</li>
|
||||
<li>Having more than four (4) people in a room is not advisable due to performance reasons</li>
|
||||
<li>Having more than four (4) people in a room is not advisable due to performance reasons.</li>
|
||||
<br />
|
||||
With a room name entered, enter the room as a director. Links to invite guests will be provided.
|
||||
<br />
|
||||
@ -550,10 +578,29 @@ video {
|
||||
<form method="post" onsubmit="setFormSubmitting()" style="display:none;">
|
||||
<input type="submit" />
|
||||
</form>
|
||||
<script>
|
||||
<script>
|
||||
/////////////
|
||||
|
||||
/////////////
|
||||
var VIS = vis;
|
||||
// Some browsers partially implement mediaDevices. We can't just assign an object
|
||||
// with getUserMedia as it would overwrite existing properties.
|
||||
// Here, we will just add the getUserMedia property if it's missing.
|
||||
if (navigator.mediaDevices.getUserMedia === undefined) {
|
||||
navigator.mediaDevices.getUserMedia = function(constraints) {
|
||||
// First get ahold of the legacy getUserMedia, if present
|
||||
var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
|
||||
// Some browsers just don't implement it - return a rejected promise with an error
|
||||
// to keep a consistent interface
|
||||
if (!getUserMedia) {
|
||||
return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
|
||||
}
|
||||
// Otherwise, wrap the call to the old navigator.getUserMedia with a Promise
|
||||
return new Promise(function(resolve, reject) {
|
||||
getUserMedia.call(navigator, constraints, resolve, reject);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var VIS = vis;
|
||||
var formSubmitting = true;
|
||||
var setFormSubmitting = function() { formSubmitting = true; };
|
||||
window.onload = function() { // This just keeps people from killing the live stream accidentally. Also give me a headsup that the stream is ending
|
||||
@ -591,10 +638,57 @@ if (urlParams.has('permaid')){
|
||||
var permaid = urlParams.get('permaid');
|
||||
session.changeStreamID(permaid);
|
||||
}
|
||||
if (urlParams.has('stereo')){
|
||||
log("STEREO ENABLED");
|
||||
session.stereo = true;
|
||||
}
|
||||
|
||||
if (urlParams.has('bitrate')){
|
||||
session.bitrate = parseInt(urlParams.get('bitrate'));
|
||||
log("BITRATE ENABLED");
|
||||
log(session.bitrate);
|
||||
}
|
||||
if (urlParams.has('turn')){
|
||||
try {
|
||||
var turnstring = urlParams.get('turn').split(";");
|
||||
var turn = {};
|
||||
turn.username = turnstring[0]; // myusername
|
||||
turn.credential = turnstring[1]; mypassword
|
||||
turn.urls = [turnstring[2]]; // ["turn:turn.obs.ninja:443"];
|
||||
session.configuration.iceServers.push(turn);
|
||||
} catch (e){
|
||||
alert("TURN server parameters were wrong.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var micvolume = 100;
|
||||
session.connect();
|
||||
|
||||
session.volume = micvolume;
|
||||
if (urlParams.has('roomid')){
|
||||
var roomid = urlParams.get('roomid');
|
||||
session.roomid = roomid;
|
||||
document.getElementById("videoname1").value = roomid;
|
||||
document.getElementById("dirroomid").innerHTML = roomid;
|
||||
document.getElementById("roomid").innerHTML = roomid;
|
||||
if (urlParams.has('scene')){
|
||||
session.scene = urlParams.get('scene');
|
||||
document.getElementById("container-4").className = 'column columnfade';
|
||||
document.getElementById("container-3").className = 'column columnfade';
|
||||
document.getElementById("container-2").className = 'column columnfade';
|
||||
document.getElementById("container-1").className = 'column columnfade';
|
||||
document.getElementById("header").className = 'advanced';
|
||||
document.getElementById("info").className = 'advanced';
|
||||
document.getElementById("header").className = 'advanced';
|
||||
document.getElementById("head1").className = 'advanced';
|
||||
document.getElementById("head2").className = 'advanced';
|
||||
document.getElementById("head3").className = 'advanced';
|
||||
document.getElementById("mainmenu").innerHTML = "";
|
||||
joinRoom(roomid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function checkConnection(){
|
||||
if (session.ws.readyState === WebSocket.OPEN) {
|
||||
@ -605,8 +699,8 @@ function checkConnection(){
|
||||
}
|
||||
setInterval(function(){checkConnection();},5000);
|
||||
|
||||
function toggleMute(){
|
||||
var msg = {};
|
||||
function toggleMute(){ // TODO: I need to have this be MUTE, toggle, with volume not touched.
|
||||
var msg = {};
|
||||
if (micvolume==0){
|
||||
micvolume = 100;
|
||||
document.getElementById("mutetoggle").className="fa fa-microphone my-float";
|
||||
@ -621,6 +715,54 @@ function toggleMute(){
|
||||
session.sendMessage(msg);
|
||||
}
|
||||
|
||||
function directMute(ele){ // A directing room only is controlled by the Director, with the exception of MUTE.
|
||||
log("mute");
|
||||
var msg = {};
|
||||
msg.request = "sendroom";
|
||||
msg.roomid = session.roomid;
|
||||
msg.director = "placeholder";
|
||||
msg.action = "mute";
|
||||
msg.value = 0;
|
||||
msg.target = ele.dataset.UUID;
|
||||
session.sendMsg(msg); // send to everyone in the room, so they know if they are on air or not.
|
||||
}
|
||||
|
||||
|
||||
function directVolume(ele){ // A directing room only is controlled by the Director, with the exception of MUTE.
|
||||
log("volume");
|
||||
var msg = {};
|
||||
msg.request = "sendroom";
|
||||
msg.roomid = session.roomid;
|
||||
msg.director = "placeholder";
|
||||
msg.action = "volume";
|
||||
msg.value = ele.value;
|
||||
msg.target = ele.dataset.UUID; // i want to focus on the STREAM ID, not the UUID...
|
||||
session.sendMsg(msg); // send to everyone in the room, so they know if they are on air or not.
|
||||
}
|
||||
|
||||
function directVisibility(ele){ // A directing room only is controlled by the Director, with the exception of MUTE.
|
||||
log("display ");
|
||||
var msg = {};
|
||||
msg.request = "sendroom";
|
||||
msg.roomid = session.roomid;
|
||||
msg.director = "placeholder";
|
||||
msg.action = "display";
|
||||
msg.value = 0;
|
||||
msg.target = ele.dataset.UUID;
|
||||
session.sendMsg(msg); // send to everyone in the room, so they know if they are on air or not.
|
||||
}
|
||||
|
||||
function chatRoom(chatmessage="hi"){ // A directing room only is controlled by the Director, with the exception of MUTE.
|
||||
log("display ");
|
||||
var msg = {};
|
||||
msg.request = "sendroom";
|
||||
msg.roomid = session.roomid;
|
||||
msg.action = "chat";
|
||||
msg.value = chatmessage;
|
||||
session.sendMsg(msg); // send to everyone in the room, so they know if they are on air or not.
|
||||
}
|
||||
|
||||
|
||||
function changeTitle(aTitle="Untitled"){
|
||||
log("changing title; if connected at least");
|
||||
session.changeTitle(aTitle);
|
||||
@ -640,11 +782,11 @@ function publishScreen(){
|
||||
|
||||
if (urlParams.has('width')){
|
||||
width = urlParams.get('width');
|
||||
width = {exact: width};
|
||||
width = {ideal: width};
|
||||
}
|
||||
if (urlParams.has('height')){
|
||||
height = urlParams.get('height');
|
||||
height = {exact: height};
|
||||
height = {ideal: height};
|
||||
}
|
||||
|
||||
var constraints = window.constraints = {
|
||||
@ -676,6 +818,10 @@ function publishWebcam(){
|
||||
|
||||
formSubmitting = false;
|
||||
window.scrollTo(0, 0); // iOS has a nasty habit of overriding the CSS when changing camaera selections, so this addresses that.
|
||||
|
||||
joinRoom(session.roomid,300);
|
||||
|
||||
|
||||
session.publishStream(stream, title);
|
||||
log("streamID is: "+session.streamID);
|
||||
document.getElementById("head1").className = 'advanced';
|
||||
@ -684,15 +830,38 @@ function publishWebcam(){
|
||||
|
||||
document.getElementById("mutebutton").className="float3";
|
||||
document.getElementById("helpbutton").className="float2";
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
function joinRoom(roomname){
|
||||
log("Join room",roomname);
|
||||
session.joinRoom(roomname).then(function(response){
|
||||
log("Members in Room",response);
|
||||
},function(error){return {}});
|
||||
function joinRoom(roomname, maxbitrate=false){
|
||||
roomname = roomname.replace(/[^0-9a-z]/gi, '');
|
||||
if (roomname.length){
|
||||
log("Join room",roomname);
|
||||
session.joinRoom(roomname,maxbitrate).then(function(response){
|
||||
log("Members in Room");
|
||||
log(response);
|
||||
for (i in response){
|
||||
if ("UUID" in response[i]){
|
||||
if ("streamID" in response[i]){
|
||||
if (response[i]['UUID'] in session.pcs){
|
||||
console.log("RTC already connected"); /// lets just say instead of Stream, we have
|
||||
} else {
|
||||
//var title = "";
|
||||
//if ("title" in response[i]){
|
||||
// title = response[i]["title"];
|
||||
//}
|
||||
console.log("PLAYING VIDEO 729");
|
||||
session.watchStream(response[i]['streamID']); // How do I make sure they aren't requesting the same movie twice as a race condition?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
},function(error){return {}});
|
||||
} else {
|
||||
errorlog("Room name not long enough or contained all bad characaters");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -706,7 +875,7 @@ function createRoom(){
|
||||
}
|
||||
|
||||
var gridlayout = document.getElementById("gridlayout");
|
||||
gridlayout.className = "gridlayout";
|
||||
gridlayout.classList.add("directorsgrid");
|
||||
|
||||
// var sheet = document.createElement('style');
|
||||
// sheet.innerHTML = ".tile{object-fit:contain }";
|
||||
@ -729,6 +898,7 @@ function createRoom(){
|
||||
|
||||
//document.getElementById("mutebutton").className="float3";
|
||||
//document.getElementById("helpbutton").className="float2";
|
||||
session.director = true;
|
||||
joinRoom(roomname);
|
||||
|
||||
}
|
||||
@ -779,7 +949,7 @@ function gotDevices(deviceInfos) { // https://github.com/webrtc/samples/blob/gh-
|
||||
// TODO: Add in the option to select the OUTPUT and Disable Mic/Cam
|
||||
|
||||
// Handles being called several times to update labels. Preserve values.
|
||||
const values = selectors.map(select => select.value);
|
||||
const values = selectors.map(select => select.value);
|
||||
selectors.forEach(select => {
|
||||
while (select.firstChild) {
|
||||
select.removeChild(select.firstChild);
|
||||
@ -799,12 +969,12 @@ function gotDevices(deviceInfos) { // https://github.com/webrtc/samples/blob/gh-
|
||||
} else {
|
||||
log('Some other kind of source/device: ', deviceInfo);
|
||||
}
|
||||
}
|
||||
selectors.forEach((select, selectorIndex) => {
|
||||
if (Array.prototype.slice.call(select.childNodes).some(n => n.value === values[selectorIndex])) {
|
||||
select.value = values[selectorIndex];
|
||||
}
|
||||
selectors.forEach((select, selectorIndex) => {
|
||||
if (Array.prototype.slice.call(select.childNodes).some(n => n.value === values[selectorIndex])) {
|
||||
select.value = values[selectorIndex];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function handleError(error) {
|
||||
@ -883,8 +1053,8 @@ function getUserMediaVideoParams(resolutionFallbackLevel, isSafariBrowser) {
|
||||
}
|
||||
else {
|
||||
return {
|
||||
width: { min: 360, ideal: 640, max: 1440 },
|
||||
height: { min: 360, ideal: 360, max: 720 }
|
||||
width: { min: 360, ideal: 640, max: 3840 },
|
||||
height: { min: 360, ideal: 360, max: 2160 }
|
||||
};
|
||||
}
|
||||
case 6:
|
||||
@ -892,17 +1062,20 @@ function getUserMediaVideoParams(resolutionFallbackLevel, isSafariBrowser) {
|
||||
return {}; // iphone users probably don't need to wait any longer, so let them just get to it
|
||||
}
|
||||
else {
|
||||
return { // If the camera is recording in low-light, it may have a low framerate. It coudl also be recording at a very high resolution.
|
||||
width: { min: 360, ideal: 640 },
|
||||
height: { min: 360, ideal: 360 },
|
||||
framerate: 10
|
||||
};
|
||||
return {width: {min:360,max:1920}, height: {min:360, max:1920}}; // same as default, but I didn't want to mess with framerates until I gave it all a try first
|
||||
}
|
||||
case 7:
|
||||
return {}; // same as default, but I didn't want to mess with framerates until I gave it all a try first
|
||||
return { // If the camera is recording in low-light, it may have a low framerate. It coudl also be recording at a very high resolution.
|
||||
width: { min: 360, ideal: 640 },
|
||||
height: { min: 360, ideal: 360 },
|
||||
framerate: 10
|
||||
};
|
||||
|
||||
case 8:
|
||||
return {width: {min:360,max:1920}, height: {min:360, max:1920}}; // same as default, but I didn't want to mess with framerates until I gave it all a try first
|
||||
case 9:
|
||||
return {framerate: 0 }; // Some Samsung Devices report they can only support a framerate of 0.
|
||||
default:
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
@ -918,7 +1091,13 @@ function grabVideo(quality=0, audio=false){
|
||||
var iOS = !!navigator.platform && /iPad|iPhone|iPod/.test(navigator.platform);
|
||||
|
||||
if (audio==true){
|
||||
audio = {deviceId: {exact: audioSelect.value}}
|
||||
audio = {deviceId: {exact: audioSelect.value}};
|
||||
if (urlParams.has('stereo')){
|
||||
audio.echoCancellation = false;
|
||||
audio.autoGainControl = false;
|
||||
audio.noiseSuppression = false;
|
||||
}
|
||||
|
||||
}
|
||||
var constraints = {
|
||||
audio: audio,
|
||||
@ -953,7 +1132,7 @@ function grabVideo(quality=0, audio=false){
|
||||
navigator.mediaDevices.getUserMedia(constraints).then(function(stream){
|
||||
if (audio ==false){
|
||||
stream.getTracks().forEach(function(track) { // We don't want to keep it without audio; so we are going to try to add audio now.
|
||||
track.stop();
|
||||
track.stop();
|
||||
});
|
||||
log("GOT IT BUT WITH NO AUDIO");
|
||||
activatedPreview = false;
|
||||
@ -964,88 +1143,94 @@ function grabVideo(quality=0, audio=false){
|
||||
}
|
||||
}).catch(function(e){
|
||||
activatedPreview = false;
|
||||
errorlog(e);
|
||||
if (e.name === "OverconstrainedError"){
|
||||
errorlog(e.message);
|
||||
log("Resolution didn't work");
|
||||
} else if (e.name === "NotReadableError"){
|
||||
alert("Error Listing Media Devices.\n\nThe default Camera may already be in use with another app. Typically webcams can only be accessed by one program at a time.\n\nThe selected device may also not be supported.");
|
||||
if (iOS){
|
||||
alert("An error occured. Upgrading to at least iOS 13.4 should fix this glitch from happening again");
|
||||
} else {
|
||||
alert("Error Listing Media Devices.\n\nThe default Camera may already be in use with another app. Typically webcams can only be accessed by one program at a time.\n\nThe selected device may also not be supported.");
|
||||
}
|
||||
activatedPreview=true;
|
||||
return;
|
||||
} else if (e.name === "NavigatorUserMediaError"){
|
||||
alert("Unknown error: 'NavigatorUserMediaError'");
|
||||
return;
|
||||
} else {
|
||||
errorlog(e);
|
||||
errorlog("An unknown camera error occured");
|
||||
}
|
||||
if (quality<=8){
|
||||
grabVideo(quality+1);
|
||||
} else {
|
||||
errorlog(e);
|
||||
activatedPreview=true;
|
||||
alert("Camera is over-constrained. Please report which camera/device/browser you are using to steve@seguin.email");
|
||||
}
|
||||
});
|
||||
},0);
|
||||
}
|
||||
if (quality<=9){
|
||||
grabVideo(quality+1);
|
||||
} else {
|
||||
errorlog("********Camera failed to work");
|
||||
activatedPreview=true;
|
||||
alert("Camera failed to load. Please report which camera/device/browser you are using to steve@seguin.email");
|
||||
}
|
||||
});
|
||||
},0);
|
||||
}
|
||||
|
||||
var activatedPreview = false;
|
||||
function previewWebcam(){
|
||||
if( activatedPreview == true){log("activeated preview return");return;}
|
||||
activatedPreview = true;
|
||||
var activatedPreview = false;
|
||||
function previewWebcam(){
|
||||
if( activatedPreview == true){log("activeated preview return");return;}
|
||||
activatedPreview = true;
|
||||
|
||||
var audioSelect = document.querySelector('select#audioSource');
|
||||
var videoSelect = document.querySelector('select#videoSource');
|
||||
var audioSelect = document.querySelector('select#audioSource');
|
||||
var videoSelect = document.querySelector('select#videoSource');
|
||||
|
||||
var constraints = {audio:true, video:true };
|
||||
var constraints = {audio:true, video:true };
|
||||
|
||||
|
||||
window.setTimeout(() => {
|
||||
window.setTimeout(() => {
|
||||
|
||||
var oldstream= document.getElementById('previewWebcam').srcObject;
|
||||
if (oldstream){
|
||||
oldstream.getTracks().forEach(function(track) {
|
||||
track.stop();
|
||||
});
|
||||
}
|
||||
var oldstream= document.getElementById('previewWebcam').srcObject;
|
||||
if (oldstream){
|
||||
oldstream.getTracks().forEach(function(track) {
|
||||
track.stop();
|
||||
});
|
||||
}
|
||||
|
||||
navigator.mediaDevices.getUserMedia(constraints).then(function(stream){ // Apple needs thi to happen before I can access EnumerateDevices.
|
||||
//document.getElementById('previewWebcam').srcObject=stream;
|
||||
stream.getTracks().forEach(function(track) { // We don't want to keep it without audio; so we are going to try to add audio now.
|
||||
track.stop();
|
||||
});
|
||||
enumerateDevices().then(gotDevices).then(function(){
|
||||
navigator.mediaDevices.getUserMedia(constraints).then(function(stream){ // Apple needs thi to happen before I can access EnumerateDevices.
|
||||
//document.getElementById('previewWebcam').srcObject=stream;
|
||||
stream.getTracks().forEach(function(track) { // We don't want to keep it without audio; so we are going to try to add audio now.
|
||||
track.stop();
|
||||
});
|
||||
enumerateDevices().then(gotDevices).then(function(){
|
||||
|
||||
var audioSelect = document.querySelector('select#audioSource');
|
||||
var videoSelect = document.querySelector('select#videoSource');
|
||||
var audioSelect = document.querySelector('select#audioSource');
|
||||
var videoSelect = document.querySelector('select#videoSource');
|
||||
|
||||
audioSelect.onchange = function(){log("AUDIO source CHANGED");activatedPreview=false;grabVideo();};
|
||||
videoSelect.onchange = function(){log("video source changed");activatedPreview=false;grabVideo();};
|
||||
activatedPreview = false;
|
||||
grabVideo();
|
||||
audioSelect.onchange = function(){log("AUDIO source CHANGED");activatedPreview=false;grabVideo();};
|
||||
videoSelect.onchange = function(){log("video source changed");activatedPreview=false;grabVideo();};
|
||||
activatedPreview = false;
|
||||
grabVideo();
|
||||
|
||||
}).catch(handleError);
|
||||
}).catch(function(e){
|
||||
if (e.name === "NotReadableError"){
|
||||
window.setTimeout(() => {
|
||||
enumerateDevices().then(gotDevices).then(function(){
|
||||
}).catch(handleError);
|
||||
}).catch(function(e){
|
||||
if (e.name === "NotReadableError"){
|
||||
window.setTimeout(() => {
|
||||
enumerateDevices().then(gotDevices).then(function(){
|
||||
|
||||
var audioSelect = document.querySelector('select#audioSource');
|
||||
var videoSelect = document.querySelector('select#videoSource');
|
||||
var audioSelect = document.querySelector('select#audioSource');
|
||||
var videoSelect = document.querySelector('select#videoSource');
|
||||
|
||||
audioSelect.onchange = function(){log("AUDIO source CHANGED");activatedPreview=false;grabVideo();};
|
||||
videoSelect.onchange = function(){log("video source changed");activatedPreview=false;grabVideo();};
|
||||
activatedPreview = false;
|
||||
grabVideo();
|
||||
audioSelect.onchange = function(){log("AUDIO source CHANGED");activatedPreview=false;grabVideo();};
|
||||
videoSelect.onchange = function(){log("video source changed");activatedPreview=false;grabVideo();};
|
||||
activatedPreview = false;
|
||||
grabVideo();
|
||||
|
||||
}).catch(handleError);
|
||||
},0);
|
||||
} else if (e.name === "NotAllowedError"){
|
||||
alert("Error: Cannot access media devices \n\nPlease ensure both CAMERA and MICROPHONE permissions are allowed for this website to continue");
|
||||
} else {
|
||||
errorlog(e);
|
||||
}
|
||||
});
|
||||
},0);
|
||||
}
|
||||
}).catch(handleError);
|
||||
},0);
|
||||
} else if (e.name === "NotAllowedError"){
|
||||
alert("Error: Cannot access media devices \n\nPlease ensure both CAMERA and MICROPHONE permissions are allowed for this website to continue");
|
||||
} else {
|
||||
errorlog(e);
|
||||
}
|
||||
});
|
||||
},0);
|
||||
}
|
||||
|
||||
|
||||
function checkOBS(){
|
||||
@ -1112,7 +1297,7 @@ function generateQRPage(ele){
|
||||
}
|
||||
|
||||
|
||||
var urlParams = new URLSearchParams(window.location.search);
|
||||
|
||||
if (urlParams.has('streamid')){
|
||||
document.getElementById("container-4").className = 'column columnfade';
|
||||
document.getElementById("container-3").className = 'column columnfade';
|
||||
@ -1124,42 +1309,42 @@ if (urlParams.has('streamid')){
|
||||
document.getElementById("head1").className = 'advanced';
|
||||
document.getElementById("head2").className = 'advanced';
|
||||
document.getElementById("head3").className = 'advanced';
|
||||
document.getElementById("roomid").innerHTML = urlParams.get('streamid');
|
||||
|
||||
document.getElementById("mainmenu").style.backgroundImage = "url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8c3ZnIHdpZHRoPSI0MHB4IiBoZWlnaHQ9IjQwcHgiIHZpZXdCb3g9IjAgMCA0MCA0MCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWw6c3BhY2U9InByZXNlcnZlIiBzdHlsZT0iZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjEuNDE0MjE7IiB4PSIwcHgiIHk9IjBweCI+CiAgICA8ZGVmcz4KICAgICAgICA8c3R5bGUgdHlwZT0idGV4dC9jc3MiPjwhW0NEQVRBWwogICAgICAgICAgICBALXdlYmtpdC1rZXlmcmFtZXMgc3BpbiB7CiAgICAgICAgICAgICAgZnJvbSB7CiAgICAgICAgICAgICAgICAtd2Via2l0LXRyYW5zZm9ybTogcm90YXRlKDBkZWcpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHRvIHsKICAgICAgICAgICAgICAgIC13ZWJraXQtdHJhbnNmb3JtOiByb3RhdGUoLTM1OWRlZykKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgQGtleWZyYW1lcyBzcGluIHsKICAgICAgICAgICAgICBmcm9tIHsKICAgICAgICAgICAgICAgIHRyYW5zZm9ybTogcm90YXRlKDBkZWcpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHRvIHsKICAgICAgICAgICAgICAgIHRyYW5zZm9ybTogcm90YXRlKC0zNTlkZWcpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHN2ZyB7CiAgICAgICAgICAgICAgICAtd2Via2l0LXRyYW5zZm9ybS1vcmlnaW46IDUwJSA1MCU7CiAgICAgICAgICAgICAgICAtd2Via2l0LWFuaW1hdGlvbjogc3BpbiAxLjVzIGxpbmVhciBpbmZpbml0ZTsKICAgICAgICAgICAgICAgIC13ZWJraXQtYmFja2ZhY2UtdmlzaWJpbGl0eTogaGlkZGVuOwogICAgICAgICAgICAgICAgYW5pbWF0aW9uOiBzcGluIDEuNXMgbGluZWFyIGluZmluaXRlOwogICAgICAgICAgICB9CiAgICAgICAgXV0+PC9zdHlsZT4KICAgIDwvZGVmcz4KICAgIDxnIGlkPSJvdXRlciI+CiAgICAgICAgPGc+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMCwwQzIyLjIwNTgsMCAyMy45OTM5LDEuNzg4MTMgMjMuOTkzOSwzLjk5MzlDMjMuOTkzOSw2LjE5OTY4IDIyLjIwNTgsNy45ODc4MSAyMCw3Ljk4NzgxQzE3Ljc5NDIsNy45ODc4MSAxNi4wMDYxLDYuMTk5NjggMTYuMDA2MSwzLjk5MzlDMTYuMDA2MSwxLjc4ODEzIDE3Ljc5NDIsMCAyMCwwWiIgc3R5bGU9ImZpbGw6YmxhY2s7Ii8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8cGF0aCBkPSJNNS44NTc4Niw1Ljg1Nzg2QzcuNDE3NTgsNC4yOTgxNSA5Ljk0NjM4LDQuMjk4MTUgMTEuNTA2MSw1Ljg1Nzg2QzEzLjA2NTgsNy40MTc1OCAxMy4wNjU4LDkuOTQ2MzggMTEuNTA2MSwxMS41MDYxQzkuOTQ2MzgsMTMuMDY1OCA3LjQxNzU4LDEzLjA2NTggNS44NTc4NiwxMS41MDYxQzQuMjk4MTUsOS45NDYzOCA0LjI5ODE1LDcuNDE3NTggNS44NTc4Niw1Ljg1Nzg2WiIgc3R5bGU9ImZpbGw6cmdiKDIxMCwyMTAsMjEwKTsiLz4KICAgICAgICA8L2c+CiAgICAgICAgPGc+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMCwzMi4wMTIyQzIyLjIwNTgsMzIuMDEyMiAyMy45OTM5LDMzLjgwMDMgMjMuOTkzOSwzNi4wMDYxQzIzLjk5MzksMzguMjExOSAyMi4yMDU4LDQwIDIwLDQwQzE3Ljc5NDIsNDAgMTYuMDA2MSwzOC4yMTE5IDE2LjAwNjEsMzYuMDA2MUMxNi4wMDYxLDMzLjgwMDMgMTcuNzk0MiwzMi4wMTIyIDIwLDMyLjAxMjJaIiBzdHlsZT0iZmlsbDpyZ2IoMTMwLDEzMCwxMzApOyIvPgogICAgICAgIDwvZz4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggZD0iTTI4LjQ5MzksMjguNDkzOUMzMC4wNTM2LDI2LjkzNDIgMzIuNTgyNCwyNi45MzQyIDM0LjE0MjEsMjguNDkzOUMzNS43MDE5LDMwLjA1MzYgMzUuNzAxOSwzMi41ODI0IDM0LjE0MjEsMzQuMTQyMUMzMi41ODI0LDM1LjcwMTkgMzAuMDUzNiwzNS43MDE5IDI4LjQ5MzksMzQuMTQyMUMyNi45MzQyLDMyLjU4MjQgMjYuOTM0MiwzMC4wNTM2IDI4LjQ5MzksMjguNDkzOVoiIHN0eWxlPSJmaWxsOnJnYigxMDEsMTAxLDEwMSk7Ii8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8cGF0aCBkPSJNMy45OTM5LDE2LjAwNjFDNi4xOTk2OCwxNi4wMDYxIDcuOTg3ODEsMTcuNzk0MiA3Ljk4NzgxLDIwQzcuOTg3ODEsMjIuMjA1OCA2LjE5OTY4LDIzLjk5MzkgMy45OTM5LDIzLjk5MzlDMS43ODgxMywyMy45OTM5IDAsMjIuMjA1OCAwLDIwQzAsMTcuNzk0MiAxLjc4ODEzLDE2LjAwNjEgMy45OTM5LDE2LjAwNjFaIiBzdHlsZT0iZmlsbDpyZ2IoMTg3LDE4NywxODcpOyIvPgogICAgICAgIDwvZz4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggZD0iTTUuODU3ODYsMjguNDkzOUM3LjQxNzU4LDI2LjkzNDIgOS45NDYzOCwyNi45MzQyIDExLjUwNjEsMjguNDkzOUMxMy4wNjU4LDMwLjA1MzYgMTMuMDY1OCwzMi41ODI0IDExLjUwNjEsMzQuMTQyMUM5Ljk0NjM4LDM1LjcwMTkgNy40MTc1OCwzNS43MDE5IDUuODU3ODYsMzQuMTQyMUM0LjI5ODE1LDMyLjU4MjQgNC4yOTgxNSwzMC4wNTM2IDUuODU3ODYsMjguNDkzOVoiIHN0eWxlPSJmaWxsOnJnYigxNjQsMTY0LDE2NCk7Ii8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8cGF0aCBkPSJNMzYuMDA2MSwxNi4wMDYxQzM4LjIxMTksMTYuMDA2MSA0MCwxNy43OTQyIDQwLDIwQzQwLDIyLjIwNTggMzguMjExOSwyMy45OTM5IDM2LjAwNjEsMjMuOTkzOUMzMy44MDAzLDIzLjk5MzkgMzIuMDEyMiwyMi4yMDU4IDMyLjAxMjIsMjBDMzIuMDEyMiwxNy43OTQyIDMzLjgwMDMsMTYuMDA2MSAzNi4wMDYxLDE2LjAwNjFaIiBzdHlsZT0iZmlsbDpyZ2IoNzQsNzQsNzQpOyIvPgogICAgICAgIDwvZz4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggZD0iTTI4LjQ5MzksNS44NTc4NkMzMC4wNTM2LDQuMjk4MTUgMzIuNTgyNCw0LjI5ODE1IDM0LjE0MjEsNS44NTc4NkMzNS43MDE5LDcuNDE3NTggMzUuNzAxOSw5Ljk0NjM4IDM0LjE0MjEsMTEuNTA2MUMzMi41ODI0LDEzLjA2NTggMzAuMDUzNiwxMy4wNjU4IDI4LjQ5MzksMTEuNTA2MUMyNi45MzQyLDkuOTQ2MzggMjYuOTM0Miw3LjQxNzU4IDI4LjQ5MzksNS44NTc4NloiIHN0eWxlPSJmaWxsOnJnYig1MCw1MCw1MCk7Ii8+CiAgICAgICAgPC9nPgogICAgPC9nPgo8L3N2Zz4K')";
|
||||
|
||||
document.getElementById("mainmenu").style.backgroundRepeat = "no-repeat";
|
||||
document.getElementById("mainmenu").style.backgroundPosition = "bottom center";
|
||||
document.getElementById("mainmenu").style.minHeight = "300px";
|
||||
document.getElementById("mainmenu").style.backgroundSize = "100px 100px";
|
||||
document.getElementById("mainmenu").innerHTML = '<font style="color:#666"><h1>Attempting to load video stream.</h1></font>';
|
||||
document.getElementById("mainmenu").style.backgroundRepeat = "no-repeat";
|
||||
document.getElementById("mainmenu").style.backgroundPosition = "bottom center";
|
||||
document.getElementById("mainmenu").style.minHeight = "300px";
|
||||
document.getElementById("mainmenu").style.backgroundSize = "100px 100px";
|
||||
document.getElementById("mainmenu").innerHTML = '<font style="color:#666"><h1>Attempting to load video stream.</h1></font>';
|
||||
|
||||
setTimeout(function(){
|
||||
try{
|
||||
if (urlParams.get("streamid")){
|
||||
if (document.getElementById("mainmenu")){
|
||||
document.getElementById("mainmenu").innerHTML += '<font style="color:#EEE">If the stream does not load within a few seconds, the stream may not be available or some other error has occured. If the issue persists, please check out the <a href="https://reddit.com/r/obsninja">https://reddit.com/r/obsninja</a> for possible solutions or contact <a href="mailto:steve@seguin.email" target="_top">steve@seguin.email</a>.</font><br/><button onclick="location.reload();">Retry Connecting</button><br/>';
|
||||
setTimeout(function(){
|
||||
try{
|
||||
if (urlParams.get("streamid")){
|
||||
if (document.getElementById("mainmenu")){
|
||||
document.getElementById("mainmenu").innerHTML += '<font style="color:#EEE">If the stream does not load within a few seconds, the stream may not be available or some other error has occured. If the issue persists, please check out the <a href="https://reddit.com/r/obsninja">https://reddit.com/r/obsninja</a> for possible solutions or contact <a href="mailto:steve@seguin.email" target="_top">steve@seguin.email</a>.</font><br/><button onclick="location.reload();">Retry Connecting</button><br/>';
|
||||
|
||||
document.getElementById("mainmenu").innerHTML += '<div id="qrcode" style="background-color:white;display:inline-block;color:black;max-width:300px;padding:20px;"><h2 style="color:black">Stream Invite URL:</h2><p><a href="https://' + location.hostname+ location.pathname + '?permaid=' + session.streamID + '">https://' + location.hostname + location.pathname + '?permaid=' + urlParams.get("streamid") + '</a></p><br /></div>';
|
||||
var qrcode = new QRCode(document.getElementById("qrcode"), {
|
||||
width : 300,
|
||||
height : 300,
|
||||
colorDark : "#000000",
|
||||
colorLight : "#FFFFFF",
|
||||
useSVG: false
|
||||
});
|
||||
qrcode.makeCode('https://' + location.hostname + location.pathname + '?permaid=' + urlParams.get("streamid"));
|
||||
retry = setInterval(function(){
|
||||
if (document.getElementById("mainmenu")){
|
||||
play(urlParams.get('streamid'));
|
||||
} else {
|
||||
clearInterval(retry);
|
||||
}
|
||||
},10000)
|
||||
}}
|
||||
} catch(e){
|
||||
errorlog("Error handling QR Code failure");
|
||||
}
|
||||
},2000);
|
||||
document.getElementById("mainmenu").innerHTML += '<div id="qrcode" style="background-color:white;display:inline-block;color:black;max-width:300px;padding:20px;"><h2 style="color:black">Stream Invite URL:</h2><p><a href="https://' + location.hostname+ location.pathname + '?permaid=' + session.streamID + '">https://' + location.hostname + location.pathname + '?permaid=' + urlParams.get("streamid") + '</a></p><br /></div>';
|
||||
var qrcode = new QRCode(document.getElementById("qrcode"), {
|
||||
width : 300,
|
||||
height : 300,
|
||||
colorDark : "#000000",
|
||||
colorLight : "#FFFFFF",
|
||||
useSVG: false
|
||||
});
|
||||
qrcode.makeCode('https://' + location.hostname + location.pathname + '?permaid=' + urlParams.get("streamid"));
|
||||
retry = setInterval(function(){
|
||||
if (document.getElementById("mainmenu")){
|
||||
play(urlParams.get('streamid'));
|
||||
} else {
|
||||
clearInterval(retry);
|
||||
}
|
||||
},10000)
|
||||
}}
|
||||
} catch(e){
|
||||
errorlog("Error handling QR Code failure");
|
||||
}
|
||||
},2000);
|
||||
|
||||
log("auto playing");
|
||||
|
||||
@ -1333,6 +1518,10 @@ function poker(){
|
||||
<div class='credits'>Icons made by <a href="https://www.flaticon.com/authors/lucy-g" title="Lucy G">Lucy G</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a> is licensed by <a href="https://creativecommons.org/licenses/by/3.0/" title="Creative Commons BY 3.0" target="_blank">CC 3.0 BY</a> and by <a href="https://www.flaticon.com/authors/gregor-cresnar" title="Gregor Cresnar">Gregor Cresnar</a> from <a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a></div>
|
||||
</div>
|
||||
<div style="margin:0;border:0;padding:0;width:100%;height:100%;" id="gridlayout"></div>
|
||||
<div id="controls_blank" style="display:none"><center>
|
||||
<button>Enable</button><button onclick="directMute(this.parentNode.parentNode);">Mute</button><button onclick="directVisibility(this.parentNode.parentNode);">Pause</button><input type="range" min="0" max="100" onclick="directVolume(this.parentNode.parentNode);"><br />
|
||||
<a href="https://obs.ninja/?streamid=xxxxx">https://obs.ninja/?streamid=xxxxx</a>
|
||||
</center></div>
|
||||
|
||||
</body>
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user