mirror of
https://github.com/eliasstepanik/vdo.ninja.git
synced 2026-01-11 21:58:35 +00:00
&contenthint and examples added; & pt-br
This commit is contained in:
parent
dbf1f286aa
commit
494db979cd
54
examples/custom_video_switcher.html
Normal file
54
examples/custom_video_switcher.html
Normal file
@ -0,0 +1,54 @@
|
||||
<html>
|
||||
<body>
|
||||
<button onclick="togglePlayer('STREAM123a')" >toggle video 1</button>
|
||||
<button onclick="togglePlayer('STREAM123b')" >toggle video 2</button>
|
||||
<iframe id="scene"
|
||||
style="position: relative; display:block; width:100%; height: calc(100vh - 50px);"
|
||||
allow="document-domain;encrypted-media;sync-xhr;cross-origin-isolated;accelerometer;midi;autoplay;fullscreen;picture-in-picture;display-capture;"
|
||||
src="https://vdo.ninja/alpha/?room=ROOMHERE123&cleanoutput&transparent&noaudio&controls=0&noap&optimize=0&scale=100&scene&manual&b64css=dmlkZW97CiAgICBwb3NpdGlvbjogYWJzb2x1dGU7CiAgICBsZWZ0OiAwOwogICAgdG9wOiAwOwp9"
|
||||
></iframe>
|
||||
<script>
|
||||
|
||||
// you can remotely switch between video streams A and B, instead of using the toggle buttons. You'll need your own API service to switch, but that's up to you.
|
||||
|
||||
// https://vdo.ninja/alpha/?room=ROOMHERE123&push=STREAM123a&view <= invite guest-a
|
||||
// https://vdo.ninja/alpha/?room=ROOMHERE123&push=STREAM123b&view <= invite guest-b
|
||||
|
||||
// &b64css=dmlkZW97CiAgICBwb3NpdGlvbjogYWJzb2x1dGU7CiAgICBsZWZ0OiAwOwogICAgdG9wOiAwOwp9" -- makes sure all videos added align to the top-left corner, overlapping other videos if needed
|
||||
// we do not use &fadein=0, as that can cause flicker
|
||||
// &manual disables the auto mixer for scene=0, so we can manually add/remove elements to the scene via the IFRAME API instead
|
||||
var scene = document.getElementById("scene");
|
||||
|
||||
//////////// LISTEN FOR EVENTS
|
||||
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
|
||||
var eventer = window[eventMethod];
|
||||
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";
|
||||
eventer(messageEvent, function (e) {
|
||||
if (scene && e.source == scene.contentWindow){
|
||||
if (e.data.action === 'view-connection') {
|
||||
console.log(e.data);
|
||||
} else if (e.data.action === 'end-view-connection') {
|
||||
console.log(e.data);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
var activeVideo = null;
|
||||
async function togglePlayer(video){
|
||||
activeVideo = video;
|
||||
scene.contentWindow.postMessage({
|
||||
add: true,
|
||||
target: activeVideo
|
||||
}, '*');
|
||||
|
||||
setTimeout(function(){
|
||||
scene.contentWindow.postMessage({
|
||||
replace: true, // this replaces all videos in the current scene with the target stream ID. We coudl use `remove` instead, but that requires specifying the streamID to remove
|
||||
target: activeVideo
|
||||
}, '*');
|
||||
},500);
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
10
iframe.html
10
iframe.html
@ -54,10 +54,7 @@
|
||||
iframeExample.append(exampleHeader, exampleBody);
|
||||
container.prepend(iframeExample);
|
||||
|
||||
//////////// LISTEN FOR EVENTS
|
||||
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
|
||||
var eventer = window[eventMethod];
|
||||
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";
|
||||
|
||||
|
||||
var media = {};
|
||||
media.tracks = {};
|
||||
@ -67,6 +64,11 @@
|
||||
console.error(e);
|
||||
});
|
||||
|
||||
//////////// LISTEN FOR EVENTS
|
||||
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
|
||||
var eventer = window[eventMethod];
|
||||
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";
|
||||
|
||||
eventer(messageEvent, function (e) {
|
||||
if (e.source != iframe.contentWindow){return} // reject messages send from other iframes
|
||||
|
||||
|
||||
@ -82,7 +82,7 @@
|
||||
<link itemprop="url" href="./media/vdoNinja_logo_full.png" />
|
||||
</span>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/CodecsHandler.js?ver=37"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=503"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=508"></script>
|
||||
<input id="zoomSlider" type="range" style="display: none;" />
|
||||
<span id="electronDragZone" style="pointer-events: none; z-index:-10; position:absolute;top:0;left:0;width:100%;height:2%;-webkit-app-region: drag;min-height:20px;"></span>
|
||||
<div id="header">
|
||||
@ -2118,7 +2118,8 @@
|
||||
<li><a onclick="changeLg('en');toggle(document.getElementById('languages'));" style="cursor: pointer;">English</a></li>
|
||||
<li><a onclick="changeLg('ru');toggle(document.getElementById('languages'));" style="cursor: pointer;" data-tz="Europe/Moscow">Russian</a></li>
|
||||
<li><a onclick="changeLg('fr');toggle(document.getElementById('languages'));" style="cursor: pointer;" data-tz="Europe/Paris">French</a></li>
|
||||
<li><a onclick="changeLg('pt');toggle(document.getElementById('languages'));" style="cursor: pointer;" data-tz="Europe/Lisbon;America/Araguaina">Portuguese</a></li>
|
||||
<li><a onclick="changeLg('pt');toggle(document.getElementById('languages'));" style="cursor: pointer;" data-tz="Europe/Lisbon;">Portuguese (Europe)</a></li>
|
||||
<li><a onclick="changeLg('pt-br');toggle(document.getElementById('languages'));" style="cursor: pointer;" data-tz="America/Araguaina">Portuguese (Brazil)</a></li>
|
||||
<li><a onclick="changeLg('it');toggle(document.getElementById('languages'));" style="cursor: pointer;" data-tz="Europe/Rome">Italian</a></li>
|
||||
<li><a onclick="changeLg('de');toggle(document.getElementById('languages'));" style="cursor: pointer;" data-tz="Europe/Berlin">German</a></li>
|
||||
<li><a onclick="changeLg('es');toggle(document.getElementById('languages'));" style="cursor: pointer;" data-tz="Europe/Madrid">Spanish</a></li>
|
||||
@ -2236,11 +2237,11 @@
|
||||
// session.defaultBackgroundImages = ["./media/bg_sample1.webp", "./media/bg_sample2.webp"]; // for &effects=5 (virtual backgrounds)
|
||||
</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=406"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="lib-js" src="./lib.js?ver=408"></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=417"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=418"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
194
lib.js
194
lib.js
@ -12999,7 +12999,19 @@ async function createDirectorOnlyBox() {
|
||||
var newScene = document.createElement("div");
|
||||
newScene.innerHTML = '<button style="margin: 0 5px 10px 5px;" data-sid="'+session.streamID+'" data-action-type="addToScene" data-scene="'+scene+'" title="Add to Scene '+scene+'" onclick="directEnable(this, event);"><span ><i class="las la-plus-square" style="color:#060"></i> Scene: '+scene+'</span></button>';
|
||||
newScene.classList.add("customScene");
|
||||
getById("container_director").appendChild(newScene);
|
||||
//getById("container_director").appendChild(newScene);
|
||||
|
||||
var added = false;
|
||||
getById("container_director").querySelectorAll('.customScene>[data-scene]').forEach(ele=>{
|
||||
if (!added && ele.dataset.scene>scene+""){
|
||||
ele.parentNode.parentNode.insertBefore(newScene, ele.parentNode);
|
||||
added = true;
|
||||
}
|
||||
});
|
||||
if (!added){
|
||||
getById("container_director").appendChild(newScene);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -15188,9 +15200,7 @@ async function getAudioOnly(selector, trackid = null, override = false) {
|
||||
log("CONSTRAINT");
|
||||
log(constraint);
|
||||
var stream = await navigator.mediaDevices.getUserMedia(constraint).then(function(stream2) {
|
||||
|
||||
pokeIframeAPI("local-microphone-event");
|
||||
|
||||
return stream2;
|
||||
}).catch(function(err) {
|
||||
warnlog(err);
|
||||
@ -16834,9 +16844,21 @@ async function grabVideo(quality = 0, eleName = 'previewWebcam', selector = "sel
|
||||
if (session.mc && session.mc.getSenders){
|
||||
session.mc.getSenders().forEach((sender) => { // I suppose there could be a race condition between negotiating and updating this. if joining at the same time as changnig streams?
|
||||
if (sender.track && sender.track.kind == "video") {
|
||||
session.mc.canvasStream.getVideoTracks().forEach(trk=>{
|
||||
sender.replaceTrack(trk); // replace may not be supported by all browsers. eek.
|
||||
});
|
||||
var trk = getMeshcastCanvasTrack();
|
||||
if (session.screenShareState && session.screenshareContentHint && (trk.kind === "video")){
|
||||
try {
|
||||
trk.contentHint = session.screenshareContentHint;
|
||||
} catch(e){
|
||||
errorlog(e);
|
||||
}
|
||||
} else if (session.contentHint && (trk.kind === "video")){
|
||||
try {
|
||||
trk.contentHint = session.contentHint;
|
||||
} catch(e){
|
||||
errorlog(e);
|
||||
}
|
||||
}
|
||||
sender.replaceTrack(trk); // replace may not be supported by all browsers. eek.
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -17365,6 +17387,28 @@ function pushOutVideoTrack(track){
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (session.audioContentHint && (track.kind === "audio")){
|
||||
try {
|
||||
track.contentHint = session.audioContentHint;
|
||||
} catch(e){
|
||||
errorlog(e);
|
||||
}
|
||||
}
|
||||
if (session.screenShareState && session.screenshareContentHint && (track.kind === "video")){
|
||||
try {
|
||||
track.contentHint = session.screenshareContentHint;
|
||||
} catch(e){
|
||||
errorlog(e);
|
||||
}
|
||||
} else if (session.contentHint && (track.kind === "video")){
|
||||
try {
|
||||
track.contentHint = session.contentHint;
|
||||
} catch(e){
|
||||
errorlog(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (session.mc && session.mc.getSenders){ // should only be 0 or 1 video sender, ever.
|
||||
//var added = false;
|
||||
@ -17780,6 +17824,16 @@ function senderAudioUpdate(callback=false){
|
||||
if (session.videoElement.srcObject.getAudioTracks()) {
|
||||
var tracks = session.videoElement.srcObject.getAudioTracks();
|
||||
|
||||
if (session.audioContentHint && tracks.length){
|
||||
tracks.forEach(trk=>{
|
||||
try {
|
||||
trk.contentHint = session.audioContentHint;
|
||||
} catch(e){
|
||||
errorlog(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (session.mc && session.mc.getSenders && tracks.length){
|
||||
session.mc.getSenders().forEach((sender) => { // I suppose there could be a race condition between negotiating and updating this. if joining at the same time as changnig streams?
|
||||
if (sender.track && sender.track.kind == "audio") {
|
||||
@ -19212,7 +19266,6 @@ session.publishFile = function(ele, event){ // webcam stream is used to generate
|
||||
v.src = fileURL;
|
||||
|
||||
|
||||
|
||||
try {
|
||||
if (Firefox){
|
||||
session.streamSrc = v.mozCaptureStream();
|
||||
@ -19244,44 +19297,12 @@ session.publishFile = function(ele, event){ // webcam stream is used to generate
|
||||
session.streamSrc = vid.captureStream(); // gaaaaaaaaaaaahhhhhhhh!
|
||||
}
|
||||
|
||||
toggleMute(true);
|
||||
session.streamSrc.getTracks().forEach(function(track){ // I'm making an exception I guess -- reversing the role?
|
||||
for (UUID in session.pcs){
|
||||
if ("realUUID" in session.pcs[UUID]){continue;}
|
||||
var senders = getSenders2(UUID);
|
||||
log(track);
|
||||
if (track.kind == "video"){
|
||||
try {
|
||||
if ((session.pcs[UUID].guest==true) && (session.roombitrate===0)) {
|
||||
log("room rate restriction detected. No videos will be published to other guests");
|
||||
} else if (session.pcs[UUID].allowVideo==true){ // allow
|
||||
// for any connected peer, update the video they have if connected with a video already.
|
||||
var added=false;
|
||||
senders.forEach((sender) => { // I suppose there could be a race condition between negotiating and updating this. if joining at the same time as changnig streams?
|
||||
if (added) {
|
||||
return;
|
||||
}
|
||||
if (sender.track && sender.track.kind == "video"){
|
||||
sender.replaceTrack(track); // replace may not be supported by all browsers. eek.
|
||||
added=true;
|
||||
}
|
||||
|
||||
});
|
||||
if (added==false){
|
||||
session.pcs[UUID].addTrack(track, session.streamSrc);
|
||||
setTimeout(function(uuid){session.optimizeBitrate(uuid);},session.rampUpTime, UUID); // 3 seconds lets us ramp up the quality a bit and figure out the total bandwidth quicker
|
||||
}
|
||||
}
|
||||
} catch (e){
|
||||
errorlog(e);
|
||||
}
|
||||
|
||||
} else {
|
||||
session.pcs[UUID].addTrack(track, session.streamSrc);
|
||||
}
|
||||
}
|
||||
});
|
||||
session.refreshScale();
|
||||
var tracks = session.streamSrc.getVideoTracks();
|
||||
if (tracks.length){
|
||||
pushOutVideoTrack(tracks[0]);
|
||||
}
|
||||
var tracks = session.streamSrc.getAudioTracks();
|
||||
senderAudioUpdate();
|
||||
}
|
||||
|
||||
session.applySoloChat(); // mute streams that should be muted if a director
|
||||
@ -22817,6 +22838,16 @@ function createScreenShareURL(transparent=true){
|
||||
extras += "&smallshare";
|
||||
}
|
||||
|
||||
if (session.screenshareContentHint){
|
||||
extras += "&sshint="+session.screenshareContentHint;
|
||||
} else if (session.contentHint){
|
||||
extras += "&sshint="+session.contentHint;
|
||||
}
|
||||
|
||||
if (session.audioContentHint){
|
||||
extras += "&audiohint="+session.audioContentHint;
|
||||
}
|
||||
|
||||
if (session.meshcastScreenShareCodec){
|
||||
extras += "&mccodec="+session.meshcastScreenShareCodec;
|
||||
} else if (session.meshcastCodec){
|
||||
@ -23467,7 +23498,18 @@ function initSceneList(UUID){
|
||||
var newScene = document.createElement("div");
|
||||
newScene.innerHTML = '<button style="margin: 0 5px 10px 5px;" data-sid="'+session.rpcs[UUID].streamID+'" data--u-u-i-d="'+UUID+'" data-action-type="addToScene" data-scene="'+scene+'" title="Add to Scene '+scene+'" onclick="directEnable(this, event);"><span ><i class="las la-plus-square" style="color:#060"></i> Scene: '+scene+'</span></button>';
|
||||
newScene.classList.add("customScene");
|
||||
getById("container_" + UUID).appendChild(newScene);
|
||||
|
||||
var added = false;
|
||||
getById("container_" + UUID).querySelectorAll('.customScene>[data-scene]').forEach(ele=>{
|
||||
log(ele);
|
||||
if (!added && ele.dataset.scene>scene+""){
|
||||
ele.parentNode.parentNode.insertBefore(newScene, ele.parentNode);
|
||||
added = true;
|
||||
}
|
||||
});
|
||||
if (!added){
|
||||
getById("container_" + UUID).appendChild(newScene);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -23484,15 +23526,37 @@ function updateSceneList(scene){
|
||||
var newScene = document.createElement("div");
|
||||
newScene.innerHTML = '<button style="margin: 0 5px 10px 5px;" data-sid="'+session.rpcs[UUID].streamID+'" data--u-u-i-d="'+UUID+'" data-action-type="addToScene" data-scene="'+scene+'" title="Add to Scene '+scene+'" onclick="directEnable(this, event);"><span ><i class="las la-plus-square" style="color:#060"></i> Scene: '+scene+'</span></button>';
|
||||
newScene.classList.add("customScene");
|
||||
getById("container_" + UUID).appendChild(newScene);
|
||||
var added = false;
|
||||
getById("container_" + UUID).querySelectorAll('.customScene>[data-scene]').forEach(ele=>{
|
||||
log(ele);
|
||||
if (!added && ele.dataset.scene>scene+""){
|
||||
ele.parentNode.parentNode.insertBefore(newScene, ele.parentNode);
|
||||
added = true;
|
||||
}
|
||||
});
|
||||
if (!added){
|
||||
getById("container_" + UUID).appendChild(newScene);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (session.showDirector){
|
||||
if (document.getElementById("container_director")){
|
||||
var newScene = document.createElement("div");
|
||||
newScene.innerHTML = '<button style="margin: 0 5px 10px 5px;" data-sid="'+session.streamID+'" data-action-type="addToScene" data-scene="'+scene+'" title="Add to Scene '+scene+'" onclick="directEnable(this, event);"><span ><i class="las la-plus-square" style="color:#060"></i> Scene: '+scene+'</span></button>';
|
||||
newScene.classList.add("customScene");
|
||||
getById("container_director").appendChild(newScene);
|
||||
//getById("container_director").appendChild(newScene);
|
||||
|
||||
var added = false;
|
||||
getById("container_director").querySelectorAll('.customScene>[data-scene]').forEach(ele=>{
|
||||
if (!added && ele.dataset.scene>scene+""){
|
||||
ele.parentNode.parentNode.insertBefore(newScene, ele.parentNode);
|
||||
added = true;
|
||||
}
|
||||
});
|
||||
if (!added){
|
||||
getById("container_director").appendChild(newScene);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -27960,8 +28024,42 @@ function createSecondStream2(UUID){
|
||||
}
|
||||
}
|
||||
|
||||
/* if (session.audioContentHint && tracks.length){
|
||||
tracks.forEach(trk=>{
|
||||
try {
|
||||
|
||||
trk.contentHint = session.audioContentHint;
|
||||
} catch(e){
|
||||
errorlog(e);
|
||||
}
|
||||
});
|
||||
} */
|
||||
|
||||
var senders = getSenders2(UUID+"_screen");
|
||||
session.screenStream.getTracks().forEach(function(track){
|
||||
|
||||
if (session.audioContentHint && (track.kind === "audio")){
|
||||
try {
|
||||
track.contentHint = session.audioContentHint;
|
||||
} catch(e){
|
||||
errorlog(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (session.screenshareContentHint && (track.kind === "video")){
|
||||
try {
|
||||
track.contentHint = session.screenshareContentHint;
|
||||
} catch(e){
|
||||
errorlog(e);
|
||||
}
|
||||
} else if (session.contentHint && (track.kind === "video")){
|
||||
try {
|
||||
track.contentHint = session.contentHint;
|
||||
} catch(e){
|
||||
errorlog(e);
|
||||
}
|
||||
}
|
||||
|
||||
var added = false;
|
||||
senders.forEach((sender) => { // I suppose there could be a race condition between negotiating and updating this. if joining at the same time as changnig streams?
|
||||
if (added){return;}
|
||||
|
||||
139
main.js
139
main.js
@ -2263,6 +2263,18 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
}
|
||||
}
|
||||
|
||||
if (urlParams.has('contenthint') || urlParams.has('contenttype') || urlParams.has('content') || urlParams.has('hint')) {
|
||||
session.contentHint = urlParams.get('contenthint') || urlParams.get('contenttype') || urlParams.get('content') || urlParams.get('hint') || "detail";
|
||||
}
|
||||
|
||||
if (urlParams.has('audiocontenthint') || urlParams.has('audiocontenttype') || urlParams.has('audiocontent') || urlParams.has('audiohint')) {
|
||||
session.audioContentHint = urlParams.get('audiocontenthint') || urlParams.get('audiocontenttype') || urlParams.get('audiocontent') || urlParams.get('audiohint') || "music";
|
||||
}
|
||||
|
||||
if (urlParams.has('screensharecontenthint') || urlParams.has('sscontenthint') || urlParams.has('screensharecontenttype') || urlParams.has('sscontent') || urlParams.has('sshint')) {
|
||||
session.screenshareContentHint = urlParams.get('screensharecontenthint') || urlParams.get('sscontenthint') || urlParams.get('screensharecontenttype') || urlParams.get('sscontent') || urlParams.get('sshint') || "detail";
|
||||
}
|
||||
|
||||
|
||||
if (urlParams.has('codec')) {
|
||||
log("CODEC CHANGED");
|
||||
@ -4199,77 +4211,81 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
reloadRequested(); // location.reload();, but with no user prompt (force reload)
|
||||
}
|
||||
|
||||
if ("getStats" in e.data) {
|
||||
|
||||
if (("getStats" in e.data)){
|
||||
var stats = {};
|
||||
stats.total_outbound_connections = Object.keys(session.pcs).length;
|
||||
stats.total_inbound_connections = Object.keys(session.rpcs).length;
|
||||
stats.inbound_stats = {};
|
||||
for (var i in session.rpcs) {
|
||||
stats.inbound_stats[session.rpcs[i].streamID] = session.rpcs[i].stats;
|
||||
}
|
||||
try {
|
||||
stats.inbound_stats = {};
|
||||
stats.total_outbound_connections = Object.keys(session.pcs).length;
|
||||
stats.total_inbound_connections = Object.keys(session.rpcs).length;
|
||||
for (var i in session.rpcs) {
|
||||
stats.inbound_stats[session.rpcs[i].streamID] = session.rpcs[i].stats;
|
||||
}
|
||||
for (var uuid in session.pcs) {
|
||||
setTimeout(function(UUID) {
|
||||
session.pcs[UUID].getStats().then(function(stats) {
|
||||
stats.forEach(stat => {
|
||||
if (stat.type == "outbound-rtp") {
|
||||
if (stat.kind == "video") {
|
||||
|
||||
for (var uuid in session.pcs) {
|
||||
setTimeout(function(UUID) {
|
||||
session.pcs[UUID].getStats().then(function(stats) {
|
||||
stats.forEach(stat => {
|
||||
if (stat.type == "outbound-rtp") {
|
||||
if (stat.kind == "video") {
|
||||
if ("qualityLimitationReason" in stat) {
|
||||
|
||||
if ("qualityLimitationReason" in stat) {
|
||||
|
||||
session.pcs[UUID].stats.quality_limitation_reason = stat.qualityLimitationReason;
|
||||
session.pcs[UUID].stats.quality_limitation_reason = stat.qualityLimitationReason;
|
||||
}
|
||||
if ("framesPerSecond" in stat) {
|
||||
session.pcs[UUID].stats.resolution = stat.frameWidth + " x " + stat.frameHeight + " @ " + stat.framesPerSecond;
|
||||
}
|
||||
if ("encoderImplementation" in stat) {
|
||||
session.pcs[UUID].stats.encoder = stat.encoderImplementation;
|
||||
}
|
||||
}
|
||||
if ("framesPerSecond" in stat) {
|
||||
session.pcs[UUID].stats.resolution = stat.frameWidth + " x " + stat.frameHeight + " @ " + stat.framesPerSecond;
|
||||
} else if (stat.type == "remote-candidate") {
|
||||
if ("relayProtocol" in stat) {
|
||||
if ("ip" in stat) {
|
||||
session.pcs[UUID].stats.remote_relay_IP = stat.ip;
|
||||
}
|
||||
session.pcs[UUID].stats.remote_relayProtocol = stat.relayProtocol;
|
||||
}
|
||||
if ("encoderImplementation" in stat) {
|
||||
session.pcs[UUID].stats.encoder = stat.encoderImplementation;
|
||||
if ("candidateType" in stat) {
|
||||
session.pcs[UUID].stats.remote_candidateType = stat.candidateType;
|
||||
}
|
||||
}
|
||||
} else if (stat.type == "remote-candidate") {
|
||||
if ("relayProtocol" in stat) {
|
||||
if ("ip" in stat) {
|
||||
session.pcs[UUID].stats.remote_relay_IP = stat.ip;
|
||||
} else if (stat.type == "local-candidate") {
|
||||
if ("relayProtocol" in stat) {
|
||||
if ("ip" in stat) {
|
||||
session.pcs[UUID].stats.local_relayIP = stat.ip;
|
||||
}
|
||||
session.pcs[UUID].stats.local_relayProtocol = stat.relayProtocol;
|
||||
}
|
||||
session.pcs[UUID].stats.remote_relayProtocol = stat.relayProtocol;
|
||||
}
|
||||
if ("candidateType" in stat) {
|
||||
session.pcs[UUID].stats.remote_candidateType = stat.candidateType;
|
||||
}
|
||||
} else if (stat.type == "local-candidate") {
|
||||
if ("relayProtocol" in stat) {
|
||||
if ("ip" in stat) {
|
||||
session.pcs[UUID].stats.local_relayIP = stat.ip;
|
||||
if ("candidateType" in stat) {
|
||||
session.pcs[UUID].stats.local_candidateType = stat.candidateType;
|
||||
}
|
||||
session.pcs[UUID].stats.local_relayProtocol = stat.relayProtocol;
|
||||
}
|
||||
if ("candidateType" in stat) {
|
||||
session.pcs[UUID].stats.local_candidateType = stat.candidateType;
|
||||
}
|
||||
} else if ((stat.type == "candidate-pair" ) && (stat.nominated)) {
|
||||
|
||||
if ("availableOutgoingBitrate" in stat){
|
||||
session.pcs[UUID].stats.available_outgoing_bitrate_kbps = parseInt(stat.availableOutgoingBitrate/1024);
|
||||
}
|
||||
if ("totalRoundTripTime" in stat){
|
||||
if ("responsesReceived" in stat){
|
||||
session.pcs[UUID].stats.average_roundTripTime_ms = parseInt((stat.totalRoundTripTime/stat.responsesReceived)*1000);
|
||||
}
|
||||
} else if ((stat.type == "candidate-pair" ) && (stat.nominated)) {
|
||||
|
||||
if ("availableOutgoingBitrate" in stat){
|
||||
session.pcs[UUID].stats.available_outgoing_bitrate_kbps = parseInt(stat.availableOutgoingBitrate/1024);
|
||||
}
|
||||
if ("totalRoundTripTime" in stat){
|
||||
if ("responsesReceived" in stat){
|
||||
session.pcs[UUID].stats.average_roundTripTime_ms = parseInt((stat.totalRoundTripTime/stat.responsesReceived)*1000);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
});
|
||||
return;
|
||||
});
|
||||
return;
|
||||
});
|
||||
}, 0, uuid);
|
||||
}, 0, uuid);
|
||||
}
|
||||
} catch(e){
|
||||
// disconnected probably
|
||||
}
|
||||
setTimeout(function() {
|
||||
stats.outbound_stats = {};
|
||||
for (var i in session.pcs) {
|
||||
stats.outbound_stats[i] = session.pcs[i].stats;
|
||||
}
|
||||
try {
|
||||
for (var i in session.pcs) {
|
||||
stats.outbound_stats[i] = session.pcs[i].stats;
|
||||
}
|
||||
} catch(e){}
|
||||
parent.postMessage({
|
||||
"stats": stats
|
||||
}, session.iframetarget);
|
||||
@ -4555,9 +4571,16 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
session.rpcs[i].videoElement.parentNode.parentNode.removeChild(session.rpcs[i].videoElement.parentNode);
|
||||
} catch (e) {}
|
||||
}
|
||||
} else if ("replace" in e.data) { // should allow for a cleaner cut between two video streams.
|
||||
try {
|
||||
getById("gridlayout").appendChild(session.rpcs[i].videoElement);
|
||||
getById("gridlayout").childNodes.forEach(ele=>{
|
||||
if ((!ele.id) || (ele.id !== session.rpcs[i].videoElement.id)){
|
||||
getById("gridlayout").removeChild(ele);
|
||||
}
|
||||
});
|
||||
} catch(e){}
|
||||
}
|
||||
|
||||
// video and audio bitrate handled else where
|
||||
} catch (e) {
|
||||
errorlog(e);
|
||||
}
|
||||
|
||||
@ -31,11 +31,7 @@
|
||||
<canvas id="packetloss-graph"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div id="log" onclick="copyFunction(this.innerText)">
|
||||
<h2>Log <i class="las la-clipboard"></i></h2>
|
||||
<ul></ul>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="explanation">
|
||||
<h2>How to use</h2>
|
||||
<ol>
|
||||
@ -155,12 +151,10 @@
|
||||
return out;
|
||||
}
|
||||
|
||||
var logged = [];
|
||||
function logData(type, data) {
|
||||
var log = document.getElementById("log").getElementsByTagName("ul")[0];
|
||||
var entry = document.createElement('li');
|
||||
entry.textContent =
|
||||
"[" + new Date().toLocaleTimeString() + "] " + type + " : " + data;
|
||||
log.prepend(entry);
|
||||
data.timestamp = new Date().now();
|
||||
logged.push(data);
|
||||
}
|
||||
|
||||
function reloadTurn(){
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user