mirror of
https://github.com/eliasstepanik/vdo.ninja.git
synced 2026-01-10 21:28:34 +00:00
battery status and other fixes
This commit is contained in:
parent
23e84322df
commit
b989e3dff5
55
codecs.html
55
codecs.html
@ -16,7 +16,16 @@ function getSupportedMimeTypes(media, types, codecs) {
|
||||
mimeType+';codecs:"'+codec.toUpperCase()+', '+codec2.toUpperCase()+'"'
|
||||
].forEach(variation => {
|
||||
if (isSupported(variation)){
|
||||
supported.push(variation);
|
||||
try {
|
||||
options.mimeType = variation;
|
||||
new MediaRecorder(stream, options);
|
||||
|
||||
mediaSource.addSourceBuffer(variation);
|
||||
|
||||
supported.push(variation);
|
||||
} catch(e){
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
}));
|
||||
});
|
||||
@ -26,26 +35,46 @@ function getSupportedMimeTypes(media, types, codecs) {
|
||||
return supported;
|
||||
};
|
||||
|
||||
// Usage ------------------
|
||||
|
||||
var options = {};
|
||||
options.videoBitsPerSecond = parseInt(2500 * 1024);
|
||||
|
||||
const videoTypes = ["webm", "ogg", "mp4", "x-matroska"];
|
||||
const audioTypes = ["webm", "ogg", "mp3", "x-matroska"];
|
||||
const codecs = ["vp9", "vp9.0", "vp8", "vp8.0", "avc1", "av1", "h265", "h.265", "h264", "h.264"]
|
||||
const acodecs = ["opus"];
|
||||
|
||||
const supportedVideos = getSupportedMimeTypes("video", videoTypes, codecs);
|
||||
const supportedAudios = getSupportedMimeTypes("audio", audioTypes, codecs);
|
||||
|
||||
console.log('-- Top supported Video : ', supportedVideos[0])
|
||||
console.log('-- Top supported Audio : ', supportedAudios[0])
|
||||
console.log('-- All supported Videos : ', supportedVideos)
|
||||
console.log('-- All supported Audios : ', supportedAudios)
|
||||
const acodecs = ["opus", "pcm", "aac", "mpeg", "mp4a", "mp3", "vorbis"];
|
||||
|
||||
document.getElementById("output").innerHTML= "";
|
||||
var supportedVideos = null;
|
||||
var supportedAudios = null;
|
||||
// Usage ------------------
|
||||
var stream = null;
|
||||
var mediaSource = new MediaSource();
|
||||
|
||||
for (var i=0;i<supportedVideos.length;i++){
|
||||
document.getElementById("output").innerHTML += supportedVideos[i]+"<br/>";
|
||||
var video = document.createElement("video");
|
||||
video.autoplay = true;
|
||||
video.muted = false;
|
||||
video.setAttribute("playsinline","");
|
||||
video.src = URL.createObjectURL(mediaSource);
|
||||
|
||||
mediaSource.addEventListener('sourceopen', sourceOpen);
|
||||
console.log("1");
|
||||
function sourceOpen(e) {
|
||||
console.log("2");
|
||||
navigator.mediaDevices.getUserMedia({audio:true,video:true}).then(function(s) {
|
||||
stream = s;
|
||||
|
||||
supportedVideos = getSupportedMimeTypes("video", videoTypes, codecs);
|
||||
supportedAudios = getSupportedMimeTypes("audio", audioTypes, codecs);
|
||||
|
||||
for (var i=0;i<supportedVideos.length;i++){
|
||||
document.getElementById("output").innerHTML += supportedVideos[i]+"<br/>";
|
||||
}
|
||||
}).catch(function(err) {
|
||||
/* handle the error */
|
||||
});
|
||||
}
|
||||
|
||||
//for (var i=0;i<supportedAudios.length;i++){
|
||||
//document.getElementById("output").innerHTML += supportedAudios[i]+"<br/>";
|
||||
//}
|
||||
|
||||
56
index.html
56
index.html
@ -67,7 +67,7 @@
|
||||
<link itemprop="url" href="./media/vdoNinja_logo_full.png" />
|
||||
</span>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/CodecsHandler.js?ver=35"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=336"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=338"></script>
|
||||
<input id="zoomSlider" type="range" style="display: none;" />
|
||||
<div id="header">
|
||||
|
||||
@ -434,8 +434,8 @@
|
||||
</span>
|
||||
|
||||
<div id="selectImageTFLITE" style="display:none;margin-top:10px;">
|
||||
<img src="./media/bg_sample.webp" style="max-width:130px;max-height:73.5px;display:inline-block:margin:10px;cursor:pointer;" onclick="changeTFLiteImage(event, this);"/>
|
||||
<img src="./media/bg_sample2.webp" style="max-width:130px;max-height:73.5px;display:inline-block:margin:10px;cursor:pointer;" onclick="changeTFLiteImage(event, this);"/>
|
||||
<img src="./media/bg_sample.webp" loading="lazy" style="max-width:130px;max-height:73.5px;display:inline-block:margin:10px;cursor:pointer;" onclick="changeTFLiteImage(event, this);"/>
|
||||
<img src="./media/bg_sample2.webp" loading="lazy" style="max-width:130px;max-height:73.5px;display:inline-block:margin:10px;cursor:pointer;" onclick="changeTFLiteImage(event, this);"/>
|
||||
<label style="width:130px;display:inline-block;margin:0 10px; text-align: center; cursor:pointer;">
|
||||
<i class="las la-hdd" style="font-size: 3em;"></i><br />Select Local Image
|
||||
<input type="file" onchange="changeTFLiteImage(event, this)" accept="image/*" style="position: fixed; top: -100em; margin-left:10px; border:1px solid #555;">
|
||||
@ -474,7 +474,7 @@
|
||||
</h2>
|
||||
<div class="container-inner">
|
||||
<span>
|
||||
<video id="screenshare" autoplay="true" muted="true" loop src="./media/screenshare.webm" ></video>
|
||||
<video id="screenshare" autoplay="true" muted="true" loop src="./media/screenshare.webm" class="lazy" style='background-image: unset;'></video>
|
||||
</span>
|
||||
<br />
|
||||
<button class='gobutton' style="padding: 10px; font-size: 120%;" alt="clilck to select you screen to share" onclick="publishScreen()">
|
||||
@ -1286,6 +1286,22 @@
|
||||
<i class="las la-eye-slash"></i> <span data-translate="toggle-remote-display">Blind Guest</span>
|
||||
</button>
|
||||
|
||||
<font class="tooltip hidden" data-cluster="2" style="height: 0; border: 0;">
|
||||
<input data-action-type="volume" type="range" min="0" max="200" value="100" title="Remotely change the volume of this guest" oninput="remoteVolumeUI(this)" ondblclick="this.value=100;remoteVolume(this);remoteVolumeUI(this);" onchange="remoteVolume(this);" style="grid-column: 2; margin:5px; width: 93%; position: relative;top: 0.6em; background-color:#fff0;"/><span class="tooltiptext" style='float: right; overflow: auto; left: 40px; width: 2.5em; top: -13px; margin: 0; position:relative;font-family:"Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji", Times, Symbola, Aegyptus,Code2000, Code2001, Code2002, Musica, serif, LastResort;' >100</span>
|
||||
</font>
|
||||
|
||||
<span class="hidden" data-cluster="2" data-action-type="change-quality">
|
||||
<button style="width: 35.2px" data-action-type="change-quality1" title="Disable Video Preview" onclick="toggleQualityDirector(0, this.dataset.UUID, this);">
|
||||
<span data-translate="change-to-low-quality"> <i class="las la-video-slash"></i></span>
|
||||
</button>
|
||||
<button class="pressed" style="width:35.2px;" data-action-type="change-quality2" title="Low-Quality Preview" onclick="toggleQualityDirector(50, this.dataset.UUID, this);">
|
||||
<span data-translate="change-to-medium-quality"> <i class="las la-video"></i></span>
|
||||
</button>
|
||||
<button style="width: 35.2px" data-action-type="change-quality3" title="High-Quality Preview" onclick="toggleQualityDirector(1200, this.dataset.UUID, this);">
|
||||
<span data-translate="change-to-high-quality"> <i class="las la-binoculars"></i></span>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
<span class="hidden" data-cluster="2" data-action-type="ordering">
|
||||
<button style="width:34px;" data-action-type="order-down" title="Shift this Video Down in Order" onclick="changeOrder(-1,this.dataset.UUID);">
|
||||
<span data-translate="order-down"><i class="las la-minus"></i></span>
|
||||
@ -1329,23 +1345,6 @@
|
||||
</button>
|
||||
|
||||
|
||||
<font class="tooltip hidden" data-cluster="2" style="height: 0; border: 0;">
|
||||
<input data-action-type="volume" type="range" min="0" max="200" value="100" title="Remotely change the volume of this guest" oninput="remoteVolumeUI(this)" ondblclick="this.value=100;remoteVolume(this);remoteVolumeUI(this);" onchange="remoteVolume(this);" style="grid-column: 2; margin:5px; width: 93%; position: relative;top: 0.6em; background-color:#fff0;"/><span class="tooltiptext" style='float: right; overflow: auto; left: 40px; width: 2.5em; top: -13px; margin: 0; position:relative;font-family:"Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji", Times, Symbola, Aegyptus,Code2000, Code2001, Code2002, Musica, serif, LastResort;' >100</span>
|
||||
</font>
|
||||
|
||||
<span class="hidden" data-cluster="2" data-action-type="change-quality">
|
||||
<button style="width: 35.2px" data-action-type="change-quality1" title="Disable Video Preview" onclick="toggleQualityDirector(0, this.dataset.UUID, this);">
|
||||
<span data-translate="change-to-low-quality"> <i class="las la-video-slash"></i></span>
|
||||
</button>
|
||||
<button class="pressed" style="width:35.2px;" data-action-type="change-quality2" title="Low-Quality Preview" onclick="toggleQualityDirector(50, this.dataset.UUID, this);">
|
||||
<span data-translate="change-to-medium-quality"> <i class="las la-video"></i></span>
|
||||
</button>
|
||||
<button style="width: 35.2px" data-action-type="change-quality3" title="High-Quality Preview" onclick="toggleQualityDirector(1200, this.dataset.UUID, this);">
|
||||
<span data-translate="change-to-high-quality"> <i class="las la-binoculars"></i></span>
|
||||
</button>
|
||||
</span>
|
||||
|
||||
|
||||
<span id="channelGroup1" class="hidden" data-cluster="2">
|
||||
|
||||
<button style="width:35.2px;" data-action-type="add-channel" title="Set to Audio Channel 1" onclick="changeChannelOffset(this.dataset.UUID, 0);">
|
||||
@ -1545,8 +1544,8 @@
|
||||
<i class="las la-info-circle"></i>
|
||||
</span>
|
||||
<div id="selectImageTFLITE3" style="display:none;margin-top:10px;">
|
||||
<img src="./media/bg_sample.webp" style="max-width:130px;max-height:73.5px;display:inline-block:margin:10px;cursor:pointer;" onclick="changeTFLiteImage(event, this);"/>
|
||||
<img src="./media/bg_sample2.webp" style="max-width:130px;max-height:73.5px;display:inline-block:margin:10px;cursor:pointer;" onclick="changeTFLiteImage(event, this);"/>
|
||||
<img src="./media/bg_sample.webp" loading="lazy" style="max-width:130px;max-height:73.5px;display:inline-block:margin:10px;cursor:pointer;" onclick="changeTFLiteImage(event, this);"/>
|
||||
<img src="./media/bg_sample2.webp" loading="lazy" style="max-width:130px;max-height:73.5px;display:inline-block:margin:10px;cursor:pointer;" onclick="changeTFLiteImage(event, this);"/>
|
||||
<label style="width:130px;display:inline-block;margin:0 10px; text-align: center; cursor:pointer;">
|
||||
<i class="las la-hdd" style="font-size: 3em;"></i><br /><span data-translate="select-local-image">Select Local Image</span>
|
||||
<input type="file" accept="image/*" onchange="changeTFLiteImage(event, this)" style="position: fixed; top: -100em; margin-left:10px; border:1px solid #555;">
|
||||
@ -1740,10 +1739,13 @@
|
||||
<div id="userList">
|
||||
</div>
|
||||
</div>
|
||||
<div id="signalMeterTemplate" class="signal-meter" data-cpu="0" data-level="0">
|
||||
<div id="signalMeterTemplate" class="signal-meter advanced" data-cpu="0" data-level="0">
|
||||
<i class="las la-signal"></i>
|
||||
<i class="las la-fire-alt"></i>
|
||||
</div>
|
||||
<div id="batteryMeterTemplate" class="battery advanced" data-plugged="1">
|
||||
<div class="battery-level" style="height:100%;"></div>
|
||||
</div>
|
||||
<div id="voiceMeterTemplate" class="video-meter advanced">
|
||||
</div>
|
||||
<div id="voiceMeterTemplate2" class="video-meter2 advanced">
|
||||
@ -1763,7 +1765,7 @@
|
||||
</audio>
|
||||
<div class="gone" >
|
||||
<!-- This image is used when dragging elements -->
|
||||
<img src="./media/favicon-32x32.png" id="dragImage" />
|
||||
<img src="./media/favicon-32x32.png" id="dragImage" loading="lazy" />
|
||||
</div>
|
||||
<div id="request_info_prompt" style="display:none">
|
||||
</div>
|
||||
@ -1897,11 +1899,11 @@
|
||||
// session.introOnClean = true; // this will load the page with the webcam selection screen if &push or &room is in the URL; no need to use &webcam.
|
||||
</script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/aes.js"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="lib-js" src="./lib.js?ver=244"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="lib-js" src="./lib.js?ver=246"></script>
|
||||
<!--
|
||||
// If you wish to change branding, blank offers a good clean start.
|
||||
<script type="text/javascript" id="main-js" src="./main.js" data-translation="blank"></script>
|
||||
-->
|
||||
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=285"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=287"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
492
lib.js
492
lib.js
@ -1369,18 +1369,21 @@ function setupIncomingScreenTracking(v, UUID){ // SCREEN element.
|
||||
}
|
||||
}
|
||||
|
||||
v.addEventListener('resize', (e) => {
|
||||
v.addEventListener('resize', (e) => { // if the aspect ratio changes, then we might want to update the mixer. If audio only, then this doesn't matter.
|
||||
log("resize event");
|
||||
var aspectRatio = parseFloat(e.target.videoWidth/e.target.videoHeight);
|
||||
if (!aspectRatio){return;} // if Audio only, then we don't want to set or update any aspect ratio.
|
||||
|
||||
if (v.dataset.aspectRatio){
|
||||
if (aspectRatio != v.dataset.aspectRatio){
|
||||
v.dataset.aspectRatio = aspectRatio;
|
||||
setTimeout(function(){updateMixer();},1); // We don't want to run this on the first resize? just subsequent ones.
|
||||
}
|
||||
} else {
|
||||
log("ASPECT RATIO CHANGED");
|
||||
v.dataset.aspectRatio = aspectRatio;
|
||||
setTimeout(function(){updateMixer();},1);
|
||||
}
|
||||
v.dataset.aspectRatio = parseFloat(e.target.videoWidth/e.target.videoHeight);
|
||||
});
|
||||
|
||||
v.volume = 1.0; // play audio automatically
|
||||
@ -1644,7 +1647,7 @@ function setupIncomingVideoTracking(v, UUID){ // video element.
|
||||
warnlog("Vidieo element threw an error; going to reconnect it");
|
||||
session.rpcs[UUID].videoElement.stop();
|
||||
session.rpcs[UUID].videoElement.srcObject = null;
|
||||
session.rpcs[UUID].videoElement.srcObject = session.rpcs[UUID].streamSrc;
|
||||
session.rpcs[UUID].videoElement.srcObject = session.rpcs[UUID].streamSrc; // replaecd with updateIncomingVideoElement these days
|
||||
session.rpcs[UUID].videoElement.play();
|
||||
setTimeout(function(){updateMixer();},1);
|
||||
} catch(e){errorlog(e);}
|
||||
@ -1679,19 +1682,21 @@ function setupIncomingVideoTracking(v, UUID){ // video element.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
v.addEventListener('resize', (e) => {
|
||||
log("resize event");
|
||||
var aspectRatio = parseFloat(e.target.videoWidth/e.target.videoHeight);
|
||||
if (!aspectRatio){return;} // if Audio only, then we don't want to set or update any aspect ratio.
|
||||
|
||||
if (v.dataset.aspectRatio){
|
||||
if (aspectRatio != v.dataset.aspectRatio){
|
||||
v.dataset.aspectRatio = aspectRatio;
|
||||
setTimeout(function(){updateMixer();},1); // We don't want to run this on the first resize? just subsequent ones.
|
||||
}
|
||||
} else {
|
||||
log("ASPECT RATIO CHANGED");
|
||||
v.dataset.aspectRatio = aspectRatio;
|
||||
setTimeout(function(){updateMixer();},1);
|
||||
}
|
||||
v.dataset.aspectRatio = parseFloat(e.target.videoWidth/e.target.videoHeight);
|
||||
});
|
||||
|
||||
v.volume = 1.0; // play audio automatically
|
||||
@ -1734,7 +1739,6 @@ function setupIncomingVideoTracking(v, UUID){ // video element.
|
||||
session.rpcs[UUID].mutedStateScene = true;
|
||||
}
|
||||
|
||||
setTimeout(function(){updateMixer();},1);
|
||||
} else if (session.roomid!==false){
|
||||
if (session.cleanOutput){
|
||||
v.controls = false;
|
||||
@ -1743,19 +1747,9 @@ function setupIncomingVideoTracking(v, UUID){ // video element.
|
||||
} else {
|
||||
v.controls = true;
|
||||
}
|
||||
//if ((session.roomid==="") && (session.bitrate)){
|
||||
// let's keep the default bitrates, since this isn't a real room and bitrates are specified.
|
||||
//} //else if (session.novideo !== false){
|
||||
// if (session.novideo.includes(session.rpcs[UUID].streamID)){ // no video will have muted the video already anyways.
|
||||
// session.requestRateLimit(0,UUID, false);// optimizing audio here doesn't later get turned back on. let the automixer disable audio instead
|
||||
// }
|
||||
//} //else {
|
||||
// session.requestRateLimit(0,UUID, false);//// optimizing audio here doesn't later get turned back on. let the automixer disable audio instead
|
||||
//}
|
||||
setTimeout(function(){updateMixer();},1);
|
||||
|
||||
} else {
|
||||
v.style.display="block";
|
||||
setTimeout(function(){updateMixer();},1);
|
||||
}
|
||||
|
||||
|
||||
@ -2398,7 +2392,16 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
}
|
||||
}
|
||||
if (session.rpcs[i].videoMuted){
|
||||
continue;
|
||||
if (session.rpcs[i].videoElement.srcObject.getAudioTracks().length==0){ // if no audio track, no point in removing the video track, since it will just stall out then.
|
||||
continue; // easiest is to just not show anything if no video and no audio track.
|
||||
}
|
||||
if (session.rpcs[i].videoElement.srcObject){
|
||||
session.rpcs[i].videoElement.srcObject.getVideoTracks().forEach(track=>{
|
||||
session.rpcs[i].videoElement.srcObject.removeTrack(track);
|
||||
session.rpcs[i].videoElement.load();
|
||||
});
|
||||
}
|
||||
//continue; // currently disabling this, since we want to show it.
|
||||
} else if (session.rpcs[i].directorVideoMuted){
|
||||
continue;
|
||||
} else if (session.rpcs[i].virtualHangup){
|
||||
@ -2548,7 +2551,13 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
if (sscount && !session.layout){
|
||||
customLayout = {};
|
||||
console.log(sscount);
|
||||
if (mediaPool.length>=5){
|
||||
if (mediaPool.length>8){
|
||||
customLayout[sscount] = {"x":0,"y":20,"w":80,"h":80, "c": session.cover};
|
||||
} else if (mediaPool.length>=7){
|
||||
customLayout[sscount] = {"x":0,"y":25,"w":75,"h":75, "c": session.cover};
|
||||
} else if (mediaPool.length==5){
|
||||
customLayout[sscount] = {"x":0,"y":0,"w":75,"h":100, "c": session.cover};
|
||||
} else if (mediaPool.length>5){
|
||||
customLayout[sscount] = {"x":0,"y":33.333,"w":66.667,"h":66.667, "c": session.cover};
|
||||
} else {
|
||||
customLayout[sscount] = {"x":0,"y":0,"w":66.667,"h":100, "c": session.cover};
|
||||
@ -2563,12 +2572,8 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
} else if (mediaPool.length==4){
|
||||
customLayout[mediaPool[i].dataset.sid] = {"x":66.667,"y":posCount*33.333,"w":33.333,"h":33.333, "c":true};
|
||||
} else if (mediaPool.length==5){
|
||||
if (posCount==0){
|
||||
customLayout[mediaPool[i].dataset.sid] = {"x":33.333,"y":0,"w":33.333,"h":33.333, "c":true};
|
||||
} else {
|
||||
customLayout[mediaPool[i].dataset.sid] = {"x":66.667,"y":(posCount-1)*33.333,"w":33.333,"h":33.333, "c":true};
|
||||
}
|
||||
} else if (mediaPool.length>=6){
|
||||
customLayout[mediaPool[i].dataset.sid] = {"x":75,"y":(posCount)*25,"w":25,"h":25, "c":true};
|
||||
} else if (mediaPool.length==6){
|
||||
if (posCount==0){
|
||||
customLayout[mediaPool[i].dataset.sid] = {"x":0,"y":0,"w":33.333,"h":33.333, "c":true};
|
||||
} else if (posCount==1){
|
||||
@ -2576,6 +2581,28 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
} else {
|
||||
customLayout[mediaPool[i].dataset.sid] = {"x":66.667,"y":(posCount-2)*33.333,"w":33.333,"h":33.333, "c":true};
|
||||
}
|
||||
} else if (mediaPool.length>8){
|
||||
if (posCount==0){
|
||||
customLayout[mediaPool[i].dataset.sid] = {"x":0,"y":0,"w":20,"h":20, "c":true};
|
||||
} else if (posCount==1){
|
||||
customLayout[mediaPool[i].dataset.sid] = {"x":20,"y":0,"w":20,"h":20, "c":true};
|
||||
} else if (posCount==2){
|
||||
customLayout[mediaPool[i].dataset.sid] = {"x":40,"y":0,"w":20,"h":20, "c":true};
|
||||
} else if (posCount==3){
|
||||
customLayout[mediaPool[i].dataset.sid] = {"x":60,"y":0,"w":20,"h":20, "c":true};
|
||||
} else {
|
||||
customLayout[mediaPool[i].dataset.sid] = {"x":80,"y":(posCount-4)*20,"w":20,"h":20, "c":true};
|
||||
}
|
||||
} else if (mediaPool.length>=7){
|
||||
if (posCount==0){
|
||||
customLayout[mediaPool[i].dataset.sid] = {"x":0,"y":0,"w":25,"h":25, "c":true};
|
||||
} else if (posCount==1){
|
||||
customLayout[mediaPool[i].dataset.sid] = {"x":25,"y":0,"w":25,"h":25, "c":true};
|
||||
} else if (posCount==2){
|
||||
customLayout[mediaPool[i].dataset.sid] = {"x":50,"y":0,"w":25,"h":25, "c":true};
|
||||
} else {
|
||||
customLayout[mediaPool[i].dataset.sid] = {"x":75,"y":(posCount-3)*25,"w":25,"h":25, "c":true};
|
||||
}
|
||||
} else {
|
||||
customLayout[mediaPool[i].dataset.sid] = {"x":66.667,"y":posCount*33.333,"w":33.333,"h":33.333, "c":true};
|
||||
}
|
||||
@ -3162,34 +3189,40 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
}
|
||||
} catch(e){errorlog(e);}
|
||||
|
||||
if (("rotated" in vid) && vid.rotated){
|
||||
if (("rotated" in vid) && (vid.rotated!==false)){
|
||||
if (vid.rotated==90){
|
||||
vid.style.transform = "rotate(90deg)";
|
||||
var vh1 = vid.style.height;
|
||||
vid.style.height = vid.style.width;
|
||||
vid.style.width = vh1;
|
||||
// var vh1 = vid.style.height;
|
||||
// vid.style.height = vid.style.width;
|
||||
// vid.style.width = vh1;
|
||||
} else if (vid.rotated==270){
|
||||
vid.style.transform = "rotate(270deg)";
|
||||
var vh1 = vid.style.height;
|
||||
vid.style.height = vid.style.width;
|
||||
vid.style.width = vh1;
|
||||
// var vh1 = vid.style.height;
|
||||
// vid.style.height = vid.style.width;
|
||||
// vid.style.width = vh1;
|
||||
} else if (vid.rotated==180){
|
||||
vid.style.transform = "rotate(180deg)";
|
||||
// vid.style.width = "100%";
|
||||
// vid.style.height = "100%";
|
||||
} else if (!vid.rotated){
|
||||
vid.style.transform = "rotate(0deg)";
|
||||
// vid.style.width = "100%";
|
||||
// vid.style.height = "100%";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
holder.style.position = "absolute";
|
||||
vid.style.width = "100%";
|
||||
vid.style.height = "100%";
|
||||
|
||||
holder.style.position = "absolute";
|
||||
|
||||
if (session.cover){
|
||||
holder.style.width = "100%";
|
||||
holder.style.height = "100%";
|
||||
holder.style.left = 0;
|
||||
holder.style.top = 0;
|
||||
} else if (vid.videoWidth && vid.videoHeight){
|
||||
if (("rotated" in vid) && vid.rotated && ((vid.rotated==90) || (vid.rotated==270))){
|
||||
if (("rotated" in vid) && ((vid.rotated==90) || (vid.rotated==270))){
|
||||
var asw = wrw/vid.videoHeight;
|
||||
var ash = hrh/vid.videoWidth;
|
||||
if (asw < ash){
|
||||
@ -3239,6 +3272,21 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
vid.style.left = (parseFloat(holder.style.left) - (parseFloat(holder.style.height) - parseFloat(holder.style.width))/2) + "px";
|
||||
}
|
||||
//}
|
||||
} else if (("rotated" in vid) && (vid.rotated!==false)){
|
||||
var asw = wrw/vid.videoWidth;
|
||||
var ash = hrh/vid.videoHeight;
|
||||
vid.style.left = "unset";
|
||||
if (asw < ash){
|
||||
holder.style.width = Math.ceil(vid.videoWidth*asw)+"px";
|
||||
holder.style.height = Math.ceil(vid.videoHeight*asw)+"px";
|
||||
holder.style.left = Math.ceil((Math.ceil(w/rw) - Math.ceil(vid.videoWidth*asw))/2);
|
||||
holder.style.top = Math.ceil(( Math.ceil(h/rh) - Math.ceil(vid.videoHeight*asw))/2);
|
||||
} else {
|
||||
holder.style.width = Math.ceil(vid.videoWidth*ash)+"px";
|
||||
holder.style.height = Math.ceil(vid.videoHeight*ash)+"px";
|
||||
holder.style.left = Math.ceil((Math.ceil(w/rw) - Math.ceil(vid.videoWidth*ash))/2);
|
||||
holder.style.top = Math.ceil((Math.ceil(h/rh) - Math.ceil(vid.videoHeight*ash))/2);
|
||||
}
|
||||
} else {
|
||||
var asw = wrw/vid.videoWidth;
|
||||
var ash = hrh/vid.videoHeight;
|
||||
@ -3373,7 +3421,7 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
if (session.signalMeter){
|
||||
if (vid.dataset.UUID && !session.rpcs[vid.dataset.UUID].signalMeter){
|
||||
session.rpcs[vid.dataset.UUID].signalMeter = getById("signalMeterTemplate").cloneNode(true);
|
||||
//session.rpcs[vid.dataset.UUID].signalMeter.style.display = "block";
|
||||
session.rpcs[vid.dataset.UUID].signalMeter.classList.remove("advanced");
|
||||
session.rpcs[vid.dataset.UUID].signalMeter.id = "signalMeter_" + vid.dataset.UUID;
|
||||
session.rpcs[vid.dataset.UUID].signalMeter.dataset.level = 0;
|
||||
session.rpcs[vid.dataset.UUID].signalMeter.title = miscTranslations["signal-meter"];
|
||||
@ -4155,13 +4203,14 @@ function updateUserList(){
|
||||
getById("userList").innerHTML = "";
|
||||
|
||||
for (var UUID in session.rpcs){
|
||||
var track = false;
|
||||
if (session.rpcs[UUID].videoElement && session.rpcs[UUID].streamSrc && session.rpcs[UUID].streamSrc.getVideoTracks().length){
|
||||
if (session.rpcs[UUID].videoElement && session.rpcs[UUID].streamSrc && session.rpcs[UUID].streamSrc.getTracks().length){
|
||||
if (document.body.contains(session.rpcs[UUID].videoElement)){
|
||||
track=true;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if (((session.rpcs[UUID].videoMuted || (track==false && !session.rpcs[UUID].imageElement)) && !session.rpcs[UUID].canvas) || ( session.infocus && session.infocus!==UUID )){
|
||||
if ((session.rpcs[UUID].videoMuted || (!session.rpcs[UUID].imageElement && !session.rpcs[UUID].canvas)) || ( session.infocus && session.infocus!==UUID )){
|
||||
|
||||
if (session.directorList.indexOf(UUID)>=0){
|
||||
if (!session.rpcs[UUID].streamSrc){ // director not active yet, so we won't bother showing it.
|
||||
@ -7122,6 +7171,78 @@ function publishScreen() {
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
function updateForceRotate(mirror=null){
|
||||
if (session.orientation){
|
||||
try {
|
||||
var track = false;
|
||||
if (session.streamSrc){
|
||||
var tracks = session.streamSrc.getVideoTracks();
|
||||
if (tracks.length){
|
||||
track = tracks[0];
|
||||
}
|
||||
}
|
||||
if (!track){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const settings = track.getSettings();
|
||||
if ("width" in settings){
|
||||
if ("height" in settings){
|
||||
if (settings.width < settings.height){
|
||||
if (session.orientation=="landscape"){
|
||||
if (session.forceRotate==270){return;}
|
||||
session.forceRotate=270;
|
||||
} else {
|
||||
if (!session.forceRotate){return;}
|
||||
session.forceRotate = 0;
|
||||
}
|
||||
} else if (settings.width > settings.height){
|
||||
if (session.orientation=="portrait"){
|
||||
if (session.forceRotate==90){return;}
|
||||
session.forceRotate=90;
|
||||
} else {
|
||||
if (!session.forceRotate){return;}
|
||||
session.forceRotate = 0;
|
||||
}
|
||||
} else {
|
||||
if (!session.forceRotate){return;}
|
||||
session.forceRotate = 0;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
var msg = {};
|
||||
if (session.forceRotate!==false){
|
||||
if (session.rotate){
|
||||
msg.rotate_video = session.forceRotate + parseInt(session.rotate);
|
||||
} else {
|
||||
msg.rotate_video = session.forceRotate;
|
||||
}
|
||||
} else {
|
||||
msg.rotate_video = session.rotate;
|
||||
}
|
||||
|
||||
if (msg.rotate_video && (msg.rotate_video>=360)){
|
||||
msg.rotate_video-=360;
|
||||
}
|
||||
|
||||
session.sendMessage(msg);
|
||||
|
||||
if (mirror!==null){
|
||||
if (document.getElementById('previewWebcam')){
|
||||
applyMirror(mirror);
|
||||
}
|
||||
}
|
||||
|
||||
} catch(e){errorlog(e);}
|
||||
}
|
||||
}
|
||||
|
||||
function publishWebcam(btn = false) {
|
||||
if (btn) {
|
||||
if (btn.dataset.ready == "false") {
|
||||
@ -7167,12 +7288,18 @@ function publishWebcam(btn = false) {
|
||||
// no room, no viewing, viewing disabled
|
||||
session.manual = true;
|
||||
window.onresize = updateMixer;
|
||||
window.onorientationchange = function(){setTimeout(updateMixer, 200);};
|
||||
window.onorientationchange = function(){setTimeout(function(){
|
||||
updateForceRotate();
|
||||
updateMixer();
|
||||
}, 200);};
|
||||
} else {
|
||||
log("ROOM ID ENABLED");
|
||||
log("Update Mixer Event on REsize SET");
|
||||
window.onresize = updateMixer;
|
||||
window.onorientationchange = function(){setTimeout(updateMixer, 200);};
|
||||
window.onorientationchange = function(){setTimeout(function(){
|
||||
updateForceRotate();
|
||||
updateMixer();
|
||||
}, 200);};
|
||||
getById("main").style.overflow = "hidden";
|
||||
//session.cbr=0; // we're just going to override it
|
||||
|
||||
@ -8550,7 +8677,10 @@ function createRoomCallback(passAdd, passAdd2) {
|
||||
|
||||
|
||||
window.onresize = updateMixer;
|
||||
window.onorientationchange = function(){setTimeout(updateMixer, 200);};
|
||||
window.onorientationchange = function(){setTimeout(function(){
|
||||
updateForceRotate();
|
||||
updateMixer();
|
||||
}, 200);};
|
||||
getById("reshare").parentNode.removeChild(getById("reshare"));
|
||||
|
||||
|
||||
@ -8966,6 +9096,7 @@ function createControlBox(UUID, soloLink, streamID) {
|
||||
}
|
||||
session.rpcs[UUID].voiceMeter.id = "voiceMeter_" + UUID;
|
||||
session.rpcs[UUID].voiceMeter.dataset.level = 0;
|
||||
session.rpcs[UUID].voiceMeter.classList.remove("advanced");
|
||||
}
|
||||
|
||||
session.rpcs[UUID].remoteMuteElement = getById("muteStateTemplate").cloneNode(true);
|
||||
@ -9026,7 +9157,7 @@ function createControlBox(UUID, soloLink, streamID) {
|
||||
session.rpcs[UUID].signalMeter = getById("signalMeterTemplate").cloneNode(true);
|
||||
session.rpcs[UUID].signalMeter.id = "signalMeter_" + UUID;
|
||||
session.rpcs[UUID].signalMeter.dataset.level = 0;
|
||||
//session.rpcs[UUID].signalMeter.style.display = "block";
|
||||
session.rpcs[UUID].signalMeter.classList.remove("advanced");
|
||||
session.rpcs[UUID].signalMeter.dataset.UUID = UUID;
|
||||
session.rpcs[UUID].signalMeter.title = miscTranslations["signal-meter"];
|
||||
session.rpcs[UUID].signalMeter.addEventListener('click', function(e) { // show stats of video if double clicked
|
||||
@ -9049,8 +9180,38 @@ function createControlBox(UUID, soloLink, streamID) {
|
||||
} catch(e){errorlog(e);}
|
||||
});
|
||||
}
|
||||
|
||||
videoContainer.appendChild(session.rpcs[UUID].signalMeter);
|
||||
|
||||
////////
|
||||
if (!session.rpcs[UUID].batteryMeter){
|
||||
session.rpcs[UUID].batteryMeter = getById("batteryMeterTemplate").cloneNode(true);
|
||||
session.rpcs[UUID].batteryMeter.id = "batteryMeter_" + UUID;
|
||||
session.rpcs[UUID].batteryMeter.classList.remove("advanced");
|
||||
if (session.rpcs[UUID].stats.info && (session.rpcs[UUID].stats.info.power_level!==null)){
|
||||
var level = session.rpcs[UUID].batteryMeter.querySelector(".battery-level");
|
||||
if (level){
|
||||
var value = session.rpcs[UUID].stats.info.power_level;
|
||||
if (value > 100){value = 100;}
|
||||
if (value < 0){ value = 0;}
|
||||
level.style.height = parseInt(value)+"%";
|
||||
if (value<10){
|
||||
session.rpcs[UUID].batteryMeter.classList.add("alert");
|
||||
} else if (value<25){
|
||||
session.rpcs[UUID].batteryMeter.classList.add("warn");
|
||||
}
|
||||
session.rpcs[UUID].batteryMeter.title = level+"% battery remaining";
|
||||
}
|
||||
}
|
||||
if (session.rpcs[UUID].stats.info && ("plugged_in" in session.rpcs[UUID].stats.info) && (session.rpcs[UUID].stats.info.plugged_in===false)){
|
||||
session.rpcs[UUID].batteryMeter.dataset.plugged = "0";
|
||||
} else {
|
||||
session.rpcs[UUID].batteryMeter.dataset.plugged = "1";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
videoContainer.appendChild(session.rpcs[UUID].batteryMeter);
|
||||
}
|
||||
|
||||
videoContainer.appendChild(session.rpcs[UUID].voiceMeter);
|
||||
@ -9536,7 +9697,7 @@ function gotDevices(deviceInfos) { // https://github.com/webrtc/samples/blob/gh-
|
||||
}
|
||||
|
||||
|
||||
if ((session.videoDevice) && (session.videoDevice !== 1)) { // this sorts according to users's manual selection
|
||||
if ((session.videoDevice) && (session.videoDevice !== 1)){ // this sorts according to users's manual selection
|
||||
var tmp = [];
|
||||
for (let i = 0; i !== deviceInfos.length; ++i) {
|
||||
deviceInfo = deviceInfos[i];
|
||||
@ -9559,6 +9720,39 @@ function gotDevices(deviceInfos) { // https://github.com/webrtc/samples/blob/gh-
|
||||
deviceInfos = tmp;
|
||||
log("VDECICE:" + session.videoDevice);
|
||||
log(deviceInfos);
|
||||
} else if ((session.videoDevice===false) && session.facingMode){
|
||||
var tmp = [];
|
||||
if (session.facingMode=="environment"){
|
||||
for (let i = 0; i !== deviceInfos.length; ++i) {
|
||||
deviceInfo = deviceInfos[i];
|
||||
if ((deviceInfo.kind === 'videoinput') && (deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase().includes("back"))) {
|
||||
tmp.push(deviceInfo);
|
||||
log("V DEVICE FOUND = " + deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase());
|
||||
} else if ((deviceInfo.kind === 'videoinput') && (deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase().includes("rear"))) {
|
||||
tmp.push(deviceInfo);
|
||||
log("V DEVICE FOUND = " + deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase());
|
||||
}
|
||||
}
|
||||
} else if (session.facingMode=="user"){
|
||||
for (let i = 0; i !== deviceInfos.length; ++i) {
|
||||
deviceInfo = deviceInfos[i];
|
||||
if ((deviceInfo.kind === 'videoinput') && (deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase().includes("front"))) {
|
||||
tmp.push(deviceInfo);
|
||||
log("V DEVICE FOUND = " + deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let i = 0; i !== deviceInfos.length; ++i) {
|
||||
deviceInfo = deviceInfos[i];
|
||||
if (!((deviceInfo.kind === 'videoinput') && (deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase().includes(session.videoDevice)))) {
|
||||
if (deviceInfo.deviceId !== session.videoDevice){
|
||||
tmp.push(deviceInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
deviceInfos = tmp;
|
||||
log("VDECICE:" + session.videoDevice);
|
||||
log(deviceInfos);
|
||||
}
|
||||
|
||||
|
||||
@ -10717,25 +10911,27 @@ function applyMirror(mirror, eleName = 'previewWebcam') { // true unmirrors as i
|
||||
}
|
||||
}
|
||||
if (eleName == 'previewWebcam'){
|
||||
if (session.rotate=="90"){
|
||||
if (getById(eleName).style.transform){
|
||||
getById(eleName).style.transform += " rotate(90deg)";
|
||||
var rotate = 0;
|
||||
|
||||
if (session.forceRotate!==false){
|
||||
if (session.rotate){
|
||||
rotate = session.forceRotate + parseInt(session.rotate);
|
||||
} else {
|
||||
getById(eleName).style.transform = "rotate(90deg)";
|
||||
rotate = session.forceRotate;
|
||||
}
|
||||
getById(eleName).classList.add("rotate");
|
||||
} else if (session.rotate=="270"){
|
||||
} else {
|
||||
rotate = session.rotate;
|
||||
}
|
||||
|
||||
if (rotate && (rotate>=360)){
|
||||
rotate-=360;
|
||||
}
|
||||
|
||||
if (rotate){
|
||||
if (getById(eleName).style.transform){
|
||||
getById(eleName).style.transform += " rotate(270deg)";
|
||||
getById(eleName).style.transform += " rotate("+rotate+"deg)";
|
||||
} else {
|
||||
getById(eleName).style.transform = "rotate(270deg)";
|
||||
}
|
||||
getById(eleName).classList.add("rotate");
|
||||
} else if (session.rotate){
|
||||
if (getById(eleName).style.transform){
|
||||
getById(eleName).style.transform += " rotate("+session.rotate+"deg)";
|
||||
} else {
|
||||
getById(eleName).style.transform = "rotate("+session.rotate+"deg)";
|
||||
getById(eleName).style.transform = "rotate("+rotate+"deg)";
|
||||
}
|
||||
getById(eleName).classList.add("rotate");
|
||||
} else {
|
||||
@ -10744,7 +10940,7 @@ function applyMirror(mirror, eleName = 'previewWebcam') { // true unmirrors as i
|
||||
} else {
|
||||
getById(eleName).classList.remove("rotate");
|
||||
}
|
||||
getById(eleName).rotated = session.rotate;
|
||||
getById(eleName).rotated = rotate;
|
||||
}
|
||||
|
||||
function cleanupMediaTracks() {
|
||||
@ -11943,6 +12139,8 @@ async function grabVideo(quality = 0, eleName = 'previewWebcam', selector = "sel
|
||||
return;
|
||||
}
|
||||
|
||||
if (session.miconly){return;}
|
||||
|
||||
activatedPreview = true;
|
||||
log("Grabbing video: " + quality);
|
||||
if (grabVideoTimer) {
|
||||
@ -12055,7 +12253,6 @@ async function grabVideo(quality = 0, eleName = 'previewWebcam', selector = "sel
|
||||
quality = sq; // override the user's setting
|
||||
}
|
||||
|
||||
|
||||
if ((iOS || iPad) && safariVersion()<15) { // iOS will not work correctly at 1080p; likely a h264 codec issue.
|
||||
if (quality == 0) {
|
||||
quality = 1;
|
||||
@ -12069,7 +12266,9 @@ async function grabVideo(quality = 0, eleName = 'previewWebcam', selector = "sel
|
||||
|
||||
log("Quality selected:" + quality);
|
||||
|
||||
if ((iOS) || (iPad)) {
|
||||
if (session.facingMode){
|
||||
constraints.video.facingMode = { exact: session.facingMode }; // user or environment
|
||||
} else if ((iOS) || (iPad)) {
|
||||
constraints.video.deviceId = {
|
||||
exact: videoSelect.value
|
||||
}; // iPhone 6s compatible ? Needs to be exact for iPhone 6s
|
||||
@ -12174,6 +12373,7 @@ async function grabVideo(quality = 0, eleName = 'previewWebcam', selector = "sel
|
||||
log("adding video tracks 2412");
|
||||
|
||||
checkBasicStreamsExist();
|
||||
|
||||
|
||||
stream.getVideoTracks().forEach(function(track) {
|
||||
|
||||
@ -12188,8 +12388,7 @@ async function grabVideo(quality = 0, eleName = 'previewWebcam', selector = "sel
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch(e){
|
||||
}
|
||||
} catch(e){}
|
||||
|
||||
session.streamSrc.addTrack(track); // tracks previously removed.
|
||||
try{
|
||||
@ -12260,7 +12459,7 @@ async function grabVideo(quality = 0, eleName = 'previewWebcam', selector = "sel
|
||||
getById("popupSelector_constraints_loading").style.display = "";
|
||||
}
|
||||
|
||||
grabVideoTimer = setTimeout(function(callback3) {
|
||||
grabVideoTimer = setTimeout(function(callback3, mirr) {
|
||||
|
||||
makeImages(true);
|
||||
|
||||
@ -12282,8 +12481,10 @@ async function grabVideo(quality = 0, eleName = 'previewWebcam', selector = "sel
|
||||
} catch(e){}
|
||||
}
|
||||
|
||||
updateForceRotate(mirr);
|
||||
|
||||
dragElement(session.videoElement);
|
||||
}, 1000, callback2); // focus
|
||||
}, 1000, callback2, mirror); // focus
|
||||
|
||||
log("DONE - found stream");
|
||||
}).catch(function(e) {
|
||||
@ -12295,6 +12496,9 @@ async function grabVideo(quality = 0, eleName = 'previewWebcam', selector = "sel
|
||||
} else if (e.name === "NotReadableError") {
|
||||
if (quality <= 10) {
|
||||
grabVideo(quality + 1, eleName, selector);
|
||||
} else if (session.facingMode){
|
||||
session.facingMode = false;
|
||||
grabVideo(false, eleName, selector); // restart.
|
||||
} else {
|
||||
if (!(session.cleanOutput)) {
|
||||
if (iOS) {
|
||||
@ -12333,6 +12537,9 @@ async function grabVideo(quality = 0, eleName = 'previewWebcam', selector = "sel
|
||||
|
||||
if (quality <= 10) {
|
||||
grabVideo(quality + 1, eleName, selector);
|
||||
} else if (session.facingMode){
|
||||
session.facingMode = false;
|
||||
grabVideo(false, eleName, selector); // restart.
|
||||
} else {
|
||||
errorlog("********Camera failed to work");
|
||||
activatedPreview = true;
|
||||
@ -13398,7 +13605,10 @@ async function publishScreen2(constraints, audioList=[], audio=true){ // webcam
|
||||
log("ROOMID EANBLED");
|
||||
log("Update Mixer Event on REsize SET");
|
||||
window.onresize = updateMixer;
|
||||
window.onorientationchange = function(){setTimeout(updateMixer, 200);};
|
||||
window.onorientationchange = function(){setTimeout(function(){
|
||||
updateForceRotate();
|
||||
updateMixer();
|
||||
}, 200);};
|
||||
joinRoom(session.roomid);
|
||||
}
|
||||
|
||||
@ -16743,6 +16953,7 @@ function setupWebcamSelection(stream = null) {
|
||||
document.getElementById("gowebcam").innerHTML = miscTranslations["start"];
|
||||
document.getElementById("gowebcam").dataset.audioready = "true";
|
||||
document.getElementById("gowebcam").dataset.ready = "true";
|
||||
setTimeout(function(){updateForceRotate();},1000);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -19166,14 +19377,116 @@ function changeAudioOutputDevice(ele) {
|
||||
} catch(e){warnlog(e);}
|
||||
}
|
||||
|
||||
function addAudioPipeline(stream, UUID, track){ // INBOUND AUDIO EFFECTS
|
||||
|
||||
function updateIncomingVideoElement(UUID, video=true, audio=true){
|
||||
|
||||
if (!session.rpcs[UUID].videoElement){return;}
|
||||
if (!session.rpcs[UUID].streamSrc){return;}
|
||||
|
||||
if (!session.rpcs[UUID].videoElement.srcObject) {
|
||||
session.rpcs[UUID].videoElement.srcObject = createMediaStream();
|
||||
}
|
||||
|
||||
if (video){
|
||||
var tracks = session.rpcs[UUID].videoElement.srcObject.getVideoTracks(); // add video track
|
||||
session.rpcs[UUID].streamSrc.getVideoTracks().forEach((trk)=>{
|
||||
var added = false;
|
||||
tracks.forEach(trk2 =>{
|
||||
if (trk2.id == trk.id){
|
||||
added=true;
|
||||
}
|
||||
});
|
||||
if (!added){
|
||||
session.rpcs[UUID].videoElement.srcObject.getVideoTracks().forEach((trk2)=>{ // make sure only one video track is added at a time.
|
||||
session.rpcs[UUID].videoElement.srcObject.removeTrack(trk2);
|
||||
});
|
||||
|
||||
if (trk.muted && (trk.kind=="video") && session.director){
|
||||
trk.onunmute = function(e){
|
||||
if (!session.rpcs[UUID]){return;}
|
||||
this.onunmute = null;
|
||||
warnlog("ON UN-MUTE");
|
||||
updateIncomingVideoElement(UUID, true, false);
|
||||
};
|
||||
} else {
|
||||
if (session.rpcs[UUID].videoElement.controls){
|
||||
session.rpcs[UUID].videoElement.controls = false;
|
||||
setTimeout(function(ele){
|
||||
if (ele){
|
||||
ele.controls=true;
|
||||
}
|
||||
},500, session.rpcs[UUID].videoElement);
|
||||
}
|
||||
session.rpcs[UUID].videoElement.srcObject.addTrack(trk);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (audio){
|
||||
if (session.audioEffects===true){
|
||||
var tracks = session.rpcs[UUID].streamSrc.getAudioTracks();
|
||||
if (tracks.length){
|
||||
var track = tracks[0];
|
||||
track = addAudioPipeline(UUID, track)
|
||||
|
||||
var added = false;
|
||||
var tracks2 = session.rpcs[UUID].videoElement.srcObject.getAudioTracks();
|
||||
tracks2.forEach(trk2 =>{
|
||||
if (trk2.label && (trk2.label == "MediaStreamAudioDestinationNode")){ // an old morphed node; delete it.
|
||||
session.rpcs[UUID].videoElement.srcObject.removeTrack(trk2);
|
||||
} else if (track.id == trk2.id){ // maybe it didn't morph; already added either way
|
||||
added = true;
|
||||
} else if ((trk2.id == tracks[0].id) && (track.id != tracks[0].id)){ // remove original audio track that is now morphed
|
||||
session.rpcs[UUID].videoElement.srcObject.removeTrack(trk2);
|
||||
}
|
||||
});
|
||||
if (!added){
|
||||
session.rpcs[UUID].videoElement.srcObject.addTrack(track);
|
||||
}
|
||||
|
||||
} else {
|
||||
session.rpcs[UUID].videoElement.srcObject.getAudioTracks().forEach(trk=>{ // make sure to remove all tracks.
|
||||
session.rpcs[UUID].videoElement.srcObject.remove(trk);
|
||||
});
|
||||
}
|
||||
|
||||
} else {
|
||||
var expected = [];
|
||||
tracks = session.rpcs[UUID].videoElement.srcObject.getAudioTracks(); // add audio tracks
|
||||
session.rpcs[UUID].streamSrc.getAudioTracks().forEach((trk)=>{
|
||||
var added = false;
|
||||
tracks.forEach(trk2 =>{
|
||||
if (trk2.id == trk.id){
|
||||
added=true;
|
||||
expected.push(trk2); //
|
||||
}
|
||||
});
|
||||
if (!added){
|
||||
session.rpcs[UUID].videoElement.srcObject.addTrack(trk);
|
||||
}
|
||||
});
|
||||
tracks.forEach((trk)=>{
|
||||
var added = false;
|
||||
expected.forEach((trk2)=>{
|
||||
if (trk2.id == trk.id){
|
||||
added=true;
|
||||
}
|
||||
});
|
||||
if (!added){ // not expected. so lets delete.
|
||||
warnlog("this shouldn't happen that often, audio track orphaned. removing it");
|
||||
session.rpcs[UUID].videoElement.srcObject.removeTrack(trk);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function addAudioPipeline(UUID, track){ // INBOUND AUDIO EFFECTS
|
||||
try{
|
||||
log("Triggered webaudio effects path");
|
||||
|
||||
if (session.audioEffects!==true){ // audio effects is not enable. Do not apply.
|
||||
errorlog("Add Audio Pipeline tried to add effects but should be disabled?");
|
||||
return stream;
|
||||
}
|
||||
for (var tid in session.rpcs[UUID].inboundAudioPipeline){
|
||||
delete session.rpcs[UUID].inboundAudioPipeline[tid]; // get rid of old nodes.
|
||||
}
|
||||
@ -19237,24 +19550,11 @@ function addAudioPipeline(stream, UUID, track){ // INBOUND AUDIO EFFECTS
|
||||
screwedUp = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (screwedUp){
|
||||
if (session.rpcs[UUID].inboundAudioPipeline[trackid].destination===false){
|
||||
session.rpcs[UUID].inboundAudioPipeline[trackid].destination = session.audioCtx.createMediaStreamDestination();
|
||||
}
|
||||
source.connect(session.rpcs[UUID].inboundAudioPipeline[trackid].destination);
|
||||
stream.getTracks().forEach((trk)=>{
|
||||
if (trackid != trk.id){
|
||||
if (trk.muted && (trk.kind=="video") && session.director){
|
||||
// if the video track is muted, we don't want to add it. The unmute event can deal with this if it unmutes. Director only condition, since not impactful elsewhere.
|
||||
} else {
|
||||
session.rpcs[UUID].inboundAudioPipeline[trackid].destination.stream.addTrack(trk);
|
||||
log("secondary stream added");
|
||||
}
|
||||
log(trk);
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
if (session.audioCtx.state == "suspended"){
|
||||
@ -19262,7 +19562,7 @@ function addAudioPipeline(stream, UUID, track){ // INBOUND AUDIO EFFECTS
|
||||
}
|
||||
} catch(e){warnlog("session.audioCtx.resume(); failed");}
|
||||
|
||||
return session.rpcs[UUID].inboundAudioPipeline[trackid].destination.stream;
|
||||
return session.rpcs[UUID].inboundAudioPipeline[trackid].destination.stream.getAudioTrack()[0];
|
||||
}
|
||||
|
||||
try {
|
||||
@ -19271,9 +19571,9 @@ function addAudioPipeline(stream, UUID, track){ // INBOUND AUDIO EFFECTS
|
||||
}
|
||||
} catch(e){warnlog("session.audioCtx.resume(); failed");}
|
||||
|
||||
return stream;
|
||||
return track;
|
||||
} catch(e) {errorlog(e);}
|
||||
return stream;
|
||||
return track;
|
||||
}
|
||||
|
||||
|
||||
@ -19312,14 +19612,9 @@ function changeChannelOffset(UUID, channel){
|
||||
ele[i].classList.remove("pressed");
|
||||
}
|
||||
}
|
||||
|
||||
session.rpcs[UUID].channelOffset = channel;
|
||||
var tracks = session.rpcs[UUID].streamSrc.getAudioTracks();
|
||||
if (tracks.length){
|
||||
var track = tracks[0];
|
||||
session.rpcs[UUID].videoElement.srcObject = addAudioPipeline(session.rpcs[UUID].streamSrc, UUID, track);
|
||||
}
|
||||
|
||||
updateIncomingVideoElement(UUID, false, true);
|
||||
}
|
||||
|
||||
function offsetChannel(destination, source, offset){
|
||||
@ -20886,6 +21181,7 @@ function createControlBoxScreenshare(UUID, soloLink, streamID) {
|
||||
}
|
||||
session.rpcs[UUID].voiceMeter.id = "voiceMeter_" + UUID;
|
||||
session.rpcs[UUID].voiceMeter.dataset.level = 0;
|
||||
session.rpcs[UUID].voiceMeter.classList.remove("advanced");
|
||||
}
|
||||
|
||||
session.rpcs[UUID].remoteMuteElement = getById("muteStateTemplate").cloneNode(true);
|
||||
@ -20946,7 +21242,7 @@ function createControlBoxScreenshare(UUID, soloLink, streamID) {
|
||||
session.rpcs[UUID].signalMeter = getById("signalMeterTemplate").cloneNode(true);
|
||||
session.rpcs[UUID].signalMeter.id = "signalMeter_" + UUID;
|
||||
session.rpcs[UUID].signalMeter.dataset.level = 0;
|
||||
//session.rpcs[UUID].signalMeter.style.display = "block";
|
||||
session.rpcs[UUID].signalMeter.classList.remove("advanced");
|
||||
session.rpcs[UUID].signalMeter.dataset.UUID = UUID;
|
||||
session.rpcs[UUID].signalMeter.title = miscTranslations["signal-meter"];
|
||||
session.rpcs[UUID].signalMeter.addEventListener('click', function(e) { // show stats of video if double clicked
|
||||
|
||||
33
main.css
33
main.css
@ -547,6 +547,38 @@ hr {
|
||||
transform: scale(1);
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
.battery {
|
||||
border: 3px solid #4192c5;
|
||||
width: 11px;
|
||||
height: 19px;
|
||||
border-radius: 4px;
|
||||
position: absolute;
|
||||
left: 27px;
|
||||
top: 3px;
|
||||
background-color: #FFF2;
|
||||
font-size: 1.5em;
|
||||
z-index: 2;
|
||||
cursor: help;
|
||||
display:none;
|
||||
}
|
||||
.battery[data-plugged="0"]{
|
||||
display:block;
|
||||
}
|
||||
.battery.warn {
|
||||
border: 3px solid #EFAF13;
|
||||
}
|
||||
.battery.alert {
|
||||
border: 3px solid #e81309;
|
||||
}
|
||||
.battery-level {
|
||||
background: #30b455;
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.signal-meter{
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
@ -3291,6 +3323,7 @@ input:checked + .slider:before {
|
||||
.alertModalInner {
|
||||
position: relative;
|
||||
padding: 2em;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.modalClose {
|
||||
|
||||
118
main.js
118
main.js
@ -271,6 +271,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
session.meshcast = urlParams.get('meshcast') || "both";
|
||||
}
|
||||
|
||||
|
||||
var filename = false;
|
||||
try {
|
||||
filename = window.location.pathname.substring(window.location.pathname.lastIndexOf('/') + 1);
|
||||
@ -358,6 +359,34 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
session.rotate = urlParams.get('rotate') || 90;
|
||||
session.rotate = parseInt(session.rotate);
|
||||
}
|
||||
|
||||
if (urlParams.has('facing') ) {
|
||||
session.facingMode = urlParams.get('facing') || false;
|
||||
}
|
||||
if (session.facingMode){
|
||||
session.facingMode = session.facingMode.toLowerCase();
|
||||
if (session.facingMode == "user"){
|
||||
//
|
||||
} else if (session.facingMode == "environment"){
|
||||
//
|
||||
} else if (session.facingMode == "rear"){
|
||||
session.facingMode = "environment";
|
||||
} else if (session.facingMode == "back"){
|
||||
session.facingMode = "environment";
|
||||
} else if (session.facingMode == "front"){
|
||||
session.facingMode = "user";
|
||||
} else {
|
||||
session.facingMode = false;
|
||||
}
|
||||
}
|
||||
|
||||
// session.facingMode }; // user or environment
|
||||
|
||||
if (urlParams.has('forcelandscape') || urlParams.has('fl')){
|
||||
session.orientation = "landscape";
|
||||
} else if (urlParams.has('forceportrait') || urlParams.has('fp')){
|
||||
session.orientation = "portrait";
|
||||
}
|
||||
|
||||
if (urlParams.has('midi') || urlParams.has('hotkeys')) {
|
||||
session.midiHotkeys = urlParams.get('midi') || urlParams.get ('hotkeys') || 1;
|
||||
@ -401,10 +430,12 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
session.screensharebutton = false;
|
||||
if (urlParams.has('miconly')){
|
||||
session.videoDevice=0;
|
||||
session.miconly = true;
|
||||
getById("add_camera").innerHTML = "Share your Microphone";
|
||||
miniTranslate(getById("add_camera"), "share-your-mic");
|
||||
getById("videoMenu").style.display = "none";
|
||||
//session.autostart = true;
|
||||
getById("flipcamerabutton").style.setProperty("display", "none", "important");
|
||||
getById("mutevideobutton").style.setProperty("display", "none", "important");
|
||||
getById("videoMenu3").style.setProperty("display", "none", "important");
|
||||
getById("previewWebcam").classList.add("miconly");
|
||||
@ -1692,6 +1723,12 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
session.codec = "vp8";
|
||||
warnlog("Defaulting to VP8 manually, as H264 with remote iOS devices is not supported");
|
||||
}
|
||||
|
||||
if (urlParams.has('h264profile')) {
|
||||
session.h264profile = urlParams.get('h264profile') || "42e01f";
|
||||
session.h264profile = session.h264profile.substring(0, 6);
|
||||
session.h264profile = session.h264profile.toLowerCase();
|
||||
}
|
||||
|
||||
if (urlParams.has('nonacks')){ // disables error control / throttling.
|
||||
session.noNacks = true;
|
||||
@ -1800,8 +1837,8 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
session.limitTotalBitrate = parseInt(session.limitTotalBitrate);
|
||||
}
|
||||
|
||||
if (urlParams.has('mcvb') || urlParams.has('meshcastbitrate')){
|
||||
session.meshcastBitrate = urlParams.get('mcvb') || urlParams.get('meshcastbitrate') || 2500;
|
||||
if (urlParams.has('mcb') || urlParams.has('mcbitrate') || urlParams.has('meshcastbitrate')){
|
||||
session.meshcastBitrate = urlParams.get('mcb') || urlParams.get('mcbitrate') || urlParams.get('meshcastbitrate') || 2500;
|
||||
session.meshcastBitrate = parseInt(session.meshcastBitrate);
|
||||
}
|
||||
|
||||
@ -3544,6 +3581,33 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
var lazyVideos = [].slice.call(document.querySelectorAll("video.lazy"));
|
||||
|
||||
if ("IntersectionObserver" in window) {
|
||||
var lazyVideoObserver = new IntersectionObserver(function(entries, observer) {
|
||||
entries.forEach(function(video) {
|
||||
if (video.isIntersecting) {
|
||||
for (var source in video.target.children) {
|
||||
var videoSource = video.target.children[source];
|
||||
if (typeof videoSource.tagName === "string" && videoSource.tagName === "SOURCE") {
|
||||
videoSource.src = videoSource.dataset.src;
|
||||
}
|
||||
}
|
||||
|
||||
video.target.load();
|
||||
video.target.classList.remove("lazy");
|
||||
lazyVideoObserver.unobserve(video.target);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
lazyVideos.forEach(function(lazyVideo) {
|
||||
lazyVideoObserver.observe(lazyVideo);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("dragstart", event => {
|
||||
var url = event.target.href || event.target.value;
|
||||
@ -3591,6 +3655,56 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
//event.dataTransfer.setData("url", encodeURI(url));
|
||||
|
||||
});
|
||||
|
||||
if (navigator.getBattery){
|
||||
navigator.getBattery().then(function(battery) {
|
||||
session.batteryState = {};
|
||||
if ("level" in battery){
|
||||
session.batteryState.level = battery.level;
|
||||
}
|
||||
if ("charging" in battery){
|
||||
session.batteryState.charging = battery.charging;
|
||||
}
|
||||
|
||||
if (session.batteryState == {}){
|
||||
session.batteryState = null;
|
||||
}
|
||||
battery.addEventListener('chargingchange', function() {
|
||||
session.batteryState = {};
|
||||
var miniInfo = {};
|
||||
if ("level" in battery){
|
||||
session.batteryState.level = battery.level;
|
||||
miniInfo.bat = battery.level;
|
||||
}
|
||||
if ("charging" in battery){
|
||||
session.batteryState.charging = battery.charging;
|
||||
miniInfo.chrg = battery.charging;
|
||||
}
|
||||
if (session.batteryState == {}){
|
||||
session.batteryState = null;
|
||||
}
|
||||
session.sendMessage({"miniInfo":miniInfo});
|
||||
});
|
||||
|
||||
battery.addEventListener('levelchange', function(){
|
||||
session.batteryState = {};
|
||||
var miniInfo = {};
|
||||
if ("level" in battery){
|
||||
session.batteryState.level = battery.level;
|
||||
miniInfo.bat = battery.level;
|
||||
}
|
||||
if ("charging" in battery){
|
||||
session.batteryState.charging = battery.charging;
|
||||
miniInfo.chrg = battery.charging;
|
||||
}
|
||||
if (session.batteryState == {}){
|
||||
session.batteryState = null;
|
||||
}
|
||||
session.sendMessage({"miniInfo":miniInfo});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
window.onload = function winonLoad() { // This just keeps people from killing the live stream accidentally. Also give me a headsup that the stream is ending
|
||||
window.addEventListener("beforeunload", function(e) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user