\
-
\
-
" + soloLink + "\
-
copy Solo link\
-
This is you, the director. You are also a performer. ";
-
-
- controls.querySelectorAll('[data-action-type]').forEach((ele) => { // give action buttons some self-reference
- ele.dataset.sid = session.streamID;
- });
-
- container.innerHTML = buttons;
- container.appendChild(controls);
-
- Object.keys(session.sceneList).forEach((scene, index) => {
- if (session.showDirector){
- if (document.getElementById("container_director")){
- if (!(getById("container_director").querySelectorAll('[data-scene="'+scene+'"]').length)){
- var newScene = document.createElement("div");
- newScene.innerHTML = '
Scene: '+scene+'';
- getById("container_director").appendChild(newScene);
- }
- }
- }
- });
-
-
- var labelID = document.getElementById("label_director");
-
- labelID.onclick = function(ee){
- var oldlabel = ee.target.innerText;
- if (session.label===false){
- oldlabel = "";
- }
- window.focus();
- var newlabel = prompt("Enter a new Display Name for this stream", oldlabel);
- if (newlabel!==null){
- if (newlabel == ""){
- newlabel = false;
- ee.target.innerText = "Add a label";
- } else {
- ee.target.innerText = newlabel;
- }
- session.label = newlabel;
- var data = {};
- data.changeLabel = true;
- data.value = session.label;
- session.sendMessage(data);
- }
- }
- labelID.style.float = "left";
- labelID.style.top = "2px";
- labelID.style.marginLeft = "5px";
- labelID.style.position = "relative";
- labelID.style.cursor="pointer";
- if (session.label){
- labelID.innerText = session.label;
- }
-}
-
-function createControlBox(UUID, soloLink, streamID) {
- if (document.getElementById("deleteme")) {
- getById("deleteme").parentNode.removeChild(getById("deleteme"));
- }
- var controls = getById("controls_blank").cloneNode(true);
-
- var container = document.createElement("div");
- container.id = "container_" + UUID; // needed to delete on user disconnect
- container.className = "vidcon directorMargins";
- controls.style.display = "block";
- controls.id = "controls_" + UUID;
- getById("guestFeeds").appendChild(container);
-
- var buttons = "
ID: " + streamID + " \
- \
- \
-
";
-
- if (!session.rpcs[UUID].voiceMeter) {
- if (session.meterStyle==1){
- session.rpcs[UUID].voiceMeter = getById("voiceMeterTemplate2").cloneNode(true);
- } else {
- session.rpcs[UUID].voiceMeter = getById("voiceMeterTemplate").cloneNode(true);
- session.rpcs[UUID].voiceMeter.classList.add("video-meter-director");
- session.rpcs[UUID].voiceMeter.style.opacity = 0;
- }
- session.rpcs[UUID].voiceMeter.id = "voiceMeter_" + UUID;
- session.rpcs[UUID].voiceMeter.dataset.level = 0;
- }
-
- session.rpcs[UUID].remoteMuteElement = getById("muteStateTemplate").cloneNode(true);
- session.rpcs[UUID].remoteMuteElement.id = "";
- session.rpcs[UUID].remoteMuteElement.style.top = "5px";
- session.rpcs[UUID].remoteMuteElement.style.right = "7px";
-
- session.rpcs[UUID].remoteVideoMuteElement = getById("videoMuteStateTemplate").cloneNode(true);
- session.rpcs[UUID].remoteVideoMuteElement.id = "";
- session.rpcs[UUID].remoteVideoMuteElement.style.top = "5px";
- session.rpcs[UUID].remoteVideoMuteElement.style.right = "28px";
-
- session.rpcs[UUID].remoteRaisedHandElement = getById("raisedHandTemplate").cloneNode(true);
- session.rpcs[UUID].remoteRaisedHandElement.id = "";
- session.rpcs[UUID].remoteRaisedHandElement.style.top = "5px";
- session.rpcs[UUID].remoteRaisedHandElement.style.right = "49px";
-
-
- var videoContainer = document.createElement("div");
- videoContainer.id = "videoContainer_" + UUID; // needed to delete on user disconnect
- videoContainer.style.margin = "0";
- videoContainer.style.position = "relative";
-
- controls.innerHTML += "
";
- controls.innerHTML += "
";
-
- var handsID = "hands_" + UUID;
-
- controls.innerHTML += "
\
-
\
-
" + soloLink + "\
-
copy Solo link\
-
\
-
\
- \
- Lower Raised Hand \
- \
-
";
-
- controls.querySelectorAll('[data-action-type]').forEach((ele) => { // give action buttons some self-reference
- ele.dataset.UUID = UUID;
- ele.dataset.sid = streamID;
- });
-
- container.innerHTML = buttons;
- container.appendChild(videoContainer);
- videoContainer.appendChild(session.rpcs[UUID].voiceMeter);
- videoContainer.appendChild(session.rpcs[UUID].remoteMuteElement);
- videoContainer.appendChild(session.rpcs[UUID].remoteVideoMuteElement);
- videoContainer.appendChild(session.rpcs[UUID].remoteRaisedHandElement);
- container.appendChild(controls);
- initSceneList(UUID);
-}
-
-function createDirectorCam(vid) {
-
- getById("press2talk").innerHTML = "";
- getById("press2talk").outerHTML = "";
- if (document.getElementById("videoContainer_director")){
- getById("videoContainer_director").appendChild(vid);
- } else {
- getById("miniPerformer").appendChild(vid);
- }
- vid.title = "This is the preview of the Director's audio and video output.";
- getById("press2talk").dataset.value = 1;
- session.muted = false;
- toggleMute(true);
- getById("screensharebutton").classList.remove("advanced");
- getById("hangupbutton2").classList.remove("advanced");
- setTimeout(function() {
- toggleSettings();
- }, 200);
-
- if (urlParams.has('permaid')) {
- updateURL("permaid=" + session.streamID);
- } else {
- updateURL("push=" + session.streamID);
- }
-}
-
-function press2talk(clean = false) {
- var ele = getById("press2talk");
- ele.style.minWidth = "127px";
- ele.style.padding = "7px";
- getById("settingsbutton").classList.remove("advanced");
-
-
- if (!document.getElementById("controls_director") && session.showDirector){createDirectorOnlyBox();}
-
-
- if (session.videoDevice || (session.audioDevice && session.audioDevice!==1)){
- if ((session.videoDevice === 1) && (session.audioDevice===false || session.audioDevice==1)){
- session.publishDirector(clean, true);
- session.muted = false;
- toggleMute(true);
- return;
- } else {
- enumerateDevices().then(function(deviceInfos) {
- var vdevice = false;
- var adevice = true;
- if (session.audioDevice==0){
- adevice=false;
- }
- if (session.videoDevice && (session.videoDevice!=1)){
- for (let i = 0; i !== deviceInfos.length; ++i) {
- var deviceInfo = deviceInfos[i];
- if ((deviceInfo.kind === 'videoinput') && (deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase().includes(session.videoDevice))) {
- vdevice = {deviceId: {exact: deviceInfo.deviceId}};
- break;
- } else if (deviceInfo.deviceId === session.videoDevice){
- vdevice = {deviceId: {exact: deviceInfo.deviceId}};
- break;
- }
- }
- }
- if (session.audioDevice && (session.audioDevice!=1)){
- for (let i = 0; i !== deviceInfos.length; ++i) {
- var deviceInfo = deviceInfos[i];
- if ((deviceInfo.kind === 'audioinput') && (deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase().includes(session.audioDevice))) {
- adevice = {deviceId: {exact: deviceInfo.deviceId}};
- break;
- } else if (deviceInfo.deviceId === session.audioDevice){
- adevice = {deviceId: {exact: deviceInfo.deviceId}};
- break;
- }
- }
- }
- session.publishDirector(clean, vdevice, adevice);
- session.muted = false;
- toggleMute(true);
- });
- return;
- }
- }
-
- session.publishDirector(clean);
- session.muted = false;
- toggleMute(true);
-
-}
-
-function addToGoogleCalendar(){
- var title = "Live Stream";
- //var dates = "20180512T230000Z/20180513T030000Z";
- var linkout = getById("director_block_1").innerText;
- var details = "Join the live stream as a performer at the following link:
===> "+linkout+"
To test your connection and camera ahead of time, please visit https://obs.ninja/speedtest
Do not share the details of this invite with others, unless explicitly told to.";
- details = details.split(' ').join('+');
- details = details.split('&').join('%26');
- var linkToOpen = "https://calendar.google.com/calendar/r/eventedit?text="+title+"&details="+details;
- //https://calendar.google.com/calendar/r/eventedit?text=My+Custom+Event&dates=20180512T230000Z/20180513T030000Z&details=For+details,+link+here:+https://example.com/tickets-43251101208&location=Garage+Boston+-+20+Linden+Street+-+Allston,+MA+02134
-
- window.open(linkToOpen);
-
-}
-
-function addToOutlookCalendar(){
- var title = "Live Stream";
- var linkout = getById("director_block_1").innerText;
- var details = "Join the live stream as a performer at the following link:
===> "+linkout+"
To test your connection and camera ahead of time, please visit https://obs.ninja/speedtest
Do not share the details of this invite with others, unless explicitly told to.";
- details = details.split(' ').join('%20');
- details = details.split('&').join('%26');
-
-
- var linkToOpen = "https://outlook.live.com/owa/?path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&subject="+title+"&body="+details;
- //https://calendar.google.com/calendar/r/eventedit?text=My+Custom+Event&dates=20180512T230000Z/20180513T030000Z&details=For+details,+link+here:+https://example.com/tickets-43251101208&location=Garage+Boston+-+20+Linden+Street+-+Allston,+MA+02134
-
- window.open(linkToOpen);
-}
-
-function addToYahooCalendar(){
- var title = "Live Stream";
- var linkout = getById("director_block_1").innerText;
- var details = "Join the live stream as a performer at the following link:
===> "+linkout+"
To test your connection and camera ahead of time, please visit https://obs.ninja/speedtest
Do not share the details of this invite with others, unless explicitly told to.";
- details = details.split(' ').join('%20');
- details = details.split('&').join('%26');
- var linkToOpen = "https://calendar.yahoo.com?v60&title="+title+"&desc="+details;
- //https://calendar.google.com/calendar/r/eventedit?text=My+Custom+Event&dates=20180512T230000Z/20180513T030000Z&details=For+details,+link+here:+https://example.com/tickets-43251101208&location=Garage+Boston+-+20+Linden+Street+-+Allston,+MA+02134
-
- window.open(linkToOpen);
-}
-
-function toggle(ele, tog = false, inline = true) {
- var x = ele;
- if (x.style.display === "none") {
- if (inline) {
- x.style.display = "inline-block";
- } else {
- x.style.display = "block";
- }
- } else {
- x.style.display = "none";
- }
- if (tog) {
- if (tog.dataset.saved) {
- tog.innerHTML = tog.dataset.saved;
- delete(tog.dataset.saved);
- } else {
- tog.dataset.saved = tog.innerHTML;
- tog.innerHTML = "Hide This";
- }
- }
-}
-
-function toggleByDataset(filter) {
- var elements = document.querySelectorAll('[data-cluster="'+filter+'"]'); // ie: .cluster1
- for (var i = 0; i < elements.length; i++) {
- elements[i].classList.toggle('hidden');
- }
-}
-
-
-var SelectedAudioOutputDevices = []; // order matters.
-var SelectedAudioInputDevices = []; // ..
-var SelectedVideoInputDevices = []; // ..
-
-function enumerateDevices() {
-
- log("enumerated start");
-
- if (typeof navigator.enumerateDevices === "function") {
- log("enumerated failed 1");
- return navigator.enumerateDevices();
- } else if (typeof navigator.mediaDevices === "object" && typeof navigator.mediaDevices.enumerateDevices === "function") {
- return navigator.mediaDevices.enumerateDevices();
- } else {
- return new Promise((resolve, reject) => {
- try {
- if (window.MediaStreamTrack == null || window.MediaStreamTrack.getSources == null) {
- throw new Error();
- }
- window.MediaStreamTrack.getSources((devices) => {
- resolve(devices
- .filter(device => {
- return device.kind.toLowerCase() === "video" || device.kind.toLowerCase() === "videoinput";
- })
- .map(device => {
- return {
- deviceId: device.deviceId != null ? device.deviceId : ""
- , groupId: device.groupId
- , kind: "videoinput"
- , label: device.label
- , toJSON: /* istanbul ignore next */ function() {
- return this;
- }
- };
- }));
- });
- } catch (e) {
- errorlog(e);
- }
- });
- }
-}
-
-function requestOutputAudioStream() {
- try {
- //warnlog("GET USER MEDIA");
- return navigator.mediaDevices.getUserMedia({
- audio: true
- , video: false
- }).then(function(stream1) { // Apple needs thi to happen before I can access EnumerateDevices.
- log("get media sources; request audio stream");
- return enumerateDevices().then(function(deviceInfos) {
- stream1.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(); // I need to do this after the enumeration step, else it breaks firefox's labels
- });
- const audioOutputSelect = getById('outputSourceScreenshare');
- audioOutputSelect.remove(0);
- audioOutputSelect.removeAttribute("onclick");
-
- for (let i = 0; i !== deviceInfos.length; ++i) {
- const deviceInfo = deviceInfos[i];
- if (deviceInfo == null) {
- continue;
- }
- const option = document.createElement('option');
- option.value = deviceInfo.deviceId;
- if (deviceInfo.kind === 'audiooutput') {
- const option = document.createElement('option');
- if (audioOutputSelect.length === 0) {
- option.dataset.default = true;
- } else {
- option.dataset.default = false;
- }
- option.value = deviceInfo.deviceId || "default";
- if (option.value == session.sink) {
- option.selected = true;
- }
- option.text = deviceInfo.label || `Speaker ${audioOutputSelect.length + 1}`;
- audioOutputSelect.appendChild(option);
- } else {
- log('Some other kind of source/device: ', deviceInfo);
- }
- }
- });
- });
- } catch (e) {
- if (!(session.cleanOutput)) {
- if (window.isSecureContext) {
- warnUser("An error has occured when trying to access the default audio device. The reason is not known.");
- } else if ((iOS) || (iPad)) {
- warnUser("iOS version 13.4 and up is generally recommended; older than iOS 11 is not supported.");
- } else {
- warnUser("Error acessing the default audio device.\n\nThe website may be loaded in an insecure context.\n\nPlease see: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia");
- }
- }
- }
-}
-
-
-function requestAudioStream() {
- try {
- //warnlog("GET USER MEDIA");
- return navigator.mediaDevices.getUserMedia({
- audio: true
- , video: false
- }).then(function(stream1) { // Apple needs thi to happen before I can access EnumerateDevices.
- log("get media sources; request audio stream");
- return enumerateDevices().then(function(deviceInfos) {
- stream1.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(); // I need to do this after the enumeration step, else it breaks firefox's labels
- });
- log("updating audio");
- const audioInputSelect = getById('audioSourceScreenshare');
- audioInputSelect.remove(1);
- audioInputSelect.removeAttribute("onchange");
-
-
- for (let i = 0; i !== deviceInfos.length; ++i) {
- const deviceInfo = deviceInfos[i];
- if (deviceInfo == null) {
- continue;
- }
- const option = document.createElement('option');
- option.value = deviceInfo.deviceId;
- if (deviceInfo.kind === 'audioinput') {
- option.text = deviceInfo.label || `Microphone ${audioInputSelect.length + 1}`;
- audioInputSelect.appendChild(option);
- } else {
- log('Some other kind of source/device: ', deviceInfo);
- }
- }
- audioInputSelect.style.minHeight = ((audioInputSelect.childElementCount + 1) * 1.15 * 16) + 'px';
- audioInputSelect.style.minWidth = "342px";
- });
- });
- } catch (e) {
- if (!(session.cleanOutput)) {
- if (window.isSecureContext) {
- warnUser("An error has occured when trying to access the default audio device. The reason is not known.");
- } else if ((iOS) || (iPad)) {
- warnUser("iOS version 13.4 and up is generally recommended; older than iOS 11 is not supported.");
- } else {
- warnUser("Error acessing the default audio device.\n\nThe website may be loaded in an insecure context.\n\nPlease see: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia");
- }
- }
- }
-}
-
-
-function gotDevices(deviceInfos) { // https://github.com/webrtc/samples/blob/gh-pages/src/content/devices/input-output/js/main.js#L19
-
- log("got devices!");
- log(deviceInfos);
- try {
- const audioInputSelect = getById('audioSource');
-
- audioInputSelect.innerHTML = "";
-
- var option = document.createElement('input');
- option.type = "checkbox";
- option.value = "ZZZ";
- option.name = "multiselect1";
- option.id = "multiselect1";
- option.style.display = "none";
- option.checked = true;
-
-
- var label = document.createElement('label');
- label.for = option.name;
- label.innerHTML = '
No Audio ';
-
- var listele = document.createElement('li');
- listele.appendChild(option);
- listele.appendChild(label);
- audioInputSelect.appendChild(listele);
-
-
- option.onchange = function(event) { // make sure to clear 'no audio option' if anything else is selected
- if (!(getById("multiselect1").checked)) {
- getById("multiselect1").checked = true;
-
- if (SelectedAudioInputDevices.indexOf(event.currentTarget.value) > -1) {} else {
- SelectedAudioInputDevices.push(event.currentTarget.value);
- }
-
- log("CHECKED 1");
- } else {
-
- var list = document.querySelectorAll("#audioSource>li>input");
- for (var i = 0; i < list.length; i++) {
- if (list[i].id !== "multiselect1") {
- list[i].checked = false;
- }
- }
-
- while (SelectedAudioInputDevices.indexOf(event.currentTarget.value) > -1) {
- SelectedAudioInputDevices.splice(SelectedAudioInputDevices.indexOf(event.currentTarget.value), 1);
- }
- }
- };
-
- getById('multiselect-trigger').dataset.state = '0';
- getById('multiselect-trigger').classList.add('closed');
- getById('multiselect-trigger').classList.remove('open');
- getById('chevarrow1').classList.add('bottom');
-
- const videoSelect = getById('videoSourceSelect');
- const audioOutputSelect = getById('outputSource');
- const selectors = [videoSelect];
-
- const values = selectors.map(select => select.value);
- selectors.forEach(select => {
- while (select.firstChild) {
- select.removeChild(select.firstChild);
- }
- });
-
-
- function comp(a, b) {
- if (a.kind === 'audioinput') {
- return 0;
- } else if (a.kind === 'audiooutput') {
- return 0;
- }
- const labelA = a.label.toUpperCase();
- const labelB = b.label.toUpperCase();
- if (labelA > labelB) {
- return 1;
- } else if (labelA < labelB) {
- return -1;
- }
- return 0;
- }
- //deviceInfos.sort(comp); // I like this idea, but it messes with the defaults. I just don't know what it will do.
-
- // This is to hide NDI from default device. NDI Tools fucks up.
- var tmp = [];
- for (let i = 0; i !== deviceInfos.length; ++i) {
- deviceInfo = deviceInfos[i];
- if (!((deviceInfo.kind === 'videoinput') && (deviceInfo.label.toLowerCase().startsWith("ndi") || deviceInfo.label.toLowerCase().startsWith("newtek")))) {
- tmp.push(deviceInfo);
- }
- }
-
- for (let i = 0; i !== deviceInfos.length; ++i) {
- deviceInfo = deviceInfos[i];
- if ((deviceInfo.kind === 'videoinput') && (deviceInfo.label.toLowerCase().startsWith("ndi") || deviceInfo.label.toLowerCase().startsWith("newtek"))) {
- tmp.push(deviceInfo);
- log("V DEVICE FOUND = " + deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase());
- }
- }
- deviceInfos = tmp;
- log(deviceInfos);
-
- if ((session.audioDevice) && (session.audioDevice !== 1)) { // this sorts according to users's manual selection
- var tmp = [];
- for (let i = 0; i !== deviceInfos.length; ++i) {
- deviceInfo = deviceInfos[i];
- if ((deviceInfo.kind === 'audioinput') && (deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase().includes(session.audioDevice))) {
- tmp.push(deviceInfo);
- log("A DEVICE FOUND = " + deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase());
- } else if (deviceInfo.deviceId === session.audioDevice){
- tmp.push(deviceInfo);
- log("EXACT A DEVICE FOUND");
- }
- }
- for (let i = 0; i !== deviceInfos.length; ++i) {
- deviceInfo = deviceInfos[i];
- if (!((deviceInfo.kind === 'audioinput') && (deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase().includes(session.audioDevice)))) {
- if (deviceInfo.deviceId !== session.audioDevice){
- tmp.push(deviceInfo);
- }
- }
- }
-
- deviceInfos = tmp;
- log(session.audioDevice);
- log(deviceInfos);
- }
-
-
- 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];
- if ((deviceInfo.kind === 'videoinput') && (deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase().includes(session.videoDevice))) {
- tmp.push(deviceInfo);
- log("V DEVICE FOUND = " + deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase());
- } else if (deviceInfo.deviceId === session.videoDevice){
- tmp.push(deviceInfo);
- log("EXACT V DEVICE FOUND");
- }
- }
- 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);
- }
-
-
- var counter = 1;
- for (let i = 0; i !== deviceInfos.length; ++i) {
- const deviceInfo = deviceInfos[i];
- if (deviceInfo == null) {
- continue;
- }
-
- if (deviceInfo.kind === 'audioinput') {
- option = document.createElement('input');
- option.type = "checkbox";
- counter++;
- listele = document.createElement('li');
- if (counter == 2) {
- option.checked = true;
- listele.style.display = "block";
- option.style.display = "none";
- getById("multiselect1").checked = false;
- try{
- getById("multiselect1").parentNode.style.display = "none";
- } catch(e){}
- } else {
- listele.style.display = "none";
- }
-
-
- option.value = deviceInfo.deviceId || "default";
- option.name = "multiselect" + counter;
- option.id = "multiselect" + counter;
- label = document.createElement('label');
- label.for = option.name;
-
- label.innerHTML = " " + (deviceInfo.label || ("microphone " + ((audioInputSelect.length || 0) + 1)));
-
- listele.appendChild(option);
- listele.appendChild(label);
- audioInputSelect.appendChild(listele);
-
- option.onchange = function(event) { // make sure to clear 'no audio option' if anything else is selected
- getById("multiselect1").checked = false;
- log("UNCHECKED");
- if (!(CtrlPressed)) {
- document.querySelectorAll("#audioSource input[type='checkbox']").forEach(function(item) {
- if (event.currentTarget.id !== item.id) {
- item.checked = false;
-
- while (SelectedAudioInputDevices.indexOf(item.value) > -1) {
- SelectedAudioInputDevices.splice(SelectedAudioInputDevices.indexOf(item.value), 1);
- }
-
- } else {
- item.checked = true;
- if (SelectedAudioInputDevices.indexOf(event.currentTarget.value) > -1) {} else {
- SelectedAudioInputDevices.push(event.currentTarget.value);
- }
- }
- });
- }
- };
-
- } else if (deviceInfo.kind === 'videoinput') {
- option = document.createElement('option');
- option.value = deviceInfo.deviceId || "default";
- option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`;
- videoSelect.appendChild(option);
- } else if (deviceInfo.kind === 'audiooutput') {
- option = document.createElement('option');
- if (audioOutputSelect.length === 0) {
- option.dataset.default = true;
- } else {
- option.dataset.default = false;
- }
- option.value = deviceInfo.deviceId || "default";
- if (option.value == session.sink) {
- option.selected = true;
- }
- option.text = deviceInfo.label || `Speaker ${audioOutputSelect.length + 1}`;
- audioOutputSelect.appendChild(option);
- } else {
- log('Some other kind of source/device: ', deviceInfo);
- }
- }
-
- if (audioOutputSelect.childNodes.length == 0) {
- option = document.createElement('option');
- option.value = "default";
- option.text = "System Default";
- audioOutputSelect.appendChild(option);
- }
-
- option = document.createElement('option');
- option.text = "Disable Video";
- option.value = "ZZZ";
- videoSelect.appendChild(option); // NO AUDIO OPTION
-
- selectors.forEach((select, selectorIndex) => {
- if (Array.prototype.slice.call(select.childNodes).some(n => n.value === values[selectorIndex])) {
- select.value = values[selectorIndex];
- }
- });
-
- } catch (e) {
- errorlog(e);
- }
-}
-
-
-if (location.protocol !== 'https:') {
- if (!(session.cleanOutput)) {
- warnUser("SSL (https) is not enabled. This site will not work without it!
Try accessing the site from here instead. ");
- }
-}
-
-
-function getUserMediaVideoParams(resolutionFallbackLevel, isSafariBrowser) {
- switch (resolutionFallbackLevel) {
- case 0:
- if (isSafariBrowser) {
- return {
- width: {
- min: 360
- , ideal: 1920
- , max: 1920
- }
- , height: {
- min: 360
- , ideal: 1080
- , max: 1080
- }
- };
- } else {
- return {
- width: {
- min: 720
- , ideal: 1920
- , max: 1920
- }
- , height: {
- min: 720
- , ideal: 1080
- , max: 1920
- }
- };
- }
- case 1:
- if (isSafariBrowser) {
- return {
- width: {
- min: 360
- , ideal: 1280
- , max: 1280
- }
- , height: {
- min: 360
- , ideal: 720
- , max: 720
- }
- };
- } else {
- return {
- width: {
- min: 720
- , ideal: 1280
- , max: 1280
- }
- , height: {
- min: 720
- , ideal: 720
- , max: 1280
- }
- };
- }
- case 2:
- if (isSafariBrowser) {
- return {
- width: {
- min: 640
- }
- , height: {
- min: 360
- }
- };
- } else {
- return {
- width: {
- min: 240
- , ideal: 640
- , max: 1280
- }
- , height: {
- min: 240
- , ideal: 360
- , max: 1280
- }
- };
- }
- case 3:
- if (isSafariBrowser) {
- return {
- width: {
- min: 360
- , ideal: 1280
- , max: 1440
- }
- };
- } else {
- return {
- width: {
- min: 360
- , ideal: 1280
- , max: 1440
- }
- };
- }
- case 4:
- if (isSafariBrowser) {
- return {
- height: {
- min: 360
- , ideal: 720
- , max: 960
- }
- };
- } else {
- return {
- height: {
- ideal: 720
- , max: 960
- }
- };
- }
- case 5:
- if (isSafariBrowser) {
- return {
- width: {
- min: 360
- , ideal: 640
- , max: 1440
- }
- , height: {
- min: 360
- , ideal: 360
- , max: 720
- }
- };
- } else {
- return {
- width: {
- ideal: 640
- , max: 1920
- }
- , height: {
- ideal: 360
- , max: 1920
- }
- }; // same as default, but I didn't want to mess with framerates until I gave it all a try first
- }
- case 6:
- if (isSafariBrowser) {
- return {}; // iphone users probably don't need to wait any longer, so let them just get to it
- } else {
- return {
- width: {
- min: 360
- , ideal: 640
- , max: 3840
- }
- , height: {
- min: 360
- , ideal: 360
- , max: 2160
- }
- };
-
- }
- case 7:
- 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
- }
- , };
-
- case 8:
- return {
- width: {
- min: 360
- }
- , height: {
- min: 360
- }
- , frameRate: 10
- }; // 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.
- case 10:
- return {}
- default:
- return {};
- }
-}
-
-function addScreenDevices(device) {
- if (device.kind == "audio") {
- const audioInputSelect = getById('audioSource3');
- const listele = document.createElement('li');
- listele.style.display = "block";
-
- const option = document.createElement('input');
- option.type = "checkbox";
- option.checked = true;
-
- if (getById('multiselect-trigger3').dataset.state == 0) {
- option.style.display = "none";
- }
-
- option.value = device.id;
- option.name = device.label;
- option.dataset.type = "screen";
- option.label = device.label;
-
- const label = document.createElement('label');
- label.for = option.name;
- label.innerHTML = " " + device.label;
- listele.appendChild(option);
- listele.appendChild(label);
-
- option.onchange = function(event) { // make sure to clear 'no audio option' if anything else is selected
- log("change 4644");
- if (!(CtrlPressed)) {
- document.querySelectorAll("#audioSource3 input[type='checkbox']").forEach(function(item) {
- if (event.currentTarget.value !== item.value) { // this shoulnd't happen, but if it does.
-
- item.checked = false;
-
- if (item.dataset.type == "screen") {
- item.parentElement.parentElement.removeChild(item.parentElement);
- }
-
- while (SelectedAudioInputDevices.indexOf(item.value) > -1) {
- SelectedAudioInputDevices.splice(SelectedAudioInputDevices.indexOf(item.value), 1);
- }
-
- activatedPreview = false;
- grabAudio("videosource", "#audioSource3"); // exclude item.id
-
- } else {
- if (SelectedAudioInputDevices.indexOf(item.value) > -1) {} else {
- SelectedAudioInputDevices.push(item.value);
- }
-
- item.checked = true;
- activatedPreview = false;
- grabAudio("videosource", "#audioSource3", item.value); // exclude item.id. we will reconnect, even if already connected, as a way to 'reset' a device if it isn't working.
- }
- });
- }
- event.stopPropagation();
- return false;
- };
- audioInputSelect.appendChild(listele);
- getById("audioSourceNoAudio2").checked = false;
-
- } else if (device.kind == "video") {
- const videoSelect = getById('videoSource3');
- //const selectors = [ videoSelect];
- //const values = selectors.map(select => select.value);
- const option = document.createElement('option');
- option.value = device.id;
- option.text = device.label;
- option.selected = true;
- option.label = device.label;
- videoSelect.appendChild(option);
- }
-}
-
-function gotDevices2(deviceInfos) {
- log("got devices!");
- log(deviceInfos);
-
- getById("multiselect-trigger3").dataset.state = "0";
- getById("multiselect-trigger3").classList.add('closed');
- getById("multiselect-trigger3").classList.remove('open');
- getById("chevarrow2").classList.add('bottom');
-
- var knownTrack = false;
-
- try {
- const audioInputSelect = getById('audioSource3');
- const videoSelect = getById('videoSource3');
- const audioOutputSelect = getById('outputSource3');
- const selectors = [videoSelect];
-
-
- [audioInputSelect].forEach(select => {
- while (select.firstChild) {
- select.removeChild(select.firstChild);
- }
- });
-
- const values = selectors.map(select => select.value);
- selectors.forEach(select => {
- while (select.firstChild) {
- select.removeChild(select.firstChild);
- }
- });
-
- [audioOutputSelect].forEach(select => {
- while (select.firstChild) {
- select.removeChild(select.firstChild);
- }
- });
-
- var counter = 0;
- for (let i = 0; i !== deviceInfos.length; ++i) {
- const deviceInfo = deviceInfos[i];
- if (deviceInfo == null) {
- continue;
- }
-
- if (deviceInfo.kind === 'audioinput') {
- const option = document.createElement('input');
- option.type = "checkbox";
- counter++;
- const listele = document.createElement('li');
- listele.style.display = "none";
-
- try {
- session.streamSrc.getAudioTracks().forEach(function(track) {
- if (deviceInfo.label == track.label) {
- option.checked = true;
- listele.style.display = "inherit";
- }
- });
- } catch (e) {
- errorlog(e);
- }
-
- option.style.display = "none"
- option.value = deviceInfo.deviceId || "default";
- option.name = "multiselecta" + counter;
- option.id = "multiselecta" + counter;
- option.dataset.label = deviceInfo.label || ("microphone " + ((audioInputSelect.length || 0) + 1));
-
- const label = document.createElement('label');
- label.for = option.name;
-
- label.innerHTML = " " + (deviceInfo.label || ("microphone " + ((audioInputSelect.length || 0) + 1)));
-
- listele.appendChild(option);
- listele.appendChild(label);
- audioInputSelect.appendChild(listele);
-
- option.onchange = function(event) { // make sure to clear 'no audio option' if anything else is selected
- log("change 4768");
- if (!(CtrlPressed)) {
- document.querySelectorAll("#audioSource3 input[type='checkbox']").forEach(function(item) {
- if (event.currentTarget.value !== item.value) {
- item.checked = false;
- if (item.dataset.type == "screen") {
- item.parentElement.parentElement.removeChild(item.parentElement);
- }
- while (SelectedAudioInputDevices.indexOf(item.value) > -1) {
- SelectedAudioInputDevices.splice(SelectedAudioInputDevices.indexOf(item.value), 1);
- }
- } else {
- item.checked = true;
- if (SelectedAudioInputDevices.indexOf(event.currentTarget.value) > -1) {} else {
- SelectedAudioInputDevices.push(event.currentTarget.value);
- }
- }
- });
- } else {
-
- if (SelectedAudioInputDevices.indexOf(event.currentTarget.value) > -1) {} else {
- SelectedAudioInputDevices.push(event.currentTarget.value);
- }
-
- getById("audioSourceNoAudio2").checked = false;
- }
- };
-
- } else if (deviceInfo.kind === 'videoinput') {
- const option = document.createElement('option');
- option.value = deviceInfo.deviceId || "default";
- option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`;
- try {
- if (!knownTrack){
- if (session.canvasSource){
- session.canvasSource.srcObject.getVideoTracks().forEach(function(track) {
- if (option.text == track.label) {
- option.selected = true;
- knownTrack = true;
- }
- });
- }
- }
- if (!knownTrack){
- session.streamSrc.getVideoTracks().forEach(function(track) {
- if (option.text == track.label) {
- option.selected = true;
- knownTrack = true;
- }
- });
- }
- } catch (e) {
- errorlog(e);
- }
- videoSelect.appendChild(option);
-
- } else if (deviceInfo.kind === 'audiooutput') {
- const option = document.createElement('option');
- if (audioOutputSelect.length === 0) {
- option.dataset.default = true;
- } else {
- option.dataset.default = false;
- }
- option.value = deviceInfo.deviceId || "default";
- if (option.value == session.sink) {
- option.selected = true;
- }
- option.text = deviceInfo.label || `Speaker ${outputSelect.length + 1}`;
- audioOutputSelect.appendChild(option);
-
- } else {
- log('Some other kind of source/device: ', deviceInfo);
- }
- }
-
- if (audioOutputSelect.childNodes.length == 0) {
- const option = document.createElement('option');
- option.value = "default";
- option.text = "System Default";
- audioOutputSelect.appendChild(option);
- }
-
- ////////////
-
- session.streamSrc.getAudioTracks().forEach(function(track) { // add active ScreenShare audio tracks to the list
- log("Checking for screenshare audio");
- var matched = false;
- for (var i = 0; i !== deviceInfos.length; ++i) {
- var deviceInfo = deviceInfos[i];
- if (deviceInfo == null) {
- continue;
- }
- log("---");
- if (track.label == deviceInfo.label) {
- matched = true;
- continue;
- }
- }
- if (matched == false) { // Not a gUM device
-
- var listele = document.createElement('li');
- listele.style.display = "block";
- var option = document.createElement('input');
- option.type = "checkbox";
- option.value = track.id;
- option.checked = true;
- option.style.display = "none";
- option.name = track.label;
- option.label = track.label;
- option.dataset.type = "screen";
- const label = document.createElement('label');
- label.for = option.name;
- label.innerHTML = " " + track.label;
- listele.appendChild(option);
- listele.appendChild(label);
- option.onchange = function(event) { // make sure to clear 'no audio option' if anything else is selected
- log("change 4873");
- var trackid = null;
- if (!(CtrlPressed)) {
-
- document.querySelectorAll("#audioSource3 input[type='checkbox']").forEach(function(item) {
- if (event.currentTarget.value !== item.value) { // this shoulnd't happen, but if it does.
- item.checked = false;
- if (item.dataset.type == "screen") {
- item.parentElement.parentElement.removeChild(item.parentElement);
- }
- } else {
- event.currentTarget.checked = true;
- trackid = item.value;
- }
- });
- } else {
- //getById("audioSourceNoAudio2").checked=false;
- if (event.currentTarget.dataset.type == "screen") {
- event.currentTarget.parentElement.parentElement.removeChild(event.currentTarget.parentElement);
- }
- }
- activatedPreview = false;
- grabAudio("videosource", "#audioSource3", trackid); // exclude item.id.
- event.stopPropagation();
- return false;
- };
- audioInputSelect.appendChild(listele);
- }
- });
- /////////// no video option
- var optionss = false;
- if (screensharesupport) {
- optionss = document.createElement('option');
- optionss.text = "New Screen Share";
- optionss.value = "XXX";
- optionss.previous =
- videoSelect.appendChild(optionss); // NO AUDIO OPTION
- }
-
- option = document.createElement('option'); // no video
- option.text = "Disable Video";
- option.value = "ZZZ";
- videoSelect.appendChild(option);
- if (session.streamSrc.getVideoTracks().length == 0) {
- option.selected = true;
- } else if (knownTrack == false) {
- option = document.createElement('option'); // no video
- option.text = session.streamSrc.getVideoTracks()[0].label;
- option.value = "YYY";
- videoSelect.appendChild(option);
- option.selected = true;
-
- }
-
- if (optionss) {
- optionss.lastSelected = videoSelect.selectedIndex;
- }
-
- ///////////// /// NO AUDIO appended option
-
- var option = document.createElement('input');
- option.type = "checkbox";
- option.value = "ZZZ";
- option.style.display = "none"
- option.id = "audioSourceNoAudio2";
-
- var label = document.createElement('label');
- label.for = option.name;
- label.innerHTML = " No Audio";
- var listele = document.createElement('li');
-
- if (session.streamSrc.getAudioTracks().length == 0) {
- option.checked = true;
- } else {
- listele.style.display = "none";
- option.checked = false;
- }
- option.onchange = function(event) { // make sure to clear 'no audio option' if anything else is selected
- log("change 4938");
- if (!(CtrlPressed)) {
- document.querySelectorAll("#audioSource3 input[type='checkbox']").forEach(function(item) {
- if (event.currentTarget.value !== item.value) {
- item.checked = false;
- if (item.dataset.type == "screen") {
- item.parentElement.parentElement.removeChild(item.parentElement);
- }
-
- while (SelectedAudioInputDevices.indexOf(item.value) > -1) {
- SelectedAudioInputDevices.splice(SelectedAudioInputDevices.indexOf(item.value), 1);
- }
- } else {
- item.checked = true;
- if (SelectedAudioInputDevices.indexOf(event.currentTarget.value) > -1) {
- //
- } else {
- SelectedAudioInputDevices.push(event.currentTarget.value);
- }
- }
- });
- } else {
- document.querySelectorAll("#audioSource3 input[type='checkbox']").forEach(function(item) {
- if (event.currentTarget.value === item.value) {
- event.currentTarget.checked = true;
- if (SelectedAudioInputDevices.indexOf(event.currentTarget.value) > -1) {} else {
- SelectedAudioInputDevices.push(event.currentTarget.value);
- }
- } else {
- item.checked = false;
- if (item.dataset.type == "screen") {
- item.parentElement.parentElement.removeChild(item.parentElement);
- }
- while (SelectedAudioInputDevices.indexOf(item.value) > -1) {
- SelectedAudioInputDevices.splice(SelectedAudioInputDevices.indexOf(item.value), 1);
- }
- }
-
- });
- }
- };
- listele.appendChild(option);
- listele.appendChild(label);
- audioInputSelect.appendChild(listele);
-
- ////////////
-
-
- selectors.forEach((select, selectorIndex) => {
- if (Array.prototype.slice.call(select.childNodes).some(n => n.value === values[selectorIndex])) {
- select.value = values[selectorIndex];
- }
- });
-
- audioInputSelect.onchange = function() {
- log("Audio OPTION HAS CHANGED? 2");
- activatedPreview = false;
- setTimeout(function(){
- grabAudio("videosource", "#audioSource3");
- },10)
- };
- videoSelect.onchange = function(event) {
- try {
- if (event.target.options[event.target.options.selectedIndex].value === "XXX") {
- videoSelect.selectedIndex = event.target.options[event.target.options.selectedIndex].lastSelected;
- if (session.screenShareState == false) {
- toggleScreenShare();
- } else {
- toggleScreenShare(true);
- }
- return;
- }
- } catch (e) {}
- log("video source changed");
- activatedPreview = false;
- grabVideo(session.quality, "videosource", "select#videoSource3");
- enumerateDevices().then(gotDevices2).then(function() {
- session.screenShareState = false;
- pokeIframeAPI("screen-share-ended");
- getById("screensharebutton").classList.add("float");
- getById("screensharebutton").classList.remove("float2");
- });
- };
- getById("refreshVideoButton").onclick = function() {
- if (session.screenShareState) {
- log("can't refresh a screenshare");
- return;
- }
- log("video source changed");
- activatedPreview = false;
- grabVideo(session.quality, "videosource", "select#videoSource3");
- };
-
- audioOutputSelect.onchange = function() {
-
- if ((iOS) || (iPad)) {
- return;
- }
-
- try {
- var outputSelect = getById('outputSource3');
- session.sink = outputSelect.options[outputSelect.selectedIndex].value;
- } catch (e) {
- errorlog(e);
- }
- if (!session.sink){return;}
-
- try {
- if (document.getElementById("videosource")){
- getById("videosource").setSinkId(session.sink).then(() => {
- log("New Output Device:" + session.sink);
- }).catch(error => {
- errorlog(error);
- });
- }
-
- for (UUID in session.rpcs) {
- try{
- if (session.rpcs[UUID].videoElement){
- session.rpcs[UUID].videoElement.setSinkId(session.sink).then(() => {
- log("New Output Device for: " + UUID);
- }).catch(error => {
- errorlog(error);
- });
- }
- } catch(e){warnlog(e);}
- }
- } catch (e) {
- errorlog(e);
- }
- }
-
- } catch (e) {
- errorlog(e);
- }
-}
-
-function gotDevicesRemote(deviceInfos, UUID) {
-
- try {
- if (document.getElementById("remoteVideoSelect_"+UUID)){
- var videoSelect = document.getElementById("remoteVideoSelect_"+UUID);
- var length = videoSelect.options.length;
- for (i = length-1; i >= 0; i--) {
- videoSelect.options[i] = null;
- }
- } else {
- var videoSelect = document.createElement("select");
- videoSelect.id = "remoteVideoSelect_"+UUID;
- videoSelect.style = "max-width:180px;font-size: 70% !important; margin: 5px 5px 5px 0; padding:2px;";
- var buttonGO = document.createElement("button");
- buttonGO.innerHTML = '
Apply';
- buttonGO.style = "padding: 5px;";
- buttonGO.title = "This will ask the remote guest for permission to change";
- buttonGO.onclick = function(){
- var data = {}
- data.changeCamera = videoSelect.value;
- data.UUID = UUID;
- session.sendRequest(data, UUID); // Viewer is requesting the PUBLISHER
- };
-
- getById("advanced_video_director_" + UUID).appendChild(videoSelect);
- getById("advanced_video_director_" + UUID).appendChild(buttonGO);
- }
-
- if (document.getElementById("remoteAudioSelect_"+UUID)){
- var audioSelect = document.getElementById("remoteAudioSelect_"+UUID);
- var length = audioSelect.options.length;
- for (i = length-1; i >= 0; i--) {
- audioSelect.options[i] = null;
- }
- } else {
- var audioSelect = document.createElement("select");
- audioSelect.id = "remoteAudioSelect_"+UUID;
- audioSelect.style = "max-width:180px;font-size: 70% !important; margin: 5px 5px 5px 0; padding:2px;";
- var buttonGO = document.createElement("button");
- buttonGO.innerHTML = '
Apply';
- buttonGO.style = "padding: 5px;";
- buttonGO.title = "This will ask the remote guest for permission to change";
- buttonGO.onclick = function(){
- var data = {}
- data.changeMicrophone = audioSelect.value;
- data.UUID = UUID;
- session.sendRequest(data, UUID); // Viewer is requesting the PUBLISHER
- }
- getById("advanced_audio_director_" + UUID).appendChild(audioSelect);
- getById("advanced_audio_director_" + UUID).appendChild(buttonGO);
- }
-
- if (document.getElementById("remoteAudioOutputSelect_"+UUID)){
- var audioOutputSelect = document.getElementById("remoteAudioOutputSelect_"+UUID);
- var length = audioOutputSelect.options.length;
- for (i = length-1; i >= 0; i--) {
- audioOutputSelect.options[i] = null;
- }
- } else {
- var audioOutputSelect = document.createElement("select");
- audioOutputSelect.id = "remoteAudioOutputSelect_"+UUID;
- audioOutputSelect.style = "max-width:180px;font-size: 70% !important; margin: 5px 5px 5px 0; padding:2px;";
- var buttonGO = document.createElement("button");
- buttonGO.innerHTML = '
Apply';
- buttonGO.style = "padding: 5px;";
- buttonGO.title = "This will ask the remote guest for permission to change";
- buttonGO.onclick = function(){
- var data = {}
- data.changeSpeaker = audioOutputSelect.value;
- data.UUID = UUID;
- session.sendRequest(data, UUID); // Viewer is requesting the PUBLISHER
- }
- getById("advanced_audio_director_" + UUID).appendChild(audioOutputSelect);
- getById("advanced_audio_director_" + UUID).appendChild(buttonGO);
- getById("advanced_audio_director_" + UUID).appendChild(buttonGO);
- }
-
-
- for (let i = 0; i !== deviceInfos.length; ++i) {
- const deviceInfo = deviceInfos[i];
- if (deviceInfo == null) {
- continue;
- }
- if (deviceInfo.kind === 'videoinput'){
- const option = document.createElement('option');
- option.value = deviceInfo.deviceId || "default";
- option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`;
- videoSelect.appendChild(option);
-
- } else if (deviceInfo.kind === 'audioinput'){
- const option = document.createElement('option');
- option.value = deviceInfo.deviceId || "default";
- option.text = deviceInfo.label || `microphone ${audioSelect.length + 1}`;
- audioSelect.appendChild(option);
-
- } else if (deviceInfo.kind === 'audiooutput'){
- const option = document.createElement('option');
- option.value = deviceInfo.deviceId || "default";
- option.text = deviceInfo.label || `microphone ${audioOutputSelect.length + 1}`;
- audioOutputSelect.appendChild(option);
- }
- }
-
- } catch(e){errorlog(e);}
-}
-
-function playtone(screen = false) {
-
- if ((iOS) || (iPad)) {
- // try{
- // session.audioContext.resume();
- // } catch(e){errorlog(e);}
- var testtone = document.getElementById("testtone");
- if (testtone) {
- testtone.mute
- testtone.play();
- }
- return;
- }
-
- if (screen) {
- try{
- var outputSelect = getById('outputSourceScreenshare');
- session.sink = outputSelect.options[outputSelect.selectedIndex].value;
- } catch(e){errorlog(e);}
- }
-
- var testtone = document.getElementById("testtone");
- if (testtone) {
- if (session.sink) {
- try {
- testtone.setSinkId(session.sink).then(() => { // TODO: iOS doens't support sink. Needs to bypass if IOS
- log("changing audio sink:" + session.sink);
- testtone.play();
- }).catch(error => {
- errolog("couldn't set sink");
- errorlog(error);
- });
- } catch (e) {
- warnlog(e); // firefox?
- testtone.play();
- }
- } else {
- testtone.play();
- }
- }
-}
-
-async function getAudioOnly(selector, trackid = null, override = false) {
- var audioSelect = document.querySelector(selector).querySelectorAll("input");
- var audioList = [];
- var streams = [];
- log("getAudioOnly()");
- for (var i = 0; i < audioSelect.length; i++) {
- if (audioSelect[i].value == "ZZZ") {
- continue;
- } else if (trackid == audioSelect[i].value) { // skip already excluded
- continue;
- } else if ("screen" == audioSelect[i].dataset.type) { // skip already excluded ---------- !!!!!! DOES THIS MAKE SENSE? TODO: CHECK
- continue;
- } else if (audioSelect[i].checked) {
- log(audioSelect[i]);
- audioList.push(audioSelect[i]);
- }
- }
- for (var i = 0; i < audioList.length; i++) {
-
- if ((audioList[i].value == "default") && (session.echoCancellation !== false) && (session.autoGainControl !== false) && (session.noiseSuppression !== false)) {
- var constraint = {
- audio: true
- };
- } else { // Just trying to avoid problems with some systems that don't support these features
- var constraint = {
- audio: {
- deviceId: {
- exact: audioList[i].value
- }
- }
- };
- if (session.echoCancellation === false) {
- constraint.audio.echoCancellation = false;
- } else {
- constraint.audio.echoCancellation = true;
- }
- if (session.autoGainControl === false) {
- constraint.audio.autoGainControl = false;
- } else {
- constraint.audio.autoGainControl = true;
- }
- if (session.noiseSuppression === false) {
- constraint.audio.noiseSuppression = false;
- } else {
- constraint.audio.noiseSuppression = true;
- }
- }
- constraint.video = false;
- if (override !== false) {
- try {
- if (override.audio.deviceId == audioList[i].value) {
- constraint = override;
- }
- } catch (e) {}
- }
-
- if (session.audioInputChannels) {
- if (constraint.audio === true) {
- constraint.audio = {};
- constraint.audio.channelCount = session.audioInputChannels;
- } else if (constraint.audio) {
- constraint.audio.channelCount = session.audioInputChannels;
- }
- }
- log("CONSTRAINT");
- log(constraint);
- var stream = await navigator.mediaDevices.getUserMedia(constraint).then(function(stream2) {
- return stream2;
- }).catch(function(err) {
- warnlog(err);
- if (!(session.cleanOutput)) {
- if (override !== false) {
- if (err.name) {
- if (err.constraint) {
- warnUser(err['name'] + ": " + err['constraint']);
- }
- }
- }
- }
- }); // More error reporting maybe?
- if (stream) {
- streams.push(stream);
- }
- }
-
- return streams;
-}
-
-function applyMirror(mirror, eleName = 'previewWebcam') { // true unmirrors as its already mirrored
-
- var transFlip = "";
- var transNorm = "";
- if ((eleName == 'videosource') && (session.windowed)) {
- transFlip = " translate(0, 50%)";
- transNorm = " translate(0, -50%)";
- }
-
- if (session.mirrored == 2) {
- mirror = true;
- } else if (session.mirrored === 0) {
- mirror = true;
- }
-
-
- if (mirror) {
- if (session.mirrored && session.flipped) {
- getById(eleName).style.transform = " scaleX(-1) scaleY(-1)" + transFlip;
- getById(eleName).classList.add("mirrorControl");
- } else if (session.mirrored) {
- getById(eleName).style.transform = "scaleX(-1)" + transNorm;
- getById(eleName).classList.add("mirrorControl");
- } else if (session.flipped) {
- getById(eleName).style.transform = "scaleY(-1) scaleX(1)" + transFlip;
- getById(eleName).classList.remove("mirrorControl");
- } else {
- getById(eleName).style.transform = "scaleX(1)" + transNorm;
- getById(eleName).classList.remove("mirrorControl");
- }
- } else {
- if (session.mirrored && session.flipped) {
- getById(eleName).style.transform = " scaleX(1) scaleY(-1)" + transFlip;
- getById(eleName).classList.remove("mirrorControl");
- } else if (session.mirrored) {
- getById(eleName).style.transform = "scaleX(1)" + transNorm;
- getById(eleName).classList.remove("mirrorControl");
- } else if (session.flipped) {
- getById(eleName).style.transform = "scaleY(-1) scaleX(-1)" + transFlip;
- getById(eleName).classList.add("mirrorControl");
- } else {
- getById(eleName).style.transform = "scaleX(-1)" + transNorm;
- getById(eleName).classList.add("mirrorControl");
- }
- }
-}
-
-function cleanupMediaTracks() {
- try {
- if (session.streamSrc) {
- session.streamSrc.getTracks().forEach(function(track) {
- session.streamSrc.removeTrack(track);
- track.stop();
- log("stopping old track");
- });
- }
- if (session.videoElement) {
- session.videoElement.srcObject.getTracks().forEach(function(track) {
- session.videoElement.srcObject.removeTrack(track);
- track.stop();
- log("stopping old track");
- });
- }
- activatedPreview = false;
- } catch (e) {
- errorlog(e);
- }
-}
-
-/// Detect system changes; handle change or use for debugging
-var lastAudioDevice = null;
-var lastVideoDevice = null;
-var lastPlaybackDevice = null;
-
-var audioReconnectTimeout = null;
-var videoReconnectTimeout = null;
-var grabDevicesTimeout = null;
-var playbackReconnectTimeout = null;
-
-function reconnectDevices(event) { /// TODO: Perhaps change this to only if there is a DISCONNECT; rather than ON NEW DEVICE?
- if ((iOS) || (iPad)) {
- // try{
- // session.audioContext.resume();
- // } catch(e){errorlog(e);}
- // resetupAudioOut();
- return;
- }
- warnlog("A media device has changed");
-
- if (document.getElementById("previewWebcam")) {
- var outputSelect = document.getElementById("outputSource");
- if (!outputSelect) {
- errorlog("resetup audio failed");
- return;
- }
- try {
- session.sink = outputSelect.options[outputSelect.selectedIndex].value;
- } catch (e) {
- errorlog(e);
- }
- if (session.sink){
- try {
- getById("previewWebcam").setSinkId(session.sink).then(() => {}).catch(error => {
- warnlog(error);
- });
- } catch(e){errorlog(e);}
- }
- return;
- }
-
-
- if (session.streamSrc === null) {
- return;
- }
- if (document.getElementById("videosource") === null) {
- return;
- }
-
- try {
- session.streamSrc.getTracks().forEach(function(track) {
-
- if (track.readyState == "ended") {
- if (track.kind == "audio") {
- lastAudioDevice = track.label;
- } else if (track.kind == "video") {
- lastVideoDevice = track.label;
- }
- session.streamSrc.removeTrack(track);
- log("remove ended old track");
- }
- });
-
- session.videoElement.srcObject.getTracks().forEach(function(track) {
- if (track.readyState == "ended") {
- session.videoElement.srcObject.removeTrack(track);
- log("remove ended old track");
- }
- });
-
- } catch (e) {
- errorlog(e);
- }
-
- clearTimeout(audioReconnectTimeout);
- audioReconnectTimeout = null;
- if (lastAudioDevice) {
- audioReconnectTimeout = setTimeout(function() { // only reconnect same audio device. If reconnected, clear the disconnected flag.
- enumerateDevices().then(gotDevices2).then(function() {
- // TODO: check to see if any audio is connected?
- var streamConnected = false;
- var audioSelect = getById("audioSource3").querySelectorAll("input");
- for (var i = 0; i < audioSelect.length; i++) {
- if (audioSelect[i].value == "ZZZ") {
- continue;
- } else if (audioSelect[i].checked) {
- log("checked");
- streamConnected = true;
- break;
- }
- }
-
- if (!streamConnected) {
- for (var i = 0; i < audioSelect.length; i++) {
- if (audioSelect[i].value == "ZZZ") {
- continue;
- }
- //errorlog(lastAudioDevice + " : " + audioSelect[i].dataset.label);
- if (lastAudioDevice == audioSelect[i].dataset.label) { // if the last disconnected device matches.
- audioSelect[i].checked = true;
- streamConnected = true;
- lastAudioDevice = null;
- warnlog("DISCONNECTED AUDIO DEVICE RECONNECTED");
- //for (var j=0; j
check if session.sink still exists -> if not, select default default (track past last sink) -> if last disconnected devices comes back, reconnect it.
-
- // lastPlaybackDevice
- //if (session.sink){ // Let Chrome handle the audio automatically, since not manually specified.
- clearTimeout(playbackReconnectTimeout);
- playbackReconnectTimeout = setTimeout(function() {
- enumerateDevices().then(gotDevices2).then(function() {
- resetupAudioOut();
- });
- }, 500);
-
-}
-
-function resetupAudioOut() {
- if ((iOS) || (iPad)) {
- for (var UUID in session.rpcs) {
- if (session.rpcs[UUID].videoElement){
- try{
- session.rpcs[UUID].videoElement.pause().then(() => {
- setTimeout(function(uuid) {
- try{
- session.rpcs[uuid].videoElement.play().then(() => {
- log("toggle pause/play");
- });
- } catch(e){errorlog(e);}
- }, 0, UUID);
- });
- } catch(e){errorlog(e);}
- }
- }
- return;
- }
-
- var outputSelect = document.getElementById("outputSource3");
- if (!outputSelect) {
- errorlog("resetup audio failed");
- return;
- }
- log("Resetting Audio Output");
- var sinkSet = false;
- for (var i = 0; i < outputSelect.options.length; i++) {
- if (outputSelect.options[i].value == session.sink) {
- outputSelect.options[i].selected = true;
- sinkSet = true;
- }
- }
- if (sinkSet == false) {
- if (outputSelect.options[0]) {
- outputSelect.options[0].selected = true;
- sinkSet = outputSelect.value;
- }
- } else {
- sinkSet = session.sink;
- }
- if (sinkSet) {
- if (session.videoElement){
- session.videoElement.setSinkId(sinkSet).then(() => {}).catch(error => {
- errorlog(error);
- });
- }
- for (UUID in session.rpcs) {
- try{
- if (session.rpcs[UUID].videoElement){
- session.rpcs[UUID].videoElement.setSinkId(sinkSet).then(() => {
- log("New Output Device for: " + UUID);
- }).catch(error => {
- errorlog(error);
- });
- }
- } catch(e){warnlog(e);}
- }
- }
-}
-
-function obfuscateURL(input) {
- if (input.startsWith("https://obs.ninja/")) {
- input = input.replace('https://obs.ninja/', '');
- } else if (input.startsWith("http://obs.ninja/")) {
- input = input.replace('http://obs.ninja/', '');
- } else if (input.startsWith("obs.ninja/")) {
- input = input.replace('obs.ninja/', '');
- }
-
- input = input.replace('&view=', '&v=');
- input = input.replace('&view&', '&v&');
- input = input.replace('?view&', '?v&');
- input = input.replace('?view=', '?v=');
-
- input = input.replace('&videobitrate=', '&vb=');
- input = input.replace('?videobitrate=', '?vb=');
- input = input.replace('&bitrate=', '&vb=');
- input = input.replace('?bitrate=', '?vb=');
-
- input = input.replace('?audiodevice=', '?ad=');
- input = input.replace('&audiodevice=', '&ad=');
-
- input = input.replace('?label=', '?l=');
- input = input.replace('&label=', '&l=');
-
- input = input.replace('?stereo=', '?s=');
- input = input.replace('&stereo=', '&s=');
- input = input.replace('&stereo&', '&s&');
- input = input.replace('?stereo&', '?s&');
-
- input = input.replace('?webcam&', '?wc&');
- input = input.replace('&webcam&', '&wc&');
-
- input = input.replace('?remote=', '?rm=');
- input = input.replace('&remote=', '&rm=');
-
- input = input.replace('?password=', '?p=');
- input = input.replace('&password=', '&p=');
-
- input = input.replace('&maxvideobitrate=', '&mvb=');
- input = input.replace('?maxvideobitrate=', '?mvb=');
-
- input = input.replace('&maxbitrate=', '&mvb=');
- input = input.replace('?maxbitrate=', '?mvb=');
-
- input = input.replace('&height=', '&h=');
- input = input.replace('?height=', '?h=');
-
- input = input.replace('&width=', '&w=');
- input = input.replace('?width=', '?w=');
-
- input = input.replace('&quality=', '&q=');
- input = input.replace('?quality=', '?q=');
-
- input = input.replace('&cleanoutput=', '&clean=');
- input = input.replace('?cleanoutput=', '?clean=');
-
- input = input.replace('&maxviewers=', '&clean=');
- input = input.replace('?maxviewers=', '?clean=');
-
- input = input.replace('&framerate=', '&fr=');
- input = input.replace('?framerate=', '?fr=');
-
- input = input.replace('&fps=', '&fr=');
- input = input.replace('?fps=', '?fr=');
-
- input = input.replace('&permaid=', '&push=');
- input = input.replace('?permaid=', '?push=');
-
- input = input.replace('&roomid=', '&r=');
- input = input.replace('?roomid=', '?r=');
-
- input = input.replace('&room=', '&r=');
- input = input.replace('?room=', '?r=');
-
- log(input);
- var key = "OBSNINJAFORLIFE";
- var encrypted = CryptoJS.AES.encrypt(input, key);
- var output = "https://invite.cam/" + encrypted.toString();
- return output;
-}
-
-
-
-try {
- navigator.mediaDevices.ondevicechange = reconnectDevices;
-} catch (e) {
- errorlog(e);
-}
-
-
-function updateConnectionStatus() {
- warnlog("Connection type changed from " + session.stats.network_type + " to " + Connection.effectiveType);
- session.stats.network_type = Connection.effectiveType + " / " + Connection.type;
- session.ping();
-}
-
-try {
- var Connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
- session.stats.network_type = Connection.effectiveType + " / " + Connection.type;
- Connection.addEventListener('change', updateConnectionStatus);
-} catch (e) {}
-
-
-
-var beforeScreenShare = null; // video
-var screenShareAudioTrack = null;
-async function toggleScreenShare(reload = false) { ////////////////////////////
-
- if (reload) {
- await grabScreen(quality = 0, audio = true, videoOnEnd = true).then(res => {
- if (res != false) {
- session.screenShareState = true;
- getById("screensharebutton").classList.add("float2");
- getById("screensharebutton").classList.remove("float");
- enumerateDevices().then(gotDevices2).then(function() {});
- }
-
- });
- return;
- }
-
-
- if (session.screenShareState == false) { // adding a screen
-
- await grabScreen(quality = 0, audio = true, videoOnEnd = true).then(res => {
- if (res != false) {
- session.screenShareState = true;
- getById("screensharebutton").classList.add("float2");
- getById("screensharebutton").classList.remove("float");
- enumerateDevices().then(gotDevices2).then(function() {});
- }
-
- });
-
- } else { // removing a screen . session.screenShareState already true true /////////////////////////////////
-
-
- session.screenShareState = false;
- pokeIframeAPI("screen-share-ended");
-
- if (beforeScreenShare) {
-
- session.streamSrc.getAudioTracks().forEach(function(track) { // previous video track; saving it. Must remove the track at some point.
- if (screenShareAudioTrack == track) { // since there are more than one audio track, lets see if we can remove JUST the audio track for the screen share.
- session.streamSrc.removeTrack(track);
- track.stop();
- }
- });
- session.streamSrc.getVideoTracks().forEach(function(track) {
- //errorlog(track);
- session.streamSrc.removeTrack(track);
- track.stop();
- });
-
- session.videoElement.srcObject.getVideoTracks().forEach(function(track) {
- //errorlog(track);
- session.videoElement.srcObject.removeTrack(track);
- track.stop();
- });
-
- getById("screensharebutton").classList.add("float");
- getById("screensharebutton").classList.remove("float2");
-
- session.streamSrc.addTrack(beforeScreenShare); // add back in the video track we had before we started screen sharing. It should be NULL if we changed the video track else where (such as via the settings). #TODO:
- session.videoElement.srcObject.addTrack(beforeScreenShare);
-
- toggleVideoMute(true);
- for (UUID in session.pcs) {
- 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
- var senders = session.pcs[UUID].getSenders(); // 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 (sender.track) {
- if (sender.track && sender.track.kind == "video") {
- sender.replaceTrack(beforeScreenShare); // replace may not be supported by all browsers. eek.
- sender.track.enabled = true;
- added = true;
- }
- }
- });
- if (added == false) {
- session.pcs[UUID].addTrack(beforeScreenShare, stream);
- 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);
- }
- }
- session.refreshScale();
- beforeScreenShare = null;
- }
- toggleSettings(forceShow = true);
- //enumerateDevices().then(gotDevices2).then(function(){
- //grabVideo();
- //grabAudio();
- // toggleSettings(forceShow=true);
- //});
-
-
- }
-}
-var ElectronDesktopCapture = false;
-if (navigator.userAgent.toLowerCase().indexOf(' electron/') > -1) { // this enables Screen Capture in Electron
- try {
- const { desktopCapturer} = require('electron'); // This is definitely Electron specific. Requires Node Integration to be on, which is a potential security hazzard
- window.navigator.mediaDevices.getDisplayMedia = () => {
- return new Promise(async (resolve, reject) => {
- try {
- const sources = await desktopCapturer.getSources({ types: ['screen', 'window'] });
-
- const selectionElem = document.createElement('div');
- selectionElem.classList = 'desktop-capturer-selection';
- selectionElem.innerHTML = `
-
- `;
- document.body.appendChild(selectionElem);
-
- document.getElementById('cancelscreenshare').addEventListener('click', async () => {
- selectionElem.remove()
- reject(err)
- });
-
-
- document.querySelectorAll('.desktop-capturer-selection__btn').forEach(button => {
- button.addEventListener('click', async () => {
- try {
- const id = button.getAttribute('data-id')
- const source = sources.find(source => source.id === id)
- if(!source) {
- throw new Error(`Source with id ${id} does not exist`)
- }
-
- const stream = await window.navigator.mediaDevices.getUserMedia({
- audio: false,
- video: {
- mandatory: {
- chromeMediaSource: 'desktop',
- chromeMediaSourceId: source.id,
- maxFrameRate: 60
- }
- }
- })
- resolve(stream)
-
- selectionElem.remove()
- } catch (err) {
- errorlog('Error selecting desktop capture source:', err)
- reject(err)
- }
- })
- });
- } catch (err) {
- errorlog('Error displaying desktop capture sources:', err);
- reject(err);
- }
- })
- }
- ElectronDesktopCapture = true;
- } catch(e){
- warnlog("couldn't load electron's screen capture; you might need to decrease security permissions a bit.");
- }
-}
-
-async function grabScreen(quality = 0, audio = true, videoOnEnd = false) {
- if (!navigator.mediaDevices.getDisplayMedia) {
- if (!(session.cleanOutput)) {
- setTimeout(function() {
- warnUser("Sorry, your browser is not supported. Please use the desktop versions of Firefox or Chrome instead");
- }, 1);
- }
- return false;
- }
-
- if (navigator.userAgent.toLowerCase().indexOf(' electron/') > -1) {
- if (!ElectronDesktopCapture){
- if (!(session.cleanOutput)) {
- warnUser("Your Electron app does not support Screen Capture. Update your Electron Capture app and then enable Elevated Privileges (right click) to access screen-sharing.");
- }
- return false;
- }
- }
-
- if (quality == 0) { // I'm going to go with default quality in most cases, as I assume Dynamic screenshare is going to want low-fps / high def.
- var width = {
- ideal: 1920
- };
- var height = {
- ideal: 1080
- };
- } else if (quality == 1) {
- var width = {
- ideal: 1280
- };
- var height = {
- ideal: 720
- };
- } else if (quality == 2) {
- var width = {
- ideal: 640
- };
- var height = {
- ideal: 360
- };
- } else if (quality >= 3) { // lowest
- var width = {
- ideal: 320
- };
- var height = {
- ideal: 180
- };
- }
-
- if (session.width) {
- width = {
- ideal: session.width
- };
- }
- if (session.height) {
- height = {
- ideal: session.height
- };
- }
-
- var constraints = { // this part is a bit annoying. Do I use the same settings? I can add custom setting controls here later
- audio: {
- echoCancellation: false, // For screen sharing, we want it off by default.
- autoGainControl: false
- , noiseSuppression: false
- }
- , video: {
- width: width
- , height: height
- }
- //,cursor: {exact: "none"}
- };
-
- try {
- let supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
- if (supportedConstraints.cursor) {
- constraints.video.cursor = "never";
- }
- } catch(e){
- warnlog("navigator.mediaDevices.getSupportedConstraints() not supported");
- }
-
- if (session.echoCancellation === true) {
- constraints.audio.echoCancellation = true;
- }
- if (session.autoGainControl === true) {
- constraints.audio.autoGainControl = true;
- }
- if (session.noiseSuppression === true) {
- constraints.audio.noiseSuppression = true;
- }
- if (audio == false) {
- constraints.audio = false;
- }
-
- if (session.framerate) {
- constraints.video.frameRate = session.framerate;
- } else if (session.maxframerate !== false){ // not limiting screen share's fps with quality=2 due to gaming centric nature
- constraints.video.frameRate = {
- ideal: session.maxframerate,
- max: session.maxframerate
- };
- }
-
- return navigator.mediaDevices.getDisplayMedia(constraints).then(function(stream) {
- log("adding video tracks 2245");
-
- var eleName = "videosource";
- try {
- if (session.streamSrc) {
- session.streamSrc.getVideoTracks().forEach(function(track) {
- //track.stop();
- beforeScreenShare = track;
- session.streamSrc.removeTrack(track);
- log("stopping video track");
- });
- session.videoElement.srcObject.getVideoTracks().forEach(function(track) {
- //track.stop();
- session.videoElement.srcObject.removeTrack(track);
- log("stopping video track 2");
- });
- } else {
- session.streamSrc = new MediaStream();
- session.videoElement.srcObject = session.streamSrc;
- log("CREATE NEW STREAM");
- }
- } catch (e) {
- warnlog(e);
- }
- //session.videoElement.srcObject = session.streamSrc;
-
- // Let's not pass the AUDIO thru the webaudio filter. It's screen share after all.
-
- try {
- stream.getVideoTracks()[0].onended = function() { // if screen share stops,
-
- session.streamSrc.getVideoTracks().forEach(function(track) {
- session.streamSrc.removeTrack(track);
- track.stop();
- log("stopping video track 3");
- });
- session.videoElement.srcObject.getVideoTracks().forEach(function(track) {
- session.videoElement.srcObject.removeTrack(track);
- track.stop();
- log("stopping video track 4");
- });
-
- session.screenShareState = false;
- pokeIframeAPI("screen-share-ended");
-
- getById("screensharebutton").classList.add("float");
- getById("screensharebutton").classList.remove("float2");
-
- if (videoOnEnd == true) {
- //activatedPreview = false;
-
- if (beforeScreenShare) {
- session.streamSrc.addTrack(beforeScreenShare);
- session.videoElement.srcObject.addTrack(beforeScreenShare);
- if (beforeScreenShare.kind == "video") {
- toggleVideoMute(true);
- for (UUID in session.pcs) {
- 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
- var senders = session.pcs[UUID].getSenders(); // 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 (sender.track) {
- if (sender.track && sender.track.kind == "video") {
- sender.replaceTrack(beforeScreenShare); // replace may not be supported by all browsers. eek.
- sender.track.enabled = true;
- added = true;
- }
- }
- });
- if (added == false) {
- session.pcs[UUID].addTrack(beforeScreenShare, stream);
- 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);
- }
- }
- session.refreshScale();
- }
- beforeScreenShare = null;
- }
-
- toggleSettings(forceShow = true);
- //grabVideo(eleName='videosource', selector="select#videoSource3");
-
-
- } else {
- grabScreen();
- }
- };
- } catch (e) {
- log("No Video selected; screensharing?");
- }
-
- stream.getTracks().forEach(function(track) {
- addScreenDevices(track);
-
- session.streamSrc.addTrack(track, stream); // Lets not add the audio to this preview; echo can be annoying
- session.videoElement.srcObject.addTrack(track, stream); // I should probably add the remote control to his ; #TODO:
-
- if (track.kind == "video") {
- toggleVideoMute(true);
- for (UUID in session.pcs) {
- 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
- var senders = session.pcs[UUID].getSenders(); // 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 (sender.track) {
- if (sender.track && sender.track.kind == "video") {
- sender.replaceTrack(track); // replace may not be supported by all browsers. eek.
- sender.track.enabled = true;
- added = true;
- }
- }
- });
- if (added == false) {
- session.pcs[UUID].addTrack(track, stream);
- 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);
- }
- }
- session.refreshScale();
- } else {
- toggleMute(true); // I might want to move this outside the loop, but whatever
- for (UUID in session.pcs) {
- try {
- if (session.pcs[UUID].allowAudio == true) {
- session.pcs[UUID].addTrack(track, stream); // If screen sharing, we will add audio; not replace.
- }
- } catch (e) {
- errorlog(log);
- }
- }
- screenShareAudioTrack = track;
- }
- });
- applyMirror(true, eleName);
- return true;
- }).catch(function(err) {
- errorlog(err);
- if ((err.name == "NotAllowedError") || (err.name == "PermissionDeniedError")) {
- // User Stopped it.
- } else {
- if (audio == true) {
- setTimeout(function() {
- grabScreen(quality, false);
- }, 1);
- }
- if (!(session.cleanOutput)) {
- setTimeout(function() {
- warnUser(err);
- }, 1); // TypeError: Failed to execute 'getDisplayMedia' on 'MediaDevices': Audio capture is not supported
- }
- }
- return false;
- });
-}
-
-function toggleRoomSettings(){
-
- toggle(getById('roomSettings'));
-
-
- if (document.getElementById("modalBackdrop")){
- getById("modalBackdrop").innerHTML = ''; // Delete modal
- getById("modalBackdrop").remove();
- } else {
- zindex = 25;
- getById('roomSettings').style.zIndex = 25;
- var modalTemplate = `
`;
- document.body.insertAdjacentHTML("beforeend", modalTemplate); // Insert modal at body end
- document.getElementById("modalBackdrop").addEventListener("click", toggleRoomSettings);
- document.getElementById('trbSettingInput').value = session.totalRoomBitrate;
- document.getElementById('trbSettingInputFeedback').innerHTML = session.totalRoomBitrate;
-
- }
-
-}
-
-function changeTRB(ele){
- session.totalRoomBitrate = parseInt(ele.value);
- var msg = {};
- msg.directorSettings={};
- msg.directorSettings.totalRoomBitrate=session.totalRoomBitrate;
- session.sendMessage(msg);
-}
-
-function sendMediaDevices(UUID){
- enumerateDevices().then(function(deviceInfos){
- var data = {};
- data.UUID = UUID;
- data.mediaDevices = deviceInfos;
- session.sendMessage(data, data.UUID);
- });
-}
-
-function changeVideoDevice(index, quality=0){
- enumerateDevices().then(gotDevices2).then(function() {
- activatedPreview=false;
- document.getElementById("videoSource3").selectedIndex = index+"";
- grabVideo(quality, "videosource", "#videoSource3");
- });
-}
-
-function changeAudioDevice(index){
- enumerateDevices().then(gotDevices2).then(function() {
- activatedPreview=false;
- var audioSelect = document.getElementById("audioSource3").querySelectorAll("input");
- for (var i = 0; i < audioSelect.length; i++) {
- audioSelect[i].checked = false;
- }
- audioSelect[index-1].checked = true;
- grabAudio("videosource", "#audioSource3");
- });
-}
-
-function changeVideoDeviceById(deviceID, UUID){
- enumerateDevices().then(gotDevices2).then(function() {
- var opts = document.getElementById("videoSource3").options;
- var index = false
- for (var opt, j = 0; opt = opts[j]; j++) {
- if (opt.value == deviceID) {
- index = j;
- break;
- }
- }
- var allow = false
- if (index!==false){
- window.focus();
- allow = confirm("Allow the director to change your video device to :"+opts[index].text+" ?");
- }
- if (allow){
- document.getElementById("videoSource3").selectedIndex = j;
- activatedPreview=false;
- grabVideo(0, "videosource", "#videoSource3");
- setTimeout(function(uuid){
- var data = {};
- data.UUID = uuid;
- data.videoOptions = listVideoSettingsPrep();
- sendMediaDevices(data.UUID);
- session.sendMessage(data, data.UUID);
- },1000, UUID);
- }
- });
-}
-
-function changeAudioDeviceById(deviceID, UUID){
- var allow = false;
- window.focus();
- allow = confirm("Allow the director to change your audio mic source?");
- if (allow){
- enumerateDevices().then(gotDevices2).then(function() {
- var audioSelect = document.getElementById("audioSource3").querySelectorAll("input");
- for (var i = 0; i < audioSelect.length; i++) {
- if (audioSelect[i].value == deviceID){
- audioSelect[i].checked=true;
- } else {
- audioSelect[i].checked = false;
- }
- }
- activatedPreview=false;
- grabAudio("videosource", "#audioSource3");
- setTimeout(function(uuid){
- var data = {};
- data.UUID = uuid;
- data.audioOptions = listAudioSettingsPrep();
- session.sendMessage(data, data.UUID);
- },1000, UUID);
- });
- }
-}
-
-function changeAudioOutputDeviceById(deviceID, UUID){
- errorlog(deviceID);
- enumerateDevices().then(gotDevices2).then(function() {
- if (!document.getElementById("outputSource3")){return;}
- var opts = document.getElementById("outputSource3").options;
- var index = false
- for (var opt, j = 0; opt = opts[j]; j++) {
- if (opt.value == deviceID) {
- index = j;
- break;
- }
- }
- var allow = false
- if (index!==false){
- window.focus();
- allow = confirm("Allow the director to change your audio's speaker to :"+opts[index].text+" ?");
- }
- if (allow){
- document.getElementById("outputSource3").selectedIndex = j;
- session.sink = document.getElementById("outputSource3").options[document.getElementById("outputSource3").selectedIndex].value;
- resetupAudioOut();
- setTimeout(function(uuid){
- var data = {};
- data.UUID = uuid;
- data.videoOptions = listVideoSettingsPrep();
- sendMediaDevices(data.UUID);
- session.sendMessage(data, data.UUID);
- },1000, UUID);
- }
- });
-}
-
-
-
-var getUserMediaRequestID = 0;
-var grabVideoUserMediaTimeout = null;
-var grabVideoTimer = null;
-
-async function grabVideo(quality = 0, eleName = 'previewWebcam', selector = "select#videoSourceSelect") {
- if (activatedPreview == true) {
- log("activated preview return 2");
- return;
- }
- activatedPreview = true;
- log("Grabbing video: " + quality);
- if (grabVideoTimer) {
- clearTimeout(grabVideoTimer);
- }
- log("element:" + eleName);
-
- var wasDisabled = true;
- try {
- if (session.streamSrc) {
-
- if (session.canvasSource){
- session.canvasSource.srcObject.getTracks().forEach(function(trk) {
- session.canvasSource.srcObject.removeTrack(trk);
- wasDisabled=false;
- });
- }
-
- if (session.videoElement.srcObject) {
- session.videoElement.srcObject.getVideoTracks().forEach(function(track) {
- session.videoElement.srcObject.removeTrack(track);
- session.videoElement.load();
- wasDisabled=false;
- });
- }
- session.streamSrc.getVideoTracks().forEach(function(track) {
- session.streamSrc.removeTrack(track);
- track.stop();
- log("track removed");
- wasDisabled=false;
- });
-
- } else {
- //log(session.videoElement.srcObject.getTracks());
- session.streamSrc = new MediaStream();
- session.videoElement.srcObject = session.streamSrc;
- log("CREATE NEW STREAM");
- }
- } catch (e) {
- errorlog(e);
- }
-
- session.videoElement.controls = false;
-
- log("selector: " + selector);
- var videoSelect = document.querySelector(selector); // document.querySelector("videoSource3").value == "ZZZ"
- log(videoSelect);
- var mirror = false;
-
- if (!videoSelect || videoSelect.value == "ZZZ") { // if there is no video, or if manually set to audio ready, then do this step.
- warnlog("ZZZ SET - so no VIDEO");
- if ((eleName == "previewWebcam") && document.getElementById("previewWebcam")){
- if (session.autostart) {
- publishWebcam(); // no need to mirror as there is no video...
- return;
- } else {
- log("4462");
- updateStats();
- var gowebcam = getById("gowebcam");
- if (gowebcam) {
- gowebcam.disabled = false;
- gowebcam.dataset.ready = "true";
- gowebcam.innerHTML = "START";
- miniTranslate(gowebcam, "start");
- }
- }
- } else { // If they disabled the video but not in preview mode; but actualy live. We will want to remove the stream from the publishing
- // we don't want to do this otherwise, as we are "replacing" the track in other cases.
- // this does cause a problem, as previous bitrate settings & resolutions might not be applied if switched back.... must test
- for (UUID in session.pcs) {
- var senders = session.pcs[UUID].getSenders(); // for any connected peer, update the video they have if connected with a video already.
- 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 (sender.track && sender.track.kind == "video") {
- sender.track.enabled = false;
- getById("mutevideobutton").classList.add("advanced"); // hide the mute button, so they can't unmute while no video.
- //session.pcs[UUID].removeTrack(sender); // replace may not be supported by all browsers. eek.
- errorlog("DELETED SENDER");
- }
- });
-
- }
- var msg = {};
- msg.videoMuted = true;
- session.sendMessage(msg);
- }
- // end
- } else {
- var sq = 0;
- if (session.quality === false) {
- sq = session.quality_wb;
- } else if (session.quality > 2) { // 1080, 720, and 360p
- sq = 2; // hacking my own code. TODO: ugly, so I need to revisit this.
- } else {
- sq = session.quality;
- }
-
- if (session.director && (quality !== false)){ // URL-based quality won't matter if DIRECTOR;
- // quality = quality;
- } else if ((quality === false) || (quality < sq)) {
- quality = sq; // override the user's setting
- }
-
-
- if ((iOS) || (iPad)) { // iOS will not work correctly at 1080p; likely a h264 codec issue.
- if (quality == 0) {
- quality = 1;
- }
- }
-
- var constraints = {
- audio: false,
- video: getUserMediaVideoParams(quality, iOS)
- };
-
- log("Quality selected:" + quality);
- var _, sUsrAg = navigator.userAgent;
-
-
- if ((iOS) || (iPad)) {
- constraints.video.deviceId = {
- exact: videoSelect.value
- }; // iPhone 6s compatible ? Needs to be exact for iPhone 6s
-
- } else if (sUsrAg.indexOf("Firefox") > -1) {
- constraints.video.deviceId = {
- exact: videoSelect.value
- }; // Firefox is a dick. Needs it to be exact.
-
- } else if (videoSelect.options[videoSelect.selectedIndex].text.includes("NDI Video")) { // NDI does not like "EXACT"
- constraints.video.deviceId = videoSelect.value;
-
- } else {
- constraints.video.deviceId = {
- exact: videoSelect.value
- }; // Default. Should work for Logitech, etc.
- }
-
- if (session.width) {
- constraints.video.width = {
- exact: session.width
- }; // manually specified - so must be exact
- }
- if (session.height) {
- constraints.video.height = {
- exact: session.height
- };
- }
- if (session.framerate) {
- constraints.video.frameRate = {
- exact: session.framerate
- };
- } else if (session.maxframerate != false){
- constraints.video.frameRate = {
- ideal: session.maxframerate,
- max: session.maxframerate
- };
- }
- if (session.ptz){
- if (constraints.video && constraints.video!==true){
- if (getChromeVersion() && getChromeVersion()>80){
- constraints.video.pan=true;
- constraints.video.tilt=true;
- constraints.video.zoom=true;
- }
- }
- }
- var obscam = false;
- log(videoSelect.options[videoSelect.selectedIndex].text);
- if (videoSelect.options[videoSelect.selectedIndex].text.startsWith("OBS-Camera")) { // OBS Virtualcam
- mirror = true;
- obscam = true;
- } else if (videoSelect.options[videoSelect.selectedIndex].text.startsWith("OBS Virtual Camera")) { // OBS Virtualcam
- mirror = true;
- obscam = true;
- } else if (videoSelect.options[videoSelect.selectedIndex].text.includes(" back")) { // Android
- mirror = true;
- } else if (videoSelect.options[videoSelect.selectedIndex].text.includes(" rear")) { // Android
- mirror = true;
- } else if (videoSelect.options[videoSelect.selectedIndex].text.includes("NDI Video")) { // NDI Virtualcam
- mirror = true;
- } else if (videoSelect.options[videoSelect.selectedIndex].text.startsWith("Back Camera")) { // iPhone and iOS
- mirror = true;
- } else {
- mirror = false;
- }
- session.mirrorExclude = mirror;
-
- log(constraints);
- clearTimeout(grabVideoUserMediaTimeout);
- getUserMediaRequestID += 1;
- grabVideoUserMediaTimeout = setTimeout(function(gumID) {
- navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
-
- if (getUserMediaRequestID !== gumID) {
- errorlog("GET USER MEDIA CALL HAS EXPIRED");
- return;
- }
- log("adding video tracks 2412");
- stream.getVideoTracks().forEach(function(track) {
- if (!session.streamSrc) {
- session.streamSrc = new MediaStream();
- }
- if (!session.videoElement) {
- if (document.getElementById("previewWebcam")) {
- session.videoElement = document.getElementById("previewWebcam");
- } else if (document.getElementById("videosource")) {
- session.videoElement = document.getElementById("videosource");
- }
-
- }
-
- if (session.effects) {
- track = applyEffects(track,stream);
- } else {
- log(session.videoElement);
- session.streamSrc.addTrack(track, stream); // add video track to the preview video
- session.videoElement.srcObject.addTrack(track, stream); // add video track to the preview video
- }
-
- toggleVideoMute(true);
- for (UUID in session.pcs) {
- try {
- if (((iOS) || (iPad)) && (session.pcs[UUID].guest == true)) {
- warnlog("iOS and GUest detected");
- } else 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;
- session.pcs[UUID].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") {
- sender.replaceTrack(track); // replace may not be supported by all browsers. eek.
- sender.track.enabled = true;
- added = true;
- }
-
- });
- if (added == false) {
- session.pcs[UUID].addTrack(track, stream); // can't replace, so adding
- 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);
- }
- }
-
- if (wasDisabled && !session.videoMuted){
- var msg = {};
- msg.videoMuted = session.videoMuted;
- session.sendMessage(msg);
- }
-
- session.refreshScale();
- });
-
- applyMirror(mirror, eleName);
-
- if ((eleName == "previewWebcam") && document.getElementById("previewWebcam")){
- if (session.autostart) {
- publishWebcam();
- } else {
- log("4620");
- if (document.getElementById("gear_webcam")) {
- updateStats(obscam);
- }
- var gowebcam = getById("gowebcam");
- if (gowebcam) {
- gowebcam.disabled = false;
- gowebcam.dataset.ready = "true";
- gowebcam.innerHTML = "START";
- miniTranslate(gowebcam, "start");
- }
- }
- } else if (getById("gear_webcam3").style.display === "inline-block") {
- updateStats(obscam);
- }
-
- // Once crbug.com/711524 is fixed, we won't need to wait anymore. This is
- // currently needed because capabilities can only be retrieved after the
- // device starts streaming. This happens after and asynchronously w.r.t.
- // getUserMedia() returns.
- if (grabVideoTimer) {
- clearTimeout(grabVideoTimer);
- if ((eleName == "previewWebcam") && document.getElementById("previewWebcam")){
- session.videoElement.controls = true;
- }
- }
- if (getById("popupSelector_constraints_video")) {
- getById("popupSelector_constraints_video").innerHTML = "";
- }
- if (getById("popupSelector_constraints_audio")) {
- getById("popupSelector_constraints_audio").innerHTML = "";
- }
- if (getById("popupSelector_constraints_loading")) {
- getById("popupSelector_constraints_loading").style.display = "";
- }
-
- grabVideoTimer = setTimeout(function() {
- if (getById("popupSelector_constraints_loading")) {
- getById("popupSelector_constraints_loading").style.display = "none";
- }
- if ((eleName == "previewWebcam") && document.getElementById("previewWebcam")){
- session.videoElement.controls = true;
- } else {
- updateConstraintSliders();
- }
-
- dragElement(session.videoElement);
- }, 1000); // focus
-
- makeImages(true);
-
- log("DONE - found stream");
- }).catch(function(e) {
- activatedPreview = false;
- warnlog(e);
- if (e.name === "OverconstrainedError") {
- warnlog(e.message);
- log("Resolution or framerate didn't work");
- } else if (e.name === "NotReadableError") {
- if (quality <= 10) {
- grabVideo(quality + 1, eleName, selector);
- } else {
- if (!(session.cleanOutput)) {
- if (iOS) {
- warnUser("An error occured. Closing existing tabs in Safari may solve this issue.");
- } else {
- warnUser("Error: Could not start video source.\n\nTypically this means the Camera is already be in use elsewhere. Most webcams can only be accessed by one program at a time.\n\nTry a different camera or perhaps try re-plugging in the device.");
- }
- }
- activatedPreview = true;
- if (getById('gowebcam')) {
- getById('gowebcam').innerHTML = "Problem with Camera";
- }
-
- }
- return;
- } else if (e.name === "NavigatorUserMediaError") {
- if (getById('gowebcam')) {
- getById('gowebcam').innerHTML = "Problem with Camera";
- }
- if (!(session.cleanOutput)) {
- warnUser("Unknown error: 'NavigatorUserMediaError'");
- }
- return;
- } else if (e.name === "timedOut") {
- activatedPreview = true;
- if (getById('gowebcam')) {
- getById('gowebcam').innerHTML = "Problem with Camera";
- }
- if (!(session.cleanOutput)) {
- warnUser(e.message);
- }
- return;
- } else {
- errorlog("An unknown camera error occured");
- }
-
- if (quality <= 10) {
- grabVideo(quality + 1, eleName, selector);
- } else {
- errorlog("********Camera failed to work");
- activatedPreview = true;
- if (getById('gowebcam')) {
- getById('gowebcam').innerHTML = "Problem with Camera";
- }
- if (!(session.cleanOutput)) {
- if (session.width || session.height || session.framerate) {
- warnUser(" Camera failed to load.\n\nPlease ensure your camera supports the resolution and framerate that has been manually specified. Perhaps use &quality=0 instead.");
- } else {
- warnUser(" Camera failed to load.\n\nPlease make sure it is not already in use by another application.\n\nPlease make sure you have accepted the camera permissions.");
- }
- }
- }
- });
- }, 100, getUserMediaRequestID);
- }
-}
-
-
-async function grabAudio(eleName = "previewWebcam", selector = "#audioSource", trackid = null, override = false) { // trackid is the excluded track
- if (activatedPreview == true) {
- log("activated preview return 2");
- return;
- }
- activatedPreview = true;
- warnlog("GRABBING AUDIO");
- log("TRACK EXCLUDED:" + trackid);
-
-
- try {
- if (session.videoElement.srcObject) {
- var audioSelect = document.querySelector(selector).querySelectorAll("input");
- var audioExcludeList = [];
- for (var i = 0; i < audioSelect.length; i++) {
- try {
- if ("screen" == audioSelect[i].dataset.type) { // skip already excluded ---------- !!!!!! DOES THIS MAKE SENSE? TODO: CHECK
- if (audioSelect[i].checked) {
- audioExcludeList.push(audioSelect[i]);
- }
- }
- } catch (e) {
- errorlog(e);
- }
- }
-
- session.videoElement.srcObject.getAudioTracks().forEach(function(track) {
- for (var i = 0; i < audioExcludeList.length; i++) {
- try {
- if (audioExcludeList[i].label == track.label) {
- warnlog("DONE");
- return;
- }
- } catch (e) {}
- }
- if (trackid && (track.id == trackid)) {
- warnlog("SKIPPED EXCLUDED TRACK?");
- return;
- }
- session.videoElement.srcObject.removeTrack(track);
- track.stop();
- });
-
- session.streamSrc.getAudioTracks().forEach(function(track) {
- for (var i = 0; i < audioExcludeList.length; i++) {
- try {
- if (audioExcludeList[i].label == track.label) {
- warnlog("EXCLUDING TRACK; PROBABLY SCREEN SHARE");
- return;
- }
- } catch (e) {}
- }
- if (trackid && (track.id == trackid)) {
- warnlog("SKIPPED EXCLUDED TRACK?");
- return;
- }
- session.streamSrc.removeTrack(track);
- track.stop();
- });
-
-
- } else { // if no stream exists
- session.streamSrc = new MediaStream();
- session.videoElement.srcObject = session.streamSrc;
- log("CREATE NEW SOURCE FOR AUDIO");
- }
- } catch (e) {
- errorlog(e);
- }
-
- var streams = await getAudioOnly(selector, trackid, override); // Get audio streams
- warnlog(streams);
- try {
- for (var i = 0; i < streams.length; i++) {
- streams[i].getAudioTracks().forEach(function(track) {
- session.streamSrc.addTrack(track, streams[i]); // add video track to the preview video
- });
- }
-
- session.videoElement.srcObject = outboundAudioPipeline(session.streamSrc);
-
- toggleMute(true);
- if (session.videoElement.srcObject.getAudioTracks()) {
-
- for (UUID in session.pcs) {
- if (session.pcs[UUID].allowAudio == true) {
- var tracks = session.videoElement.srcObject.getAudioTracks();
-
- session.pcs[UUID].getSenders().forEach((sender) => {
- var good = false;
- if (sender.track && sender.track.id && (sender.track.kind == "audio")) {
- tracks.forEach(function(track) {
- if (track.id == sender.track.id) {
- good = true;
- }
- });
- } else { // video or something else; ignore it.
- return;
- }
- if (good) {
- return;
- }
- sender.track.enabled = false;
- //session.pcs[UUID].removeTrack(sender); // Apparently removeTrack causes renogiation; also kills send/recv.
- });
-
- if (tracks.length) {
- tracks.forEach(function(track) {
- var matched = false;
- session.pcs[UUID].getSenders().forEach((sender) => {
- if (sender.track && sender.track.id && (sender.track.kind !== "video")) {
- warnlog(sender.track.id + " " + track.id);
- if (sender.track.id == track.id) {
- warnlog("MATCHED 1");
- matched = true;
- }
- }
- });
- if (matched) {
- return;
- }
- var added = false;
- session.pcs[UUID].getSenders().forEach((sender) => {
- if (added) {
- return;
- }
- if (sender.track && (sender.track.enabled == false)) {
- sender.replaceTrack(track);
- sender.track.enabled = true;
- added = true;
- warnlog("ADDED 2");
- }
- });
- if (added) {
- return;
- }
- var sender = session.pcs[UUID].addTrack(track, session.videoElement.srcObject);
- });
- } else {
- session.pcs[UUID].getSenders().forEach((sender) => {
- if (sender.track && sender.track.kind == "audio") {
- sender.track.enabled = false; // (trying this instead)
- //session.pcs[UUID].removeTrack(sender); // Apparently removeTrack causes renogiation; also kills send/recv.
- }
- });
- }
-
- }
- }
- }
- } catch (e) {
- errorlog(e);
- }
- var gowebcam = getById("gowebcam");
- if (gowebcam) {
- gowebcam.disabled = false;
- gowebcam.dataset.ready = "true";
- gowebcam.innerHTML = "START";
- miniTranslate(gowebcam, "start");
- }
-}
-
-
-// WEBCAM
-session.publishDirector = async function(clean, vdevice=false, adevice=true){ // stream is used to generated an SDP
- log("DIRECTOR STREAM SETUP");
-
- if (getById("press2talk").dataset.enabled){log("already enabled");return;}
- getById("press2talk").dataset.enabled = 1;
-
- if (session.streamSrc){
- //if (!session.streamSrc){
- // session.streamSrc = new MediaStream();
- //}
- if (document.getElementById("videosource")){
- var v = document.getElementById("videosource");
- v.muted = true;
- v.autoplay = true;
- v.controls = false;
- v.setAttribute("playsinline","");
- session.videoElement = v;
- } else if (session.videoElement){
- var v = session.videoElement;
- v.muted = true;
- v.autoplay = true;
- v.controls = false;
- v.setAttribute("playsinline","");
- getById("miniPerformer").appendChild(v);
- } else {
- var v = document.createElement("video");
- session.videoElement = v;
- v.muted = true;
- v.autoplay = true;
- v.controls = false;
- v.setAttribute("playsinline","");
- getById("miniPerformer").appendChild(v);
- }
-
- if (session.streamID){
- session.videoElement.dataset.sid = session.streamID;
- }
-
- v.title = "This is the mini-preview of the Director's audio and video output. The director cannot be muted by guest and does not show up in scenes.";
- getById("press2talk").innerHTML = "";
- getById("press2talk").outerHTML = "";
-
- session.muted = false;
- toggleMute(true);
- getById("screensharebutton").classList.remove("advanced");
- getById("hangupbutton2").classList.remove("advanced");
-
-
- v.muted = true;
- v.autoplay = true;
- v.controls = false;
- v.setAttribute("playsinline","");
- v.srcObject = session.streamSrc; // blank, no worries.
-
- if (session.screenShareState) {
- log("can't refresh a screenshare");
- getById("screensharebutton").classList.add("float2");
- getById("screensharebutton").classList.remove("float");
- session.screenShareState = false;
- }
-
-
- activatedPreview = false;
- await grabAudio("videosource", "#audioSource3");
-
-
- enumerateDevices().then(gotDevices2).then(function() {
- activatedPreview = false;
- grabVideo(session.quality, "videosource", "select#videoSource3");
- });
-
- toggleSettings(true);
-
- var msg = {};
- msg.videoMuted = session.videoMuted;
- session.sendMessage(msg);
-
- return;
- }
-
-
- var title = "Director";
- var v = document.createElement("video");
- session.videoElement = v;
- if (session.streamID){
- session.videoElement.dataset.sid = session.streamID;
- }
- v.id = "videosource"; // could be set to UUID in the future
- v.muted = true;
- v.autoplay = true;
- v.controls = false;
- v.setAttribute("playsinline","");
-
- session.streamSrc = new MediaStream();
- v.srcObject = session.streamSrc; // blank, no worries. we dont need outbound.
-
- //createDirectorCam(v,clean);
-
- var quality = 1;
- var framerate = 30;
-
-
- if (session.quality!==false){
- quality = parseInt(session.quality) || 0;
- if (quality>2){quality=2;} else if (quality<0){quality = 0;}
- }
-
- if (session.showDirector){
- if (quality<2){
- framerate = 60;
- }
- }
-
- if (session.framerate!==false){
- framerate = parseInt(session.framerate) || 30;
- }
-
- if (session.maxframerate){
- if (framerate > session.maxframerate){
- framerate = session.maxframerate || framerate;
- }
- }
-
- if (vdevice){
- if (vdevice===true){
- vdevice = {};
- }
- if (quality===0){
- vdevice.width = {ideal:1920}; //{deviceId: {exact: deviceInfo.deviceId}};
- vdevice.height = {ideal:1080};
- vdevice.framerate = {ideal:framerate};
- } else if (quality===1){
- vdevice.width = {ideal:1280}; //{deviceId: {exact: deviceInfo.deviceId}};
- vdevice.height = {ideal:720};
- vdevice.framerate = {ideal:framerate};
- } else if (quality===2){
- vdevice.width = {ideal:640}; //{deviceId: {exact: deviceInfo.deviceId}};
- vdevice.height = {ideal:360};
- vdevice.framerate = {ideal:framerate};
- }
- if (session.framerate){
- vdevice.framerate.ideal = parseInt(session.framerate) || 30;
- }
- if (session.maxframerate){
- vdevice.framerate.max = parseInt(session.maxframerate) || 60;
- }
- if (session.width){
- vdevice.width = {exact: session.width}; //{deviceId: {exact: deviceInfo.deviceId}};
- }
- if (session.height){
- vdevice.height = {exact: session.height}; //{deviceId: {exact: deviceInfo.deviceId}};
- }
- }
-
- var constraints = {audio: adevice, video: vdevice};
-
- if (session.audioInputChannels){
- if (constraints.audio === true){
- constraints.audio = {};
- constraints.audio.channelCount = session.audioInputChannels;
- } else if (constraints.audio){
- constraints.audio.channelCount = session.audioInputChannels;
- }
- }
-
- //if (session.echoCancellation===false){
- if (constraints.audio === true){
- constraints.audio = {};
- }
- if (constraints.audio){
- if (session.echoCancellation===false || session.autoGainControl===false || session.noiseSuppression===false){
- if (session.echoCancellation===false){
- constraints.audio.echoCancellation=false;
- } else {
- constraints.audio.echoCancellation=true;
- }
- if (session.autoGainControl===false){
- constraints.audio.autoGainControl=false;
- } else {
- constraints.audio.autoGainControl=true;
- }
- if (session.noiseSuppression===false){
- constraints.audio.noiseSuppression=false;
- } else {
- constraints.audio.noiseSuppression=true;
- }
- }
- }
-
-
- try {
- getById("webcamquality3").elements.namedItem("resolution").value = quality;
- getById("gear_webcam3").style.display = "inline-block";
- getById("webcamquality3").onchange = function(event) {
- if (parseInt(getById("webcamquality3").elements.namedItem("resolution").value) == 2) {
- if (session.maxframerate===false){
- session.maxframerate = 30;
- session.maxframerate_q2 = true;
- }
- } else if (session.maxframerate_q2){
- session.maxframerate = false;
- session.maxframerate_q2 = false;
- }
- activatedPreview = false;
- session.quality_wb = parseInt(getById("webcamquality3").elements.namedItem("resolution").value);
-
- grabVideo(session.quality_wb, "videosource", "select#videoSource3");
- };
- } catch (e) {}
-
- log("constraint");
- navigator.mediaDevices.getUserMedia(constraints).then(function(stream){ // very simple.
- session.streamSrc = stream;
- v.srcObject = outboundAudioPipeline(session.streamSrc); // not blank, so now we worry
-
- for (UUID in session.pcs){
- session.initialPublish(UUID); // Start publishing!
- }
- enumerateDevices().then(gotDevices2).then(function(){});
- createDirectorCam(v, clean);
- });
-
-
- changeAudioOutputDevice(v);
-
- v.onpause = (event) => { // prevent things from pausing; human or other
- if (!((event.ctrlKey) || (event.metaKey) )){
- log("Video paused; auto playing");
- event.currentTarget.play().then(_ => {
- log("playing");
- }).catch(warnlog);
- }
- };
-
- v.addEventListener('click', function(e) { // show stats of video if double clicked
- log("click");
- try {
- if ((e.ctrlKey)||(e.metaKey)){
- e.preventDefault();
-
- ////////////////////////
-
- var [menu, innerMenu] = statsMenuCreator();
-
- //////////////////////////////////
-
- menu.interval = setInterval(printMyStats,3000, innerMenu);
- printMyStats(innerMenu);
- e.stopPropagation();
-
- return false;
- }
- } catch(e){errorlog(e);}
- });
-
- if (session.directorEnabledPPT){
- return;
- }
-
- if (session.videoMutedFlag){
- session.videoMuted = true;
- toggleVideoMute(true);
- }
-
- session.title=title;
- session.directorEnabledPPT = true;
-
-
- if (session.seeding){
- return;
- }
-
- session.seeding=true;
- session.seedStream();
-
-};
-
-function statsMenuCreator(){
-
- if (getById("menuStatsBox")){
- clearInterval(getById("menuStatsBox").interval);
- getById("menuStatsBox").remove();
- }
-
- var menu = document.createElement("div");
- menu.id = "menuStatsBox";
- menu.className = "debugStats remotestats";
- getById('main').appendChild(menu);
-
- menu.style.left = parseInt(Math.random()*10)+15+"px"
- menu.style.top = parseInt(Math.random()*10)+"px"
-
- menu.innerHTML="Statistics ";
- var menuCloseBtn = document.createElement("button");
- menuCloseBtn.className="close";
- menuCloseBtn.innerHTML="×";
- menu.appendChild(menuCloseBtn);
-
- var innerMenu = document.createElement("div");
- menu.appendChild(innerMenu);
-
- menuCloseBtn.addEventListener('click', function(eve) {
- clearInterval(menu.interval);
- eve.currentTarget.parentNode.remove();
- });
- return [menu, innerMenu];
-}
-
-
-// WEBCAM
-session.publishStream = function(v, title="Stream Sharing Session"){ // stream is used to generated an SDP
- log("STREAM SETUP");
-
- try {
- //session.streamSrc = v.srcObject; // this shoulnd't be needed
- v.parentNode.removeChild(v); // remove the preview video element after we switch streams to avoid bug on iOS beta 14
- v.className = "";
- } catch (e){
- errorlog(e);
- return;
- }
-
- if (session.transcript){
- setTimeout(function(){setupClosedCaptions();},0);
- }
-
- toggleMute(true); // apply mute state
-
- if (!session.streamSrc){
- log("no stream selected");
- session.streamSrc = new MediaStream(); // this is just for backup.
- }
-
- session.streamSrc.oninactive = function streamoninactive() {
- errorlog('Stream inactive');
- if (session.videoElement.recording){
- session.videoElement.recorder.stop();
- }
- };
-
- if (session.streamSrc.getVideoTracks().length==0){
- warnlog("NO VIDEO TRACK INCLUDED");
- }
-
- if (session.streamSrc.getAudioTracks().length==0){
- warnlog("NO AUDIO TRACK INCLUDED");
- }
-
-
- var container = document.createElement("div");
- container.id = "container";
-
- if (session.cleanOutput){
- container.style.height = "100%";
- v.style.maxWidth = "100%";
- v.style.boxShadow = "none";
- }
-
- container.className = "vidcon";
- getById("gridlayout").appendChild(container);
-
- v.className = "tile";
-
- v.muted = true;
- v.autoplay = true;
- v.controls = false;
- v.setAttribute("playsinline","");
- v.id = "videosource"; // could be set to UUID in the future
- v.oncanplay = null;
- container.appendChild(v);
-
- if (session.nopreview){
- v.style.display="none";
- container.style.display="none";
- }
-
- changeAudioOutputDevice(v);
-
- if (session.mirrored && session.flipped){
- v.style.transform = "scaleX(1) scaleY(-1) ";
- } else if (session.mirrored){
- v.style.transform = "scaleX(1) ";
- } else if (session.flipped){
- v.style.transform = "scaleY(-1) scaleX(-1)";
- } else {
- v.style.transform = "scaleX(-1) ";
- }
-
- var bigPlayButton = document.getElementById("bigPlayButton");
- if (bigPlayButton){
- bigPlayButton.parentNode.removeChild(bigPlayButton);
- }
-
- session.videoElement = v;
-
- if (session.streamID){
- session.videoElement.dataset.sid = session.streamID;
- }
-
- if (session.director){
- // audio is not mucked with
- } else if (session.scene!==false){
- setTimeout(function(){updateMixer();},1);
- } else if (session.roomid!==false){
- if (session.roomid===""){
- if (!(session.view) || (session.view==="")){
-
-
- if (session.fullscreen){
- session.windowed = false;
- } else {
- v.className = "myVideo";
- session.windowed = true;
- }
- getById("mutespeakerbutton").classList.add("advanced");
-
- applyMirror(session.mirrorExclude, 'videosource');
-
- container.style.width="100%";
- //container.style.height="100%";
-
- container.style.alignItems = "center";
- container.backgroundColor = "#666";
-
- setTimeout(function (){dragElement(v);},1000);
- play();
- } else {
- session.windowed = false;
- applyMirror(session.mirrorExclude, 'videosource');
- play();
- setTimeout(function(){updateMixer();},1);
- }
- } else {
- //session.cbr=0; // we're just going to override it
- if (session.stereo==5){ // not a scene or director, so we will assume its a guest. changing to stereo=3
- session.stereo=3;
- }
- session.windowed = false;
- applyMirror(session.mirrorExclude, 'videosource');
-
- setTimeout(function(){updateMixer();},1);
- }
- } else {
-
-
- if (session.fullscreen){
- session.windowed = false;
- } else {
- v.className = "myVideo";
- session.windowed = true;
- }
- getById("mutespeakerbutton").classList.add("advanced");
-
- applyMirror(session.mirrorExclude, 'videosource');
-
- container.style.width="100%";
- //container.style.height="100%";
- //container.style.display = "flex";
-
- container.style.alignItems = "center";
- container.backgroundColor = "#666";
-
- setTimeout(function (){dragElement(v);},1000);
-
- }
-
- v.onpause = (event) => { // prevent things from pausing; human or other
- if (!((event.ctrlKey) || (event.metaKey) )){
- log("Video paused; auto playing");
- event.currentTarget.play().then(_ => {
- log("playing");
- }).catch(warnlog);
- }
- };
-
- v.addEventListener('click', function(e) {
- log("click");
- try {
- if ((e.ctrlKey)||(e.metaKey)){
- e.preventDefault();
-
- var [menu, innerMenu] = statsMenuCreator();
-
- menu.interval = setInterval(printMyStats,3000, innerMenu);
-
- printMyStats(innerMenu);
- e.stopPropagation();
- return false;
- }
- } catch(e){errorlog(e);}
- });
-
- v.touchTimeOut = null;
- v.touchLastTap = 0;
- v.touchCount = 0;
- v.addEventListener('touchend', function(event) {
- log("touched");
-
- document.ontouchup = null;
- document.onmouseup = null;
- document.onmousemove = null;
- document.ontouchmove = null;
-
- var currentTime = new Date().getTime();
- var tapLength = currentTime - v.touchLastTap;
- clearTimeout(v.touchTimeOut);
- if (tapLength < 500 && tapLength > 0) {
- ///
- log("double touched");
- v.touchCount+=1;
- event.preventDefault();
- if (v.touchCount<5){
- v.touchLastTap = currentTime;
- return false;
- }
- v.touchLastTap = 0;
- v.touchCount=0;
-
- var [menu, innerMenu] = statsMenuCreator();
-
- menu.interval = setInterval(printMyStats,3000, innerMenu);
-
- printMyStats(innerMenu);
- event.stopPropagation();
- return false;
- //////
- } else {
- v.touchCount=1;
- v.touchLastTap = currentTime;
-
- v.touchTimeOut = setTimeout(function(vv) {
- clearTimeout(vv.touchTimeOut);
- vv.touchLastTap = 0;
- vv.touchCount=0;
- }, 5000, v);
-
- }
-
- });
-
- try{
- var m = getById("mainmenu");
- m.remove();
- } catch (e){}
-
- var added = "";
- if (session.defaultPassword===false){
- if (session.password){
- added="&pw="+session.password;
- }
- }
-
- var pie = "";
- if (session.pie){
- if (session.pie!==true){
- pie = "&pie="+session.pie;
- }
- }
-
- getById("reshare").href = "https://"+location.host+location.pathname+"?view="+session.streamID+added+pie;
- getById("reshare").text = "https://"+location.host+location.pathname+"?view="+session.streamID+added+pie;
- getById("reshare").style.width = ((getById("reshare").text.length + 1)*1.15 * 8) + 'px';
- pokeIframeAPI('started-camera');
-
-
-
- if (session.videoMutedFlag){
- session.videoMuted = true;
- toggleVideoMute(true);
- }
-
- clearInterval(session.updateLocalStatsInterval);
- session.updateLocalStatsInterval = setInterval(function(){updateLocalStats();},3000);
-
- session.title=title;
- session.seeding=true;
- session.seedStream();
-
-};
-
-
-session.publishScreen = function(constraints, title="Screen Sharing Session", audioList=[], audio=true){ // webcam stream is used to generated an SDP
- log("SCREEN SHARE SETUP");
- if (!navigator.mediaDevices.getDisplayMedia){
- setTimeout(function(){warnUser("Sorry, your browser is not supported. Please use the desktop versions of Firefox or Chrome instead");},1);
- return false;
- }
- if (navigator.userAgent.toLowerCase().indexOf(' electron/') > -1) {
- if (!ElectronDesktopCapture){
- if (!(session.cleanOutput && session.cleanish==false)){
- warnUser("Your Electron app does not support Screen Capture. Update your Electron Capture app and then enable Elevated Privileges to access screen-sharing.");
- }
- return false;
- }
- }
-
- var streams = [];
- for (var i=1; i{
- streams.push(stream);
- }).catch(errorlog);
- }
- }
-
- if (session.audioDevice === 0 ){
- constraints.audio = false;
- }
-
- log(constraints);
- return navigator.mediaDevices.getDisplayMedia(constraints).then(function (stream){
- /// RETURN stream for preview? rather than jumping right in.
- session.screenShareState=true;
- try {
- stream.getVideoTracks()[0].onended = function () {
- session.screenShareState=false;
- pokeIframeAPI("screen-share-ended");
- grabScreen();
- };
- } catch(e){log("No Video selected; screensharing?");}
-
- // OR, jump right in, and let user change from there
- if (session.roomid!==false){
- if ((session.roomid==="") && ((!(session.view)) || (session.view===""))){
-
- } else {
- getById("head3").className = 'advanced';
-
- log("ROOMID EANBLED");
- log("Update Mixer Event on REsize SET");
- window.addEventListener("resize", updateMixer);
- window.addEventListener("orientationchange", updateMixer);
- joinRoom(session.roomid);
- }
-
- } else {
- getById("head3").className = '';
- getById("logoname").style.display = 'none';
- }
-
- if (urlParams.has('permaid')){
- updateURL("permaid="+session.streamID);
- } else {
- updateURL("push="+session.streamID);
- }
-
- log("adding tracks");
- for (var i=0; i{
- stream.addTrack(track);
- });
- }
- streams = null;
- if (session.audioDevice !== 0){
- if (stream.getAudioTracks().length==0){
- if (!(session.cleanOutput)){
- if (navigator.userAgent.toLowerCase().indexOf(' electron/') > -1){
- // Electron has no audio.
- } else {
- setTimeout(function(){warnUser("No Audio Source was detected.\n\nIf you were wanting to capture an Application's Audio, please see:\nhttps://docs.obs.ninja/help/guides-and-how-tos#audio for some guides.");},300);
- }
- }
- }
- }
-
-
-
- try {
- session.streamSrc = stream;
- } catch (e){errorlog(e);}
-
- toggleMute(true);
-
- var v = document.createElement("video");
-
- session.videoElement = v;
-
-
- if (session.streamID){
- session.videoElement.dataset.sid = session.streamID;
- }
-
-
- var container = document.createElement("div");
- container.id = "container";
-
- if (session.cleanOutput){
- container.style.height = "100%";
- v.style.maxWidth = "100%";
- v.style.boxShadow = "none";
- }
-
- container.className = "vidcon";
- getById("gridlayout").appendChild(container);
-
- if (session.nopreview){
- v.style.display="none";
- container.style.display="none";
- }
-
- container.appendChild(v);
-
-
- v.className = "tile";
-
- changeAudioOutputDevice(v);
-
- if (session.director){
- } else if (session.scene!==false){
- setTimeout(function(){updateMixer();},1);
- } else if (session.roomid!==false){
- if (session.roomid===""){
- if (!(session.view) || (session.view==="")){
-
- if (session.fullscreen){
- session.windowed = false;
- } else {
- v.className = "myVideo";
- session.windowed = true;
- }
- getById("mutespeakerbutton").classList.add("advanced");
-
- if (session.mirrored && session.flipped){
- v.style.transform = " scaleX(-1) scaleY(-1) translate(0, 50%)";
- v.classList.add("mirrorControl");
- } else if (session.mirrored){
- v.style.transform = "scaleX(-1) translate(0, -50%)";
- v.classList.add("mirrorControl");
- } else if (session.flipped){
- v.style.transform = "scaleY(-1) translate(0, 50%)";
- v.classList.remove("mirrorControl");
- } else {
- v.style.transform = " translate(0, -50%)";
- v.classList.remove("mirrorControl");
- }
-
- container.style.width="100%";
- //container.style.height="100%";
- container.style.alignItems = "center";
- container.backgroundColor = "#666";
-
- setTimeout(function (){dragElement(v);},1000);
- play();
- } else {
- play();
- setTimeout(function(){updateMixer();},1);
- }
- } else {
- setTimeout(function(){updateMixer();},1);
- }
- } else {
-
- if (session.fullscreen){
- session.windowed = false;
- } else {
- v.className = "myVideo";
- session.windowed = true;
- }
- getById("mutespeakerbutton").classList.add("advanced");
-
- if (session.mirrored && session.flipped){
- v.style.transform = " scaleX(-1) scaleY(-1) translate(0, 50%)";
- v.classList.add("mirrorControl");
- } else if (session.mirrored){
- v.style.transform = "scaleX(-1) translate(0, -50%)";
- v.classList.add("mirrorControl");
- } else if (session.flipped){
- v.style.transform = "scaleY(-1) translate(0, 50%)";
- v.classList.remove("mirrorControl");
- } else {
- v.style.transform = " translate(0, -50%)";
- v.classList.remove("mirrorControl");
- }
-
- container.style.width="100%";
- //container.style.height="100%";
- container.style.alignItems = "center";
- container.backgroundColor = "#666";
- }
-
- v.autoplay = true;
- v.controls = false;
- v.setAttribute("playsinline","");
- v.muted = true;
- v.id = "videosource";
-
- //if (!v.srcObject || v.srcObject.id !== stream.id) {
- // v.srcObject = stream;
- v.srcObject = outboundAudioPipeline(session.streamSrc);
- //}
-
- v.onpause = (event) => { // prevent things from pausing; human or other
- if (!((event.ctrlKey) || (event.metaKey) )){
- log("Video paused; auto playing");
- event.currentTarget.play().then(_ => {
- log("playing");
- }).catch(warnlog);
- }
- };
-
- v.addEventListener('click', function(e) { // show stats of video if double clicked
- log("click");
- try {
- if ((e.ctrlKey)||(e.metaKey)){
- e.preventDefault();
-
- var [menu, innerMenu] = statsMenuCreator();
-
- menu.interval = setInterval(printMyStats,3000, innerMenu);
-
- printMyStats(innerMenu);
- e.stopPropagation();
- return false;
- }
- } catch(e){errorlog(e);}
- });
-
- try{
- var m = getById("mainmenu");
- m.remove();
- } catch (e){}
-
- var pie = "";
- if (session.pie){
- if (session.pie!==true){
- pie = "&pie="+session.pie;
- }
- }
-
- getById("reshare").href = "https://"+location.host+location.pathname+"?view="+session.streamID+pie;
- getById("reshare").text = "https://"+location.host+location.pathname+"?view="+session.streamID+pie;
- getById("reshare").style.width = ((getById("reshare").text.length + 1)*1.15 * 8) + 'px';
-
-
- if (session.videoMutedFlag){
- session.videoMuted = true;
- toggleVideoMute(true);
- }
-
- clearInterval(session.updateLocalStatsInterval);
- session.updateLocalStatsInterval = setInterval(function(){updateLocalStats();},3000);
-
- session.title=title;
- session.seeding=true;
- session.seedStream();
-
- pokeIframeAPI('started-screenshare');
-
- return true;
- }).catch(function(err){
- warnlog(err); /* handle the error */
- if (navigator.userAgent.toLowerCase().indexOf(' electron/') > -1) {
- if (!ElectronDesktopCapture){
- if (!(session.cleanOutput)) {
- warnUser("Your Electron app does not support Screen Capture. Update your Electron Capture app and then enable Elevated Privileges to access screen-sharing.");
- }
- return false;
- }
- }
- if ((err.name == "NotAllowedError") || (err.name == "PermissionDeniedError")){
- // User Stopped it.
- session.screenShareState=false;
- pokeIframeAPI("screen-share-ended");
- return false;
- } else {
- if (audio==true){
- constraints.audio=false;
- if (!(session.cleanOutput)){
- setTimeout(function(){warnUser(err);},1); // TypeError: Failed to execute 'getDisplayMedia' on 'MediaDevices': Audio capture is not supported
- }
- return session.publishScreen(constraints, title, audioList, false);
- } else {
- if (!(session.cleanOutput)){
- setTimeout(function(){warnUser(err);},1); // TypeError: Failed to execute 'getDisplayMedia' on 'MediaDevices': Audio capture is not supported
- }
- return false;
- }
-
- }
- });
-
-};
-
-session.publishFile = function(ele, event, title="Video File Sharing Session"){ // webcam stream is used to generated an SDP
- log("FILE SHARE SETUP");
-
- if (session.transcript){
- setTimeout(function(){setupClosedCaptions();},0);
- }
-
- var files = [];
- for (var i = 0; i < ele.files.length; i++){ // changing from a FileList to an Array. Arrays are easier to modify later on
- files.push(ele.files[i]);
- }
- log(files);
- //var type = file.type;
-
- var fileURL = URL.createObjectURL(files[0]);
- var container = document.createElement("div");
- container.id = "container";
-
-
-
- container.className = "vidcon";
- var v = document.createElement("video");
-
- if (session.cleanOutput){
- container.style.height = "100%";
- v.style.maxWidth = "100%";
- v.style.boxShadow = "none";
- }
-
- if (session.streamID){
- v.dataset.sid = session.streamID;
- }
-
- getById("gridlayout").appendChild(container);
-
- if (session.roomid!==false){
- if ((session.roomid==="") && ((!(session.view)) || (session.view===""))){
-
- } else {
- log("ROOMID EANBLED");
- log("Update Mixer Event on REsize SET");
- window.addEventListener("resize", updateMixer);
- window.addEventListener("orientationchange", updateMixer);
- getById("head3").className = 'advanced';
-
- joinRoom(session.roomid);
- }
-
- } else {
- getById("head3").className = '';
- getById("logoname").style.display = 'none';
- }
- getById("head1").className = 'advanced';
-
- if (urlParams.has('permaid')){
- updateURL("permaid="+session.streamID);
- } else {
- updateURL("push="+session.streamID);
- }
-
- getById("head1").className = 'advanced';
- getById("head2").className = 'advanced';
-
- if (!(session.cleanOutput)){
- getById("chatbutton").className="float";
- getById("hangupbutton").className="float";
- getById("controlButtons").style.display="flex";
- getById("helpbutton").style.display = "inherit";
- getById("reportbutton").style.display = "";
- } else {
- getById("controlButtons").style.display="none";
- }
-
- var bigPlayButton = document.getElementById("bigPlayButton");
- if (bigPlayButton){
- bigPlayButton.parentNode.removeChild(bigPlayButton);
- }
-
-
-
- v.autoplay = false;
- v.controls = true;
- v.muted = false;
-
- if (files.length ==1){ // we don't want to do the complex logic if there is just one video
- v.loop = true;
- } else {
- v.loop = false; // triggers the complex track/rtc logic.
- }
-
- v.setAttribute("playsinline","");
- v.src = fileURL;
-
- try {
- session.streamSrc=v.captureStream();
- } catch (e){
- errorlog(e);
- return;
- }
-
- v.className = "tile clean";
- v.id = "videosource"; // could be set to UUID in the future
- v.playlist = files;
-
- v.addEventListener('ended',myHandler,false); // only fires if the video doesn't loop.
-
-
- function myHandler(e) {
- log("MY HANDLER TRIGGERED");
- var vid = getById("videosource");
- log(vid.playlist);
- vid.playlist.unshift(vid.playlist.pop());
- vid.src = URL.createObjectURL(vid.playlist[0]);
- vid.onloadeddata = function(){
- session.streamSrc=vid.captureStream();
-
- session.streamSrc.getTracks().forEach(function(track){
- for (UUID in session.pcs){
- var senders = session.pcs[UUID].getSenders();
- 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 (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();
- }
- vid.load();
- log(session.streamSrc);
- vid.play().then(_ => {
- log("playing");
- }).catch(warnlog);
-
- }
-
- // no preview doesn't work, so just stop it from doing its thing.
-
-
- container.appendChild(v);
- changeAudioOutputDevice(v);
-
- if (session.mirrored && session.flipped){
- v.style.transform = "scaleX(1) scaleY(-1) ";
- } else if (session.mirrored){
- v.style.transform = "scaleX(1) ";
- } else if (session.flipped){
- v.style.transform = "scaleY(-1) scaleX(-1)";
- } else {
- v.style.transform = "scaleX(-1) ";
- }
-
- session.mirrorExclude=true;
-
- if (session.director){
- } else if (session.scene!==false){
- setTimeout(function(){updateMixer();},1);
- } else if (session.roomid!==false){
- if (session.roomid===""){
- if (!(session.view) || (session.view==="")){
-
- if (session.fullscreen){
- session.windowed = false;
- } else {
- v.className = "myVideo clean";
- session.windowed = true;
- }
- getById("mutespeakerbutton").classList.add("advanced");
-
- applyMirror(session.mirrorExclude, 'videosource');
-
- container.style.width="100%";
- //container.style.height="100%";
-
- container.style.alignItems = "center";
- container.backgroundColor = "#666";
-
- play();
- } else {
- session.windowed = false;
- applyMirror(session.mirrorExclude, 'videosource');
- play();
- setTimeout(function(){updateMixer();},1);
- }
- } else {
- //session.cbr=0; // we're just going to override it
- if (session.stereo==5){
- session.stereo=3;
- }
- session.windowed = false;
- applyMirror(session.mirrorExclude, 'videosource');
- setTimeout(function(){updateMixer();},1);
- }
- } else {
-
-
- if (session.fullscreen){
- session.windowed = false;
- } else {
- v.className = "myVideo clean";
- session.windowed = true;
- }
- getById("mutespeakerbutton").classList.add("advanced");
-
- applyMirror(session.mirrorExclude, 'videosource');
-
- container.style.width="100%";
- //container.style.height="100%";
- //container.style.display = "flex";
-
- container.style.alignItems = "center";
- container.backgroundColor = "#666";
-
- }
-
-
- v.addEventListener('click', function(e){
- log("click");
- try {
- if ((e.ctrlKey)||(e.metaKey)){
- e.preventDefault();
-
- var [menu, innerMenu] = statsMenuCreator();
-
- menu.interval = setInterval(printMyStats,3000, innerMenu);
-
- printMyStats(innerMenu);
- e.stopPropagation();
- return false;
- }
- } catch(e){errorlog(e);}
- });
-
-
- v.touchTimeOut = null;
- v.touchLastTap = 0;
- v.touchCount = 0;
- v.addEventListener('touchend', function(event) {
- log("touched");
-
- document.ontouchup = null;
- document.onmouseup = null;
- document.onmousemove = null;
- document.ontouchmove = null;
-
- var currentTime = new Date().getTime();
- var tapLength = currentTime - v.touchLastTap;
- clearTimeout(v.touchTimeOut);
- if (tapLength < 500 && tapLength > 0) {
- ///
- log("double touched");
- v.touchCount+=1;
- event.preventDefault();
- if (v.touchCount<5){
- v.touchLastTap = currentTime;
- return false;
- }
- v.touchLastTap = 0;
- v.touchCount=0;
-
- var [menu, innerMenu] = statsMenuCreator();
-
- menu.interval = setInterval(printMyStats,3000, innerMenu);
-
- printMyStats(innerMenu);
- event.stopPropagation();
- return false;
- //////
- } else {
- v.touchCount=1;
- v.touchTimeOut = setTimeout(function(vv) {
- clearTimeout(vv.touchTimeOut);
- vv.touchLastTap = 0;
- vv.touchCount=0;
- }, 5000, v);
- v.touchLastTap = currentTime;
- }
-
- });
-
- try{
- var m = getById("mainmenu");
- m.remove();
- } catch (e){}
-
- var pie = "";
- if (session.pie){
- if (session.pie!==true){
- pie = "&pie="+session.pie;
- }
- }
-
- getById("reshare").href = "https://"+location.host+location.pathname+"?view="+session.streamID+pie;
- getById("reshare").text = "https://"+location.host+location.pathname+"?view="+session.streamID+pie;
- getById("reshare").style.width = ((getById("reshare").text.length + 1)*1.15 * 8) + 'px';
- pokeIframeAPI('started-fileshare');
-
- clearInterval(session.updateLocalStatsInterval);
- session.updateLocalStatsInterval = setInterval(function(){updateLocalStats();},3000);
-
- session.title=title;
- session.seeding=true;
-
- if (session.videoMutedFlag){
- session.videoMuted = true;
- toggleVideoMute(true);
- }
-
- session.seedStream();
-};
-
-
-function tryAgain(event) { // audio or video agnostic track reconnect ------------not actually in use,. maybe out of date
- log("TRY AGAIN TRIGGERED");
- warnlog(event);
-}
-
-
-function enterPressedClick(event, ele) {
- if (event.keyCode === 13) {
- event.preventDefault();
- ele.click();
- }
-}
-
-function enterPressed(event, callback) {
- // Number 13 is the "Enter" key on the keyboard
- if (event.keyCode === 13) {
- event.preventDefault();
- callback();
- }
-}
-
-
-function dragElement(elmnt) {
- var millis = Date.now();
- try {
- var input = getById("zoomSlider");
- var stream = elmnt.srcObject;
- try {
- var track0 = stream.getVideoTracks();
- } catch (e) {
- return;
- }
-
- if (!(track0.length)) {
- return;
- }
-
- track0 = track0[0];
- if (track0.getCapabilities) {
- var capabilities = track0.getCapabilities();
- var settings = track0.getSettings();
-
- // Check whether zoom is supported or not.
- if (!('zoom' in capabilities)) {
- log('Zoom is not supported by ' + track0.label);
- return;
- }
-
- // Map zoom to a slider element.
- input.min = capabilities.zoom.min;
- input.max = capabilities.zoom.max;
- input.step = capabilities.zoom.step;
- input.value = settings.zoom;
- }
- } catch (e) {
- errorlog(e);
- return;
- }
-
- log("drag on");
- elmnt.onmousedown = dragMouseDown;
- elmnt.onclick = onvideoclick;
- elmnt.ontouchstart = dragMouseDown;
-
- var pos0 = 1;
-
- function onvideoclick(e) {
- log(e);
- log("onvideoclick");
- e = e || window.event;
- e.preventDefault();
- return false;
- }
-
- function dragMouseDown(e) {
- log(e);
- log("dragMouseDown");
-
- //closeDragElement(null);
-
- //elmnt.controls = false;
- e = e || window.event;
- e.preventDefault();
-
- pos0 = input.value;
- if (e.type == 'touchstart' || e.type == 'touchmove' || e.type == 'touchend' || e.type == 'touchcancel') {
- var touch = e.touches[0] || e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
- pos3 = touch.clientX;
- pos4 = touch.clientY;
- } else if (e.type == 'mousedown' || e.type == 'mouseup' || e.type == 'mousemove' || e.type == 'mouseover' || e.type == 'mouseout' || e.type == 'mouseenter' || e.type == 'mouseleave') {
- pos3 = e.clientX;
- pos4 = e.clientY;
- }
- document.ontouchup = closeDragElement;
- document.onmouseup = closeDragElement;
-
- document.ontouchmove = elementDrag;
- document.onmousemove = elementDrag;
- }
-
- function elementDrag(e) {
- e = e || window.event;
- e.preventDefault();
- // calculate the new cursor position:
-
- if (Date.now() - millis < 50) {
- return;
- }
- millis = Date.now();
-
- if (e.type == 'touchstart' || e.type == 'touchmove' || e.type == 'touchend' || e.type == 'touchcancel') {
- var touch = e.touches[0] || e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
- pos1 = touch.clientX;
- pos2 = touch.clientY;
- } else if (e.type == 'mousedown' || e.type == 'mouseup' || e.type == 'mousemove' || e.type == 'mouseover' || e.type == 'mouseout' || e.type == 'mouseenter' || e.type == 'mouseleave') {
- pos1 = e.clientX;
- pos2 = e.clientY;
- }
-
- var zoom = parseFloat((pos4 - pos2) * 2 / elmnt.offsetHeight);
-
- if (zoom > 1) {
- zoom = 1.0;
- } else if (zoom < -1) {
- zoom = -1.0;
- }
- input.value = zoom * (input.max - input.min) + input.min;
- if (input.value != pos0) {
- track0.applyConstraints({
- advanced: [{
- zoom: input.value
- }]
- });
- }
- }
-
- function closeDragElement(e) {
- log(e);
- log("closeDragElement");
- //if (e!==null){
- // elmnt.controls=true;
- //}
- /* stop moving when mouse button is released:*/
- document.ontouchup = null;
- document.onmouseup = null;
- document.onmousemove = null;
- document.ontouchmove = null;
- }
-}
-
-function previewIframe(iframesrc) { // this is pretty important if you want to avoid camera permission popup problems. You can also call it automatically via: loadIframe();"> , but don't call it before the page loads.
-
- var iframe = document.createElement("iframe");
- iframe.allow = "autoplay;camera;microphone";
- iframe.allowtransparency = "true";
- iframe.allowfullscreen = "true";
- iframe.style.width = "100%";
- iframe.style.height = "100%";
- iframe.style.border = "10px dashed rgb(64 65 62)";
-
- if (iframesrc == "") {
- iframesrc = "./";
- }
-
-
- if (iframesrc.startsWith("https://") || iframesrc.startsWith("http://")){
- var domain = (new URL(iframesrc));
- domain = domain.hostname;
- log(domain);
- if ((domain=="www.youtube.com") || (domain=="youtube.com")){
- var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
- var match = iframesrc.match(regExp);
- var vidid = (match&&match[7].length==11)? match[7] : false;
-
- if(vidid){
- iframesrc = "https://www.youtube.com/embed/"+vidid+"?autoplay=1&modestbranding=1";
- log(iframesrc);
- }
- } else if (domain=="www.twitch.tv"){
- var vidid = iframesrc.split('/').pop().split('#')[0].split('?')[0];
- if (vidid){
- iframesrc = "https://player.twitch.tv/?channel="+vidid+"&parent="+location.hostname;
- log(iframesrc);
- }
- } else if (domain=="twitch.tv"){
- var vidid = iframesrc.split('/').pop().split('#')[0].split('?')[0];
- if (vidid){
- iframesrc = "https://player.twitch.tv/?channel="+vidid+"&parent="+location.hostname;
- log(iframesrc);
- }
- }
-
- }
-
- iframe.src = iframesrc;
- getById("previewIframe").innerHTML = "";
- getById("previewIframe").style.width = "640px";
- getById("previewIframe").style.height = "360px";
- getById("previewIframe").style.margin = "auto";
- getById("previewIframe").appendChild(iframe);
-}
-
-function loadIframe(iframesrc) { // this is pretty important if you want to avoid camera permission popup problems. You can also call it automatically via: loadIframe();"> , but don't call it before the page loads.
-
- var iframe = document.createElement("iframe");
- iframe.allow = "autoplay;camera;microphone";
- iframe.allowtransparency = "true";
- iframe.allowfullscreen = "true";
- iframe.style.width = "100%";
- iframe.style.height = "100%";
- iframe.style.border = "10px dashed rgb(64 65 62)";
-
- if (iframesrc == "") {
- iframesrc = "./";
- iframe.style.border = "0";
- }
-
- if (iframesrc.startsWith("https://obs.ninja/")){
- iframe.style.border = "0";
- } else if (iframesrc.startsWith("https://youtube.com/")){
- iframe.style.border = "0";
- } else if (iframesrc.startsWith("https://www.youtube.com/")){
- iframe.style.border = "0";
- } else if (iframesrc.startsWith("https://youtube.com/")){
- iframe.style.border = "0";
- } else if (iframesrc.startsWith("https://player.twitch.tv/")){
- iframe.style.border = "0";
- } else if (iframesrc.startsWith("https://meshcast.io/")){
- iframe.style.border = "0";
- }
-
- if (document.getElementById("mainmenu")) {
- var m = getById("mainmenu");
- m.remove();
- }
- iframe.src = iframesrc;
- return iframe
-}
-
-function dropDownButtonAction(ele) {
- var ele = getById("dropButton");
- if (ele) {
- ele.parentNode.removeChild(ele);
- getById('container-5').classList.remove('advanced');
- getById('container-8').classList.remove('advanced');
- getById('container-6').classList.remove('advanced');
- getById('container-7').classList.remove('advanced');
- }
-}
-
-function updateConstraintSliders() {
- log("updateConstraintSliders");
- if (session.roomid !== false && session.roomid !== "" && session.director !== true && session.forceMediaSettings == false) {
- if (session.controlRoomBitrate !== false) {
- listCameraSettings();
- }
- if (session.effects!==false){
- if ((iOS) || (iPad)){
- } else {
- getById("effectsDiv3").style.display = "block";
- getById("effectSelector3").value = (parseInt(session.effects) || 0) +"";
- }
- }
- } else {
- listAudioSettings();
- listCameraSettings();
- if ((iOS) || (iPad)){
- } else {
- if (session.effects!==false){
- getById("effectsDiv3").style.display = "block";
- try{
- getById("effectSelector3").value = (parseInt(session.effects) || 0) +"";
- } catch(E){}
- }
- }
- }
- //checkIfPIP(); // this doesn't actually work on iOS still, so whatever.
-}
-
-function checkIfPIP() {
- try {
- if (session.videoElement && ((session.videoElement.webkitSupportsPresentationMode && typeof session.videoElement.webkitSetPresentationMode === "function") || (document.pictureInPictureEnabled || !videoElement.disablePictureInPicture))) {
- // Toggle PiP when the user clicks the button.
-
- getById("pIpStartButton").addEventListener("click", function(event) {
- // if ( (document.pictureInPictureEnabled || !videoElement.disablePictureInPicture)){
- //session.videoElement.requestPictureInPicture();
- // } else {
- session.videoElement.webkitSetPresentationMode(session.videoElement.webkitPresentationMode === "picture-in-picture" ? "inline" : "picture-in-picture");
- // }
- });
- getById("pIpStartButton").style.display = "inline-block";
- }
- } catch (e) {
- errorlog(e);
- }
-}
-
-function listAudioSettingsPrep() {
- try {
- var tracks = session.streamSrc.getAudioTracks();
- if (!tracks.length) {
- warnlog("session.streamSrc contains no audio tracks");
- return;
- }
- } catch (e) {
- warnlog(e);
- return;
- }
-
- var data = [];
-
- for (var i = 0; i < tracks.length; i += 1) {
- track0 = tracks[i];
- var trackSet = {};
-
- if (track0.getCapabilities) {
- trackSet.audioConstraints = track0.getCapabilities();
- }
-
- if (track0.getSettings) {
- trackSet.currentAudioConstraints = track0.getSettings();
- }
-
- trackSet.trackLabel = "unknown or none";
- if (track0.label) {
- trackSet.trackLabel = track0.label;
- }
-
- if (i == 0) {
- trackSet.equalizer = session.equalizer; // only supporting the first track at the moment.
- } else {
- trackSet.equalizer = false;
- }
-
- if (i == 0) {
- trackSet.lowcut = session.lowcut; // only supporting the first track at the moment.
- } else {
- trackSet.lowcut = false;
- }
-
- data.push(trackSet);
- }
- return data;
-}
-
-function listVideoSettingsPrep() {
- try {
- var track0 = session.streamSrc.getVideoTracks();
- if (track0.length) {
- track0 = track0[0];
- if (track0.getCapabilities) {
- session.cameraConstraints = track0.getCapabilities();
- }
- log(session.cameraConstraints);
- }
- } catch (e) {
- warnlog(e);
- return;
- }
-
- try {
- if (track0.getSettings) {
- session.currentCameraConstraints = track0.getSettings();
- }
- } catch (e) {
- warnlog(e);
- return;
- }
- var msg = {};
- msg.trackLabel = "unknown or none";
- if (track0.label) {
- msg.trackLabel = track0.label;
- }
- msg.currentCameraConstraints = session.currentCameraConstraints;
- msg.cameraConstraints = session.cameraConstraints;
- return msg;
-}
-
-
-var Final_transcript = "";
-var Interim_transcript = "";
-var Recognition = null;
-
-if ("webkitSpeechRecognition" in window) {
- var SpeechRecognition = webkitSpeechRecognition;
-} else if ("SpeechRecognition" in window) {
- var SpeechRecognition = window.SpeechRecognition;
-} else {
- var SpeechRecognition = false;
-}
-
-var TranscriptionCounter = 0;
-
-function setupClosedCaptions() {
- log("CLOSED CAPTIONING SETUP");
- if (SpeechRecognition) {
- Recognition = new SpeechRecognition();
-
- Recognition.lang = session.transcript;
-
- Recognition.continuous = true;
- Recognition.interimResults = true;
- Recognition.maxAlternatives = 0;
-
- Recognition.onstart = function() {
- log("started transcription");
- };
- Recognition.onerror = function(event) {
- errorlog(event);
- try {
- Recognition.stop();
- } catch (e) {}
- setTimeout(function() {
- setupClosedCaptions();
- }, 0); // restart it if it fails.
- };
- Recognition.onend = function(e) {
- warnlog(e);
- log("Stopped transcription");
- setTimeout(function() {
- setupClosedCaptions();
- }, 0); // restart it if it fails.
- };
-
- Recognition.onresult = function(event) {
-
- Interim_transcript = '';
- if (typeof(event.results) == 'undefined') {
- log(event);
- return;
- }
- for (var i = event.resultIndex; i < event.results.length; ++i) {
- if (event.results[i].isFinal) {
- Final_transcript += event.results[i][0].transcript;
- } else {
- Interim_transcript += event.results[i][0].transcript;
- }
- }
-
- if (Final_transcript.length > 0) {
- log("FINAL:" + Final_transcript);
- try {
- var data = {};
- data.isFinal = true;
- data.transcript = Final_transcript;
- data.counter = TranscriptionCounter;
- session.sendMessage(data);
- TranscriptionCounter += 1;
- Final_transcript = "";
- Interim_transcript = "";
- } catch (e) {
- errorlog(e);
- }
-
- } else {
- try {
- var data = {};
- data.isFinal = false;
- data.transcript = Interim_transcript;
- data.counter = TranscriptionCounter;
- session.sendMessage(data);
- } catch (e) {
- errorlog(e);
- Interim_transcript = "";
- }
- }
- };
-
- Recognition.start();
- }
-}
-
-
-function requestVideoRecord(ele) {
- var UUID = ele.dataset.UUID
- if (ele.classList.contains("pressed")) {
- var msg = {};
- msg.requestVideoRecord = false;
- msg.UUID = UUID;
- session.sendRequest(msg, msg.UUID);
- ele.classList.remove("pressed");
- } else {
- var msg = {};
- msg.requestVideoRecord = true;
- msg.UUID = UUID;
- window.focus();
- var bitrate = prompt("What bitrate would you like to record at? (kbps)", 6000);
- if (bitrate) {
- msg.value = bitrate;
- session.sendRequest(msg, msg.UUID);
- ele.classList.add("pressed");
- }
- }
-}
-
-function changeOrderDirector(value) {
- if (session.order==false){
- session.order=0;
- }
- session.order += parseInt(value) || 0;
-
- var elements = document.querySelectorAll('[data-action-type="order-value-director"]');
- //log(elements);
- if (elements[0]){
- elements[0].innerText = parseInt(session.order) || 0;
- }
-
- var data = {};
- data = {};
- data.order = session.order;
- session.sendPeers(data);
-}
-
-
-
-function changeOrder(value, UUID) {
- var msg = {};
- msg.changeOrder = value;
- msg.UUID = UUID;
- session.sendRequest(msg, msg.UUID);
-}
-
-function requestVideoHack(keyname, value, UUID) {
- var msg = {};
- msg.requestVideoHack = true;
- msg.keyname = keyname;
- msg.value = value;
- msg.UUID = UUID;
- session.sendRequest(msg, msg.UUID);
-}
-
-function requestAudioHack(keyname, value, UUID, track = 0) { // updateCameraConstraints
- var msg = {};
- msg.requestAudioHack = true;
- msg.keyname = keyname;
- msg.value = value;
- msg.UUID = UUID;
- msg.track = track;
- session.sendRequest(msg, msg.UUID);
-}
-
-function requestChangeEQ(keyname, value, UUID, track = 0) { // updateCameraConstraints
- var msg = {};
- msg.requestChangeEQ = true;
- msg.keyname = keyname;
- msg.value = value;
- msg.UUID = UUID;
- msg.track = track;
- session.sendRequest(msg, msg.UUID);
-}
-
-function requestChangeLowcut(value, UUID, track = 0) { // updateCameraConstraints
- var msg = {};
- msg.requestChangeLowcut = true;
- msg.value = value;
- msg.UUID = UUID;
- msg.track = track;
- session.sendRequest(msg, msg.UUID);
-}
-
-function toggleSystemPip(vid) {
- if (vid.webkitSupportsPresentationMode && (typeof vid.webkitSetPresentationMode === "function")) {
- vid.webkitSetPresentationMode(
- vid.webkitPresentationMode === "picture-in-picture"
- ? "inline"
- : "picture-in-picture"
- );
- } else {
- if (document.pictureInPictureElemen) {
- document.exitPictureInPicture();
- vid.requestPictureInPicture();
- } else {
- vid.requestPictureInPicture();
- }
-
- }
-}
-
-function updateDirectorsAudio(dataN, UUID) {
- var audioEle = document.createElement("div");
- getById("advanced_audio_director_" + UUID).innerHTML = "";
- getById("advanced_audio_director_" + UUID).className = "";
-
- //log(dataN);
- if (!dataN.length) {
- return;
- }
-
- for (var n = 0; n < dataN.length; n += 1) {
- var data = dataN[n];
-
- if (data.trackLabel) {
- var label = document.createElement("span");
- label.innerText = data.trackLabel;
- label.style.marginBottom = "10px";
- label.style.display = "block";
- audioEle.appendChild(label);
- }
- if (n !== 0) {
- //var label = document.createElement("span");
- //label.innerText = "Coming Soon";
- //audioEle.appendChild(label);
- continue; // remove to more than one audio device (assuming other fixes are applied)
- }
-
-
- if (data.lowcut) {
- var label = document.createElement("label");
- var i = "Low_Cut";
- label.id = "label_" + i;
- label.htmlFor = "constraints_" + i;
- label.innerText = "low cut:";
-
- var input = document.createElement("input");
- input.min = 50;
- input.max = 150;
-
- input.type = "range";
- input.dataset.keyname = i;
- input.dataset.labelname = label.innerText;
- input.dataset.track = n;
- input.dataset.UUID = UUID;
- input.id = "constraints_" + i;
- input.style = "display:block; width:100%;";
- input.name = "constraints_" + i;
- input.style.margin = "8px 0";
-
- input.onchange = function(e) {
- getById("label_" + e.target.dataset.keyname).innerText = e.target.dataset.labelname + " " + e.target.value;
- requestChangeLowcut(parseInt(e.target.value), e.target.dataset.UUID, parseInt(e.target.dataset.track));
- };
-
- audioEle.appendChild(label);
- audioEle.appendChild(input);
- }
-
- if (data.equalizer) {
- var label = document.createElement("label");
- var i = "Low_EQ";
- label.id = "label_" + i;
- label.htmlFor = "constraints_" + i;
- label.innerText = "low EQ:";
-
- var input = document.createElement("input");
- input.min = -50;
- input.max = 50;
-
- input.type = "range";
- input.dataset.keyname = i;
- input.dataset.labelname = label.innerText;
- input.dataset.track = n;
- input.dataset.UUID = UUID;
- input.id = "constraints_" + i;
- input.style = "display:block; width:100%;";
- input.name = "constraints_" + i;
- input.style.margin = "8px 0";
-
- input.onchange = function(e) {
- getById("label_" + e.target.dataset.keyname).innerText = e.target.dataset.labelname + " " + e.target.value;
- //changeLowEQ( e.target.value);
- requestChangeEQ("low", parseInt(e.target.value), e.target.dataset.UUID, parseInt(e.target.dataset.track));
- };
-
- audioEle.appendChild(label);
- audioEle.appendChild(input);
-
- var label = document.createElement("label");
- var i = "Mid_EQ";
- label.id = "label_" + i;
- label.htmlFor = "constraints_" + i;
- label.innerText = "mid EQ:";
-
- var input = document.createElement("input");
- input.min = -50;
- input.max = 50;
-
- input.type = "range";
- input.dataset.keyname = i;
- input.dataset.labelname = label.innerText;
- input.dataset.track = n;
- input.dataset.UUID = UUID;
- input.id = "constraints_" + i;
- input.style = "display:block; width:100%;";
- input.name = "constraints_" + i;
- input.style.margin = "8px 0";
-
-
- input.onchange = function(e) {
- getById("label_" + e.target.dataset.keyname).innerText = e.target.dataset.labelname + " " + e.target.value;
- //changeMidEQ( e.target.value);
- requestChangeEQ("mid", parseInt(e.target.value), e.target.dataset.UUID, parseInt(e.target.dataset.track));
- };
-
- audioEle.appendChild(label);
- audioEle.appendChild(input);
-
-
- var label = document.createElement("label");
- var i = "High_EQ";
- label.id = "label_" + i;
- label.htmlFor = "constraints_" + i;
- label.innerText = "high EQ:";
-
- var input = document.createElement("input");
- input.min = -50;
- input.max = 50;
-
- input.type = "range";
- input.dataset.keyname = i;
- input.dataset.labelname = label.innerText;
- input.dataset.track = n;
- input.dataset.UUID = UUID;
- input.id = "constraints_" + i;
- input.style = "display:block; width:100%;";
- input.name = "constraints_" + i;
- input.style.margin = "8px 0";
-
- input.onchange = function(e) {
- getById("label_" + e.target.dataset.keyname).innerText = e.target.dataset.labelname + " " + e.target.value;
- requestChangeEQ("high", parseInt(e.target.value), e.target.dataset.UUID, parseInt(e.target.dataset.track));
- };
-
- audioEle.appendChild(label);
- audioEle.appendChild(input);
- }
- for (var i in data.audioConstraints) {
- try {
- log(i);
- log(data.audioConstraints[i]);
- if ((typeof data.audioConstraints[i] === 'object') && (data.audioConstraints[i] !== null) && ("max" in data.audioConstraints[i]) && ("min" in data.audioConstraints[i])) {
- if (i === "aspectRatio") {
- continue;
- } else if (i === "width") {
- continue;
- } else if (i === "height") {
- continue;
- } else if (i === "frameRate") {
- continue;
- } else if (i === "latency") {
- continue;
- } else if (i === "sampleRate") {
- continue;
- } else if (i === "channelCount") {
- continue;
- }
-
- var label = document.createElement("label");
- label.id = "label_" + i;
- label.htmlFor = "constraints_" + i;
- label.innerText = i + ":";
-
- var input = document.createElement("input");
- input.min = data.audioConstraints[i].min;
- input.max = data.audioConstraints[i].max;
-
- if (parseFloat(input.min) == parseFloat(input.max)) {
- continue;
- }
-
- if (i in data.currentAudioConstraints) {
- input.value = data.currentAudioConstraints[i];
- label.innerText = i + ": " + data.currentAudioConstraints[i];
- label.title = "Previously was: " + data.currentAudioConstraints[i];
- input.title = "Previously was: " + data.currentAudioConstraints[i];
- } else {
- label.innerText = i;
- }
- if ("step" in data.audioConstraints[i]) {
- input.step = data.audioConstraints[i].step;
- }
- input.type = "range";
- input.dataset.keyname = i;
- input.dataset.track = n;
- input.dataset.UUID = UUID;
- input.id = "constraints_" + i;
- input.style = "display:block; width:100%;";
- input.name = "constraints_" + i;
-
-
- input.onchange = function(e) {
- getById("label_" + e.target.dataset.keyname).innerText = e.target.dataset.keyname + ": " + e.target.value;
- //updateAudioConstraints(e.target.dataset.keyname, e.target.value);
- requestAudioHack(e.target.dataset.keyname, e.target.value, e.target.dataset.UUID, e.target.dataset.track);
- };
-
- audioEle.appendChild(label);
- audioEle.appendChild(input);
- } else if ((typeof data.audioConstraints[i] === 'object') && (data.audioConstraints[i] !== null)) {
- if (i == "resizeMode") {
- continue;
- }
-
- var div = document.createElement("div");
- var label = document.createElement("label");
- label.id = "label_" + i;
- label.htmlFor = "constraints_" + i;
- label.innerText = i + ":";
- label.style = "display:inline-block; padding:0;margin: 5px 0px 9px;";
- label.dataset.keyname = i;
- var input = document.createElement("select");
- var c = document.createElement("option");
-
- if (data.audioConstraints[i].length > 1) {
- for (var opts in data.audioConstraints[i]) {
- log(opts);
- var opt = new Option(data.audioConstraints[i][opts], data.audioConstraints[i][opts]);
- input.options.add(opt);
- if (i in data.currentAudioConstraints) {
- if (data.audioConstraints[i][opts] == data.currentAudioConstraints[i]) {
- opt.selected = true;
- }
- }
- }
- } else if (i.toLowerCase == "torch") {
- var opt = new Option("Off", false);
- input.options.add(opt);
- opt = new Option("On", true);
- input.options.add(opt);
- } else {
- continue;
- }
-
- input.id = "constraints_" + i;
- input.className = "constraintCameraInput";
- input.name = "constraints_" + i;
- input.style = "display:inline; padding:2px; margin:0 10px;";
- input.dataset.keyname = i;
- input.dataset.track = n;
- input.dataset.UUID = UUID;
- input.onchange = function(e) {
- //getById("label_"+e.target.dataset.keyname).innerText =e.target.dataset.keyname+": "+e.target.value;
- //updateAudioConstraints(e.target.dataset.keyname, e.target.value);
- requestAudioHack(e.target.dataset.keyname, e.target.value, e.target.dataset.UUID, e.target.dataset.track);
- log(e.target.dataset.keyname, e.target.value);
- };
- audioEle.appendChild(div);
- div.appendChild(label);
- div.appendChild(input);
- } else if (typeof data.audioConstraints[i] === 'boolean') {
-
- var div = document.createElement("div");
- var label = document.createElement("label");
- label.id = "label_" + i;
- label.htmlFor = "constraints_" + i;
- label.innerText = i + ":";
- label.style = "display:inline-block; padding:0;margin: 5px 0px 9px;";
- label.dataset.keyname = i;
- var input = document.createElement("select");
- var c = document.createElement("option");
-
- var opt = new Option("Off", false);
- input.options.add(opt);
- opt = new Option("On", true);
- input.options.add(opt);
-
- input.id = "constraints_" + i;
- input.className = "constraintCameraInput";
- input.name = "constraints_" + i;
- input.style = "display:inline; padding:2px; margin:0 10px;";
- input.dataset.keyname = i;
- input.dataset.track = n;
- input.dataset.UUID = UUID;
- input.onchange = function(e) {
- //getById("label_"+e.target.dataset.keyname).innerText =e.target.dataset.keyname+": "+e.target.value;
- //updateAudioConstraints(e.target.dataset.keyname, e.target.value);
- requestAudioHack(e.target.dataset.keyname, e.target.value, e.target.dataset.UUID, e.target.dataset.track);
- log(e.target.dataset.keyname, e.target.value);
- };
- audioEle.appendChild(div);
- div.appendChild(label);
- div.appendChild(input);
- }
- } catch (e) {
- errorlog(e);
- }
- }
- getById("advanced_audio_director_" + UUID).appendChild(audioEle);
- }
-}
-
-function updateDirectorsVideo(data, UUID) {
- var videoEle = document.createElement("div");
- if (data.trackLabel) {
- var label = document.createElement("span");
- label.innerText = data.trackLabel;
- label.style.marginBottom = "10px";
- label.style.display = "block";
- videoEle.appendChild(label);
- }
-
-
- for (var i in data.cameraConstraints) {
- try {
- log(i);
- log(data.cameraConstraints[i]);
- if ((typeof data.cameraConstraints[i] === 'object') && (data.cameraConstraints[i] !== null) && ("max" in data.cameraConstraints[i]) && ("min" in data.cameraConstraints[i])) {
- if (i === "aspectRatio") {
- continue;
- } else if (i === "width") {
- continue;
- } else if (i === "height") {
- continue;
- } else if (i === "frameRate") {
- continue;
- } else if (i === "latency") {
- continue;
- } else if (i === "sampleRate") {
- continue;
- } else if (i === "channelCount") {
- continue;
- }
-
- var label = document.createElement("label");
- label.id = "label_" + i;
- label.htmlFor = "constraints_" + i;
- label.innerText = i + ":";
-
- var input = document.createElement("input");
- input.min = data.cameraConstraints[i].min;
- input.max = data.cameraConstraints[i].max;
-
- if (parseFloat(input.min) == parseFloat(input.max)) {
- continue;
- }
-
-
- if (i in data.currentCameraConstraints) {
- input.value = data.currentCameraConstraints[i];
- label.innerText = i + ": " + data.currentCameraConstraints[i];
- label.title = "Previously was: " + data.currentCameraConstraints[i];
- input.title = "Previously was: " + data.currentCameraConstraints[i];
- } else {
- label.innerText = i;
- }
- if ("step" in data.cameraConstraints[i]) {
- input.step = data.cameraConstraints[i].step;
- }
- input.type = "range";
- input.dataset.keyname = i;
- input.id = "constraints_" + i;
- input.style = "display:block; width:100%;margin: 8px 0;";
- input.name = "constraints_" + i;
-
-
- input.onchange = function(e) {
- getById("label_" + e.target.dataset.keyname).innerText = e.target.dataset.keyname + ": " + e.target.value;
- //updateVideoConstraints(e.target.dataset.keyname, e.target.value);
- requestVideoHack(e.target.dataset.keyname, e.target.value, UUID);
- };
-
-
- videoEle.appendChild(label);
- videoEle.appendChild(input);
- } else if ((typeof data.cameraConstraints[i] === 'object') && (data.cameraConstraints[i] !== null)) {
- if (i == "resizeMode") {
- continue;
- }
-
- var div = document.createElement("div");
- var label = document.createElement("label");
- label.id = "label_" + i;
- label.htmlFor = "constraints_" + i;
- label.innerText = i + ":";
- label.style = "display:inline-block; padding:0;margin: 5px 0px 9px;";
- label.dataset.keyname = i;
- var input = document.createElement("select");
- var c = document.createElement("option");
-
- if (data.cameraConstraints[i].length > 1) {
- for (var opts in data.cameraConstraints[i]) {
- log(opts);
- var opt = new Option(data.cameraConstraints[i][opts], data.cameraConstraints[i][opts]);
- input.options.add(opt);
- if (i in data.currentCameraConstraints) {
- if (data.cameraConstraints[i][opts] == data.currentCameraConstraints[i]) {
- opt.selected = true;
- }
- }
- }
- } else if (i.toLowerCase == "torch") {
- var opt = new Option("Off", false);
- input.options.add(opt);
- opt = new Option("On", true);
- input.options.add(opt);
- } else {
- continue;
- }
-
- input.id = "constraints_" + i;
- input.className = "constraintCameraInput";
- input.name = "constraints_" + i;
- input.style = "display:inline; padding:2px; margin:0 10px;";
- input.dataset.keyname = i;
- input.onchange = function(e) {
- //getById("label_"+e.target.dataset.keyname).innerText =e.target.dataset.keyname+": "+e.target.value;
- //updateVideoConstraints(e.target.dataset.keyname, e.target.value);
- requestVideoHack(e.target.dataset.keyname, e.target.value, UUID);
- log(e.target.dataset.keyname, e.target.value);
- };
- videoEle.appendChild(div);
- div.appendChild(label);
- div.appendChild(input);
- } else if (typeof data.cameraConstraints[i] === 'boolean') {
-
- var div = document.createElement("div");
- var label = document.createElement("label");
- label.id = "label_" + i;
- label.htmlFor = "constraints_" + i;
- label.innerText = i + ":";
- label.style = "display:inline-block; padding:0;margin: 5px 0px 9px;";
- label.dataset.keyname = i;
- var input = document.createElement("select");
- var c = document.createElement("option");
-
- var opt = new Option("Off", false);
- input.options.add(opt);
- opt = new Option("On", true);
- input.options.add(opt);
-
- input.id = "constraints_" + i;
- input.className = "constraintCameraInput";
- input.name = "constraints_" + i;
- input.style = "display:inline; padding:2px; margin:0 10px;";
- input.dataset.keyname = i;
- input.onchange = function(e) {
- //getById("label_"+e.target.dataset.keyname).innerText =e.target.dataset.keyname+": "+e.target.value;
- //updateVideoConstraints(e.target.dataset.keyname, e.target.value);
- requestVideoHack(e.target.dataset.keyname, e.target.value, UUID);
- log(e.target.dataset.keyname, e.target.value);
- };
- videoEle.appendChild(div);
- div.appendChild(label);
- div.appendChild(input);
- }
- } catch (e) {
- errorlog(e);
- }
- }
-
- getById("advanced_video_director_" + UUID).innerHTML = "";
- getById("advanced_video_director_" + UUID).appendChild(videoEle);
- getById("advanced_video_director_" + UUID).className = "";
-}
-
-///////
-
-function listAudioSettings() {
- getById("popupSelector_constraints_audio").innerHTML = "";
- try {
- var track0 = session.streamSrc.getAudioTracks();
- if (track0.length) {
- track0 = track0[0];
- if (track0.getCapabilities) {
- session.audioConstraints = track0.getCapabilities();
- }
- log(session.audioConstraints);
- } else {
- warnlog("session.streamSrc contains no audio tracks");
- return;
- }
- } catch (e) {
- warnlog("session.streamSrc contains no audio tracks");
- errorlog(e);
- return;
- }
- try {
- if (track0.getSettings) {
- session.currentAudioConstraints = track0.getSettings();
- }
- } catch (e) {
- errorlog(e);
- }
- //////
-
- if (session.lowcut) {
- if (getById("popupSelector_constraints_audio").style.display == "none") {
- getById("advancedOptionsAudio").style.display = "inline-block";
- }
-
- var label = document.createElement("label");
- var i = "Low_Cut";
- label.id = "label_" + i;
- label.htmlFor = "constraints_" + i;
- label.innerText = "Low Cut:";
-
- var input = document.createElement("input");
- input.min = 50;
- input.max = 400;
-
- input.type = "range";
- input.dataset.keyname = i;
- input.dataset.labelname = label.innerHTML;
- input.id = "constraints_" + i;
- input.style = "display:block; width:100%;";
- input.name = "constraints_" + i;
-
- for (var webAudio in session.webAudios) {
- if (session.webAudios[webAudio].lowcut1.frequency) {
- input.value = session.webAudios[webAudio].lowcut1.frequency.value;
- label.innerHTML += " " + session.webAudios[webAudio].lowcut1.frequency.value;
- }
- }
-
- input.onchange = function(e) {
- getById("label_" + e.target.dataset.keyname).innerHTML = e.target.dataset.labelname + " " + e.target.value;
- changeLowCut(e.target.value, 0);
- };
-
- getById("popupSelector_constraints_audio").appendChild(label);
- getById("popupSelector_constraints_audio").appendChild(input);
- }
-
- if (session.equalizer) {
- if (getById("popupSelector_constraints_audio").style.display == "none") {
- getById("advancedOptionsAudio").style.display = "inline-block";
- }
-
- var label = document.createElement("label");
- var i = "Low_EQ";
- label.id = "label_" + i;
- label.htmlFor = "constraints_" + i;
- label.innerHTML = "Low EQ:";
-
- var input = document.createElement("input");
- input.min = -50;
- input.max = 50;
-
- input.type = "range";
- input.dataset.keyname = i;
- input.dataset.labelname = label.innerHTML;
- input.id = "constraints_" + i;
- input.style = "display:block; width:100%;";
- input.name = "constraints_" + i;
-
- for (var webAudio in session.webAudios) {
- if (session.webAudios[webAudio].lowEQ.gain) {
- input.value = session.webAudios[webAudio].lowEQ.gain.value;
- label.innerHTML += " " + session.webAudios[webAudio].lowEQ.gain.value;
- }
- }
-
- input.onchange = function(e) {
- getById("label_" + e.target.dataset.keyname).innerHTML = e.target.dataset.labelname + " " + e.target.value;
- changeLowEQ(e.target.value, 0);
- };
-
- getById("popupSelector_constraints_audio").appendChild(label);
- getById("popupSelector_constraints_audio").appendChild(input);
- //
- if (getById("popupSelector_constraints_audio").style.display == "none") {
- getById("advancedOptionsAudio").style.display = "inline-block";
- }
-
- var label = document.createElement("label");
- var i = "Mid_EQ";
- label.id = "label_" + i;
- label.htmlFor = "constraints_" + i;
- label.innerHTML = "Mid EQ:";
-
- var input = document.createElement("input");
- input.min = -50;
- input.max = 50;
-
- input.type = "range";
- input.dataset.keyname = i;
- input.dataset.labelname = label.innerHTML;
- input.id = "constraints_" + i;
- input.style = "display:block; width:100%;";
- input.name = "constraints_" + i;
-
-
- for (var webAudio in session.webAudios) {
- if (session.webAudios[webAudio].midEQ.gain) {
- input.value = session.webAudios[webAudio].midEQ.gain.value;
- label.innerHTML += " " + session.webAudios[webAudio].midEQ.gain.value;
- }
- }
-
-
- input.onchange = function(e) {
- getById("label_" + e.target.dataset.keyname).innerHTML = e.target.dataset.labelname + " " + e.target.value;
- changeMidEQ(e.target.value, 0);
- };
-
- getById("popupSelector_constraints_audio").appendChild(label);
- getById("popupSelector_constraints_audio").appendChild(input);
- //
- if (getById("popupSelector_constraints_audio").style.display == "none") {
- getById("advancedOptionsAudio").style.display = "inline-block";
- }
-
- var label = document.createElement("label");
- var i = "High_EQ";
- label.id = "label_" + i;
- label.htmlFor = "constraints_" + i;
- label.innerHTML = "High EQ:";
-
- var input = document.createElement("input");
- input.min = -50;
- input.max = 50;
-
-
- input.type = "range";
- input.dataset.keyname = i;
- input.dataset.labelname = label.innerHTML;
- input.id = "constraints_" + i;
- input.style = "display:block; width:100%;";
- input.name = "constraints_" + i;
-
- for (var webAudio in session.webAudios) {
- if (session.webAudios[webAudio].highEQ.gain) {
- input.value = session.webAudios[webAudio].highEQ.gain.value;
- label.innerHTML += " " + session.webAudios[webAudio].highEQ.gain.value;
- }
- }
-
-
- input.onchange = function(e) {
- getById("label_" + e.target.dataset.keyname).innerHTML = e.target.dataset.labelname + " " + e.target.value;
- changeHighEQ(e.target.value, 0);
- };
-
- getById("popupSelector_constraints_audio").appendChild(label);
- getById("popupSelector_constraints_audio").appendChild(input);
- }
- ////////
- for (var i in session.audioConstraints) {
- try {
- log(i);
- log(session.audioConstraints[i]);
- if ((typeof session.audioConstraints[i] === 'object') && (session.audioConstraints[i] !== null) && ("max" in session.audioConstraints[i]) && ("min" in session.audioConstraints[i])) {
- if (i === "aspectRatio") {
- continue;
- } else if (i === "width") {
- continue;
- } else if (i === "height") {
- continue;
- } else if (i === "frameRate") {
- continue;
- } else if (i === "latency") {
- continue;
- } else if (i === "sampleRate") {
- continue;
- } else if (i === "channelCount") {
- continue;
- }
-
- var label = document.createElement("label");
- label.id = "label_" + i;
- label.htmlFor = "constraints_" + i;
- label.innerHTML = i + ":";
-
-
- var input = document.createElement("input");
- input.min = session.audioConstraints[i].min;
- input.max = session.audioConstraints[i].max;
-
- if (parseFloat(input.min) == parseFloat(input.max)) {
- continue;
- }
-
- if (getById("popupSelector_constraints_audio").style.display == "none") {
- getById("advancedOptionsAudio").style.display = "inline-block";
- }
-
-
- if (i in session.currentAudioConstraints) {
- input.value = session.currentAudioConstraints[i];
- label.innerHTML = i + ": " + session.currentAudioConstraints[i];
- label.title = "Previously was: " + session.currentAudioConstraints[i];
- input.title = "Previously was: " + session.currentAudioConstraints[i];
- } else {
- label.innerHTML = i;
- }
- if ("step" in session.audioConstraints[i]) {
- input.step = session.audioConstraints[i].step;
- }
- input.type = "range";
- input.dataset.keyname = i;
- input.id = "constraints_" + i;
- input.style = "display:block; width:100%;";
- input.name = "constraints_" + i;
-
-
- input.onchange = function(e) {
- getById("label_" + e.target.dataset.keyname).innerHTML = e.target.dataset.keyname + ": " + e.target.value;
- //updateAudioConstraints(e.target.dataset.keyname, e.target.value);
- applyAudioHack(e.target.dataset.keyname, e.target.value);
- };
-
-
- getById("popupSelector_constraints_audio").appendChild(label);
- getById("popupSelector_constraints_audio").appendChild(input);
- } else if ((typeof session.audioConstraints[i] === 'object') && (session.audioConstraints[i] !== null)) {
- if (i == "resizeMode") {
- continue;
- }
-
- var div = document.createElement("div");
- var label = document.createElement("label");
- label.id = "label_" + i;
- label.htmlFor = "constraints_" + i;
- label.innerHTML = i + ":";
- label.style = "display:inline-block; padding:0;margin: 15px 0px 29px;";
- label.dataset.keyname = i;
- var input = document.createElement("select");
- var c = document.createElement("option");
-
- if (session.audioConstraints[i].length > 1) {
- for (var opts in session.audioConstraints[i]) {
- log(opts);
- var opt = new Option(session.audioConstraints[i][opts], session.audioConstraints[i][opts]);
- input.options.add(opt);
-
- if (i in session.currentAudioConstraints) {
- if (session.audioConstraints[i][opts] == session.currentAudioConstraints[i]) {
- opt.selected = true;
- }
- }
-
- }
- } else if (i.toLowerCase == "torch") {
- var opt = new Option("Off", false);
- input.options.add(opt);
- opt = new Option("On", true);
- input.options.add(opt);
- } else {
- continue;
- }
-
- if (getById("popupSelector_constraints_audio").style.display == "none") {
- getById("advancedOptionsAudio").style.display = "inline-block";
- }
-
- input.id = "constraints_" + i;
- input.className = "constraintCameraInput";
- input.name = "constraints_" + i;
- input.style = "display:inline; padding:2px; margin:0 10px;";
- input.dataset.keyname = i;
- input.onchange = function(e) {
- //getById("label_"+e.target.dataset.keyname).innerHTML =e.target.dataset.keyname+": "+e.target.value;
- //updateAudioConstraints(e.target.dataset.keyname, e.target.value);
- applyAudioHack(e.target.dataset.keyname, e.target.value);
- log(e.target.dataset.keyname, e.target.value);
- };
- getById("popupSelector_constraints_audio").appendChild(div);
- div.appendChild(label);
- div.appendChild(input);
- } else if (typeof session.audioConstraints[i] === 'boolean') {
-
- var div = document.createElement("div");
- var label = document.createElement("label");
- label.id = "label_" + i;
- label.htmlFor = "constraints_" + i;
- label.innerHTML = i + ":";
- label.style = "display:inline-block; padding:0;margin: 15px 0px 29px;";
- label.dataset.keyname = i;
- var input = document.createElement("select");
- var c = document.createElement("option");
-
- var opt = new Option("Off", false);
- input.options.add(opt);
- opt = new Option("On", true);
- input.options.add(opt);
-
- if (getById("popupSelector_constraints_audio").style.display == "none") {
- getById("advancedOptionsAudio").style.display = "inline-block";
- }
-
- input.id = "constraints_" + i;
- input.className = "constraintCameraInput";
- input.name = "constraints_" + i;
- input.style = "display:inline; padding:2px; margin:0 10px;";
- input.dataset.keyname = i;
- input.onchange = function(e) {
- //getById("label_"+e.target.dataset.keyname).innerHTML =e.target.dataset.keyname+": "+e.target.value;
- //updateAudioConstraints(e.target.dataset.keyname, e.target.value);
- applyAudioHack(e.target.dataset.keyname, e.target.value);
- log(e.target.dataset.keyname, e.target.value);
- };
- getById("popupSelector_constraints_audio").appendChild(div);
- div.appendChild(label);
- div.appendChild(input);
- }
- } catch (e) {
- errorlog(e);
- }
-
- }
-}
-
-
-function applyAudioHack(constraint, value = null) {
- if (value == parseFloat(value)) {
- value = parseFloat(value);
- value = {
- exact: value
- };
- } else if (value == "true") {
- value = true;
- } else if (value == "false") {
- value = false;
- }
- log(constraint);
- ////////////////
- try {
- var track0 = session.streamSrc.getAudioTracks();
- if (track0.length) {
- track0 = track0[0];
- if (track0.getCapabilities) {
- session.audioConstraints = track0.getCapabilities();
- }
- log(session.audioConstraints);
- } else {
- warnlog("session.streamSrc contains no audio tracks");
- return;
- }
- } catch (e) {
- warnlog("session.streamSrc contains no audio tracks");
- errorlog(e);
- return;
- }
- try {
- if (track0.getSettings) {
- session.currentAudioConstraints = track0.getSettings();
- }
- } catch (e) {
- errorlog(e);
- }
- ////////
-
- var new_constraints = Object.assign(track0.getSettings(), {
- [constraint]: value
- }, );
- new_constraints = {
- audio: new_constraints
- , video: false
- };
- log(new_constraints);
- activatedPreview = false;
- enumerateDevices().then(gotDevices2).then(function() {
- grabAudio("videosource", "#audioSource3", null, new_constraints);
- });
-
-}
-
-function updateAudioConstraints(constraint, value = null) { // this is what it SHOULD be, but this doesn't work yet.
- var track0 = session.streamSrc.getAudioTracks();
- track0 = track0[0];
- if (value == parseFloat(value)) {
- value = parseFloat(value);
- } else if (value == "true") {
- value = true;
- } else if (value == "false") {
- value = false;
- }
- log({
- advanced: [{
- [constraint]: value
- }]
- });
- track0.applyConstraints({
- advanced: [{
- [constraint]: value
- }]
- });
- return;
-
-}
-
-function listCameraSettings() {
- getById("popupSelector_constraints_video").innerHTML = "";
-
- if (session.controlRoomBitrate===true){
- session.controlRoomBitrate = session.totalRoomBitrate;
- }
-
- if (session.roomid && (session.view !== "") && (session.controlRoomBitrate!==false)) {
- log("LISTING OPTION FOR BITRATE CONTROL");
- var i = "room video bitrate (kbps)";
- var label = document.createElement("label");
- label.id = "label_" + i;
- label.htmlFor = "constraints_" + i;
- label.innerHTML = i + ":";
- label.title = "If you're on a slow network, you can improve frame rate and audio quality by reducing the amount of video data that others send you";
-
- var input = document.createElement("input");
- input.min = 0;
- input.max = parseInt(session.totalRoomBitrate);
-
- if (getById("popupSelector_constraints_video").style.display == "none") {
- getById("advancedOptionsCamera").style.display = "inline-block";
- }
-
- input.value = session.controlRoomBitrate;
- label.innerHTML = i + ": " + session.controlRoomBitrate;
-
- input.type = "range";
- input.dataset.keyname = i;
- input.id = "constraints_" + i;
- input.style = "display:block; width:100%;";
- input.name = "constraints_" + i;
- input.title = "If you're on a slow network, you can improve frame rate and audio quality by reducing the amount of video data that others send you";
-
-
- input.onchange = function(e) {
- getById("label_" + e.target.dataset.keyname).innerHTML = e.target.dataset.keyname + ": " + e.target.value;
-
- if (e.target.value > session.totalRoomBitrate) {
- return;
- } else {
- session.controlRoomBitrate = parseInt(e.target.value);
- }
- updateMixer();
- };
-
-
- getById("popupSelector_constraints_video").appendChild(label);
- getById("popupSelector_constraints_video").appendChild(input);
-
- }
- try {
- var track0 = session.streamSrc.getVideoTracks();
- if (track0.length) {
- track0 = track0[0];
- if (track0.getCapabilities) {
- session.cameraConstraints = track0.getCapabilities();
- }
- log(session.cameraConstraints);
- }
- } catch (e) {
- errorlog(e);
- return;
- }
-
- try {
-
- if (track0.getSettings) {
- session.currentCameraConstraints = track0.getSettings();
- }
- } catch (e) {
- errorlog(e);
- }
-
- for (var i in session.cameraConstraints) {
- try {
- log(i);
- log(session.cameraConstraints[i]);
- if ((typeof session.cameraConstraints[i] === 'object') && (session.cameraConstraints[i] !== null) && ("max" in session.cameraConstraints[i]) && ("min" in session.cameraConstraints[i])) {
- if (i === "aspectRatio") {
- continue;
- } else if (i === "width") {
- continue;
- } else if (i === "height") {
- continue;
- } else if (i === "frameRate") {
- continue;
- }
-
-
- var label = document.createElement("label");
- label.id = "label_" + i;
- label.htmlFor = "constraints_" + i;
- label.innerHTML = i + ":";
-
- var input = document.createElement("input");
- input.min = session.cameraConstraints[i].min;
- input.max = session.cameraConstraints[i].max;
-
- if (parseFloat(input.min) == parseFloat(input.max)) {
- continue;
- }
-
- if (getById("popupSelector_constraints_video").style.display == "none") {
- getById("advancedOptionsCamera").style.display = "inline-block";
- }
-
- if (i in session.currentCameraConstraints) {
- input.value = session.currentCameraConstraints[i];
- label.innerHTML = i + ": " + session.currentCameraConstraints[i];
- label.title = "Previously was: " + session.currentCameraConstraints[i];
- input.title = "Previously was: " + session.currentCameraConstraints[i];
- } else {
- label.innerHTML = i;
- }
- if ("step" in session.cameraConstraints[i]) {
- input.step = session.cameraConstraints[i].step;
- }
- input.type = "range";
- input.dataset.keyname = i;
- input.id = "constraints_" + i;
- input.style = "display:block; width:100%;";
- input.name = "constraints_" + i;
-
-
- input.onchange = function(e) {
- getById("label_" + e.target.dataset.keyname).innerHTML = e.target.dataset.keyname + ": " + e.target.value;
- updateCameraConstraints(e.target.dataset.keyname, e.target.value);
- };
-
-
- getById("popupSelector_constraints_video").appendChild(label);
- getById("popupSelector_constraints_video").appendChild(input);
- } else if ((typeof session.cameraConstraints[i] === 'object') && (session.cameraConstraints[i] !== null)) {
- if (i == "resizeMode") {
- continue;
- }
-
- var div = document.createElement("div");
- var label = document.createElement("label");
- label.id = "label_" + i;
- label.htmlFor = "constraints_" + i;
- label.innerHTML = i + ":";
- label.style = "display:inline-block; padding:0;margin: 15px 0px 29px;";
- label.dataset.keyname = i;
- var input = document.createElement("select");
- var c = document.createElement("option");
-
- if (session.cameraConstraints[i].length > 1) {
- for (var opts in session.cameraConstraints[i]) {
- log(opts);
- var opt = new Option(session.cameraConstraints[i][opts], session.cameraConstraints[i][opts]);
- input.options.add(opt);
- if (i in session.currentCameraConstraints) {
- if (session.cameraConstraints[i][opts] == session.currentCameraConstraints[i]) {
- opt.selected = true;
- }
- }
- }
- } else if (i.toLowerCase == "torch") {
- var opt = new Option("Off", false);
- input.options.add(opt);
- opt = new Option("On", true);
- input.options.add(opt);
- } else {
- continue;
- }
-
- if (getById("popupSelector_constraints_video").style.display == "none") {
- getById("advancedOptionsCamera").style.display = "inline-block";
- }
-
- input.id = "constraints_" + i;
- input.className = "constraintCameraInput";
- input.name = "constraints_" + i;
- input.style = "display:inline; padding:2px; margin:0 10px;";
- input.dataset.keyname = i;
- input.onchange = function(e) {
- //getById("label_"+e.target.dataset.keyname).innerHTML =e.target.dataset.keyname+": "+e.target.value;
- updateCameraConstraints(e.target.dataset.keyname, e.target.value);
- log(e.target.dataset.keyname, e.target.value);
- };
- getById("popupSelector_constraints_video").appendChild(div);
- div.appendChild(label);
- div.appendChild(input);
- } else if (typeof session.cameraConstraints[i] === 'boolean') {
-
- var div = document.createElement("div");
- var label = document.createElement("label");
- label.id = "label_" + i;
- label.htmlFor = "constraints_" + i;
- label.innerHTML = i + ":";
- label.style = "display:inline-block; padding:0;margin: 15px 0px 29px;";
- label.dataset.keyname = i;
- var input = document.createElement("select");
- var c = document.createElement("option");
-
- var opt = new Option("Off", false);
- input.options.add(opt);
- opt = new Option("On", true);
- input.options.add(opt);
-
- if (getById("popupSelector_constraints_video").style.display == "none") {
- getById("advancedOptionsCamera").style.display = "inline-block";
- }
-
- input.id = "constraints_" + i;
- input.className = "constraintCameraInput";
- input.name = "constraints_" + i;
- input.style = "display:inline; padding:2px; margin:0 10px;";
- input.dataset.keyname = i;
- input.onchange = function(e) {
- //getById("label_"+e.target.dataset.keyname).innerHTML =e.target.dataset.keyname+": "+e.target.value;
- updateCameraConstraints(e.target.dataset.keyname, e.target.value);
- log(e.target.dataset.keyname, e.target.value);
- };
- getById("popupSelector_constraints_video").appendChild(div);
- div.appendChild(label);
- div.appendChild(input);
- }
- } catch (e) {
- errorlog(e);
- }
-
- }
-}
-
-function updateCameraConstraints(constraint, value = null) {
- var track0 = session.streamSrc.getVideoTracks();
- track0 = track0[0];
- if (value == parseFloat(value)) {
- value = parseFloat(value);
- } else if (value == "true") {
- value = true;
- } else if (value == "false") {
- value = false;
- }
- log({
- advanced: [{
- [constraint]: value
- }]
- });
- track0.applyConstraints({
- advanced: [{
- [constraint]: value
- }]
- });
- return;
-
-}
-
-function setupWebcamSelection(stream = null) {
- log("setup webcam");
-
- if (stream) {
- log(getById("previewWebcam"));
- session.streamSrc = stream;
- getById("previewWebcam").srcObject = outboundAudioPipeline(session.streamSrc);
- } else {
- log("THIS IS NO STREAM??");
- }
-
- if (!session.videoElement) {
- session.videoElement = getById("previewWebcam");
- }
-
- try {
- return enumerateDevices().then(gotDevices).then(function() {
-
- if (getById("webcamquality").elements && parseInt(getById("webcamquality").elements.namedItem("resolution").value) == 3) {
- if (session.maxframerate===false){
- session.maxframerate = 30;
- session.maxframerate_q2 = true;
- }
- } else if (session.maxframerate_q2){
- session.maxframerate = false;
- session.maxframerate_q2 = false;
- }
-
- var audioSelect = getById('audioSource');
- var videoSelect = getById('videoSourceSelect');
- var outputSelect = getById('outputSource');
-
- audioSelect.onchange = function() {
-
- var gowebcam = getById("gowebcam");
- if (gowebcam) {
- gowebcam.disabled = true;
- gowebcam.dataset.ready = "true";
- gowebcam.style.backgroundColor = "#DDDDDD";
- gowebcam.style.fontWeight = "normal";
- gowebcam.innerHTML = "Waiting for Camera to load";
- miniTranslate(gowebcam, "waiting-for-camera-to-load");
- }
- activatedPreview = false;
- grabAudio();
- };
- videoSelect.onchange = function() {
-
- var gowebcam = getById("gowebcam");
- if (gowebcam) {
- gowebcam.disabled = true;
- gowebcam.dataset.ready = "true";
- gowebcam.style.backgroundColor = "#DDDDDD";
- gowebcam.style.fontWeight = "normal";
- gowebcam.innerHTML = "Waiting for Camera to load";
- miniTranslate(gowebcam, "waiting-for-camera-to-load");
- }
- warnlog("video source changed");
-
- activatedPreview = false;
- if (session.quality !== false) {
- grabVideo(session.quality);
- } else {
- session.quality_wb = parseInt(getById("webcamquality").elements.namedItem("resolution").value);
- grabVideo(session.quality_wb);
- }
- };
-
- outputSelect.onchange = function() {
-
- if ((iOS) || (iPad)) {
- return;
- }
- try{
- session.sink = outputSelect.options[outputSelect.selectedIndex].value;
- } catch(e){errorlog(e);}
-
- if (!session.sink){return;}
-
- try{
- getById("previewWebcam").setSinkId(session.sink).then(() => {
- log("New Output Device:" + session.sink);
- }).catch(error => {
- errorlog("6597");
- errorlog(error);
- //setTimeout(function(){warnUser("Failed to change audio output destination.");},1);
- });
- } catch(e){errorlog(e);}
- }
-
- getById("webcamquality").onchange = function() {
- var gowebcam = getById("gowebcam");
- if (gowebcam) {
- gowebcam.disabled = true;
- gowebcam.dataset.ready = "true";
- gowebcam.style.backgroundColor = "#DDDDDD";
- gowebcam.style.fontWeight = "normal";
- gowebcam.innerHTML = "Waiting for Camera to load";
- miniTranslate(gowebcam, "waiting-for-camera-to-load");
- }
-
- if (parseInt(getById("webcamquality").elements.namedItem("resolution").value) == 2) {
- if (session.maxframerate===false){
- session.maxframerate = 30;
- session.maxframerate_q2 = true;
- }
- } else if (session.maxframerate_q2){
- session.maxframerate = false;
- session.maxframerate_q2 = false;
- }
-
- activatedPreview = false;
- session.quality_wb = parseInt(getById("webcamquality").elements.namedItem("resolution").value);
- grabVideo(session.quality_wb);
- };
-
- if ((session.audioDevice) && (session.audioDevice !== 1)) { // change from Auto to Selected Audio Device
- log("SETTING AUDIO DEVICE!!");
- activatedPreview = false;
- grabAudio();
- }
-
- if (session.videoDevice === 0) {
- if (session.autostart) {
- publishWebcam(); // no need to mirror as there is no video...
- return;
- } else {
- var gowebcam = getById("gowebcam");
- if (gowebcam) {
- gowebcam.disabled = false;
- gowebcam.dataset.ready = "true";
- gowebcam.innerHTML = "START";
- miniTranslate(gowebcam, "start");
- }
- return;
- }
- } else {
- log("GRabbing video: " + session.quality);
- activatedPreview = false;
- if (session.quality !== false) {
- grabVideo(session.quality);
- } else {
- session.quality_wb = parseInt(getById("webcamquality").elements.namedItem("resolution").value);
- grabVideo(session.quality_wb);
- }
- }
-
- if ((iOS) || (iPad)) {
- return;
- }
- try {
- if (outputSelect.selectedIndex >= 0) {
- session.sink = outputSelect.options[outputSelect.selectedIndex].value;
- }
- } catch(e){errorlog(e);}
-
- if (document.getElementById("previewWebcam") && document.getElementById("previewWebcam").setSinkId) {
- if (session.sink) {
- getById("previewWebcam").setSinkId(session.sink).then(() => {}).catch(error => {
- warnlog("6665");
- warnlog(error);
- });
- }
- }
-
- }).catch(e => {
- errorlog(e);
- });
- } catch (e) {
- errorlog(e);
- }
-}
-
-Promise.wait = function(ms) {
- return new Promise(function(resolve) {
- setTimeout(resolve, ms);
- });
-};
-
-Promise.prototype.timeout = function(ms) {
- return Promise.race([
- this, Promise.wait(ms).then(function() {
- var errormsg = new Error("Time Out\nDid you accept camera permissions in time? Please do so first.\n\nOtherwise, do you have NDI Tools installed? Maybe try uninstalling it.\n\nPlease also ensure your camera and audio device are correctly connected and not already in use. You may also need to refresh the page.");
- errormsg.name = "timedOut";
- errormsg.message = "Time Out\nDid you accept camera permissions in time? Please do so first.\n\nOtherwise, do you have NDI Tools installed? Maybe try uninstalling it.\n\nPlease also ensure your camera and audio device are correctly connected and not already in use. You may also need to refresh the page."
- throw errormsg;
-
- })
- ])
-};
-
-
-function shareWebsite(autostart=false){
-
- if (session.iframeSrc){
- session.iframeSrc = false;
- session.iframeEle = null;
- getById("websitesharetoggle").classList.add("la-window-maximize");
- getById("websitesharetoggle").classList.remove("la-window-close");
-
- getById("websitesharebutton").classList.remove("float2");
- getById("websitesharebutton").classList.add("float");
-
- var data = {};
- data.iframeSrc = false;
- for (var UUID in session.pcs){
- if (session.pcs[UUID].allowIframe===true){
- session.sendMessage(data, UUID);
- }
- }
- return
- }
- if (autostart===false){
- window.focus();
- var iframeURL = prompt("Enter a website URL to share", "https://www.youtube.com/watch?v=dQw4w9WgXcQ");
- } else {
- var iframeURL = autostart;
- }
- if (!iframeURL){
- return;
- }
- if (iframeURL == session.iframeSrc){return;}
-
- if (!(iframeURL.startsWith("https://") || iframeURL.startsWith("http://"))){
- iframeURL = "https://"+iframeURL;
- }
-
- var domain = new URL(iframeURL);
- domain = domain.hostname;
- log(domain);
- if ((domain=="www.youtube.com") || (domain=="youtube.com")){
- var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
- var match = iframeURL.match(regExp);
- var vidid = (match&&match[7].length==11)? match[7] : false;
-
- if(vidid){
- iframeURL = "https://www.youtube.com/embed/"+vidid+"?autoplay=1&modestbranding=1";
- log(iframeURL);
- }
- } else if (domain=="www.twitch.tv"){
- var vidid = iframeURL.split('/').pop().split('#')[0].split('?')[0];
- if (vidid){
- iframeURL = "https://player.twitch.tv/?channel="+vidid+"&parent="+location.hostname;
- log(iframeURL);
- }
- } else if (domain=="twitch.tv"){
- var vidid = iframeURL.split('/').pop().split('#')[0].split('?')[0];
- if (vidid){
- iframeURL = "https://player.twitch.tv/?channel="+vidid+"&parent="+location.hostname;
- log(iframeURL);
- }
- }
-
-
-
- session.iframeSrc = iframeURL;
-
- var iframe = document.createElement("iframe");
- iframe.allow="autoplay;camera;microphone;fullscreen;picture-in-picture";
- iframe.allowtransparency="true";
- iframe.allowfullscreen ="true";
- iframe.src = session.iframeSrc;
- iframe.id = "iframe_source"
- session.iframeEle = iframe;
-
- getById("websitesharetoggle").classList.remove("la-window-maximize");
- getById("websitesharetoggle").classList.add("la-window-close");
-
- getById("websitesharebutton").classList.add("float2");
- getById("websitesharebutton").classList.remove("float");
-
- var data = {};
- data.iframeSrc = iframeURL;
- for (var UUID in session.pcs){
- if (session.pcs[UUID].allowIframe===true){
- session.sendMessage(data, UUID);
- }
- }
-}
-
-function createIframePopup() {
-
- if (session.screenShareElement) {
- session.screenShareElement.contentWindow.postMessage({
- "close": true
- }, '*');
- session.screenShareElement.parentNode.removeChild(session.screenShareElement);
- session.screenShareElement = false;
- updateMixer();
- getById("screenshare2button").classList.add("float");
- getById("screenshare2button").classList.remove("float2");
- return;
- }
-
- if (session.queue || session.transferred){
- getById("screenshare2button").classList.add("advanced");
- getById("screensharebutton").classList.remove("advanced");
- toggleScreenShare();
- return;
- } // can't secondary-screen share if in a queue.
-
- if (session.screenshareid) {
- var iFrameID = session.screenshareid;
- } else {
- var iFrameID = session.streamID.substring(0, 12) + "_" + session.generateStreamID(5);
- }
-
- if (session.exclude) {
- session.exclude.push(iFrameID);
- } else {
- session.exclude = [];
- session.exclude.push(iFrameID);
- }
-
- var iframe = document.createElement("iframe");
- iframe.allow = "autoplay";
- iframe.allowtransparency = "true";
-
- var extras = "";
- if (session.password){
- extras += "&password=" + session.password; // encodeURIComponent(
- }
-
- if (session.privacy){
- extras += "&privacy";
- }
-
- if (session.screensharequality!==false){
- extras += "&q="+session.screensharequality;
- } else if (session.quality){
- extras += "&q="+session.quality;
- } else {
- extras += "&q=0";
- }
-
- if (session.screensharefps!==false){
- extras += "&maxframerate="+session.screensharefps;
- }
-
- if (session.muted){
- iframe.src = "./?audiodevice=1&screenshare&transparent&cleanish&noheader&autostart&view&muted&room=" + session.roomid + "&push=" + iFrameID + extras;
- } else {
- iframe.src = "./?audiodevice=1&screenshare&transparent&cleanish&noheader&autostart&view&room=" + session.roomid + "&push=" + iFrameID + extras;
- }
-
- iframe.style.width = "100%";
- iframe.style.height = "100%";
- iframe.style.overflow = "hidden";
- iframe.id = "screensharesource";
- iframe.style.zIndex = "0";
-
-
- session.screenShareElement = iframe;
- session.screenShareElement.dataset.doNotMove = true;
-
-
- document.getElementById("main").appendChild(iframe);
-
-
- updateMixer();
- getById("screenshare2button").classList.add("float2");
- getById("screenshare2button").classList.remove("float");
-
- return; // ignore the rest.
-}
-
-function previewWebcam() {
-
- if (session.taintedSession === null) {
- log("STILL WAITING ON HASH TO VALIDATE");
- setTimeout(function() {
- previewWebcam();
- }, 1000);
- return;
- } else if (session.taintedSession === true) {
- warnlog("HASH FAILED; PASSWORD NOT VALID");
- return;
- } else {
- log("NOT TAINTED");
- }
-
- if (activatedPreview == true) {
- log("activeated preview return 1");
- return;
- }
- activatedPreview = true;
-
- if (session.audioDevice === 0) { // OFF
- var constraint = {
- audio: false
- };
- } else if ((session.echoCancellation !== false) && (session.autoGainControl !== false) && (session.noiseSuppression !== false)) { // AUTO
- var constraint = {
- audio: true
- };
- } else { // Disable Echo Cancellation and stuff for the PREVIEW (DEFAULT CAM/MIC)
- var constraint = {
- audio: {}
- };
- if (session.echoCancellation !== false) { // if not disabled, we assume it's on
- constraint.audio.echoCancellation = true;
- } else {
- constraint.audio.echoCancellation = false;
- }
- if (session.autoGainControl !== false) {
- constraint.audio.autoGainControl = true;
- } else {
- constraint.audio.autoGainControl = false;
- }
- if (session.noiseSuppression !== false) {
- constraint.audio.noiseSuppression = true;
- } else {
- constraint.audio.noiseSuppression = false;
- }
- }
-
- if (session.videoDevice === 0) {
- constraint.video = false;
- } else {
- constraint.video = true;
- }
-
- if ((constraint.video === false) && (constraint.audio === false)){
-
- if (session.autostart) {
- publishWebcam(); // no need to mirror as there is no video...
- return;
- } else {
- var gowebcam = document.getElementById("gowebcam");
- getById("getPermissions").style.display = "none";
- if (gowebcam) {
- gowebcam.style.display = "";
- gowebcam.disabled = false;
- gowebcam.dataset.ready = "true";
- gowebcam.innerHTML = "START";
- miniTranslate(gowebcam, "start");
- }
- }
- return;
- }
-
- enumerateDevices().then(function(devices) {
- log("enumeratated");
- log(devices);
- var vtrue = false;
- var atrue = false;
- devices.forEach(function(device) {
- if (device.kind === 'audioinput') {
- atrue = true;
- } else if (device.kind === 'videoinput') {
- vtrue = true;
- }
- });
- if (atrue === false) {
- constraint.audio = false;
- }
- if (vtrue === false) {
- constraint.video = false;
- }
- setTimeout(function(constraint) {
- requestBasicPermissions(constraint);
- }, 0, constraint);
- }).catch((error) => {
- log("enumeratated failed. Seeking permissions.");
- setTimeout(function(constraint) {
- requestBasicPermissions(constraint);
- }, 0, constraint);
- });
-
-}
-
-function requestBasicPermissions(constraint = {
- video: true
- , audio: true
-}) {
- if (session.taintedSession === null) {
- log("STILL WAITING ON HASH TO VALIDATE");
- setTimeout(function(constraint) {
- requestBasicPermissions(constraint);
- }, 1000, constraint);
- return;
- } else if (session.taintedSession === true) {
- warnlog("HASH FAILED; PASSWORD NOT VALID");
- return;
- } else {
- log("NOT TAINTED 1");
- }
- setTimeout(function() {
- getById("getPermissions").style.display = "none";
- getById("gowebcam").style.display = "";
- }, 0);
- log("REQUESTING BASIC PERMISSIONS");
-
- try {
- var timerBasicCheck = null;
- if (!(session.cleanOutput)) {
- log("Setting Timer for getUserMedia");
- timerBasicCheck = setTimeout(function() {
- if (!(session.cleanOutput)) {
- warnUser("Camera Access Request Timed Out\nDid you accept camera permissions? Please do so first.\n\nOtherwise, do you have NDI Tools installed? Maybe try uninstalling NDI tools.\n\nPlease also ensure that your camera and audio devices are correctly connected and not already in use. You may also need to refresh the page.");
- }
- }, 10000);
- }
-
- if (session.audioInputChannels) {
- if (constraint.audio === true) {
- constraint.audio = {};
- constraint.audio.channelCount = session.audioInputChannels;
- } else if (constraint.audio) {
- constraint.audio.channelCount = session.audioInputChannels;
- }
- }
-
- log("CONSTRAINT");
- log(constraint);
- navigator.mediaDevices.getUserMedia(constraint).then(function(stream) { // Apple needs thi to happen before I can access EnumerateDevices.
- log("got first stream");
- clearTimeout(timerBasicCheck);
- setupWebcamSelection(stream);
- }).catch(function(err) {
- clearTimeout(timerBasicCheck);
- warnlog("some error with GetUSERMEDIA");
- errorlog(err); /* handle the error */
- if (err.name == "NotFoundError" || err.name == "DevicesNotFoundError") {
- //required track is missing
- } else if (err.name == "NotReadableError" || err.name == "TrackStartError") {
- //webcam or mic are already in use
- } else if (err.name == "OverconstrainedError" || err.name == "ConstraintNotSatisfiedError") {
- //constraints can not be satisfied by avb. devices
- } else if (err.name == "NotAllowedError" || err.name == "PermissionDeniedError") {
- //permission denied in browser
- if (!(session.cleanOutput)) {
- setTimeout(function() {
- warnUser("Permissions denied. Please ensure you have allowed the mic/camera permissions.");
- }, 1);
- }
- return;
- } else if (err.name == "TypeError" || err.name == "TypeError") {
- //empty constraints object
- } else {
- //permission denied in browser
- if (!(session.cleanOutput)) {
- setTimeout(function() {
- warnUser(err);
- }, 1);
- }
- }
- errorlog("trying to list webcam again");
- setupWebcamSelection();
- });
- } catch (e) {
- errorlog(e);
- if (!(session.cleanOutput)) {
- if (window.isSecureContext) {
- warnUser("An error has occured when trying to access the webcam or microphone. The reason is not known.");
- } else if ((iOS) || (iPad)) {
- warnUser("iOS version 13.4 and up is generally recommended; older than iOS 11 is not supported.");
- } else {
- warnUser("Error acessing camera or microphone.\n\nThe website may be loaded in an insecure context.\n\nPlease see: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia");
- }
- }
- }
-}
-
-
-function copyFunction(copyText) {
-
- try {
- copyText.select();
- copyText.setSelectionRange(0, 99999);
- document.execCommand("copy");
- } catch (e) {
- var dummy = document.createElement('input');
- document.body.appendChild(dummy);
- dummy.value = copyText;
- dummy.select();
- document.execCommand('copy');
- document.body.removeChild(dummy);
- return false;
- }
-}
-
-function generateQRPage() {
- var pass = sanitizePassword(getById("invite_password").value);
- if (pass.length) {
- return session.generateHash(pass + session.salt, 4).then(function(hash) {
- generateQRPageCallback(hash);
- });
- } else {
- generateQRPageCallback("");
- }
-}
-
-function updateLinkWebP(arg, input) {
- if (input.checked){
- if (!((getById("director_block_" + arg).dataset.raw.includes("&broadcast")) || (getById("director_block_" + arg).dataset.raw.includes("?broadcast")))){
- getById("broadcastSlider").checked=true;
- updateLink(arg, getById("broadcastSlider"));
- }
- }
- updateLink(arg, input);
-}
-
-function updateLink(arg, input) {
- log(input.dataset.param);
- if (input.checked) {
-
- getById("director_block_" + arg).dataset.raw += input.dataset.param;
-
- var string = getById("director_block_" + arg).dataset.raw;
-
- if (getById("obfuscate_director_" + arg).checked) {
- string = obfuscateURL(string);
- }
-
-
- getById("director_block_" + arg).href = string;
- getById("director_block_" + arg).innerText = string;
- } else {
- var string = getById("director_block_" + arg).dataset.raw + "&";
- string = string.replace(input.dataset.param + "&", "&");
- string = string.substring(0, string.length - 1);
- getById("director_block_" + arg).dataset.raw = string;
-
- if (getById("obfuscate_director_" + arg).checked) {
- string = obfuscateURL(string);
- }
-
- getById("director_block_" + arg).href = string;
- getById("director_block_" + arg).innerText = string;
- }
- saveDirectorSettings();
-}
-
-
-function updateLinkInverse(arg, input) {
- log(input.dataset.param);
- if (!(input.checked)) {
-
- getById("director_block_" + arg).dataset.raw += input.dataset.param;
-
- var string = getById("director_block_" + arg).dataset.raw;
-
- if (getById("obfuscate_director_" + arg).checked) {
- string = obfuscateURL(string);
- }
-
-
- getById("director_block_" + arg).href = string;
- getById("director_block_" + arg).innerText = string;
- } else {
- var string = getById("director_block_" + arg).dataset.raw + "&";
- string = string.replace(input.dataset.param + "&", "&");
- string = string.substring(0, string.length - 1);
- getById("director_block_" + arg).dataset.raw = string;
-
- if (getById("obfuscate_director_" + arg).checked) {
- string = obfuscateURL(string);
- }
-
- getById("director_block_" + arg).href = string;
- getById("director_block_" + arg).innerText = string;
- }
-}
-
-function updateLinkScene(arg, input) {
- var string = getById("director_block_" + arg).dataset.raw;
-
- if (input.checked) {
- string = changeParam(string, "scene", "0");
- } else {
- string = changeParam(string, "scene", "1");
- }
- getById("director_block_" + arg).dataset.raw = string;
-
- if (getById("obfuscate_director_" + arg).checked) {
- string = obfuscateURL(string);
- }
-
- getById("director_block_" + arg).href = string;
- getById("director_block_" + arg).innerText = string;
-}
-
-function resetGen() {
- getById("gencontent").style.display = "block";
- getById("gencontent2").style.display = "none";
- getById("gencontent2").className = ""; //container-inner
- getById("gencontent").className = "container-inner"; //
- getById("gencontent2").innerHTML = "";
- getById("videoname4").focus();
-}
-
-function generateQRPageCallback(hash) {
- try {
- var title = getById("videoname4").value;
- if (title.length) {
- title = title.replace(/[\W]+/g, "_").replace(/_+/g, '_'); // but not what others might get.
- title = "&label=" + title;
- }
- var sid = session.generateStreamID();
-
- var viewstr = "";
- var sendstr = "";
-
- if (getById("invite_bitrate").checked) {
- viewstr += "&bitrate=20000";
- }
- if (getById("invite_vp9").checked) {
- viewstr += "&codec=vp9";
- }
- if (getById("invite_stereo").checked) {
- viewstr += "&stereo";
- sendstr += "&stereo";
- }
- if (getById("invite_automic").checked) {
- sendstr += "&audiodevice=1";
- }
- if (getById("invite_hidescreen").checked) {
- sendstr += "&webcam";
- }
-
- if (getById("invite_remotecontrol").checked) { //
- var remote_gen_id = session.generateStreamID();
- sendstr += "&remote=" + remote_gen_id; // security
- viewstr += "&remote=" + remote_gen_id;
- }
-
- if (getById("invite_joinroom").value.trim().length) {
- sendstr += "&room=" + getById("invite_joinroom").value.trim();
- viewstr += "&scene&room=" + getById("invite_joinroom").value.trim();
- }
-
- if (getById("invite_password").value.trim().length) {
- sendstr += "&hash=" + hash;
- viewstr += "&password=" + getById("invite_password").value.trim();
- }
-
-
- if (getById("invite_group_chat_type").value) { // 0 is default
- if (getById("invite_group_chat_type").value == 1) { // no video
- sendstr += "&novideo";
- } else if (getById("invite_group_chat_type").value == 2) { // no view or audio
- sendstr += "&view";
- }
- }
-
- if (getById("invite_quality").value) {
- if (getById("invite_quality").value == 0) {
- sendstr += "&quality=0";
- } else if (getById("invite_quality").value == 1) {
- sendstr += "&quality=1";
- } else if (getById("invite_quality").value == 2) {
- sendstr += "&quality=2";
- }
- }
-
- var pie = "";
- if (session.pie){
- if (session.pie!==true){
- pie = "&pie="+session.pie;
- }
- }
-
- sendstr = 'https://' + location.host + location.pathname + '?push=' + sid + sendstr + title + pie;
-
- if (getById("invite_obfuscate").checked) {
- sendstr = obfuscateURL(sendstr);
- }
-
- viewstr = 'https://' + location.host + location.pathname + '?view=' + sid + viewstr + title + pie;
- getById("gencontent").style.display = "none";
- getById("gencontent").className = ""; //
- getById("gencontent2").style.display = "block";
- getById("gencontent2").className = "container-inner"; //
- getById("gencontent2").innerHTML = ' \
- and don\'t forget theOBS Browser Source Link: ' + viewstr + ' \
- \
- This invite link and OBS ingestion link are reusable. Only one person may use a specific invite at a time. Create Another Invite Link ';
- var qrcode = new QRCode(getById("qrcode"), {
- width: 300
- , height: 300
- , colorDark: "#000000"
- , colorLight: "#FFFFFF"
- , useSVG: false
- });
- qrcode.makeCode(sendstr);
- setTimeout(function() {
- getById("qrcode").title = "";
- if (getById("qrcode").getElementsByTagName('img').length) {
- getById("qrcode").getElementsByTagName('img')[0].style.cursor = "none";
- }
- }, 100); // i really hate the title overlay that the qrcode function makes
-
- } catch (e) {
- errorlog(e);
- }
-}
-
-
-if (session.view) {
- getById("main").className = "";
- getById("credits").style.display = 'none';
- try {
- if (session.label === false) {
- if (document.title == "") {
- document.title = "View=" + session.view.toString();
- } else {
- document.title += ", View=" + session.view.toString();
- }
- }
- } catch (e) {
- errorlog(e);
- };
-}
-
-
-function initSceneList(UUID){
- Object.keys(session.sceneList).forEach((scene, index) => {
- if (getById("container_" + UUID).querySelectorAll('[data-scene="'+scene+'"]').length){return;} // already exists.
- var newScene = document.createElement("div");
- newScene.innerHTML = ' Scene: '+scene+' ';
- getById("container_" + UUID).appendChild(newScene);
- });
-}
-
-function updateSceneList(scene){
- if (!session.director){return;}
- if (scene in session.sceneList){return;}
- if ((parseInt(scene)+"")===scene){
- if ((parseInt(scene)>=0) && (parseInt(scene)<=8)){
- return;
- }
- }
- session.sceneList[scene] = true;
- for (var UUID in session.rpcs){
- var newScene = document.createElement("span");
- newScene.innerHTML = ' Scene: '+scene+' ';
- getById("container_" + UUID).appendChild(newScene);
- }
-
- if (session.showDirector){
- if (document.getElementById("container_director")){
- var newScene = document.createElement("div");
- newScene.innerHTML = ' Scene: '+scene+' ';
- getById("container_director").appendChild(newScene);
- }
- }
-}
-
-function safariVersion() {
- try {
- var ver = navigator.appVersion.split("Version/");
- if (ver.length > 1) {
- ver = ver[1].split(" Safari");
- }
- if (ver.length > 1) {
- ver = ver[0].split(".");
- }
- if (ver.length > 1) {
- ver = parseInt(ver[0]);
- } else {
- ver = 0;
- }
- } catch (e) {
- return 0;
- }
- return ver;
-}
-
-if ((session.view) && (session.roomid === false)) {
- getById("container-4").className = 'column columnfade';
- getById("container-3").className = 'column columnfade';
- getById("container-2").className = 'column columnfade';
- getById("container-1").className = 'column columnfade';
- //getById("header").className = 'advanced';
- getById("info").className = 'advanced';
- getById("header").className = 'advanced';
- getById("head1").className = 'advanced';
- getById("head2").className = 'advanced';
- getById("head3").className = 'advanced';
-
-
- getById("mainmenu").style.backgroundRepeat = "no-repeat";
- getById("mainmenu").style.backgroundPosition = "bottom center";
- getById("mainmenu").style.minHeight = "300px";
- getById("mainmenu").style.backgroundSize = "100px 100px";
- getById("mainmenu").innerHTML = '';
-
- setTimeout(function() {
- try {
- if ((session.view) && (!(session.cleanOutput))) {
- if (document.getElementById("mainmenu")) {
- getById("mainmenu").style.backgroundImage = "url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8c3ZnIHdpZHRoPSI0MHB4IiBoZWlnaHQ9IjQwcHgiIHZpZXdCb3g9IjAgMCA0MCA0MCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWw6c3BhY2U9InByZXNlcnZlIiBzdHlsZT0iZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjEuNDE0MjE7IiB4PSIwcHgiIHk9IjBweCI+CiAgICA8ZGVmcz4KICAgICAgICA8c3R5bGUgdHlwZT0idGV4dC9jc3MiPjwhW0NEQVRBWwogICAgICAgICAgICBALXdlYmtpdC1rZXlmcmFtZXMgc3BpbiB7CiAgICAgICAgICAgICAgZnJvbSB7CiAgICAgICAgICAgICAgICAtd2Via2l0LXRyYW5zZm9ybTogcm90YXRlKDBkZWcpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHRvIHsKICAgICAgICAgICAgICAgIC13ZWJraXQtdHJhbnNmb3JtOiByb3RhdGUoLTM1OWRlZykKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgQGtleWZyYW1lcyBzcGluIHsKICAgICAgICAgICAgICBmcm9tIHsKICAgICAgICAgICAgICAgIHRyYW5zZm9ybTogcm90YXRlKDBkZWcpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHRvIHsKICAgICAgICAgICAgICAgIHRyYW5zZm9ybTogcm90YXRlKC0zNTlkZWcpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHN2ZyB7CiAgICAgICAgICAgICAgICAtd2Via2l0LXRyYW5zZm9ybS1vcmlnaW46IDUwJSA1MCU7CiAgICAgICAgICAgICAgICAtd2Via2l0LWFuaW1hdGlvbjogc3BpbiAxLjVzIGxpbmVhciBpbmZpbml0ZTsKICAgICAgICAgICAgICAgIC13ZWJraXQtYmFja2ZhY2UtdmlzaWJpbGl0eTogaGlkZGVuOwogICAgICAgICAgICAgICAgYW5pbWF0aW9uOiBzcGluIDEuNXMgbGluZWFyIGluZmluaXRlOwogICAgICAgICAgICB9CiAgICAgICAgXV0+PC9zdHlsZT4KICAgIDwvZGVmcz4KICAgIDxnIGlkPSJvdXRlciI+CiAgICAgICAgPGc+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMCwwQzIyLjIwNTgsMCAyMy45OTM5LDEuNzg4MTMgMjMuOTkzOSwzLjk5MzlDMjMuOTkzOSw2LjE5OTY4IDIyLjIwNTgsNy45ODc4MSAyMCw3Ljk4NzgxQzE3Ljc5NDIsNy45ODc4MSAxNi4wMDYxLDYuMTk5NjggMTYuMDA2MSwzLjk5MzlDMTYuMDA2MSwxLjc4ODEzIDE3Ljc5NDIsMCAyMCwwWiIgc3R5bGU9ImZpbGw6YmxhY2s7Ii8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8cGF0aCBkPSJNNS44NTc4Niw1Ljg1Nzg2QzcuNDE3NTgsNC4yOTgxNSA5Ljk0NjM4LDQuMjk4MTUgMTEuNTA2MSw1Ljg1Nzg2QzEzLjA2NTgsNy40MTc1OCAxMy4wNjU4LDkuOTQ2MzggMTEuNTA2MSwxMS41MDYxQzkuOTQ2MzgsMTMuMDY1OCA3LjQxNzU4LDEzLjA2NTggNS44NTc4NiwxMS41MDYxQzQuMjk4MTUsOS45NDYzOCA0LjI5ODE1LDcuNDE3NTggNS44NTc4Niw1Ljg1Nzg2WiIgc3R5bGU9ImZpbGw6cmdiKDIxMCwyMTAsMjEwKTsiLz4KICAgICAgICA8L2c+CiAgICAgICAgPGc+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMCwzMi4wMTIyQzIyLjIwNTgsMzIuMDEyMiAyMy45OTM5LDMzLjgwMDMgMjMuOTkzOSwzNi4wMDYxQzIzLjk5MzksMzguMjExOSAyMi4yMDU4LDQwIDIwLDQwQzE3Ljc5NDIsNDAgMTYuMDA2MSwzOC4yMTE5IDE2LjAwNjEsMzYuMDA2MUMxNi4wMDYxLDMzLjgwMDMgMTcuNzk0MiwzMi4wMTIyIDIwLDMyLjAxMjJaIiBzdHlsZT0iZmlsbDpyZ2IoMTMwLDEzMCwxMzApOyIvPgogICAgICAgIDwvZz4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggZD0iTTI4LjQ5MzksMjguNDkzOUMzMC4wNTM2LDI2LjkzNDIgMzIuNTgyNCwyNi45MzQyIDM0LjE0MjEsMjguNDkzOUMzNS43MDE5LDMwLjA1MzYgMzUuNzAxOSwzMi41ODI0IDM0LjE0MjEsMzQuMTQyMUMzMi41ODI0LDM1LjcwMTkgMzAuMDUzNiwzNS43MDE5IDI4LjQ5MzksMzQuMTQyMUMyNi45MzQyLDMyLjU4MjQgMjYuOTM0MiwzMC4wNTM2IDI4LjQ5MzksMjguNDkzOVoiIHN0eWxlPSJmaWxsOnJnYigxMDEsMTAxLDEwMSk7Ii8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8cGF0aCBkPSJNMy45OTM5LDE2LjAwNjFDNi4xOTk2OCwxNi4wMDYxIDcuOTg3ODEsMTcuNzk0MiA3Ljk4NzgxLDIwQzcuOTg3ODEsMjIuMjA1OCA2LjE5OTY4LDIzLjk5MzkgMy45OTM5LDIzLjk5MzlDMS43ODgxMywyMy45OTM5IDAsMjIuMjA1OCAwLDIwQzAsMTcuNzk0MiAxLjc4ODEzLDE2LjAwNjEgMy45OTM5LDE2LjAwNjFaIiBzdHlsZT0iZmlsbDpyZ2IoMTg3LDE4NywxODcpOyIvPgogICAgICAgIDwvZz4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggZD0iTTUuODU3ODYsMjguNDkzOUM3LjQxNzU4LDI2LjkzNDIgOS45NDYzOCwyNi45MzQyIDExLjUwNjEsMjguNDkzOUMxMy4wNjU4LDMwLjA1MzYgMTMuMDY1OCwzMi41ODI0IDExLjUwNjEsMzQuMTQyMUM5Ljk0NjM4LDM1LjcwMTkgNy40MTc1OCwzNS43MDE5IDUuODU3ODYsMzQuMTQyMUM0LjI5ODE1LDMyLjU4MjQgNC4yOTgxNSwzMC4wNTM2IDUuODU3ODYsMjguNDkzOVoiIHN0eWxlPSJmaWxsOnJnYigxNjQsMTY0LDE2NCk7Ii8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8cGF0aCBkPSJNMzYuMDA2MSwxNi4wMDYxQzM4LjIxMTksMTYuMDA2MSA0MCwxNy43OTQyIDQwLDIwQzQwLDIyLjIwNTggMzguMjExOSwyMy45OTM5IDM2LjAwNjEsMjMuOTkzOUMzMy44MDAzLDIzLjk5MzkgMzIuMDEyMiwyMi4yMDU4IDMyLjAxMjIsMjBDMzIuMDEyMiwxNy43OTQyIDMzLjgwMDMsMTYuMDA2MSAzNi4wMDYxLDE2LjAwNjFaIiBzdHlsZT0iZmlsbDpyZ2IoNzQsNzQsNzQpOyIvPgogICAgICAgIDwvZz4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggZD0iTTI4LjQ5MzksNS44NTc4NkMzMC4wNTM2LDQuMjk4MTUgMzIuNTgyNCw0LjI5ODE1IDM0LjE0MjEsNS44NTc4NkMzNS43MDE5LDcuNDE3NTggMzUuNzAxOSw5Ljk0NjM4IDM0LjE0MjEsMTEuNTA2MUMzMi41ODI0LDEzLjA2NTggMzAuMDUzNiwxMy4wNjU4IDI4LjQ5MzksMTEuNTA2MUMyNi45MzQyLDkuOTQ2MzggMjYuOTM0Miw3LjQxNzU4IDI4LjQ5MzksNS44NTc4NloiIHN0eWxlPSJmaWxsOnJnYig1MCw1MCw1MCk7Ii8+CiAgICAgICAgPC9nPgogICAgPC9nPgo8L3N2Zz4K')";
- getById("mainmenu").innerHTML = 'Attempting to load video stream. ';
- getById("mainmenu").innerHTML += 'The stream is not available yet or an error occured. Retry Manually ';
-
- }
- }
- } catch (e) {
- errorlog("Error handling QR Code failure");
- }
- }, 15000);
-
- log("auto playing");
- var SafariVer = safariVersion();
- if ((iPad || iOS) && navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1 && SafariVer > 13) { // Modern iOS doesn't need pop up
- play();
- } else if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) { // Safari on Desktop does require pop up
- if (!(session.cleanOutput)) {
- warnUser("Safari requires us to ask for an audio permission to use peer-to-peer technology. You will need to accept it in a moment if asked to view this live video", 20000);
- }
- navigator.mediaDevices.getUserMedia({
- audio: true
- }).then(function() {
- closeModal();
- play();
- }).catch(function() {
- play();
- });
- } else { // everything else is OK.
- play();
- }
-} else if (session.roomid) {
- try {
- if (session.label === false) {
- if (document.title == "") {
- document.title = "Room=" + session.roomid.toString();
- } else {
- document.title += ": " + session.roomid.toString();
- }
- }
- } catch (e) {
- errorlog(e);
- };
-
-}
-
-
-var vis = (function() {
- var stateKey, eventKey, keys = {
- hidden: "visibilitychange"
- , webkitHidden: "webkitvisibilitychange"
- , mozHidden: "mozvisibilitychange"
- , msHidden: "msvisibilitychange"
- };
- for (stateKey in keys) {
- if (stateKey in document) {
- eventKey = keys[stateKey];
- break;
- }
- }
- return function(c) {
- if (c) {
- document.addEventListener(eventKey, c);
- //document.addEventListener("blur", c);
- //document.addEventListener("focus", c);
- }
- return !document[stateKey];
- };
-})();
-
-(function rightclickmenuthing() { // right click menu
- "use strict";
-
- function clickInsideElement(e, className) {
- var el = e.srcElement || e.target;
-
- if (el.classList.contains(className)) {
- return el;
- } else {
- while (el = el.parentNode) {
- if (el.classList && el.classList.contains(className)) {
- return el;
- }
- }
- }
-
- return false;
- }
-
- function getPosition(event2) {
- var posx = 0;
- var posy = 0;
-
- if (!event2) var event = window.event;
-
- if (event2.pageX || event2.pageY) {
- posx = event2.pageX;
- posy = event2.pageY;
- } else if (event2.clientX || event2.clientY) {
- posx = event2.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
- posy = event2.clientY + document.body.scrollTop + document.documentElement.scrollTop;
- }
-
- return {
- x: posx
- , y: posy
- };
- }
- var contextMenuClassName = "context-menu";
- var contextMenuItemClassName = "context-menu__item";
- var contextMenuLinkClassName = "context-menu__link";
- var contextMenuActive = "context-menu--active";
-
- var taskItemClassName = "task";
- var taskItemInContext;
-
- var clickCoords;
- var clickCoordsX;
- var clickCoordsY;
-
- var menu = getById("context-menu");
- var menuItems = menu.querySelectorAll(".context-menu__item");
- var menuState = 0;
- var menuWidth;
- var menuHeight;
- var menuPosition;
- var menuPositionX;
- var menuPositionY;
-
- var windowWidth;
- var windowHeight;
-
- function init() {
- contextListener();
- clickListener();
- keyupListener();
- resizeListener();
- }
-
- function contextListener() {
- document.addEventListener("contextmenu", function(e) {
- taskItemInContext = clickInsideElement(e, taskItemClassName);
-
- if (taskItemInContext) {
- e.preventDefault();
- toggleMenuOn();
- positionMenu(e);
- } else {
- taskItemInContext = null;
- toggleMenuOff();
- }
- });
- }
-
- function clickListener() {
- document.addEventListener("click", function(e) {
- var clickeElIsLink = clickInsideElement(e, contextMenuLinkClassName);
-
- if (clickeElIsLink) {
- e.preventDefault();
- menuItemListener(clickeElIsLink);
- } else {
- var button = e.which || e.button;
- if (button === 1) {
- toggleMenuOff();
- }
- }
- });
- }
-
- function keyupListener() {
- window.onkeyup = function(e) {
- // if ( e.keyCode === 27 ) {
- // toggleMenuOff();
- // }
- if (e.altKey && e.shiftKey && e.keyCode === 67 /* C */) {
- toggleControlBar();
- }
- };
- }
-
- function resizeListener() {
- //window.onresize = function(e) {
- // toggleMenuOff();
- // };
- }
-
- function toggleMenuOn() {
- if (menuState !== 1) {
- menuState = 1;
- menu.classList.add(contextMenuActive);
- }
- }
-
- function toggleMenuOff() {
- if (menuState !== 0) {
- menuState = 0;
- menu.classList.remove(contextMenuActive);
- }
- }
-
- function toggleControlBar() {
- if (getById("controlButtons").style.display != 'none') {
- // Dont hardcode style here. Copy it over to data-style before changing to none;
- getById("controlButtons").dataset.style = getById("controlButtons").style.display;
- getById("controlButtons").style.display = 'none';
- } else {
- // Copy the style over from the data-style attribute.
- getById("controlButtons").style.display = getById("controlButtons").dataset.style;
- };
- }
-
- function positionMenu(e) {
- clickCoords = getPosition(e);
- clickCoordsX = clickCoords.x;
- clickCoordsY = clickCoords.y;
-
- menuWidth = menu.offsetWidth + 4;
- menuHeight = menu.offsetHeight + 4;
-
- windowWidth = window.innerWidth;
- windowHeight = window.innerHeight;
-
- if ((windowWidth - clickCoordsX) < menuWidth) {
- menu.style.left = windowWidth - menuWidth + "px";
- } else {
- menu.style.left = clickCoordsX + "px";
- }
-
- if ((windowHeight - clickCoordsY) < menuHeight) {
- menu.style.top = windowHeight - menuHeight + "px";
- } else {
- menu.style.top = clickCoordsY + "px";
- }
- }
-
- function menuItemListener(link) {
- if (link.getAttribute("data-action") == "Open") {
- window.open(taskItemInContext.value);
- } else {
- // nothing needed
- }
- log("Task ID - " + taskItemInContext + ", Task action - " + link.getAttribute("data-action"));
- toggleMenuOff();
- }
-
- init();
-
-})();
-
-document.addEventListener("dragstart", event => {
- var url = event.target.href || event.target.value;
- if (!url || !url.startsWith('https://')) return;
- if (event.target.dataset.drag != "1") {
- return;
- }
- //event.target.ondragend = function(){event.target.blur();}
-
- var streamId = url.split('view=');
- var label = url.split('label=');
-
- if (session.label !== false) {
- url += '&layer-name=' + session.label;
- } else {
- url += '&layer-name=OBS.Ninja';
- }
- if (streamId.length > 1) url += ': ' + streamId[1].split('&')[0];
- if (label.length > 1) url += ' - ' + decodeURI(label[1].split('&')[0]);
-
- try {
- if (document.getElementById("videosource")) {
- var video = getById('videosource');
- if (typeof(video.videoWidth) == "undefined") {
- url += '&layer-width=1920'; // this isn't always 100% correct, as the resolution can fluxuate, but it is probably good enough
- url += '&layer-height=1080';
- } else if ((parseInt(video.videoWidth) < 360) || (video.videoHeight < 640)) {
- url += '&layer-width=1920'; // this isn't always 100% correct, as the resolution can fluxuate, but it is probably good enough
- url += '&layer-height=1080';
- } else {
- url += '&layer-width=' + video.videoWidth; // this isn't always 100% correct, as the resolution can fluxuate, but it is probably good enough
- url += '&layer-height=' + video.videoHeight;
- }
- } else {
- url += '&layer-width=1920'; // this isn't always 100% correct, as the resolution can fluxuate, but it is probably good enough
- url += '&layer-height=1080';
- }
- } catch (error) {
- url += '&layer-width=1920'; // this isn't always 100% correct, as the resolution can fluxuate, but it is probably good enough
- url += '&layer-height=1080';
- }
-
- event.dataTransfer.setDragImage( getById('dragImage'), 24, 24);
- event.dataTransfer.setData("text/uri-list", encodeURI(url));
- //event.dataTransfer.setData("url", encodeURI(url));
-
-});
-
-function popupMessage(e, message = "Copied to Clipboard") { // right click menu
-
- var posx = 0;
- var posy = 0;
-
- if (!e) var e = window.event;
-
- if (e.pageX || e.pageY) {
- posx = e.pageX;
- posy = e.pageY;
- } else if (e.clientX || e.clientY) {
- posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
- posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
- }
-
- posx += 10;
-
-
- var menu = getById("messagePopup");
- menu.innerHTML = "" + message + " ";
- var menuState = 0;
- var menuWidth;
- var menuHeight;
- var menuPosition;
- var menuPositionX;
- var menuPositionY;
-
- var windowWidth;
- var windowHeight;
-
- if (menuState !== 1) {
- menuState = 1;
- menu.classList.add("context-menu--active");
- }
-
- menuWidth = menu.offsetWidth + 4;
- menuHeight = menu.offsetHeight + 4;
-
- windowWidth = window.innerWidth;
- windowHeight = window.innerHeight;
-
- if ((windowWidth - posx) < menuWidth) {
- menu.style.left = windowWidth - menuWidth + "px";
- } else {
- menu.style.left = posx + "px";
- }
-
- if ((windowHeight - posy) < menuHeight) {
- menu.style.top = windowHeight - menuHeight + "px";
- } else {
- menu.style.top = posy + "px";
- }
-
- function toggleMenuOff() {
- if (menuState !== 0) {
- menuState = 0;
- menu.classList.remove("context-menu--active");
- }
- }
- setTimeout(function() {
- toggleMenuOff();
- }, 1000);
- event.preventDefault();
-}
-
-function timeSince(date) {
-
- var seconds = Math.floor((new Date() - date) / 1000);
-
- var interval = seconds / 31536000;
-
- if (interval > 1) {
- return Math.floor(interval) + " years";
- }
- interval = seconds / 2592000;
- if (interval > 1) {
- return Math.floor(interval) + " months";
- }
- interval = seconds / 86400;
- if (interval > 1) {
- return Math.floor(interval) + " days";
- }
- interval = seconds / 3600;
- if (interval > 1) {
- return Math.floor(interval) + " hours";
- }
- interval = seconds / 60;
- if (interval > 1) {
- return Math.floor(interval) + " minutes";
- }
- return "Seconds ago";
-}
-var chatUpdateTimeout = null;
-var messageList = []
-
-function sendChatMessage(chatMsg = false) { // filtered + visual
- var data = {};
- if (chatMsg === false) {
- var msg = document.getElementById('chatInput').value;
- } else {
- var msg = chatMsg;
- }
- //msg = sanitizeChat(msg);
- if (msg == "") {
- return;
- }
-
- if (msg.trim()==="/list"){
- var listMsg = null;
- for (var UUID in session.rpcs){
- if (session.rpcs[UUID].label){
- listMsg = UUID+": "+session.rpcs[UUID].label
- } else if (session.directorUUID === UUID){
- listMsg = UUID+": Director";
- } else {
- listMsg = UUID+": Unknown User";
- }
- var data = {};
- data.msg = listMsg;
- data.label = false;
- data.type = "alert";
- data.time = Date.now();
- messageList.push(data);
- }
- for (var UUID in session.pcs){
- if (UUID in session.rpcs){continue;}
- if (session.pcs[UUID].label){
- listMsg = UUID+"; "+session.pcs[UUID].label
- } else if (session.directorUUID === UUID){
- listMsg = UUID+"; Director";
- } else {
- listMsg = UUID+"; Unknown User";
- }
- var data = {};
- data.msg = listMsg;
- data.label = false;
- data.type = "alert";
- data.time = Date.now();
- messageList.push(data);
- }
- if (listMsg===null){
- data.msg = "No other users are connected to you";
- data.label = false;
- data.type = "alert";
- data.time = Date.now();
- messageList.push(data);
- }
- } else if (msg.startsWith("\/msg ")){
- var msg = msg.split("\/msg ")[1];
- msg = msg.split(" ");
- uid = msg.shift().toLowerCase();
- msg = msg.join(" ");
- if (msg == ""){return;}
- var sent = false;
- for (var UUID in session.rpcs){
- if (UUID.startsWith(uid)){
- sendChat(msg, UUID); // send message to peers
- var data = {};
- data.time = Date.now();
- data.msg = sanitizeChat(msg); // this is what the other person should see
- data.label = false;
- data.type = "sent";
- messageList.push(data);
- sent=true;
- } else if (session.rpcs[UUID].label && session.rpcs[UUID].label.toLowerCase().startsWith(uid)){
- sendChat(msg, UUID); // send message to peers
- var data = {};
- data.time = Date.now();
- data.msg = sanitizeChat(msg); // this is what the other person should see
- data.label = false;
- data.type = "sent";
- messageList.push(data);
- sent=true;
- } else if ((session.directorUUID === UUID) && "director".startsWith(uid)){
- sendChat(msg, UUID); // send message to peers
- var data = {};
- data.time = Date.now();
- data.msg = sanitizeChat(msg); // this is what the other person should see
- data.label = false;
- data.type = "sent";
- messageList.push(data);
- sent=true;
- }
- }
- for (var UUID in session.pcs){
- if (UUID in session.rpcs){continue;}
- if (UUID.startsWith(uid)){
- sendChat(msg, UUID); // send message to peers
- var data = {};
- data.time = Date.now();
- data.msg = sanitizeChat(msg); // this is what the other person should see
- data.label = false;
- data.type = "sent";
- messageList.push(data);
- sent=true;
- } else if (session.pcs[UUID].label && session.pcs[UUID].label.toLowerCase().startsWith(uid)){
- sendChat(msg, UUID); // send message to peers
- var data = {};
- data.time = Date.now();
- data.msg = sanitizeChat(msg); // this is what the other person should see
- data.label = false;
- data.type = "sent";
- messageList.push(data);
- sent=true;
- } else if ((session.directorUUID === UUID) && "director".startsWith(uid)){
- sendChat(msg, UUID); // send message to peers
- var data = {};
- data.time = Date.now();
- data.msg = sanitizeChat(msg); // this is what the other person should see
- data.label = false;
- data.type = "sent";
- messageList.push(data);
- sent=true;
- }
- }
- if (sent == false){
- var data = {};
- data.msg = "No user found. Message not sent.";
- data.label = false;
- data.type = "alert";
- data.time = Date.now();
- messageList.push(data);
- updateMessages();
- return;
- }
- } else if (msg.startsWith("\/")){
- data.msg = "Unknown command. Try '/list' or '/msg username message'.";
- data.label = false;
- data.type = "alert";
- data.time = Date.now();
- messageList.push(data);
- updateMessages();
- return;
- } else if (session.directorChat===true){
- if (session.directorUUID){
- sendChat(msg, session.directorUUID); // send message to peers
- var data = {};
- data.time = Date.now();
- data.msg = sanitizeChat(msg); // this is what the other person should see
- data.label = false;
- data.type = "sent";
- messageList.push(data);
- }
- } else {
- sendChat(msg); // send message to peers
- data.time = Date.now();
- data.msg = sanitizeChat(msg); // this is what the other person should see
- data.label = false;
- data.type = "sent";
- messageList.push(data);
- }
- document.getElementById('chatInput').value = "";
-
- messageList = messageList.slice(-100);
- if (session.broadcastChannel !== false) {
- log(session.broadcastChannel);
- session.broadcastChannel.postMessage(data);
- }
- updateMessages();
-}
-
-function toggleQualityDirector(bitrate, UUID, ele = null) { // ele is specific to the button in the director's room
- var eles = ele.parentNode.childNodes;
- for (var i=0;i ";
- } else {
- data.label = "" + data.label + ": ";
- }
- label = label+":";
- } else if (director) {
- data.label = "Director: ";
- label = "Director:";
- } else {
- if (session.director){
- data.label = "Someone: ";
- } else {
- data.label = "";
- }
- label = "";
- }
- data.type = "recv";
-
- if (overlay) {
- if (!(session.cleanOutput && session.cleanish==false)){
- var textOverlay = getById("overlayMsgs");
- if (textOverlay) {
- var spanOverlay = document.createElement("span");
- spanOverlay.innerHTML = "" + label + " " + msg + " ";
- textOverlay.appendChild(spanOverlay);
- textOverlay.style.display = "block";
- var showtime = msg.length * 200 + 3000;
- if (showtime > 8000) {
- showtime = 8000;
- }
- setTimeout(function(ele) {
- ele.parentNode.removeChild(ele);
- }, showtime, spanOverlay);
- }
- }
- }
-
- if (isIFrame) {
- parent.postMessage({
- "gotChat": data
- }, "*");
- }
-
- if (session.chatbutton===false){return;} // messages can still appear as overlays ^
-
- messageList.push(data);
- messageList = messageList.slice(-100);
-
- if (session.beepToNotify) {
- playtone();
- }
- updateMessages();
-
- if (session.chat == false) {
- getById("chattoggle").className = "las la-comments my-float toggleSize puslate";
- getById("chatbutton").className = "float";
-
- if (getById("chatNotification").value) {
- getById("chatNotification").value = getById("chatNotification").value + 1;
- } else {
- getById("chatNotification").value = 1;
- }
- getById("chatNotification").classList.add("notification");
-
- }
-
-
- if (session.broadcastChannel !== false) {
- session.broadcastChannel.postMessage(data); /* send */
- }
-
-}
-
-function updateClosedCaptions(msg, label, UUID) {
- msg.counter = parseInt(msg.counter);
- var transcript = sanitizeChat(msg.transcript); // keep it clean.
- if (transcript == "") {
- return;
- }
- transcript = transcript.toUpperCase();
-
- if (label) {
- label = sanitizeLabel(label);
- label = "" + label + ": ";
- } else {
- label = "";
- }
-
- var textOverlay = getById("overlayMsgs");
- if (textOverlay) {
- if (document.getElementById(UUID + "_" + msg.counter)) {
- var spanOverlay = document.getElementById(UUID + "_" + msg.counter);
- } else {
- var spanOverlay = document.createElement("span");
- spanOverlay.id = UUID + "_" + msg.counter;
- textOverlay.appendChild(spanOverlay);
- textOverlay.style.height = "auto";
- textOverlay.style.textAlign = "left";
- textOverlay.style.display = "block";
- textOverlay.style.position = "relative";
- }
- spanOverlay.innerHTML = label + transcript + " ";
-
- spanOverlay.style.fontSize = (parseInt(session.labelsize || 100) / 100.0 * 4.5) + "vh";
- spanOverlay.style.lineHeight = (parseInt(session.labelsize || 100) / 100 * 6) + "vh";
- spanOverlay.style.margin = (parseInt(session.labelsize || 100) / 100.0 * 0.75) + "vh";
-
- if (msg.isFinal) {
- var showtime = 3000;
- clearTimeout(spanOverlay.timeout);
- spanOverlay.timeout = setTimeout(function(ele) {
- ele.parentNode.removeChild(ele);
- }, showtime, spanOverlay);
- } else {
- clearTimeout(spanOverlay.timeout);
- spanOverlay.timeout = setTimeout(function(ele) {
- ele.parentNode.removeChild(ele);
- }, 30000, spanOverlay);
- }
-
- }
-}
-
-function updateMessages() {
- if (session.chatbutton===false){return;}
- document.getElementById("chatBody").innerHTML = "";
- for (i in messageList) {
-
- var time = timeSince(messageList[i].time) || "";
- var msg = document.createElement("div");
- //console.log(messageList[i].msg); // Display received messages for View-Only clients.
- /////////////////////////////
- if (messageList[i].type == "sent") {
- msg.innerHTML = messageList[i].msg + " - " + time + " ";
- msg.classList.add("outMessage");
- } else if (messageList[i].type == "recv") {
- var label = "";
- if (messageList[i].label) {
- label = messageList[i].label;
- }
- msg.innerHTML = label + messageList[i].msg + " - " + time + " ";
- msg.classList.add("inMessage");
- } else if (messageList[i].type == "alert") {
- msg.innerHTML = messageList[i].msg + " - " + time + " ";
- msg.classList.add("inMessage");
- } else {
- msg.innerHTML = messageList[i].msg;
- msg.classList.add("outMessage");
- }
-
- document.getElementById("chatBody").appendChild(msg);
- }
- if (chatUpdateTimeout) {
- clearInterval(chatUpdateTimeout);
- }
- document.getElementById("chatBody").scrollTop = document.getElementById("chatBody").scrollHeight;
- chatUpdateTimeout = setTimeout(function() {
- updateMessages();
- }, 60000);
-}
-
-function EnterButtonChat(event) {
- // Number 13 is the "Enter" key on the keyboard
- var key = event.which || event.keyCode;
- if (key === 13) {
- // Cancel the default action, if needed
- event.preventDefault();
- // Trigger the button element with a click
- sendChatMessage();
- }
-}
-
-function showCustomizer(arg, ele) {
- //getById("directorLinksButton").innerHTML=' LINKS (GUEST INVITES & SCENES) '
- getById("showCustomizerButton1").style.backgroundColor = "";
- getById("showCustomizerButton2").style.backgroundColor = "";
- getById("showCustomizerButton3").style.backgroundColor = "";
- getById("showCustomizerButton4").style.backgroundColor = "";
- getById("showCustomizerButton1").style.boxShadow = "";
- getById("showCustomizerButton2").style.boxShadow = "";
- getById("showCustomizerButton3").style.boxShadow = "";
- getById("showCustomizerButton4").style.boxShadow = "";
-
-
- if (getById("customizeLinks" + arg).style.display != "none") {
- getById("customizeLinks").style.display = "none";
- getById("customizeLinks" + arg).style.display = "none";
- } else {
- //directorLinks").style.display="none";
- getById("showCustomizerButton" + arg).style.backgroundColor = "#1e0000";
- getById("showCustomizerButton" + arg).style.boxShadow = "inset 0px 0px 1px #b90000";
- getById("customizeLinks1").style.display = "none";
- getById("customizeLinks3").style.display = "none";
- getById("customizeLinks").style.display = "block";
- getById("customizeLinks" + arg).style.display = "block";
- }
-}
-
-
-var defaultRecordingBitrate = false;
-
-function recordVideo(target, event, videoKbps = false) { // event.currentTarget,this.parentNode.parentNode.dataset.UUID
-
- var UUID = target.dataset.UUID;
- var video = session.rpcs[UUID].videoElement;
- var audioKbps = false;
-
- if (event === null) {
- if (defaultRecordingBitrate === null) {
- updateLocalRecordButton(UUID, -1);
- //target.style.backgroundColor = null;
- //target.innerHTML = ' record local ';
- return;
- }
- } else if ((event.ctrlKey) || (event.metaKey)) {
- updateLocalRecordButton(UUID, -3);
- //target.innerHTML = ' ARMED ';
- //target.style.backgroundColor = "#BF3F3F";
- Callbacks.push([recordVideo, target, null, false]);
- log("Record Video queued");
- defaultRecordingBitrate = false;
- return;
- } else {
- defaultRecordingBitrate = false;
- }
-
- log("Record Video Clicked");
- if ("recording" in video) {
- log("ALREADY RECORDING!");
- //target.style.backgroundColor = null;
- //target.innerHTML = ' record local ';
- updateLocalRecordButton(UUID, -2);
- video.recorder.stop();
- session.requestRateLimit(35, UUID); // 100kbps
- if (session.audiobitrate===false){
- session.requestAudioRateLimit(-1,UUID);
- }
-
- var elements = document.querySelectorAll('[data-action-type="change-quality2"][data--u-u-i-d="' + UUID + '"]');
- if (elements[0]) {
- elements[0].classList.add("pressed");
- }
- var elements = document.querySelectorAll('[data-action-type="change-quality1"][data--u-u-i-d="' + UUID + '"]');
- if (elements[0]) {
- elements[0].classList.remove("pressed");
- }
- var elements = document.querySelectorAll('[data-action-type="change-quality3"][data--u-u-i-d="' + UUID + '"]');
- if (elements[0]) {
- elements[0].classList.remove("pressed");
- }
- return;
- } else {
- updateLocalRecordButton(UUID, 0);
- //target.style.backgroundColor = "#FCC";
- //target.innerHTML = " Download ";
- video.recording = true;
- }
-
- video.recorder = {};
-
- if (videoKbps == false) {
- if (defaultRecordingBitrate == false) {
- videoKbps = 4000; // 4mbps recording bitrate
- window.focus();
- videoKbps = prompt("Press OK to start recording. Press again to stop and download.\n\nWarning: Keep this browser tab active to continue recording.\n\nYou can change the default video bitrate if desired below (kbps)", videoKbps);
- if (videoKbps === null) {
- //target.style.backgroundColor = null;
- //target.innerHTML = ' record local ';
- updateLocalRecordButton(UUID, -1);
- target.style.backgroundColor = "";
- delete(video.recorder);
- delete(video.recording);
- defaultRecordingBitrate = null;
- return;
- }
- videoKbps = parseInt(videoKbps);
- defaultRecordingBitrate = videoKbps;
- } else {
- videoKbps = defaultRecordingBitrate;
- }
- }
-
- if (videoKbps <= 0) {
- audioKbps = videoKbps * (-1);
- videoKbps = false;
- if (session.audiobitrate===false){
- if ((audioKbps>0) && (audioKbps>=128)){
- session.requestAudioRateLimit(128,UUID); // no point going higher
- } else if (audioKbps==0){
- session.requestAudioRateLimit(256,UUID); // PCM
- } else {
- session.requestAudioRateLimit(parseInt(audioKbps),UUID); // exact? sure. why not.
- }
- }
- } else if (videoKbps < 50) { // this just makes sure you can't set 0 on the record bitrate.
- videoKbps = 50;
- session.requestRateLimit(parseInt(videoKbps * 0.8), UUID); // 3200kbps transfer bitrate. Less than the recording bitrate, to avoid waste.
- } else {
- session.requestRateLimit(parseInt(videoKbps * 0.8), UUID); // 3200kbps transfer bitrate. Less than the recording bitrate, to avoid waste.
-
- if (videoKbps>4000){
- if (session.audiobitrate===false){
- if (session.pcm){
- session.requestAudioRateLimit(256,UUID);
- } else {
- session.requestAudioRateLimit(128,UUID);
- }
- }
- } else if (videoKbps>2500){
- if (session.audiobitrate===false){
- if (session.pcm){
- session.requestAudioRateLimit(256,UUID);
- } else {
- session.requestAudioRateLimit(80,UUID);
- }
- }
- }
-
- }
-
- var timestamp = Date.now();
- var filename = "";
- if (session.rpcs[UUID].label || session.rpcs[UUID].streamID) {
- filename = session.rpcs[UUID].label || session.rpcs[UUID].streamID;
- filename = filename.replace(/[\W]+/g, "_");
- filename = filename.substring(0, 200);
- }
-
- filename += "_" + timestamp.toString();
-
- var cancell = false;
- if (typeof video.srcObject === "undefined" || !video.srcObject) {
- return;
- }
-
- const {readable, writable} = new TransformStream({
- transform: (chunk, ctrl) => chunk.arrayBuffer().then(b => ctrl.enqueue(new Uint8Array(b)))
- });
- readable.pipeTo(streamSaver.createWriteStream(filename + '.webm'));
- var writer = writable.getWriter();
- video.recorder.writer = writer;
- video.recorder.stop = function() {
- if (!video.recording) {
- errorlog("ALREADY STOPPED");
- updateLocalRecordButton(UUID, -1);
- return;
- }
- video.recording = false;
- updateLocalRecordButton(UUID, -2);
- try {
- if (video.recorder.mediaRecorder.state !== "inactive") {
- video.recorder.mediaRecorder.stop();
- }
- } catch (e) {
- errorlog(e);
- }
-
- session.requestRateLimit(35, UUID); // 100kbps
- if (session.audiobitrate===false){
- session.requestAudioRateLimit(-1,UUID);
- }
- var elements = document.querySelectorAll('[data-action-type="change-quality2"][data--u-u-i-d="' + UUID + '"]');
- if (elements[0]) {
- elements[0].classList.add("pressed");
- }
- var elements = document.querySelectorAll('[data-action-type="change-quality1"][data--u-u-i-d="' + UUID + '"]');
- if (elements[0]) {
- elements[0].classList.remove("pressed");
- }
- var elements = document.querySelectorAll('[data-action-type="change-quality3"][data--u-u-i-d="' + UUID + '"]');
- if (elements[0]) {
- elements[0].classList.remove("pressed");
- }
-
- cancell = true;
- // log('Recorded Blobs: ', recordedBlobs);
- // download();
- setTimeout(() => {
- writer.close();
- updateLocalRecordButton(UUID, -1);
- delete(video.recorder);
- delete(video.recording);
- }, 1200);
- };
-
- let options = {};
-
- if (videoKbps) {
- options.mimeType = "video/webm";
- if (session.pcm){
- options.mimeType += ";codecs=pcm";
- }
- if (videoKbps < 1000) {
- options.videoBitsPerSecond = parseInt(videoKbps * 1024); // 100 kbps audio
- } else {
- options.bitsPerSecond = parseInt(videoKbps * 1024); // 100 to 132 kbps audio
- }
- video.recorder.mediaRecorder = new MediaRecorder(video.srcObject, options);
- } else {
- options.mimeType = "audio/webm";
- if (audioKbps == 0) {
- if (MediaRecorder.isTypeSupported("audio/webm;codecs=pcm")) {
- options.mimeType = "audio/webm;codecs=pcm";
- }
- } else {
- options.bitsPerSecond = parseInt(audioKbps * 1024);
- }
- var stream = new MediaStream();
- video.srcObject.getAudioTracks().forEach((track) => {
- stream.addTrack(track, video.srcObject);
- });
- video.recorder.mediaRecorder = new MediaRecorder(stream, options);
- }
- log(options);
-
- function download() {
- const blob = new Blob(recordedBlobs, {
- type: "video/webm"
- });
- const url = window.URL.createObjectURL(blob);
- const a = document.createElement('a');
- a.style.display = 'none';
- a.href = url;
- a.download = filename + ".webm";
- document.body.appendChild(a);
- a.click();
- setTimeout(() => {
- document.body.removeChild(a);
- window.URL.revokeObjectURL(url);
- }, 100);
- }
-
- function handleDataAvailable(event) {
- if (event.data && event.data.size > 0) {
- //recordedBlobs.push(event.data);
- writer.write(event.data); ////////////
- if (video.recording) {
- updateLocalRecordButton(UUID, (parseInt((Date.now() - timestamp) / 1000) || 0));
- }
- }
- }
-
- video.recorder.mediaRecorder.ondataavailable = handleDataAvailable;
-
- video.recorder.mediaRecorder.onerror = function(event) {
- errorlog(event);
- video.recorder.stop();
- session.requestRateLimit(35, UUID);
- if (!(session.cleanOutput)) {
- setTimeout(function() {
- warnUser("an error occured with the media recorder; stopping recording");
- }, 1);
- }
- };
-
- video.srcObject.ended = function(event) {
- video.recorder.stop();
- session.requestRateLimit(35, UUID);
- if (!(session.cleanOutput)) {
- setTimeout(function() {
- warnUser("stream ended! stopping recording");
- }, 1);
- }
- };
-
-
- setTimeout(function(v) {
- v.recorder.mediaRecorder.start(1000);
- }, 500, video); // 100ms chunks
-
- return;
-}
-
-function updateRemoteRecordButton(UUID, recorder) {
- var elements = document.querySelectorAll('[data-action-type="recorder-remote"][data--u-u-i-d="' + UUID + '"]');
- if (elements[0]) {
- var time = parseInt(recorder) || 0;
- if (time == -3) {
- elements[0].classList.remove("pressed");
- elements[0].disabled = true;
- elements[0].innerHTML = ' Not Supported';
- if (!(session.cleanOutput)) {
- setTimeout(function() {
- warnUser('The remote browser does not support recording.\n\nPerhaps try local recording instead.');
- }, 0);
- }
-
- } else if (time == -2) {
- elements[0].classList.add("pressed");
- elements[0].innerHTML = ' stopping...';
- } else if (time == -1) {
- elements[0].classList.remove("pressed");
- elements[0].innerHTML = ' Record Remote ';
- } else {
- var minutes = Math.floor(time / 60);
- var seconds = time - minutes * 60;
- elements[0].classList.add("pressed");
- elements[0].innerHTML = ' ' + minutes + "m : " + (seconds + "").padStart(2, '0') + "s";
- }
- }
-}
-
-function updateLocalRecordButton(UUID, recorder) {
- var elements = document.querySelectorAll('[data-action-type="recorder-local"][data--u-u-i-d="' + UUID + '"]');
- if (elements[0]) {
- var time = parseInt(recorder) || 0;
-
- //target.innerHTML = ' ARMED ';
- //
- if (time == -3) {
- elements[0].classList.add("pressed");
- elements[0].innerHTML = ' ARMED ';
- elements[0].style.backgroundColor = "#BF3F3F";
- } else if (time == -2) {
- elements[0].classList.add("pressed");
- elements[0].innerHTML = ' stopping...';
- elements[0].style.backgroundColor = "";
- } else if (time == -1) {
- elements[0].classList.remove("pressed");
- elements[0].innerHTML = ' Record Local ';
- elements[0].style.backgroundColor = "";
- } else {
- var minutes = Math.floor(time / 60);
- var seconds = time - minutes * 60;
- elements[0].classList.add("pressed");
- elements[0].innerHTML = ' ' + minutes + "m : " + (seconds + "").padStart(2, '0') + "s";
- elements[0].style.backgroundColor = "";
- }
- }
-}
-
-function recordLocalVideoToggle() {
- var ele = getById("recordLocalbutton");
- if (ele.dataset.state == "0") {
- ele.dataset.state = "1";
- ele.style.backgroundColor = "red";
- ele.innerHTML = ' ';
- if ("recording" in session.videoElement) {
-
- } else {
- recordLocalVideo("start");
- }
-
- if (session.director){
- var elements = document.querySelectorAll('[data-action-type="recorder-local"][data-sid="' + session.streamID + '"]');
- if (elements[0]) {
- elements[0].classList.add("pressed");
- elements[0].innerHTML = ' Record ';
- }
- }
-
- } else {
- if ("recording" in session.videoElement) {
- recordLocalVideo("stop");
- }
- ele.dataset.state = "0";
- ele.style.backgroundColor = "";
- ele.innerHTML = ' ';
-
- if (session.director){
- var elements = document.querySelectorAll('[data-action-type="recorder-local"][data-sid="' + session.streamID + '"]');
- if (elements[0]) {
- elements[0].classList.remove("pressed");
- elements[0].innerHTML = ' Record ';
- }
- }
- }
-
-}
-
-function setupSensorData(pollrate = 30) {
- session.sensors = {};
- session.sensors.data = {};
- session.sensors.data.sensors = true;
-
- if (window.Accelerometer) {
- session.sensors.data.acc = {};
- session.sensors.Accelerometer = new Accelerometer({
- frequency: pollrate
- });
- session.sensors.Accelerometer.addEventListener('reading', e => {
- session.sensors.data.acc.x = session.sensors.Accelerometer.x;
- session.sensors.data.acc.y = session.sensors.Accelerometer.y;
- session.sensors.data.acc.z = session.sensors.Accelerometer.z;
- session.sensors.data.acc.t = parseInt(Math.round(session.sensors.Accelerometer.timestamp));
- });
- session.sensors.Accelerometer.start();
- }
- if (window.Gyroscope) {
- session.sensors.data.gyro = {};
- session.sensors.Gyroscope = new Gyroscope({
- frequency: pollrate
- });
- session.sensors.Gyroscope.addEventListener('reading', e => {
- session.sensors.data.gyro.x = session.sensors.Gyroscope.x;
- session.sensors.data.gyro.y = session.sensors.Gyroscope.y;
- session.sensors.data.gyro.z = session.sensors.Gyroscope.z;
- session.sensors.data.gyro.t = parseInt(Math.round(session.sensors.Gyroscope.timestamp));
- });
- session.sensors.Gyroscope.start();
- }
- if (window.Magnetometer) {
- session.sensors.data.mag = {};
- session.sensors.Magnetometer = new Magnetometer({
- frequency: pollrate
- });
- session.sensors.Magnetometer.addEventListener('reading', e => {
- session.sensors.data.mag.x = session.sensors.Magnetometer.x;
- session.sensors.data.mag.y = session.sensors.Magnetometer.y;
- session.sensors.data.mag.z = session.sensors.Magnetometer.z;
- session.sensors.data.mag.t = parseInt(Math.round(session.sensors.Magnetometer.timestamp));
-
- });
- session.sensors.Magnetometer.start();
- }
- if (window.LinearAccelerationSensor) {
- session.sensors.data.lin = {};
- session.sensors.LinearAccelerationSensor = new LinearAccelerationSensor({
- frequency: pollrate
- });
- session.sensors.LinearAccelerationSensor.addEventListener('reading', e => {
- session.sensors.data.lin.x = session.sensors.LinearAccelerationSensor.x;
- session.sensors.data.lin.y = session.sensors.LinearAccelerationSensor.y;
- session.sensors.data.lin.z = session.sensors.LinearAccelerationSensor.z;
- session.sensors.data.lin.t = parseInt(Math.round(session.sensors.LinearAccelerationSensor.timestamp));
- });
- session.sensors.LinearAccelerationSensor.start();
- }
- setInterval(function() {
- firehoseSensorData();
- }, parseInt(1000 / pollrate));
-}
-
-
-function firehoseSensorData() {
- session.sendMessage(session.sensors.data);
-}
-if (session.sensorData) {
- setupSensorData(parseInt(session.sensorData));
-}
-
-async function chunkedVideoTransfer(videoKbps = 500) {
-
- var video = session.videoElement;
- var recorder = {};
-
- var options = {};
- options.mimeType = "video/webm";
- if (videoKbps < 1000) {
- options.videoBitsPerSecond = parseInt(videoKbps * 1024); // 100 kbps audio
- } else {
- options.bitsPerSecond = parseInt(videoKbps * 1024); // 100 to 132 kbps audio
- }
-
- recorder.mediaRecorder = new MediaRecorder(video.srcObject, options);
-
- async function handleDataAvailable(event) {
- if (event.data && event.data.size > 0) {
- try{
- recorder.mediaRecorder.stop();
- setTimeout(function(){recorder.mediaRecorder.start(500);},500);
- } catch(e){
- return;
- }
-
- const arrayBuffer = await event.data.arrayBuffer();
- for (var i in session.pcs){
- session.pcs[i].sendChannel.send(arrayBuffer);
-
- }
- }
-
- }
-
- recorder.mediaRecorder.ondataavailable = handleDataAvailable;
-
- recorder.mediaRecorder.onerror = function(event) {
- errorlog(event);
- };
-
- video.srcObject.ended = function(event) {
- errorlog(event);
- };
-
- recorder.mediaRecorder.start(500); // 100ms chunks
-
-}
-
-function recordLocalVideo(action = null, videoKbps = 6000) { // event.currentTarget,this.parentNode.parentNode.dataset.UUID
- var audioKbps = false;
- var video = session.videoElement;
- if ("recording" in video) {
- if (action == "stop") {
- log("Stopping RECORDING!");
- video.recorder.stop();
- delete(video.recorder);
- delete(video.recording);
- return;
- } else if (action == "start") {
- log("ALREADY RECORDING!");
- getById("recordLocalbutton").dataset.state = "1";
- getById("recordLocalbutton").style.backgroundColor = "red";
- getById("recordLocalbutton").innerHTML = ' ';
- return;
- } else {
- log("STOPPING RECORDING by default toggle!");
- video.recorder.stop();
- return;
- }
- return;
- } else if (action == "start") {
- if (safariVersion()) {
- var msg = {};
- msg.UUID = session.directorUUID;
- msg.recorder = -3;
- session.sendMessage(msg, msg.UUID);
- return;
- }
- video.recording = true;
- getById("recordLocalbutton").dataset.state = "1";
- getById("recordLocalbutton").style.backgroundColor = "red";
- getById("recordLocalbutton").innerHTML = ' ';
- } else if (action == "stop") {
- return;
- } else {
- getById("recordLocalbutton").dataset.state = "1";
- getById("recordLocalbutton").style.backgroundColor = "red";
- getById("recordLocalbutton").innerHTML = ' ';
- video.recording = true;
- }
-
- video.recorder = {};
-
- if (session.recordLocal !== false) {
- videoKbps = session.recordLocal;
- }
-
- if (videoKbps <= 0) {
- audioKbps = videoKbps * (-1);
- videoKbps = false;
- } else if (videoKbps < 50) { // this just makes sure you can't set 0 on the record bitrate.
- videoKbps = 50;
- }
-
- if (typeof video.srcObject === "undefined" || !video.srcObject) {
- return;
- }
-
- const {readable, writable} = new TransformStream({
- transform: (chunk, ctrl) => chunk.arrayBuffer().then(b => ctrl.enqueue(new Uint8Array(b)))
- });
-
- var timestamp = Date.now();
- var filename = "";
- if (session.label || session.streamID) {
- filename = session.label || session.streamID;
- filename = filename.replace(/[\W]+/g, "_");
- filename = filename.substring(0, 200);
- }
-
- filename += "_" + timestamp.toString();
- readable.pipeTo(streamSaver.createWriteStream(filename.toString() + '.webm'));
-
- var writer = writable.getWriter();
- video.recorder.writer = writer;
- pokeIframeAPI("recording-started");
-
- video.recorder.stop = function(restart = false) {
- if (restart) {
- if (getById("recordLocalbutton").dataset.state == 2) {
- getById("recordLocalbutton").dataset.state = "0";
- getById("recordLocalbutton").style.backgroundColor = "";
- getById("recordLocalbutton").innerHTML = ' ';
- restart = false;
- warnUser("Media Recording Stopped due to an error.");
- } else {
- getById("recordLocalbutton").innerHTML = ' ';
- getById("recordLocalbutton").dataset.state = "2";
- }
- } else {
- getById("recordLocalbutton").dataset.state = "0";
- getById("recordLocalbutton").style.backgroundColor = "";
- getById("recordLocalbutton").innerHTML = ' ';
- }
- if (!video.recording) {
- errorlog("ALREADY STOPPED");
- return;
- }
- video.recording = false;
- try {
- if (video.recorder.mediaRecorder.state !== "inactive") {
- video.recorder.mediaRecorder.stop();
- }
- } catch (e) {
- errorlog(e);
- }
-
- setTimeout(() => {
- writer.close();
- pokeIframeAPI("recording-stopped");
- try {
- if (session.directorUUID) {
- var msg = {};
- msg.UUID = session.directorUUID;
- msg.recorder = -1;
- session.sendMessage(msg, msg.UUID);
- }
- } catch (e) {
- errorlog(e);
- }
- delete(video.recorder);
- delete(video.recording);
-
- if (restart) {
- setTimeout(function() {
- recordLocalVideo("start", videoKbps);
- }, 0);
- }
-
- }, 500);
- try {
- if (session.directorUUID) {
- var msg = {};
- msg.UUID = session.directorUUID;
- msg.recorder = -2;
- session.sendMessage(msg, msg.UUID);
- }
- } catch (e) {
- errorlog(e);
- }
-
- };
-
- let options = {};
-
- if (videoKbps) {
- options.mimeType = "video/webm";
- if (session.pcm){
- options.mimeType += ";codecs=pcm";
- }
- if (videoKbps < 1000) {
- options.videoBitsPerSecond = parseInt(videoKbps * 1024); // 100 kbps audio
- } else {
- options.bitsPerSecond = parseInt(videoKbps * 1024); // 100 to 132 kbps audio
- }
- video.recorder.mediaRecorder = new MediaRecorder(video.srcObject, options);
- } else {
- options.mimeType = "audio/webm";
- if (audioKbps == 0) {
- if (MediaRecorder.isTypeSupported("audio/webm;codecs=pcm")) {
- options.mimeType = "audio/webm;codecs=pcm";
- }
- } else {
- options.bitsPerSecond = parseInt(audioKbps * 1024);
- }
- var stream = new MediaStream();
- video.srcObject.getAudioTracks().forEach((track) => {
- stream.addTrack(track, video.srcObject);
- });
- video.recorder.mediaRecorder = new MediaRecorder(stream, options);
- }
- log(options);
-
- function handleDataAvailable(event) {
- if (event.data && event.data.size > 0) {
- writer.write(event.data);
- if (session.directorUUID) {
- if (video.recording) {
- var msg = {};
- msg.UUID = session.directorUUID;
- msg.recorder = parseInt((Date.now() - timestamp) / 1000) || 0;
- session.sendMessage(msg, msg.UUID);
- }
- }
- }
- }
-
- video.recorder.mediaRecorder.ondataavailable = handleDataAvailable;
-
- video.recorder.mediaRecorder.onerror = function(event) {
- errorlog(event);
- video.recorder.stop(true);
- };
-
- video.srcObject.ended = function(event) {
- video.recorder.stop();
- };
-
- video.recorder.mediaRecorder.start(1000); // 100ms chunks
-
- if (session.directorUUID) {
- var msg = {};
- msg.UUID = session.directorUUID;
- msg.recorder = 0;
- session.sendMessage(msg, msg.UUID);
- }
- return;
-}
-
-
-function changeAudioOutputDevice(ele) {
- if (session.sink){
- if ((iOS) || (iPad)){return;} // iOS devices do not support this.
-
- if (typeof ele.sinkId !== 'undefined'){
- navigator.mediaDevices.getUserMedia({audio:true,video:false}).then(function (stream){
- ele.setSinkId(session.sink).then(() => {
- log("New Output Device:"+session.sink);
- }).catch(errorlog);
- stream.getTracks().forEach(track => {
- track.stop();
- });
- }).catch(function canplayspecificaudio(){errorlog("Can't play out to specific audio device without mic permissions allowed");});
- } else {
- warnlog("Your browser does not support alternative audio sources.");
- }
- }
-}
-
-function addAudioPipeline(stream, 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.
- }
- var trackid = track.id;
- session.rpcs[UUID].inboundAudioPipeline[trackid] = {};
-
- session.rpcs[UUID].inboundAudioPipeline[trackid].mediaStream = new MediaStream();
- session.rpcs[UUID].inboundAudioPipeline[trackid].mediaStream.addTrack(track);
- session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio = new Audio();
- session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio.muted = true;
- session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio.srcObject = session.rpcs[UUID].inboundAudioPipeline[trackid].mediaStream; // needs to be added as an streamed element to be usable, even if its hidden
-
- session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio.play().then(_ => {
- log("playing");
- }).catch(warnlog);
-
- // https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/createMediaStreamTrackSource
- source = session.audioCtx.createMediaStreamSource(session.rpcs[UUID].inboundAudioPipeline[trackid].mediaStream);
-
- //////////////////
-
- var screwedUp = false;
- session.rpcs[UUID].inboundAudioPipeline[trackid].destination = false;
- if (session.sync!==false){
- log("adding a delay node to audio");
- source = addDelayNode( source, UUID, trackid);
- screwedUp = true;
- }
-
- if (session.style===2){
- log("adding a fftwave node to audio");
- source = fftWaveform( source, UUID, trackid);
- } else if (session.style===3){
- log("adding a loudness meter node to audio");
- source = audioMeterGuest(source, UUID, trackid);
- } else if (session.audioMeterGuest){
- log("adding a loudness meter node to audio");
- source = audioMeterGuest(source, UUID, trackid);
- } else if (session.activeSpeaker){
- log("adding a loudness meter node to audio");
- source = audioMeterGuest(source, UUID, trackid);
- }
-
- if (session.rpcs[UUID].channelOffset !== false){
- log("custom offset set");
- session.rpcs[UUID].inboundAudioPipeline[trackid].destination = session.audioCtx.createMediaStreamDestination();
- source = offsetChannel( session.rpcs[UUID].inboundAudioPipeline[trackid].destination, source, session.rpcs[UUID].channelOffset);
- screwedUp = true;
- } else if (session.offsetChannel !== false){ // proably better to do this last.
- log("adding offset channels");
- session.rpcs[UUID].inboundAudioPipeline[trackid].destination = session.audioCtx.createMediaStreamDestination();
- source = offsetChannel( session.rpcs[UUID].inboundAudioPipeline[trackid].destination, source, session.offsetChannel);
- 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){
- session.rpcs[UUID].inboundAudioPipeline[trackid].destination.stream.addTrack(trk);
- log("secondary stream added");
- log(trk);
- }
- });
-
- return session.rpcs[UUID].inboundAudioPipeline[trackid].destination.stream;
- }
- return stream;
- } catch(e) {errorlog(e);}
- return stream;
-}
-
-function changeChannelOffset(UUID, channel){
-
-
- var ele = document.querySelectorAll('[data-action-type="add-channel"][data--u-u-i-d="' + UUID + '"]');
- for (var i=0;i ((val-128.0)*(val-128.0)));
- var Sum = Squares.reduce((acum, val) => (acum + val));
- var Mean = Sum/loudness.length;
- loudness = Math.sqrt(Mean)*10;
- session.rpcs[uuid].stats.Audio_Loudness = parseInt(loudness);
-
- if (session.pushLoudness==true){
- var loudnessObj = {};
- loudnessObj[session.rpcs[uuid].streamID] = session.rpcs[uuid].stats.Audio_Loudness;
-
- if (isIFrame){
- parent.postMessage({"loudness": loudnessObj, "action":"loudness", "value":loudness, "UUID":uuid}, "*");
- }
- }
-
- if (loudness<2){return;}
-
- //log(bufferLength);
- session.rpcs[uuid].canvasCtx.beginPath();
- var m = session.rpcs[uuid].canvas.height / 256.0;
- session.rpcs[uuid].canvasCtx.moveTo(0, dataArray[0]*m);
- for (var i = 1; i < bufferLength; i++){
- var y = dataArray[i] * m;
- session.rpcs[uuid].canvasCtx.lineTo(x, y);
- x += sliceWidth;
- }
- session.rpcs[uuid].canvasCtx.lineTo(session.rpcs[uuid].canvas.width, session.rpcs[uuid].canvas.height / 2);
- session.rpcs[uuid].canvasCtx.stroke();
- } catch(e){
- warnlog(e);
- warnlog("Did the remote source disconnect?");
- clearInterval(fftInterval);
- warnlog(session.rpcs[uuid]);
- }
- },50, UUID);
- return session.rpcs[UUID].inboundAudioPipeline[trackid].analyser;
-}
-
-function audioMeterGuest(mediaStreamSource, UUID, trackid){
- log("audioMeterGuest started");
- session.rpcs[UUID].inboundAudioPipeline[trackid].analyser = session.audioCtx.createAnalyser();
- mediaStreamSource.connect(session.rpcs[UUID].inboundAudioPipeline[trackid].analyser);
- session.rpcs[UUID].inboundAudioPipeline[trackid].analyser.fftSize = 256;
- session.rpcs[UUID].inboundAudioPipeline[trackid].analyser.smoothingTimeConstant = 0.05;
-
- var bufferLength = session.rpcs[UUID].inboundAudioPipeline[trackid].analyser.frequencyBinCount;
- var dataArray = new Uint8Array(bufferLength);
-
- function updateLevels() {
- if (!(UUID in session.rpcs)){return;}
- try {
- session.rpcs[UUID].inboundAudioPipeline[trackid].analyser.getByteFrequencyData(dataArray);
- var total = 0;
- for (var i = 0; i < dataArray.length; i++){
- total += dataArray[i];
- }
- total = total/100;
- session.rpcs[UUID].stats.Audio_Loudness = parseInt(total);
-
- if (session.pushLoudness==true){
- var loudnessObj = {};
- loudnessObj[session.rpcs[UUID].streamID] = session.rpcs[UUID].stats.Audio_Loudness;
-
- if (isIFrame){
- parent.postMessage({"loudness": loudnessObj, "action":"loudness", "value":session.rpcs[UUID].stats.Audio_Loudness, "UUID":UUID}, "*");
- }
- }
-
- try{
- clearTimeout(session.rpcs[UUID].inboundAudioPipeline[trackid].analyser.interval);
- session.rpcs[UUID].inboundAudioPipeline[trackid].analyser.interval = setTimeout(function(){updateLevels();},100);
- } catch(e){
- log("closing old inaudio pipeline");
- }
-
- if (session.scene!==false){return;} // don't show if a scene
- if (session.audioMeterGuest===false){return;} // don't show if we just want the volume levels
-
- if (session.rpcs[UUID].voiceMeter){
- session.rpcs[UUID].voiceMeter.dataset.level = total;
- if (session.meterStyle==1){
- session.rpcs[UUID].voiceMeter.style.height = Math.min(total,100) + "%";
- if (total>75){
- total = Math.min(100,(total - 75)*4);
- var R = parseInt((255 * total) / 100).toString(16).padStart(2, '0');
- var G = parseInt(255 * (100 - total) / 100).toString(16).padStart(2, '0');
- session.rpcs[UUID].voiceMeter.style.backgroundColor = "#" + R + G + "00";
- } else {
- session.rpcs[UUID].voiceMeter.style.backgroundColor = "#00FF00";
- }
- } else {
- if (total>15){
- session.rpcs[UUID].voiceMeter.style.opacity = 100; // temporary
- } else {
- session.rpcs[UUID].voiceMeter.style.opacity = 0; // temporary
- }
- }
-
- } else {
- if (session.meterStyle==1){
- session.rpcs[UUID].voiceMeter = getById("voiceMeterTemplate2").cloneNode(true);
- } else {
- session.rpcs[UUID].voiceMeter = getById("voiceMeterTemplate").cloneNode(true);
- if (total>15){
- session.rpcs[UUID].voiceMeter.style.opacity = 100; // temporary
- } else {
- session.rpcs[UUID].voiceMeter.style.opacity = 0; // temporary
- }
- }
- session.rpcs[UUID].voiceMeter.id = "voiceMeter_"+UUID;
- session.rpcs[UUID].voiceMeter.dataset.level = total;
- updateMixer();
- }
-
- } catch(e){
- warnlog(e);
- return;
- }
- };
- clearTimeout(session.rpcs[UUID].inboundAudioPipeline[trackid].analyser.interval);
- session.rpcs[UUID].inboundAudioPipeline[trackid].analyser.interval = setTimeout(function(){updateLevels();},100);
- return session.rpcs[UUID].inboundAudioPipeline[trackid].analyser;
-}
-
-function effectsDynamicallyUpdate(event, ele, preview=true){
-
- var effect = ele.options[ele.selectedIndex].value;
- getById("selectImageTFLITE").style.display = "none";
- if (effect === "0"){
- session.effects = 0;
- activatedPreview=false;
- if (preview){
- grabVideo();
- } else {
- grabVideo(session.quality, "videosource", "select#videoSource3");
- }
- if (ele.id == "effectSelector"){
- getById("selectImageTFLITE").style.display = "none";
- } else {
- getById("selectImageTFLITE3").style.display = "none";
- }
- return;
- } else if (effect === "3"){
- if ((session.effects<3) || (session.effects>5)){
- session.effects = 3;
- activatedPreview=false;
- if (preview){
- grabVideo();
- } else {
- grabVideo(session.quality, "videosource", "select#videoSource3");
- }
- } else {
- session.effects = 3;
- }
- } else if (effect === "4"){
- if ((session.effects<3) || (session.effects>5)){
- session.effects = 4;
- activatedPreview=false;
- if (preview){
- grabVideo();
- } else {
- grabVideo(session.quality, "videosource", "select#videoSource3");
- }
- } else {
- session.effects = 4;
- }
- } else if (effect === "5"){
- if (session.tfliteModule.img){
- session.tfliteModule.img.src = "./media/bg_sample.webp";
- }
- if ((session.effects<3) || (session.effects>5)){
- session.effects = 5;
- activatedPreview=false;
- if (preview){
- grabVideo();
- } else {
- grabVideo(session.quality, "videosource", "select#videoSource3");
- }
- } else {
- session.effects = 5;
- }
- if (ele.id == "effectSelector"){
- getById("selectImageTFLITE").style.display = "block";
- } else {
- getById("selectImageTFLITE3").style.display = "block";
- }
- } else if (effect === "6"){
- session.effects = 6;
- activatedPreview=false;
- if (preview){
- grabVideo();
- } else {
- grabVideo(session.quality, "videosource", "select#videoSource3");
- }
- }
-
- if (session.effects !== 5){
- if (ele.id == "effectSelector"){
- getById("selectImageTFLITE").style.display = "none";
- } else {
- getById("selectImageTFLITE3").style.display = "none";
- }
- }
-
- if (session.tfliteModule===false){
- attemptTFLiteJsFileLoad();
- }
-}
-var TFLITELOADING = false;
-function attemptTFLiteJsFileLoad(){
- if (session.tfliteModule!==false){
- return true;
- }
- TFLITELOADING=true;
- session.tfliteModule={};
-
- if (!document.getElementById("tflitesimdjs")){
- var tmpScript = document.createElement('script');
- tmpScript.onload = loadTFLiteModel;
- tmpScript.type = 'text/javascript';
- tmpScript.src = "./thirdparty/tflite/tflite-simd.js?ver=2";
- tmpScript.id = "tflitesimdjs";
- document.head.appendChild(tmpScript);
- }
-
- return false;
-}
-async function changeTFLiteImage(ev, ele){
-
- if (ele.files && ele.files[0]) {
- session.tfliteModule.img = document.querySelector('img');
- session.tfliteModule.img.ready=false;
- session.tfliteModule.img.onload = () => {
- URL.revokeObjectURL(session.tfliteModule.img.src); // no longer needed, free memory
- session.tfliteModule.img.ready=true;
- }
- session.tfliteModule.img.src = URL.createObjectURL(ele.files[0]); // set src to blob url
- } else if (ele.tagName.toLowerCase() == "img"){
- session.tfliteModule.img = ele
- session.tfliteModule.img.ready=true;
- }
-}
-
-
-async function loadTFLiteModel(){
- try{
- if (session.tfliteModule && (session.tfliteModule.img)){
- var img = session.tfliteModule.img;
- session.tfliteModule = await createTFLiteSIMDModule();
- session.tfliteModule.img = img;
- } else {
- session.tfliteModule = {};
- session.tfliteModule = await createTFLiteSIMDModule();
- }
- if (!session.tfliteModule.simd){
- var elements = document.querySelectorAll('[data-warnSimdNotice]')
- for (let i = 0; i < elements.length; i++) {
- elements[i].style.display = "inline-block";
- }
- }
- } catch(e){
- warnlog("TF-LITE FAILED TO LOAD");
- return;
- }
- const modelResponse = await fetch("./thirdparty/tflite/segm_full_v679.tflite");
- session.tfliteModule.model = await modelResponse.arrayBuffer();
- console.log('Model buffer size:', session.tfliteModule.model.byteLength);
- session.tfliteModule.HEAPU8.set(new Uint8Array(session.tfliteModule.model), session.tfliteModule._getModelBufferMemoryOffset());
- session.tfliteModule._loadModel(session.tfliteModule.model.byteLength);
- session.tfliteModule.activelyProcessing = false;
- TFLITELOADING = false;
- if ((session.effects>=3) && (session.effects<=5)){
- if (document.getElementById("videosource")){
- activatedPreview=false;
- grabVideo(session.quality, "videosource", "select#videoSource3");
- }
- }
- if (LaunchTFWorkerCallback){TFLiteWorker();}
-}
-
-
-if ((session.effects==3) || (session.effects==4) || (session.effects==5)){
- attemptTFLiteJsFileLoad();
-} else if (session.effects==6){
- var script = document.createElement('script');
- var script2 = document.createElement('script');
- var script3 = document.createElement('script');
- var script4 = document.createElement('script');
- var model = false;
- script.onload = function() {
- document.head.appendChild(script2);
- }
- script2.onload = function() {
- document.head.appendChild(script3);
- }
- script3.onload = function() {
- document.head.appendChild(script4);
- }
- script4.onload = function() {
- async function loadModel(){
- model = await faceLandmarksDetection.load(faceLandmarksDetection.SupportedPackages.mediapipeFacemesh);
-
- }
- loadModel();
- }
- script.src = "https://unpkg.com/@tensorflow/tfjs-core@2.4.0/dist/tf-core.js";
- script2.src = "https://unpkg.com/@tensorflow/tfjs-converter@2.4.0/dist/tf-converter.js";
- script3.src = "https://unpkg.com/@tensorflow/tfjs-backend-webgl@2.4.0/dist/tf-backend-webgl.js";
- script4.src = "https://unpkg.com/@tensorflow-models/face-landmarks-detection@0.0.1/dist/face-landmarks-detection.js";
-
- script.type = 'text/javascript';script2.type = 'text/javascript';script3.type = 'text/javascript';script4.type = 'text/javascript';
- document.head.appendChild(script);
-}
-
-
-
-if (session.midiHotkeys || session.midiOut!==false) {
-
- var script = document.createElement('script');
- script.onload = function() {
- WebMidi.enable(function(err) { // hotkeys
-
- if (err) {
- errorlog(err);
- }
-
- WebMidi.addListener("connected", function(e) {
- log(e);
- });
-
- WebMidi.addListener("disconnected", function(e) {
- log(e);
- });
-
- console.log(WebMidi.inputs);
-
- if (session.midiOut===true){
- for (var i = 0; i < WebMidi.inputs.length; i++) {
- var input = WebMidi.inputs[i];
-
- input.addListener("midimessage", "all", function(e) {
- log(e);
- var msg = {};
- msg.midi = {};
- msg.midi.d = e.data;
- msg.midi.s = e.timestamp;
- msg.midi.t = e.type;
-
- for (var UUID in session.pcs){
- if (session.pcs[UUID].allowMIDI){
- session.sendMessage(msg, UUID);
- }
- }
- });
- }
- } else if (session.midiOut==parseInt(session.midiOut)){
- try{
- var input = WebMidi.inputs[parseInt(session.midiOut)];
- input.addListener("midimessage", "all", function(e) {
- log(e);
- var msg = {};
- msg.midi = {};
- msg.midi.d = e.data;
- msg.midi.s = e.timestamp;
- msg.midi.t = e.type;
-
- for (var UUID in session.pcs){
- if (session.pcs[UUID].allowMIDI){
- session.sendMessage(msg, UUID);
- }
- }
- });
- } catch(e){errorlog(e);};
- }
-
- for (var i = 0; i < WebMidi.inputs.length; i++) {
- var input = WebMidi.inputs[i];
- input.addListener('noteon', "all", function(e) {
- log(e);
- if (session.midiHotkeys==1){
- log(e);
- var note = e.note.name + e.note.octave;
- if (note == "G3") { // open and close the chat window
- toggleChat();
- } else if (note == "A3") { // mute your audio output
- toggleMute();
- } else if (note == "B3") { // mute your video output
- toggleVideoMute();
- } else if (note == "C4") { // enable / disable screenshare
- toggleScreenShare();
- } else if (note == "D4") { // completely kill your connection/session
- hangup();
- } else if (note == "E4") { // raise your hand; director sees this
- raisehand();
- } else if (note == "F4") { // start/stop local recording
- recordLocalVideoToggle();
- } else if (note == "G4") { // Director Enables their Audio output
- press2talk(true);
- } else if (note == "A4") { // Director cut's their audio/video output
- hangup2();
- }
- } else if (session.midiHotkeys==2){
- log(e);
- var note = e.note.name + e.note.octave;
- if (note == "G1") { // open and close the chat window
- toggleChat();
- } else if (note == "A1") { // mute your audio output
- toggleMute();
- } else if (note == "B1") { // mute your video output
- toggleVideoMute();
- } else if (note == "C2") { // enable / disable screenshare
- toggleScreenShare();
- } else if (note == "D2") { // completely kill your connection/session
- hangup();
- } else if (note == "E2") { // raise your hand; director sees this
- raisehand();
- } else if (note == "F2") { // start/stop local recording
- recordLocalVideoToggle();
- } else if (note == "G2") { // Director Enables their Audio output
- press2talk(true);
- } else if (note == "A2") { // Director cut's their audio/video output
- hangup2();
- }
- } else if (session.midiHotkeys==3){
- log(e);
- var note = e.note.name + e.note.octave;
- var velocity = e.velocity;
- if (note == "C1"){
- if (velocity == "0") { // open and close the chat window
- toggleChat();
- } else if (note == "1") { // mute your audio output
- toggleMute();
- } else if (note == "2") { // mute your video output
- toggleVideoMute();
- } else if (note == "3") { // enable / disable screenshare
- toggleScreenShare();
- } else if (note == "4") { // completely kill your connection/session
- hangup();
- } else if (note == "5") { // raise your hand; director sees this
- raisehand();
- } else if (note == "6") { // start/stop local recording
- recordLocalVideoToggle();
- } else if (note == "7") { // Director Enables their Audio output
- press2talk(true);
- } else if (note == "8") { // Director cut's their audio/video output
- hangup2();
- }
- }
- }
- });
- input.addListener('controlchange', "all", function(e) {
-
- if (session.midiHotkeys==4){
- /* channel: 1
- controller: {number: 110, name: undefined}
- data: Uint8Array(3) [176, 110, 3]
- target: Input {_userHandlers: {…}, _midiInput: MIDIInput, …}
- timestamp: 98235.34000001382
- type: "controlchange"
- value: 3 */
- log(e);
- if (e.channel!==1){
- errorlog("OBSN is currently configured for use on channel 1 for MIDI hotkeys");
- return;
- } // channel 1?
-
- var command = e.controller.number;
- var value = e.value;
-
- if (command == 110){
- if (value == 0) { // open and close the chat window
- toggleChat();
- } else if (value == 1) { // mute your audio output
- toggleMute();
- } else if (value == 2) { // mute your video output
- toggleVideoMute();
- } else if (value == 3) { // enable / disable screenshare
- toggleScreenShare();
- } else if (value == 4) { // completely kill your connection/session
- hangup();
- } else if (value == 5) { // raise your hand; director sees this
- raisehand();
- } else if (value == 6) { // start/stop local recording
- recordLocalVideoToggle();
- } else if (value == 7) { // Director Enables their Audio output
- press2talk(true);
- } else if (value == 8) { // Director cut's their audio/video output
- hangup2();
- }
- } else if (command > 110){
- var guestslot = command-111;
- if (value == 0) {
- var elements = document.querySelectorAll('[data-action-type="forward"][data--u-u-i-d]');
- if (elements[guestslot]) {
- directMigrate(elements[guestslot], true);
- }
- } else if (value == 1) {
- var elements = document.querySelectorAll('[data-action-type="addToScene"][data--u-u-i-d]');
- if (elements[guestslot]) {
- directEnable(elements[guestslot], true);
- }
- } else if (value == 2) {
- var elements = document.querySelectorAll('[data-action-type="mute-scene"][data--u-u-i-d]');
- if (elements[guestslot]) {
- directMute(elements[guestslot], true);
- }
- } else if (value == 3) {
- var elements = document.querySelectorAll('[data-action-type="mute-guest"][data--u-u-i-d]');
- if (elements[guestslot]) {
- remoteMute(elements[guestslot], true);
- }
- } else if (value == 4) {
- var elements = document.querySelectorAll('[data-action-type="hangup"][data--u-u-i-d]');
- if (elements[guestslot]) {
- directHangup(elements[guestslot], true);
- }
- } else if (value == 5) {
- var elements = document.querySelectorAll('[data-action-type="solo-chat"][data--u-u-i-d]');
- if (elements[guestslot]) {
- session.toggleSoloChat(elements[guestslot].dataset.UUID);
- }
- } else if (value == 6) {
- var elements = document.querySelectorAll('[data-action-type="toggle-remote-speaker"][data--u-u-i-d]');
- if (elements[guestslot]) {
- remoteSpeakerMute(elements[guestslot]);
- }
- } else if (value == 7) {
- var elements = document.querySelectorAll('[data-action-type="toggle-remote-display"][data--u-u-i-d]');
- if (elements[guestslot]) {
- remoteDisplayMute(elements[guestslot]);
- }
- } else if ((value => 27)) {
- var elements = document.querySelectorAll('[data-action-type="volume"][data--u-u-i-d]');
- if (elements[guestslot]) {
- elements[guestslot].value = parseInt(value-27);
- remoteVolume(elements[guestslot]);
- }
- }
- }
- }
- });
- }
- });
- };
- script.src = "./thirdparty/webmidi.js"; // dynamically load this only if its needed. Keeps loading time down.
- document.head.appendChild(script);
-} else if (session.midiIn){
- var script = document.createElement('script');
- script.src = "./thirdparty/webmidi.js"; // dynamically load this only if its needed. Keeps loading time down.
- script.onload = function() {
- WebMidi.enable(function(err) { // hotkeys
- if (err) {
- errorlog(err);
- }
- console.log(WebMidi.outputs);
-
- });
- }
- document.head.appendChild(script);
-}
-
-function playbackMIDI(msg){
- if (session.midiIn===false){return;} // just in case.
- else if (session.midiHotkeys || session.midiOut){return;}
- //msg.midi.d = e.data;
- //msg.midi.s = e.timestamp;
- //msg.midi.t = e.type;
- log(msg);
- if (session.midiIn===true){
- if ("d" in msg){
- for (var i in WebMidi.outputs){
- try {
- WebMidi.outputs[i].send(msg.d[0], [msg.d[1] || 0, msg.d[2] || 0]);
- } catch(e){errorlog(e);}
- }
- }
- } else if (session.midiIn==parseInt(session.midiIn)){
- try {
- var i = parseInt(session.midiIn);
- if ("d" in msg){
- WebMidi.outputs[i].send(msg.d[0], [msg.d[1] || 0, msg.d[2] || 0]);
- }
- } catch(e){errorlog(e);};
- }
- //var output = WebMidi.getOutputById("123456789");
- //output = WebMidi.getOutputByName("Axiom Pro 25 Ext Out");
- //output = WebMidi.outputs[0];
-}
-
-document.body.innerHTML += '';
-addEventToAll(".column", 'click', function(e, ele) {
- if (ele.classList.contains("skip-animation")) {
- return;
- }
- var bounding_box = ele.getBoundingClientRect();
- ele.style.top = bounding_box.top + "px";
- ele.style.left = (bounding_box.left - 20) + "px";
- ele.classList.add('in-animation');
- ele.classList.remove('pointer');
- if (document.getElementById("empty-container")) {
- getById("empty-container").parentNode.removeChid(getById("empty-container"));
- }
- var empty = document.createElement("DIV");
- empty.id = "empty-container";
- empty.className = "column";
- ele.parentNode.insertBefore(empty, ele.nextSibling);
- const styles = "\
- @keyframes outlightbox {\
- 0% {\
- height: 100%;\
- width: 100%;\
- top: 0px;\
- left: 0px;\
- }\
- 50% {\
- height: 200px;\
- top: " + bounding_box.y + "px;\
- }\
- 100% {\
- height: 200px;\
- width: " + bounding_box.width + "px;\
- top: " + bounding_box.y + "px;\
- left: " + bounding_box.x + "px;\
- }\
- }\
- ";
- if (document.getElementById('lightbox-animations')) {
- getById("lightbox-animations").innerHTML = styles;
- }
- document.body.style.overflow = "hidden";
-});
-addEventToAll(".close", 'click', function(e, ele) {
- cleanupMediaTracks();
- ele.style.display = "none";
- mapToAll(".container-inner", function(target) {
- target.style.display = "none";
- });
- document.body.style.overflow = "auto";
- var bounding_box = getById("empty-container").parentNode.getBoundingClientRect();
- setTimeout(function() { // just smoothes things out; breathing room to clean up things first.
- ele.parentNode.classList.add('out-animation');
- }, 1);
- ele.parentNode.style.top = bounding_box.top + 'px';
- ele.parentNode.style.left = bounding_box.left + 'px';
- e.stopPropagation();
-});
-addEventToAll(".column", 'animationend', function(e, ele) {
- if (e.animationName == 'inlightbox') {
- ele.classList.add("skip-animation");
- mapToAll(".close", function(target) {
- target.style.display = "block";
- }, ele);
- mapToAll(".container-inner", function(target) {
- target.style.display = "block";
- }, ele);
- } else if (e.animationName == 'outlightbox') {
- ele.classList.remove('in-animation');
- ele.classList.remove('out-animation');
- ele.classList.remove("skip-animation");
- ele.classList.remove('columnfade');
- ele.classList.add('pointer');
- getById("empty-container").parentNode.removeChild(getById("empty-container"));
- getById("lightbox-animations").sheet.deleteRule(0);
- }
-});
-addEventToAll("#audioSource", 'mousedown touchend focusin focusout', function(e, ele) {
- var state = getById('multiselect-trigger').dataset.state || 0;
- if (state == 0) {
- getById('multiselect-trigger').dataset.state = 1;
- getById('multiselect-trigger').classList.add('open');
- getById('multiselect-trigger').classList.remove('closed');
- mapToAll('.chevron', function(ele) {
- ele.classList.remove('bottom');
- }, parentElement = getById('multiselect-trigger'));
- mapToAll('.multiselect-contents', function(ele) {
- ele.style.display = "block";
- mapToAll('input[type="checkbox"]', function(ele2) {
- ele2.parentNode.style.display = "block";
- ele2.style.display = "inline-block";
- }, ele);
- }, parentElement = getById('multiselect-trigger').parentNode);
- }
- e.stopPropagation();
- //e.preventDefault();
-});
-addEventToAll("#audioSource3", 'mousedown touchend focusin focusout', function(e, ele) {
- var state = getById('multiselect-trigger3').dataset.state || 0;
- if (state == 0) {
- getById('multiselect-trigger3').dataset.state = 1;
- getById('multiselect-trigger3').classList.add('open');
- getById('multiselect-trigger3').classList.remove('closed');
- mapToAll(".chevron", function(target) {
- target.classList.remove('bottom');
- }, getById('multiselect-trigger3'));
- mapToAll(".multiselect-contents", function(target) {
- target.style.display = "block";
- }, getById('multiselect-trigger3').parentNode);
- mapToAll(".multiselect-contents", function(target) {
- mapToAll('input[type="checkbox"]', function(target2) {
- target2.style.display = "inline-block";
- target2.parentNode.style.display = "block";
- }, target);
- }, getById('multiselect-trigger3').parentNode);
- }
- e.stopPropagation();
- //e.preventDefault();
-});
-addEventToAll("#multiselect-trigger", 'mousedown touchend focusin focusout', function(e, ele) {
- var state = ele.dataset.state || 0;
- if (state == 0) { // open the dropdown
- ele.dataset.state = 1;
- ele.classList.add('open');
- ele.classList.remove('closed');
- mapToAll(".chevron", function(target) {
- target.classList.remove('bottom');
- }, getById('multiselect-trigger'));
- mapToAll(".multiselect-contents", function(target) {
- target.style.display = "block";
- }, ele.parentNode);
- mapToAll(".multiselect-contents", function(target) {
- mapToAll('input[type="checkbox"]', function(target2) {
- target2.style.display = "inline-block";
- target2.parentNode.style.display = "block";
- }, target);
- }, ele.parentNode);
- } else { // close the dropdown
- ele.dataset.state = 0;
- ele.classList.add('closed');
- ele.classList.remove('open');
- mapToAll(".chevron", function(target) {
- target.classList.add('bottom');
- }, ele);
- mapToAll(".multiselect-contents", function(target) {
- mapToAll('input[type="checkbox"]', function(target2) {
- target2.style.display = "none";
- if (!target2.checked) {
- target2.parentNode.style.display = "none";
- }
- }, target);
- }, ele.parentNode);
- }
- e.preventDefault();
- e.stopPropagation();
-});
-addEventToAll("#multiselect-trigger3", 'mousedown touchend focusin focusout', function(e, ele) {
- var state = ele.dataset.state || 0;
- if (state == 0) { // open the dropdown
- ele.dataset.state = 1;
- ele.classList.add('open');
- ele.classList.remove('closed');
- mapToAll(".chevron", function(target) {
- target.classList.remove('bottom');
- }, ele);
- mapToAll(".multiselect-contents", function(target) {
- target.style.display = "block";
- }, ele.parentNode);
- mapToAll(".multiselect-contents", function(target) {
- mapToAll('input[type="checkbox"]', function(target2) {
- target2.style.display = "inline-block";
- target2.parentNode.style.display = "block";
- }, target);
- }, ele.parentNode);
- } else { // close the dropdown
- ele.dataset.state = 0;
- ele.classList.add('closed');
- ele.classList.remove('open');
- mapToAll(".chevron", function(target) {
- target.classList.add('bottom');
- }, ele);
- mapToAll(".multiselect-contents", function(target) {
- mapToAll('input[type="checkbox"]', function(target2) {
- target2.style.display = "none";
- if (!target2.checked) {
- target2.parentNode.style.display = "none";
- }
- }, target);
- }, ele.parentNode);
- }
- e.preventDefault();
- e.stopPropagation();
-});
-
-
-// Warns user about network going down
-window.addEventListener("offline", function (e) {
- if ((session.view) && (session.permaid === false)) {
- log( "OBS.Ninja has no network connectivity and can't work properly." );
- } else if (session.scene !== false) {
- log( "OBS.Ninja has no network connectivity and can't work properly." );
- } else if (!session.cleanOutput) {
- warnUser("Network connection lost.");
- } else {
- log("OBS.Ninja has no network connectivity and can't work properly.");
- }
-});
-
-window.addEventListener("online", function (e) {
- closeModal();
-});
-
-// Remove modal if network comes back up
-window.addEventListener("online", function (e) {
- if (!session.cleanOutput) {
- // Remove last inserted modal; Could be improved by tagging the
- // modal elements and only removing modals tagged 'offline'
- userWarnings = document.querySelectorAll('.alertModal');
- closeModal(userWarnings[userWarnings.length- 1]);
- } else {
- log(
- "Network connectivity has been restored."
- );
- }
- });
+/*
+* Copyright (c) 2020 Steve Seguin. All Rights Reserved.
+*
+* Use of this source code is governed by the APGLv3 open-source license
+* that can be found in the LICENSE file in the root of the source
+* tree. Alternative licencing options can be made available on request.
+*
+*/
+/*jshint esversion: 6 */
+
+var formSubmitting = true;
+var activatedPreview = false;
+
+
+// function log(msg){ // uncomment to enable logging.
+ // console.log(msg);
+// }
+// function warnlog(msg, url=false, lineNumber=false){
+ // onsole.warn(msg);
+ // if (lineNumber){
+ // console.warn(lineNumber);
+ // }
+// }
+// function errorlog(msg, url=false, lineNumber=false){
+ // console.error(msg);
+ // if (lineNumber){
+ // console.error(lineNumber);
+ // }
+// }
+
+function addEventToAll(targets, trigger, callback) { // js helper
+ const target = document.querySelectorAll(targets);
+ var triggers = trigger.split(" ");
+ for (let i = 0; i < target.length; i++) {
+ for (let j = 0; j < triggers.length; j++) {
+ setTimeout(function(t1,t2){
+ t1.addEventListener(t2, function(e) {
+ callback(e, t1);
+ });
+ },0,target[i],triggers[j]);
+ }
+ }
+}
+
+function mapToAll(targets, callback, parentElement = document) { // js helper
+ if (!targets) {
+ return;
+ }
+ if (!parentElement) {
+ return;
+ }
+ const target = parentElement.querySelectorAll(targets);
+ for (let i = 0; i < target.length; i++) {
+ callback(target[i]);
+ }
+}
+
+var isIFrame = false;
+if ( parent && (window.location !== window.parent.location )) {
+ isIFrame = true;
+}
+
+function changeParam(url, paramName, paramValue) {
+ paramName = paramName.replace("?", "");
+ var qind = url.indexOf('?');
+ url = url.replace("?", "&");
+ var params = url.substring(qind + 1).split('&');
+ var query = '';
+ var match = false;
+ for (var i = 0; i < params.length; i++) {
+ var tokens = params[i].split('=');
+ var name = tokens[0];
+ var value = "";
+ if (tokens.length > 1 && tokens[1] !== '') {
+ value = tokens[1];
+ }
+
+ if (name == paramName) {
+ if (match) {
+ continue;
+ } // already matched the first time.
+ match = true;
+ value = paramValue;
+ }
+ if (value !== "") {
+ value = '=' + value;
+ }
+
+ if (query == '') {
+ query = "?" + name + value;
+ } else {
+ query = query + '&' + name + value;
+ }
+ }
+ return url.substring(0, qind) + query;
+}
+
+function updateURL(param, force = false, cleanUrl = false) {
+ param = param.replace("?", "");
+ var para = param.split('=');
+ if (cleanUrl) {
+ if (history.pushState) {
+ var href = new URL(cleanUrl);
+ if (para.length == 1) {
+ href = changeParam(cleanUrl, para[0], "");
+ } else {
+ href = changeParam(cleanUrl, para[0], para[1]);
+ }
+ log("--" + href.toString());
+ window.history.pushState({path: href.toString()}, '', href.toString());
+ }
+ } else if (!(urlParams.has(para[0]))) { // don't need to replace as it doesn't exist.
+ if (history.pushState) {
+ var href = window.location.href;
+ href = href.replace("??", "?");
+ var arr = href.split('?');
+ var newurl;
+ if (arr.length > 1 && arr[1] !== '') {
+ newurl = href + '&' + param;
+ } else {
+ newurl = href + '?' + param;
+ }
+
+ window.history.pushState({path: newurl.toString()}, '', newurl.toString());
+ }
+ } else if (force) {
+ if (history.pushState) {
+ var href = new URL(window.location.href);
+ if (para.length == 1) {
+ href = changeParam(window.location.href, para[0], "");
+ } else {
+ href = changeParam(window.location.href, para[0], para[1]);
+ }
+ log("---" + href.toString());
+ window.history.pushState({path: href.toString()}, '', href.toString());
+ }
+ }
+ if (session.sticky) {
+ setStorage("settings", encodeURI(window.location.href), 90);
+ }
+ urlParams = new URLSearchParams(window.location.search);
+}
+
+function changeGuestSettings(ele){
+ var eles = ele.querySelectorAll('[data-param]');
+ var UUID = ele.dataset.UUID;
+ var settings = {};
+ for (var i = 0;i< eles.length; i++){
+ if (eles[i].tagName.toLowerCase() == "input"){
+ if (eles[i].checked===true){
+ settings[eles[i].dataset.param] = true;
+ } else if (eles[i].checked===false){
+ settings[eles[i].dataset.param] = false;
+ } else {
+ settings[eles[i].dataset.param] = eles[i].value;
+ }
+ }
+ }
+ warnlog(settings);
+
+ if (!settings.changepassword){
+ delete settings.password;
+ }
+
+ delete settings.changepassword;
+
+ if (!settings.changeroom){
+ // send Migration message
+ delete settings.roomid;
+ }
+ delete settings.roomid;
+ delete settings.changeroom;
+
+ warnlog(UUID);
+ var msg = {};
+ msg.changeParams = settings;
+ session.sendRequest(msg, UUID);
+ closeModal();
+}
+
+// proper room migration needs to happen; in sync.
+// updateMixer after settings changed
+// password needs to be special cased
+// room shouldn't be sent
+
+function applyNewParams(changeParams){
+ for (var key in changeParams){
+ session[key] = changeParams[key];
+ log(key);
+ }
+ log(changeParams);
+ updateMixer();
+}
+
+function promptUser(eleId, UUID=null){
+ if (document.getElementById("modalBackdrop")){
+ getById("promptModal").innerHTML = ''; // Delete modal
+ getById("promptModal").remove();
+ getById("modalBackdrop").innerHTML = ''; // Delete modal
+ getById("modalBackdrop").remove();
+ }
+
+ zindex = 30 + document.querySelectorAll('#promptModal').length;
+ modalTemplate =
+ `
+
`;
+ document.body.insertAdjacentHTML("beforeend", modalTemplate); // Insert modal at body end
+
+ getById("promptModalMessage").innerHTML = getById(eleId).innerHTML;
+ if (UUID){
+ getById("promptModalMessage").dataset.UUID = UUID;
+ }
+
+
+ document.getElementById("modalBackdrop").addEventListener("click", closeModal);
+
+ getById("promptModal").addEventListener("click", function(e) {
+ e.stopPropagation();
+ return false;
+ });
+
+}
+var warnUserTimeout=null;
+function warnUser(message, timeout=false){
+ // Allows for multiple alerts to stack better.
+ // Every modal and backdrop has an increasing z-index
+ // to block the previous modal
+ if (document.getElementById("modalBackdrop")){
+ getById("alertModal").innerHTML = ''; // Delete modal
+ getById("alertModal").remove();
+ getById("modalBackdrop").innerHTML = ''; // Delete modal
+ getById("modalBackdrop").remove();
+ }
+
+ zindex = 31 + document.querySelectorAll('.alertModal').length;
+ message = message.replace(/\n/g," ");
+ modalTemplate =
+ `
+
`;
+ document.body.insertAdjacentHTML("beforeend", modalTemplate); // Insert modal at body end
+
+ document.getElementById("modalBackdrop").addEventListener("click", closeModal);
+
+ clearTimeout(warnUserTimeout);
+ if (timeout){
+ warnUserTimeout = setTimeout(closeModal, timeout);
+ }
+ getById("alertModal").addEventListener("click", function(e) {
+ e.stopPropagation();
+ return false;
+ });
+
+}
+function closeModal(){
+ getById("modalBackdrop").innerHTML = ''; // Delete modal
+ getById("modalBackdrop").remove();
+ getById("alertModal").innerHTML = ''; // Delete modal
+ getById("alertModal").remove();
+ getById("promptModal").innerHTML = ''; // Delete modal
+ getById("promptModal").remove();
+}
+
+var filename = false;
+try {
+ filename = window.location.pathname.substring(window.location.pathname.lastIndexOf('/') + 1);
+ filename = filename.replace("??", "?");
+ filename2 = filename.split("?")[0];
+ // split at ???
+ if (filename.split(".").length == 1) {
+ if (filename2.length < 2) { // easy win
+ filename = false;
+ } else if (filename.startsWith("&")) { // easy win
+ var tmpHref = window.location.href.substring(0, window.location.href.lastIndexOf('/')) + "/?" + filename.split("&").slice(1).join("&");
+ log("TMP " + tmpHref);
+ updateURL(filename.split("&")[1], true, tmpHref);
+ filename = false;
+ } else if (filename2.split("&")[0].includes("=")) {
+ log("asdf " + filename.split("&")[0]);
+ if (history.pushState) {
+ var tmpHref = window.location.href.substring(0, window.location.href.lastIndexOf('/'));
+ tmpHref = tmpHref + "/?" + filename;
+ filename = false;
+ //warnUser("Please ensure your URL is correctly formatted.");
+ window.history.pushState({path: tmpHref.toString()}, '', tmpHref.toString());
+ }
+ } else {
+ filename = filename2.split("&")[0];
+ if (filename2 != filename) {
+ warnUser("Warning: Please ensure your URL is correctly formatted.");
+ }
+ }
+ } else {
+ filename = false;
+ }
+ log(filename);
+} catch (e) {
+ errorlog(e);
+}
+
+
+(function(w) {
+ w.URLSearchParams = w.URLSearchParams || function(searchString) {
+ var self = this;
+ searchString = searchString.replace("??", "?");
+ self.searchString = searchString;
+ self.get = function(name) {
+ var results = new RegExp('[\?&]' + name + '=([^]*)').exec(self.searchString);
+ if (results == null) {
+ return null;
+ } else {
+ return decodeURI(results[1]) || 0;
+ }
+ };
+ };
+
+})(window);
+
+var urlEdited = window.location.search.replace(/\?\?/g, "?");
+urlEdited = urlEdited.replace(/\?/g, "&");
+urlEdited = urlEdited.replace(/\&/, "?");
+
+if (urlEdited !== window.location.search){
+ warnlog(window.location.search + " changed to " + urlEdited);
+ window.history.pushState({path: urlEdited.toString()}, '', urlEdited.toString());
+}
+var urlParams = new URLSearchParams(urlEdited);
+
+var sanitizeStreamID = function(streamID) {
+ streamID = streamID.trim();
+
+ if (streamID.length < 1) {
+ streamID = session.generateStreamID(8);
+ if (!(session.cleanOutput)) {
+ warnUser("No streamID was provided; one will be generated randomily.\n\nStream ID: " + streamID);
+ }
+ }
+ var streamID_sanitized = streamID.replace(/[\W]+/g, "_");
+ if (streamID !== streamID_sanitized) {
+ if (!(session.cleanOutput)) {
+ warnUser("Info: Only AlphaNumeric characters should be used for the stream ID.\n\nThe offending characters have been replaced by an underscore");
+ }
+ }
+ if (streamID_sanitized.length > 44) {
+ streamID_sanitized = streamID_sanitized.substring(0, 44);
+ if (!(session.cleanOutput)) {
+ warnUser("The Stream ID should be less than 45 alPhaNuMeric characters long.\n\nWe will trim it to length.");
+ }
+ }
+ return streamID_sanitized;
+};
+
+var checkStrength = function(string) {
+ var matcher = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{7,30}$/;
+ if (string.match(matcher)) {
+ return true;
+ } else if (string.length > 20) {
+ return true;
+ } else {
+ return false;
+ }
+};
+
+var checkStrengthRoom = function() {
+ var result1 = checkStrength(getById('videoname1').value);
+ var result2 = getById('passwordRoom').value.length;
+ var target = getById('securityLevelRoom');
+ target.style.display = "block";
+ if (result1) {
+ if (result2) {
+ target.innerHTML = "Share only with those you trust ";
+ } else {
+ target.innerHTML = "A password is recommended ";
+ }
+ } else {
+ target.innerHTML = "Insecure room name. Allowed chars: A-Z, a-z, 0-9, _ ";
+ }
+};
+
+var sanitizeChat = function(string) {
+ var temp = document.createElement('div');
+ temp.innerText = string;
+ temp.innerText = temp.innerHTML;
+ temp = temp.textContent || temp.innerText || "";
+ temp = temp.substring(0, Math.min(temp.length, 500));
+ return temp.trim();
+};
+
+var sanitizeString = function(str) {
+ str = str.replace(/[^a-z0-9áéíóúñü \.,_-]/gim, "");
+ return str.trim();
+};
+
+var sanitizeLabel = function(string) {
+ let temp = document.createElement("div");
+ temp.innerText = string;
+ temp.innerText = temp.innerHTML;
+ temp = temp.textContent || temp.innerText || "";
+ temp = temp.substring(0, Math.min(temp.length, 50));
+ return temp.trim();
+};
+
+var sanitizeRoomName = function(roomid) {
+ roomid = roomid.trim();
+ if (roomid === "") {
+ return roomid;
+ } else if (roomid === false) {
+ return roomid;
+ }
+
+ var sanitized = roomid.replace(/[\W]+/g, "_");
+ if (sanitized !== roomid) {
+ if (!(session.cleanOutput)) {
+ warnUser("Info: Only AlphaNumeric characters should be used for the room name.\n\nThe offending characters have been replaced by an underscore");
+ }
+ }
+ if (sanitized.length > 30) {
+ sanitized = sanitized.substring(0, 30);
+ if (!(session.cleanOutput)) {
+ warnUser("The Room name should be less than 31 alPhaNuMeric characters long.\n\nWe will trim it to length.");
+ }
+ }
+ return sanitized;
+};
+
+var sanitizePassword = function(passwrd) {
+ if (passwrd === "") {
+ return passwrd;
+ } else if (passwrd === false) {
+ return passwrd;
+ } else if (passwrd === null) {
+ return passwrd;
+ }
+ passwrd = passwrd.trim();
+ if (passwrd.length < 1) {
+ if (!(session.cleanOutput)) {
+ warnUser("The password provided was blank.");
+ }
+ }
+ var sanitized = encodeURIComponent(passwrd);//.replace(/[\W]+/g, "_");
+ //if (sanitized !== passwrd) {
+ // if (!(session.cleanOutput)) {
+ // warnUser("Info: Only AlphaNumeric characters should be used in the password.\n\nThe offending characters have been replaced by an underscore");
+ // }
+ //}
+ return sanitized;
+};
+
+function isOperaGX(){
+ return (!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(' OPR/75') >= 0;
+}
+
+function getChromeVersion() {
+ var raw = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);
+ return raw ? parseInt(raw[2], 10) : false;
+}
+
+if (!(getChromeVersion()>=57)){
+ getById("effectSelector").disabled=true;
+ getById("effectSelector3").disabled=true;
+ getById("effectSelector").title = "Effects are only support on Chromium-based browsers";
+ getById("effectSelector3").title = "Effects are only support on Chromium-based browsers";
+ var elements = document.querySelectorAll('[data-effectsNotice]');
+ for (let i = 0; i < elements.length; i++) {
+ elements[i].style.display = "inline-block";
+ }
+}
+
+function safariVersion() {
+ var ver = 0;
+ try {
+ ver = navigator.appVersion.split("Version/");
+ if (ver.length > 1) {
+ ver = ver[1].split(" Safari");
+ }
+ if (ver.length > 1) {
+ ver = ver[0].split(".");
+ }
+ if (ver.length > 1) {
+ ver = parseInt(ver[0]);
+ } else {
+ ver = 0;
+ }
+ } catch (e) {
+ return 0;
+ }
+ return ver;
+}
+
+if (urlParams.has('optimize')) {
+ session.optimize = parseInt(urlParams.get('optimize')) || 0;
+}
+document.addEventListener("visibilitychange", function() {
+ log(document.hidden, document.visibilityState);
+ if ((iOS) || (iPad)) { // fixes a bug on iOS devices. Not need with other devices?
+ if (document.visibilityState === 'visible') {
+ setTimeout(function() {
+ resetupAudioOut();
+ }, 500);
+ }
+ }
+});
+function obsSceneChanged(event){
+ log(event.detail.name);
+ window.obsstudio.getCurrentScene(function(scene) {
+ log("OBS SCENE");
+ log(scene);
+ });
+}
+function obsStreamingStarted(event){
+ session.obsState.streaming = true;
+ session.obsStateSync();
+}
+function obsStreamingStopped(event){
+ session.obsState.streaming = false;
+ session.obsStateSync();
+}
+function obsRecordingStarted(event){
+ session.obsState.recording = true;
+ session.obsStateSync();
+}
+function obsRecordingStopped(event){
+ session.obsState.recording = false;
+ session.obsStateSync();
+}
+function obsSourceActiveChanged(event){
+ warnlog("obsSourceActiveChanged");
+ warnlog( event.detail);
+
+ try {
+ if (typeof event==="boolean"){var sourceActive = event;}
+ else if (typeof event.detail === "boolean"){var sourceActive = event.detail;}
+ else if (typeof event.detail.active === "boolean"){var sourceActive = event.detail.active;}
+ else {var sourceActive = event.detail.active;}
+
+ if (typeof sourceActive === "undefined"){return;} // Just fail.
+
+ if (session.obsState.sourceActive!==sourceActive){ // only move forward if there is a change; the event likes to double fire you see.
+ session.obsState.sourceActive = sourceActive;
+ session.obsStateSync();
+ }
+
+ } catch (e){errorlog(e);}
+}
+
+function obsSourceVisibleChanged(event){ // accounts for visible in OBS.Ninja scene AND visible in OBS scene
+ warnlog("obsSourceVisibleChanged");
+ warnlog(event.detail);
+ try {
+ if (typeof event==="boolean"){var visibility = event;}
+ else if (typeof event.detail === "boolean"){var visibility = event.detail;}
+ else if (typeof event.detail.visible === "boolean"){var visibility = event.detail.visible;}
+ else {var visibility = event.detail.visible;}
+
+ if (typeof visibility === "undefined"){ // fall back
+ if (typeof document.visibilityState !== "undefined"){
+ visibility = document.visibilityState==="visible"; // modern
+ } else if (typeof document.hidden !== "undefined"){
+ visibility = !document.hidden; // legacy
+ } else {
+ return; // ... unknown input? fail.
+ }
+ }
+
+ errorlog("visibility: "+visibility);
+
+ if (session.obsState.visibility!==visibility){ // only move forward if there is a change; the event likes to double fire you see.
+ session.obsState.visibility = visibility;
+ session.obsStateSync();
+ }
+
+ } catch (e){errorlog(e);}
+}
+
+if (window.obsstudio) {
+ session.disableWebAudio = true; // default true; might be useful to disable on slow or old computers?
+ session.audioMeterGuest = false;
+ session.audioEffects = false;
+ session.obsfix = 15; // can be manually set via URL. ; VP8=15, VP9=30. (previous was 20.)
+ try {
+ log("OBS VERSION:" + window.obsstudio.pluginVersion);
+ log("macOS: " + navigator.userAgent.indexOf('Mac OS X') != -1);
+ log(window.obsstudio);
+
+ if (typeof document.visibilityState !== "undefined"){
+ session.obsState.visibility = document.visibilityState==="visible";
+ //session.obsState.sourceActive = session.obsState.visibility;
+ }
+
+ window.obsstudio.getStatus(function(obsStatus) {
+ log("OBS STATUS:");
+ log(obsStatus);
+ // TODO: update state here
+ if ("recording" in obsStatus){
+ session.obsState.recording = obsStatus.recording;
+ }
+ if ("streaming" in obsStatus){
+ session.obsState.streaming = obsStatus.streaming;
+ }
+
+ });
+
+ if (!(urlParams.has('streamlabs'))) {
+
+ var ver = window.obsstudio.pluginVersion;
+ ver1 = ver.split(".");
+
+ var cefVersion = getChromeVersion();
+
+ if (ver1.length == 3) { // Should be 3, but disabled3
+ if ((ver1.length == 3) && (parseInt(ver1[0]) == 2) && (cefVersion < 76) && (navigator.userAgent.indexOf('Mac OS X') != -1)) {
+ updateURL("streamlabs");
+ getById("main").innerHTML = "";
+ }
+ }
+ }
+
+ if (navigator.userAgent.indexOf('Mac OS X') != -1) {
+ session.codec = "h264"; // default the codec to h264 if OBS is on macOS (that's all it supports with hardware)
+ }
+
+ if (session.disableOBS===false){
+ window.addEventListener("obsSourceVisibleChanged", obsSourceVisibleChanged);
+ window.addEventListener("obsSourceActiveChanged", obsSourceActiveChanged);
+ window.addEventListener("obsSceneChanged", obsSceneChanged);
+ window.addEventListener("obsStreamingStarted", obsStreamingStarted);
+ window.addEventListener("obsStreamingStopped", obsStreamingStopped);
+ window.addEventListener("obsRecordingStarted", obsRecordingStarted);
+ window.addEventListener("obsRecordingStopped", obsRecordingStopped);
+ }
+
+ } catch (e) {
+ errorlog(e);
+ }
+}
+
+function manageSceneState(data, UUID){
+ if (session.disableOBS){return;}
+ var processNeeded = false
+ try{
+ if ("sceneDisplay" in data){
+ processNeeded=true;
+ session.pcs[UUID].sceneDisplay = data.sceneDisplay;
+ }
+ if ("sceneMute" in data){
+ processNeeded=true;
+ session.pcs[UUID].sceneMute = data.sceneMute;
+ }
+ if ("obsSourceActive" in data){
+ processNeeded=true;
+ session.pcs[UUID].obsSourceActive = data.obsSourceActive;
+ }
+ if ("obsVisibility" in data){
+ processNeeded=true;
+ session.pcs[UUID].obsVisibility = data.obsVisibility;
+ session.optimizeBitrate(UUID); // &optimize flag; sets video bitrate to target value if this flag == HIDDEN (if optimize=0, disables both audio and video)
+ }
+ if ("obsStreaming" in data){
+ processNeeded=true;
+ session.pcs[UUID].obsStreaming = data.obsStreaming;
+ }
+ if ("obsRecording" in data){
+ processNeeded=true;
+ session.pcs[UUID].obsRecording = data.obsRecording;
+ }
+ } catch(e){} // just in case the client has disconnected.
+
+ if (processNeeded){
+ applySceneState();
+ }
+}
+
+function applySceneState(){
+
+ if (session.cleanOutput===false){
+ if (document.getElementById("videosource")){
+ var visibility = false;
+ var ondeck = false;
+ var recording = false;
+ for (var uid in session.pcs){
+
+ if (session.pcs[uid].obsSourceActive && session.pcs[uid].obsVisibility && (session.pcs[uid].sceneDisplay!==false)){
+ visibility=true;
+ } else if (session.pcs[uid].obsVisibility && (session.pcs[uid].sceneDisplay!==false)){
+ ondeck=true;
+ }
+ if ((session.pcs[uid].obsRecording || session.pcs[uid].obsStreaming) && (session.pcs[uid].obsSourceActive && session.pcs[uid].obsVisibility && (session.pcs[uid].sceneDisplay!==false))){ // the scene that is recording must be visible also.
+ recording=true;
+ }
+ }
+
+ if (recording){
+ getById("obsState").classList.remove("ondeck");
+ getById("obsState").classList.add("recording"); // TODO: this needs to check all peers to make sure it's valid
+ getById("obsState").innerHTML = "ON AIR";
+ } else if (ondeck && !visibility){
+ getById("obsState").classList.remove("recording");
+ getById("obsState").classList.add("ondeck"); // TODO: this needs to check all peers to make sure it's valid
+ getById("obsState").innerHTML = "STAND BY";
+ } else {
+ getById("obsState").classList.remove("recording");
+ getById("obsState").classList.remove("ondeck");
+ getById("obsState").innerHTML = "ACTIVE";
+ }
+
+ if (visibility || ondeck){ // BASIC TALLY LIGHT
+ getById("obsState").classList.add("onair"); // LIVE
+ } else {
+ getById("obsState").classList.remove("onair");
+
+ }
+
+ }
+ }
+
+}
+
+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) {
+ try {
+ session.ws.close();
+ if (session.videoElement.recording) {
+ session.videoElement.recorder.writer.close();
+ session.videoElement.recording = false;
+ }
+ for (var i in session.rpcs) {
+ if (session.rpcs[i].videoElement) {
+ if (session.rpcs[i].videoElement.recording) {
+ session.rpcs[i].videoElement.recorder.writer.close();
+ session.rpcs[i].videoElement.recording = false;
+ }
+ }
+ }
+ } catch (e) {}
+ //setTimeout(function(){session.hangup();},0);
+ return undefined; // ADDED OCT 29th; get rid of popup. Just close the socket connection if the user is refreshing the page. It's one or the other.
+
+ });
+};
+
+getById("credits").innerHTML = "Version: " + session.version + " - " + getById("credits").innerHTML;
+
+var lastTouchEnd = 0;
+document.addEventListener('touchend', function(event) {
+ var now = (new Date()).getTime();
+ if (now - lastTouchEnd <= 300) {
+ event.preventDefault();
+ }
+ lastTouchEnd = now;
+}, false);
+
+
+document.addEventListener('click', function(event) {
+ if (session.firstPlayTriggered == false) {
+ playAllVideos();
+ session.firstPlayTriggered = true;
+ history.pushState({}, '');
+ }
+});
+var Callbacks = [];
+var CtrlPressed = false; // global
+var AltPressed = false;
+document.addEventListener("keydown", event => {
+
+ if ((event.ctrlKey) || (event.metaKey)) { // detect if CTRL is pressed
+ CtrlPressed = true;
+ } else {
+ CtrlPressed = false;
+ }
+ if (event.altKey) {
+ AltPressed = true;
+ } else {
+ AltPressed = false;
+ }
+
+
+ if (CtrlPressed && event.keyCode) {
+
+ if (event.keyCode == 77) { // m
+ if (event.metaKey) {
+ if (AltPressed) {
+ toggleMute(); // macOS
+ }
+ } else {
+ toggleMute(); // Windows
+ }
+ // } else if (event.keyCode == 69) { // e
+ // hangup();
+ } else if (event.keyCode == 66) { // b
+ toggleVideoMute();
+ }
+ }
+
+
+});
+
+document.addEventListener("keyup", event => {
+ if (!((event.ctrlKey) || (event.metaKey))) {
+ if (CtrlPressed) {
+ CtrlPressed = false;
+ for (var i in Callbacks) {
+ var cb = Callbacks[i];
+ log(cb.slice(1));
+ cb[0](...cb.slice(1)); // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#A_better_apply
+ }
+ Callbacks = [];
+ }
+ }
+ if (!(event.altKey)) {
+ AltPressed = false;
+ }
+});
+
+window.onpopstate = function() {
+ if (session.firstPlayTriggered) {
+ window.location.reload(true);
+ }
+};
+
+if (typeof session === 'undefined') { // make sure to init the WebRTC if not exists.
+ var session = WebRTC.Media;
+ session.streamID = session.generateStreamID();
+ errorlog("Serious error: WebRTC session didn't load in time");
+}
+
+if (navigator.userAgent.toLowerCase().indexOf(' electron/') > -1) {
+ try {
+ getById("electronDragZone").style.cursor="grab";
+ const ipcRenderer = require('electron').ipcRenderer;
+ window.prompt = function(title, val){
+ return ipcRenderer.sendSync('prompt', {title, val});
+ };
+ } catch(e){}
+}
+
+function makeDraggableElement(elmnt) {
+ try {
+ elmnt.dragElement = false;
+ elmnt.style.bottom = "auto";
+ elmnt.style.cursor = "grab";
+ elmnt.stashonmouseup = null;
+ elmnt.stashonmousemove = null;
+
+ } catch (e) {
+ errorlog(e);
+ return;
+ }
+
+ var pos1 = 0;
+ var pos2 = 0;
+ var pos3 = 0;
+ var pos4 = 0;
+
+ function dragMouseDown(e) {
+ e = e || window.event;
+ e.preventDefault();
+
+ pos3 = e.clientX;
+ pos4 = e.clientY;
+ elmnt.stashonmouseup = document.onmouseup; // I don't want to interfere with other drag events.
+ elmnt.stashonmousemove = document.onmousemove;
+
+ document.onmouseup = closeDragElement;
+ document.onmousemove = elementDrag;
+ }
+
+ function elementDrag(e) {
+ e = e || window.event;
+ e.preventDefault();
+
+ elmnt.dragElement = true;
+ pos1 = pos3 - e.clientX;
+ pos2 = pos4 - e.clientY;
+ pos3 = e.clientX;
+ pos4 = e.clientY;
+
+ var topDrag = (elmnt.offsetTop - pos2);
+ if (topDrag > -3) {
+ topDrag = -3;
+ }
+ elmnt.style.top = topDrag + "px";
+ elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
+
+ }
+
+ elmnt.onmousedown = dragMouseDown;
+ function closeDragElement() {
+ document.onmouseup = elmnt.stashonmouseup;
+ document.onmousemove = elmnt.stashonmousemove;
+ }
+}
+
+function setStorage(cname, cvalue, exdays=999) { // not actually a cookie
+ var now = new Date();
+ var item = {
+ value: cvalue,
+ expiry: now.getTime() + (exdays * 24 * 60 * 60 * 1000),
+ };
+ localStorage.setItem(cname, JSON.stringify(item));
+}
+
+function getStorage(cname) {
+ var itemStr = localStorage.getItem(cname);
+ if (!itemStr) {
+ return "";
+ }
+ var item = JSON.parse(itemStr);
+ var now = new Date();
+ if (now.getTime() > item.expiry) {
+ localStorage.removeItem(cname);
+ return "";
+ }
+ return item.value;
+}
+
+if (!isIFrame){
+ if (getStorage("redirect") == "yes") {
+ setStorage("redirect", "", 0);
+ session.sticky = true;
+ } else if (getStorage("settings") != "") {
+ if (!(session.cleanOutput)){
+ window.focus();
+ session.sticky = confirm("Would you like you load your previous session's settings?");
+ if (!session.sticky) {
+ setStorage("settings", "", 0);
+ log("deleting cookie as user said no");
+ } else {
+ var cookieSettings = decodeURI(getStorage("settings"));
+ setStorage("redirect", "yes", 1);
+ window.location.replace(cookieSettings);
+ }
+ }
+ }
+
+ if (urlParams.has('sticky')){ // won't work with iframes.
+
+ //if (getStorage("permission") == "") {
+ // session.sticky = confirm("Would you allow us to store a cookie to keep your session settings persistent?");
+ //} else {
+ session.sticky = true;
+ //}
+ //if (session.sticky) {
+ setStorage("permission", "yes", 999);
+ setStorage("settings", encodeURI(window.location.href), 90);
+ //}
+ }
+}
+
+if (urlParams.has('cleanoutput') || urlParams.has('clean') || urlParams.has('cleanish')) {
+ session.cleanOutput = true;
+}
+
+if (urlParams.has('retrytimeout')) {
+ session.retryTimeout = parseInt(urlParams.get('retrytimeout'));
+}
+
+if (urlParams.has('ptz')){
+ session.ptz=true;
+}
+
+var screensharebutton = true;
+var screensharesupport = true;
+if (urlParams.has('nosettings') || urlParams.has('ns')) {
+ screensharebutton = false;
+ session.showSettings = false;
+}
+
+if (urlParams.has('nomicbutton') || urlParams.has('nmb')) {
+ getById("mutebutton").setAttribute('style', "display: none !important");
+}
+
+
+if (urlParams.has('novideobutton') || urlParams.has('nvb')) {
+ getById("mutevideobutton").setAttribute('style', "display: none !important");
+}
+
+if (urlParams.has('screenshareid') || urlParams.has('ssid')) {
+ if (urlParams.get('screenshareid') || urlParams.get('ssid')) {
+ session.screenshareid = urlParams.get('screenshareid') || urlParams.get('ssid');
+ session.screenshareid = sanitizeStreamID(session.screenshareid);
+ }
+}
+
+if (urlParams.has('screensharefps') || urlParams.has('ssfps')) {
+ if (urlParams.get('screensharefps') || urlParams.get('ssfps')) {
+ session.screensharefps = urlParams.get('screensharefps') || urlParams.get('ssfps');
+ session.screensharefps = parseInt(session.screensharefps) || 2;
+ }
+}
+
+if (urlParams.has('screensharequality') || urlParams.has('ssq')) {
+ if (urlParams.get('screensharequality') || urlParams.get('ssq')) {
+ session.screensharequality = urlParams.get('screensharequality') || urlParams.get('ssq');
+ session.screensharequality = parseInt(session.screensharequality) || 1;
+ }
+}
+
+if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
+ //session.webcamonly = true;
+ session.mobile = true;
+ getById("shareScreenGear").style.display = "none";
+ screensharebutton = false;
+ screensharesupport = false;
+ getById("container-2").className = 'column columnfade advanced'; // Hide screen share on mobile
+ getById("dropButton").style.display = "none";
+ //session.disableWebAudio = true; // default true; might be useful to disable on slow or old computers?
+ session.audioEffects = false; // disable audio inbound effects also.
+ session.audioMeterGuest = false;
+
+} else if ((iOS) || (iPad)) {
+ getById("shareScreenGear").style.display = "none";
+ session.mobile = true;
+ screensharebutton = false;
+ screensharesupport = false;
+ getById("container-2").className = 'column columnfade advanced'; // Hide screen share on mobile
+ getById("dropButton").style.display = "none";
+ //session.audiobitrate = false; // iOS devices seem to get distortion with custom audio bitrates. Disable for now.
+ //session.maxiosbitrate = 10; // this is 10-kbps by default already.
+ //session.disableWebAudio = true; // default true; might be useful to disable on slow or old computers?
+ session.audioEffects = false; // disable audio inbound effects also.
+ session.audioMeterGuest = false;
+} else {
+ log("MAKE DRAGGABLE");
+ setTimeout(function(){makeDraggableElement(document.getElementById("subControlButtons"));},100);
+
+ if (safariVersion() && !getChromeVersion()){
+ getById("SafariWarning").style.display = "block";
+ }
+}
+
+
+if ((iOS) || (iPad)) {
+ window.addEventListener('resize', function() { // Safari is the new IE.
+ var msg = {};
+ msg.requestSceneUpdate = true;
+ session.sendMessage(msg);
+
+ if ( window.matchMedia("(orientation: portrait)").matches ) {
+ document.getElementsByTagName("html")[0].style.height = "100vh";
+ setTimeout(function(){
+ document.getElementsByTagName("html")[0].style.height = "100%";
+ }, 1000);
+ } else if ( window.matchMedia("(orientation: landscape)").matches ) {
+ document.getElementsByTagName("html")[0].style.height = "100vh";
+ setTimeout(function(){
+ document.getElementsByTagName("html")[0].style.height = "100%";
+ }, 1000);
+ }
+ });
+}
+
+if (/CriOS/i.test(navigator.userAgent) && (iOS || iPad)) {
+ if (!(session.cleanOutput)) {
+ try {
+ navigator.mediaDevices.getUserMedia;
+ } catch (e) {
+ warnUser("Chrome on this device does not support the required technology to use this site.\n\nPlease use Safari instead or update your iOS and browser version.");
+ }
+ }
+}
+
+if (urlParams.has('tips')){
+ getById("guestTips").style.display="flex";
+}
+
+if (urlParams.has('broadcast') || urlParams.has('bc')) {
+ log("Broadcast flag set");
+ session.broadcast = urlParams.get('broadcast') || urlParams.get('bc') || null;
+ //if ((iOS) || (iPad)) {
+ // session.nopreview = false;
+ //} else {
+ // session.nopreview = true;
+ //}
+ session.minipreview = 2; // full screen if nothing else on screen.
+ session.style = 1;
+ getById("header").style.display = "none";
+ getById("header").style.opacity = 0;
+ session.showList=false;
+}
+
+if (urlParams.has('showlist')) {
+ session.showList = urlParams.get('showlist');
+ if (session.showList === "false") {
+ session.showList = false;
+ } else if (session.showList=== "0") {
+ session.showList = false;
+ } else if (session.showList === "no") {
+ session.showList = false;
+ } else if (session.showList === "off") {
+ session.showList = false;
+ } else {
+ session.showList = true;
+ }
+}
+
+var directorLanding = false;
+if (urlParams.has('director') || urlParams.has('dir')) {
+ directorLanding = urlParams.get('director') || urlParams.get('dir') || null;
+ if (directorLanding === null) {
+ directorLanding = true;
+ } else if (directorLanding.length === 0) {
+ directorLanding = true;
+ } else {
+ directorLanding = false;
+ }
+ session.meterStyle = 1;
+} else if (filename === "director") {
+ directorLanding = true;
+ filename = false;
+ session.meterStyle = 1;
+}
+
+if (urlParams.has('rooms')) {
+ session.rooms = urlParams.get('rooms').split(",").map(function(e) {
+ return sanitizeRoomName(e);
+ });
+ getById("rooms").classList.remove('advanced');
+}
+
+if (urlParams.has('showdirector')) {
+ session.showDirector = true;
+}
+
+if (urlParams.has('midi') || urlParams.has('hotkeys')) {
+ session.midiHotkeys = urlParams.get('midi') || urlParams.get ('hotkeys') || 1;
+ session.midiHotkeys = parseInt(session.midiHotkeys);
+}
+
+if (urlParams.has('midipush') || urlParams.has('midiout') || urlParams.has('mo')){
+ session.midiOut = urlParams.get('midipush') || urlParams.get('midiout') || urlParams.get('mo') || true;
+}
+
+if (urlParams.has('midipull') || urlParams.has('midiin') || urlParams.has('mi')){
+ session.midiIn = urlParams.get('midipull') || urlParams.get('midiin') || urlParams.get('mi') || true;
+}
+
+var loadedQRCode = false;
+function loadQR(){
+ if (loadedQRCode==false){
+ loadedQRCode=true;
+ var script = document.createElement('script');
+ script.src = "./thirdparty/qrcode.min.js"; // dynamically load this only if its needed. Keeps loading time down.
+ document.head.appendChild(script);
+ }
+}
+
+if (urlParams.has('webcam') || urlParams.has('wc')) {
+ session.webcamonly = true;
+ screensharebutton = false;
+} else if (urlParams.has('screenshare') || urlParams.has('ss')) {
+ session.screenshare = true;
+} else if (urlParams.has('fileshare') || urlParams.has('fs')) {
+ getById("container-5").classList.remove('advanced');
+ getById("container-5").classList.add("skip-animation");
+ getById("container-5").classList.remove('pointer');
+} else if (directorLanding) {
+ getById("container-1").classList.remove('advanced');
+ getById("container-1").classList.add("skip-animation");
+ getById("container-1").classList.remove('pointer');
+} else if (urlParams.has('website') || urlParams.has('iframe')) {
+ getById("container-6").classList.remove('advanced');
+ getById("container-6").classList.add("skip-animation");
+ getById("container-6").classList.remove('pointer');
+ session.website = urlParams.get('website') || urlParams.get('iframe') || false;
+
+ if (session.website){
+ if (session.director){
+ setTimeout(function(){shareWebsite(session.website);},100);
+ } else {
+ setTimeout(function(){session.publishIFrame(session.website);},100);
+
+ }
+ }
+}
+
+
+if (urlParams.has('ssb')) {
+ screensharebutton = true;
+}
+
+if (urlParams.has('mute') || urlParams.has('muted') || urlParams.has('m')) {
+ session.muted = true;
+}
+
+if (urlParams.has('videomute') || urlParams.has('videomuted') || urlParams.has('vm')) {
+ session.videoMutedFlag = true;
+}
+
+
+if (urlParams.has('deaf') || urlParams.has('deafen')) {
+ session.directorSpeakerMuted=true; // false == true in this case.
+}
+
+if (urlParams.has('blind')) {
+ session.directorDisplayMuted=true; // false == true in this case.
+}
+
+
+if (urlParams.has('dpi') || urlParams.has('dpr')) {
+ session.devicePixelRatio = urlParams.get('dpi') || urlParams.get('dpr') || 2.0;
+} //else if (window.devicePixelRatio && window.devicePixelRatio!==1){
+// session.devicePixelRatio = window.devicePixelRatio; // this annoys me to no end.
+//}
+
+if (urlParams.has('speakermute') || urlParams.has('mutespeaker') || urlParams.has('sm') || urlParams.has('ms')) {
+ session.speakerMuted = true;
+ getById("mutespeakertoggle").className = "las la-volume-mute my-float toggleSize";
+ //getById("mutespeakerbutton").className="advanced float2 red";
+ getById("mutespeakerbutton").classList.add("red");
+ getById("mutespeakerbutton").classList.add("float2");
+ getById("mutespeakerbutton").classList.remove("float");
+
+ var sounds = document.getElementsByTagName("video");
+ for (var i = 0; i < sounds.length; ++i) {
+ sounds[i].muted = session.speakerMuted;
+ }
+}
+
+if (urlParams.has('chatbutton') || urlParams.has('chat') || urlParams.has('cb')) {
+ session.chatbutton = urlParams.get('chatbutton') || urlParams.get('chat') || urlParams.get('cb') || null;
+ if (session.chatbutton === "false") {
+ session.chatbutton = false;
+ } else if (session.chatbutton === "0") {
+ session.chatbutton = false;
+ } else if (session.chatbutton === "no") {
+ session.chatbutton = false;
+ } else if (session.chatbutton === "off") {
+ session.chatbutton = false;
+ } else {
+ session.chatbutton = true;
+ getById("chatbutton").classList.remove("advanced");
+ getById("controlButtons").style.display = "inherit";
+ }
+}
+
+if (session.screenshare == true) {
+ getById("container-3").className = 'column columnfade advanced'; // Hide screen share on mobile
+ getById("container-2").classList.add("skip-animation");
+ getById("container-2").classList.remove('pointer');
+}
+
+if (urlParams.has('manual')) {
+ session.manual = true;
+}
+
+if (urlParams.has('hands') || urlParams.has('hand')) {
+ session.raisehands = true;
+}
+
+if (urlParams.has('portrait') || urlParams.has('916') || urlParams.has('vertical')) {
+ session.aspectratio = 1; // 9:16 (default of 0 is 16:9)
+} else if (urlParams.has('square') || urlParams.has('11')) {
+ session.aspectratio = 2; //1:1 ?
+}
+
+if (urlParams.has('cover')) {
+ session.cover = true;
+ document.documentElement.style.setProperty('--fit-style', 'cover');
+}
+
+if (urlParams.has('record')) {
+ if (safariVersion()) {
+ if (!(session.cleanOutput)) {
+ warnUser("Your browser or device is not supported. Try Chrome if on macOS.");
+ }
+ } else {
+ session.recordLocal = urlParams.get('record');
+
+ if (session.recordLocal !== parseInt(session.recordLocal)) {
+ session.recordLocal = 6000;
+ } else {
+ session.recordLocal = parseInt(session.recordLocal);
+ }
+ }
+}
+if (urlParams.has('pcm')) {
+ session.pcm = true;
+}
+
+if (urlParams.has('bigbutton')) {
+ session.bigmutebutton = true;
+ getById("mutebutton").style.width = "min(40vh,40vw)";
+ getById("mutebutton").style.height = "min(40vh,40vw)";
+ getById("mutetoggle").style.width = "min(40vh,40vw)";
+ getById("mutetoggle").style.height = "min(40vh,40vw)";
+
+}
+
+if (urlParams.has('scene')) {
+ session.scene = urlParams.get('scene') || 0;
+ if (typeof session.scene === "string"){
+ session.scene = session.scene.replace(/[\W]+/g, "_");
+ } else {
+ session.scene = (parseInt(session.scene) || 0) + "";
+
+ }
+ session.disableWebAudio = true;
+ session.audioEffects = false;
+ session.audioMeterGuest = false;
+}
+if (session.scene!=="1"){ // scene =0 and 1 should load instantly.
+ session.hiddenSceneViewBitrate = 0; // By default this is ~ 400kbps, but if you have 10 scenes, i don't want to kill things.
+}
+
+if (urlParams.has('scenetype') || urlParams.has('type')) {
+ session.sceneType = parseInt(urlParams.get('scenetype')) || parseInt(urlParams.get('type')) || false;
+}
+
+if (urlParams.has('mediasettings')) {
+ session.forceMediaSettings = true;
+}
+
+
+if (urlParams.has('transcript') || urlParams.has('transcribe') || urlParams.has('trans')) {
+ session.transcript = urlParams.get('transcript') || urlParams.get('transcribe') || urlParams.get('trans') || "en-US";
+}
+
+
+if (urlParams.has('cc') || urlParams.has('closedcaptions') || urlParams.has('captions')) {
+ session.closedCaptions = true;
+}
+
+if (session.webcamonly == true) {
+ getById("container-2").className = 'column columnfade advanced'; // Hide screen share on mobile
+ getById("container-3").classList.add("skip-animation");
+ getById("container-3").classList.remove('pointer');
+ setTimeout(function() {
+ previewWebcam();
+ }, 100);
+}
+
+if (urlParams.has('css')){
+ var cssURL = urlParams.get('css');
+ cssURL = decodeURI(cssURL);
+ log(cssURL);
+ var cssStylesheet = document.createElement('link');
+ cssStylesheet.rel = 'stylesheet';
+ cssStylesheet.type = 'text/css';
+ cssStylesheet.media = 'screen';
+ cssStylesheet.href = cssURL;
+ document.getElementsByTagName('head')[0].appendChild(cssStylesheet);
+
+ cssStylesheet.onload = function() {
+ getById("main").classList.remove('hidden');
+ log("loaded remote style sheet");
+ };
+
+ cssStylesheet.onerror = function() {
+ getById("main").classList.remove('hidden');
+ errorlog("REMOTE STYLE SHEET HAD ERROR");
+ };
+
+} else {
+ getById("main").classList.remove('hidden');
+}
+
+if (urlParams.has('password') || urlParams.has('pass') || urlParams.has('pw') || urlParams.has('p')) {
+ session.password = urlParams.get('password') || urlParams.get('pass') || urlParams.get('pw') || urlParams.get('p');
+ if (!session.password) {
+ window.focus();
+ session.password = prompt("Please enter the password below: \n\n(Note: Passwords are case-sensitive and you will not be alerted if it is incorrect.)");
+ } else if (session.password === "false") {
+ session.password = false;
+ session.defaultPassword = false;
+ } else if (session.password === "0") {
+ session.password = false;
+ session.defaultPassword = false;
+ } else if (session.password === "off") {
+ session.password = false;
+ session.defaultPassword = false;
+ }
+}
+
+if (session.password) {
+ session.password = sanitizePassword(session.password);
+ getById("passwordRoom").value = session.password;
+ session.defaultPassword = false;
+ getById("addPasswordBasic").style.display = "none";
+}
+
+
+if (urlParams.has('hash') || urlParams.has('crc') || urlParams.has('check')) { // could be brute forced in theory, so not as safe as just not using a hash check.
+ session.taintedSession = null; // waiting to see if valid or not.
+ var hash_input = urlParams.get('hash') || urlParams.get('crc') || urlParams.get('check');
+ if (session.password === false) {
+ window.focus();
+ session.password = prompt("Please enter the password below: \n\n(Note: Passwords are case-sensitive.)");
+ session.password = sanitizePassword(session.password);
+ getById("passwordRoom").value = session.password;
+ session.defaultPassword = false;
+ }
+
+ session.generateHash(session.password + session.salt, 6).then(function(hash) { // million to one error.
+ log("hash is " + hash);
+ if (hash.substring(0, 4) !== hash_input) { // hash crc checks are just first 4 characters.
+ session.taintedSession = true;
+ if (!(session.cleanOutput)) {
+ getById("request_info_prompt").innerHTML = "The password was incorrect.\n\nRefresh and try again.";
+ getById("request_info_prompt").style.display = "block";
+ getById("mainmenu").style.display = "none";
+ getById("head1").style.display = "none";
+ session.cleanOutput = true;
+
+ } else {
+ getById("request_info_prompt").innerHTML = "";
+ getById("request_info_prompt").style.display = "block";
+ getById("mainmenu").style.display = "none";
+ getById("head1").style.display = "none";
+ }
+ } else {
+ session.taintedSession = false;
+ session.hash = hash;
+ }
+ });
+}
+
+if (session.defaultPassword !== false) {
+ session.password = session.defaultPassword; // no user entered password; let's use the default password if its not disabled.
+}
+
+if (urlParams.has('showlabels') || urlParams.has('showlabel') || urlParams.has('sl')) {
+ session.showlabels = urlParams.get('showlabels') || urlParams.get('showlabel') || urlParams.get('sl') || "";
+ session.showlabels = sanitizeLabel(session.showlabels.replace(/[\W]+/g, "_").replace(/_+/g, '_'));
+ if (session.showlabels == "") {
+ session.showlabels = true;
+ session.labelstyle = false;
+ } else {
+ session.labelstyle = session.showlabels;
+ session.showlabels = true;
+ }
+}
+
+if (urlParams.has('sizelabel') || urlParams.has('labelsize') || urlParams.has('fontsize')) {
+ session.labelsize = urlParams.get('sizelabel') || urlParams.get('labelsize') || urlParams.get('fontsize') || 100;
+ session.labelsize = parseInt(session.labelsize);
+}
+
+if (urlParams.has('label') || urlParams.has('l')) {
+ session.label = urlParams.get('label') || urlParams.get('l') || null;
+ var updateURLAsNeed = true;
+ if (session.label == null || session.label.length == 0) {
+ window.focus();
+ session.label = prompt("Please enter your display name:");
+ } else {
+ var updateURLAsNeed = false;
+ session.label = decodeURIComponent(session.label);
+ session.label = session.label.replace(/_/g, " ")
+ }
+ if (session.label != null) {
+ session.label = sanitizeLabel(session.label); // alphanumeric was too strict.
+ document.title = session.label; // what the result is.
+
+ if (updateURLAsNeed) {
+ var label = encodeURIComponent(session.label);
+ if (urlParams.has('l')) {
+ updateURL("l=" + label, true, false);
+ } else {
+ updateURL("label=" + label, true, false);
+ }
+ }
+ }
+}
+
+if (urlParams.has('transparent')) { // sets the window to be transparent - useful for IFRAMES?
+ getById("main").style.backgroundColor = "rgba(0,0,0,0)";
+ document.documentElement.style.setProperty('--container-color', '#0000');
+ document.documentElement.style.setProperty('--background-color', '#0000');
+ document.documentElement.style.setProperty('--regular-margin', '0');
+ document.documentElement.style.setProperty('--director-margin', '0 25px 0 0');
+ getById("directorLinksButton").style.color = "black";
+ session.transparent=true;
+}
+
+if (urlParams.has('stereo') || urlParams.has('s') || urlParams.has('proaudio')) { // both peers need this enabled for HD stereo to be on. If just pub, you get no echo/noise cancellation. if just viewer, you get high bitrate mono
+ log("STEREO ENABLED");
+ session.stereo = urlParams.get('stereo') || urlParams.get('s') || urlParams.get('proaudio');
+
+ if (session.stereo) {
+ session.stereo = session.stereo.toLowerCase();
+ }
+
+ //var supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
+ //supportedConstraints.channelCount;
+
+ if (session.stereo === "false") {
+ session.stereo = 0;
+ session.audioInputChannels = 1;
+ } else if (session.stereo === "0") {
+ session.stereo = 0;
+ session.audioInputChannels = 1;
+ } else if (session.stereo === "no") {
+ session.stereo = 0;
+ session.audioInputChannels = 1;
+ } else if (session.stereo === "off") {
+ session.stereo = 0;
+ session.audioInputChannels = 1;
+
+ } else if (session.stereo === "1") {
+ session.stereo = 1;
+ } else if (session.stereo === "both") {
+ session.stereo = 1;
+ } else if (session.stereo === "3") {
+ session.stereo = 3;
+ } else if (session.stereo === "out") {
+ session.stereo = 3;
+ } else if (session.stereo === "mono") {
+ session.stereo = 3;
+ session.audiobitrate = 128;
+ } else if (session.stereo === "4") {
+ session.stereo = 4;
+ } else if (session.stereo === "multi") {
+ session.stereo = 4;
+ } else if (session.stereo === "2") {
+ session.stereo = 2;
+ } else if (session.stereo === "in") {
+ session.stereo = 2;
+ } else {
+ session.stereo = 5; // guests; no stereo in, no high bitrate in, but otherwise like stereo=1
+ }
+}
+
+
+if (urlParams.has('pie')){
+ session.pie = urlParams.get('pie') || false; // If session.pie == true, then there is no need to set parameters via URL
+ if (session.pie){
+ session.wss = "wss://us-nyc-1.websocket.me/v3/1?api_key="+session.pie; // if URL param is set, it will use the API key.
+ }
+}
+
+if ((session.stereo == 1) || (session.stereo == 3) || (session.stereo == 4) || (session.stereo == 5)) {
+ session.echoCancellation = false;
+ session.autoGainControl = false;
+ session.noiseSuppression = false;
+}
+
+if (urlParams.has('mono')) {
+ session.mono = true;
+ if ((session.stereo == 1) || (session.stereo == 4)) {
+ session.stereo = 3;
+ session.audiobitrate = 128;
+ } else if (session.stereo == 5) {
+ session.stereo = 3;
+ session.audiobitrate = 128;
+ } else if (session.stereo == 2) {
+ session.stereo = 0;
+ session.audiobitrate = 128;
+ }
+}
+
+if (urlParams.has("channelcount") || urlParams.has("ac")) {
+ session.audioInputChannels = urlParams.get('channelcount') || urlParams.get('ac');
+ session.audioInputChannels = parseInt(session.audioInputChannels);
+ if (!session.audioInputChannels) {
+ session.audioInputChannels = false;
+ }
+}
+
+
+if (urlParams.has("aec") || urlParams.has("ec")) {
+
+ session.echoCancellation = urlParams.get('aec') || urlParams.get('ec');
+
+ if (session.echoCancellation) {
+ session.echoCancellation = session.echoCancellation.toLowerCase();
+ }
+ if (session.echoCancellation == "false") {
+ session.echoCancellation = false;
+ } else if (session.echoCancellation == "0") {
+ session.echoCancellation = false;
+ } else if (session.echoCancellation == "no") {
+ session.echoCancellation = false;
+ } else if (session.echoCancellation == "off") {
+ session.echoCancellation = false;
+ } else {
+ session.echoCancellation = true;
+ }
+}
+
+
+if (urlParams.has("autogain") || urlParams.has("ag")) {
+
+ session.autoGainControl = urlParams.get('autogain') || urlParams.get('ag');
+ if (session.autoGainControl) {
+ session.autoGainControl = session.autoGainControl.toLowerCase();
+ }
+ if (session.autoGainControl == "false") {
+ session.autoGainControl = false;
+ } else if (session.autoGainControl == "0") {
+ session.autoGainControl = false;
+ } else if (session.autoGainControl == "no") {
+ session.autoGainControl = false;
+ } else if (session.autoGainControl == "off") {
+ session.autoGainControl = false;
+ } else {
+ session.autoGainControl = true;
+ }
+}
+
+if (urlParams.has("denoise") || urlParams.has("dn")) {
+
+ session.noiseSuppression = urlParams.get('denoise') || urlParams.get('dn');
+
+ if (session.noiseSuppression) {
+ session.noiseSuppression = session.noiseSuppression.toLowerCase();
+ }
+ if (session.noiseSuppression == "false") {
+ session.noiseSuppression = false;
+ } else if (session.noiseSuppression == "0") {
+ session.noiseSuppression = false;
+ } else if (session.noiseSuppression == "no") {
+ session.noiseSuppression = false;
+ } else if (session.noiseSuppression == "off") {
+ session.noiseSuppression = false;
+ } else {
+ session.noiseSuppression = true;
+ }
+}
+
+
+if (urlParams.has('roombitrate') || urlParams.has('roomvideobitrate') || urlParams.has('rbr')) {
+ log("Room BITRATE SET");
+ session.roombitrate = urlParams.get('roombitrate') || urlParams.get('rbr') || urlParams.get('roomvideobitrate');
+ session.roombitrate = parseInt(session.roombitrate);
+ if (session.roombitrate < 1) {
+ session.roombitrate = 0;
+ }
+}
+
+if ( urlParams.has('outboundaudiobitrate') || urlParams.has('oab')) {
+ session.outboundAudioBitrate = parseInt(urlParams.get('outboundaudiobitrate')) || parseInt(urlParams.get('oab')) || false;
+}
+if (urlParams.has('outboundvideobitrate') || urlParams.has('ovb')) {
+ session.outboundVideoBitrate = parseInt(urlParams.get('outboundvideobitrate')) || parseInt(urlParams.get('ovb')) || false;
+}
+
+if (urlParams.has('webp')){
+ session.webp = true;
+}
+
+if (urlParams.has('webpquality') || urlParams.has('webpq') || urlParams.has('wq')){
+ session.webPquality = parseInt(urlParams.get('webpquality')) || parseInt(urlParams.get('webpq')) || parseInt(urlParams.get('wq')) || 4;
+}
+
+
+if (urlParams.has('audiobitrate') || urlParams.has('ab')) { // both peers need this enabled for HD stereo to be on. If just pub, you get no echo/noise cancellation. if just viewer, you get high bitrate mono
+ log("AUDIO BITRATE SET");
+ session.audiobitrate = urlParams.get('audiobitrate') || urlParams.get('ab');
+ session.audiobitrate = parseInt(session.audiobitrate);
+ if (session.audiobitrate < 1) {
+ session.audiobitrate = false;
+ } else if (session.audiobitrate > 510) {
+ session.audiobitrate = 510;
+ } // this is to just prevent abuse
+}
+if ((iOS) || (iPad)) {
+ session.audiobitrate = false; // iOS devices seem to get distortion with custom audio bitrates. Disable for now.
+}
+
+/* if (urlParams.has('whitebalance') || urlParams.has('temp')){ // Need to be applied after the camera is selected. bleh. not enforcible. remove for now.
+ var temperature = urlParams.get('whitebalance') || urlParams.get('temp');
+ try{
+ updateCameraConstraints('colorTemperature', parseFloat(temperature));
+ } catch (e){errorlog(e);}
+} */
+
+if (urlParams.has('streamid') || urlParams.has('view') || urlParams.has('v') || urlParams.has('pull')) { // the streams we want to view; if set, but let blank, we will request no streams to watch.
+ session.view = urlParams.get('streamid') || urlParams.get('view') || urlParams.get('v') || urlParams.get('pull') || null; // this value can be comma seperated for multiple streams to pull
+
+ getById("headphonesDiv2").style.display = "inline-block";
+ getById("headphonesDiv").style.display = "inline-block";
+ getById("addPasswordBasic").style.display = "none";
+
+ if (session.view == null) {
+ session.view = "";
+ }
+ if (session.view) {
+ if (session.view.split(",").length > 1) {
+ session.view_set = session.view.split(",");
+ }
+ }
+}
+
+//if (urlParams.has('directorview') || urlParams.has('dv')){
+// session.directorView = true;
+// if (!session.view){
+// session.view = true;
+// }
+//}
+
+if (urlParams.has('nopreview') || urlParams.has('np')) {
+ log("preview OFF");
+ session.nopreview = true;
+} else if ((urlParams.has('preview')) || (urlParams.has('showpreview'))) {
+ log("preview ON");
+ session.nopreview = false;
+} else if ((urlParams.has('minipreview')) || (urlParams.has('mini'))) {
+ var mini = urlParams.has('minipreview') || urlParams.has('mini') || true; // 2 is a valid option.
+ log("preview ON");
+ session.nopreview = false;
+ session.minipreview = mini;
+}
+
+if (urlParams.has('obsfix')) {
+ session.obsfix = urlParams.get('obsfix');
+ if (session.obsfix) {
+ session.obsfix = session.obsfix.toLowerCase();
+ }
+ if (session.obsfix == "false") {
+ session.obsfix = false;
+ } else if (session.obsfix == "0") {
+ session.obsfix = false;
+ } else if (session.obsfix == "no") {
+ session.obsfix = false;
+ } else if (session.obsfix == "off") {
+ session.obsfix = false;
+ } else if (parseInt(session.obsfix) > 0) {
+ session.obsfix = parseInt(session.obsfix);
+ } else {
+ session.obsfix = 1; // aggressive.
+ }
+}
+
+if (urlParams.has('controlroombitrate') || urlParams.has('crb')) {
+ session.controlRoomBitrate = true;
+}
+
+if (urlParams.has('remote') || urlParams.has('rem')) {
+ log("remote ENABLED");
+ session.remote = urlParams.get('remote') || urlParams.get('rem') || "nosecurity";
+ session.remote = session.remote.trim();
+}
+
+if (urlParams.has('latency') || urlParams.has('al') || urlParams.has('audiolatency')) {
+ log("latency ENABLED");
+ session.audioLatency = urlParams.get('latency') || urlParams.get('al') || urlParams.get('audiolatency');
+ session.audioLatency = parseInt(session.audioLatency) || 0;
+ session.disableWebAudio = false;
+}
+
+
+
+if (urlParams.has('micdelay') || urlParams.has('delay') || urlParams.has('md')) {
+ log("audio gain ENABLED");
+ session.micDelay = urlParams.get('micdelay') || urlParams.get('delay') || urlParams.get('md');
+ session.micDelay = parseInt(session.micDelay) || 0;
+ session.disableWebAudio = false;
+}
+
+if (urlParams.has('tips')){
+ getById("guestTips").style.display="flex";
+}
+
+if (urlParams.has('audiogain') || urlParams.has('gain') || urlParams.has('g')) {
+ log("audio gain ENABLED");
+ session.audioGain = urlParams.get('audiogain') || urlParams.get('gain') || urlParams.get('g');
+ session.audioGain = parseInt(session.audioGain) || 0;
+ session.disableWebAudio = false;
+}
+if (urlParams.has('compressor') || urlParams.has('comp')) {
+ log("audio gain ENABLED");
+ session.compressor = 1;
+ session.disableWebAudio = false;
+} else if (urlParams.has('limiter')) {
+ log("audio gain ENABLED");
+ session.compressor = 2;
+ session.disableWebAudio = false;
+}
+if ((urlParams.has('equalizer')) || (urlParams.has('eq'))) {
+ session.equalizer = true;
+ session.disableWebAudio = false;
+}
+if ((urlParams.has('lowcut')) || (urlParams.has('lc')) || (urlParams.has('higpass'))) {
+ session.lowcut = urlParams.get('lowcut') || urlParams.get('lc') || urlParams.get('higpass') || 100;
+ session.lowcut = parseInt(session.lowcut);
+ session.disableWebAudio = false;
+}
+
+if (urlParams.has('pip')) {
+ session.pip = true; // togglePip
+ //session.manual=true;
+ //innerHTML =
+}
+
+if (urlParams.has('keyframeinterval') || urlParams.has('keyframerate') || urlParams.has('keyframe') || urlParams.has('fki')) {
+ log("keyframerate ENABLED");
+ session.keyframerate = parseInt(urlParams.get('keyframeinterval') || urlParams.get('keyframerate') || urlParams.get('keyframe') || urlParams.get('fki')) || 0;
+}
+
+if (urlParams.has('tallyoff') || urlParams.has('obsoff') || urlParams.has('oo')) {
+ log("OBS feedback disabled");
+ session.disableOBS = true;
+}
+
+
+if (urlParams.has('chroma')) {
+ log("Chroma ENABLED");
+ getById("main").style.backgroundColor = "#" + (urlParams.get('chroma') || "0F0");
+}
+
+if (urlParams.has('margin')) {
+ if (urlParams.get('margin') || 10){
+ try {
+ var videoMargin = urlParams.get('margin') || 10;
+ videoMargin = parseInt(videoMargin);
+ videoMargin+="px";
+ document.querySelector(':root').style.setProperty('--video-margin', videoMargin);
+ } catch(e){errorlog("variable css failed");}
+ }
+}
+
+if (urlParams.has('fadein')) {
+ if (urlParams.get('fadein') || 0){
+ try {
+ var fadeinspeed = parseInt(urlParams.get('fadein') || 0)/1000.0;
+ fadeinspeed+="s";
+ document.querySelector(':root').style.setProperty('--fadein-speed', fadeinspeed);
+ } catch(e){errorlog("variable css failed");}
+ } else {
+ try {
+ var fadeinspeed = 0.5;
+ fadeinspeed+="s";
+ document.querySelector(':root').style.setProperty('--fadein-speed', fadeinspeed);
+ } catch(e){errorlog("variable css failed");}
+ }
+}
+
+
+if (urlParams.has("videodevice") || urlParams.has("vdevice") || urlParams.has('vd') || urlParams.has('device') || urlParams.has('d')) {
+
+ session.videoDevice = urlParams.get("videodevice") || urlParams.get("vdevice") || urlParams.get("vd") || urlParams.get("device") || urlParams.get("d");
+
+ if (session.videoDevice === null) {
+ session.videoDevice = "1";
+ } else if (session.videoDevice) {
+ session.videoDevice = session.videoDevice.toLowerCase().replace(/[\W]+/g, "_");
+ }
+ if (session.videoDevice == "false") {
+ session.videoDevice = 0;
+ } else if (session.videoDevice == "0") {
+ session.videoDevice = 0;
+ } else if (session.videoDevice == "no") {
+ session.videoDevice = 0;
+ } else if (session.videoDevice == "off") {
+ session.videoDevice = 0;
+ } else if (session.videoDevice == "snapcam") {
+ session.videoDevice = "snap_camera";
+ } else if (session.videoDevice == "canon") {
+ session.videoDevice = "eos";
+ } else if (session.videoDevice == "camlink") {
+ session.videoDevice = "cam_link";
+ } else if (session.videoDevice == "ndi") {
+ session.videoDevice = "newtek_ndi_video";
+ } else if (session.videoDevice == "") {
+ session.videoDevice = 1;
+ } else if (session.videoDevice == "1") {
+ session.videoDevice = 1;
+ } else if (session.videoDevice == "default") {
+ session.videoDevice = 1;
+ } else {
+ // whatever the user entered I guess, santitized.
+ session.videoDevice = session.videoDevice.replace(/[\W]+/g, "_").toLowerCase();
+ }
+
+ if (session.videoDevice === 0) {
+ getById("add_camera").innerHTML = "Share your Microphone";
+ miniTranslate(getById("add_camera"), "share-your-mic");
+ }
+
+ getById("videoMenu").style.display = "none";
+ log("session.videoDevice:" + session.videoDevice);
+}
+
+// audioDevice
+if (urlParams.has('audiodevice') || urlParams.has('adevice') || urlParams.has('ad') || urlParams.has('device') || urlParams.has('d')) {
+
+ session.audioDevice = urlParams.get("audiodevice") || urlParams.get("adevice") || urlParams.get("ad") || urlParams.get("device") || urlParams.get("d");
+
+ if (session.audioDevice === null) {
+ session.audioDevice = "1";
+ } else if (session.audioDevice) {
+ session.audioDevice = session.audioDevice.toLowerCase().replace(/[\W]+/g, "_");
+ }
+
+ if (session.audioDevice == "false") {
+ session.audioDevice = 0;
+ } else if (session.audioDevice == "0") {
+ session.audioDevice = 0;
+ } else if (session.audioDevice == "no") {
+ session.audioDevice = 0;
+ } else if (session.audioDevice == "off") {
+ session.audioDevice = 0;
+ } else if (session.audioDevice == "") {
+ session.audioDevice = 1;
+ } else if (session.audioDevice == "1") {
+ session.audioDevice = 1;
+ } else if (session.audioDevice == "default") {
+ session.audioDevice = 1;
+ } else if (session.audioDevice == "ndi") {
+ session.audioDevice = "line_newtek_ndi_audio";
+ } else {
+ // whatever the user entered I guess
+ session.audioDevice = session.audioDevice.replace(/[\W]+/g, "_").toLowerCase();
+ }
+
+
+ if (session.videoDevice === 0) {
+ if (session.audioDevice === 0) {
+ getById("add_camera").innerHTML = "Click Start to Join";
+ miniTranslate(getById("add_camera"), "click-start-to-join");
+ getById("container-2").className = 'column columnfade advanced'; // Hide screen share on mobile
+ getById("container-3").classList.add("skip-animation");
+ getById("container-3").classList.remove('pointer');
+ setTimeout(function() {
+ previewWebcam();
+ }, 100);
+ session.webcamonly = true;
+ }
+ }
+
+ log("session.audioDevice:" + session.audioDevice);
+
+ getById("audioMenu").style.display = "none";
+ getById("headphonesDiv").style.display = "none";
+ getById("headphonesDiv2").style.display = "none";
+ getById("audioScreenShare1").style.display = "none";
+
+}
+
+
+if (urlParams.has('autojoin') || urlParams.has('autostart') || urlParams.has('aj') || urlParams.has('as')) {
+ session.autostart = true;
+ if (session.screenshare) {
+ setTimeout(function() {
+ publishScreen();
+ }, 2000);
+ }
+}
+
+if (urlParams.has('noiframe') || urlParams.has('noiframes') || urlParams.has('nif')) {
+
+ session.noiframe = urlParams.get('noiframe') || urlParams.get('noiframes') || urlParams.get('nif');
+
+ if (!(session.noiframe)) {
+ session.noiframe = [];
+ } else {
+ session.noiframe = session.noiframe.split(",");
+ }
+ log("disable iframe playback");
+ log(session.noiframe);
+}
+
+
+if (urlParams.has('exclude') || urlParams.has('ex')) {
+
+ session.exclude = urlParams.get('exclude') || urlParams.get('ex');
+
+ if (!(session.exclude)) {
+ session.exclude = false;
+ } else {
+ session.exclude = session.exclude.split(",");
+ }
+ log("exclude video playback");
+ log(session.exclude);
+}
+
+
+if (urlParams.has('novideo') || urlParams.has('nv') || urlParams.has('hidevideo') || urlParams.has('showonly')) {
+
+ session.novideo = urlParams.get('novideo') || urlParams.get('nv') || urlParams.get('hidevideo') || urlParams.get('showonly');
+
+ if (!(session.novideo)) {
+ session.novideo = [];
+ } else {
+ session.novideo = session.novideo.split(",");
+ }
+ log("disable video playback");
+ log(session.novideo);
+}
+
+if (urlParams.has('noaudio') || urlParams.has('na') || urlParams.has('hideaudio')) {
+
+ session.noaudio = urlParams.get('noaudio') || urlParams.get('na') || urlParams.get('hideaudio');
+
+ if (!(session.noaudio)) {
+ session.noaudio = [];
+ } else {
+ session.noaudio = session.noaudio.split(",");
+ }
+ log("disable audio playback");
+}
+
+if (urlParams.has('forceios')) {
+ log("allow iOS to work in video group chat; for this user at least");
+ session.forceios = true;
+}
+
+if (urlParams.has('nocursor')) {
+ session.nocursor = true;
+ log("DISABLE CURSOR");
+ var style = document.createElement('style');
+ style.innerHTML = `
+ video {
+ margin: 0;
+ padding: 0;
+ overflow: hidden;
+ cursor: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=), none;
+ user-select: none;
+ }
+ `;
+ document.head.appendChild(style);
+
+}
+
+if (urlParams.has('vbr')) {
+ session.cbr = 0;
+}
+
+if (urlParams.has('order')) {
+ session.order = parseInt(urlParams.get('order')) || 0;
+}
+if (urlParams.has('sensors') || urlParams.has('sensor') || urlParams.has('gyro') || urlParams.has('gyros') || urlParams.has('accelerometer')) {
+ session.sensorData = urlParams.get('sensors') || urlParams.get('sensor') || urlParams.get('gyro') || urlParams.get('gyros') || urlParams.get('accelerometer') || 30;
+ session.sensorData = parseInt(session.sensorData);
+}
+
+if (urlParams.has('minptime')) {
+ session.minptime = parseInt(urlParams.get('minptime')) || 10;
+ if (session.minptime < 10) {
+ session.minptime = 10;
+ }
+ if (session.minptime > 300) {
+ session.minptime = 300;
+ }
+}
+
+if (urlParams.has('maxptime')) {
+ session.maxptime = parseInt(urlParams.get('maxptime')) || 60;
+ if (session.maxptime < 10) {
+ session.maxptime = 10;
+ }
+ if (session.maxptime > 300) {
+ session.maxptime = 300;
+ }
+}
+
+if (urlParams.has('ptime')) {
+ session.ptime = parseInt(urlParams.get('ptime')) || 20;
+ if (session.minptime < 10) {
+ session.ptime = 10;
+ }
+ if (session.minptime > 300) {
+ session.ptime = 300;
+ }
+}
+
+
+if (urlParams.has('codec')) {
+ log("CODEC CHANGED");
+ session.codec = urlParams.get('codec').toLowerCase();
+ if (session.codec=="webp"){
+ session.webp = true;
+ session.codec = false;
+ }
+} else if (isOperaGX()){
+ session.codec = "vp8";
+ warnlog("Defaulting to VP8 manually, as H264 with remote iOS devices is not supported");
+}
+
+if (urlParams.has('nonacks')){ // disables error control / throttling.
+ session.noNacks = true;
+}
+if (urlParams.has('nopli')){ // disables error control / throttling.
+ session.noPLIs = true;
+}
+if (urlParams.has('noremb')){ // disables error control / throttling.
+ session.noREMB = true;
+}
+
+if (urlParams.has('scale')) {
+ if (urlParams.get('scale') == "false") {} else if (urlParams.get('scale') == "0") {} else if (urlParams.get('scale') == "no") {} else if (urlParams.get('scale') == "off") {} else {
+ log("Resolution scale requested");
+ session.scale = parseInt(urlParams.get('scale')) || 100;
+ }
+ session.dynamicScale = false; // default true
+}
+
+var ConfigSettings = getById("main-js");
+var ln_template = false;
+var translation = false;
+try {
+ if (ConfigSettings) {
+ ln_template = ConfigSettings.getAttribute('data-translation'); // Translations
+ if (typeof ln_template === "undefined") {
+ ln_template = false;
+ } else if (ln_template === null) {
+ ln_template = false;
+ }
+ }
+
+ if (urlParams.has('ln')) {
+ ln_template = urlParams.get('ln');
+ }
+} catch (e) {
+ errorlog(e);
+}
+
+if (ln_template) { // checking if manual lanuage override enabled
+ try {
+ log("Template: " + ln_template);
+ fetch("./translations/" + ln_template + '.json').then(function(response) {
+ if (response.status !== 200) {
+ log('Looks like there was a problem. Status Code: ' +
+ response.status);
+ return;
+ }
+ response.json().then(function(data) {
+ log(data);
+ translation = data;
+ var trans = data.innerHTML;
+ var allItems = document.querySelectorAll('[data-translate]');
+ allItems.forEach(function(ele) {
+ if (ele.dataset.translate in trans) {
+ ele.innerHTML = trans[ele.dataset.translate];
+ }
+ });
+ trans = data.titles;
+ var allTitles = document.querySelectorAll('[title]');
+ allTitles.forEach(function(ele) {
+ var key = ele.title.replace(/[\W]+/g, "-").toLowerCase();
+ if (key in trans) {
+ ele.title = trans[key];
+ }
+ });
+ trans = data.placeholders;
+ var allPlaceholders = document.querySelectorAll('[placeholder]');
+ allPlaceholders.forEach(function(ele) {
+ var key = ele.placeholder.replace(/[\W]+/g, "-").toLowerCase();
+ if (key in trans) {
+ ele.placeholder = trans[key];
+ }
+ });
+
+
+ getById("mainmenu").style.opacity = 1;
+ }).catch(function(err) {
+ errorlog(err);
+ getById("mainmenu").style.opacity = 1;
+ });
+ }).catch(function(err) {
+ errorlog(err);
+ getById("mainmenu").style.opacity = 1;
+ });
+
+ } catch (error) {
+ errorlog(error);
+ getById("mainmenu").style.opacity = 1;
+ }
+} else if (location.hostname !== "obs.ninja") {
+ if (location.hostname === "rtc.ninja"){
+ try {
+ if (session.label === false) {
+ document.title = "";
+ }
+ getById("qos").innerHTML = "";
+ getById("logoname").innerHTML = "";
+ getById("helpbutton").style.display = "none";
+ getById("helpbutton").style.opacity = 0;
+ getById("reportbutton").style.display = "none";
+ getById("reportbutton").style.opacity = 0;
+ getById("mainmenu").style.opacity = 1;
+ getById("mainmenu").style.margin = "30px 0";
+ getById("translateButton").style.display = "none";
+ getById("translateButton").style.opacity = 0;
+ getById("info").style.display = "none";
+ getById("info").style.opacity = 0;
+ getById("chatBody").innerHTML = "";
+ } catch (e) {}
+ }
+ try {
+ fetch("./translations/blank.json").then(function(response) {
+ if (response.status !== 200) {
+ log('Looks like there was a problem. Status Code: ' +
+ response.status);
+ return;
+ }
+ response.json().then(function(data) {
+ log(data);
+
+ var trans = data.innerHTML;
+ var allItems = document.querySelectorAll('[data-translate]');
+ allItems.forEach(function(ele) {
+ if (ele.dataset.translate in trans) {
+ ele.innerHTML = trans[ele.dataset.translate];
+ }
+ });
+ trans = data.titles;
+ var allTitles = document.querySelectorAll('[title]');
+ allTitles.forEach(function(ele) {
+ var key = ele.title.replace(/[\W]+/g, "-").toLowerCase();
+ if (key in trans) {
+ ele.title = trans[key];
+ }
+ });
+ trans = data.placeholders;
+ var allPlaceholders = document.querySelectorAll('[placeholder]');
+ allPlaceholders.forEach(function(ele) {
+ var key = ele.placeholder.replace(/[\W]+/g, "-").toLowerCase();
+ if (key in trans) {
+ ele.placeholder = trans[key];
+ }
+ });
+
+ if (session.label === false) {
+ document.title = location.hostname;
+ }
+ getById("qos").innerHTML = location.hostname;
+ getById("logoname").innerHTML = getById("qos").outerHTML;
+ getById("helpbutton").style.display = "none";
+ getById("reportbutton").style.display = "none";
+ getById("mainmenu").style.opacity = 1;
+ }).catch(function(err) {
+ errorlog(err);
+ getById("mainmenu").style.opacity = 1;
+ });
+ }).catch(function(err) {
+ errorlog(err);
+ getById("mainmenu").style.opacity = 1;
+ });
+ if (session.label === false) {
+ document.title = location.hostname;
+ }
+ getById("qos").innerHTML = location.hostname;
+ getById("logoname").innerHTML = getById("qos").outerHTML;
+ getById("helpbutton").style.display = "none";
+ getById("reportbutton").style.display = "none";
+ getById("chatBody").innerHTML = "";
+ } catch (error) {
+ errorlog(error);
+ }
+} else { // check if automatic language translation is available
+ getById("mainmenu").style.opacity = 1;
+}
+
+try {
+ if (location.hostname === "rtc.ninja"){ // an extra-brand-free version of OBS.Ninja
+ if (session.label === false) {
+ document.title = "";
+ }
+ getById("qos").innerHTML = "";
+ getById("logoname").innerHTML = "";
+ getById("helpbutton").style.display = "none";
+ getById("helpbutton").style.opacity = 0;
+ getById("reportbutton").style.display = "none";
+ getById("reportbutton").style.opacity = 0;
+ getById("mainmenu").style.opacity = 1;
+ getById("mainmenu").style.margin = "30px 0";
+ getById("translateButton").style.display = "none";
+ getById("translateButton").style.opacity = 0;
+ getById("info").style.display = "none";
+ getById("info").style.opacity = 0;
+ getById("chatBody").innerHTML = "";
+ } else if (location.hostname !== "obs.ninja") {
+ if (session.label === false) {
+ document.title = location.hostname;
+ }
+ getById("qos").innerHTML = sanitizeLabel(location.hostname);
+ getById("logoname").innerHTML = getById("qos").outerHTML;
+ getById("helpbutton").style.display = "none";
+ getById("reportbutton").style.display = "none";
+ }
+
+} catch (e) {}
+
+if (isIFrame) {
+ getById("helpbutton").style.display = "none";
+ getById("helpbutton").style.opacity = 0;
+ getById("reportbutton").style.display = "none";
+ getById("reportbutton").style.opacity = 0;
+ getById("chatBody").innerHTML = "";
+}
+
+function miniTranslate(ele, ident = false) {
+ if (ident) {
+ ele.dataset.translate = ident;
+ } else {
+ ident = ele.dataset.translate;
+ }
+ try {
+ if (ident in translation.innerHTML) {
+ ele.innerHTML = translation.innerHTML[ident];
+ }
+ } catch (e) {}
+}
+
+function changeLg(lang) {
+ fetch("./translations/" + lang + '.json').then(function(response) {
+ if (response.status !== 200) {
+ logerror('Language translation file not found.' + response.status);
+ return;
+ }
+ response.json().then(function(data) {
+ log(data);
+ translation = data; // translation.innerHTML[ele.dataset.translate]
+ var trans = data.innerHTML;
+ var allItems = document.querySelectorAll('[data-translate]');
+ allItems.forEach(function(ele) {
+ if (ele.dataset.translate in trans) {
+ ele.innerHTML = trans[ele.dataset.translate];
+ }
+ });
+ trans = data.titles;
+ var allTitles = document.querySelectorAll('[title]');
+ allTitles.forEach(function(ele) {
+ var key = ele.title.replace(/[\W]+/g, "-").toLowerCase();
+ if (key in trans) {
+ ele.title = trans[key];
+ }
+ });
+ trans = data.placeholders;
+ var allPlaceholders = document.querySelectorAll('[placeholder]');
+ allPlaceholders.forEach(function(ele) {
+ var key = ele.placeholder.replace(/[\W]+/g, "-").toLowerCase();
+ if (key in trans) {
+ ele.placeholder = trans[key];
+ }
+ });
+ });
+ }).catch(function(err) {
+ errorlog(err);
+ });
+}
+
+if (urlParams.has('beep') || urlParams.has('notify') || urlParams.has('tone')) {
+ session.beepToNotify = true;
+}
+
+if (urlParams.has('r2d2')) {
+ getById("testtone").innerHTML = "";
+ getById("testtone").src = "./media/robot.mp3";
+ session.beepToNotify = true;
+}
+
+if (urlParams.has('videobitrate') || urlParams.has('bitrate') || urlParams.has('vb')) {
+ session.bitrate = urlParams.get('videobitrate') || urlParams.get('bitrate') || urlParams.get('vb');
+ if (session.bitrate) {
+ if ((session.view_set) && (session.bitrate.split(",").length > 1)) {
+ session.bitrate_set = session.bitrate.split(",");
+ session.bitrate = parseInt(session.bitrate_set[0]);
+ } else {
+ session.bitrate = parseInt(session.bitrate);
+ }
+ if (session.bitrate < 1) {
+ session.bitrate = false;
+ }
+ log("BITRATE ENABLED");
+ log(session.bitrate);
+
+ }
+}
+
+if (urlParams.has('maxvideobitrate') || urlParams.has('maxbitrate') || urlParams.has('mvb')) {
+ session.maxvideobitrate = urlParams.get('maxvideobitrate') || urlParams.get('maxbitrate') || urlParams.get('mvb');
+ session.maxvideobitrate = parseInt(session.maxvideobitrate);
+
+ if (session.maxvideobitrate < 1) {
+ session.maxvideobitrate = false;
+ }
+ log("maxvideobitrate ENABLED");
+ log(session.maxvideobitrate);
+}
+
+if (urlParams.has('totalroombitrate') || urlParams.has('totalroomvideobitrate') || urlParams.has('trb')) {
+ session.totalRoomBitrate = urlParams.get('totalroombitrate') || urlParams.get('totalroomvideobitrate') || urlParams.get('trb');
+ session.totalRoomBitrate = parseInt(session.totalRoomBitrate);
+
+ if (session.totalRoomBitrate < 1) {
+ session.totalRoomBitrate = false;
+ }
+ log("totalRoomBitrate ENABLED");
+ log(session.totalRoomBitrate);
+
+}
+if (session.totalRoomBitrate===false){
+ session.totalRoomBitrate = session.totalRoomBitrate_default;
+} else {
+ session.totalRoomBitrate_default = session.totalRoomBitrate; // trb_default doesn't change dynamically, but trb can (per director I guess)
+}
+
+
+if (urlParams.has('limittotalbitrate') || urlParams.has('ltb')){
+ session.limitTotalBitrate = urlParams.get('limittotalbitrate') || urlParams.get('ltb') || 2500;
+ session.limitTotalBitrate = parseInt(session.limitTotalBitrate);
+}
+
+
+
+if (urlParams.has('height') || urlParams.has('h')) {
+ session.height = urlParams.get('height') || urlParams.get('h');
+ session.height = parseInt(session.height);
+}
+
+if (urlParams.has('width') || urlParams.has('w')) {
+ session.width = urlParams.get('width') || urlParams.get('w');
+ session.width = parseInt(session.width);
+}
+
+if (urlParams.has('quality') || urlParams.has('q')) {
+ try {
+ session.quality = urlParams.get('quality') || urlParams.get('q') || 0;
+ session.quality = parseInt(session.quality);
+ getById("gear_screen").parentNode.removeChild(getById("gear_screen"));
+ getById("gear_webcam").parentNode.removeChild(getById("gear_webcam"));
+ } catch (e) {
+ errorlog(e);
+ }
+}
+
+if (urlParams.has('sink')) {
+ session.sink = urlParams.get('sink');
+} else if (urlParams.has('outputdevice') || urlParams.has('od') || urlParams.has('audiooutput')) {
+ session.outputDevice = urlParams.get('outputdevice') || urlParams.get('od') || urlParams.get('audiooutput') || null;
+
+ if (session.outputDevice) {
+ session.outputDevice = session.outputDevice.toLowerCase().replace(/[\W]+/g, "_");
+ } else {
+ session.outputDevice = null;
+ getById("headphonesDiv3").style.display = "none"; //
+ }
+
+ if (session.outputDevice) {
+ try {
+ enumerateDevices().then(function(deviceInfos) {
+ for (let i = 0; i !== deviceInfos.length; ++i) {
+ if (deviceInfos[i].kind === 'audiooutput') {
+ if (deviceInfos[i].label.replace(/[\W]+/g, "_").toLowerCase().includes(session.outputDevice)) {
+ session.sink = deviceInfos[i].deviceId;
+ log("AUDIO OUT DEVICE: " + deviceInfos[i].deviceId);
+ break;
+ }
+ }
+ }
+ });
+ } catch (e) {}
+ }
+
+ getById("headphonesDiv").style.display = "none";
+ getById("headphonesDiv2").style.display = "none";
+}
+
+if (window.obsstudio || (navigator.userAgent.toLowerCase().indexOf(' electron/') > -1)){
+ session.fullscreen = true;
+} else if (urlParams.has('fullscreen')) {
+ session.fullscreen = true;
+}
+
+if (urlParams.has('stats')) {
+ session.statsMenu = true;
+}
+
+
+if (urlParams.has('cleandirector') || urlParams.has('cdv')) {
+ session.cleanDirector = true;
+}
+
+
+if (session.cleanOutput){
+ getById("translateButton").style.display = "none";
+ getById("credits").style.display = "none";
+ getById("header").style.display = "none";
+ getById("controlButtons").style.display = "none";
+ var style = document.createElement('style');
+ style.innerHTML = `
+ video {
+ background-image: none;
+ }
+ `;
+ document.head.appendChild(style);
+}
+
+if (urlParams.has('cleanish')) {
+ session.cleanish = true;
+}
+
+if (urlParams.has('channels')) { // must be loaded before channelOffset
+ session.audioChannels = parseInt(urlParams.get('channels'));
+ session.offsetChannel = 0;
+ log("max channels is 32; channels offset");
+ session.audioEffects = true;
+}
+if (urlParams.has('channeloffset')) {
+ session.offsetChannel = parseInt(urlParams.get('channeloffset'));
+ log("max channels is 32; channels offset");
+ session.audioEffects = true;
+}
+
+
+
+if (urlParams.has('enhance')) {
+ //if (parseInt(urlParams.get('enhance')>0){
+ session.enhance = true; //parseInt(urlParams.get('enhance'));
+ //}
+}
+
+if (urlParams.has('maxviewers') || urlParams.has('mv')) {
+
+ session.maxviewers = urlParams.get('maxviewers') || urlParams.get('mv');
+ if (session.maxviewers.length == 0) {
+ session.maxviewers = 1;
+ } else {
+ session.maxviewers = parseInt(session.maxviewers);
+ }
+ log("maxviewers set");
+}
+
+if (urlParams.has('maxpublishers') || urlParams.has('mp')) {
+
+ session.maxpublishers = urlParams.get('maxpublishers') || urlParams.get('mp');
+ if (session.maxpublishers.length == 0) {
+ session.maxpublishers = 1;
+ } else {
+ session.maxpublishers = parseInt(session.maxpublishers);
+ }
+ log("maxpublishers set");
+}
+
+if (urlParams.has('maxconnections') || urlParams.has('mc')) {
+
+ session.maxconnections = urlParams.get('maxconnections') || urlParams.get('maxconnections');
+ if (session.maxconnections.length == 0) {
+ session.maxconnections = 1;
+ } else {
+ session.maxconnections = parseInt(session.maxconnections);
+ }
+
+ log("maxconnections set");
+}
+
+
+if (urlParams.has('secure')) {
+ session.security = true;
+ if (!(session.cleanOutput)) {
+ setTimeout(function() {
+ warnUser("Enhanced Security Mode Enabled.");
+ }, 100);
+ }
+}
+
+if (urlParams.has('random') || urlParams.has('randomize')) {
+ session.randomize = true;
+}
+
+if (urlParams.has('framerate') || urlParams.has('fr') || urlParams.has('fps')) {
+ session.framerate = urlParams.get('framerate') || urlParams.get('fr') || urlParams.get('fps');
+ session.framerate = parseInt(session.framerate);
+ log("framerate Changed");
+ log(session.framerate);
+}
+
+if (urlParams.has('maxframerate') || urlParams.has('mfr') || urlParams.has('mfps')) {
+ session.maxframerate = urlParams.get('maxframerate') || urlParams.get('mfr') || urlParams.get('mfps');
+ session.maxframerate = parseInt(session.maxframerate);
+ log("max framerate assigned");
+ log(session.maxframerate);
+}
+
+if (urlParams.has('buffer')) { // needs to be before sync
+ session.buffer = parseFloat(urlParams.get('buffer')) || 0;
+ log("buffer Changed: " + session.buffer);
+ session.sync = 0;
+ session.audioEffects = true;
+}
+
+if (urlParams.has('sync')) {
+ session.sync = parseFloat(urlParams.get('sync'));
+ log("sync Changed; in milliseconds. If not set, defaults to auto.");
+ log(session.sync);
+ session.audioEffects = true;
+ if (session.buffer === false) {
+ session.buffer = 0;
+ }
+}
+
+if (urlParams.has('mirror')) {
+ if (urlParams.get('mirror') == "3") {
+ getById("main").classList.add("mirror");
+ } else if (urlParams.get('mirror') == "2") {
+ session.mirrored = 2;
+ } else if (urlParams.get('mirror') == "0") {
+ session.mirrored = 0;
+ } else if (urlParams.get('mirror') == "false") {
+ session.mirrored = 0;
+ } else if (urlParams.get('mirror') == "off") {
+ session.mirrored = 0;
+ } else {
+ session.mirrored = 1;
+ }
+}
+
+if (urlParams.has('flip')) {
+ if (urlParams.get('flip') == "0") {
+ session.flipped = false;
+ } else if (urlParams.get('flip') == "false") {
+ session.flipped = false;
+ } else if (urlParams.get('flip') == "off") {
+ session.flipped = false;
+ } else {
+ session.flipped = true;
+ }
+}
+
+if ((session.mirrored) && (session.flipped)) {
+ try {
+ log("Mirror all videos");
+ var mirrorStyle = document.createElement('style');
+ mirrorStyle.innerHTML = "video {transform: scaleX(-1) scaleY(-1); }";
+ document.getElementsByTagName("head")[0].appendChild(mirrorStyle);
+ } catch (e) {
+ errorlog(e);
+ }
+} else if (session.mirrored) { // mirror the video horizontally
+ try {
+ log("Mirror all videos");
+ var mirrorStyle = document.createElement('style');
+ mirrorStyle.innerHTML = "video {transform: scaleX(-1);}";
+ document.getElementsByTagName("head")[0].appendChild(mirrorStyle);
+ } catch (e) {
+ errorlog(e);
+ }
+} else if (session.flipped) { // mirror the video vertically
+ try {
+ log("Mirror all videos");
+ var mirrorStyle = document.createElement('style');
+ mirrorStyle.innerHTML = "video {transform: scaleY(-1);}";
+ document.getElementsByTagName("head")[0].appendChild(mirrorStyle);
+ } catch (e) {
+ errorlog(e);
+ }
+}
+
+
+if (urlParams.has('icefilter')) {
+ log("ICE FILTER ENABLED");
+ session.icefilter = urlParams.get('icefilter');
+}
+
+
+if (urlParams.has('effects') || urlParams.has('effect')) {
+ session.effects = urlParams.get('effects') || urlParams.get('effect') || null;
+ if (session.effects === null){
+ getById("effectsDiv").style.display = "block";
+ session.effects = 0;
+ } else if (session.effects === "0" || session.effects === "false" || session.effects === "off"){
+ session.effects = false;
+ getById("effectSelector3").style.display = "none";
+ getById("effectsDiv3").style.display = "none";
+ getById("effectSelector").style.display = "none";
+ getById("effectsDiv").style.display = "none";
+ } else {
+ session.effects = parseInt(session.effects);
+ }
+
+ if (session.effects === 5){
+ getById("selectImageTFLITE").style.display = "block";
+ getById("selectImageTFLITE3").style.display = "block";
+ getById("effectSelector").style.display = "none";
+ getById("effectsDiv").style.display = "block";
+ }
+ // mirror == 2
+ // face == 1
+ // blur = 3
+ // green = 4
+ // image = 5
+}
+
+if (urlParams.has('activespeaker') || urlParams.has('speakerview') || urlParams.has('sas')){
+ session.activeSpeaker = true;
+ session.audioEffects = true;
+ session.audioMeterGuest = true;
+ setInterval(function(){activeSpeaker(false);},100);
+}
+
+if (urlParams.has('meter') || urlParams.has('meterstyle')){
+ session.meterStyle = urlParams.get('meter') || urlParams.get('meterstyle') || 1;
+}
+
+if (urlParams.has('directorchat') || urlParams.has('dc')){
+ session.directorChat = true;
+}
+
+if (urlParams.has('style') || urlParams.has('st')) {
+ session.style = urlParams.get('style') || urlParams.get('st') || 1;
+ if ((parseInt(session.style) == 1) || (session.style == "justvideo")) { // no audio only
+ session.style = 1;
+ } else if ((parseInt(session.style) == 2) || (session.style == "waveform")) { // audio waveform
+ session.style = 2;
+ session.audioEffects = true; ////!!!!!!! Do I want to enable the audioEffects myself? or do it here?
+ } else if ((parseInt(session.style) == 3) || (session.style == "volume")) { // photo is taken? upload option? canvas?
+ session.style = 3;
+ session.audioEffects = true;
+ } else {
+ session.style = 1;
+ }
+}
+
+
+if (urlParams.has('samplerate') || urlParams.has('sr')) {
+ session.sampleRate = parseInt(urlParams.get('samplerate')) || parseInt(urlParams.get('samplerate')) || 48000;
+ if (session.audioCtx) {
+ session.audioCtx.close(); // close the default audio context.
+ }
+ session.audioCtx = new AudioContext({ // create a new audio context with a higher sample rate.
+ sampleRate: session.sampleRate
+ });
+ session.audioEffects = true;
+}
+
+
+if (urlParams.has('noaudioprocessing') || urlParams.has('noap')) {
+ session.disableWebAudio = true; // default true; might be useful to disable on slow or old computers?
+ session.audioEffects = false; // disable audio inbound effects also.
+ session.audioMeterGuest = false;
+}
+
+if (urlParams.has('tcp')){ // forces the TURN servers to use TCP mode; still need to add &private to force TURN also tho
+ session.forceTcpMode = true;
+}
+if (urlParams.has('speedtest')){ // forces essentially UDP mode, unless TCP is specified, and some other stuff
+ session.speedtest = true;
+}
+
+if (urlParams.has('turn')) {
+ var turnstring = urlParams.get('turn');
+ if (turnstring == "twilio") { // a sample function on loading remote credentials for TURN servers.
+ try {
+
+ session.ws = false; // prevents connection
+ var twillioRequest = new XMLHttpRequest();
+ twillioRequest.onreadystatechange = function() {
+ if (twillioRequest.status === 200) {
+ try{
+ var res = JSON.parse(twillioRequest.responseText);
+ } catch(e){return;}
+ session.configuration = {
+ iceServers: [{
+ "username": res["1"],
+ "credential": res["2"],
+ "url": "turn:global.turn.twilio.com:3478?transport=tcp",
+ "urls": "turn:global.turn.twilio.com:3478?transport=tcp"
+ },
+ {
+ "username": res["1"],
+ "credential": res["2"],
+ "url": "turn:global.turn.twilio.com:443?transport=tcp",
+ "urls": "turn:global.turn.twilio.com:443?transport=tcp"
+ }
+ ],
+ sdpSemantics: 'unified-plan' // future-proofing
+ };
+ if (session.ws===false){
+ session.ws=null; // allows connection (clears state)
+ session.connect(); // connect if not already connected.
+ }
+ }
+ // system does not connect if twilio API does not respond.
+ };
+ twillioRequest.open('GET', 'https://api.obs.ninja:1443/twilio', true); // `false` makes the request synchronous
+ twillioRequest.send();
+
+
+ } catch (e) {
+ errorlog("Twilio Failed");
+ }
+ } else if (turnstring == "nostun") { // disable TURN servers
+ session.configuration = {
+ sdpSemantics: 'unified-plan' // future-proofing
+ };
+ } else if ((turnstring == "false") || (turnstring == "off") || (turnstring == "0")) { // disable TURN servers
+ if (!session.configuration){session.configuration={};}
+ session.configuration = {
+ iceServers: [
+ { urls: ["stun:stun.l.google.com:19302", "stun:stun4.l.google.com:19302"]} // more than 4 stun+turn servers will cause firefox issues? (2 + 2 for now then)
+ ],
+ sdpSemantics: 'unified-plan' // future-proofing
+ };
+ } else {
+ try {
+ //session.configuration = {iceServers: [], sdpSemantics: 'unified-plan'};
+ turnstring = turnstring.split(";");
+ if (turnstring !== "false") { // false disables the TURN server. Useful for debuggin
+ var turn = {};
+ turn.username = turnstring[0]; // myusername
+ turn.credential = turnstring[1]; //mypassword
+ turn.urls = [turnstring[2]]; // ["turn:turn.obs.ninja:443"];
+ session.configuration = {
+ iceServers: [
+ { urls: ["stun:stun.l.google.com:19302", "stun:stun4.l.google.com:19302"]} // more than 4 stun+turn servers will cause firefox issues? (2 + 2 for now then)
+ ],
+ sdpSemantics: 'unified-plan' // future-proofing
+ };
+ session.configuration.iceServers.push(turn);
+ }
+ } catch (e) {
+ if (!(session.cleanOutput)) {
+ warnUser("TURN server parameters were wrong.");
+ }
+ errorlog(e);
+ }
+ }
+} else {
+ chooseBestTURN(); // obs.ninja turn servers, if needed.
+}
+
+
+if (urlParams.has('privacy') || urlParams.has('private') || urlParams.has('relay')) { // please only use if you are also using your own TURN service.
+ session.privacy = true;
+
+ try {
+ session.configuration.iceTransportPolicy = "relay"; // https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidate/address
+ } catch (e) {
+ if (!(session.cleanOutput)) {
+ warnUser("Privacy mode failed to configure.");
+ }
+ errorlog(e);
+ }
+
+ if (session.speedtest){
+ if (session.maxvideobitrate !== false) {
+ if (session.maxvideobitrate > 6000) {
+ session.maxvideobitrate = 6000; // Please feel free to get rid of this if using your own TURN servers...
+ }
+ } else {
+ session.maxvideobitrate = 6000; // don't let people pull more than 2500 from you
+ }
+ if (session.bitrate !== false) {
+ if (session.bitrate > 6000) {
+ session.bitrate = 6000; // Please feel free to get rid of this if using your own TURN servers...
+ }
+ }
+ } else {
+ if (session.maxvideobitrate !== false) {
+ if (session.maxvideobitrate > 2500) {
+ session.maxvideobitrate = 2500; // Please feel free to get rid of this if using your own TURN servers...
+ }
+ } else {
+ session.maxvideobitrate = 2500; // don't let people pull more than 2500 from you
+ }
+ if (session.bitrate !== false) {
+ if (session.bitrate > 2500) {
+ session.bitrate = 2500; // Please feel free to get rid of this if using your own TURN servers...
+ }
+ }
+ }
+}
+
+if (urlParams.has('wss')) {
+ if (urlParams.get('wss')) {
+ session.wss = "wss://" + urlParams.get('wss');
+ }
+}
+
+if (urlParams.has('queue')) {
+ session.queue = true;
+}
+
+if (isIFrame) { // reduce CPU load if not needed.
+ window.onmessage = function(e) { // iFRAME support
+ log(e);
+ try {
+ if ("function" in e.data) { // these are calling in-app functions, with perhaps a callback -- TODO: add callbacks
+ var ret = null;
+ if (e.data.function === "previewWebcam") {
+ ret = previewWebcam();
+ } else if (e.data.function === "changeHTML") {
+ ret = getById(e.data.target);
+ ret.innerHTML = e.data.value;
+ } else if (e.data.function === "publishScreen") {
+ ret = publishScreen();
+ } else if (e.data.function === "eval") {
+ eval(e.data.value); // eval == evil ; feedback welcomed
+ }
+ }
+ } catch (err) {
+ errorlog(err);
+ }
+
+ if ("sendChat" in e.data) {
+ sendChat(e.data.sendChat); // sends to all peers; more options down the road
+ }
+ // Chat out gets called via getChatMessage function
+ // Related code: parent.postMessage({"chat": {"msg":-----,"type":----,"time":---} }, "*");
+
+ if ("mic" in e.data) { // this should work for the director's mic mute button as well. Needs to be manually enabled the first time still tho.
+ if (e.data.mic === true) { // unmute
+ session.muted = false; // set
+ log(session.muted);
+ toggleMute(true); // apply
+ } else if (e.data.mic === false) { // mute
+ session.muted = true; // set
+ log(session.muted);
+ toggleMute(true); // apply
+ } else if (e.data.mic === "toggle") { // toggle
+ toggleMute();
+ }
+ }
+
+ if ("camera" in e.data) { // this should work for the director's mic mute button as well. Needs to be manually enabled the first time still tho.
+ if (e.data.camera === true) { // unmute
+ session.videoMuted = false; // set
+ log(session.videoMuted);
+ toggleVideoMute(true); // apply
+ } else if (e.data.camera === false) { // mute
+ session.videoMuted = true; // set
+ log(session.videoMuted);
+ toggleVideoMute(true); // apply
+ } else if (e.data.camera === "toggle") { // toggle
+ toggleVideoMute();
+ }
+ }
+
+ if ("keyframe" in e.data) {
+ session.sendKeyFrameScenes();
+ }
+
+ if ("mute" in e.data) {
+ if (e.data.mute === true) { // unmute
+ session.speakerMuted = true; // set
+ toggleSpeakerMute(true); // apply
+ } else if (e.data.mute === false) { // mute
+ session.speakerMuted = false; // set
+ toggleSpeakerMute(true); // apply
+ } else if (e.data.mute === "toggle") { // toggle
+ toggleSpeakerMute();
+ }
+ } else if ("speaker" in e.data) { // same thing as mute.
+ if (e.data.speaker === true) { // unmute
+ session.speakerMuted = false; // set
+ toggleSpeakerMute(true); // apply
+ } else if (e.data.speaker === false) { // mute
+ session.speakerMuted = true; // set
+ toggleSpeakerMute(true); // apply
+ } else if (e.data.speaker === "toggle") { // toggle
+ toggleSpeakerMute();
+ }
+ }
+
+ if ("record" in e.data) {
+ if (e.data.record == false) { // mute
+ if ("recording" in session.videoElement) {
+ recordLocalVideo("stop");
+ }
+ } else if (e.data.record == true){
+ if ("recording" in session.videoElement) {
+ // already recording
+ } else {
+ recordLocalVideo("start");
+ }
+ }
+ }
+
+
+ if ("volume" in e.data) {
+ for (var i in session.rpcs) {
+ try {
+ session.rpcs[i].videoElement.volume = parseFloat(e.data.volume);
+ } catch (e) {
+ errorlog(e);
+ }
+ }
+ }
+
+ if ("bitrate" in e.data) {
+ for (var i in session.rpcs) {
+ try {
+ session.requestRateLimit(parseInt(e.data.bitrate), i);
+ } catch (e) {
+ errorlog(e);
+ }
+ }
+ }
+
+ if ("audiobitrate" in e.data) {
+ for (var i in session.rpcs) {
+ try {
+ session.requestAudioRateLimit(parseInt(e.data.audiobitrate), i);
+ } catch (e) {
+ errorlog(e);
+ }
+ }
+ }
+
+ if ("changeVideoDevice" in e.data) {
+ warnlog(e.data.changeVideoDevice);
+ changeVideoDevice(e.data.changeVideoDevice);
+ }
+
+ if ("changeAudioDevice" in e.data) {
+ warnlog(e.data.changeAudioDevice);
+ changeAudioDevice(e.data.changeAudioDevice);
+ }
+
+
+ if ("sceneState" in e.data) { // TRUE OR FALSE - tells the connected peers if they are live or not via a tally light change.
+
+ var visibility = e.data.sceneState;
+
+ if (session.obsState.visibility !== visibility) { // only move forward if there is a change; the event likes to double fire you see.
+ session.obsStateSync();
+ }
+ }
+
+ if ("sendMessage" in e.data) { // webrtc send to viewers
+ session.sendMessage(e.data);
+ }
+
+ if ("sendRequest" in e.data) { // webrtc send to publishers
+ session.sendRequest(e.data);
+ }
+
+ if ("sendPeers" in e.data) { // webrtc send message to every connected peer; like send and request; a hammer vs a knife.
+ session.sendPeers(e.data);
+ }
+
+ if ("reload" in e.data) {
+ location.reload();
+ }
+
+ 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;
+ }
+
+
+ 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) {
+ 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;
+ }
+ }
+ } 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 ("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;
+ }
+ 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);
+ }
+
+ }
+ }
+ return;
+ });
+ return;
+ });
+ }, 0, uuid);
+ }
+ setTimeout(function() {
+ stats.outbound_stats = {};
+ for (var i in session.pcs) {
+ stats.outbound_stats[i] = session.pcs[i].stats;
+ }
+ parent.postMessage({
+ "stats": stats
+ }, "*");
+ }, 1000);
+ }
+
+ if ("getRemoteStats" in e.data) {
+ session.sendRequest({"requestStats":true, "remote":session.remote});
+ }
+
+ if ("getLoudness" in e.data) {
+ log("GOT LOUDNESS REQUEST");
+ if (e.data.getLoudness == true) {
+ session.pushLoudness = true;
+ var loudness = {};
+
+ for (var i in session.rpcs) {
+ loudness[session.rpcs[i].streamID] = session.rpcs[i].stats.Audio_Loudness;
+ }
+
+ parent.postMessage({
+ "loudness": loudness
+ }, "*");
+
+ } else {
+ session.pushLoudness = false;
+ }
+ }
+
+ if ("getStreamIDs" in e.data) {
+ if (e.data.getStreamIDs == true) {
+ var streamIDs = {};
+ for (var i in session.rpcs) {
+ streamIDs[session.rpcs[i].streamID] = session.rpcs[i].label;
+ }
+ parent.postMessage({
+ "streamIDs": streamIDs
+ }, "*");
+
+ }
+ }
+
+ if ("close" in e.data) {
+ for (var i in session.rpcs) {
+ try {
+ session.rpcs[i].close();
+ } catch (e) {
+ errorlog(e);
+ }
+ }
+ }
+
+ if ("style" in e.data) {
+ try {
+ const style = document.createElement('style');
+ style.textContent = e.data.style;
+ document.head.append(style);
+ log(style);
+ } catch (e) {
+ errorlog(e);
+ }
+ }
+
+
+ if ("automixer" in e.data) {
+ if (e.data.automixer == true) {
+ session.manual = false;
+ try {
+ updateMixer();
+ } catch (e) {}
+ } else if (e.data.automixer == false) {
+ session.manual = true;
+ }
+ }
+
+ if ("target" in e.data) {
+ log(e.data);
+ for (var i in session.rpcs) {
+ try {
+ if ("streamID" in session.rpcs[i]) {
+ if ((session.rpcs[i].streamID == e.data.target) || (e.data.target == "*")) {
+ try {
+ if ("settings" in e.data) {
+ for (const property in e.data.settings) {
+ session.rpcs[i].videoElement[property] = e.data.settings[property];
+ }
+ }
+ if ("add" in e.data) {
+ getById("gridlayout").appendChild(session.rpcs[i].videoElement);
+
+ } else if ("remove" in e.data) {
+ try {
+ session.rpcs[i].videoElement.parentNode.removeChild(session.rpcs[i].videoElement);
+ } catch (e) {
+ try {
+ session.rpcs[i].videoElement.parentNode.parentNode.removeChild(session.rpcs[i].videoElement.parentNode);
+ } catch (e) {}
+ }
+ }
+ } catch (e) {
+ errorlog(e);
+ }
+ }
+ }
+ } catch (e) {
+ errorlog(e);
+ }
+ }
+ }
+ };
+}
+
+function setupIncomingVideoTracking(v, UUID){ // video element.
+
+ if (session.directorUUID===UUID){
+ v.muted=false;
+ } else {
+ v.muted = session.speakerMuted;
+ }
+
+ v.onpause = (event) => { // prevent things from pausing; human or other
+ if (!((event.ctrlKey) || (event.metaKey) )){
+ warnlog("Video paused; force it to play again");
+ //return;
+ //session.audioCtx.resume();
+ //log("ctx resume");
+
+ event.currentTarget.play().then(_ => {
+ log("playing");
+ }).catch(error => {
+ warnlog("didnt play 1");
+ });
+
+ }
+ }
+
+ v.onplay = function(){
+ try {
+ var bigPlayButton = document.getElementById("bigPlayButton");
+ if (bigPlayButton){
+ bigPlayButton.parentNode.removeChild(bigPlayButton);
+ }
+ } catch(e){}
+ if (session.pip){
+ if (v.readyState >= 3){
+ if (!(v.pip)){
+ v.pip=true;
+ toggleSystemPip(v, true);
+ }
+ }
+ }
+
+ }
+
+ if (session.pip){
+ v.onloadedmetadata = function(){
+ if (!v.paused){
+ if (!(v.pip)){
+ v.pip=true;
+ toggleSystemPip(v, true);
+ }
+ }
+ }
+ }
+
+
+ v.addEventListener('resize', (e) => {
+ log("resize event");
+ var aspectRatio = parseFloat(e.target.videoWidth/e.target.videoHeight);
+ if (v.dataset.aspectRatio){
+ if (aspectRatio != v.dataset.aspectRatio){
+ setTimeout(function(){updateMixer();},1); // We don't want to run this on the first resize? just subsequent ones.
+ }
+ } else {
+ log("ASPECT RATIO CHANGED");
+ setTimeout(function(){updateMixer();},1);
+ }
+ v.dataset.aspectRatio = parseFloat(e.target.videoWidth/e.target.videoHeight);
+ });
+
+ v.volume = 1.0; // play audio automatically
+ v.autoplay = true;
+ v.controls = false;
+ v.classList.add("tile");
+ v.setAttribute("playsinline","");
+ v.controlTimer = null;
+
+ changeAudioOutputDevice(v); // if enabled, changes to desired output audio device.
+
+ if (document.getElementById("mainmenu")){
+ var m = getById("mainmenu");
+ m.remove();
+ }
+
+ if (session.director){
+ v.controls = true;
+ var container = getById("videoContainer_"+UUID);
+ v.disablePictureInPicture = false
+ v.setAttribute("controls","controls")
+ container.appendChild(v);
+ session.requestRateLimit(session.directorViewBitrate,UUID); /// limit resolution for director
+
+ if (session.beepToNotify) {
+ playtone();
+ }
+
+ } else if (session.scene!==false){
+ v.controls = false;
+
+ if (session.view){ // specific video to be played
+ v.style.display="block";
+ } else if (session.scene==="0"){
+ v.style.display="block";
+ } else { // group scene I guess; needs to be added manually
+ v.style.display="none";
+ v.muted= true;
+ }
+
+ setTimeout(function(){updateMixer();},1);
+ } else if (session.roomid!==false){
+ if (session.cleanOutput){
+ v.controls = false;
+ } else if (window.obsstudio) {
+ v.controls = false;
+ } 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)){
+ session.requestRateLimit(0,UUID);// limit resolution for guests see ln: 1804 in main.js also
+ }
+ } else {
+ session.requestRateLimit(0,UUID);// limit resolution for guests see ln: 1804 in main.js also
+ }
+ setTimeout(function(){updateMixer();},1);
+ } else {
+ v.style.display="block";
+ if (window.obsstudio) {
+ v.controls = false;
+ }
+ setTimeout(function(){updateMixer();},1);
+ }
+
+
+ v.addEventListener('click', function(e) { // show stats of video if double clicked
+ log("clicked");
+ try {
+ if ((e.ctrlKey)||(e.metaKey)){
+ e.preventDefault();
+ var uid = e.currentTarget.dataset.UUID;
+ if ("stats" in session.rpcs[uid]){
+
+ var [menu, innerMenu] = statsMenuCreator();
+
+ printViewStats(innerMenu, uid );
+
+ menu.interval = setInterval(printViewStats,3000, innerMenu, uid);
+
+
+ }
+ e.stopPropagation();
+ return false;
+ }
+ } catch(e){errorlog(e);}
+ });
+
+ if (session.statsMenu){
+ if ("stats" in session.rpcs[UUID]){
+
+ if (getById("menuStatsBox")){
+ clearInterval(getById("menuStatsBox").interval);
+ getById("menuStatsBox").remove();
+ }
+
+ var [menu, innerMenu] = statsMenuCreator();
+
+ printViewStats(innerMenu, UUID );
+
+ menu.interval = setInterval(printViewStats,3000, innerMenu, UUID);
+
+ }
+ }
+
+
+ v.touchTimeOut = null;
+ v.touchLastTap = 0;
+ v.touchCount = 0;
+ v.addEventListener('touchend', function(event) {
+ log("touched");
+
+ document.ontouchup = null;
+ document.onmouseup = null;
+ document.onmousemove = null;
+ document.ontouchmove = null;
+
+ var currentTime = new Date().getTime();
+ var tapLength = currentTime - v.touchLastTap;
+ clearTimeout(v.touchTimeOut);
+ if (tapLength < 500 && tapLength > 0) {
+ ///
+ log("double touched");
+ v.touchCount+=1;
+ event.preventDefault();
+ if (v.touchCount<5){
+ v.touchLastTap = currentTime;
+ return false;
+ }
+ v.touchLastTap = 0;
+ v.touchCount=0;
+
+ log("double touched");
+ var uid = event.currentTarget.dataset.UUID;
+ if ("stats" in session.rpcs[uid]){
+
+ var [menu, innerMenu] = statsMenuCreator();
+
+ printViewStats(innerMenu, uid );
+
+ menu.interval = setInterval(printViewStats,3000, innerMenu, uid);
+
+
+ }
+ event.stopPropagation();
+ return false;
+ //////
+ } else {
+ v.touchCount=1;
+ v.touchTimeOut = setTimeout(function(vv) {
+ clearTimeout(vv.touchTimeOut);
+ vv.touchLastTap = 0;
+ vv.touchCount=0;
+ }, 5000, v);
+ v.touchLastTap = currentTime;
+ }
+
+ });
+
+
+ if (session.remote){
+ v.addEventListener("wheel", session.remoteControl);
+ }
+
+ if (v.controls == false){
+ v.addEventListener("click", function () {
+ if (v.paused){
+ log("PLAYING MANUALLY?");
+ v.play().then(_ => {
+ log("playing");
+ }).catch(warnlog);
+ }
+ });
+ if (session.nocursor==false){ // we do not want to show the controls. This is because MacOS + OBS does not work; so electron app needs this.
+ if (!(session.cleanOutput)){
+ if (!(window.obsstudio)){
+ if (v.controlTimer){
+ clearInterval(v.controlTimer);
+ }
+ v.controlTimer = setTimeout(showControlBar.bind(null,v),3000);
+ //v.controlTimer = setTimeout(function (){v.controls=true;},3000); // 3 seconds before I enable the controls automatically. This way it doesn't auto appear during loading. 3s enough, right?
+ }
+ }
+ }
+ }
+
+ if (session.fadein){
+ v.classList.add("fadein"); // allows the video to fade in.
+ }
+
+ setTimeout(session.processStats, 1000, UUID);
+
+}
+
+function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a giant function that runs when there are changes to screensize, video track statuses, etc.
+ if (getById("subControlButtons").dragElement){
+ if (parseInt(getById("subControlButtons").style.top) > 0){
+ getById("subControlButtons").style.top = "0px";
+ } else if (parseInt(getById("subControlButtons").style.top) < parseInt(50 - window.innerHeight) ){
+ getById("subControlButtons").style.top = parseInt( 50 - window.innerHeight)+"px";
+ }
+ if (parseInt(getById("subControlButtons").style.left) < 0){
+ getById("subControlButtons").style.left = "0px";
+ } else if (parseInt(getById("subControlButtons").style.left) > parseInt( window.innerWidth - getById("subControlButtons").offsetWidth) ){
+ getById("subControlButtons").style.left = parseInt( window.innerWidth -getById("subControlButtons").offsetWidth )+"px";
+ }
+ }
+ if (session.director){return;}
+ if (session.manual === true){return;}
+ var playarea = getById("gridlayout");
+ var header = getById("header");
+
+ var hi = header.offsetHeight ;
+ var w = window.innerWidth;
+ var h = window.innerHeight - hi;
+
+ if ( window.innerHeight<=700 ){
+ if (document.getElementById("controlButtons")){
+ var h = window.innerHeight - hi - document.getElementById("controlButtons").offsetHeight;
+ } else {
+ var h = window.innerHeight - hi;
+ }
+ }
+
+ var arW = 16.0;
+ var arH = 9.0;
+
+ if (session.aspectratio){
+ if (session.aspectratio==1){
+ arW = 9.0;
+ arH = 16.0;
+ } else if (session.aspectratio==2){
+ arW = 12.0; // square root; cause why not.
+ arH = 12.0;
+ }
+ }
+
+ var ww = w/arW;
+ var hh = h/arH;
+
+ var mediaPool = [];
+ var mediaPool_invisible = [];
+
+ if (session.videoElement){ // I, myself, exist
+ if (session.videoElement.style.display!="none"){ // local feed
+ if (session.minipreview && (session.infocus!==true)){
+
+ session.videoElement.onclick = function(){
+ if (session.infocus === true){
+ session.infocus = false;
+ } else {
+ session.infocus = true;
+ log("session: myself");
+ }
+ setTimeout(()=>updateMixer(),10);
+ };
+
+ } else {
+ if (session.order!==false){
+ session.videoElement.order=session.order;
+ } else {
+ session.videoElement.order=0;
+ }
+ if (session.activeSpeaker && (!session.activelySpeaking)){
+ mediaPool_invisible.push(session.videoElement);
+ } else {
+ mediaPool.push(session.videoElement);
+ }
+ }
+ }
+ }
+
+ if (session.screenShareElement){ // I, myself, exist
+ if (session.screenShareElement.style.display!="none"){ // local feed
+ if (session.order!==false){
+ session.screenShareElement.order=session.order;
+ } else {
+ session.screenShareElement.order=0;
+ }
+
+ if (session.infocus!==false){
+ mediaPool_invisible.push(session.screenShareElement);
+ } else if (session.activeSpeaker && (!session.activelySpeaking)){
+ mediaPool_invisible.push(session.screenShareElement);
+ } else {
+ mediaPool.push(session.screenShareElement);
+ }
+ }
+ }
+
+ if (session.iframeEle){ // I, myself, exist
+ if (session.iframeEle.style.display!="none"){ // local feed
+ if (session.order!==false){
+ session.iframeEle.order=session.order;
+ } else {
+ session.iframeEle.order=0;
+ }
+ if (session.activeSpeaker && (!session.activelySpeaking)){
+ mediaPool_invisible.push(session.iframeEle);
+ } else {
+ mediaPool.push(session.iframeEle);
+ }
+ }
+ }
+
+
+ if ((session.infocus) && (session.infocus in session.rpcs)){ // remote guest being full screened; infocus == UUID
+ log(session.infocus+" set fullscreen");
+ mediaPool = []; // remove myself from fullscreen
+ for (var j in session.rpcs){
+ if (j != session.infocus){
+ session.requestRateLimit(0, j); // disable the video of non-fullscreen videos
+ try {
+ if (session.rpcs[j].videoElement.style.display!="none"){ // Add it if not hidden
+ mediaPool_invisible.push(session.rpcs[j].videoElement);
+ }
+ } catch(e){}
+ } else { // in focus video
+ ////////
+ try {
+ if (session.rpcs[j].order!==false){
+ session.rpcs[j].videoElement.order=session.rpcs[j].order;
+ } else {
+ session.rpcs[j].videoElement.order=0;
+ }
+ ///////////
+ if (session.activeSpeaker && (!session.rpcs[j].activelySpeaking)){
+ mediaPool_invisible.push(session.rpcs[j].videoElement);
+ } else {
+ mediaPool.push(session.rpcs[j].videoElement);
+ }
+
+ session.rpcs[j].videoElement.style.visibility = "visible";
+ if ((session.rpcs[j].targetBandwidth!==-1) && (session.rpcs[j].targetBandwidth0){
+ if (session.nopreview!==false){
+ mediaPool = []; // we don't want to show our self-preview if in broadcast mode and there is a director.
+ }
+ }
+ }
+
+ if (roomQuality === 0){roomQuality=1;}
+
+ var totalRoomBitrate = session.totalRoomBitrate;
+ if ((session.controlRoomBitrate!==false) && (session.controlRoomBitrate!==true)){
+ totalRoomBitrate = Math.min(session.controlRoomBitrate, totalRoomBitrate);
+ }
+
+ roomQuality = parseInt(totalRoomBitrate/roomQuality);
+ //if (roomQuality<20){
+ // roomQuality=20;
+ //}
+
+ for (var i in session.rpcs){
+ if (session.rpcs[i]===null){continue;}
+
+ if (session.rpcs[i].iframeEle){
+ if (session.rpcs[i].order!==false){
+ session.rpcs[i].iframeEle.order=session.rpcs[i].order;
+ } else {
+ session.rpcs[i].iframeEle.order=0;
+ }
+ if (session.activeSpeaker && (!session.rpcs[i].activelySpeaking)){
+ mediaPool_invisible.push(session.rpcs[i].iframeEle);
+ } else {
+ mediaPool.push(session.rpcs[i].iframeEle);
+ }
+
+ if (session.rpcs[i].videoElement){
+ if (!(session.rpcs[i].videoElement in mediaPool_invisible)){
+ mediaPool_invisible.push(session.rpcs[i].videoElement);
+ }
+ session.requestRateLimit(0, i);
+ }
+
+ continue;
+ }
+
+ if (session.rpcs[i].imageElement){
+ //if (session.rpcs[i].videoElement.srcObject.getVideoTracks().length==0){ // video shouldn't be on if images are on.
+
+ if (session.rpcs[i].videoElement){ // is there audio?
+ mediaPool_invisible.push(session.rpcs[i].videoElement); // include audio as hidden track;
+ }
+
+ if (session.rpcs[i].videoMuted){
+ continue;
+ } else if (session.rpcs[i].directorVideoMuted){
+ continue;
+ }
+
+ if (session.rpcs[i].order!==false){
+ session.rpcs[i].imageElement.order=session.rpcs[i].order;
+ } else {
+ session.rpcs[i].imageElement.order=0;
+ }
+ if (session.activeSpeaker && (!session.rpcs[i].activelySpeaking)){
+ // mediaPool_invisible.push(session.rpcs[i].imageElement);
+ } else {
+ mediaPool.push(session.rpcs[i].imageElement);
+ }
+
+ continue;
+ // } else {
+ // errorlog("Video track added while in webp streaming mode? wasted bandwidth / cpu ..")
+ // }
+ }
+
+ if (session.rpcs[i].videoElement){ // remote feeds
+
+ //session.rpcs[i].targetBandwidth = -1;
+ if (session.rpcs[i].videoElement.style.opacity==="0"){
+ continue;
+ }
+
+ try{
+ session.rpcs[i].videoElement.style.visibility = "visible";
+ } catch(e){}
+
+ if (session.directorUUID ===session.rpcs[i].UUID){ // director is never audio-only. Video if need, yes, but not visualized-audio.
+ if (session.rpcs[i].videoElement.srcObject.getVideoTracks().length==0){
+ //if (session.style==1){ // avatars and waveforms might be better done elsewhere? as a canvas effect even?
+ continue;
+ //}
+ }
+ } else if (session.style==2){
+ log("style = 2");
+ if (session.rpcs[i].videoElement.srcObject.getVideoTracks().length==0){
+ if (session.rpcs[i].canvas){
+ if (session.rpcs[i].order!==false){
+ session.rpcs[i].canvas.order=session.rpcs[i].order;
+ } else {
+ session.rpcs[i].canvas.order=0;
+ }
+
+ if (session.activeSpeaker && (!session.rpcs[i].activelySpeaking)){
+ mediaPool_invisible.push(session.rpcs[i].canvas);
+ } else {
+ mediaPool.push(session.rpcs[i].canvas);
+ }
+ }
+ continue;
+ }
+ } else if (session.style==1){
+ if (session.rpcs[i].videoElement.srcObject.getVideoTracks().length==0){
+ //if (session.style==1){ // avatars and waveforms might be better done elsewhere? as a canvas effect even?
+ continue;
+ //}
+ }
+ } else if (session.scene!==false){
+ if (session.rpcs[i].videoElement.srcObject.getVideoTracks().length==0){ // unless style==2, then scenes don't show audio.
+ //if (session.style==1){ // avatars and waveforms might be better done elsewhere? as a canvas effect even?
+ continue;
+ //}
+ }
+ }
+
+ if (session.rpcs[i].videoMuted){
+ continue;
+ } else if (session.rpcs[i].directorVideoMuted){
+ continue;
+ }
+
+ if (session.director){ // director video should be low-bitrate, although this should never fire.
+ warnlog("Update should not be called on DIRECTORs view? sorta at least"); // the director should never be called.
+ return;
+ } else if (session.rpcs[i].videoElement.style.display=="none"){ // Video is disabled; run at lowest
+ if (session.scene!==false){
+ session.requestRateLimit(session.hiddenSceneViewBitrate, i); // hidden. I dont want it to be super low, for video quality reasons.
+ if (!session.hiddenSceneViewBitrate){
+ session.rpcs[i].videoElement.classList.add("nogb");
+ }
+ } else {
+ session.requestRateLimit(0, i); // w/e This is not in OBS, so we just set it as low as possible. Shoudln't exist really unless loading?
+ }
+ } else if (session.scene!==false){ // max
+ session.requestRateLimit(-1, i); // unlock.
+ if (session.rpcs[i].order!==false){
+ session.rpcs[i].videoElement.order=session.rpcs[i].order;
+ } else {
+ session.rpcs[i].videoElement.order=0;
+ }
+ if (session.activeSpeaker && (!session.rpcs[i].activelySpeaking)){
+ if (!(session.rpcs[i].videoElement in mediaPool_invisible)){
+ mediaPool_invisible.push(session.rpcs[i].videoElement);
+ } else {
+ errorlog("THIS SHOULD NOT HAPPEN; 650");
+ }
+ } else {
+ mediaPool.push(session.rpcs[i].videoElement);
+ }
+ } else if (session.roomid!==false){ // guests should see video at low bitrate, ie: 100kbps (not 35kbps like if disabled)
+ if (session.rpcs[i].order!==false){
+ session.rpcs[i].videoElement.order=session.rpcs[i].order;
+ } else {
+ session.rpcs[i].videoElement.order=0;
+ }
+ if (session.activeSpeaker && (!session.rpcs[i].activelySpeaking)){
+ if (!(session.rpcs[i].videoElement in mediaPool_invisible)){
+ mediaPool_invisible.push(session.rpcs[i].videoElement);
+ } else {
+ errorlog("THIS SHOULD NOT HAPPEN; 665");
+ }
+ } else {
+ mediaPool.push(session.rpcs[i].videoElement);
+ }
+ if ((session.roomid==="") && (session.bitrate)){
+ // we will let the URL specified bitrate hold, since this isn't a real room.
+ session.requestRateLimit(-1, i);
+ } else {
+ session.requestRateLimit(roomQuality, i); // well, screw that. Setting it to room quality.
+ }
+ } else { // view=xx,yy or whatever. This should be highest quality.
+ if (session.rpcs[i].order!==false){
+ session.rpcs[i].videoElement.order=session.rpcs[i].order;
+ } else {
+ session.rpcs[i].videoElement.order=0;
+ }
+ if (session.activeSpeaker && (!session.rpcs[i].activelySpeaking)){
+ if (!(session.rpcs[i].videoElement in mediaPool_invisible)){
+ mediaPool_invisible.push(session.rpcs[i].videoElement);
+ } else {
+ errorlog("THIS SHOULD NOT HAPPEN; 684");
+ }
+ } else {
+ mediaPool.push(session.rpcs[i].videoElement);
+ }
+ session.requestRateLimit(-1, i);
+ }
+ }
+ }
+ }
+ if (session.director){return;} // director view says go no further :)
+
+ if (document.fullscreenElement) {
+ log("FULL SCREEN: "+document.fullscreenElement.id);
+ return; // This is FULL SCREEN, so let's not continue.
+ }
+
+ var mpl = mediaPool.length;
+ if (mpl>1){
+ var BB = 0;
+ var rw = 1;
+ var rh = 1;
+ var NW;
+ var NH;
+ var current;
+ for (NW=1; NW <= mpl; NW++){
+ NH = Math.ceil(mpl/NW);
+ var www = ww/NW;
+ var hhh = hh/NH;
+ if (www>hhh){
+ current = hhh * hhh * (mpl/(NW*NH));
+ } else {
+ current = www * www * (mpl/(NW*NH));
+ }
+
+ if (current>=BB){
+ BB = current;
+ rw = NW;
+ rh = NH;
+ }
+
+ }
+ } else { var rw=1; var rh=1;}
+
+
+ if (playarea.getElementsByTagName("iframe").length){
+
+ var childNodes = playarea.childNodes;
+
+ for (var n=0;n{
+ vid.style.width = "0px";
+ vid.style.height = "0px";
+ vid.style.top = "0px";
+ vid.style.left = "0px";
+ //vid.alreadyAdded=false; // what am I doing here? wtf? TODO: this is a typo, right?
+ if (vid.alreadyAdded && vid.alreadyAdded==true){
+ vid.alreadyAdded=false;
+ return;
+ } else if (vid.dataset.doNotMove){
+ return;
+ }
+ playarea.appendChild(vid);
+ });
+
+ mediaPool.sort(compare_vids);
+
+ mediaPool.forEach(vid=>{
+
+ var container = document.createElement("div");
+
+ container.style.position = "absolute";
+ container.style.display = "flex";
+ container.style.alignItems = "center";
+ offsetx=0;
+
+ if (i!==0){
+ if (Math.ceil((i+0.01)/rw)==rh){
+ if (mediaPool.length%rw){
+ offsetx = ((rw - mediaPool.length%rw)*(window.innerWidth/rw))/2;
+ }
+ }
+ }
+
+ offsety = (h- Math.ceil(mediaPool.length/rw)*Math.ceil(h/rh))/2;
+
+ if (vid.alreadyAdded && vid.alreadyAdded==true){
+ container = vid.parentNode;
+ }
+
+ container.style.left = offsetx+Math.floor(((i%rw)+0)*w/rw)+"px";
+ container.style.top = offsety+Math.floor((Math.floor(i/rw)+0)*h/rh + hi)+"px";
+ container.style.width = Math.ceil(w/rw)+"px";
+ container.style.height = Math.ceil(h/rh)+"px";
+
+ if (vid.alreadyAdded && vid.alreadyAdded==true){
+ vid.alreadyAdded=false;
+ i+=1;
+ return;
+ } else if (vid.dataset.doNotMove){
+ vid.style.position = "absolute";
+ vid.style.left = container.style.left;
+ vid.style.top = container.style.top;
+ vid.style.width = container.style.width;
+ vid.style.height = container.style.height;
+ vid.style.display = "flex";
+ i+=1;
+ return;
+ }
+
+
+ playarea.appendChild(container);
+
+ var wrw = Math.ceil(w/rw);
+ var hrh = Math.ceil(h/rh);
+
+ if (session.dynamicScale){
+ if (vid.dataset.UUID){
+ if (wrw && hrh){
+ if (session.devicePixelRatio){
+ session.requestResolution(vid.dataset.UUID, wrw * session.devicePixelRatio, hrh * session.devicePixelRatio);
+ } else if (window.devicePixelRatio && parseInt(window.devicePixelRatio) > 1 ){
+ session.requestResolution(vid.dataset.UUID, wrw*window.devicePixelRatio, hrh*window.devicePixelRatio);
+ } else {
+ session.requestResolution(vid.dataset.UUID, wrw, hrh);
+ }
+ }
+ }
+ }
+
+
+ //vid.style.objectFit = "contain"; // set by .tile now
+ //vid.classList="";
+ vid.style.maxWidth = "100%";
+ vid.style.maxHeight = "100%";
+ //vid.style.margin = "auto";
+
+ // Creates relative positioned element, important for label pos
+ var holder = document.createElement("div");
+ holder.className = "holder";
+ //holder.appendChild(vid);
+ container.appendChild(vid);
+ container.appendChild(holder);
+
+
+
+ if (vid.videoWidth && vid.videoHeight){
+ var asw = wrw/vid.videoWidth;
+ var ash = hrh/vid.videoHeight;
+
+ 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 if (vid.width && vid.height){
+ var asw = wrw/vid.width;
+ var ash = hrh/vid.height;
+
+ if (asw < ash){
+ holder.style.width = Math.ceil(vid.width*asw)+"px";
+ holder.style.height = Math.ceil(vid.height*asw)+"px";
+ holder.style.left = Math.ceil((Math.ceil(w/rw) - Math.ceil(vid.width*asw))/2);
+ holder.style.top = Math.ceil(( Math.ceil(h/rh) - Math.ceil(vid.height*asw))/2);
+ } else {
+ holder.style.width = Math.ceil(vid.width*ash)+"px";
+ holder.style.height = Math.ceil(vid.height*ash)+"px";
+ holder.style.left = Math.ceil((Math.ceil(w/rw) - Math.ceil(vid.width*ash))/2);
+ holder.style.top = Math.ceil((Math.ceil(h/rh) - Math.ceil(vid.height*ash))/2);
+ }
+ } else if (wrw/hrh < arW/arH){
+ holder.style.width = "100%";
+ holder.style.height = "100%";
+ if (vid.tagName.toLowerCase()=="iframe"){
+ holder.style.height = "100%";
+ }
+ holder.style.left = 0;
+ holder.style.top = 0;
+
+ } else {
+ holder.style.width = "100%";
+ holder.style.height = "100%";
+ if (vid.tagName.toLowerCase()=="iframe"){
+ holder.style.width = "100%";
+ }
+ holder.style.left = 0;
+ holder.style.top = 0;
+ }
+
+ if (session.cover){
+ holder.style.width = "100%";
+ holder.style.height = "100%";
+ holder.style.left = 0;
+ holder.style.top = 0;
+ }
+
+ holder.style.position = "absolute";
+
+ vid.style.width = "100%";
+ vid.style.height = "100%";
+
+ var fontsize = (vid.offsetWidth + vid.offsetHeight)*0.03;
+ log("fontsize " +fontsize + " - " +vid.offsetWidth + " - " + vid.offsetHeight);
+ if (!fontsize){
+ if (vid.videoWidth/holder.offsetWidth > vid.videoHeight/holder.offsetHeight){
+ fontsize = (holder.offsetHeight + vid.videoHeight/holder.offsetHeight*vid.offsetWidth)*0.03;
+ } else {
+ fontsize = (holder.offsetWidth + vid.videoWidth/holder.offsetWidth*vid.offsetHeight)*0.03;
+ }
+ }
+ if (!fontsize){
+
+ fontsize = (holder.offsetWidth + holder.offsetHeight)*0.03;
+ }
+ log("fontsize final:" +fontsize);
+
+
+ if (vid.dataset.UUID && session.rpcs[vid.dataset.UUID].label !== false && session.showlabels===true){ // remote source
+
+ // creates a video label holder inside the recently created label holder
+ var label = document.createElement("span");
+ if (session.labelstyle){
+ label.className = 'video-label '+session.labelstyle;
+ } else {
+ label.className = 'video-label';
+ }
+ if (fontsize){
+ if (session.labelsize){
+ fontsize = fontsize*session.labelsize/100;
+ }
+ fontsize = parseInt(fontsize);
+ fontsize = fontsize+"px";
+ label.style.fontSize = fontsize;
+ }
+ label.innerText = session.rpcs[vid.dataset.UUID].label;
+ holder.appendChild(label);
+ } else if ((session.showlabels===true) && (vid.id === "videosource") && (session.label)){ // local source
+ // creates a label holder that's the same size of the vid element.
+
+ // creates a video label holder inside the recently created label holder
+ var label = document.createElement("span");
+ if (session.labelstyle){
+ label.className = 'video-label '+session.labelstyle;
+ } else {
+ label.className = 'video-label';
+ }
+ if (fontsize){
+ if (session.labelsize){
+ fontsize = fontsize*session.labelsize/100;
+ }
+ fontsize = parseInt(fontsize);
+ fontsize = fontsize+"px";
+ label.style.fontSize = fontsize;
+ }
+
+ label.innerText = sanitizeLabel(session.label);//.replace(/[\W]+/g,"_").replace(/_+/g, ' ');
+ holder.appendChild(label);
+ }
+
+ if (vid.dataset.UUID && session.rpcs[vid.dataset.UUID] && session.rpcs[vid.dataset.UUID].voiceMeter){
+ holder.appendChild(session.rpcs[vid.dataset.UUID].voiceMeter);
+
+ }
+ if (vid.dataset.UUID && session.rpcs[vid.dataset.UUID] && session.rpcs[vid.dataset.UUID].remoteMuteElement){
+ holder.appendChild(session.rpcs[vid.dataset.UUID].remoteMuteElement);
+ }
+ try {
+ if (!(session.cleanOutput && session.cleanish==false)){
+ if (session.firstPlayTriggered===false){ // don't play unless needed; might cause clicking or who knows what else.
+ warnlog("VIDEO IS NOT PLAYING");
+ if (vid.tagName.toLowerCase()=="video"){ // we don't want to try playing an Iframe or Canvas.
+ var playPromise = vid.play();
+ if (playPromise !== undefined){
+ playPromise.then(_ => {
+ // playing
+ session.firstPlayTriggered=true; // global tracking. "user gesture obtained", so no longer needed if playing.
+ }).catch((err)=>{
+
+ var bigPlayButton = document.getElementById("bigPlayButton");
+ if (bigPlayButton){
+ bigPlayButton.innerHTML = ' ';
+ bigPlayButton.style.display="block";
+ }
+ });
+ } else {
+ session.firstPlayTriggered=true; // well, I don't know if it's playing, and so whatever. fail gracefully.
+ }
+ }
+ }
+ }
+ } catch(e) {
+ log("VIDEO IS PLAYING");
+ var bigPlayButton = document.getElementById("bigPlayButton");
+ if (bigPlayButton){
+ bigPlayButton.parentNode.removeChild(bigPlayButton);
+ }
+
+ }
+
+ if (vid.tagName.toLowerCase()=="iframe"){ // I need to add this back in at some point.
+ i+=1;
+ return;
+ }
+
+ if (!session.cleanOutput && !session.nocursor){
+ if ((session.roomid!==false) && (session.scene===false)){
+ var button = document.createElement("div");
+ button.id = "button_"+vid.id;
+
+ if (session.infocus){
+ button.innerHTML = " ";
+ button.title = "Show all active videos togethers";
+ } else if (mediaPool.length>1){
+ button.innerHTML = " ";
+ button.title = "Enlarge video and increase its clarity";
+ } else {
+ button.style.visibility = "hidden";
+ }
+ button.style.transition = "opacity 0.3s"
+ button.style.width ="4vh";
+ button.style.height = "4vh";
+ button.style.maxWidth ="30px";
+ button.style.maxHeight = "30px";
+ button.style.minWidth ="15px";
+ button.style.minHeight = "15px";
+ button.style.position = "absolute";
+ button.style.display="none";
+ //button.style.opacity="10%";
+ button.style.zIndex="6";
+ button.style.right = "4vh";//(Math.ceil(w/rw) -30 - 30 + offsetx+Math.floor(((i%rw)+0)*w/rw))+"px";
+ button.style.top = "4vh";//( offsety + 30 + Math.floor((Math.floor(i/rw)+0)*h/rh + hi))+"px";
+ button.style.color = "white";
+ button.style.cursor = "pointer";
+
+
+ container.appendChild(button);
+ if (vid.id == "videosource"){
+ button.onclick = function(){
+ var target = event.currentTarget;
+ log(target);
+ if (session.infocus === true){
+ session.infocus = false;
+ //target.childNodes[0].className = 'las la-arrows-alt';
+ } else {
+ session.infocus = true;
+ log("session: myself");
+ //target.childNodes[0].className = 'las la-compress';
+ }
+ setTimeout(()=>updateMixer(),10);
+ };
+
+ } else {
+ button.dataset.UUID = vid.dataset.UUID;
+ button.onclick = function(event){
+ var target = event.currentTarget;
+ log("fullscreen");
+ log(target);
+ if (session.infocus === target.dataset.UUID){
+ //target.childNodes[0].className = 'las la-arrows-alt';
+ session.infocus = false;
+ } else {
+ //target.childNodes[0].className = 'las la-compress';
+ session.infocus = target.dataset.UUID;
+ //log("session:"+target.dataset.UUID);
+ }
+ setTimeout(()=>updateMixer(),10);
+ };
+
+ }
+ vid.onclick = function(){
+ button.style.display="block";
+ container.style.backgroundColor= "#4444";
+ button.style.opacity="100%";
+ };
+ button.onmouseenter = function(){
+ button.style.display="block";
+ container.style.backgroundColor= "#4444";
+ setTimeout(function(button){button.style.opacity="100%";},0,button);
+
+ };
+ container.onmouseenter = function(){
+ button.style.display="block";
+ container.style.backgroundColor= "#4444";
+ setTimeout(function(button){button.style.opacity="100%";},0,button);
+ };
+ container.onmouseleave = function(){
+ button.style.display="none";
+ container.style.backgroundColor= null;
+ button.style.opacity="10%";
+ };
+ }
+ }
+ i+=1;
+ });
+}
+
+
+var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
+var eventer = window[eventMethod];
+var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";
+eventer(messageEvent, function(e) { // this listens for child IFRAMES.
+ if ("action" in e.data) {
+ if (e.data.action == "screen-share-ended") {
+ if (session.screenShareElement) {
+ if (e.source == session.screenShareElement.contentWindow) { // reject messages send from other iframes
+ warnlog(e);
+ session.screenShareElement.contentWindow.postMessage({
+ "close": true
+ }, '*');
+ session.screenShareElement.parentNode.removeChild(session.screenShareElement);
+ session.screenShareElement = false;
+ updateMixer();
+ getById("screenshare2button").classList.add("float");
+ getById("screenshare2button").classList.remove("float2");
+ }
+ }
+ }
+ }
+});
+
+
+function requestKeyframeScene(ele) {
+ var UUID = ele.dataset.UUID;
+ if (ele.dataset.value == 1) {
+ } else {
+ ele.dataset.value = 1;
+ ele.classList.add("pressed");
+ session.requestKeyframe(UUID, true);
+ setTimeout(function(el){
+ el.dataset.value = 0;
+ el.classList.remove("pressed");
+ }, 1000, ele)
+ }
+}
+
+function pokeIframeAPI(action, value = null, UUID = null) {
+ if (!isIFrame){return;}
+ try {
+ var data = {};
+
+ data.action = action;
+
+ if (value !== null) {
+ data.value = value;
+ }
+ if (UUID !== null) {
+ data.UUID = UUID;
+ }
+
+ if (isIFrame) {
+ parent.postMessage(data, "*");
+ }
+ } catch (e) {
+ errorlog(e);
+ }
+}
+
+function jumptoroom(event = null) {
+
+ if (event) {
+ if (event.which !== 13) {
+ return;
+ }
+ }
+
+ var arr = window.location.href.split('?');
+ var roomname = getById("joinroomID").value;
+ roomname = sanitizeRoomName(roomname);
+ if (roomname.length) {
+
+ var passStr = "";
+ window.focus();
+ var pass = prompt("Enter a password if provided, otherwise just click cancel"); //sanitizePassword(session.password);
+ if (pass && pass.length) {
+ session.password = sanitizePassword(pass);
+ passStr = "&password=" + session.password;
+ } else {
+ session.password = false;
+ }
+
+ if (arr.length > 1 && arr[1] !== '') {
+ window.location += "&room=" + roomname + passStr;
+ } else {
+ window.location += "?room=" + roomname + passStr;
+ }
+ }
+}
+
+function sleep(ms = 0) {
+ return new Promise(r => setTimeout(r, ms)); // LOLz!
+}
+
+////////// Canvas Effects ///////////////
+
+function drawFrameMirrored() {
+ session.canvasCtx.save();
+ session.canvasCtx.scale(-1, 1);
+ session.canvasCtx.drawImage(session.canvasSource, 0, 0, session.canvas.width * -1, session.canvas.height);
+ session.canvasCtx.restore();
+}
+
+function setupCanvas() {
+ if (session.canvas === null) {
+ warnlog("SETUP CANVAS");
+ session.canvas = document.createElement("canvas");
+ session.canvas.width = 512;
+ session.canvas.height = 288;
+ session.canvasCtx = session.canvas.getContext('2d', {alpha: false, desynchronized: true});
+ //session.canvasCtx.width=288;
+ //session.canvasCtx.height=720;
+ session.canvasCtx.fillStyle = "blue";
+ session.canvasCtx.fillRect(0, 0, 512, 288);
+ session.canvasSource = document.createElement("video");
+ session.canvasSource.width=512;
+ session.canvasSource.height=288;
+ session.canvasSource.autoplay = true;
+ session.canvasSource.srcObject = new MediaStream();
+ }
+}
+
+function applyEffects(track, stream) {
+
+ setupCanvas();
+
+ session.canvasSource.srcObject.addTrack(track, stream);
+ session.canvasSource.width = track.getSettings().width || 1280;
+ session.canvasSource.height = track.getSettings().height || 720;
+ session.canvas.width = track.getSettings().width || 1280;
+ session.canvas.height = track.getSettings().height || 720;
+
+ var audioTracks = session.streamSrc.getAudioTracks();
+ session.streamSrc = session.canvas.captureStream();
+ audioTracks.forEach(function(trk) {
+ session.streamSrc.addTrack(trk);
+ });
+ session.videoElement.srcObject = session.streamSrc;
+
+ if (session.effects == 1) { // auto align face
+ setTimeout(function() {
+ drawFace();
+ }, 100);
+ } else if (session.effects == 2) { // mirror video at a canvas level
+ var drawRate = parseInt(1000 / track.getSettings().frameRate) + 1;
+ if (session.canvasInterval !== null) {
+ clearInterval(session.canvasInterval);
+ }
+ session.canvasInterval = setInterval(function() {
+ drawFrameMirrored();
+ }, drawRate);
+ } else if ((session.effects == 3) || (session.effects == 4) || (session.effects == 5)){ // blur & greenscreen (low and high)
+ TFLiteWorker();
+ } else if (session.effects == 6){
+ session.canvasSource.onloadeddata = mainMeshMask;
+ }
+ return session.streamSrc.getVideoTracks()[0];
+}
+
+function dataURItoArraybuffer(dataURI) {
+ var byteString = atob(dataURI.split(',')[1]);
+ var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
+ var ab = new ArrayBuffer(byteString.length);
+ var ia = new Uint8Array(ab);
+ for (var i = 0; i < byteString.length; i++) {
+ ia[i] = byteString.charCodeAt(i);
+ }
+ return ab;
+}
+
+
+var makeImagesActive = null;
+var makeImagesTimeout = null;
+async function makeImages(startup=false){
+ if (makeImagesActive===true){return;}
+ if (!session.videoElement){return;}
+ if (session.videoMuted){return;}
+ if (!session.videoElement.srcObject.getVideoTracks().length){return;}
+
+ if (makeImagesActive===null){
+ makeImagesActive=true;
+ session.webPcanvas = document.createElement("canvas");
+
+ var width = 480;
+ var height = 270;
+ var timeout = 60;
+
+ if (session.webPquality===0){
+ width = 1920;
+ height = 1080;
+ timeout = 15;
+ } else if (session.webPquality===1){
+ width = 1280;
+ height = 720;
+ timeout = 15;
+ } else if (session.webPquality===2){
+ width = 640;
+ height = 360;
+ timeout = 15;
+ } else if (session.webPquality===3){
+ width = 480;
+ height = 270;
+ timeout = 15;
+ } else if (session.webPquality===4){
+ width = 480;
+ height = 270;
+ timeout = 30;
+ } else {
+ width = 480;
+ height = 270;
+ timeout = 60;
+ }
+ session.webPcanvas.width = width;
+ session.webPcanvas.height = height;
+ session.webPcanvas.timeout = timeout;
+ session.webPcanvasCtx = session.webPcanvas.getContext('2d', {alpha: false, desynchronized: true});
+ session.webPcanvasCtx.fillStyle = "black";
+ session.webPcanvasCtx.fillRect(0, 0, width, height);
+ } else {
+ makeImagesActive=true;
+ }
+
+ if (startup){
+ var exit = true;
+ for (var i in session.pcs){
+ if (session.pcs[i].allowBroadcast){ // just for safety, to avoid a race condition, double check that it's still not active.
+ exit = false;
+ }
+ }
+ if (exit){
+ makeImagesActive=false;
+ return;
+ }
+ }
+
+ try{
+ session.webPcanvasCtx.drawImage(session.videoElement, 0, 0, session.webPcanvas.width, session.webPcanvas.height);
+ const webp = session.webPcanvas.toDataURL("image/webp",0.6); // seems like a good balance here
+ const arrayBuffer = dataURItoArraybuffer(webp);
+ var broadcasting = false;
+ for (var i in session.pcs){
+ try{
+ if (session.pcs[i].allowBroadcast){ // only publish to those seeking this stream
+ broadcasting = true;
+ if (!session.pcs[i].sendChannel.bufferedAmount){ // only send when the buffer is free. don't clog it up or wait.
+ session.pcs[i].sendChannel.send(arrayBuffer);
+ }
+ }
+ } catch(e){}
+ }
+ } catch(e){
+ warnlog(e);
+ makeImagesActive=false;
+ return;
+ }
+ makeImagesActive=false;
+ if (broadcasting){ // cancel broadcasting since now one is active.
+ clearTimeout(makeImagesTimeout);
+ makeImagesTimeout = setTimeout(function(){
+ window.requestAnimationFrame(makeImages);
+ },session.webPcanvas.timeout);
+ } else {
+ for (var i in session.pcs){
+ if (session.pcs[i].allowBroadcast){ // just for safety, to avoid a race condition, double check that it's still not active.
+ clearTimeout(makeImagesTimeout);
+ makeImagesTimeout = setTimeout(function(){
+ window.requestAnimationFrame(makeImages);
+ },session.webPcanvas.timeout);
+ return;
+ }
+ }
+ log("Stopping webP broadcast.");
+ }
+}
+
+var updateUserListTimeout=null
+var updateUserListActive = false;
+function updateUserList(){
+ if ((session.showList!==true) && (session.cleanOutput || (session.scene!==false) || !session.roomid || session.director || (session.showList===false))){return;}
+ clearInterval(updateUserListTimeout);
+ updateUserListTimeout = setTimeout(function(){
+ if (updateUserListActive){return;}
+ updateUserListActive=true;
+ try {
+ var added = false;
+ getById("userList").innerHTML = "";
+
+ for (var UUID in session.rpcs){
+ var track = false;
+ if (session.rpcs[UUID].streamSrc && session.rpcs[UUID].streamSrc.getVideoTracks().length){
+ var tracks = session.rpcs[UUID].streamSrc.getVideoTracks().forEach(function(trk){
+ //if (!trk.muted){
+ track=true;
+ //}
+ });
+ }
+ if (((session.rpcs[UUID].videoMuted || (track==false && !session.rpcs[UUID].imageElement)) && !session.rpcs[UUID].canvas) || ( session.infocus && session.infocus!==UUID )){
+
+ if (UUID === session.directorUUID){
+ if (!session.rpcs[UUID].streamSrc){ // director not active yet, so we won't bother showing it.
+ continue;
+ }
+ }
+
+ var insert = document.createElement("div");
+ if (session.rpcs[UUID].label){
+ insert.innerText = session.rpcs[UUID].label + "";
+ } else if (session.directorUUID === UUID){
+ insert.innerText = "Director";
+ } else {
+ insert.innerText = "Unknown User";
+ }
+ getById("userList").appendChild(insert);
+
+ if (session.rpcs[UUID].remoteMuteState || !(session.rpcs[UUID].streamSrc)){
+ var muteInsert = document.createElement("div");
+ muteInsert.className = "video-mute-state-userlist";
+ muteInsert.innerHTML = ' ';
+ insert.appendChild(muteInsert);
+ } else if (session.rpcs[UUID].voiceMeter){
+ insert.appendChild(session.rpcs[UUID].voiceMeter);
+ }
+ //getById("userList").innerHTML += " ";
+ added=true;
+ }
+ }
+
+ if (!added){
+ getById("connectUsers").style.display = "none";
+ } else {
+ getById("connectUsers").style.display = "block";
+ }
+ } catch(e){}
+ updateUserListActive=false;
+ },200);
+}
+
+var LaunchTFWorkerCallback = false;
+function TFLiteWorker(){
+ if (session.tfliteModule==false){
+ LaunchTFWorkerCallback=true
+ return;
+ }
+ if (TFLITELOADING){LaunchTFWorkerCallback=true;return;}
+ LaunchTFWorkerCallback=false;
+
+ const segmentationWidth = 256;
+ const segmentationHeight = 144;
+ const segmentationPixelCount = segmentationWidth * segmentationHeight;
+ const inputMemoryOffset = session.tfliteModule._getInputMemoryOffset() / 4;
+ const outputMemoryOffset = session.tfliteModule._getOutputMemoryOffset() / 4;
+ const segmentationMask = new ImageData(segmentationWidth, segmentationHeight);
+ const segmentationMaskCanvas = document.createElement('canvas');
+ segmentationMaskCanvas.width = segmentationWidth;
+ segmentationMaskCanvas.height = segmentationHeight;
+ const segmentationMaskCtx = segmentationMaskCanvas.getContext('2d');
+
+ session.tfliteModule.img = document.createElement("img");
+ session.tfliteModule.img.onload = function(){
+ URL.revokeObjectURL(session.tfliteModule.img.src); // no longer needed, free memory
+ session.tfliteModule.img.ready = true;
+ }
+ session.tfliteModule.img.src = "./media/bg_sample.webp";
+ session.tfliteModule.img.ready = false;
+
+ console.log('Starting Loop');
+
+
+ function process(){
+ if (session.tfliteModule.activelyProcessing){return;}
+ session.tfliteModule.activelyProcessing=true;
+ try{
+ segmentationMaskCtx.drawImage(
+ session.canvasSource,
+ 0,
+ 0,
+ session.canvasSource.width,
+ session.canvasSource.height,
+ 0,
+ 0,
+ segmentationWidth,
+ segmentationHeight
+ )
+
+ const imageData = segmentationMaskCtx.getImageData(
+ 0,
+ 0,
+ segmentationWidth,
+ segmentationHeight
+ );
+
+ for (let i = 0; i < segmentationPixelCount; i++) {
+ session.tfliteModule.HEAPF32[inputMemoryOffset + i * 3] = imageData.data[i * 4] / 255;
+ session.tfliteModule.HEAPF32[inputMemoryOffset + i * 3 + 1] = imageData.data[i * 4 + 1] / 255;
+ session.tfliteModule.HEAPF32[inputMemoryOffset + i * 3 + 2] = imageData.data[i * 4 + 2] / 255;
+ }
+
+ session.tfliteModule._runInference();
+
+ for (let i = 0; i < segmentationPixelCount; i++) {
+ const background = session.tfliteModule.HEAPF32[outputMemoryOffset + i * 2];
+ const person = session.tfliteModule.HEAPF32[outputMemoryOffset + i * 2 + 1];
+ const shift = Math.max(background, person);
+ const backgroundExp = Math.exp(background - shift);
+ const personExp = Math.exp(person - shift);
+ segmentationMask.data[i * 4 + 3] = (255 * personExp) / (backgroundExp + personExp); // softmax
+ }
+ segmentationMaskCtx.putImageData(segmentationMask, 0, 0);
+
+ session.canvasCtx.globalCompositeOperation = 'copy';
+ session.canvasCtx.filter = 'blur(4px)';
+ session.canvasCtx.drawImage(
+ segmentationMaskCanvas,
+ 0,
+ 0,
+ segmentationWidth,
+ segmentationHeight,
+ 0,
+ 0,
+ session.canvasSource.width,
+ session.canvasSource.height
+ )
+
+ session.canvasCtx.globalCompositeOperation = 'source-in';
+ session.canvasCtx.filter = 'none';
+ session.canvasCtx.drawImage(session.canvasSource, 0, 0);
+
+ session.canvasCtx.globalCompositeOperation = 'destination-over';
+ if (session.effects=="4"){ // greenscreen
+ session.canvasCtx.filter = 'none';
+ session.canvasCtx.fillStyle = "#0F0";
+ session.canvasCtx.fillRect(0, 0, session.canvas.width, session.canvas.height);
+ } else if (session.effects=="5"){
+ session.canvasCtx.filter = 'none';
+ if (session.tfliteModule.img.ready){
+ session.canvasCtx.drawImage(session.tfliteModule.img, 0, 0, session.canvas.width, session.canvas.height);
+ }
+ } else if (session.effects=="3"){ // BLUR
+ session.canvasCtx.filter = 'blur(4px)'; // Does not work on Safari
+ session.canvasCtx.drawImage(session.canvasSource, 0, 0);
+ } else {
+ session.tfliteModule.activelyProcessing=false;
+ return;
+ }
+ } catch (e){
+ errorlog(e);
+ session.tfliteModule.activelyProcessing=false;
+ return;
+ }
+ session.tfliteModule.activelyProcessing=false;
+ window.requestAnimationFrame(process);
+ }
+ process();
+}
+
+
+function mainMeshMask() {
+ if (model == false){
+ setTimeout(function(){mainMeshMask();},1000);
+ return;
+ }
+ function heatMapColorforValue(value){
+ var h = parseInt((1.0 - value) * 240);
+ if (h<0){h=0;}
+ if (h>240){h=240;}
+ return "hsl(" + h + ", 100%, 50%)";
+ }
+ async function innerLoop(){
+ const predictions = await model.estimateFaces({
+ input: session.canvasSource
+ });
+ if (predictions.length > 0) {
+ for (let j = 0; j < predictions.length; j++) {
+ const fp = predictions[j].annotations;
+ session.canvasCtx.fillStyle = "#000000";
+ session.canvasCtx.fillRect(0, 0, session.canvas.width, session.canvas.height);
+ const keypoints = predictions[j].scaledMesh
+ for (let i = 0; i < keypoints.length; i++) {
+ const [x, y, z] = keypoints[i];
+ session.canvasCtx.fillStyle = heatMapColorforValue((z+40)/60);
+ session.canvasCtx.fillRect(parseInt(x), parseInt(y), 5, 5);
+ }
+ }
+ }
+ window.requestAnimationFrame(innerLoop);
+ }
+ innerLoop();
+}
+
+function drawFace() {
+ var faceAlignment = (function() {
+ var vid = session.canvasSource;
+
+ var canvas = session.canvas;
+ var ctx = session.canvasCtx;
+
+ var canvas_tmp = document.createElement("canvas");
+ var ctx_tmp = canvas_tmp.getContext('2d');
+
+ //var stream = canvas.captureStream(30);
+
+ var image = new Image();
+ var zoom = 10;
+ var scale = 1;
+ var lastFace = {};
+
+ var w = vid.videoWidth;
+ var h = vid.videoHeight;
+ var x = vid.videoWidth / 2;
+ var y = vid.videoHeight / 2;
+
+ lastFace.x = vid.videoWidth / 2;
+ lastFace.y = vid.videoHeight / 2;
+ lastFace.w = vid.videoWidth;
+ lastFace.h = vid.videoHeight;
+ var yoffset = 0;
+
+ if (window.FaceDetector == undefined) {
+ //console.error('Face Detection not supported');
+ var faceDetector = false;
+ } else {
+ var faceDetector = new FaceDetector();
+ //console.log('FaceD Loaded');
+ setTimeout(function() {
+ detect();
+ }, 300);
+ setTimeout(function() {
+ draw();
+ }, 33);
+ }
+
+ canvas.height = vid.videoHeight;
+ canvas.width = vid.videoWidth;
+ canvas_tmp.height = vid.videoHeight;
+ canvas_tmp.width = vid.videoWidth;
+ image.src = canvas_tmp.toDataURL();
+ scale = canvas.width / image.width;
+ lastFace.x = 0;
+ lastFace.y = 0;
+ lastFace.w = 1280 / 3 / 16 * zoom;
+ lastFace.h = 720 / 3 / 9 * zoom;
+
+ w = 1280 / 5;
+ h = 720 / 5;
+ x = 1280 / 2;
+ y = 720 / 2 - w * 9 / zoom / 2;
+
+ async function detect() {
+
+ if (session.effects !== 1){return;}
+
+ ctx_tmp.drawImage(vid, 0, 0, vid.videoWidth, vid.videoHeight);
+ image.src = canvas_tmp.toDataURL();
+ await faceDetector.detect(image).then(faces => {
+
+ if (faces.length === 0) {
+ log("NO FACES");
+ setTimeout(function() {
+ detect();
+ }, 10);
+ return;
+ }
+ for (let face of faces) {
+ lastFace.x = (face.boundingBox.x + lastFace.x) / 2 || face.boundingBox.x;
+ lastFace.y = (face.boundingBox.y + lastFace.y) / 2 || face.boundingBox.y;
+ lastFace.w = (face.boundingBox.width + lastFace.w) / 2 || face.boundingBox.width;
+ lastFace.h = (face.boundingBox.height + lastFace.h) / 2 || face.boundingBox.height;
+ }
+
+ setTimeout(function() {
+ detect();
+ }, 300);
+ }).catch((e) => {
+ console.error("Boo, Face Detection failed: " + e);
+ });
+
+ }
+
+ function draw() {
+
+ if (session.effects !== 1){return;}
+
+ canvas.height = vid.videoHeight;
+ canvas.width = vid.videoWidth;
+
+ if (lastFace.w - w < 0.15 * lastFace.w) {
+ w = w * 0.999 + 0.001 * lastFace.w;
+ }
+ if (lastFace.h - h < 0.15 * lastFace.h) {
+ h = h * 0.999 + 0.001 * lastFace.h;
+ }
+ if (Math.abs(x - (lastFace.x + lastFace.w / 2)) > 0.15 * (lastFace.x + lastFace.w / 2.0)) {
+ x = x * 0.999 + 0.001 * (lastFace.x + lastFace.w / 2.0);
+ }
+ if (Math.abs(y - (lastFace.y + lastFace.h / 2)) > 0.15 * (lastFace.y + lastFace.h / 2.0)) {
+ y = y * 0.999 + 0.001 * (lastFace.y + lastFace.h / 2.0);
+ }
+
+ yoffset = w * 9 / zoom / 2;
+
+ var yyy = y - w * 9 / zoom - yoffset;
+ var hhh = w * 3 * 9 / zoom;
+ var www = w * 3 * 16 / zoom;
+ var xxx = x - w * 16 / zoom * 1.5;
+
+ if (www + xxx < 1280) {
+ xxx = 1280 - www;
+ }
+ if (hhh + yyy < 720) {
+ yyy = 720 - hhh;
+ }
+
+ if (www + xxx > 1280) {
+ xxx = 1280 - www;
+ }
+ if (hhh + yyy > 720) {
+ yyy = 720 - hhh;
+ }
+
+ if (yyy < 0) {
+ yyy = 0;
+ }
+ if (xxx < 0) {
+ xxx = 0;
+ }
+
+ ctx.drawImage(vid, xxx, yyy, www, hhh, 0, 0, vid.videoWidth, vid.videoHeight);
+
+ setTimeout(function() {
+ draw();
+ }, 30);
+ }
+ })();
+}
+
+
+//////// END CANVAS EFFECTS ///////////////////
+
+
+if (urlParams.has('permaid') || urlParams.has('push')) {
+ session.permaid = urlParams.get('push') || urlParams.get('permaid');
+
+ if (session.permaid) {
+ session.streamID = sanitizeStreamID(session.permaid);
+ } else {
+ session.permaid = null;
+ }
+
+ if (urlParams.has('permaid')) {
+ updateURL("permaid=" + session.streamID, true, false); // I'm not deleting the permaID first tho...
+ } else {
+ updateURL("push=" + session.streamID, true, false); // I'm not deleting the permaID first tho...
+ }
+
+ if (urlParams.has('director') || urlParams.has('dir')) { // if I do a short form of this, it will cause duplications in the code elsewhere.
+ //var director_room_input = urlParams.get('director');
+ //director_room_input = sanitizeRoomName(director_room_input);
+ //createRoom(director_room_input);
+ session.permaid = false; // used to avoid a trigger later on.
+ } else {
+ getById("container-1").className = 'column columnfade advanced';
+ getById("container-4").className = 'column columnfade advanced';
+ getById("dropButton").className = 'column columnfade advanced';
+
+ getById("info").innerHTML = "";
+ if (session.videoDevice === 0) {
+ getById("add_camera").innerHTML = "Share your Microphone";
+ miniTranslate(getById("add_camera"), "share-your-mic");
+ } else {
+ getById("add_camera").innerHTML = "Share your Camera";
+ miniTranslate(getById("add_camera"), "share-your-camera");
+ }
+ getById("add_screen").innerHTML = "Share your Screen";
+ miniTranslate(getById("add_screen"), "share-your-screen");
+
+ getById("passwordRoom").value = "";
+ getById("videoname1").value = "";
+ getById("dirroomid").innerHTML = "";
+ getById("roomid").innerHTML = "";
+
+ getById("mainmenu").style.alignSelf = "center";
+ getById("mainmenu").classList.add("mainmenuclass");
+ getById("header").style.alignSelf = "center";
+
+ if ((iOS) || (iPad)) {
+ getById("header").style.display = "none"; // just trying to free up space.
+ }
+
+ if (session.webcamonly == true) { // mobile or manual flag 'webcam' pflag set
+ getById("head1").innerHTML = '- Please accept any camera permissions ';
+ } else {
+ getById("head1").innerHTML = '- Please select which you wish to share ';
+ }
+ }
+}
+
+if ((session.roomid) || (urlParams.has('roomid')) || (urlParams.has('r')) || (urlParams.has('room')) || (filename) || (session.permaid !== false)) {
+
+ var roomid = "";
+ if (filename) {
+ roomid = filename;
+ } else if (urlParams.has('room')) {
+ roomid = urlParams.get('room');
+ } else if (urlParams.has('roomid')) {
+ roomid = urlParams.get('roomid');
+ } else if (urlParams.has('r')) {
+ roomid = urlParams.get('r');
+ } else if (session.roomid) {
+ roomid = session.roomid;
+ }
+
+ session.roomid = sanitizeRoomName(roomid);
+
+ if (!(session.cleanOutput)) {
+ if (session.roomid === "test") {
+ if (session.password === session.defaultPassword) {
+ window.focus();
+ var testRoomResponse = confirm("The room name 'test' is very commonly used and may not be secure.\n\nAre you sure you wish to proceed?");
+ if (testRoomResponse == false) {
+ hangup();
+ throw new Error("User requested to not enter room 'room'.");
+ }
+ }
+ }
+ }
+
+ if (session.audioDevice === false && session.outputDevice === false) {
+ getById("headphonesDiv2").style.display = "inline-block";
+ getById("headphonesDiv").style.display = "inline-block";
+ }
+ getById("addPasswordBasic").style.display = "none";
+
+ getById("info").innerHTML = "";
+ getById("info").style.color = "#CCC";
+ getById("videoname1").value = session.roomid;
+ getById("dirroomid").innerText = session.roomid;
+ getById("roomid").innerText = session.roomid;
+ getById("container-1").className = 'column columnfade advanced';
+ getById("container-4").className = 'column columnfade advanced';
+ getById("container-7").style.display = 'none';
+ getById("container-8").style.display = 'none';
+ getById("mainmenu").style.alignSelf = "center";
+ getById("mainmenu").classList.add("mainmenuclass");
+ getById("header").style.alignSelf = "center";
+
+ if (session.webcamonly == true) { // mobile or manual flag 'webcam' pflag set
+ getById("head1").innerHTML = '';
+ } else {
+ getById("head1").innerHTML = 'Please select an option to join. ';
+ }
+
+ if (session.roomid.length > 0) {
+ if (session.videoDevice === 0) {
+ if (session.audioDevice === 0) {
+ getById("add_camera").innerHTML = "Join room";
+ miniTranslate(getById("add_camera"), "join-room");
+ } else {
+ getById("add_camera").innerHTML = "Join room with Microphone";
+ miniTranslate(getById("add_camera"), "join-room-with-mic");
+ }
+ } else {
+ getById("add_camera").innerHTML = "Join Room with Camera";
+ miniTranslate(getById("add_camera"), "join-room-with-camera");
+ }
+ getById("add_screen").innerHTML = "Screenshare with Room";
+ miniTranslate(getById("add_screen"), "share-screen-with-room");
+ } else {
+ if (session.videoDevice === 0) {
+ getById("add_camera").innerHTML = "Share your Microphone";
+ miniTranslate(getById("add_camera"), "share-your-mic");
+ } else {
+ getById("add_camera").innerHTML = "Share your Camera";
+ miniTranslate(getById("add_camera"), "share-your-camera");
+ }
+ getById("add_screen").innerHTML = "Share your Screen";
+ miniTranslate(getById("add_screen"), "share-your-screen");
+ }
+ getById("head3").className = 'advanced';
+
+ if (session.scene !== false) {
+ getById("container-4").className = 'column columnfade';
+ getById("container-3").className = 'column columnfade';
+ getById("container-2").className = 'column columnfade';
+ getById("container-1").className = 'column columnfade';
+ getById("header").className = 'advanced';
+ getById("info").className = 'advanced';
+ getById("head1").className = 'advanced';
+ getById("head2").className = 'advanced';
+ getById("mainmenu").style.display = "none";
+ getById("translateButton").style.display = "none";
+ log("Update Mixer Event on REsize SET");
+ window.addEventListener("resize", updateMixer);
+ window.addEventListener("orientationchange", function() {
+ setTimeout(updateMixer, 200);
+ });
+ joinRoom(session.roomid); // this is a scene, so we want high resolutions
+ getById("main").style.overflow = "hidden";
+ } else {
+ if ((session.permaid === null) && (session.roomid == "")) {
+ if (!(session.cleanOutput)) {
+ getById("head3").className = '';
+ }
+ }
+ }
+
+} else if (urlParams.has('director') || urlParams.has('dir')) { // if I do a short form of this, it will cause duplications in the code elsewhere.
+ if (directorLanding == false) {
+ var director_room_input = urlParams.get('director') || urlParams.get('dir');
+ director_room_input = sanitizeRoomName(director_room_input);
+ log("director_room_input:" + director_room_input);
+ createRoom(director_room_input);
+ }
+} else if ((session.view) && (session.permaid === false)) {
+ //if (!session.activeSpeaker){
+ session.audioMeterGuest = false;
+ //}
+ if (session.audioEffects === null) {
+ session.audioEffects = false;
+ }
+ log("Update Mixer Event on REsize SET");
+ getById("translateButton").style.display = "none";
+ window.addEventListener("resize", updateMixer);
+ window.addEventListener("orientationchange", function() {
+ setTimeout(updateMixer, 200);
+ });
+ getById("main").style.overflow = "hidden";
+}
+
+if (session.audioEffects === null) {
+ session.audioEffects = true;
+}
+
+if (session.audioEffects) {
+ getById("channelGroup1").style.display = "block";
+ getById("channelGroup2").style.display = "block";
+}
+
+if (urlParams.has('hidemenu') || urlParams.has('hm')) { // needs to happen the room and permaid applications
+ getById("mainmenu").style.display = "none";
+ getById("header").style.display = "none";
+ getById("mainmenu").style.opacity = 0;
+ getById("header").style.opacity = 0;
+}
+
+if (urlParams.has('hideheader') || urlParams.has('noheader') || urlParams.has('hh')) { // needs to happen the room and permaid applications
+ getById("header").style.display = "none";
+ getById("header").style.opacity = 0;
+}
+
+function checkConnection() {
+ if (session.ws === null) {
+ return;
+ }
+ if (document.getElementById("qos")) { // true or false; null might cause problems?
+ if ((session.ws) && (session.ws.readyState === WebSocket.OPEN)) {
+ getById("qos").style.color = "white";
+ } else {
+ getById("qos").style.color = "red";
+ }
+ }
+}
+setInterval(function() {
+ checkConnection();
+}, 5000);
+
+
+function remoteStats(msg){
+ if (session.director){
+ var output = "";
+ var size = 0;
+ for (var key in msg.remoteStats) {
+ if (msg.remoteStats.hasOwnProperty(key)) size++;
+ }
+ output += "Total Viewers: "+size;
+ for (var uuid in msg.remoteStats){
+ if ("scene" in msg.remoteStats[uuid] && msg.remoteStats[uuid].scene !== false){
+ output+=" scene: "+msg.remoteStats[uuid].scene;
+ if ("video_bitrate_kbps" in msg.remoteStats[uuid]){
+ output+=" video_bitrate_kbps: "+msg.remoteStats[uuid].video_bitrate_kbps;
+ }
+ if ("audio_bitrate_kbps" in msg.remoteStats[uuid]){
+ output+=" audio_bitrate_kbps: "+msg.remoteStats[uuid].audio_bitrate_kbps;
+ }
+ if (msg.remoteStats[uuid].resolution){
+ output+=" resolution: "+msg.remoteStats[uuid].resolution;
+ }
+ if (msg.remoteStats[uuid].video_encoder){
+ output+=" video_encoder: "+msg.remoteStats[uuid].video_encoder;
+ }
+ if ("scaleFactor" in msg.remoteStats[uuid]){
+ output+=" scaleFactor: "+msg.remoteStats[uuid].scaleFactor;
+ }
+ if ("nacks_per_second" in msg.remoteStats[uuid]){
+ output+=" nacks_per_second: "+msg.remoteStats[uuid].nacks_per_second;
+ }
+ if (msg.remoteStats[uuid].retransmitted_kbps){
+ output+=" quality_limitation_reason: "+msg.remoteStats[uuid].retransmitted_kbps;
+ }
+ if (msg.remoteStats[uuid].quality_limitation_reason){
+ output+=" quality_limitation_reason: "+msg.remoteStats[uuid].quality_limitation_reason;
+ }
+ }
+ }
+ warnUser(output);
+ };
+ if (isIFrame){
+ parent.postMessage({"remoteStats": msg.remoteStats }, "*");
+ }
+}
+
+
+function printViewStats(menu, UUID) { // Stats for viewing a remote video
+ if (!session.rpcs[UUID]){
+ menu.innerHTML = " Remote Publisher Disconnected";
+ return;
+ }
+
+ var statsObj = session.rpcs[UUID].stats;
+ var streamID = session.rpcs[UUID].streamID;
+ var scrollLeft = menu.scrollLeft;
+ var scrollTop = menu.scrollTop;
+ menu.innerHTML = "StreamID: " + streamID + " ";
+ menu.innerHTML += printValues(statsObj);
+ menu.scrollTop = scrollTop;
+ menu.scrollLeft = scrollLeft;
+
+ errorlog(statsObj);
+}
+
+function printValues(obj) { // see: printViewStats
+ var out = "";
+ for (var key in obj) {
+ if (typeof obj[key] === "object") {
+ if (obj[key] != null) {
+ var tmp = key;
+ tmp = sanitizeChat((tmp));
+ out += "" + tmp + " "
+ out += printValues(obj[key]);
+ }
+ } else {
+ if (key.startsWith("_")) {
+ // if it starts with _, we don't want to show it.
+ } else {
+ try {
+ var unit = '';
+
+ var value = obj[key];
+
+ var stat = sanitizeChat(key);
+
+ if (typeof obj[key] == "string") {
+ value = sanitizeChat((value));
+ }
+
+ //
+ if (key == 'useragent') {
+ value = ""+value+" "
+ }
+
+ if (key == 'Bitrate_in_kbps') {
+ var unit = " kbps";
+ stat = "Bitrate";
+ }
+ else if (key == 'type') {
+ var unit = "";
+ stat = 'Type';
+
+ if (value == "Audio Track") {
+ value = "🔊 " + value;
+ //out += " ";
+ }
+
+ if (value == "Video Track") {
+ value = "📺 " + value;
+ }
+
+ }
+ else if (key == 'packetLoss_in_percentage') {
+ var unit = " %";
+ stat = 'Packet Loss 📶';
+ value = parseInt(parseFloat(value) * 10000) / 10000.0;
+ }
+ else if (key == 'local_relayIP') {
+ value = "" + value + " ";
+ }
+ else if (key == 'remote_relay_IP') {
+ value = "" + value + " ";
+ }
+ else if (key == 'local_candidateType') {
+ if (value == "relay") {
+ value = "💸 relay server";
+ }
+ }
+ else if (key == 'remote_candidateType') {
+ if (value == "relay") {
+ value = "💸 relay server";
+ }
+ }
+ else if (key == 'height_url') {
+ if (value == false) {
+ continue;
+ }
+ }
+ else if (key == 'width_url') {
+ if (value == false) {
+ continue;
+ }
+ }
+ else if (key == 'height_url') {
+ if (value == false) {
+ continue;
+ }
+ }
+ else if (key == 'version') {
+ stat = "OBS.Ninja Version";
+ } else if (key == 'platform') {
+ stat = "Platform (OS)";
+ }
+ else if (key == 'aec_url') {
+ stat = "Echo-Cancellation";
+ }
+ else if (key == 'agc_url') {
+ stat = "Auto-Gain (agc)";
+ }
+ else if (key == 'denoise_url') {
+ stat = "De-noising ";
+ }
+ else if (key == 'audio_level') {
+ stat = "Audio Level";
+ }
+ else if (key == 'Buffer_Delay_in_ms') {
+ var unit = " ms";
+ stat = 'Buffer Delay';
+ }
+ else if (value === null) {
+ value = "null";
+ }
+ else if (key == "stereo_url") {
+ stat = "Pro-Audio (Stereo-mode)";
+ if (value == 3) {
+ value = "3 (outbound hi-fi) Use Headphones";
+ } else if (value == 1) {
+ value = "1 (in & out hi-fi) Use Headphones";
+ } else if (value == 2) {
+ value = "3 (inbound hi-fi)";
+ } else if (value == 4) {
+ value = "3 (multichannel) Use Headphones";
+ } else if (value == 5) {
+ value = "5 (auto-mode) Use Headphones";
+ }
+ }
+ else if (value === false) {
+ continue
+ }
+ else if (value === "false") {
+ continue
+ }
+ out += "" + stat + " " + value + unit + " ";
+ } catch (e) {
+ warnlog(e);
+ }
+ }
+ }
+ }
+ return out;
+}
+
+
+function printMyStats(menu) { // see: setupStatsMenu
+ var scrollLeft = getById("menuStatsBox").scrollLeft;
+ var scrollTop = getById("menuStatsBox").scrollTop;
+ menu.innerHTML = "";
+
+ session.stats.outbound_connections = Object.keys(session.pcs).length;
+ session.stats.inbound_connections = Object.keys(session.rpcs).length;
+
+ function printViewValues(obj) {
+
+ if (!(document.getElementById("menuStatsBox"))){
+ return;
+ }
+
+ for (var key in obj) {
+ if (typeof obj[key] === "object") {
+ printViewValues(obj[key]);
+ } else {
+
+ if (key.startsWith("_")){continue;}
+
+ var stat = sanitizeChat(key);
+ var value = obj[key];
+ if (typeof value == "string") {
+ value = sanitizeChat((value));
+ }
+
+ if (value === false){continue;}
+
+ if (key == 'useragent') {
+ value = ""+value+" "
+ }
+
+ if (key == 'local_relayIP') {
+ value = "" + value + " ";
+ }
+ if (key == 'remote_relay_IP') {
+ value = "" + value + " ";
+ }
+ if (key == 'local_candidateType') {
+ if (value == "relay") {
+ value = "💸 relay server";
+ }
+ }
+ if (key == 'remote_candidateType') {
+ if (value == "relay") {
+ value = "💸 relay server";
+ }
+ }
+
+ menu.innerHTML += "" + stat + " " + value + " ";
+ }
+ }
+ }
+ printViewValues(session.stats);
+ menu.innerHTML += "Send Keyframe to Viewers ";
+ for (var uuid in session.pcs) {
+ printViewValues(session.pcs[uuid].stats);
+ menu.innerHTML += " ";
+ }
+ if ((iOS) || (iPad)){
+ menu.innerHTML += "
";
+ }
+ try {
+ getById("menuStatsBox").scrollLeft = scrollLeft;
+ getById("menuStatsBox").scrollTop = scrollTop;
+ } catch (e) {}
+}
+
+
+function updateLocalStats(){
+
+ var totalBitrate = 0;
+ var totalBitrate2 = 0;
+ var cpuLimited = false;
+ for (var uuid in session.pcs) {
+ if ("video_bitrate_kbps" in session.pcs[uuid].stats){
+ totalBitrate+=session.pcs[uuid].stats.video_bitrate_kbps || 0;
+ }
+ if ("audio_bitrate_kbps" in session.pcs[uuid].stats){
+ totalBitrate+=session.pcs[uuid].stats.audio_bitrate_kbps || 0;
+ }
+ if ("total_sending_bitrate_kbps" in session.pcs[uuid].stats){
+ totalBitrate2+=session.pcs[uuid].stats.total_sending_bitrate_kbps || 0;
+ }
+
+ if ("quality_limitation_reason" in session.pcs[uuid].stats){
+ if (session.pcs[uuid].stats.quality_limitation_reason == "cpu"){
+ cpuLimited=true;
+ }
+ }
+
+ if (uuid in session.rpcs){
+ if (session.pcs[uuid].stats.label){
+ session.pcs[uuid].stats.label = session.rpcs[uuid].label;
+ }
+ if (session.pcs[uuid].stats.streamID){
+ session.pcs[uuid].stats.streamID = session.rpcs[uuid].streamID;
+ }
+ }
+
+ setTimeout(function(UUID) {
+ if (!( session.pcs[UUID])){return;}
+ session.pcs[UUID].getStats().then(function(stats) {
+ if ("audio_bitrate_kbps" in session.pcs[UUID].stats){
+ session.pcs[UUID].stats.audio_bitrate_kbps=0;
+ }
+ stats.forEach(stat => {
+ if (stat.type == "transport"){
+ if ("bytesSent" in stat) {
+ if ("_bytesSent" in session.pcs[UUID].stats){
+ if (session.pcs[UUID].stats._timestamp){
+ if (stat.timestamp){
+ session.pcs[UUID].stats.total_sending_bitrate_kbps = parseInt(8*(stat.bytesSent - session.pcs[UUID].stats._bytesSent)/(stat.timestamp - session.pcs[UUID].stats._timestamp));
+ }
+ }
+ }
+ session.pcs[UUID].stats._bytesSent = stat.bytesSent;
+ }
+ if ("timestamp" in stat) {
+ session.pcs[UUID].stats._timestamp = stat.timestamp;
+ }
+ } else if (stat.type == "outbound-rtp") {
+ if (stat.kind == "video") {
+
+ if ("qualityLimitationReason" in stat) {
+ 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.video_encoder = stat.encoderImplementation;
+ }
+ if ("bytesSent" in stat) {
+ if ("_bytesSentVideo" in session.pcs[UUID].stats){
+ if (session.pcs[UUID].stats._timestamp1){
+ session.pcs[UUID].stats.video_bitrate_kbps = parseInt(8*(stat.bytesSent - session.pcs[UUID].stats._bytesSentVideo)/(stat.timestamp - session.pcs[UUID].stats._timestamp1));
+ if (stat.timestamp){
+ }
+ }
+ }
+ session.pcs[UUID].stats._bytesSentVideo = stat.bytesSent;
+ }
+
+ if ("nackCount" in stat) {
+ if ("_nackCount" in session.pcs[UUID].stats){
+ if (session.pcs[UUID].stats._timestamp1){
+ if (stat.timestamp){
+ session.pcs[UUID].stats.nacks_per_second = parseInt(10000*(stat.nackCount - session.pcs[UUID].stats._nackCount)/(stat.timestamp - session.pcs[UUID].stats._timestamp1))/10;
+ }
+ }
+ }
+ }
+ if ("retransmittedBytesSent" in stat) {
+ if ("_retransmittedBytesSent" in session.pcs[UUID].stats){
+ if (session.pcs[UUID].stats._timestamp1){
+ if (stat.timestamp){
+ session.pcs[UUID].stats.retransmitted_kbps = parseInt(8*(stat.retransmittedBytesSent - session.pcs[UUID].stats._retransmittedBytesSent)/(stat.timestamp - session.pcs[UUID].stats._timestamp1));
+ }
+ }
+ }
+ }
+
+ if ("nackCount" in stat) {
+ session.pcs[UUID].stats._nackCount = stat.nackCount;
+
+ }
+
+ if ("retransmittedBytesSent" in stat) {
+ session.pcs[UUID].stats._retransmittedBytesSent = stat.retransmittedBytesSent;
+
+ }
+
+ if ("timestamp" in stat) {
+ session.pcs[UUID].stats._timestamp1 = stat.timestamp;
+ }
+
+ if ("pliCount" in stat) {
+ session.pcs[UUID].stats.total_pli_count = stat.pliCount;
+ }
+ if ("keyFramesEncoded" in stat) {
+ session.pcs[UUID].stats.total_key_frames_encoded = stat.keyFramesEncoded;
+ }
+
+
+ } else if (stat.kind == "audio") {
+ if ("bytesSent" in stat) {
+ if (session.pcs[UUID].stats._bytesSentAudio){
+ if (session.pcs[UUID].stats._timestamp2){
+ if (stat.timestamp){
+ if ("audio_bitrate_kbps" in session.pcs[UUID].stats){
+ session.pcs[UUID].stats.audio_bitrate_kbps += parseInt(8*(stat.bytesSent - session.pcs[UUID].stats._bytesSentAudio)/(stat.timestamp - session.pcs[UUID].stats._timestamp2));
+ } else {
+ session.pcs[UUID].stats.audio_bitrate_kbps=0;
+ }
+ }
+ }
+ }
+ }
+ if ("timestamp" in stat) {
+ session.pcs[UUID].stats._timestamp2 = stat.timestamp;
+ }
+
+ if ("bytesSent" in stat) {
+ session.pcs[UUID].stats._bytesSentAudio = stat.bytesSent;
+
+ }
+ }
+ } 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 ("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;
+ }
+ 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);
+ }
+ }
+ }
+ return;
+ });
+ return;
+ });
+ }, 0, uuid);
+ }
+ var headerStats = "Viewers: ";
+ try{
+ headerStats += Object.keys(session.pcs).length || 0;
+ } catch(e){}
+ headerStats += ", Upload (kbps): "+totalBitrate2; // + " / "+totalBitrate;
+ if (cpuLimited){
+ headerStats += ", CPU Overloaded";
+ }
+ try{
+ if (Object.keys(session.pcs).length){
+ getById("head5").classList.remove("advanced");
+ }
+ } catch(e){}
+ getById("head5").innerHTML = headerStats;
+}
+
+
+function updateStats(obsvc = false) {
+ log('updateStats - resolution found');
+ if (document.getElementById('previewWebcam')) {
+ var ele = document.getElementById('previewWebcam');
+ var wcs = "webcamstats";
+ } else if (document.getElementById('videosource')) {
+ var ele = document.getElementById('videosource');
+ var wcs = "webcamstats3";
+ } else {
+ return;
+ }
+
+ try {
+ getById(wcs).innerHTML = "";
+ ele.srcObject.getVideoTracks().forEach(
+ function(track) {
+ if ((obsvc) && (parseInt(track.getSettings().frameRate) == 30)) {
+ getById(wcs).innerHTML = "Video Settings: " + (track.getSettings().width || 0) + "x" + (track.getSettings().height || 0) + " @ up to 60fps";
+ } else {
+ getById(wcs).innerHTML = "Current Video Settings: " + (track.getSettings().width || 0) + "x" + (track.getSettings().height || 0) + "@" + (parseInt(track.getSettings().frameRate * 10) / 10) + "fps";
+ }
+ }
+ );
+
+ } catch (e) {
+ errorlog(e);
+ }
+}
+
+function toggleMute(apply = false) { // TODO: I need to have this be MUTE, toggle, with volume not touched.
+
+ log("muting");
+
+ if (session.director) {
+ if (!session.directorEnabledPPT) {
+ log("Director doesn't have PPT enabled yet");
+ // director has not enabled PTT yet.
+ return;
+ }
+ }
+
+ if (apply) {
+ session.muted = !session.muted; // we flip here as we are going to flip again in a second.
+ }
+ //try{var ptt = getById("press2talk");} catch(e){var ptt=false;}
+
+
+ if (session.muted == false) {
+ session.muted = true;
+ getById("mutetoggle").className = "las la-microphone-slash my-float toggleSize";
+ if (!(session.cleanOutput)){
+ getById("mutebutton").className = "float2 red puslate";
+ getById("header").classList.add('red');
+
+ if (session.localMuteElement){
+ session.localMuteElement.style.display = "block";
+ }
+
+ }
+ if (session.streamSrc) {
+ session.streamSrc.getAudioTracks().forEach((track) => {
+ track.enabled = false;
+ });
+ }
+ //if (ptt){
+ // ptt.innerHTML = "🔇 Push to Talk ";
+ //}
+
+ } else {
+ session.muted = false;
+ getById("mutetoggle").className = "las la-microphone my-float toggleSize";
+ if (!(session.cleanOutput)){
+ getById("mutebutton").className = "float";
+ getById("header").classList.remove('red');
+
+ if (session.localMuteElement){
+ session.localMuteElement.style.display = "none";
+ }
+
+ }
+ if (session.streamSrc) {
+ session.streamSrc.getAudioTracks().forEach((track) => {
+ track.enabled = true;
+ });
+ }
+ //if (ptt){
+ // ptt.innerHTML = "🔴 Push to Mute ";
+ //}
+ }
+
+ if (document.getElementById("screensharesource")){
+ document.getElementById("screensharesource").contentWindow.postMessage({"mic":!session.muted}, '*');
+ }
+
+ if (!apply) { // only if they are changing states do we bother to spam.
+ data = {};
+ data.muteState = session.muted;
+ session.sendMessage(data);
+ log("SEND DATA");
+ pokeIframeAPI('mic-mute-state', session.muted);
+ }
+}
+
+
+function toggleSpeakerMute(apply = false) { // TODO: I need to have this be MUTE, toggle, with volume not touched.
+
+ if (CtrlPressed) {
+ resetupAudioOut();
+ }
+
+ if (apply) {
+ session.speakerMuted = !session.speakerMuted;
+ }
+ if (session.speakerMuted == false) {
+ session.speakerMuted = true;
+ getById("mutespeakertoggle").className = "las la-volume-mute my-float toggleSize";
+ if (!(session.cleanOutput)){
+ getById("mutespeakerbutton").className = "float2 red";
+ }
+ var sounds = document.getElementsByTagName("video");
+ for (var i = 0; i < sounds.length; ++i) {
+ sounds[i].muted = session.speakerMuted;
+ }
+
+ } else {
+ session.speakerMuted = false;
+
+ getById("mutespeakertoggle").className = "las la-volume-up my-float toggleSize";
+ if (!(session.cleanOutput)){
+ getById("mutespeakerbutton").className = "float";
+ }
+
+ var sounds = document.getElementsByTagName("video");
+ for (var i = 0; i < sounds.length; ++i) {
+
+ if (sounds[i].id === "videosource") { // don't unmute ourselves. feedback galore if so.
+ continue;
+ } else if (sounds[i].id === "previewWebcam") {
+ continue;
+ } else if (sounds[i].id === "screenshare") {
+ continue;
+ } else {
+ sounds[i].muted = session.speakerMuted;
+ }
+ }
+ }
+
+ for (var UUID in session.rpcs) {
+ if (session.rpcs[UUID].videoElement) {
+ //if (UUID === session.directorUUID) {
+ // session.rpcs[UUID].videoElement.muted = false; // unmute director
+ // log("MAKE SURE DIRECTOR ISN'T MUTED");
+ //} else {
+ session.rpcs[UUID].videoElement.muted = session.speakerMuted;
+ // }
+ }
+ if (session.rpcs[UUID].iframeEle){
+ try{
+ session.rpcs[UUID].iframeEle.contentWindow.postMessage({"mute":session.speakerMuted}, '*');
+ } catch(e){errorlog(e);}
+ }
+ }
+
+
+ if ((iOS) || (iPad)) {
+ resetupAudioOut();
+ }
+}
+
+
+function toggleChat(event = null) { // TODO: I need to have this be MUTE, toggle, with volume not touched.
+ if (session.chat == false) {
+ setTimeout(function() {
+ document.addEventListener("click", toggleChat);
+ }, 10);
+
+ getById("chatModule").addEventListener("click", function(e) {
+ e.stopPropagation();
+ return false;
+ });
+ session.chat = true;
+ getById("chattoggle").className = "las la-comment-dots my-float toggleSize";
+ getById("chatbutton").className = "float2";
+ getById("chatModule").style.display = "block";
+ getById("chatInput").focus(); // give it keyboard focus
+ } else {
+ session.chat = false;
+ getById("chattoggle").className = "las la-comment-alt my-float toggleSize";
+ getById("chatbutton").className = "float";
+ getById("chatModule").style.display = "none";
+
+ document.removeEventListener("click", toggleChat);
+ getById("chatModule").removeEventListener("click", function(e) {
+ e.stopPropagation();
+ return false;
+ });
+ }
+ if (getById("chatNotification").value) {
+ getById("chatNotification").value = 0;
+ }
+ getById("chatNotification").classList.remove("notification");
+}
+
+function directorAdvanced(ele) {
+ var target = document.createElement("div");
+ target.style = "position:absolute;float:left;width:270px;height:222px;background-color:#7E7E7E;";
+
+ var closeButton = document.createElement("button");
+ closeButton.innerHTML = " close";
+ closeButton.style.left = "5px";
+ closeButton.style.position = "relative";
+ closeButton.onclick = function() {
+ target.parentNode.removeChild(target);
+ };
+ target.appendChild(closeButton);
+
+ var someButton = document.createElement("button");
+ someButton.innerHTML = " some action ";
+ someButton.style.left = "5px";
+ someButton.style.position = "relative";
+ someButton.onclick = function() {
+ var actionMsg = {};
+ session.sendRequest(actionMsg, ele.dataset.UUID);
+ };
+ target.appendChild(someButton);
+
+ ele.parentNode.appendChild(target);
+}
+
+function directorSendMessage(ele) {
+ var target = document.createElement("div");
+ target.style = "position:absolute;float:left;width:270px;height:222px;background-color:#7E7E7E;";
+
+ var inputField = document.createElement("textarea");
+ inputField.placeholder = "Enter your message here";
+ inputField.style.width = "255px";
+ inputField.style.height = "170px";
+ inputField.style.margin = "5px 10px 5px 10px";
+ inputField.style.padding = "5px";
+
+ target.appendChild(inputField);
+
+ var sendButton = document.createElement("button");
+ sendButton.innerHTML = " send message ";
+ sendButton.style.left = "5px";
+ sendButton.style.position = "relative";
+ sendButton.onclick = function() {
+ var chatMsg = {};
+ chatMsg.chat = inputField.value;
+ if (sendButton.parentNode.overlay) {
+ chatMsg.overlay = sendButton.parentNode.overlay;
+ }
+ session.sendRequest(chatMsg, ele.dataset.UUID);
+ inputField.value = "";
+ //target.parentNode.removeChild(target);
+ };
+
+
+ var closeButton = document.createElement("button");
+ closeButton.innerHTML = " close";
+ closeButton.style.left = "5px";
+ closeButton.style.position = "relative";
+ closeButton.onclick = function() {
+ inputField.value = "";
+ target.parentNode.removeChild(target);
+ };
+
+ var overlayMsg = document.createElement("span");
+
+ overlayMsg.style.left = "16px";
+ overlayMsg.style.top = "6px";
+ overlayMsg.style.position = "relative";
+ overlayMsg.innerHTML = " ";
+ target.overlay = true;
+
+ overlayMsg.onclick = function(e) {
+ log(e.target.parentNode.parentNode);
+ if (e.target.parentNode.parentNode.overlay === true) {
+ e.target.parentNode.parentNode.overlay = false;
+ e.target.parentNode.innerHTML = " ";
+ } else {
+ e.target.parentNode.parentNode.overlay = true;
+ e.target.parentNode.innerHTML = " ";
+ }
+ }
+
+
+ inputField.addEventListener("keydown", function(e) {
+ if (e.keyCode == 13) {
+ e.preventDefault();
+ sendButton.click();
+ } else if (e.keyCode == 27) {
+ e.preventDefault();
+ inputField.value = "";
+ target.parentNode.removeChild(target);
+ }
+ });
+ target.appendChild(closeButton);
+ target.appendChild(sendButton);
+ target.appendChild(overlayMsg);
+ ele.parentNode.appendChild(target);
+ inputField.focus();
+ inputField.select();
+}
+
+function toggleVideoMute(apply = false) { // TODO: I need to have this be MUTE, toggle, with volume not touched.
+ if (apply) {
+ session.videoMuted = !session.videoMuted;
+ }
+ if (session.videoMuted == false) {
+ session.videoMuted = true;
+ getById("mutevideotoggle").className = "las la-video-slash my-float toggleSize";
+ if (!(session.cleanOutput)){
+ getById("mutevideobutton").className = "float2 red";
+ }
+ if (session.streamSrc) {
+ session.streamSrc.getVideoTracks().forEach((track) => {
+ track.enabled = false;
+ });
+ }
+
+ } else {
+ session.videoMuted = false;
+
+ getById("mutevideotoggle").className = "las la-video my-float toggleSize";
+ if (!(session.cleanOutput)){
+ getById("mutevideobutton").className = "float";
+ }
+ if (session.streamSrc) {
+ session.streamSrc.getVideoTracks().forEach((track) => {
+ // try {
+ // if (document.querySelector("select#videoSource3").value == "ZZZ"){
+ // return;
+ // }
+ // } catch(e){}
+ track.enabled = true;
+ });
+ }
+ }
+
+
+
+ if (!apply) {
+ var msg = {};
+ msg.videoMuted = session.videoMuted;
+ session.sendMessage(msg);
+ pokeIframeAPI('video-mute-state', session.videoMuted);
+ if (!session.videoMuted){makeImages();}
+ }
+}
+
+var toggleSettingsState = false;
+
+function toggleSettings(forceShow = false) { // TODO: I need to have this be MUTE, toggle, with volume not touched.
+
+ getById("multiselect-trigger3").dataset.state = "0";
+ getById("multiselect-trigger3").classList.add('closed');
+ getById("multiselect-trigger3").classList.remove('open');
+ getById("chevarrow2").classList.add('bottom');
+
+ if (toggleSettingsState == true) {
+ if (forceShow == true) {
+ enumerateDevices().then(gotDevices2);
+ return;
+ }
+ } // don't close if already open
+ if (getById("popupSelector").style.display == "none") {
+
+ updateConstraintSliders();
+
+ setTimeout(function() {
+ document.addEventListener("click", toggleSettings);
+ }, 10);
+
+ getById("popupSelector").addEventListener("click", function(e) {
+ e.stopPropagation();
+ return false;
+ });
+
+ if (navigator.userAgent.indexOf('Chrome') != -1) {
+ try {
+ navigator.permissions.query({
+ name: "camera"
+ }).then(function(promise) {
+ if (promise && promise.state) {
+ if (promise.state == "prompt") {
+ navigator.mediaDevices.getUserMedia({
+ video: true
+ , audio: false
+ }).then(function(stream) {
+ enumerateDevices().then(gotDevices2).then(function() {
+ stream.getTracks().forEach(function(track) {
+ //stream.removeTrack(track);
+ track.stop(); // clean up?
+ });
+ });
+
+ }).catch(function(err) {
+ enumerateDevices().then(gotDevices2).then(function() {});
+ });
+ } else {
+ enumerateDevices().then(gotDevices2).then(function() {});
+ }
+ // console.log(promise.state); //"granted", "prompt" or "rejected"
+ } else {
+ enumerateDevices().then(gotDevices2).then(function() {});
+ }
+ });
+ } catch (e) {
+ enumerateDevices().then(gotDevices2).then(function() {});
+ }
+ } else {
+ enumerateDevices().then(gotDevices2).then(function() {});
+ }
+
+ getById("popupSelector").style.display = "inline-block"
+ getById("settingsbutton").classList.add("float2");
+ getById("settingsbutton").classList.remove("float");
+ setTimeout(function() {
+ getById("popupSelector").style.right = "0px";
+ }, 1);
+ toggleSettingsState = true;
+ } else {
+ document.removeEventListener("click", toggleSettings);
+ getById("popupSelector").removeEventListener("click", function(e) {
+ e.stopPropagation();
+ return false;
+ });
+
+ getById("popupSelector").style.right = "-400px";
+
+ getById("settingsbutton").classList.add("float");
+ getById("settingsbutton").classList.remove("float2");
+ setTimeout(function() {
+ getById("popupSelector").style.display = "none";
+ }, 200);
+ toggleSettingsState = false;
+ }
+}
+
+function hangup() { // TODO: I need to have this be MUTE, toggle, with volume not touched.
+ getById("main").innerHTML = "👋 ";
+ setTimeout(function() {
+ session.hangup();
+ }, 0);
+}
+
+function hangup2() {
+ session.hangupDirector();
+ getById("miniPerformer").innerHTML = "";
+ getById("press2talk").dataset.value = 0;
+ getById("screensharebutton").classList.add("advanced");
+ getById("settingsbutton").classList.add("advanced");
+ getById("mutebutton").classList.add("advanced");
+ getById("hangupbutton2").classList.add("advanced");
+ //getById("chatbutton").classList.remove("advanced");
+ getById("controlButtons").style.display = "inherit";
+ //getById("mutespeakerbutton").classList.add("advanced");
+ getById("mutevideobutton").classList.add("advanced");
+ getById("screenshare2button").classList.add("advanced");
+
+ getById("screensharebutton").classList.add("float");
+ getById("screensharebutton").classList.remove("float2");
+
+ if (session.showDirector == false) {
+ getById("miniPerformer").innerHTML = ' enable director`s microphone or video (only guests can see this feed) ';
+ } else {
+ getById("miniPerformer").innerHTML = ' enable director`s microphone or video ';
+ }
+ getById("miniPerformer").className = "";
+}
+
+function hangupComplete() {
+ getById("main").innerHTML = "👋 ";
+}
+
+
+function raisehand() {
+ if (session.directorUUID == false) {
+ log("no director in room yet");
+ return;
+ }
+
+ var data = {};
+ data.UUID = session.directorUUID;
+
+ log(data);
+ if (getById("raisehandbutton").dataset.raised == "0") {
+ getById("raisehandbutton").dataset.raised = "1";
+ getById("raisehandbutton").classList.add("raisedHand");
+ data.chat = "Raised hand";
+ log("hand raised");
+ } else {
+ log("hand lowered");
+ getById("raisehandbutton").dataset.raised = "0";
+ getById("raisehandbutton").classList.remove("raisedHand");
+ data.chat = "Lowered hand";
+ }
+ session.sendMessage(data, data.UUID);
+}
+
+function lowerhand() {
+ log("hand lowered");
+ getById("raisehandbutton").dataset.raised = "0";
+ getById("raisehandbutton").classList.remove("raisedHand");
+}
+
+var previousRoom = "";
+var stillNeedRoom = true;
+var transferCancelled = false;
+var armedTransfer = false;
+
+function directMigrate(ele, event) { // everyone in the room will hangup this guest also? I like that idea. What about the STREAM ID? I suppose we don't kick out if the viewID matches.
+ log("directMigrate");
+ if (event === false) {
+ if (previousRoom === null) { // user cancelled in previous callback
+ ele.innerHTML = ' Transfer ';
+ ele.style.backgroundColor = null;
+ return;
+ }
+ if (transferCancelled === true) {
+ ele.innerHTML = ' Transfer ';
+ ele.style.backgroundColor = null;
+ return;
+ }
+ var migrateRoom = previousRoom
+ } else if ((event.ctrlKey) || (event.metaKey)) {
+ ele.innerHTML = ' Armed ';
+ ele.style.backgroundColor = "#BF3F3F";
+ transferCancelled = false;
+ //armedTransfer=true;
+ Callbacks.push([directMigrate, ele, stillNeedRoom]);
+ stillNeedRoom = false;
+ log("Migrate queued");
+ return;
+ // } else if (armedTransfer){
+ //migrateRoom = sanitizeRoomName(previousRoom);
+ } else {
+ if (armedTransfer!==false && previousRoom!==""){
+ var migrateRoom = sanitizeRoomName(previousRoom);
+ } else {
+ window.focus();
+ var migrateRoom = prompt("Transfer guests to room:\n\n(Please note rooms must share the same password)", previousRoom);
+ }
+ stillNeedRoom = true;
+ if (migrateRoom === null) { // user cancelled
+ ele.innerHTML = ' Transfer ';
+ ele.style.backgroundColor = null;
+ transferCancelled = true;
+ return;
+ }
+ try {
+ migrateRoom = sanitizeRoomName(migrateRoom);
+ previousRoom = migrateRoom;
+ } catch (e) {}
+
+ }
+ ele.innerHTML = ' Transfer ';
+ ele.style.backgroundColor = null;
+
+ if (migrateRoom) {
+ previousRoom = migrateRoom;
+
+ var msg = {};
+ msg.request = "migrate";
+ if (session.password) {
+ return session.generateHash(migrateRoom + session.password + session.salt, 16).then(function(rid) {
+ var msg = {};
+ msg.request = "migrate";
+ msg.roomid = rid;
+ msg.target = ele.dataset.UUID;
+ session.sendMsg(msg); // send to everyone in the room, so they know if they are on air or not.
+ });
+ } else {
+ var msg = {};
+ msg.request = "migrate";
+ msg.roomid = migrateRoom;
+ msg.target = ele.dataset.UUID;
+ session.sendMsg(msg); // send to everyone in the room, so they know if they are on air or not.
+ }
+ }
+}
+var stillNeedHangupTarget = 1;
+
+function directHangup(ele, event) { // everyone in the room will hangup this guest? I like that idea.
+ if (event == false) {
+ if (stillNeedHangupTarget === 1) {
+ window.focus();
+ var confirmHangup = confirm("Are you sure you wish to disconnect these users?");
+ stillNeedHangupTarget = confirmHangup;
+ } else {
+ confirmHangup = stillNeedHangupTarget;
+ }
+ } else if ((event.ctrlKey) || (event.metaKey)) {
+ ele.innerHTML = ' ARMED ';
+ ele.style.backgroundColor = "#BF3F3F";
+ stillNeedHangupTarget = 1;
+ Callbacks.push([directHangup, ele, false]);
+ log("Hangup queued");
+ return;
+ } else {
+ window.focus();
+ var confirmHangup = confirm("Are you sure you wish to disconnect this user?");
+ }
+
+ if (confirmHangup) {
+ var msg = {};
+ msg.hangup = true;
+ log(msg);
+ log(ele.dataset.UUID);
+ session.sendRequest(msg, ele.dataset.UUID);
+ //session.anysend(msg); // send to everyone in the room, so they know if they are on air or not.
+ } else {
+ ele.innerHTML = ' Hangup ';
+ ele.style.backgroundColor = null;
+ }
+}
+
+function directEnable(ele, event, scene=1, director=false) { // A directing room only is controlled by the Director, with the exception of MUTE.
+
+ if (!((event.ctrlKey) || (event.metaKey))) {
+ if (ele.dataset.value == 1) {
+ ele.dataset.value = 0;
+ ele.classList.remove("pressed");
+ if (ele.children[1]){
+ ele.children[1].innerHTML = "Add to Scene "+scene;
+ }
+ if (director){
+ if (getById("container_director").querySelectorAll('[data-action-type="addToScene"][data-value="1"]').length==0){
+ getById("container_director").style.backgroundColor = null;
+ }
+ } else {
+ if (getById("container_" + ele.dataset.UUID).querySelectorAll('[data-action-type="addToScene"][data-value="1"]').length==0){
+ getById("container_" + ele.dataset.UUID).style.backgroundColor = null;
+ }
+ }
+ } else {
+ ele.dataset.value = 1;
+ ele.classList.add("pressed");
+ if (ele.children[1]){
+ ele.children[1].innerHTML = "Remove";
+ }
+ if (director){
+ getById("container_director").style.backgroundColor = "#649166";
+ } else {
+ getById("container_" + ele.dataset.UUID).style.backgroundColor = "#649166";
+ }
+ }
+ }
+ var msg = {};
+
+ scene = scene+"";
+
+ msg.scene = scene;
+ msg.action = "display";
+ msg.value = ele.dataset.value;
+ msg.target = ele.dataset.sid;
+
+ for (var uuid in session.pcs){
+ if (session.pcs[uuid].stats.info && ("version" in session.pcs[uuid].stats.info) && (session.pcs[uuid].stats.info.version < 17.2)){
+ msg.request = "sendroom";
+ session.sendMsg(msg);
+ return;
+ }
+ }
+
+ for (var uuid in session.pcs){
+ if (session.pcs[uuid].scene===scene){
+ session.sendMessage(msg, uuid);
+ }
+ }
+}
+
+var previousURL = "";
+var stillNeedURL = true;
+var reloadCancelled = false;
+var armedReload = false;
+
+function directPageReload(ele, event) {
+ log("URL Page reload");
+ if (event === false) {
+ if (previousURL === null) { // user cancelled in previous callback
+ ele.innerHTML = ' Change URL ';
+ ele.style.backgroundColor = null;
+ return;
+ }
+ if (reloadCancelled === true) {
+ ele.innerHTML = ' Change URL ';
+ ele.style.backgroundColor = null;
+ return;
+ }
+ reloadURL = previousURL
+ } else if ((event.ctrlKey) || (event.metaKey)) {
+ ele.innerHTML = ' Armed ';
+ ele.style.backgroundColor = "#BF3F3F";
+ reloadCancelled = false;
+ armedReload=true;
+ Callbacks.push([directPageReload, ele, stillNeedURL]);
+ stillNeedURL = false;
+ log("URL update queued");
+ return;
+ } else if (armedReload){
+ reloadURL = previousURL;
+ } else {
+ window.focus();
+ var reloadURL = prompt("Transfer guests to new website URL.\n\n(Guests will be prompted to accept)", previousURL);
+ stillNeedURL = true;
+ if (reloadURL === null) { // user cancelled
+ ele.innerHTML = ' Change URL ';
+ ele.style.backgroundColor = null;
+ reloadCancelled = true;
+ return;
+ }
+ try {
+ previousURL = reloadURL;
+ } catch (e) {}
+
+ }
+ ele.innerHTML = ' Change URL ';
+ ele.style.backgroundColor = null;
+
+ if (reloadURL) {
+ previousURL = reloadURL;
+
+ var msg = {};
+ msg.changeURL = reloadURL;
+ if (ele.dataset.UUID in session.rpcs){
+ session.rpcs[ele.dataset.UUID].receiveChannel.send(JSON.stringify(msg));
+ }
+ }
+}
+
+function directMute(ele, event=false) { // A directing room only is controlled by the Director, with the exception of MUTE.
+ log("mute");
+ if (!event || (!((event.ctrlKey) || (event.metaKey)))) {
+ if (ele.dataset.value == 0) {
+ ele.dataset.value = 1;
+ ele.classList.remove("pressed");
+ ele.children[1].innerHTML = "Mute in scene";
+ } else {
+ ele.dataset.value = 0;
+ ele.classList.add("pressed");
+ ele.children[1].innerHTML = "Un-mute";
+ }
+ }
+ var msg = {};
+ msg.scene = true;
+ msg.action = "mute";
+ msg.value = ele.dataset.value;
+ msg.target = ele.dataset.sid;
+
+ for (var uuid in session.pcs){
+ if (session.pcs[uuid].stats.info && ("version" in session.pcs[uuid].stats.info) && (session.pcs[uuid].stats.info.version < 17.2)){
+ msg.request = "sendroom";
+ session.sendMsg(msg);
+ return;
+ }
+ }
+
+ for (var uuid in session.pcs){
+ if (session.pcs[uuid].scene!==false){ // send to all scenes (but scene = 0)
+ session.sendMessage(msg, uuid);
+ }
+ }
+}
+
+function remoteSpeakerMute(ele, event=false){
+ log("speaker mute");
+ if (!event || (!((event.ctrlKey) || (event.metaKey)))) {
+ if (ele.dataset.value == 1) {
+ ele.dataset.value = 0;
+ ele.classList.remove("pressed");
+ ele.children[1].innerHTML = "deafen guest";
+ } else {
+ ele.dataset.value = 1;
+ ele.classList.add("pressed");
+ ele.children[1].innerHTML = "Un-deafen";
+ }
+ }
+
+ var msg = {};
+ if (ele.dataset.value == 0) {
+ msg.speakerMute = false
+ } else {
+ msg.speakerMute = true;
+ }
+ msg.UUID = ele.dataset.UUID;
+ session.sendRequest(msg, ele.dataset.UUID);
+}
+
+function updateRemoteSpeakerMute(UUID) {
+ var ele = document.querySelectorAll('[data-action-type="toggle-remote-speaker"][data--u-u-i-d="' + UUID + '"]');
+ if (ele[0]) {
+ ele[0].classList.add("pressed");
+ ele[0].dataset.value = 1;
+ ele[0].children[1].innerHTML = "Un-deafen";
+ }
+}
+
+function updateRemoteDisplayMute(UUID) {
+ var ele = document.querySelectorAll('[data-action-type="toggle-remote-display"][data--u-u-i-d="' + UUID + '"]');
+ if (ele[0]) {
+ ele[0].classList.add("pressed");
+ ele[0].dataset.value = 1;
+ ele[0].children[1].innerHTML = "Un-blind";
+ }
+}
+
+function remoteDisplayMute(ele, event=false) {
+ log("display mute");
+ if (!event || (!((event.ctrlKey) || (event.metaKey)))) {
+ if (ele.dataset.value == 1) {
+ ele.dataset.value = 0;
+ ele.classList.remove("pressed");
+ ele.children[1].innerHTML = "blind guest";
+ } else {
+ ele.dataset.value = 1;
+ ele.classList.add("pressed");
+ ele.children[1].innerHTML = "Un-blind";
+ }
+ }
+
+ var msg = {};
+ if (ele.dataset.value == 0) {
+ msg.displayMute = false;
+ } else {
+ msg.displayMute = true;
+ }
+ msg.UUID = ele.dataset.UUID;
+ session.sendRequest(msg, ele.dataset.UUID);
+}
+
+function remoteLowerhands(UUID) {
+ var msg = {};
+ msg.lowerhand = true;
+ msg.UUID = UUID;
+ session.sendRequest(msg, UUID);
+}
+
+
+function remoteMute(ele, event=false) {
+ log("mute");
+ if (!event || (!((event.ctrlKey) || (event.metaKey)))) {
+ if (ele.dataset.value == 1) {
+ ele.dataset.value = 0;
+ ele.classList.remove("pressed");
+ ele.children[1].innerHTML = "mute guest";
+ } else {
+ ele.dataset.value = 1;
+ ele.classList.add("pressed");
+ ele.children[1].innerHTML = "Un-mute guest";
+ }
+ }
+
+ try {
+ session.rpcs[ele.dataset.UUID].directorMutedState = ele.dataset.mute;
+ var volume = session.rpcs[ele.dataset.UUID].directorVolumeState;
+ } catch (e) {
+ errorlog(e);
+ var volume = 100;
+ }
+
+ var msg = {};
+ if (ele.dataset.value == 0) {
+ msg.volume = volume;
+ } else {
+ msg.volume = 0;
+ }
+ msg.UUID = ele.dataset.UUID;
+ session.sendRequest(msg, ele.dataset.UUID);
+}
+
+function remoteMuteVideo(ele, event=false) {
+ log("video mute");
+
+ if (!event || ((event.ctrlKey) || (event.metaKey))) {
+ ele.children[1].innerHTML = "ARMED";
+ ele.style.backgroundColor = "#BF3F3F";
+ Callbacks.push([remoteMuteVideo, ele, false]);
+ log("video queued");
+ return;
+ } else {
+ if (ele.dataset.value == 1) {
+ ele.dataset.value = 0;
+ ele.classList.remove("pressed");
+ ele.children[1].innerHTML = "hide guest";
+ } else {
+ ele.dataset.value = 1;
+ ele.classList.add("pressed");
+ ele.children[1].innerHTML = "Unhide guest";
+ }
+ ele.style.backgroundColor = null;
+ }
+
+ var msg = {};
+ if (ele.dataset.value == 0) {
+ msg.directVideoMuted = false;
+ } else {
+ msg.directVideoMuted = true;
+ }
+
+ for (var i in session.pcs){
+ msg.target = ele.dataset.UUID;
+
+ if (i === msg.target){
+ msg.target = true;
+ }
+ try{
+ session.pcs[i].sendChannel.send(JSON.stringify(msg));
+ } catch(e){}
+
+ }
+}
+
+function updateDirectorVideoMute(UUID) {
+ var ele = document.querySelectorAll('[data-action-type="hide-guest"][data--u-u-i-d="' + UUID + '"]');
+ if (ele[0]) {
+ ele[0].dataset.value = 1;
+ ele[0].classList.add("pressed");
+ ele[0].children[1].innerHTML = "Unhide guest";
+ }
+}
+
+function directVolume(ele) { // NOT USED ANYMORE
+ log("volume");
+ var msg = {};
+ msg.scene = true;
+ msg.action = "volume";
+ msg.target = ele.dataset.sid; // i want to focus on the STREAM ID, not the UUID...
+ msg.value = ele.value;
+
+ for (var uuid in session.pcs){
+ if (session.pcs[uuid].stats.info && ("version" in session.pcs[uuid].stats.info) && (session.pcs[uuid].stats.info.version < 17.2)){
+ msg.request = "sendroom";
+ session.sendMsg(msg);
+ return;
+ }
+ }
+
+ for (var uuid in session.pcs){
+ if (session.pcs[uuid].scene!==false){ // send to all scenes (but scene = 0)
+ session.sendMessage(msg, uuid);
+ }
+ }
+}
+
+function remoteVolumeUI(ele){
+ ele.nextSibling.innerHTML = ele.value;
+}
+
+function remoteVolume(ele) { // A directing room only is controlled by the Director, with the exception of MUTE.
+ log("volume");
+ var msg = {};
+ var muted = session.rpcs[ele.dataset.UUID].directorMutedState;
+ if (muted == 1) { // 1 is a string, not an int, so == and not ===. this happens in a few places :/
+ session.rpcs[ele.dataset.UUID].directorVolumeState = ele.value;
+ } else {
+ session.rpcs[ele.dataset.UUID].directorVolumeState = ele.value;
+ msg.volume = ele.value;
+ msg.UUID = ele.dataset.UUID;
+ session.sendRequest(msg, ele.dataset.UUID);
+ }
+}
+
+function clearDirectorSettings(){
+ setStorage("directorCustomize", {});
+}
+
+function saveDirectorSettings(){
+ var settings = {};
+
+ console.log("SAVE DIRECTOR SETTING");
+
+ if (getById("customizeLinks").classList.contains("advanced")){
+ settings.customizeLinks = true;
+ }
+
+ var customizeLinks1 = getById("customizeLinks1").querySelectorAll("input");
+ settings.customizeLinks1 = {};
+ for (var i=0;i {
+ customizeLinks1.querySelector('[data-param="'+key+'"]').checked = settings.customizeLinks1[key];
+ customizeLinks1.querySelector('[data-param="'+key+'"]').onchange();
+ });
+ }
+
+ if (settings.customizeLinks3){
+ var customizeLinks3 = getById("customizeLinks3");
+ Object.keys(settings.customizeLinks3).forEach((key, index) => {
+ customizeLinks3.querySelector('[data-param="'+key+'"]').checked = settings.customizeLinks3[key];
+ customizeLinks3.querySelector('[data-param="'+key+'"]').onchange();
+ });
+ }
+
+ if (settings.directorLinks1){
+ var directorLinks1 = getById("directorLinks1");
+ Object.keys(settings.directorLinks1).forEach((key, index) => {
+ directorLinks1.querySelector('[data-param="'+key+'"]').checked = settings.directorLinks1[key];
+ directorLinks1.querySelector('[data-param="'+key+'"]').onchange();
+ });
+ }
+
+ if (settings.directorLinks2){
+ var directorLinks2 = getById("directorLinks2");
+ Object.keys(settings.directorLinks2).forEach((key, index) => {
+ directorLinks2.querySelector('[data-param="'+key+'"]').checked = settings.directorLinks2[key];
+ directorLinks2.querySelector('[data-param="'+key+'"]').onchange();
+ });
+ }
+
+}
+
+
+
+function sendChat(chatmessage = "hi", UUID=false) { // A directing room only is controlled by the Director, with the exception of MUTE.
+ log("Chat message");
+ var msg = {};
+ msg.chat = chatmessage;
+
+ session.sendPeers(msg, UUID);
+}
+
+var activatedStream = false;
+
+function publishScreen() {
+ if (activatedStream == true) {
+ return;
+ }
+ activatedStream = true;
+ setTimeout(function() {
+ activatedStream = false;
+ }, 1000);
+
+ var title = "ScreenShare"; //getById("videoname2").value;
+
+ formSubmitting = false;
+
+ var quality = parseInt(getById("webcamquality2").elements.namedItem("resolution2").value);
+
+ if (session.quality !== false) {
+ quality = session.quality; // override the user's setting
+ }
+
+ if (quality == 0) {
+ var width = {
+ ideal: 1920
+ };
+ var height = {
+ ideal: 1080
+ };
+ } else if (quality == 1) {
+ var width = {
+ ideal: 1280
+ };
+ var height = {
+ ideal: 720
+ };
+ } else if (quality == 2) {
+ var width = {
+ ideal: 640
+ };
+ var height = {
+ ideal: 360
+ };
+ } else if (quality >= 3) { // lowest
+ var width = {
+ ideal: 320
+ };
+ var height = {
+ ideal: 180
+ };
+ }
+
+ if (session.width) {
+ width = {
+ ideal: session.width
+ };
+ }
+ if (session.height) {
+ height = {
+ ideal: session.height
+ };
+ }
+
+ var constraints = window.constraints = {
+ audio: {
+ echoCancellation: false
+ , autoGainControl: false
+ , noiseSuppression: false
+ }
+ , video: {
+ width: width
+ , height: height
+ }
+ };
+
+ if (session.noiseSuppression === true) {
+ constraints.audio.noiseSuppression = true;; // the defaults for screen publishing should be off.
+ }
+ if (session.autoGainControl === true) {
+ constraints.audio.autoGainControl = true; // the defaults for screen publishing should be off.
+ }
+ if (session.echoCancellation === true) {
+ constraints.audio.echoCancellation = true; // the defaults for screen publishing should be off.
+ }
+
+ try {
+ let supportedConstraints = navigator.mediaDevices.getSupportedConstraints(); // cursor hidding isn't supported by most browsers anyways.
+ if (supportedConstraints.cursor) {
+ constraints.video.cursor = "never";
+ }
+ } catch(e){
+ warnlog("navigator.mediaDevices.getSupportedConstraints() not supported");
+ }
+
+ //if (session.nocursor) { // we assume no cursor on screen share anyways. maybe make a different flag for screenshare cursor
+ // constraints.video.cursor = {
+ // exact: "none"
+ // }; // Not sure this does anything, but whatever.
+ //}
+
+ if (session.framerate !== false) {
+ constraints.video.frameRate = session.framerate;
+ } else if (session.maxframerate != false){
+ constraints.video.frameRate = {
+ ideal: session.maxframerate,
+ max: session.maxframerate
+ };
+ } else {
+ constraints.video.frameRate = {
+ ideal: 60
+ };
+ }
+
+ var audioSelect = getById('audioSourceScreenshare');
+ var outputSelect = getById('outputSourceScreenshare');
+
+ try {
+ session.sink = outputSelect.options[outputSelect.selectedIndex].value; // will probably fail on Safari.
+ log("Session SInk: " + session.sink);
+ if (session.sink == "default") {
+ session.sink = false;
+ }
+ } catch (e){errorlog(e);}
+
+ session.publishScreen(constraints, title, audioSelect).then((res) => {
+ if (res == false) {
+ return;
+ } // no screen selected
+ log("streamID is: " + session.streamID);
+
+ if (session.transcript) {
+ setTimeout(function() {
+ setupClosedCaptions();
+ }, 0);
+ }
+ //session.screenShareState=true;
+ if (!(session.cleanOutput)) {
+ getById("mutebutton").className = "float";
+ getById("mutespeakerbutton").classList.remove("advanced");
+ //getById("mutespeakerbutton").className="float";
+ getById("chatbutton").className = "float";
+ getById("mutevideobutton").className = "float";
+ getById("hangupbutton").className = "float";
+ if (session.showSettings) {
+ getById("settingsbutton").className = "float";
+ }
+ if (session.raisehands) {
+ getById("raisehandbutton").className = "float";
+ }
+ if (session.recordLocal !== false) {
+ getById("recordLocalbutton").className = "float";
+ }
+ if (screensharebutton) {
+ getById("screensharebutton").className = "float2";
+ }
+ getById("controlButtons").style.display = "flex";
+ getById("helpbutton").style.display = "inherit";
+ getById("reportbutton").style.display = "";
+ } else if (session.cleanish && session.recordLocal!==false){
+ getById("recordLocalbutton").className = "float";
+ getById("mutebutton").classList.add("advanced");
+ getById("mutespeakerbutton").classList.add("advanced");
+ getById("chatbutton").classList.add("advanced");
+ getById("mutevideobutton").classList.add("advanced");
+ getById("hangupbutton").classList.add("advanced");
+ getById("hangupbutton2").classList.add("advanced");
+ getById("controlButtons").style.display = "flex";
+ getById("settingsbutton").classList.add("advanced");
+ getById("screenshare2button").classList.add("advanced");
+ getById("screensharebutton").classList.add("advanced");
+ getById("queuebutton").classList.add("advanced");
+ } else {
+ getById("controlButtons").style.display = "none";
+ }
+
+ if (session.chatbutton === true) {
+ getById("chatbutton").classList.remove("advanced");
+ getById("controlButtons").style.display = "inherit";
+ } else if (session.chatbutton === false) {
+ getById("chatbutton").classList.add("advanced");
+ }
+
+ getById("head1").className = 'advanced';
+ getById("head2").className = 'advanced';
+ }).catch(() => {});
+
+}
+
+function publishWebcam(btn = false) {
+ if (btn) {
+ if (btn.dataset.ready == "false") {
+ warnlog("Clicked too quickly; button not enabled yet");
+ return;
+ }
+
+ if (getById("passwordBasicInput").value.length){
+ session.password = getById("passwordBasicInput").value;
+ session.password = sanitizePassword(session.password);
+ if (session.password.length==0){
+ session.password = false;
+ } else {
+ session.defaultPassword = false;
+ if (urlParams.has('pass')) {
+ updateURL("pass=" + session.password);
+ } else if (urlParams.has('pw')) {
+ updateURL("pw=" + session.password);
+ } else if (urlParams.has('p')) {
+ updateURL("p=" + session.password);
+ } else {
+ updateURL("password=" + session.password);
+ }
+ }
+ }
+ }
+
+ if (activatedStream == true) {
+ return;
+ }
+ activatedStream = true;
+ log("PRESSED PUBLISH WEBCAM!!");
+
+ var title = "Webcam"; // getById("videoname3").value;
+ var ele = getById("previewWebcam");
+
+ formSubmitting = false;
+ window.scrollTo(0, 0); // iOS has a nasty habit of overriding the CSS when changing camaera selections, so this addresses that.
+
+ getById("head2").className = 'advanced';
+
+ if (session.roomid !== false) {
+ if ((session.roomid === "") && ((!(session.view)) || (session.view === ""))) {
+ // no room, no viewing, viewing disabled
+ session.manual = true;
+ window.addEventListener("resize", updateMixer);
+ window.addEventListener("orientationchange", function() {
+ setTimeout(updateMixer, 200);
+ });
+ } else {
+ log("ROOM ID ENABLED");
+ log("Update Mixer Event on REsize SET");
+ window.addEventListener("resize", updateMixer);
+ window.addEventListener("orientationchange", function() {
+ setTimeout(updateMixer, 200);
+ });
+ getById("main").style.overflow = "hidden";
+ //session.cbr=0; // we're just going to override it
+
+ if (session.stereo == 5) {
+ if (session.roomid === "") {
+ session.stereo = 1;
+ } else {
+ session.stereo = 3;
+ }
+ }
+ joinRoom(session.roomid);
+ if (session.roomid !== "") {
+ if (!(session.cleanOutput)) {
+ getById("head2").className = '';
+ }
+ }
+ getById("head3").className = 'advanced';
+
+ }
+
+ } else {
+ getById("head3").className = '';
+ getById("logoname").style.display = 'none';
+ }
+
+ log("streamID is: " + session.streamID);
+ getById("head1").className = 'advanced';
+
+
+ if (!(session.cleanOutput)) {
+ getById("mutebutton").className = "float";
+ getById("mutespeakerbutton").classList.remove("advanced");
+ //getById("mutespeakerbutton").className="float";
+ getById("chatbutton").className = "float";
+ getById("mutevideobutton").className = "float";
+ getById("hangupbutton").className = "float";
+ if (session.showSettings) {
+ getById("settingsbutton").className = "float";
+ }
+ if (session.raisehands) {
+ getById("raisehandbutton").className = "float";
+ }
+ if (session.recordLocal !== false) {
+ getById("recordLocalbutton").className = "float";
+ }
+ if (screensharebutton) {
+ if (session.roomid) {
+ getById("screenshare2button").className = "float";
+ getById("screensharebutton").className = "float advanced";
+ } else {
+ getById("screensharebutton").className = "float";
+ getById("screenshare2button").className = "float advanced";
+ }
+ }
+ getById("controlButtons").style.display = "flex";
+ getById("helpbutton").style.display = "inherit";
+ getById("reportbutton").style.display = "";
+ } else if (session.cleanish && session.recordLocal!==false){
+ getById("recordLocalbutton").className = "float";
+ getById("mutebutton").classList.add("advanced");
+ getById("mutespeakerbutton").classList.add("advanced");
+ getById("chatbutton").classList.add("advanced");
+ getById("mutevideobutton").classList.add("advanced");
+ getById("hangupbutton").classList.add("advanced");
+ getById("hangupbutton2").classList.add("advanced");
+ getById("controlButtons").style.display = "flex";
+ getById("settingsbutton").classList.add("advanced");
+ getById("screenshare2button").classList.add("advanced");
+ getById("screensharebutton").classList.add("advanced");
+ getById("queuebutton").classList.add("advanced");
+ } else {
+ getById("controlButtons").style.display = "none";
+ }
+
+ if (session.chatbutton === true) {
+ getById("chatbutton").classList.remove("advanced");
+ getById("controlButtons").style.display = "inherit";
+ } else if (session.chatbutton === false) {
+ getById("chatbutton").classList.add("advanced");
+ }
+
+ if (urlParams.has('permaid')) {
+ updateURL("permaid=" + session.streamID);
+ } else {
+ updateURL("push=" + session.streamID);
+ }
+
+ session.publishStream(ele, title);
+
+}
+
+
+session.publishIFrame = function(iframeURL){
+
+ if (session.transcript){
+ setTimeout(function(){setupClosedCaptions();},0);
+ }
+
+ if (iframeURL==""){
+ iframeURL="./";
+ }
+ if (iframeURL === session.iframeSrc){return;}
+
+ if (iframeURL.startsWith("http://")){
+ try{
+ iframeURL = "https://"+ iframeURL.split("http://")[1];
+ }catch(e){errorlog(e);}
+ }
+
+
+ if (iframeURL.startsWith("https://") || iframeURL.startsWith("http://")){
+ var domain = (new URL(iframeURL));
+ domain = domain.hostname;
+ log(domain);
+ if ((domain=="www.youtube.com") || (domain=="youtube.com")){
+ var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
+ var match = iframeURL.match(regExp);
+ var vidid = (match&&match[7].length==11)? match[7] : false;
+
+ if(vidid){
+ iframeURL = "https://www.youtube.com/embed/"+vidid+"?autoplay=1&modestbranding=1";
+ log(iframeURL);
+ }
+ } else if (domain=="www.twitch.tv"){
+ var vidid = iframeURL.split('/').pop().split('#')[0].split('?')[0];
+ if (vidid){
+ iframeURL = "https://player.twitch.tv/?channel="+vidid+"&parent="+location.hostname;
+ log(iframeURL);
+ }
+ } else if (domain=="twitch.tv"){
+ var vidid = iframeURL.split('/').pop().split('#')[0].split('?')[0];
+ if (vidid){
+ iframeURL = "https://player.twitch.tv/?channel="+vidid+"&parent="+location.hostname;
+ log(iframeURL);
+ }
+ }
+
+ }
+
+
+ // https://player.twitch.tv/?channel=twitchpresents&parent=obs.ninja
+
+ session.iframeSrc = iframeURL;
+
+ var container = document.createElement("div");
+ container.id = "container";
+
+ var iframe = document.createElement("iframe");
+ iframe.allow="autoplay;camera;microphone;fullscreen;picture-in-picture";
+ iframe.allowtransparency="true";
+ iframe.allowfullscreen ="true";
+ iframe.src = session.iframeSrc;
+ iframe.id = "iframe_source"
+ session.iframeEle = iframe;
+
+ if (session.roomid!==false){
+
+ window.addEventListener("resize", updateMixer);
+
+ if ((session.roomid==="") && ((!(session.view)) || (session.view===""))){
+
+ } else {
+ log("ROOMID EANBLED");
+ getById("head3").className = 'advanced';
+
+ joinRoom(session.roomid);
+ }
+
+ } else {
+ getById("head3").className = '';
+ getById("logoname").style.display = 'none';
+ }
+ getById("head1").className = 'advanced';
+
+ if (urlParams.has('permaid')){
+ updateURL("permaid="+session.streamID);
+ } else {
+ updateURL("push="+session.streamID);
+ }
+
+ getById("head1").className = 'advanced';
+ getById("head2").className = 'advanced';
+
+ if (!(session.cleanOutput)){
+ getById("chatbutton").className="float";
+ getById("hangupbutton").className="float";
+ getById("controlButtons").style.display="flex";
+ getById("helpbutton").style.display = "inherit";
+ getById("reportbutton").style.display = "";
+ } else {
+ getById("controlButtons").style.display="none";
+ }
+
+
+
+ if (session.director){
+ } else if (session.scene!==false){
+ updateMixer();
+ } else if (session.roomid!==false){
+ if (session.roomid===""){
+ if (!(session.view) || (session.view==="")){
+
+
+ getById("mutespeakerbutton").classList.add("advanced");
+
+ container.style.width="100%";
+ container.style.height="100%";
+ container.style.alignItems = "center";
+ container.style.maxWidth= "1280px";
+ container.style.maxHeight= "720px";
+ container.style.verticalAlign= "middle";
+ container.style.margin= "auto";
+ container.style.backgroundColor = "#666";
+ container.style.border = "2px solid";
+
+ } else {
+ session.windowed = false;
+ updateMixer();
+ }
+ } else {
+
+ session.windowed = false;
+ updateMixer();
+ }
+ } else {
+
+ container.style.maxHeight= "1280px";
+ container.style.maxWidth= "720px";
+ container.style.verticalAlign= "middle";
+ container.style.height="100%";
+ container.style.width= "100%";
+ container.style.margin= "auto";
+ container.style.alignItems = "center";
+ container.style.backgroundColor = "#666";
+ }
+
+ getById("mainmenu").parentElement.removeChild(getById("mainmenu"));
+
+ getById("gridlayout").innerHTML = "";
+ container.appendChild(iframe);
+ getById("gridlayout").appendChild(container);
+
+
+ session.seeding=true;
+
+ getById("reshare").href = "https://"+location.host+location.pathname+"?view="+session.streamID;
+ getById("reshare").text = "https://"+location.host+location.pathname+"?view="+session.streamID;
+ getById("reshare").style.width = ((getById("reshare").text.length + 1)*1.15 * 8) + 'px';
+ pokeIframeAPI('started-iframe-share');
+
+ session.seedStream();
+}
+
+function outboundAudioPipeline(stream) {
+ if (session.disableWebAudio) {
+ var newStream = new MediaStream();
+ stream.getTracks().forEach(function(track) { // this seems to fix a bug with macbooks
+ newStream.addTrack(track, stream);
+ });
+ return newStream;
+ }
+
+ try {
+ log("Web Audio");
+ var tracks = stream.getAudioTracks();
+ if (tracks.length) {
+ for (var waid in session.webAudios) { // TODO: EXCLUDE CURRENT TRACK IF ALREADY EXISTS ... if (track.id === wa.id){..
+ session.webAudios[waid].stop();
+ delete session.webAudios[waid];
+ }
+
+
+ var webAudio = {};
+ webAudio.micDelay = false;
+ webAudio.compressor = false;
+ webAudio.analyser = false;
+ webAudio.gainNode = false;
+
+ webAudio.lowEQ = false;
+ webAudio.midEQ = false;
+ webAudio.highEQ = false;
+
+ webAudio.id = tracks[0].id; // first track is used.
+
+ if (session.audioLatency !== false) { // session.audioLatency could be useful for fixing clicking issues?
+ var audioContext = new AudioContext({
+ latencyHint: session.audioLatency / 1000.0 //, // needs to be in seconds, but OBSN user input is via milliseconds
+ // sampleRate: 48000 // not sure this is a great idea, but might as well add this here, versus later on since it is needed anyways.
+ });
+ } else {
+ var audioContext = new AudioContext();
+ }
+
+ webAudio.audioContext = audioContext;
+ webAudio.mediaStreamSource = audioContext.createMediaStreamSource(stream); // clone to fix iOS issue
+ webAudio.destination = audioContext.createMediaStreamDestination();
+ webAudio.gainNode = audioGainNode(webAudio.mediaStreamSource, audioContext);
+
+ var anonNode = webAudio.gainNode;
+
+ if (session.micDelay) {
+ webAudio.micDelay = micDelayNode(anonNode, audioContext);
+ anonNode = webAudio.micDelay;
+ }
+
+ if (session.audioInputChannels == 1) {
+ webAudio.splitter = audioContext.createChannelSplitter(6);
+ anonNode.connect(webAudio.splitter);
+
+ webAudio.merger = audioContext.createChannelMerger(6);
+ webAudio.splitter.connect(webAudio.merger, 0, 0);
+ webAudio.splitter.connect(webAudio.merger, 0, 1);
+ webAudio.splitter.connect(webAudio.merger, 0, 2);
+ webAudio.splitter.connect(webAudio.merger, 0, 3);
+ webAudio.splitter.connect(webAudio.merger, 0, 4);
+ webAudio.splitter.connect(webAudio.merger, 0, 5);
+ anonNode = webAudio.merger;
+ }
+
+
+ if (session.lowcut) { // https://webaudioapi.com/samples/frequency-response/ for a tool to help set values
+ webAudio.lowcut1 = audioContext.createBiquadFilter();
+ webAudio.lowcut1.type = "highpass";
+ webAudio.lowcut1.frequency.value = session.lowcut;
+
+ webAudio.lowcut2 = audioContext.createBiquadFilter();
+ webAudio.lowcut2.type = "highpass";
+ webAudio.lowcut2.frequency.value = session.lowcut;
+
+ webAudio.lowcut3 = audioContext.createBiquadFilter();
+ webAudio.lowcut3.type = "highpass";
+ webAudio.lowcut3.frequency.value = session.lowcut;
+
+ anonNode.connect(webAudio.lowcut1);
+ webAudio.lowcut1.connect(webAudio.lowcut2);
+ webAudio.lowcut2.connect(webAudio.lowcut3);
+ anonNode = webAudio.lowcut3;
+ }
+
+
+ if (session.equalizer) { // https://webaudioapi.com/samples/frequency-response/ for a tool to help set values
+ webAudio.lowEQ = audioContext.createBiquadFilter();
+ webAudio.lowEQ.type = "lowshelf";
+ webAudio.lowEQ.frequency.value = 100;
+ webAudio.lowEQ.gain.value = 0;
+
+ webAudio.midEQ = audioContext.createBiquadFilter();
+ webAudio.midEQ.type = "peaking";
+ webAudio.midEQ.frequency.value = 1000;
+ webAudio.midEQ.Q.value = 0.5;
+ webAudio.midEQ.gain.value = 0;
+
+ webAudio.highEQ = audioContext.createBiquadFilter();
+ webAudio.highEQ.type = "highshelf";
+ webAudio.highEQ.frequency.value = 10000;
+ webAudio.highEQ.gain.value = 0;
+
+ anonNode.connect(webAudio.lowEQ);
+ webAudio.lowEQ.connect(webAudio.midEQ);
+ webAudio.midEQ.connect(webAudio.highEQ);
+ anonNode = webAudio.highEQ;
+ }
+
+ if (session.compressor === 1) {
+ webAudio.compressor = audioCompressor(anonNode, audioContext);
+ anonNode = webAudio.compressor;
+ } else if (session.compressor === 2) {
+ webAudio.compressor = audioLimiter(anonNode, audioContext);
+ anonNode = webAudio.compressor;
+ }
+
+ webAudio.analyser = audioMeter(anonNode, audioContext);
+ webAudio.analyser.connect(webAudio.destination);
+
+ webAudio.stop = function() {
+ try {
+ webAudio.destination.disconnect();
+ } catch (e) {}
+ try {
+ clearInterval(webAudio.analyser.interval);
+ } catch (e) {}
+ try {
+ webAudio.analyser.disconnect();
+ } catch (e) {}
+ try {
+ webAudio.splitter.disconnect();
+ } catch (e) {}
+ try {
+ webAudio.merger.disconnect();
+ } catch (e) {}
+ try {
+ webAudio.lowcut1.disconnect();
+ webAudio.lowcut2.disconnect();
+ webAudio.lowcut3.disconnect();
+ } catch (e) {}
+ try {
+ webAudio.lowEQ.disconnect();
+ } catch (e) {}
+ try {
+ webAudio.midEQ.disconnect();
+ } catch (e) {}
+ try {
+ webAudio.highEQ.disconnect();
+ } catch (e) {}
+ try {
+ webAudio.gainNode.disconnect();
+ } catch (e) {}
+ try {
+ webAudio.micDelay.disconnect();
+ } catch (e) {}
+ try {
+ webAudio.compressor.disconnect();
+ } catch (e) {}
+ try {
+ webAudio.mediaStreamSource.context.close();
+ } catch (e) {}
+ }
+
+ webAudio.mediaStreamSource.onended = function() {
+ webAudio.stop();
+ };
+
+ session.webAudios[webAudio.id] = webAudio;
+
+ stream.getTracks().forEach(function(track) {
+ if (webAudio.id != track.id) {
+ webAudio.destination.stream.addTrack(track, stream);
+ }
+ });
+
+ return webAudio.destination.stream;
+ } else {
+ var newStream = new MediaStream();
+ stream.getTracks().forEach(function(track) { // this seems to fix a bug with macbooks
+ newStream.addTrack(track, stream);
+ });
+ return newStream;
+ //return stream; // no audio track
+ }
+ } catch (e) {
+ errorlog(e);
+ return stream;
+ }
+}
+
+function changeLowCut(freq, trackid = 0) {
+ if (trackid != 0) {
+ errorlog("EQ Doesn't work for anything but track 0. yet");
+ }
+ log("LOW EQ");
+
+ for (var webAudio in session.webAudios) {
+ if (!session.webAudios[webAudio].lowcut1) {
+ errorlog("EQ not setup");
+ return;
+ }
+ if (!session.webAudios[webAudio].lowcut2) {
+ errorlog("EQ not setup");
+ return;
+ }
+ if (!session.webAudios[webAudio].lowcut3) {
+ errorlog("EQ not setup");
+ return;
+ }
+ session.webAudios[webAudio].lowcut1.frequency.setValueAtTime(freq, session.webAudios[webAudio].audioContext.currentTime);
+ session.webAudios[webAudio].lowcut2.frequency.setValueAtTime(freq, session.webAudios[webAudio].audioContext.currentTime);
+ session.webAudios[webAudio].lowcut3.frequency.setValueAtTime(freq, session.webAudios[webAudio].audioContext.currentTime);
+ }
+
+}
+
+function changeLowEQ(lowEQ, trackid = 0) {
+ if (trackid != 0) {
+ errorlog("EQ Doesn't work for anything but track 0. yet");
+ }
+ log("LOW EQ");
+
+ for (var webAudio in session.webAudios) {
+ if (!session.webAudios[webAudio].lowEQ) {
+ errorlog("EQ not setup");
+ return;
+ }
+ session.webAudios[webAudio].lowEQ.gain.setValueAtTime(lowEQ, session.webAudios[webAudio].audioContext.currentTime);
+ }
+
+}
+
+function changeMidEQ(midEQ, trackid = 0) {
+ if (trackid != 0) {
+ errorlog("EQ Doesn't work for anything but track 0. yet");
+ }
+
+ for (var webAudio in session.webAudios) {
+ if (!session.webAudios[webAudio].midEQ) {
+ errorlog("EQ not setup");
+ return;
+ }
+ session.webAudios[webAudio].midEQ.gain.setValueAtTime(midEQ, session.webAudios[webAudio].audioContext.currentTime);
+ }
+
+}
+
+function changeHighEQ(highEQ, trackid = 0) {
+ if (trackid != 0) {
+ errorlog("EQ Doesn't work for anything but track 0. yet");
+ }
+
+ for (var webAudio in session.webAudios) {
+ if (!session.webAudios[webAudio].highEQ) {
+ errorlog("EQ not setup");
+ return;
+ }
+ session.webAudios[webAudio].highEQ.gain.setValueAtTime(highEQ, session.webAudios[webAudio].audioContext.currentTime);
+ }
+
+}
+
+
+function micDelayNode(mediaStreamSource, audioContext) {
+ var delayNode = audioContext.createDelay();
+ if (session.micDelay !== false) {
+ var delay = parseFloat(session.micDelay/1000) || 0;
+ } else {
+ var delay = 0;
+ }
+ delayNode.delayTime.value = delay;
+ mediaStreamSource.connect(delayNode);
+ return delayNode;
+}
+
+function audioGainNode(mediaStreamSource, audioContext) {
+ var gainNode = audioContext.createGain();
+ if (session.audioGain !== false) {
+ var gain = parseFloat(session.audioGain / 100.0) || 0;
+ } else {
+ var gain = 1.0;
+ }
+ gainNode.gain.value = gain;
+ mediaStreamSource.connect(gainNode);
+ return gainNode;
+}
+
+function audioMeter(mediaStreamSource, audioContext) {
+ var analyser = audioContext.createAnalyser();
+ mediaStreamSource.connect(analyser);
+ analyser.fftSize = 256;
+ analyser.smoothingTimeConstant = 0.05;
+
+ var bufferLength = analyser.frequencyBinCount;
+ var dataArray = new Uint8Array(bufferLength);
+
+
+ function draw() {
+ analyser.getByteFrequencyData(dataArray);
+ var total = 0;
+ for (var i = 0; i < dataArray.length; i++) {
+ total += dataArray[i];
+ }
+ total = total / 100;
+
+ if (document.getElementById("meter1")) {
+ if (total == 0) {
+ getById("meter1").style.width = "1px";
+ getById("meter2").style.width = "0px";
+ } else if (total <= 1) {
+ getById("meter1").style.width = "1px";
+ getById("meter2").style.width = "0px";
+ } else if (total <= 150) {
+ getById("meter1").style.width = total + "px";
+ getById("meter2").style.width = "0px";
+ } else if (total > 150) {
+ if (total > 200) {
+ total = 200;
+ }
+ getById("meter1").style.width = "150px";
+ getById("meter2").style.width = (total - 150) + "px";
+ }
+ } else if (session.cleanOutput){
+ return;
+ } else if (document.getElementById("mutetoggle")) {
+ if (total > 200) {
+ total = 200;
+ }
+ total = parseInt(total);
+ document.getElementById("mutetoggle").style.color = "rgb(" + (255 - total) + ",255," + (255 - total) + ")";
+ } else {
+ clearInterval(analyser.interval);
+ warnlog("METERS NOT FOUND");
+ return;
+ }
+ };
+
+ analyser.interval = setInterval(function() {
+ draw();
+ }, 100);
+ return analyser;
+}
+
+
+
+function audioCompressor(mediaStreamSource, audioContext) {
+ var compressor = audioContext.createDynamicsCompressor();
+ compressor.threshold.value = -50;
+ compressor.knee.value = 40;
+ compressor.ratio.value = 12;
+ compressor.attack.value = 0;
+ compressor.release.value = 0.25;
+ mediaStreamSource.connect(compressor);
+ return compressor;
+}
+
+function audioLimiter(mediaStreamSource, audioContext) {
+ var compressor = audioContext.createDynamicsCompressor();
+ compressor.threshold.value = -5;
+ compressor.knee.value = 0;
+ compressor.ratio.value = 20.0; // 1 to 20
+ compressor.attack.value = 0.001;
+ compressor.release.value = 0.1;
+ mediaStreamSource.connect(compressor);
+ return compressor;
+}
+
+
+function activeSpeaker(border=false) {
+ var lastActiveSpeaker = null;
+ var changed = false;
+ for (var UUID in session.rpcs) {
+ if (session.rpcs[UUID].stats._Audio_Loudness_average) {
+ session.rpcs[UUID].stats._Audio_Loudness_average = parseFloat(session.rpcs[UUID].stats.Audio_Loudness*0.2 + session.rpcs[UUID].stats._Audio_Loudness_average*0.8);
+ } else {
+ session.rpcs[UUID].stats._Audio_Loudness_average = 1;
+ }
+ //log(session.rpcs[UUID].stats._Audio_Loudness_average);
+ if (session.rpcs[UUID].stats._Audio_Loudness_average > 13) {
+
+ if (border) {
+ if (session.rpcs[UUID].videoElement) {
+ session.rpcs[UUID].videoElement.style.border = "green solid 1px";
+ session.rpcs[UUID].videoElement.style.padding = "0";
+ }
+ } else if (!session.rpcs[UUID].activelySpeaking){
+ session.rpcs[UUID].activelySpeaking = true;
+ changed = true;
+ lastActiveSpeaker = UUID;
+ session.rpcs[UUID].stats._Audio_Loudness_average+=2000000;
+ }
+
+ } else if (session.rpcs[UUID].stats._Audio_Loudness_average > 6) {
+
+ } else {
+ if (border){
+ if (session.rpcs[UUID].videoElement) {
+ session.rpcs[UUID].videoElement.style.border = "";
+ session.rpcs[UUID].videoElement.style.padding = "1px";
+ }
+ } else if (session.rpcs[UUID].activelySpeaking) {
+ changed = true;
+ session.rpcs[UUID].activelySpeaking=false;
+ lastActiveSpeaker = UUID;
+ }
+ }
+ }
+
+ var speaker = false;
+ for (var UUID in session.rpcs) {
+ if (session.rpcs[UUID].activelySpeaking){speaker=true;}
+ }
+
+ if (!speaker && lastActiveSpeaker && (session.nopreview || session.minipreview || (session.scene!==false) || (session.permaid === false))){
+ session.rpcs[lastActiveSpeaker].activelySpeaking=true;
+ } else if (changed) {
+ setTimeout(function(){updateMixer();},0);
+ }
+}
+
+
+
+function randomizeArray(unshuffled) {
+
+ var arr = unshuffled.map((a) => ({
+ sort: Math.random(), value: a
+ })).sort((a, b) => a.sort - b.sort).map((a) => a.value); // shuffle once
+
+ for (var i = arr.length - 1; i > 0; i--) { // shuffle twice
+ var j = Math.floor(Math.random() * (i + 1));
+ var tmp = arr[i];
+ arr[i] = arr[j];
+ arr[j] = tmp;
+ }
+ return arr
+}
+
+function joinRoom(roomname) {
+ if (roomname.length) {
+ roomname = sanitizeRoomName(roomname);
+ log("Join room");
+ log(roomname);
+ session.joinRoom(roomname).then(function(response) { // callback from server; we've joined the room. Just the listing is returned
+
+ if (session.joiningRoom === "seedPlz") { // allow us to seed, now that we have joined the room.
+ session.joiningRoom = false; // joined
+ session.seedStream();
+ } else {
+ session.joiningRoom = false; // no seeding callback
+ }
+
+ log("Members in Room");
+ log(response);
+
+ if (session.randomize === true) {
+ response = randomizeArray(response);
+ log("Randomized List of Viewers");
+ log(response);
+ for (var i in response) {
+ if ("UUID" in response[i]) {
+ if ("streamID" in response[i]) {
+ if (response[i].UUID in session.rpcs) {
+ log("RTC already connected"); /// lets just say instead of Stream, we have
+ } else {
+ log(response[i].streamID);
+ var streamID = session.desaltStreamID(response[i].streamID);
+ if (session.queue){
+ if (session.directorUUID === response[i].UUID){
+ play(streamID);
+ } else if (session.queueList.length<5000){
+ if (!session.queueList.includes(streamID)){
+ session.queueList.push(streamID);
+ }
+ }
+ } else {
+ log("STREAM ID DESALTED 3: " + streamID);
+ setTimeout(function(sid) {
+ play(sid);
+ }, (Math.floor(Math.random() * 100)), streamID); // add some furtherchance with up to 100ms added latency
+ }
+ }
+ }
+ }
+ }
+ } else {
+ for (var i in response) {
+ if ("UUID" in response[i]) {
+ if ("streamID" in response[i]) {
+ if (response[i].UUID in session.rpcs) {
+ log("RTC already connected"); /// lets just say instead of Stream, we have
+ } else {
+ log(response[i].streamID);
+ var streamID = session.desaltStreamID(response[i].streamID);
+ if (session.queue){
+ if (session.directorUUID === response[i].UUID){
+ play(streamID);
+ } else if (session.queueList.length<5000){
+ if (!session.queueList.includes(streamID)){
+ session.queueList.push(streamID);
+ }
+ }
+ } else {
+ log("STREAM ID DESALTED 3: " + streamID);
+ play(streamID); // play handles the group room mechanics here
+ }
+ }
+ }
+ }
+ }
+ }
+ session.updateQueue();
+ }, function(error) {
+ return {};
+ });
+ } else {
+ log("Room name not long enough or contained all bad characaters");
+ }
+}
+
+function createRoom(roomname = false) {
+
+ if (roomname == false) {
+ roomname = getById("videoname1").value;
+ roomname = sanitizeRoomName(roomname);
+
+ clearDirectorSettings();
+
+ if (roomname.length != 0) {
+ if (urlParams.has('dir')){
+ updateURL("dir=" + roomname, true, false); // make the link reloadable.
+ } else {
+ updateURL("director=" + roomname, true, false); // make the link reloadable.
+ }
+ }
+ }
+ if (roomname.length == 0) {
+ if (!(session.cleanOutput)) {
+ warnUser("Please enter a room name before continuing");
+ }
+ return;
+ }
+ log(roomname);
+ session.roomid = roomname;
+
+ getById("dirroomid").innerHTML = decodeURIComponent(session.roomid);
+ getById("roomid").innerHTML = session.roomid;
+
+ var passwordRoom = getById("passwordRoom").value;
+ passwordRoom = sanitizePassword(passwordRoom);
+ if (passwordRoom.length) {
+ session.password = passwordRoom;
+ session.defaultPassword = false;
+
+ if (urlParams.has('pass')) {
+ updateURL("pass=" + session.password);
+ } else if (urlParams.has('pw')) {
+ updateURL("pw=" + session.password);
+ } else if (urlParams.has('p')) {
+ updateURL("p=" + session.password);
+ } else {
+ updateURL("password=" + session.password);
+ }
+ }
+
+ var passAdd = "";
+ var passAdd2 = "";
+
+ if ((session.defaultPassword === false) && (session.password)) {
+ passAdd2 = "&password=" + session.password;
+ return session.generateHash(session.password + session.salt, 4).then(function(hash) {
+ passAdd = "&hash=" + hash;
+ createRoomCallback(passAdd, passAdd2);
+ });
+ } else {
+ createRoomCallback(passAdd, passAdd2);
+ }
+}
+
+function hideDirectorinvites(ele, skip=true) {
+
+ if (getById("directorLinks2").style.display == "none") {
+ ele.innerHTML = ' LINKS (GUEST INVITES & SCENES) ';
+ getById("directorLinks2").style.display = "inline-block";
+ getById("customizeLinks").classList.remove("advanced");
+ } else {
+ ele.innerHTML = ' LINKS (GUEST INVITES & SCENES) '
+ getById("directorLinks2").style.display = "none";
+ getById("help_directors_room").style.display = "none";
+ getById("roomnotes2").style.display = "none";
+ getById("customizeLinks").classList.add("advanced");
+ }
+ if (getById("directorLinks1").style.display == "none") {
+ getById("directorLinks1").style.display = "inline-block";
+ getById("customizeLinks").classList.remove("advanced");
+ } else {
+ getById("directorLinks1").style.display = "none";
+ getById("help_directors_room").style.display = "none";
+ getById("roomnotes2").style.display = "none";
+ getById("customizeLinks").classList.add("advanced");
+
+ }
+ if (skip){
+ saveDirectorSettings();
+ }
+}
+
+function createRoomCallback(passAdd, passAdd2) {
+
+ var gridlayout = getById("gridlayout");
+ gridlayout.classList.add("directorsgrid");
+
+ var broadcastFlag = getById("broadcastFlag");
+ try {
+ if (broadcastFlag.checked) {
+ broadcastFlag = true;
+ } else {
+ broadcastFlag = false;
+ }
+ } catch (e) {
+ broadcastFlag = false;
+ }
+
+ var broadcastString = "";
+ if (broadcastFlag) {
+ broadcastString = "&broadcast";
+ getById("broadcastSlider").checked = true;
+ }
+
+ var pie = "";
+ if (session.pie){
+ if (session.pie!==true){
+ pie = "&pie="+session.pie;
+ }
+ }
+
+ var showdirectorFlag = getById("showdirectorFlag");
+ try {
+ if (showdirectorFlag.checked) {
+ showdirectorFlag = true;
+ } else {
+ showdirectorFlag = false;
+ }
+ } catch (e) {
+ showdirectorFlag = false;
+ }
+
+ if (showdirectorFlag) {
+ updateURL("showdirector", true, false);
+ session.showDirector = true;
+ //getById("broadcastSlider").checked=true;
+ }
+
+
+ var codecGroupFlag = getById("codecGroupFlag");
+
+ if (codecGroupFlag.value) {
+ if (codecGroupFlag.value === "vp9") {
+ codecGroupFlag = "&codec=vp9";
+ getById("codech264toggle").disabled=true;
+ } else if (codecGroupFlag.value === "h264") {
+ codecGroupFlag = "&codec=h264";
+ getById("codech264toggle").checked=true;
+ } else if (codecGroupFlag.value === "vp8") {
+ codecGroupFlag = "&codec=vp8";
+ getById("codech264toggle").disabled=true;
+ } else if (codecGroupFlag.value === "av1") {
+ codecGroupFlag = "&codec=av1";
+ getById("codech264toggle").disabled=true;
+ } else {
+ codecGroupFlag = "";
+ }
+ } else {
+ codecGroupFlag = "";
+ }
+ if (codecGroupFlag) {
+ session.codecGroupFlag = codecGroupFlag;
+ }
+
+ formSubmitting = false;
+
+ var m = getById("mainmenu");
+ m.remove();
+
+ getById("head1").className = 'advanced';
+ getById("head2").className = 'advanced';
+ //getById("head3").className = 'advanced';
+ getById("head4").className = '';
+
+ try {
+ if (session.label === false) {
+ document.title = "Control Room";
+ }
+ } catch (e) {
+ errorlog(e);
+ };
+
+ session.director = true;
+ screensharesupport = false;
+
+ window.addEventListener("resize", updateMixer);
+ window.addEventListener("orientationchange", updateMixer);
+ getById("reshare").parentNode.removeChild(getById("reshare"));
+
+
+ //getById("mutespeakerbutton").style.display = null;
+ session.speakerMuted = true; // the director will start with audio playback muted.
+ toggleSpeakerMute(true);
+
+
+ if (session.cleanDirector == false) {
+
+ getById("roomHeader").style.display = "";
+ //getById("directorLinks").style.display = "";
+ getById("directorLinks1").style.display = "inline-block";
+ getById("directorLinks2").style.display = "inline-block";
+
+
+ getById("director_block_1").dataset.raw = "https://" + location.host + location.pathname + "?room=" + session.roomid + broadcastString + passAdd + pie;
+ getById("director_block_1").href = "https://" + location.host + location.pathname + "?room=" + session.roomid + broadcastString + passAdd + pie;
+ getById("director_block_1").innerText = "https://" + location.host + location.pathname + "?room=" + session.roomid + broadcastString + passAdd + pie;
+
+
+ getById("director_block_3").dataset.raw = "https://" + location.host + location.pathname + "?scene&room=" + session.roomid + codecGroupFlag + passAdd2 + pie;
+ getById("director_block_3").href = "https://" + location.host + location.pathname + "?scene&room=" + session.roomid + codecGroupFlag + passAdd2 + pie;
+ getById("director_block_3").innerText = "https://" + location.host + location.pathname + "?scene&room=" + session.roomid + codecGroupFlag + passAdd2 + pie;
+
+ getById("calendarButton").style.display = "inline-block";
+
+
+ } else {
+ getById("guestFeeds").innerHTML = '';
+ }
+ getById("guestFeeds").style.display = "";
+
+ if (!(session.cleanOutput)) {
+ if (session.queue){
+ getById("queuebutton").classList.remove("advanced");
+ }
+ getById("chatbutton").classList.remove("advanced");
+ getById("controlButtons").style.display = "inherit";
+ getById("mutespeakerbutton").classList.remove("advanced");
+ getById("websitesharebutton").classList.remove("advanced");
+
+ if (session.totalRoomBitrate){
+ getById("roomsettingsbutton").classList.remove("advanced");
+ }
+
+ if (session.showDirector == false) {
+ getById("miniPerformer").innerHTML = ' enable director`s microphone or video (only guests can see this feed) ';
+ } else {
+ getById("miniPerformer").innerHTML = ' enable director`s microphone or video ';
+ }
+ getById("miniPerformer").className = "";
+
+ var tabindex = 26;
+ if (session.rooms && session.rooms.length > 0){
+ var container = getById("rooms");
+ container.innerHTML += 'Arm Transfer: ';
+ session.rooms.forEach(function (r) {
+ if(session.roomid == r) return; //don't include self
+ container.innerHTML += ' ' + r + ' ';
+ tabindex++;
+ });
+ }
+
+ } else {
+ getById("miniPerformer").style.display = "none";
+ getById("controlButtons").style.display = "none";
+ }
+
+ if (session.chatbutton === true) {
+ getById("chatbutton").classList.remove("advanced");
+ getById("controlButtons").style.display = "inherit";
+ } else if (session.chatbutton === false) {
+ getById("chatbutton").classList.add("advanced");
+ }
+
+ clearInterval(session.updateLocalStatsInterval);
+ session.updateLocalStatsInterval = setInterval(function(){updateLocalStats();},3000);
+
+ setTimeout(function(){loadDirectorSettings();},100);
+
+ joinRoom(session.roomid);
+
+ if (session.autostart){
+ setTimeout(function(){press2talk(true);},400);
+ } else {
+ session.seeding=true;
+ session.seedStream();
+ }
+}
+/**
+ * Handles click actions on the room selection buttons in #controlButtons
+ * @param {string} room - Room name to select/deselect for the next transfer call
+ */
+function handleRoomSelect(room) {
+ var elems = document.querySelectorAll(".btnArmTransferRoom");
+ [].forEach.call(elems, function(el) {
+ el.classList.remove("selected");
+ });
+ if (previousRoom == room) {
+ previousRoom = "";
+ armedTransfer = false;
+ stillNeedRoom = true;
+ } else {
+ previousRoom = room;
+ stillNeedRoom = false;
+ armedTransfer = true;
+ getById("roomselect_" + room).classList.add('selected');
+ }
+}
+
+function getDirectorSettings(scene){
+ var settings = {};
+ var eles = document.querySelectorAll('[data-action-type="solo-video"]');
+ settings.soloVideo = false;
+ for (var i=0;i\
+ \
+ Add a label \
+ \
+
\
+
" + soloLink + "\
+
copy Solo link\
+
This is you, the director. You are also a performer. ";
+
+
+ controls.querySelectorAll('[data-action-type]').forEach((ele) => { // give action buttons some self-reference
+ ele.dataset.sid = session.streamID;
+ });
+
+ container.innerHTML = buttons;
+ container.appendChild(controls);
+
+ Object.keys(session.sceneList).forEach((scene, index) => {
+ if (session.showDirector){
+ if (document.getElementById("container_director")){
+ if (!(getById("container_director").querySelectorAll('[data-scene="'+scene+'"]').length)){
+ var newScene = document.createElement("div");
+ newScene.innerHTML = '
Scene: '+scene+'';
+ getById("container_director").appendChild(newScene);
+ }
+ }
+ }
+ });
+
+
+ var labelID = document.getElementById("label_director");
+
+ labelID.onclick = function(ee){
+ var oldlabel = ee.target.innerText;
+ if (session.label===false){
+ oldlabel = "";
+ }
+ window.focus();
+ var newlabel = prompt("Enter a new Display Name for this stream", oldlabel);
+ if (newlabel!==null){
+ if (newlabel == ""){
+ newlabel = false;
+ ee.target.innerText = "Add a label";
+ } else {
+ ee.target.innerText = newlabel;
+ }
+ session.label = newlabel;
+ var data = {};
+ data.changeLabel = true;
+ data.value = session.label;
+ session.sendMessage(data);
+ }
+ }
+ labelID.style.float = "left";
+ labelID.style.top = "2px";
+ labelID.style.marginLeft = "5px";
+ labelID.style.position = "relative";
+ labelID.style.cursor="pointer";
+ if (session.label){
+ labelID.innerText = session.label;
+ }
+}
+
+function createControlBox(UUID, soloLink, streamID) {
+ if (document.getElementById("deleteme")) {
+ getById("deleteme").parentNode.removeChild(getById("deleteme"));
+ }
+ var controls = getById("controls_blank").cloneNode(true);
+
+ var container = document.createElement("div");
+ container.id = "container_" + UUID; // needed to delete on user disconnect
+ container.className = "vidcon directorMargins";
+ controls.style.display = "block";
+ controls.id = "controls_" + UUID;
+ getById("guestFeeds").appendChild(container);
+
+ var buttons = "
ID: " + streamID + " \
+ \
+ \
+
";
+
+ if (!session.rpcs[UUID].voiceMeter) {
+ if (session.meterStyle==1){
+ session.rpcs[UUID].voiceMeter = getById("voiceMeterTemplate2").cloneNode(true);
+ } else {
+ session.rpcs[UUID].voiceMeter = getById("voiceMeterTemplate").cloneNode(true);
+ session.rpcs[UUID].voiceMeter.classList.add("video-meter-director");
+ session.rpcs[UUID].voiceMeter.style.opacity = 0;
+ }
+ session.rpcs[UUID].voiceMeter.id = "voiceMeter_" + UUID;
+ session.rpcs[UUID].voiceMeter.dataset.level = 0;
+ }
+
+ session.rpcs[UUID].remoteMuteElement = getById("muteStateTemplate").cloneNode(true);
+ session.rpcs[UUID].remoteMuteElement.id = "";
+ session.rpcs[UUID].remoteMuteElement.style.top = "5px";
+ session.rpcs[UUID].remoteMuteElement.style.right = "7px";
+
+ session.rpcs[UUID].remoteVideoMuteElement = getById("videoMuteStateTemplate").cloneNode(true);
+ session.rpcs[UUID].remoteVideoMuteElement.id = "";
+ session.rpcs[UUID].remoteVideoMuteElement.style.top = "5px";
+ session.rpcs[UUID].remoteVideoMuteElement.style.right = "28px";
+
+ session.rpcs[UUID].remoteRaisedHandElement = getById("raisedHandTemplate").cloneNode(true);
+ session.rpcs[UUID].remoteRaisedHandElement.id = "";
+ session.rpcs[UUID].remoteRaisedHandElement.style.top = "5px";
+ session.rpcs[UUID].remoteRaisedHandElement.style.right = "49px";
+
+
+ var videoContainer = document.createElement("div");
+ videoContainer.id = "videoContainer_" + UUID; // needed to delete on user disconnect
+ videoContainer.style.margin = "0";
+ videoContainer.style.position = "relative";
+
+ controls.innerHTML += "
";
+ controls.innerHTML += "
";
+
+ var handsID = "hands_" + UUID;
+
+ controls.innerHTML += "
\
+
\
+
" + soloLink + "\
+
copy Solo link\
+
\
+
\
+ \
+ Lower Raised Hand \
+ \
+
";
+
+ controls.querySelectorAll('[data-action-type]').forEach((ele) => { // give action buttons some self-reference
+ ele.dataset.UUID = UUID;
+ ele.dataset.sid = streamID;
+ });
+
+ container.innerHTML = buttons;
+ container.appendChild(videoContainer);
+ videoContainer.appendChild(session.rpcs[UUID].voiceMeter);
+ videoContainer.appendChild(session.rpcs[UUID].remoteMuteElement);
+ videoContainer.appendChild(session.rpcs[UUID].remoteVideoMuteElement);
+ videoContainer.appendChild(session.rpcs[UUID].remoteRaisedHandElement);
+ container.appendChild(controls);
+ initSceneList(UUID);
+}
+
+function createDirectorCam(vid) {
+
+ getById("press2talk").innerHTML = "";
+ getById("press2talk").outerHTML = "";
+ if (document.getElementById("videoContainer_director")){
+ getById("videoContainer_director").appendChild(vid);
+ } else {
+ getById("miniPerformer").appendChild(vid);
+ }
+ vid.title = "This is the preview of the Director's audio and video output.";
+ getById("press2talk").dataset.value = 1;
+ session.muted = false;
+ toggleMute(true);
+ getById("screensharebutton").classList.remove("advanced");
+ getById("hangupbutton2").classList.remove("advanced");
+ setTimeout(function() {
+ toggleSettings();
+ }, 200);
+
+ if (urlParams.has('permaid')) {
+ updateURL("permaid=" + session.streamID);
+ } else {
+ updateURL("push=" + session.streamID);
+ }
+}
+
+function press2talk(clean = false) {
+ var ele = getById("press2talk");
+ ele.style.minWidth = "127px";
+ ele.style.padding = "7px";
+ getById("settingsbutton").classList.remove("advanced");
+
+
+ if (!document.getElementById("controls_director") && session.showDirector){createDirectorOnlyBox();}
+
+
+ if (session.videoDevice || (session.audioDevice && session.audioDevice!==1)){
+ if ((session.videoDevice === 1) && (session.audioDevice===false || session.audioDevice==1)){
+ session.publishDirector(clean, true);
+ session.muted = false;
+ toggleMute(true);
+ return;
+ } else {
+ enumerateDevices().then(function(deviceInfos) {
+ var vdevice = false;
+ var adevice = true;
+ if (session.audioDevice==0){
+ adevice=false;
+ }
+ if (session.videoDevice && (session.videoDevice!=1)){
+ for (let i = 0; i !== deviceInfos.length; ++i) {
+ var deviceInfo = deviceInfos[i];
+ if ((deviceInfo.kind === 'videoinput') && (deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase().includes(session.videoDevice))) {
+ vdevice = {deviceId: {exact: deviceInfo.deviceId}};
+ break;
+ } else if (deviceInfo.deviceId === session.videoDevice){
+ vdevice = {deviceId: {exact: deviceInfo.deviceId}};
+ break;
+ }
+ }
+ }
+ if (session.audioDevice && (session.audioDevice!=1)){
+ for (let i = 0; i !== deviceInfos.length; ++i) {
+ var deviceInfo = deviceInfos[i];
+ if ((deviceInfo.kind === 'audioinput') && (deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase().includes(session.audioDevice))) {
+ adevice = {deviceId: {exact: deviceInfo.deviceId}};
+ break;
+ } else if (deviceInfo.deviceId === session.audioDevice){
+ adevice = {deviceId: {exact: deviceInfo.deviceId}};
+ break;
+ }
+ }
+ }
+ session.publishDirector(clean, vdevice, adevice);
+ session.muted = false;
+ toggleMute(true);
+ });
+ return;
+ }
+ }
+
+ session.publishDirector(clean);
+ session.muted = false;
+ toggleMute(true);
+
+}
+
+function addToGoogleCalendar(){
+ var title = "Live Stream";
+ //var dates = "20180512T230000Z/20180513T030000Z";
+ var linkout = getById("director_block_1").innerText;
+ var details = "Join the live stream as a performer at the following link:
===> "+linkout+"
To test your connection and camera ahead of time, please visit https://obs.ninja/speedtest
Do not share the details of this invite with others, unless explicitly told to.";
+ details = details.split(' ').join('+');
+ details = details.split('&').join('%26');
+ var linkToOpen = "https://calendar.google.com/calendar/r/eventedit?text="+title+"&details="+details;
+ //https://calendar.google.com/calendar/r/eventedit?text=My+Custom+Event&dates=20180512T230000Z/20180513T030000Z&details=For+details,+link+here:+https://example.com/tickets-43251101208&location=Garage+Boston+-+20+Linden+Street+-+Allston,+MA+02134
+
+ window.open(linkToOpen);
+
+}
+
+function addToOutlookCalendar(){
+ var title = "Live Stream";
+ var linkout = getById("director_block_1").innerText;
+ var details = "Join the live stream as a performer at the following link:
===> "+linkout+"
To test your connection and camera ahead of time, please visit https://obs.ninja/speedtest
Do not share the details of this invite with others, unless explicitly told to.";
+ details = details.split(' ').join('%20');
+ details = details.split('&').join('%26');
+
+
+ var linkToOpen = "https://outlook.live.com/owa/?path=%2Fcalendar%2Faction%2Fcompose&rru=addevent&subject="+title+"&body="+details;
+ //https://calendar.google.com/calendar/r/eventedit?text=My+Custom+Event&dates=20180512T230000Z/20180513T030000Z&details=For+details,+link+here:+https://example.com/tickets-43251101208&location=Garage+Boston+-+20+Linden+Street+-+Allston,+MA+02134
+
+ window.open(linkToOpen);
+}
+
+function addToYahooCalendar(){
+ var title = "Live Stream";
+ var linkout = getById("director_block_1").innerText;
+ var details = "Join the live stream as a performer at the following link:
===> "+linkout+"
To test your connection and camera ahead of time, please visit https://obs.ninja/speedtest
Do not share the details of this invite with others, unless explicitly told to.";
+ details = details.split(' ').join('%20');
+ details = details.split('&').join('%26');
+ var linkToOpen = "https://calendar.yahoo.com?v60&title="+title+"&desc="+details;
+ //https://calendar.google.com/calendar/r/eventedit?text=My+Custom+Event&dates=20180512T230000Z/20180513T030000Z&details=For+details,+link+here:+https://example.com/tickets-43251101208&location=Garage+Boston+-+20+Linden+Street+-+Allston,+MA+02134
+
+ window.open(linkToOpen);
+}
+
+function toggle(ele, tog = false, inline = true) {
+ var x = ele;
+ if (x.style.display === "none") {
+ if (inline) {
+ x.style.display = "inline-block";
+ } else {
+ x.style.display = "block";
+ }
+ } else {
+ x.style.display = "none";
+ }
+ if (tog) {
+ if (tog.dataset.saved) {
+ tog.innerHTML = tog.dataset.saved;
+ delete(tog.dataset.saved);
+ } else {
+ tog.dataset.saved = tog.innerHTML;
+ tog.innerHTML = "Hide This";
+ }
+ }
+}
+
+function toggleByDataset(filter) {
+ var elements = document.querySelectorAll('[data-cluster="'+filter+'"]'); // ie: .cluster1
+ for (var i = 0; i < elements.length; i++) {
+ elements[i].classList.toggle('hidden');
+ }
+}
+
+
+var SelectedAudioOutputDevices = []; // order matters.
+var SelectedAudioInputDevices = []; // ..
+var SelectedVideoInputDevices = []; // ..
+
+function enumerateDevices() {
+
+ log("enumerated start");
+
+ if (typeof navigator.enumerateDevices === "function") {
+ log("enumerated failed 1");
+ return navigator.enumerateDevices();
+ } else if (typeof navigator.mediaDevices === "object" && typeof navigator.mediaDevices.enumerateDevices === "function") {
+ return navigator.mediaDevices.enumerateDevices();
+ } else {
+ return new Promise((resolve, reject) => {
+ try {
+ if (window.MediaStreamTrack == null || window.MediaStreamTrack.getSources == null) {
+ throw new Error();
+ }
+ window.MediaStreamTrack.getSources((devices) => {
+ resolve(devices
+ .filter(device => {
+ return device.kind.toLowerCase() === "video" || device.kind.toLowerCase() === "videoinput";
+ })
+ .map(device => {
+ return {
+ deviceId: device.deviceId != null ? device.deviceId : ""
+ , groupId: device.groupId
+ , kind: "videoinput"
+ , label: device.label
+ , toJSON: /* istanbul ignore next */ function() {
+ return this;
+ }
+ };
+ }));
+ });
+ } catch (e) {
+ errorlog(e);
+ }
+ });
+ }
+}
+
+function requestOutputAudioStream() {
+ try {
+ //warnlog("GET USER MEDIA");
+ return navigator.mediaDevices.getUserMedia({
+ audio: true
+ , video: false
+ }).then(function(stream1) { // Apple needs thi to happen before I can access EnumerateDevices.
+ log("get media sources; request audio stream");
+ return enumerateDevices().then(function(deviceInfos) {
+ stream1.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(); // I need to do this after the enumeration step, else it breaks firefox's labels
+ });
+ const audioOutputSelect = getById('outputSourceScreenshare');
+ audioOutputSelect.remove(0);
+ audioOutputSelect.removeAttribute("onclick");
+
+ for (let i = 0; i !== deviceInfos.length; ++i) {
+ const deviceInfo = deviceInfos[i];
+ if (deviceInfo == null) {
+ continue;
+ }
+ const option = document.createElement('option');
+ option.value = deviceInfo.deviceId;
+ if (deviceInfo.kind === 'audiooutput') {
+ const option = document.createElement('option');
+ if (audioOutputSelect.length === 0) {
+ option.dataset.default = true;
+ } else {
+ option.dataset.default = false;
+ }
+ option.value = deviceInfo.deviceId || "default";
+ if (option.value == session.sink) {
+ option.selected = true;
+ }
+ option.text = deviceInfo.label || `Speaker ${audioOutputSelect.length + 1}`;
+ audioOutputSelect.appendChild(option);
+ } else {
+ log('Some other kind of source/device: ', deviceInfo);
+ }
+ }
+ });
+ });
+ } catch (e) {
+ if (!(session.cleanOutput)) {
+ if (window.isSecureContext) {
+ warnUser("An error has occured when trying to access the default audio device. The reason is not known.");
+ } else if ((iOS) || (iPad)) {
+ warnUser("iOS version 13.4 and up is generally recommended; older than iOS 11 is not supported.");
+ } else {
+ warnUser("Error acessing the default audio device.\n\nThe website may be loaded in an insecure context.\n\nPlease see: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia");
+ }
+ }
+ }
+}
+
+
+function requestAudioStream() {
+ try {
+ //warnlog("GET USER MEDIA");
+ return navigator.mediaDevices.getUserMedia({
+ audio: true
+ , video: false
+ }).then(function(stream1) { // Apple needs thi to happen before I can access EnumerateDevices.
+ log("get media sources; request audio stream");
+ return enumerateDevices().then(function(deviceInfos) {
+ stream1.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(); // I need to do this after the enumeration step, else it breaks firefox's labels
+ });
+ log("updating audio");
+ const audioInputSelect = getById('audioSourceScreenshare');
+ audioInputSelect.remove(1);
+ audioInputSelect.removeAttribute("onchange");
+
+
+ for (let i = 0; i !== deviceInfos.length; ++i) {
+ const deviceInfo = deviceInfos[i];
+ if (deviceInfo == null) {
+ continue;
+ }
+ const option = document.createElement('option');
+ option.value = deviceInfo.deviceId;
+ if (deviceInfo.kind === 'audioinput') {
+ option.text = deviceInfo.label || `Microphone ${audioInputSelect.length + 1}`;
+ audioInputSelect.appendChild(option);
+ } else {
+ log('Some other kind of source/device: ', deviceInfo);
+ }
+ }
+ audioInputSelect.style.minHeight = ((audioInputSelect.childElementCount + 1) * 1.15 * 16) + 'px';
+ audioInputSelect.style.minWidth = "342px";
+ });
+ });
+ } catch (e) {
+ if (!(session.cleanOutput)) {
+ if (window.isSecureContext) {
+ warnUser("An error has occured when trying to access the default audio device. The reason is not known.");
+ } else if ((iOS) || (iPad)) {
+ warnUser("iOS version 13.4 and up is generally recommended; older than iOS 11 is not supported.");
+ } else {
+ warnUser("Error acessing the default audio device.\n\nThe website may be loaded in an insecure context.\n\nPlease see: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia");
+ }
+ }
+ }
+}
+
+
+function gotDevices(deviceInfos) { // https://github.com/webrtc/samples/blob/gh-pages/src/content/devices/input-output/js/main.js#L19
+
+ log("got devices!");
+ log(deviceInfos);
+ try {
+ const audioInputSelect = getById('audioSource');
+
+ audioInputSelect.innerHTML = "";
+
+ var option = document.createElement('input');
+ option.type = "checkbox";
+ option.value = "ZZZ";
+ option.name = "multiselect1";
+ option.id = "multiselect1";
+ option.style.display = "none";
+ option.checked = true;
+
+
+ var label = document.createElement('label');
+ label.for = option.name;
+ label.innerHTML = '
No Audio ';
+
+ var listele = document.createElement('li');
+ listele.appendChild(option);
+ listele.appendChild(label);
+ audioInputSelect.appendChild(listele);
+
+
+ option.onchange = function(event) { // make sure to clear 'no audio option' if anything else is selected
+ if (!(getById("multiselect1").checked)) {
+ getById("multiselect1").checked = true;
+
+ if (SelectedAudioInputDevices.indexOf(event.currentTarget.value) > -1) {} else {
+ SelectedAudioInputDevices.push(event.currentTarget.value);
+ }
+
+ log("CHECKED 1");
+ } else {
+
+ var list = document.querySelectorAll("#audioSource>li>input");
+ for (var i = 0; i < list.length; i++) {
+ if (list[i].id !== "multiselect1") {
+ list[i].checked = false;
+ }
+ }
+
+ while (SelectedAudioInputDevices.indexOf(event.currentTarget.value) > -1) {
+ SelectedAudioInputDevices.splice(SelectedAudioInputDevices.indexOf(event.currentTarget.value), 1);
+ }
+ }
+ };
+
+ getById('multiselect-trigger').dataset.state = '0';
+ getById('multiselect-trigger').classList.add('closed');
+ getById('multiselect-trigger').classList.remove('open');
+ getById('chevarrow1').classList.add('bottom');
+
+ const videoSelect = getById('videoSourceSelect');
+ const audioOutputSelect = getById('outputSource');
+ const selectors = [videoSelect];
+
+ const values = selectors.map(select => select.value);
+ selectors.forEach(select => {
+ while (select.firstChild) {
+ select.removeChild(select.firstChild);
+ }
+ });
+
+
+ function comp(a, b) {
+ if (a.kind === 'audioinput') {
+ return 0;
+ } else if (a.kind === 'audiooutput') {
+ return 0;
+ }
+ const labelA = a.label.toUpperCase();
+ const labelB = b.label.toUpperCase();
+ if (labelA > labelB) {
+ return 1;
+ } else if (labelA < labelB) {
+ return -1;
+ }
+ return 0;
+ }
+ //deviceInfos.sort(comp); // I like this idea, but it messes with the defaults. I just don't know what it will do.
+
+ // This is to hide NDI from default device. NDI Tools fucks up.
+ var tmp = [];
+ for (let i = 0; i !== deviceInfos.length; ++i) {
+ deviceInfo = deviceInfos[i];
+ if (!((deviceInfo.kind === 'videoinput') && (deviceInfo.label.toLowerCase().startsWith("ndi") || deviceInfo.label.toLowerCase().startsWith("newtek")))) {
+ tmp.push(deviceInfo);
+ }
+ }
+
+ for (let i = 0; i !== deviceInfos.length; ++i) {
+ deviceInfo = deviceInfos[i];
+ if ((deviceInfo.kind === 'videoinput') && (deviceInfo.label.toLowerCase().startsWith("ndi") || deviceInfo.label.toLowerCase().startsWith("newtek"))) {
+ tmp.push(deviceInfo);
+ log("V DEVICE FOUND = " + deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase());
+ }
+ }
+ deviceInfos = tmp;
+ log(deviceInfos);
+
+ if ((session.audioDevice) && (session.audioDevice !== 1)) { // this sorts according to users's manual selection
+ var tmp = [];
+ for (let i = 0; i !== deviceInfos.length; ++i) {
+ deviceInfo = deviceInfos[i];
+ if ((deviceInfo.kind === 'audioinput') && (deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase().includes(session.audioDevice))) {
+ tmp.push(deviceInfo);
+ log("A DEVICE FOUND = " + deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase());
+ } else if (deviceInfo.deviceId === session.audioDevice){
+ tmp.push(deviceInfo);
+ log("EXACT A DEVICE FOUND");
+ }
+ }
+ for (let i = 0; i !== deviceInfos.length; ++i) {
+ deviceInfo = deviceInfos[i];
+ if (!((deviceInfo.kind === 'audioinput') && (deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase().includes(session.audioDevice)))) {
+ if (deviceInfo.deviceId !== session.audioDevice){
+ tmp.push(deviceInfo);
+ }
+ }
+ }
+
+ deviceInfos = tmp;
+ log(session.audioDevice);
+ log(deviceInfos);
+ }
+
+
+ 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];
+ if ((deviceInfo.kind === 'videoinput') && (deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase().includes(session.videoDevice))) {
+ tmp.push(deviceInfo);
+ log("V DEVICE FOUND = " + deviceInfo.label.replace(/[\W]+/g, "_").toLowerCase());
+ } else if (deviceInfo.deviceId === session.videoDevice){
+ tmp.push(deviceInfo);
+ log("EXACT V DEVICE FOUND");
+ }
+ }
+ 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);
+ }
+
+
+ var counter = 1;
+ for (let i = 0; i !== deviceInfos.length; ++i) {
+ const deviceInfo = deviceInfos[i];
+ if (deviceInfo == null) {
+ continue;
+ }
+
+ if (deviceInfo.kind === 'audioinput') {
+ option = document.createElement('input');
+ option.type = "checkbox";
+ counter++;
+ listele = document.createElement('li');
+ if (counter == 2) {
+ option.checked = true;
+ listele.style.display = "block";
+ option.style.display = "none";
+ getById("multiselect1").checked = false;
+ try{
+ getById("multiselect1").parentNode.style.display = "none";
+ } catch(e){}
+ } else {
+ listele.style.display = "none";
+ }
+
+
+ option.value = deviceInfo.deviceId || "default";
+ option.name = "multiselect" + counter;
+ option.id = "multiselect" + counter;
+ label = document.createElement('label');
+ label.for = option.name;
+
+ label.innerHTML = " " + (deviceInfo.label || ("microphone " + ((audioInputSelect.length || 0) + 1)));
+
+ listele.appendChild(option);
+ listele.appendChild(label);
+ audioInputSelect.appendChild(listele);
+
+ option.onchange = function(event) { // make sure to clear 'no audio option' if anything else is selected
+ getById("multiselect1").checked = false;
+ log("UNCHECKED");
+ if (!(CtrlPressed)) {
+ document.querySelectorAll("#audioSource input[type='checkbox']").forEach(function(item) {
+ if (event.currentTarget.id !== item.id) {
+ item.checked = false;
+
+ while (SelectedAudioInputDevices.indexOf(item.value) > -1) {
+ SelectedAudioInputDevices.splice(SelectedAudioInputDevices.indexOf(item.value), 1);
+ }
+
+ } else {
+ item.checked = true;
+ if (SelectedAudioInputDevices.indexOf(event.currentTarget.value) > -1) {} else {
+ SelectedAudioInputDevices.push(event.currentTarget.value);
+ }
+ }
+ });
+ }
+ };
+
+ } else if (deviceInfo.kind === 'videoinput') {
+ option = document.createElement('option');
+ option.value = deviceInfo.deviceId || "default";
+ option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`;
+ videoSelect.appendChild(option);
+ } else if (deviceInfo.kind === 'audiooutput') {
+ option = document.createElement('option');
+ if (audioOutputSelect.length === 0) {
+ option.dataset.default = true;
+ } else {
+ option.dataset.default = false;
+ }
+ option.value = deviceInfo.deviceId || "default";
+ if (option.value == session.sink) {
+ option.selected = true;
+ }
+ option.text = deviceInfo.label || `Speaker ${audioOutputSelect.length + 1}`;
+ audioOutputSelect.appendChild(option);
+ } else {
+ log('Some other kind of source/device: ', deviceInfo);
+ }
+ }
+
+ if (audioOutputSelect.childNodes.length == 0) {
+ option = document.createElement('option');
+ option.value = "default";
+ option.text = "System Default";
+ audioOutputSelect.appendChild(option);
+ }
+
+ option = document.createElement('option');
+ option.text = "Disable Video";
+ option.value = "ZZZ";
+ videoSelect.appendChild(option); // NO AUDIO OPTION
+
+ selectors.forEach((select, selectorIndex) => {
+ if (Array.prototype.slice.call(select.childNodes).some(n => n.value === values[selectorIndex])) {
+ select.value = values[selectorIndex];
+ }
+ });
+
+ } catch (e) {
+ errorlog(e);
+ }
+}
+
+
+if (location.protocol !== 'https:') {
+ if (!(session.cleanOutput)) {
+ warnUser("SSL (https) is not enabled. This site will not work without it!
Try accessing the site from here instead. ");
+ }
+}
+
+
+function getUserMediaVideoParams(resolutionFallbackLevel, isSafariBrowser) {
+ switch (resolutionFallbackLevel) {
+ case 0:
+ if (isSafariBrowser) {
+ return {
+ width: {
+ min: 360
+ , ideal: 1920
+ , max: 1920
+ }
+ , height: {
+ min: 360
+ , ideal: 1080
+ , max: 1080
+ }
+ };
+ } else {
+ return {
+ width: {
+ min: 720
+ , ideal: 1920
+ , max: 1920
+ }
+ , height: {
+ min: 720
+ , ideal: 1080
+ , max: 1920
+ }
+ };
+ }
+ case 1:
+ if (isSafariBrowser) {
+ return {
+ width: {
+ min: 360
+ , ideal: 1280
+ , max: 1280
+ }
+ , height: {
+ min: 360
+ , ideal: 720
+ , max: 720
+ }
+ };
+ } else {
+ return {
+ width: {
+ min: 720
+ , ideal: 1280
+ , max: 1280
+ }
+ , height: {
+ min: 720
+ , ideal: 720
+ , max: 1280
+ }
+ };
+ }
+ case 2:
+ if (isSafariBrowser) {
+ return {
+ width: {
+ min: 640
+ }
+ , height: {
+ min: 360
+ }
+ };
+ } else {
+ return {
+ width: {
+ min: 240
+ , ideal: 640
+ , max: 1280
+ }
+ , height: {
+ min: 240
+ , ideal: 360
+ , max: 1280
+ }
+ };
+ }
+ case 3:
+ if (isSafariBrowser) {
+ return {
+ width: {
+ min: 360
+ , ideal: 1280
+ , max: 1440
+ }
+ };
+ } else {
+ return {
+ width: {
+ min: 360
+ , ideal: 1280
+ , max: 1440
+ }
+ };
+ }
+ case 4:
+ if (isSafariBrowser) {
+ return {
+ height: {
+ min: 360
+ , ideal: 720
+ , max: 960
+ }
+ };
+ } else {
+ return {
+ height: {
+ ideal: 720
+ , max: 960
+ }
+ };
+ }
+ case 5:
+ if (isSafariBrowser) {
+ return {
+ width: {
+ min: 360
+ , ideal: 640
+ , max: 1440
+ }
+ , height: {
+ min: 360
+ , ideal: 360
+ , max: 720
+ }
+ };
+ } else {
+ return {
+ width: {
+ ideal: 640
+ , max: 1920
+ }
+ , height: {
+ ideal: 360
+ , max: 1920
+ }
+ }; // same as default, but I didn't want to mess with framerates until I gave it all a try first
+ }
+ case 6:
+ if (isSafariBrowser) {
+ return {}; // iphone users probably don't need to wait any longer, so let them just get to it
+ } else {
+ return {
+ width: {
+ min: 360
+ , ideal: 640
+ , max: 3840
+ }
+ , height: {
+ min: 360
+ , ideal: 360
+ , max: 2160
+ }
+ };
+
+ }
+ case 7:
+ 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
+ }
+ , };
+
+ case 8:
+ return {
+ width: {
+ min: 360
+ }
+ , height: {
+ min: 360
+ }
+ , frameRate: 10
+ }; // 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.
+ case 10:
+ return {}
+ default:
+ return {};
+ }
+}
+
+function addScreenDevices(device) {
+ if (device.kind == "audio") {
+ const audioInputSelect = getById('audioSource3');
+ const listele = document.createElement('li');
+ listele.style.display = "block";
+
+ const option = document.createElement('input');
+ option.type = "checkbox";
+ option.checked = true;
+
+ if (getById('multiselect-trigger3').dataset.state == 0) {
+ option.style.display = "none";
+ }
+
+ option.value = device.id;
+ option.name = device.label;
+ option.dataset.type = "screen";
+ option.label = device.label;
+
+ const label = document.createElement('label');
+ label.for = option.name;
+ label.innerHTML = " " + device.label;
+ listele.appendChild(option);
+ listele.appendChild(label);
+
+ option.onchange = function(event) { // make sure to clear 'no audio option' if anything else is selected
+ log("change 4644");
+ if (!(CtrlPressed)) {
+ document.querySelectorAll("#audioSource3 input[type='checkbox']").forEach(function(item) {
+ if (event.currentTarget.value !== item.value) { // this shoulnd't happen, but if it does.
+
+ item.checked = false;
+
+ if (item.dataset.type == "screen") {
+ item.parentElement.parentElement.removeChild(item.parentElement);
+ }
+
+ while (SelectedAudioInputDevices.indexOf(item.value) > -1) {
+ SelectedAudioInputDevices.splice(SelectedAudioInputDevices.indexOf(item.value), 1);
+ }
+
+ activatedPreview = false;
+ grabAudio("videosource", "#audioSource3"); // exclude item.id
+
+ } else {
+ if (SelectedAudioInputDevices.indexOf(item.value) > -1) {} else {
+ SelectedAudioInputDevices.push(item.value);
+ }
+
+ item.checked = true;
+ activatedPreview = false;
+ grabAudio("videosource", "#audioSource3", item.value); // exclude item.id. we will reconnect, even if already connected, as a way to 'reset' a device if it isn't working.
+ }
+ });
+ }
+ event.stopPropagation();
+ return false;
+ };
+ audioInputSelect.appendChild(listele);
+ getById("audioSourceNoAudio2").checked = false;
+
+ } else if (device.kind == "video") {
+ const videoSelect = getById('videoSource3');
+ //const selectors = [ videoSelect];
+ //const values = selectors.map(select => select.value);
+ const option = document.createElement('option');
+ option.value = device.id;
+ option.text = device.label;
+ option.selected = true;
+ option.label = device.label;
+ videoSelect.appendChild(option);
+ }
+}
+
+function gotDevices2(deviceInfos) {
+ log("got devices!");
+ log(deviceInfos);
+
+ getById("multiselect-trigger3").dataset.state = "0";
+ getById("multiselect-trigger3").classList.add('closed');
+ getById("multiselect-trigger3").classList.remove('open');
+ getById("chevarrow2").classList.add('bottom');
+
+ var knownTrack = false;
+
+ try {
+ const audioInputSelect = getById('audioSource3');
+ const videoSelect = getById('videoSource3');
+ const audioOutputSelect = getById('outputSource3');
+ const selectors = [videoSelect];
+
+
+ [audioInputSelect].forEach(select => {
+ while (select.firstChild) {
+ select.removeChild(select.firstChild);
+ }
+ });
+
+ const values = selectors.map(select => select.value);
+ selectors.forEach(select => {
+ while (select.firstChild) {
+ select.removeChild(select.firstChild);
+ }
+ });
+
+ [audioOutputSelect].forEach(select => {
+ while (select.firstChild) {
+ select.removeChild(select.firstChild);
+ }
+ });
+
+ var counter = 0;
+ for (let i = 0; i !== deviceInfos.length; ++i) {
+ const deviceInfo = deviceInfos[i];
+ if (deviceInfo == null) {
+ continue;
+ }
+
+ if (deviceInfo.kind === 'audioinput') {
+ const option = document.createElement('input');
+ option.type = "checkbox";
+ counter++;
+ const listele = document.createElement('li');
+ listele.style.display = "none";
+
+ try {
+ session.streamSrc.getAudioTracks().forEach(function(track) {
+ if (deviceInfo.label == track.label) {
+ option.checked = true;
+ listele.style.display = "inherit";
+ }
+ });
+ } catch (e) {
+ errorlog(e);
+ }
+
+ option.style.display = "none"
+ option.value = deviceInfo.deviceId || "default";
+ option.name = "multiselecta" + counter;
+ option.id = "multiselecta" + counter;
+ option.dataset.label = deviceInfo.label || ("microphone " + ((audioInputSelect.length || 0) + 1));
+
+ const label = document.createElement('label');
+ label.for = option.name;
+
+ label.innerHTML = " " + (deviceInfo.label || ("microphone " + ((audioInputSelect.length || 0) + 1)));
+
+ listele.appendChild(option);
+ listele.appendChild(label);
+ audioInputSelect.appendChild(listele);
+
+ option.onchange = function(event) { // make sure to clear 'no audio option' if anything else is selected
+ log("change 4768");
+ if (!(CtrlPressed)) {
+ document.querySelectorAll("#audioSource3 input[type='checkbox']").forEach(function(item) {
+ if (event.currentTarget.value !== item.value) {
+ item.checked = false;
+ if (item.dataset.type == "screen") {
+ item.parentElement.parentElement.removeChild(item.parentElement);
+ }
+ while (SelectedAudioInputDevices.indexOf(item.value) > -1) {
+ SelectedAudioInputDevices.splice(SelectedAudioInputDevices.indexOf(item.value), 1);
+ }
+ } else {
+ item.checked = true;
+ if (SelectedAudioInputDevices.indexOf(event.currentTarget.value) > -1) {} else {
+ SelectedAudioInputDevices.push(event.currentTarget.value);
+ }
+ }
+ });
+ } else {
+
+ if (SelectedAudioInputDevices.indexOf(event.currentTarget.value) > -1) {} else {
+ SelectedAudioInputDevices.push(event.currentTarget.value);
+ }
+
+ getById("audioSourceNoAudio2").checked = false;
+ }
+ };
+
+ } else if (deviceInfo.kind === 'videoinput') {
+ const option = document.createElement('option');
+ option.value = deviceInfo.deviceId || "default";
+ option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`;
+ try {
+ if (!knownTrack){
+ if (session.canvasSource){
+ session.canvasSource.srcObject.getVideoTracks().forEach(function(track) {
+ if (option.text == track.label) {
+ option.selected = true;
+ knownTrack = true;
+ }
+ });
+ }
+ }
+ if (!knownTrack){
+ session.streamSrc.getVideoTracks().forEach(function(track) {
+ if (option.text == track.label) {
+ option.selected = true;
+ knownTrack = true;
+ }
+ });
+ }
+ } catch (e) {
+ errorlog(e);
+ }
+ videoSelect.appendChild(option);
+
+ } else if (deviceInfo.kind === 'audiooutput') {
+ const option = document.createElement('option');
+ if (audioOutputSelect.length === 0) {
+ option.dataset.default = true;
+ } else {
+ option.dataset.default = false;
+ }
+ option.value = deviceInfo.deviceId || "default";
+ if (option.value == session.sink) {
+ option.selected = true;
+ }
+ option.text = deviceInfo.label || `Speaker ${outputSelect.length + 1}`;
+ audioOutputSelect.appendChild(option);
+
+ } else {
+ log('Some other kind of source/device: ', deviceInfo);
+ }
+ }
+
+ if (audioOutputSelect.childNodes.length == 0) {
+ const option = document.createElement('option');
+ option.value = "default";
+ option.text = "System Default";
+ audioOutputSelect.appendChild(option);
+ }
+
+ ////////////
+
+ session.streamSrc.getAudioTracks().forEach(function(track) { // add active ScreenShare audio tracks to the list
+ log("Checking for screenshare audio");
+ var matched = false;
+ for (var i = 0; i !== deviceInfos.length; ++i) {
+ var deviceInfo = deviceInfos[i];
+ if (deviceInfo == null) {
+ continue;
+ }
+ log("---");
+ if (track.label == deviceInfo.label) {
+ matched = true;
+ continue;
+ }
+ }
+ if (matched == false) { // Not a gUM device
+
+ var listele = document.createElement('li');
+ listele.style.display = "block";
+ var option = document.createElement('input');
+ option.type = "checkbox";
+ option.value = track.id;
+ option.checked = true;
+ option.style.display = "none";
+ option.name = track.label;
+ option.label = track.label;
+ option.dataset.type = "screen";
+ const label = document.createElement('label');
+ label.for = option.name;
+ label.innerHTML = " " + track.label;
+ listele.appendChild(option);
+ listele.appendChild(label);
+ option.onchange = function(event) { // make sure to clear 'no audio option' if anything else is selected
+ log("change 4873");
+ var trackid = null;
+ if (!(CtrlPressed)) {
+
+ document.querySelectorAll("#audioSource3 input[type='checkbox']").forEach(function(item) {
+ if (event.currentTarget.value !== item.value) { // this shoulnd't happen, but if it does.
+ item.checked = false;
+ if (item.dataset.type == "screen") {
+ item.parentElement.parentElement.removeChild(item.parentElement);
+ }
+ } else {
+ event.currentTarget.checked = true;
+ trackid = item.value;
+ }
+ });
+ } else {
+ //getById("audioSourceNoAudio2").checked=false;
+ if (event.currentTarget.dataset.type == "screen") {
+ event.currentTarget.parentElement.parentElement.removeChild(event.currentTarget.parentElement);
+ }
+ }
+ activatedPreview = false;
+ grabAudio("videosource", "#audioSource3", trackid); // exclude item.id.
+ event.stopPropagation();
+ return false;
+ };
+ audioInputSelect.appendChild(listele);
+ }
+ });
+ /////////// no video option
+ var optionss = false;
+ if (screensharesupport) {
+ optionss = document.createElement('option');
+ optionss.text = "New Screen Share";
+ optionss.value = "XXX";
+ optionss.previous =
+ videoSelect.appendChild(optionss); // NO AUDIO OPTION
+ }
+
+ option = document.createElement('option'); // no video
+ option.text = "Disable Video";
+ option.value = "ZZZ";
+ videoSelect.appendChild(option);
+ if (session.streamSrc.getVideoTracks().length == 0) {
+ option.selected = true;
+ } else if (knownTrack == false) {
+ option = document.createElement('option'); // no video
+ option.text = session.streamSrc.getVideoTracks()[0].label;
+ option.value = "YYY";
+ videoSelect.appendChild(option);
+ option.selected = true;
+
+ }
+
+ if (optionss) {
+ optionss.lastSelected = videoSelect.selectedIndex;
+ }
+
+ ///////////// /// NO AUDIO appended option
+
+ var option = document.createElement('input');
+ option.type = "checkbox";
+ option.value = "ZZZ";
+ option.style.display = "none"
+ option.id = "audioSourceNoAudio2";
+
+ var label = document.createElement('label');
+ label.for = option.name;
+ label.innerHTML = " No Audio";
+ var listele = document.createElement('li');
+
+ if (session.streamSrc.getAudioTracks().length == 0) {
+ option.checked = true;
+ } else {
+ listele.style.display = "none";
+ option.checked = false;
+ }
+ option.onchange = function(event) { // make sure to clear 'no audio option' if anything else is selected
+ log("change 4938");
+ if (!(CtrlPressed)) {
+ document.querySelectorAll("#audioSource3 input[type='checkbox']").forEach(function(item) {
+ if (event.currentTarget.value !== item.value) {
+ item.checked = false;
+ if (item.dataset.type == "screen") {
+ item.parentElement.parentElement.removeChild(item.parentElement);
+ }
+
+ while (SelectedAudioInputDevices.indexOf(item.value) > -1) {
+ SelectedAudioInputDevices.splice(SelectedAudioInputDevices.indexOf(item.value), 1);
+ }
+ } else {
+ item.checked = true;
+ if (SelectedAudioInputDevices.indexOf(event.currentTarget.value) > -1) {
+ //
+ } else {
+ SelectedAudioInputDevices.push(event.currentTarget.value);
+ }
+ }
+ });
+ } else {
+ document.querySelectorAll("#audioSource3 input[type='checkbox']").forEach(function(item) {
+ if (event.currentTarget.value === item.value) {
+ event.currentTarget.checked = true;
+ if (SelectedAudioInputDevices.indexOf(event.currentTarget.value) > -1) {} else {
+ SelectedAudioInputDevices.push(event.currentTarget.value);
+ }
+ } else {
+ item.checked = false;
+ if (item.dataset.type == "screen") {
+ item.parentElement.parentElement.removeChild(item.parentElement);
+ }
+ while (SelectedAudioInputDevices.indexOf(item.value) > -1) {
+ SelectedAudioInputDevices.splice(SelectedAudioInputDevices.indexOf(item.value), 1);
+ }
+ }
+
+ });
+ }
+ };
+ listele.appendChild(option);
+ listele.appendChild(label);
+ audioInputSelect.appendChild(listele);
+
+ ////////////
+
+
+ selectors.forEach((select, selectorIndex) => {
+ if (Array.prototype.slice.call(select.childNodes).some(n => n.value === values[selectorIndex])) {
+ select.value = values[selectorIndex];
+ }
+ });
+
+ audioInputSelect.onchange = function() {
+ log("Audio OPTION HAS CHANGED? 2");
+ activatedPreview = false;
+ setTimeout(function(){
+ grabAudio("videosource", "#audioSource3");
+ },10)
+ };
+ videoSelect.onchange = function(event) {
+ try {
+ if (event.target.options[event.target.options.selectedIndex].value === "XXX") {
+ videoSelect.selectedIndex = event.target.options[event.target.options.selectedIndex].lastSelected;
+ if (session.screenShareState == false) {
+ toggleScreenShare();
+ } else {
+ toggleScreenShare(true);
+ }
+ return;
+ }
+ } catch (e) {}
+ log("video source changed");
+ activatedPreview = false;
+ grabVideo(session.quality, "videosource", "select#videoSource3");
+ enumerateDevices().then(gotDevices2).then(function() {
+ session.screenShareState = false;
+ pokeIframeAPI("screen-share-ended");
+ getById("screensharebutton").classList.add("float");
+ getById("screensharebutton").classList.remove("float2");
+ });
+ };
+ getById("refreshVideoButton").onclick = function() {
+ if (session.screenShareState) {
+ log("can't refresh a screenshare");
+ return;
+ }
+ log("video source changed");
+ activatedPreview = false;
+ grabVideo(session.quality, "videosource", "select#videoSource3");
+ };
+
+ audioOutputSelect.onchange = function() {
+
+ if ((iOS) || (iPad)) {
+ return;
+ }
+
+ try {
+ var outputSelect = getById('outputSource3');
+ session.sink = outputSelect.options[outputSelect.selectedIndex].value;
+ } catch (e) {
+ errorlog(e);
+ }
+ if (!session.sink){return;}
+
+ try {
+ if (document.getElementById("videosource")){
+ getById("videosource").setSinkId(session.sink).then(() => {
+ log("New Output Device:" + session.sink);
+ }).catch(error => {
+ errorlog(error);
+ });
+ }
+
+ for (UUID in session.rpcs) {
+ try{
+ if (session.rpcs[UUID].videoElement){
+ session.rpcs[UUID].videoElement.setSinkId(session.sink).then(() => {
+ log("New Output Device for: " + UUID);
+ }).catch(error => {
+ errorlog(error);
+ });
+ }
+ } catch(e){warnlog(e);}
+ }
+ } catch (e) {
+ errorlog(e);
+ }
+ }
+
+ } catch (e) {
+ errorlog(e);
+ }
+}
+
+function gotDevicesRemote(deviceInfos, UUID) {
+
+ try {
+ if (document.getElementById("remoteVideoSelect_"+UUID)){
+ var videoSelect = document.getElementById("remoteVideoSelect_"+UUID);
+ var length = videoSelect.options.length;
+ for (i = length-1; i >= 0; i--) {
+ videoSelect.options[i] = null;
+ }
+ } else {
+ var videoSelect = document.createElement("select");
+ videoSelect.id = "remoteVideoSelect_"+UUID;
+ videoSelect.style = "max-width:180px;font-size: 70% !important; margin: 5px 5px 5px 0; padding:2px;";
+ var buttonGO = document.createElement("button");
+ buttonGO.innerHTML = '
Apply';
+ buttonGO.style = "padding: 5px;";
+ buttonGO.title = "This will ask the remote guest for permission to change";
+ buttonGO.onclick = function(){
+ var data = {}
+ data.changeCamera = videoSelect.value;
+ data.UUID = UUID;
+ session.sendRequest(data, UUID); // Viewer is requesting the PUBLISHER
+ };
+
+ getById("advanced_video_director_" + UUID).appendChild(videoSelect);
+ getById("advanced_video_director_" + UUID).appendChild(buttonGO);
+ }
+
+ if (document.getElementById("remoteAudioSelect_"+UUID)){
+ var audioSelect = document.getElementById("remoteAudioSelect_"+UUID);
+ var length = audioSelect.options.length;
+ for (i = length-1; i >= 0; i--) {
+ audioSelect.options[i] = null;
+ }
+ } else {
+ var audioSelect = document.createElement("select");
+ audioSelect.id = "remoteAudioSelect_"+UUID;
+ audioSelect.style = "max-width:180px;font-size: 70% !important; margin: 5px 5px 5px 0; padding:2px;";
+ var buttonGO = document.createElement("button");
+ buttonGO.innerHTML = '
Apply';
+ buttonGO.style = "padding: 5px;";
+ buttonGO.title = "This will ask the remote guest for permission to change";
+ buttonGO.onclick = function(){
+ var data = {}
+ data.changeMicrophone = audioSelect.value;
+ data.UUID = UUID;
+ session.sendRequest(data, UUID); // Viewer is requesting the PUBLISHER
+ }
+ getById("advanced_audio_director_" + UUID).appendChild(audioSelect);
+ getById("advanced_audio_director_" + UUID).appendChild(buttonGO);
+ }
+
+ if (document.getElementById("remoteAudioOutputSelect_"+UUID)){
+ var audioOutputSelect = document.getElementById("remoteAudioOutputSelect_"+UUID);
+ var length = audioOutputSelect.options.length;
+ for (i = length-1; i >= 0; i--) {
+ audioOutputSelect.options[i] = null;
+ }
+ } else {
+ var audioOutputSelect = document.createElement("select");
+ audioOutputSelect.id = "remoteAudioOutputSelect_"+UUID;
+ audioOutputSelect.style = "max-width:180px;font-size: 70% !important; margin: 5px 5px 5px 0; padding:2px;";
+ var buttonGO = document.createElement("button");
+ buttonGO.innerHTML = '
Apply';
+ buttonGO.style = "padding: 5px;";
+ buttonGO.title = "This will ask the remote guest for permission to change";
+ buttonGO.onclick = function(){
+ var data = {}
+ data.changeSpeaker = audioOutputSelect.value;
+ data.UUID = UUID;
+ session.sendRequest(data, UUID); // Viewer is requesting the PUBLISHER
+ }
+ getById("advanced_audio_director_" + UUID).appendChild(audioOutputSelect);
+ getById("advanced_audio_director_" + UUID).appendChild(buttonGO);
+ getById("advanced_audio_director_" + UUID).appendChild(buttonGO);
+ }
+
+
+ for (let i = 0; i !== deviceInfos.length; ++i) {
+ const deviceInfo = deviceInfos[i];
+ if (deviceInfo == null) {
+ continue;
+ }
+ if (deviceInfo.kind === 'videoinput'){
+ const option = document.createElement('option');
+ option.value = deviceInfo.deviceId || "default";
+ option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`;
+ videoSelect.appendChild(option);
+
+ } else if (deviceInfo.kind === 'audioinput'){
+ const option = document.createElement('option');
+ option.value = deviceInfo.deviceId || "default";
+ option.text = deviceInfo.label || `microphone ${audioSelect.length + 1}`;
+ audioSelect.appendChild(option);
+
+ } else if (deviceInfo.kind === 'audiooutput'){
+ const option = document.createElement('option');
+ option.value = deviceInfo.deviceId || "default";
+ option.text = deviceInfo.label || `microphone ${audioOutputSelect.length + 1}`;
+ audioOutputSelect.appendChild(option);
+ }
+ }
+
+ } catch(e){errorlog(e);}
+}
+
+function playtone(screen = false) {
+
+ if ((iOS) || (iPad)) {
+ // try{
+ // session.audioContext.resume();
+ // } catch(e){errorlog(e);}
+ var testtone = document.getElementById("testtone");
+ if (testtone) {
+ testtone.mute
+ testtone.play();
+ }
+ return;
+ }
+
+ if (screen) {
+ try{
+ var outputSelect = getById('outputSourceScreenshare');
+ session.sink = outputSelect.options[outputSelect.selectedIndex].value;
+ } catch(e){errorlog(e);}
+ }
+
+ var testtone = document.getElementById("testtone");
+ if (testtone) {
+ if (session.sink) {
+ try {
+ testtone.setSinkId(session.sink).then(() => { // TODO: iOS doens't support sink. Needs to bypass if IOS
+ log("changing audio sink:" + session.sink);
+ testtone.play();
+ }).catch(error => {
+ errolog("couldn't set sink");
+ errorlog(error);
+ });
+ } catch (e) {
+ warnlog(e); // firefox?
+ testtone.play();
+ }
+ } else {
+ testtone.play();
+ }
+ }
+}
+
+async function getAudioOnly(selector, trackid = null, override = false) {
+ var audioSelect = document.querySelector(selector).querySelectorAll("input");
+ var audioList = [];
+ var streams = [];
+ log("getAudioOnly()");
+ for (var i = 0; i < audioSelect.length; i++) {
+ if (audioSelect[i].value == "ZZZ") {
+ continue;
+ } else if (trackid == audioSelect[i].value) { // skip already excluded
+ continue;
+ } else if ("screen" == audioSelect[i].dataset.type) { // skip already excluded ---------- !!!!!! DOES THIS MAKE SENSE? TODO: CHECK
+ continue;
+ } else if (audioSelect[i].checked) {
+ log(audioSelect[i]);
+ audioList.push(audioSelect[i]);
+ }
+ }
+ for (var i = 0; i < audioList.length; i++) {
+
+ if ((audioList[i].value == "default") && (session.echoCancellation !== false) && (session.autoGainControl !== false) && (session.noiseSuppression !== false)) {
+ var constraint = {
+ audio: true
+ };
+ } else { // Just trying to avoid problems with some systems that don't support these features
+ var constraint = {
+ audio: {
+ deviceId: {
+ exact: audioList[i].value
+ }
+ }
+ };
+ if (session.echoCancellation === false) {
+ constraint.audio.echoCancellation = false;
+ } else {
+ constraint.audio.echoCancellation = true;
+ }
+ if (session.autoGainControl === false) {
+ constraint.audio.autoGainControl = false;
+ } else {
+ constraint.audio.autoGainControl = true;
+ }
+ if (session.noiseSuppression === false) {
+ constraint.audio.noiseSuppression = false;
+ } else {
+ constraint.audio.noiseSuppression = true;
+ }
+ }
+ constraint.video = false;
+ if (override !== false) {
+ try {
+ if (override.audio.deviceId == audioList[i].value) {
+ constraint = override;
+ }
+ } catch (e) {}
+ }
+
+ if (session.audioInputChannels) {
+ if (constraint.audio === true) {
+ constraint.audio = {};
+ constraint.audio.channelCount = session.audioInputChannels;
+ } else if (constraint.audio) {
+ constraint.audio.channelCount = session.audioInputChannels;
+ }
+ }
+ log("CONSTRAINT");
+ log(constraint);
+ var stream = await navigator.mediaDevices.getUserMedia(constraint).then(function(stream2) {
+ return stream2;
+ }).catch(function(err) {
+ warnlog(err);
+ if (!(session.cleanOutput)) {
+ if (override !== false) {
+ if (err.name) {
+ if (err.constraint) {
+ warnUser(err['name'] + ": " + err['constraint']);
+ }
+ }
+ }
+ }
+ }); // More error reporting maybe?
+ if (stream) {
+ streams.push(stream);
+ }
+ }
+
+ return streams;
+}
+
+function applyMirror(mirror, eleName = 'previewWebcam') { // true unmirrors as its already mirrored
+
+ var transFlip = "";
+ var transNorm = "";
+ if ((eleName == 'videosource') && (session.windowed)) {
+ transFlip = " translate(0, 50%)";
+ transNorm = " translate(0, -50%)";
+ }
+
+ if (session.mirrored == 2) {
+ mirror = true;
+ } else if (session.mirrored === 0) {
+ mirror = true;
+ }
+
+
+ if (mirror) {
+ if (session.mirrored && session.flipped) {
+ getById(eleName).style.transform = " scaleX(-1) scaleY(-1)" + transFlip;
+ getById(eleName).classList.add("mirrorControl");
+ } else if (session.mirrored) {
+ getById(eleName).style.transform = "scaleX(-1)" + transNorm;
+ getById(eleName).classList.add("mirrorControl");
+ } else if (session.flipped) {
+ getById(eleName).style.transform = "scaleY(-1) scaleX(1)" + transFlip;
+ getById(eleName).classList.remove("mirrorControl");
+ } else {
+ getById(eleName).style.transform = "scaleX(1)" + transNorm;
+ getById(eleName).classList.remove("mirrorControl");
+ }
+ } else {
+ if (session.mirrored && session.flipped) {
+ getById(eleName).style.transform = " scaleX(1) scaleY(-1)" + transFlip;
+ getById(eleName).classList.remove("mirrorControl");
+ } else if (session.mirrored) {
+ getById(eleName).style.transform = "scaleX(1)" + transNorm;
+ getById(eleName).classList.remove("mirrorControl");
+ } else if (session.flipped) {
+ getById(eleName).style.transform = "scaleY(-1) scaleX(-1)" + transFlip;
+ getById(eleName).classList.add("mirrorControl");
+ } else {
+ getById(eleName).style.transform = "scaleX(-1)" + transNorm;
+ getById(eleName).classList.add("mirrorControl");
+ }
+ }
+}
+
+function cleanupMediaTracks() {
+ try {
+ if (session.streamSrc) {
+ session.streamSrc.getTracks().forEach(function(track) {
+ session.streamSrc.removeTrack(track);
+ track.stop();
+ log("stopping old track");
+ });
+ }
+ if (session.videoElement) {
+ session.videoElement.srcObject.getTracks().forEach(function(track) {
+ session.videoElement.srcObject.removeTrack(track);
+ track.stop();
+ log("stopping old track");
+ });
+ }
+ activatedPreview = false;
+ } catch (e) {
+ errorlog(e);
+ }
+}
+
+/// Detect system changes; handle change or use for debugging
+var lastAudioDevice = null;
+var lastVideoDevice = null;
+var lastPlaybackDevice = null;
+
+var audioReconnectTimeout = null;
+var videoReconnectTimeout = null;
+var grabDevicesTimeout = null;
+var playbackReconnectTimeout = null;
+
+function reconnectDevices(event) { /// TODO: Perhaps change this to only if there is a DISCONNECT; rather than ON NEW DEVICE?
+ if ((iOS) || (iPad)) {
+ // try{
+ // session.audioContext.resume();
+ // } catch(e){errorlog(e);}
+ // resetupAudioOut();
+ return;
+ }
+ warnlog("A media device has changed");
+
+ if (document.getElementById("previewWebcam")) {
+ var outputSelect = document.getElementById("outputSource");
+ if (!outputSelect) {
+ errorlog("resetup audio failed");
+ return;
+ }
+ try {
+ session.sink = outputSelect.options[outputSelect.selectedIndex].value;
+ } catch (e) {
+ errorlog(e);
+ }
+ if (session.sink){
+ try {
+ getById("previewWebcam").setSinkId(session.sink).then(() => {}).catch(error => {
+ warnlog(error);
+ });
+ } catch(e){errorlog(e);}
+ }
+ return;
+ }
+
+
+ if (session.streamSrc === null) {
+ return;
+ }
+ if (document.getElementById("videosource") === null) {
+ return;
+ }
+
+ try {
+ session.streamSrc.getTracks().forEach(function(track) {
+
+ if (track.readyState == "ended") {
+ if (track.kind == "audio") {
+ lastAudioDevice = track.label;
+ } else if (track.kind == "video") {
+ lastVideoDevice = track.label;
+ }
+ session.streamSrc.removeTrack(track);
+ log("remove ended old track");
+ }
+ });
+
+ session.videoElement.srcObject.getTracks().forEach(function(track) {
+ if (track.readyState == "ended") {
+ session.videoElement.srcObject.removeTrack(track);
+ log("remove ended old track");
+ }
+ });
+
+ } catch (e) {
+ errorlog(e);
+ }
+
+ clearTimeout(audioReconnectTimeout);
+ audioReconnectTimeout = null;
+ if (lastAudioDevice) {
+ audioReconnectTimeout = setTimeout(function() { // only reconnect same audio device. If reconnected, clear the disconnected flag.
+ enumerateDevices().then(gotDevices2).then(function() {
+ // TODO: check to see if any audio is connected?
+ var streamConnected = false;
+ var audioSelect = getById("audioSource3").querySelectorAll("input");
+ for (var i = 0; i < audioSelect.length; i++) {
+ if (audioSelect[i].value == "ZZZ") {
+ continue;
+ } else if (audioSelect[i].checked) {
+ log("checked");
+ streamConnected = true;
+ break;
+ }
+ }
+
+ if (!streamConnected) {
+ for (var i = 0; i < audioSelect.length; i++) {
+ if (audioSelect[i].value == "ZZZ") {
+ continue;
+ }
+ //errorlog(lastAudioDevice + " : " + audioSelect[i].dataset.label);
+ if (lastAudioDevice == audioSelect[i].dataset.label) { // if the last disconnected device matches.
+ audioSelect[i].checked = true;
+ streamConnected = true;
+ lastAudioDevice = null;
+ warnlog("DISCONNECTED AUDIO DEVICE RECONNECTED");
+ //for (var j=0; j
check if session.sink still exists -> if not, select default default (track past last sink) -> if last disconnected devices comes back, reconnect it.
+
+ // lastPlaybackDevice
+ //if (session.sink){ // Let Chrome handle the audio automatically, since not manually specified.
+ clearTimeout(playbackReconnectTimeout);
+ playbackReconnectTimeout = setTimeout(function() {
+ enumerateDevices().then(gotDevices2).then(function() {
+ resetupAudioOut();
+ });
+ }, 500);
+
+}
+
+function resetupAudioOut() {
+ if ((iOS) || (iPad)) {
+ for (var UUID in session.rpcs) {
+ if (session.rpcs[UUID].videoElement){
+ try{
+ session.rpcs[UUID].videoElement.pause().then(() => {
+ setTimeout(function(uuid) {
+ try{
+ session.rpcs[uuid].videoElement.play().then(() => {
+ log("toggle pause/play");
+ });
+ } catch(e){errorlog(e);}
+ }, 0, UUID);
+ });
+ } catch(e){errorlog(e);}
+ }
+ }
+ return;
+ }
+
+ var outputSelect = document.getElementById("outputSource3");
+ if (!outputSelect) {
+ errorlog("resetup audio failed");
+ return;
+ }
+ log("Resetting Audio Output");
+ var sinkSet = false;
+ for (var i = 0; i < outputSelect.options.length; i++) {
+ if (outputSelect.options[i].value == session.sink) {
+ outputSelect.options[i].selected = true;
+ sinkSet = true;
+ }
+ }
+ if (sinkSet == false) {
+ if (outputSelect.options[0]) {
+ outputSelect.options[0].selected = true;
+ sinkSet = outputSelect.value;
+ }
+ } else {
+ sinkSet = session.sink;
+ }
+ if (sinkSet) {
+ if (session.videoElement){
+ session.videoElement.setSinkId(sinkSet).then(() => {}).catch(error => {
+ errorlog(error);
+ });
+ }
+ for (UUID in session.rpcs) {
+ try{
+ if (session.rpcs[UUID].videoElement){
+ session.rpcs[UUID].videoElement.setSinkId(sinkSet).then(() => {
+ log("New Output Device for: " + UUID);
+ }).catch(error => {
+ errorlog(error);
+ });
+ }
+ } catch(e){warnlog(e);}
+ }
+ }
+}
+
+function obfuscateURL(input) {
+ if (input.startsWith("https://obs.ninja/")) {
+ input = input.replace('https://obs.ninja/', '');
+ } else if (input.startsWith("http://obs.ninja/")) {
+ input = input.replace('http://obs.ninja/', '');
+ } else if (input.startsWith("obs.ninja/")) {
+ input = input.replace('obs.ninja/', '');
+ }
+
+ input = input.replace('&view=', '&v=');
+ input = input.replace('&view&', '&v&');
+ input = input.replace('?view&', '?v&');
+ input = input.replace('?view=', '?v=');
+
+ input = input.replace('&videobitrate=', '&vb=');
+ input = input.replace('?videobitrate=', '?vb=');
+ input = input.replace('&bitrate=', '&vb=');
+ input = input.replace('?bitrate=', '?vb=');
+
+ input = input.replace('?audiodevice=', '?ad=');
+ input = input.replace('&audiodevice=', '&ad=');
+
+ input = input.replace('?label=', '?l=');
+ input = input.replace('&label=', '&l=');
+
+ input = input.replace('?stereo=', '?s=');
+ input = input.replace('&stereo=', '&s=');
+ input = input.replace('&stereo&', '&s&');
+ input = input.replace('?stereo&', '?s&');
+
+ input = input.replace('?webcam&', '?wc&');
+ input = input.replace('&webcam&', '&wc&');
+
+ input = input.replace('?remote=', '?rm=');
+ input = input.replace('&remote=', '&rm=');
+
+ input = input.replace('?password=', '?p=');
+ input = input.replace('&password=', '&p=');
+
+ input = input.replace('&maxvideobitrate=', '&mvb=');
+ input = input.replace('?maxvideobitrate=', '?mvb=');
+
+ input = input.replace('&maxbitrate=', '&mvb=');
+ input = input.replace('?maxbitrate=', '?mvb=');
+
+ input = input.replace('&height=', '&h=');
+ input = input.replace('?height=', '?h=');
+
+ input = input.replace('&width=', '&w=');
+ input = input.replace('?width=', '?w=');
+
+ input = input.replace('&quality=', '&q=');
+ input = input.replace('?quality=', '?q=');
+
+ input = input.replace('&cleanoutput=', '&clean=');
+ input = input.replace('?cleanoutput=', '?clean=');
+
+ input = input.replace('&maxviewers=', '&clean=');
+ input = input.replace('?maxviewers=', '?clean=');
+
+ input = input.replace('&framerate=', '&fr=');
+ input = input.replace('?framerate=', '?fr=');
+
+ input = input.replace('&fps=', '&fr=');
+ input = input.replace('?fps=', '?fr=');
+
+ input = input.replace('&permaid=', '&push=');
+ input = input.replace('?permaid=', '?push=');
+
+ input = input.replace('&roomid=', '&r=');
+ input = input.replace('?roomid=', '?r=');
+
+ input = input.replace('&room=', '&r=');
+ input = input.replace('?room=', '?r=');
+
+ log(input);
+ var key = "OBSNINJAFORLIFE";
+ var encrypted = CryptoJS.AES.encrypt(input, key);
+ var output = "https://invite.cam/" + encrypted.toString();
+ return output;
+}
+
+
+
+try {
+ navigator.mediaDevices.ondevicechange = reconnectDevices;
+} catch (e) {
+ errorlog(e);
+}
+
+
+function updateConnectionStatus() {
+ warnlog("Connection type changed from " + session.stats.network_type + " to " + Connection.effectiveType);
+ session.stats.network_type = Connection.effectiveType + " / " + Connection.type;
+ session.ping();
+}
+
+try {
+ var Connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
+ session.stats.network_type = Connection.effectiveType + " / " + Connection.type;
+ Connection.addEventListener('change', updateConnectionStatus);
+} catch (e) {}
+
+
+
+var beforeScreenShare = null; // video
+var screenShareAudioTrack = null;
+async function toggleScreenShare(reload = false) { ////////////////////////////
+
+ if (reload) {
+ await grabScreen(quality = 0, audio = true, videoOnEnd = true).then(res => {
+ if (res != false) {
+ session.screenShareState = true;
+ getById("screensharebutton").classList.add("float2");
+ getById("screensharebutton").classList.remove("float");
+ enumerateDevices().then(gotDevices2).then(function() {});
+ }
+
+ });
+ return;
+ }
+
+
+ if (session.screenShareState == false) { // adding a screen
+
+ await grabScreen(quality = 0, audio = true, videoOnEnd = true).then(res => {
+ if (res != false) {
+ session.screenShareState = true;
+ getById("screensharebutton").classList.add("float2");
+ getById("screensharebutton").classList.remove("float");
+ enumerateDevices().then(gotDevices2).then(function() {});
+ }
+
+ });
+
+ } else { // removing a screen . session.screenShareState already true true /////////////////////////////////
+
+
+ session.screenShareState = false;
+ pokeIframeAPI("screen-share-ended");
+
+ if (beforeScreenShare) {
+
+ session.streamSrc.getAudioTracks().forEach(function(track) { // previous video track; saving it. Must remove the track at some point.
+ if (screenShareAudioTrack == track) { // since there are more than one audio track, lets see if we can remove JUST the audio track for the screen share.
+ session.streamSrc.removeTrack(track);
+ track.stop();
+ }
+ });
+ session.streamSrc.getVideoTracks().forEach(function(track) {
+ //errorlog(track);
+ session.streamSrc.removeTrack(track);
+ track.stop();
+ });
+
+ session.videoElement.srcObject.getVideoTracks().forEach(function(track) {
+ //errorlog(track);
+ session.videoElement.srcObject.removeTrack(track);
+ track.stop();
+ });
+
+ getById("screensharebutton").classList.add("float");
+ getById("screensharebutton").classList.remove("float2");
+
+ session.streamSrc.addTrack(beforeScreenShare); // add back in the video track we had before we started screen sharing. It should be NULL if we changed the video track else where (such as via the settings). #TODO:
+ session.videoElement.srcObject.addTrack(beforeScreenShare);
+
+ toggleVideoMute(true);
+ for (UUID in session.pcs) {
+ 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
+ var senders = session.pcs[UUID].getSenders(); // 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 (sender.track) {
+ if (sender.track && sender.track.kind == "video") {
+ sender.replaceTrack(beforeScreenShare); // replace may not be supported by all browsers. eek.
+ sender.track.enabled = true;
+ added = true;
+ }
+ }
+ });
+ if (added == false) {
+ session.pcs[UUID].addTrack(beforeScreenShare, stream);
+ 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);
+ }
+ }
+ session.refreshScale();
+ beforeScreenShare = null;
+ }
+ toggleSettings(forceShow = true);
+ //enumerateDevices().then(gotDevices2).then(function(){
+ //grabVideo();
+ //grabAudio();
+ // toggleSettings(forceShow=true);
+ //});
+
+
+ }
+}
+var ElectronDesktopCapture = false;
+if (navigator.userAgent.toLowerCase().indexOf(' electron/') > -1) { // this enables Screen Capture in Electron
+ try {
+ const { desktopCapturer} = require('electron'); // This is definitely Electron specific. Requires Node Integration to be on, which is a potential security hazzard
+ window.navigator.mediaDevices.getDisplayMedia = () => {
+ return new Promise(async (resolve, reject) => {
+ try {
+ const sources = await desktopCapturer.getSources({ types: ['screen', 'window'] });
+
+ const selectionElem = document.createElement('div');
+ selectionElem.classList = 'desktop-capturer-selection';
+ selectionElem.innerHTML = `
+
+ `;
+ document.body.appendChild(selectionElem);
+
+ document.getElementById('cancelscreenshare').addEventListener('click', async () => {
+ selectionElem.remove()
+ reject(err)
+ });
+
+
+ document.querySelectorAll('.desktop-capturer-selection__btn').forEach(button => {
+ button.addEventListener('click', async () => {
+ try {
+ const id = button.getAttribute('data-id')
+ const source = sources.find(source => source.id === id)
+ if(!source) {
+ throw new Error(`Source with id ${id} does not exist`)
+ }
+
+ const stream = await window.navigator.mediaDevices.getUserMedia({
+ audio: false,
+ video: {
+ mandatory: {
+ chromeMediaSource: 'desktop',
+ chromeMediaSourceId: source.id,
+ maxFrameRate: 60
+ }
+ }
+ })
+ resolve(stream)
+
+ selectionElem.remove()
+ } catch (err) {
+ errorlog('Error selecting desktop capture source:', err)
+ reject(err)
+ }
+ })
+ });
+ } catch (err) {
+ errorlog('Error displaying desktop capture sources:', err);
+ reject(err);
+ }
+ })
+ }
+ ElectronDesktopCapture = true;
+ } catch(e){
+ warnlog("couldn't load electron's screen capture; you might need to decrease security permissions a bit.");
+ }
+}
+
+async function grabScreen(quality = 0, audio = true, videoOnEnd = false) {
+ if (!navigator.mediaDevices.getDisplayMedia) {
+ if (!(session.cleanOutput)) {
+ setTimeout(function() {
+ warnUser("Sorry, your browser is not supported. Please use the desktop versions of Firefox or Chrome instead");
+ }, 1);
+ }
+ return false;
+ }
+
+ if (navigator.userAgent.toLowerCase().indexOf(' electron/') > -1) {
+ if (!ElectronDesktopCapture){
+ if (!(session.cleanOutput)) {
+ warnUser("Your Electron app does not support Screen Capture. Update your Electron Capture app and then enable Elevated Privileges (right click) to access screen-sharing.");
+ }
+ return false;
+ }
+ }
+
+ if (quality == 0) { // I'm going to go with default quality in most cases, as I assume Dynamic screenshare is going to want low-fps / high def.
+ var width = {
+ ideal: 1920
+ };
+ var height = {
+ ideal: 1080
+ };
+ } else if (quality == 1) {
+ var width = {
+ ideal: 1280
+ };
+ var height = {
+ ideal: 720
+ };
+ } else if (quality == 2) {
+ var width = {
+ ideal: 640
+ };
+ var height = {
+ ideal: 360
+ };
+ } else if (quality >= 3) { // lowest
+ var width = {
+ ideal: 320
+ };
+ var height = {
+ ideal: 180
+ };
+ }
+
+ if (session.width) {
+ width = {
+ ideal: session.width
+ };
+ }
+ if (session.height) {
+ height = {
+ ideal: session.height
+ };
+ }
+
+ var constraints = { // this part is a bit annoying. Do I use the same settings? I can add custom setting controls here later
+ audio: {
+ echoCancellation: false, // For screen sharing, we want it off by default.
+ autoGainControl: false
+ , noiseSuppression: false
+ }
+ , video: {
+ width: width
+ , height: height
+ }
+ //,cursor: {exact: "none"}
+ };
+
+ try {
+ let supportedConstraints = navigator.mediaDevices.getSupportedConstraints();
+ if (supportedConstraints.cursor) {
+ constraints.video.cursor = "never";
+ }
+ } catch(e){
+ warnlog("navigator.mediaDevices.getSupportedConstraints() not supported");
+ }
+
+ if (session.echoCancellation === true) {
+ constraints.audio.echoCancellation = true;
+ }
+ if (session.autoGainControl === true) {
+ constraints.audio.autoGainControl = true;
+ }
+ if (session.noiseSuppression === true) {
+ constraints.audio.noiseSuppression = true;
+ }
+ if (audio == false) {
+ constraints.audio = false;
+ }
+
+ if (session.framerate) {
+ constraints.video.frameRate = session.framerate;
+ } else if (session.maxframerate !== false){ // not limiting screen share's fps with quality=2 due to gaming centric nature
+ constraints.video.frameRate = {
+ ideal: session.maxframerate,
+ max: session.maxframerate
+ };
+ }
+
+ return navigator.mediaDevices.getDisplayMedia(constraints).then(function(stream) {
+ log("adding video tracks 2245");
+
+ var eleName = "videosource";
+ try {
+ if (session.streamSrc) {
+ session.streamSrc.getVideoTracks().forEach(function(track) {
+ //track.stop();
+ beforeScreenShare = track;
+ session.streamSrc.removeTrack(track);
+ log("stopping video track");
+ });
+ session.videoElement.srcObject.getVideoTracks().forEach(function(track) {
+ //track.stop();
+ session.videoElement.srcObject.removeTrack(track);
+ log("stopping video track 2");
+ });
+ } else {
+ session.streamSrc = new MediaStream();
+ session.videoElement.srcObject = session.streamSrc;
+ log("CREATE NEW STREAM");
+ }
+ } catch (e) {
+ warnlog(e);
+ }
+ //session.videoElement.srcObject = session.streamSrc;
+
+ // Let's not pass the AUDIO thru the webaudio filter. It's screen share after all.
+
+ try {
+ stream.getVideoTracks()[0].onended = function() { // if screen share stops,
+
+ session.streamSrc.getVideoTracks().forEach(function(track) {
+ session.streamSrc.removeTrack(track);
+ track.stop();
+ log("stopping video track 3");
+ });
+ session.videoElement.srcObject.getVideoTracks().forEach(function(track) {
+ session.videoElement.srcObject.removeTrack(track);
+ track.stop();
+ log("stopping video track 4");
+ });
+
+ session.screenShareState = false;
+ pokeIframeAPI("screen-share-ended");
+
+ getById("screensharebutton").classList.add("float");
+ getById("screensharebutton").classList.remove("float2");
+
+ if (videoOnEnd == true) {
+ //activatedPreview = false;
+
+ if (beforeScreenShare) {
+ session.streamSrc.addTrack(beforeScreenShare);
+ session.videoElement.srcObject.addTrack(beforeScreenShare);
+ if (beforeScreenShare.kind == "video") {
+ toggleVideoMute(true);
+ for (UUID in session.pcs) {
+ 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
+ var senders = session.pcs[UUID].getSenders(); // 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 (sender.track) {
+ if (sender.track && sender.track.kind == "video") {
+ sender.replaceTrack(beforeScreenShare); // replace may not be supported by all browsers. eek.
+ sender.track.enabled = true;
+ added = true;
+ }
+ }
+ });
+ if (added == false) {
+ session.pcs[UUID].addTrack(beforeScreenShare, stream);
+ 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);
+ }
+ }
+ session.refreshScale();
+ }
+ beforeScreenShare = null;
+ }
+
+ toggleSettings(forceShow = true);
+ //grabVideo(eleName='videosource', selector="select#videoSource3");
+
+
+ } else {
+ grabScreen();
+ }
+ };
+ } catch (e) {
+ log("No Video selected; screensharing?");
+ }
+
+ stream.getTracks().forEach(function(track) {
+ addScreenDevices(track);
+
+ session.streamSrc.addTrack(track, stream); // Lets not add the audio to this preview; echo can be annoying
+ session.videoElement.srcObject.addTrack(track, stream); // I should probably add the remote control to his ; #TODO:
+
+ if (track.kind == "video") {
+ toggleVideoMute(true);
+ for (UUID in session.pcs) {
+ 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
+ var senders = session.pcs[UUID].getSenders(); // 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 (sender.track) {
+ if (sender.track && sender.track.kind == "video") {
+ sender.replaceTrack(track); // replace may not be supported by all browsers. eek.
+ sender.track.enabled = true;
+ added = true;
+ }
+ }
+ });
+ if (added == false) {
+ session.pcs[UUID].addTrack(track, stream);
+ 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);
+ }
+ }
+ session.refreshScale();
+ } else {
+ toggleMute(true); // I might want to move this outside the loop, but whatever
+ for (UUID in session.pcs) {
+ try {
+ if (session.pcs[UUID].allowAudio == true) {
+ session.pcs[UUID].addTrack(track, stream); // If screen sharing, we will add audio; not replace.
+ }
+ } catch (e) {
+ errorlog(log);
+ }
+ }
+ screenShareAudioTrack = track;
+ }
+ });
+ applyMirror(true, eleName);
+ return true;
+ }).catch(function(err) {
+ errorlog(err);
+ if ((err.name == "NotAllowedError") || (err.name == "PermissionDeniedError")) {
+ // User Stopped it.
+ } else {
+ if (audio == true) {
+ setTimeout(function() {
+ grabScreen(quality, false);
+ }, 1);
+ }
+ if (!(session.cleanOutput)) {
+ setTimeout(function() {
+ warnUser(err);
+ }, 1); // TypeError: Failed to execute 'getDisplayMedia' on 'MediaDevices': Audio capture is not supported
+ }
+ }
+ return false;
+ });
+}
+
+function toggleRoomSettings(){
+
+ toggle(getById('roomSettings'));
+
+
+ if (document.getElementById("modalBackdrop")){
+ getById("modalBackdrop").innerHTML = ''; // Delete modal
+ getById("modalBackdrop").remove();
+ } else {
+ zindex = 25;
+ getById('roomSettings').style.zIndex = 25;
+ var modalTemplate = `
`;
+ document.body.insertAdjacentHTML("beforeend", modalTemplate); // Insert modal at body end
+ document.getElementById("modalBackdrop").addEventListener("click", toggleRoomSettings);
+ document.getElementById('trbSettingInput').value = session.totalRoomBitrate;
+ document.getElementById('trbSettingInputFeedback').innerHTML = session.totalRoomBitrate;
+
+ }
+
+}
+
+function changeTRB(ele){
+ session.totalRoomBitrate = parseInt(ele.value);
+ var msg = {};
+ msg.directorSettings={};
+ msg.directorSettings.totalRoomBitrate=session.totalRoomBitrate;
+ session.sendMessage(msg);
+}
+
+function sendMediaDevices(UUID){
+ enumerateDevices().then(function(deviceInfos){
+ var data = {};
+ data.UUID = UUID;
+ data.mediaDevices = deviceInfos;
+ session.sendMessage(data, data.UUID);
+ });
+}
+
+function changeVideoDevice(index, quality=0){
+ enumerateDevices().then(gotDevices2).then(function() {
+ activatedPreview=false;
+ document.getElementById("videoSource3").selectedIndex = index+"";
+ grabVideo(quality, "videosource", "#videoSource3");
+ });
+}
+
+function changeAudioDevice(index){
+ enumerateDevices().then(gotDevices2).then(function() {
+ activatedPreview=false;
+ var audioSelect = document.getElementById("audioSource3").querySelectorAll("input");
+ for (var i = 0; i < audioSelect.length; i++) {
+ audioSelect[i].checked = false;
+ }
+ audioSelect[index-1].checked = true;
+ grabAudio("videosource", "#audioSource3");
+ });
+}
+
+function changeVideoDeviceById(deviceID, UUID){
+ enumerateDevices().then(gotDevices2).then(function() {
+ var opts = document.getElementById("videoSource3").options;
+ var index = false
+ for (var opt, j = 0; opt = opts[j]; j++) {
+ if (opt.value == deviceID) {
+ index = j;
+ break;
+ }
+ }
+ var allow = false
+ if (index!==false){
+ window.focus();
+ allow = confirm("Allow the director to change your video device to :"+opts[index].text+" ?");
+ }
+ if (allow){
+ document.getElementById("videoSource3").selectedIndex = j;
+ activatedPreview=false;
+ grabVideo(0, "videosource", "#videoSource3");
+ setTimeout(function(uuid){
+ var data = {};
+ data.UUID = uuid;
+ data.videoOptions = listVideoSettingsPrep();
+ sendMediaDevices(data.UUID);
+ session.sendMessage(data, data.UUID);
+ },1000, UUID);
+ }
+ });
+}
+
+function changeAudioDeviceById(deviceID, UUID){
+ var allow = false;
+ window.focus();
+ allow = confirm("Allow the director to change your audio mic source?");
+ if (allow){
+ enumerateDevices().then(gotDevices2).then(function() {
+ var audioSelect = document.getElementById("audioSource3").querySelectorAll("input");
+ for (var i = 0; i < audioSelect.length; i++) {
+ if (audioSelect[i].value == deviceID){
+ audioSelect[i].checked=true;
+ } else {
+ audioSelect[i].checked = false;
+ }
+ }
+ activatedPreview=false;
+ grabAudio("videosource", "#audioSource3");
+ setTimeout(function(uuid){
+ var data = {};
+ data.UUID = uuid;
+ data.audioOptions = listAudioSettingsPrep();
+ session.sendMessage(data, data.UUID);
+ },1000, UUID);
+ });
+ }
+}
+
+function changeAudioOutputDeviceById(deviceID, UUID){
+ errorlog(deviceID);
+ enumerateDevices().then(gotDevices2).then(function() {
+ if (!document.getElementById("outputSource3")){return;}
+ var opts = document.getElementById("outputSource3").options;
+ var index = false
+ for (var opt, j = 0; opt = opts[j]; j++) {
+ if (opt.value == deviceID) {
+ index = j;
+ break;
+ }
+ }
+ var allow = false
+ if (index!==false){
+ window.focus();
+ allow = confirm("Allow the director to change your audio's speaker to :"+opts[index].text+" ?");
+ }
+ if (allow){
+ document.getElementById("outputSource3").selectedIndex = j;
+ session.sink = document.getElementById("outputSource3").options[document.getElementById("outputSource3").selectedIndex].value;
+ resetupAudioOut();
+ setTimeout(function(uuid){
+ var data = {};
+ data.UUID = uuid;
+ data.videoOptions = listVideoSettingsPrep();
+ sendMediaDevices(data.UUID);
+ session.sendMessage(data, data.UUID);
+ },1000, UUID);
+ }
+ });
+}
+
+
+
+var getUserMediaRequestID = 0;
+var grabVideoUserMediaTimeout = null;
+var grabVideoTimer = null;
+
+async function grabVideo(quality = 0, eleName = 'previewWebcam', selector = "select#videoSourceSelect") {
+ if (activatedPreview == true) {
+ log("activated preview return 2");
+ return;
+ }
+ activatedPreview = true;
+ log("Grabbing video: " + quality);
+ if (grabVideoTimer) {
+ clearTimeout(grabVideoTimer);
+ }
+ log("element:" + eleName);
+
+ var wasDisabled = true;
+ try {
+ if (session.streamSrc) {
+
+ if (session.canvasSource){
+ session.canvasSource.srcObject.getTracks().forEach(function(trk) {
+ session.canvasSource.srcObject.removeTrack(trk);
+ wasDisabled=false;
+ });
+ }
+
+ if (session.videoElement.srcObject) {
+ session.videoElement.srcObject.getVideoTracks().forEach(function(track) {
+ session.videoElement.srcObject.removeTrack(track);
+ session.videoElement.load();
+ wasDisabled=false;
+ });
+ }
+ session.streamSrc.getVideoTracks().forEach(function(track) {
+ session.streamSrc.removeTrack(track);
+ track.stop();
+ log("track removed");
+ wasDisabled=false;
+ });
+
+ } else {
+ //log(session.videoElement.srcObject.getTracks());
+ session.streamSrc = new MediaStream();
+ session.videoElement.srcObject = session.streamSrc;
+ log("CREATE NEW STREAM");
+ }
+ } catch (e) {
+ errorlog(e);
+ }
+
+ session.videoElement.controls = false;
+
+ log("selector: " + selector);
+ var videoSelect = document.querySelector(selector); // document.querySelector("videoSource3").value == "ZZZ"
+ log(videoSelect);
+ var mirror = false;
+
+ if (!videoSelect || videoSelect.value == "ZZZ") { // if there is no video, or if manually set to audio ready, then do this step.
+ warnlog("ZZZ SET - so no VIDEO");
+ if ((eleName == "previewWebcam") && document.getElementById("previewWebcam")){
+ if (session.autostart) {
+ publishWebcam(); // no need to mirror as there is no video...
+ return;
+ } else {
+ log("4462");
+ updateStats();
+ var gowebcam = getById("gowebcam");
+ if (gowebcam) {
+ gowebcam.disabled = false;
+ gowebcam.dataset.ready = "true";
+ gowebcam.innerHTML = "START";
+ miniTranslate(gowebcam, "start");
+ }
+ }
+ } else { // If they disabled the video but not in preview mode; but actualy live. We will want to remove the stream from the publishing
+ // we don't want to do this otherwise, as we are "replacing" the track in other cases.
+ // this does cause a problem, as previous bitrate settings & resolutions might not be applied if switched back.... must test
+ for (UUID in session.pcs) {
+ var senders = session.pcs[UUID].getSenders(); // for any connected peer, update the video they have if connected with a video already.
+ 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 (sender.track && sender.track.kind == "video") {
+ sender.track.enabled = false;
+ getById("mutevideobutton").classList.add("advanced"); // hide the mute button, so they can't unmute while no video.
+ //session.pcs[UUID].removeTrack(sender); // replace may not be supported by all browsers. eek.
+ errorlog("DELETED SENDER");
+ }
+ });
+
+ }
+ var msg = {};
+ msg.videoMuted = true;
+ session.sendMessage(msg);
+ }
+ // end
+ } else {
+ var sq = 0;
+ if (session.quality === false) {
+ sq = session.quality_wb;
+ } else if (session.quality > 2) { // 1080, 720, and 360p
+ sq = 2; // hacking my own code. TODO: ugly, so I need to revisit this.
+ } else {
+ sq = session.quality;
+ }
+
+ if (session.director && (quality !== false)){ // URL-based quality won't matter if DIRECTOR;
+ // quality = quality;
+ } else if ((quality === false) || (quality < sq)) {
+ quality = sq; // override the user's setting
+ }
+
+
+ if ((iOS) || (iPad)) { // iOS will not work correctly at 1080p; likely a h264 codec issue.
+ if (quality == 0) {
+ quality = 1;
+ }
+ }
+
+ var constraints = {
+ audio: false,
+ video: getUserMediaVideoParams(quality, iOS)
+ };
+
+ log("Quality selected:" + quality);
+ var _, sUsrAg = navigator.userAgent;
+
+
+ if ((iOS) || (iPad)) {
+ constraints.video.deviceId = {
+ exact: videoSelect.value
+ }; // iPhone 6s compatible ? Needs to be exact for iPhone 6s
+
+ } else if (sUsrAg.indexOf("Firefox") > -1) {
+ constraints.video.deviceId = {
+ exact: videoSelect.value
+ }; // Firefox is a dick. Needs it to be exact.
+
+ } else if (videoSelect.options[videoSelect.selectedIndex].text.includes("NDI Video")) { // NDI does not like "EXACT"
+ constraints.video.deviceId = videoSelect.value;
+
+ } else {
+ constraints.video.deviceId = {
+ exact: videoSelect.value
+ }; // Default. Should work for Logitech, etc.
+ }
+
+ if (session.width) {
+ constraints.video.width = {
+ exact: session.width
+ }; // manually specified - so must be exact
+ }
+ if (session.height) {
+ constraints.video.height = {
+ exact: session.height
+ };
+ }
+ if (session.framerate) {
+ constraints.video.frameRate = {
+ exact: session.framerate
+ };
+ } else if (session.maxframerate != false){
+ constraints.video.frameRate = {
+ ideal: session.maxframerate,
+ max: session.maxframerate
+ };
+ }
+ if (session.ptz){
+ if (constraints.video && constraints.video!==true){
+ if (getChromeVersion() && getChromeVersion()>80){
+ constraints.video.pan=true;
+ constraints.video.tilt=true;
+ constraints.video.zoom=true;
+ }
+ }
+ }
+ var obscam = false;
+ log(videoSelect.options[videoSelect.selectedIndex].text);
+ if (videoSelect.options[videoSelect.selectedIndex].text.startsWith("OBS-Camera")) { // OBS Virtualcam
+ mirror = true;
+ obscam = true;
+ } else if (videoSelect.options[videoSelect.selectedIndex].text.startsWith("OBS Virtual Camera")) { // OBS Virtualcam
+ mirror = true;
+ obscam = true;
+ } else if (videoSelect.options[videoSelect.selectedIndex].text.includes(" back")) { // Android
+ mirror = true;
+ } else if (videoSelect.options[videoSelect.selectedIndex].text.includes(" rear")) { // Android
+ mirror = true;
+ } else if (videoSelect.options[videoSelect.selectedIndex].text.includes("NDI Video")) { // NDI Virtualcam
+ mirror = true;
+ } else if (videoSelect.options[videoSelect.selectedIndex].text.startsWith("Back Camera")) { // iPhone and iOS
+ mirror = true;
+ } else {
+ mirror = false;
+ }
+ session.mirrorExclude = mirror;
+
+ log(constraints);
+ clearTimeout(grabVideoUserMediaTimeout);
+ getUserMediaRequestID += 1;
+ grabVideoUserMediaTimeout = setTimeout(function(gumID) {
+ navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
+
+ if (getUserMediaRequestID !== gumID) {
+ errorlog("GET USER MEDIA CALL HAS EXPIRED");
+ return;
+ }
+ log("adding video tracks 2412");
+ stream.getVideoTracks().forEach(function(track) {
+ if (!session.streamSrc) {
+ session.streamSrc = new MediaStream();
+ }
+ if (!session.videoElement) {
+ if (document.getElementById("previewWebcam")) {
+ session.videoElement = document.getElementById("previewWebcam");
+ } else if (document.getElementById("videosource")) {
+ session.videoElement = document.getElementById("videosource");
+ }
+
+ }
+
+ if (session.effects) {
+ track = applyEffects(track,stream);
+ } else {
+ log(session.videoElement);
+ session.streamSrc.addTrack(track, stream); // add video track to the preview video
+ session.videoElement.srcObject.addTrack(track, stream); // add video track to the preview video
+ }
+
+ toggleVideoMute(true);
+ for (UUID in session.pcs) {
+ try {
+ if (((iOS) || (iPad)) && (session.pcs[UUID].guest == true)) {
+ warnlog("iOS and GUest detected");
+ } else 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;
+ session.pcs[UUID].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") {
+ sender.replaceTrack(track); // replace may not be supported by all browsers. eek.
+ sender.track.enabled = true;
+ added = true;
+ }
+
+ });
+ if (added == false) {
+ session.pcs[UUID].addTrack(track, stream); // can't replace, so adding
+ 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);
+ }
+ }
+
+ if (wasDisabled && !session.videoMuted){
+ var msg = {};
+ msg.videoMuted = session.videoMuted;
+ session.sendMessage(msg);
+ }
+
+ session.refreshScale();
+ });
+
+ applyMirror(mirror, eleName);
+
+ if ((eleName == "previewWebcam") && document.getElementById("previewWebcam")){
+ if (session.autostart) {
+ publishWebcam();
+ } else {
+ log("4620");
+ if (document.getElementById("gear_webcam")) {
+ updateStats(obscam);
+ }
+ var gowebcam = getById("gowebcam");
+ if (gowebcam) {
+ gowebcam.disabled = false;
+ gowebcam.dataset.ready = "true";
+ gowebcam.innerHTML = "START";
+ miniTranslate(gowebcam, "start");
+ }
+ }
+ } else if (getById("gear_webcam3").style.display === "inline-block") {
+ updateStats(obscam);
+ }
+
+ // Once crbug.com/711524 is fixed, we won't need to wait anymore. This is
+ // currently needed because capabilities can only be retrieved after the
+ // device starts streaming. This happens after and asynchronously w.r.t.
+ // getUserMedia() returns.
+ if (grabVideoTimer) {
+ clearTimeout(grabVideoTimer);
+ if ((eleName == "previewWebcam") && document.getElementById("previewWebcam")){
+ session.videoElement.controls = true;
+ }
+ }
+ if (getById("popupSelector_constraints_video")) {
+ getById("popupSelector_constraints_video").innerHTML = "";
+ }
+ if (getById("popupSelector_constraints_audio")) {
+ getById("popupSelector_constraints_audio").innerHTML = "";
+ }
+ if (getById("popupSelector_constraints_loading")) {
+ getById("popupSelector_constraints_loading").style.display = "";
+ }
+
+ grabVideoTimer = setTimeout(function() {
+ if (getById("popupSelector_constraints_loading")) {
+ getById("popupSelector_constraints_loading").style.display = "none";
+ }
+ if ((eleName == "previewWebcam") && document.getElementById("previewWebcam")){
+ session.videoElement.controls = true;
+ } else {
+ updateConstraintSliders();
+ }
+
+ dragElement(session.videoElement);
+ }, 1000); // focus
+
+ makeImages(true);
+
+ log("DONE - found stream");
+ }).catch(function(e) {
+ activatedPreview = false;
+ warnlog(e);
+ if (e.name === "OverconstrainedError") {
+ warnlog(e.message);
+ log("Resolution or framerate didn't work");
+ } else if (e.name === "NotReadableError") {
+ if (quality <= 10) {
+ grabVideo(quality + 1, eleName, selector);
+ } else {
+ if (!(session.cleanOutput)) {
+ if (iOS) {
+ warnUser("An error occured. Closing existing tabs in Safari may solve this issue.");
+ } else {
+ warnUser("Error: Could not start video source.\n\nTypically this means the Camera is already be in use elsewhere. Most webcams can only be accessed by one program at a time.\n\nTry a different camera or perhaps try re-plugging in the device.");
+ }
+ }
+ activatedPreview = true;
+ if (getById('gowebcam')) {
+ getById('gowebcam').innerHTML = "Problem with Camera";
+ }
+
+ }
+ return;
+ } else if (e.name === "NavigatorUserMediaError") {
+ if (getById('gowebcam')) {
+ getById('gowebcam').innerHTML = "Problem with Camera";
+ }
+ if (!(session.cleanOutput)) {
+ warnUser("Unknown error: 'NavigatorUserMediaError'");
+ }
+ return;
+ } else if (e.name === "timedOut") {
+ activatedPreview = true;
+ if (getById('gowebcam')) {
+ getById('gowebcam').innerHTML = "Problem with Camera";
+ }
+ if (!(session.cleanOutput)) {
+ warnUser(e.message);
+ }
+ return;
+ } else {
+ errorlog("An unknown camera error occured");
+ }
+
+ if (quality <= 10) {
+ grabVideo(quality + 1, eleName, selector);
+ } else {
+ errorlog("********Camera failed to work");
+ activatedPreview = true;
+ if (getById('gowebcam')) {
+ getById('gowebcam').innerHTML = "Problem with Camera";
+ }
+ if (!(session.cleanOutput)) {
+ if (session.width || session.height || session.framerate) {
+ warnUser(" Camera failed to load.\n\nPlease ensure your camera supports the resolution and framerate that has been manually specified. Perhaps use &quality=0 instead.");
+ } else {
+ warnUser(" Camera failed to load.\n\nPlease make sure it is not already in use by another application.\n\nPlease make sure you have accepted the camera permissions.");
+ }
+ }
+ }
+ });
+ }, 100, getUserMediaRequestID);
+ }
+}
+
+
+async function grabAudio(eleName = "previewWebcam", selector = "#audioSource", trackid = null, override = false) { // trackid is the excluded track
+ if (activatedPreview == true) {
+ log("activated preview return 2");
+ return;
+ }
+ activatedPreview = true;
+ warnlog("GRABBING AUDIO");
+ log("TRACK EXCLUDED:" + trackid);
+
+
+ try {
+ if (session.videoElement.srcObject) {
+ var audioSelect = document.querySelector(selector).querySelectorAll("input");
+ var audioExcludeList = [];
+ for (var i = 0; i < audioSelect.length; i++) {
+ try {
+ if ("screen" == audioSelect[i].dataset.type) { // skip already excluded ---------- !!!!!! DOES THIS MAKE SENSE? TODO: CHECK
+ if (audioSelect[i].checked) {
+ audioExcludeList.push(audioSelect[i]);
+ }
+ }
+ } catch (e) {
+ errorlog(e);
+ }
+ }
+
+ session.videoElement.srcObject.getAudioTracks().forEach(function(track) {
+ for (var i = 0; i < audioExcludeList.length; i++) {
+ try {
+ if (audioExcludeList[i].label == track.label) {
+ warnlog("DONE");
+ return;
+ }
+ } catch (e) {}
+ }
+ if (trackid && (track.id == trackid)) {
+ warnlog("SKIPPED EXCLUDED TRACK?");
+ return;
+ }
+ session.videoElement.srcObject.removeTrack(track);
+ track.stop();
+ });
+
+ session.streamSrc.getAudioTracks().forEach(function(track) {
+ for (var i = 0; i < audioExcludeList.length; i++) {
+ try {
+ if (audioExcludeList[i].label == track.label) {
+ warnlog("EXCLUDING TRACK; PROBABLY SCREEN SHARE");
+ return;
+ }
+ } catch (e) {}
+ }
+ if (trackid && (track.id == trackid)) {
+ warnlog("SKIPPED EXCLUDED TRACK?");
+ return;
+ }
+ session.streamSrc.removeTrack(track);
+ track.stop();
+ });
+
+
+ } else { // if no stream exists
+ session.streamSrc = new MediaStream();
+ session.videoElement.srcObject = session.streamSrc;
+ log("CREATE NEW SOURCE FOR AUDIO");
+ }
+ } catch (e) {
+ errorlog(e);
+ }
+
+ var streams = await getAudioOnly(selector, trackid, override); // Get audio streams
+ warnlog(streams);
+ try {
+ for (var i = 0; i < streams.length; i++) {
+ streams[i].getAudioTracks().forEach(function(track) {
+ session.streamSrc.addTrack(track, streams[i]); // add video track to the preview video
+ });
+ }
+
+ session.videoElement.srcObject = outboundAudioPipeline(session.streamSrc);
+
+ toggleMute(true);
+ if (session.videoElement.srcObject.getAudioTracks()) {
+
+ for (UUID in session.pcs) {
+ if (session.pcs[UUID].allowAudio == true) {
+ var tracks = session.videoElement.srcObject.getAudioTracks();
+
+ session.pcs[UUID].getSenders().forEach((sender) => {
+ var good = false;
+ if (sender.track && sender.track.id && (sender.track.kind == "audio")) {
+ tracks.forEach(function(track) {
+ if (track.id == sender.track.id) {
+ good = true;
+ }
+ });
+ } else { // video or something else; ignore it.
+ return;
+ }
+ if (good) {
+ return;
+ }
+ sender.track.enabled = false;
+ //session.pcs[UUID].removeTrack(sender); // Apparently removeTrack causes renogiation; also kills send/recv.
+ });
+
+ if (tracks.length) {
+ tracks.forEach(function(track) {
+ var matched = false;
+ session.pcs[UUID].getSenders().forEach((sender) => {
+ if (sender.track && sender.track.id && (sender.track.kind !== "video")) {
+ warnlog(sender.track.id + " " + track.id);
+ if (sender.track.id == track.id) {
+ warnlog("MATCHED 1");
+ matched = true;
+ }
+ }
+ });
+ if (matched) {
+ return;
+ }
+ var added = false;
+ session.pcs[UUID].getSenders().forEach((sender) => {
+ if (added) {
+ return;
+ }
+ if (sender.track && (sender.track.enabled == false)) {
+ sender.replaceTrack(track);
+ sender.track.enabled = true;
+ added = true;
+ warnlog("ADDED 2");
+ }
+ });
+ if (added) {
+ return;
+ }
+ var sender = session.pcs[UUID].addTrack(track, session.videoElement.srcObject);
+ });
+ } else {
+ session.pcs[UUID].getSenders().forEach((sender) => {
+ if (sender.track && sender.track.kind == "audio") {
+ sender.track.enabled = false; // (trying this instead)
+ //session.pcs[UUID].removeTrack(sender); // Apparently removeTrack causes renogiation; also kills send/recv.
+ }
+ });
+ }
+
+ }
+ }
+ }
+ } catch (e) {
+ errorlog(e);
+ }
+ var gowebcam = getById("gowebcam");
+ if (gowebcam) {
+ gowebcam.disabled = false;
+ gowebcam.dataset.ready = "true";
+ gowebcam.innerHTML = "START";
+ miniTranslate(gowebcam, "start");
+ }
+}
+
+
+// WEBCAM
+session.publishDirector = async function(clean, vdevice=false, adevice=true){ // stream is used to generated an SDP
+ log("DIRECTOR STREAM SETUP");
+
+ if (getById("press2talk").dataset.enabled){log("already enabled");return;}
+ getById("press2talk").dataset.enabled = 1;
+
+ if (session.streamSrc){
+ //if (!session.streamSrc){
+ // session.streamSrc = new MediaStream();
+ //}
+ if (document.getElementById("videosource")){
+ var v = document.getElementById("videosource");
+ v.muted = true;
+ v.autoplay = true;
+ v.controls = false;
+ v.setAttribute("playsinline","");
+ session.videoElement = v;
+ } else if (session.videoElement){
+ var v = session.videoElement;
+ v.muted = true;
+ v.autoplay = true;
+ v.controls = false;
+ v.setAttribute("playsinline","");
+ getById("miniPerformer").appendChild(v);
+ } else {
+ var v = document.createElement("video");
+ session.videoElement = v;
+ v.muted = true;
+ v.autoplay = true;
+ v.controls = false;
+ v.setAttribute("playsinline","");
+ getById("miniPerformer").appendChild(v);
+ }
+
+ if (session.streamID){
+ session.videoElement.dataset.sid = session.streamID;
+ }
+
+ v.title = "This is the mini-preview of the Director's audio and video output. The director cannot be muted by guest and does not show up in scenes.";
+ getById("press2talk").innerHTML = "";
+ getById("press2talk").outerHTML = "";
+
+ session.muted = false;
+ toggleMute(true);
+ getById("screensharebutton").classList.remove("advanced");
+ getById("hangupbutton2").classList.remove("advanced");
+
+
+ v.muted = true;
+ v.autoplay = true;
+ v.controls = false;
+ v.setAttribute("playsinline","");
+ v.srcObject = session.streamSrc; // blank, no worries.
+
+ if (session.screenShareState) {
+ log("can't refresh a screenshare");
+ getById("screensharebutton").classList.add("float2");
+ getById("screensharebutton").classList.remove("float");
+ session.screenShareState = false;
+ }
+
+
+ activatedPreview = false;
+ await grabAudio("videosource", "#audioSource3");
+
+
+ enumerateDevices().then(gotDevices2).then(function() {
+ activatedPreview = false;
+ grabVideo(session.quality, "videosource", "select#videoSource3");
+ });
+
+ toggleSettings(true);
+
+ var msg = {};
+ msg.videoMuted = session.videoMuted;
+ session.sendMessage(msg);
+
+ return;
+ }
+
+
+ var title = "Director";
+ var v = document.createElement("video");
+ session.videoElement = v;
+ if (session.streamID){
+ session.videoElement.dataset.sid = session.streamID;
+ }
+ v.id = "videosource"; // could be set to UUID in the future
+ v.muted = true;
+ v.autoplay = true;
+ v.controls = false;
+ v.setAttribute("playsinline","");
+
+ session.streamSrc = new MediaStream();
+ v.srcObject = session.streamSrc; // blank, no worries. we dont need outbound.
+
+ //createDirectorCam(v,clean);
+
+ var quality = 1;
+ var framerate = 30;
+
+
+ if (session.quality!==false){
+ quality = parseInt(session.quality) || 0;
+ if (quality>2){quality=2;} else if (quality<0){quality = 0;}
+ }
+
+ if (session.showDirector){
+ if (quality<2){
+ framerate = 60;
+ }
+ }
+
+ if (session.framerate!==false){
+ framerate = parseInt(session.framerate) || 30;
+ }
+
+ if (session.maxframerate){
+ if (framerate > session.maxframerate){
+ framerate = session.maxframerate || framerate;
+ }
+ }
+
+ if (vdevice){
+ if (vdevice===true){
+ vdevice = {};
+ }
+ if (quality===0){
+ vdevice.width = {ideal:1920}; //{deviceId: {exact: deviceInfo.deviceId}};
+ vdevice.height = {ideal:1080};
+ vdevice.framerate = {ideal:framerate};
+ } else if (quality===1){
+ vdevice.width = {ideal:1280}; //{deviceId: {exact: deviceInfo.deviceId}};
+ vdevice.height = {ideal:720};
+ vdevice.framerate = {ideal:framerate};
+ } else if (quality===2){
+ vdevice.width = {ideal:640}; //{deviceId: {exact: deviceInfo.deviceId}};
+ vdevice.height = {ideal:360};
+ vdevice.framerate = {ideal:framerate};
+ }
+ if (session.framerate){
+ vdevice.framerate.ideal = parseInt(session.framerate) || 30;
+ }
+ if (session.maxframerate){
+ vdevice.framerate.max = parseInt(session.maxframerate) || 60;
+ }
+ if (session.width){
+ vdevice.width = {exact: session.width}; //{deviceId: {exact: deviceInfo.deviceId}};
+ }
+ if (session.height){
+ vdevice.height = {exact: session.height}; //{deviceId: {exact: deviceInfo.deviceId}};
+ }
+ }
+
+ var constraints = {audio: adevice, video: vdevice};
+
+ if (session.audioInputChannels){
+ if (constraints.audio === true){
+ constraints.audio = {};
+ constraints.audio.channelCount = session.audioInputChannels;
+ } else if (constraints.audio){
+ constraints.audio.channelCount = session.audioInputChannels;
+ }
+ }
+
+ //if (session.echoCancellation===false){
+ if (constraints.audio === true){
+ constraints.audio = {};
+ }
+ if (constraints.audio){
+ if (session.echoCancellation===false || session.autoGainControl===false || session.noiseSuppression===false){
+ if (session.echoCancellation===false){
+ constraints.audio.echoCancellation=false;
+ } else {
+ constraints.audio.echoCancellation=true;
+ }
+ if (session.autoGainControl===false){
+ constraints.audio.autoGainControl=false;
+ } else {
+ constraints.audio.autoGainControl=true;
+ }
+ if (session.noiseSuppression===false){
+ constraints.audio.noiseSuppression=false;
+ } else {
+ constraints.audio.noiseSuppression=true;
+ }
+ }
+ }
+
+
+ try {
+ getById("webcamquality3").elements.namedItem("resolution").value = quality;
+ getById("gear_webcam3").style.display = "inline-block";
+ getById("webcamquality3").onchange = function(event) {
+ if (parseInt(getById("webcamquality3").elements.namedItem("resolution").value) == 2) {
+ if (session.maxframerate===false){
+ session.maxframerate = 30;
+ session.maxframerate_q2 = true;
+ }
+ } else if (session.maxframerate_q2){
+ session.maxframerate = false;
+ session.maxframerate_q2 = false;
+ }
+ activatedPreview = false;
+ session.quality_wb = parseInt(getById("webcamquality3").elements.namedItem("resolution").value);
+
+ grabVideo(session.quality_wb, "videosource", "select#videoSource3");
+ };
+ } catch (e) {}
+
+ log("constraint");
+ navigator.mediaDevices.getUserMedia(constraints).then(function(stream){ // very simple.
+ session.streamSrc = stream;
+ v.srcObject = outboundAudioPipeline(session.streamSrc); // not blank, so now we worry
+
+ for (UUID in session.pcs){
+ session.initialPublish(UUID); // Start publishing!
+ }
+ enumerateDevices().then(gotDevices2).then(function(){});
+ createDirectorCam(v, clean);
+ });
+
+
+ changeAudioOutputDevice(v);
+
+ v.onpause = (event) => { // prevent things from pausing; human or other
+ if (!((event.ctrlKey) || (event.metaKey) )){
+ log("Video paused; auto playing");
+ event.currentTarget.play().then(_ => {
+ log("playing");
+ }).catch(warnlog);
+ }
+ };
+
+ v.addEventListener('click', function(e) { // show stats of video if double clicked
+ log("click");
+ try {
+ if ((e.ctrlKey)||(e.metaKey)){
+ e.preventDefault();
+
+ ////////////////////////
+
+ var [menu, innerMenu] = statsMenuCreator();
+
+ //////////////////////////////////
+
+ menu.interval = setInterval(printMyStats,3000, innerMenu);
+ printMyStats(innerMenu);
+ e.stopPropagation();
+
+ return false;
+ }
+ } catch(e){errorlog(e);}
+ });
+
+ if (session.directorEnabledPPT){
+ return;
+ }
+
+ if (session.videoMutedFlag){
+ session.videoMuted = true;
+ toggleVideoMute(true);
+ }
+
+ session.title=title;
+ session.directorEnabledPPT = true;
+
+
+ if (session.seeding){
+ return;
+ }
+
+ session.seeding=true;
+ session.seedStream();
+
+};
+
+function statsMenuCreator(){
+
+ if (getById("menuStatsBox")){
+ clearInterval(getById("menuStatsBox").interval);
+ getById("menuStatsBox").remove();
+ }
+
+ var menu = document.createElement("div");
+ menu.id = "menuStatsBox";
+ menu.className = "debugStats remotestats";
+ getById('main').appendChild(menu);
+
+ menu.style.left = parseInt(Math.random()*10)+15+"px"
+ menu.style.top = parseInt(Math.random()*10)+"px"
+
+ menu.innerHTML="Statistics ";
+ var menuCloseBtn = document.createElement("button");
+ menuCloseBtn.className="close";
+ menuCloseBtn.innerHTML="×";
+ menu.appendChild(menuCloseBtn);
+
+ var innerMenu = document.createElement("div");
+ menu.appendChild(innerMenu);
+
+ menuCloseBtn.addEventListener('click', function(eve) {
+ clearInterval(menu.interval);
+ eve.currentTarget.parentNode.remove();
+ });
+ return [menu, innerMenu];
+}
+
+
+// WEBCAM
+session.publishStream = function(v, title="Stream Sharing Session"){ // stream is used to generated an SDP
+ log("STREAM SETUP");
+
+ try {
+ //session.streamSrc = v.srcObject; // this shoulnd't be needed
+ v.parentNode.removeChild(v); // remove the preview video element after we switch streams to avoid bug on iOS beta 14
+ v.className = "";
+ } catch (e){
+ errorlog(e);
+ return;
+ }
+
+ if (session.transcript){
+ setTimeout(function(){setupClosedCaptions();},0);
+ }
+
+ toggleMute(true); // apply mute state
+
+ if (!session.streamSrc){
+ log("no stream selected");
+ session.streamSrc = new MediaStream(); // this is just for backup.
+ }
+
+ session.streamSrc.oninactive = function streamoninactive() {
+ errorlog('Stream inactive');
+ if (session.videoElement.recording){
+ session.videoElement.recorder.stop();
+ }
+ };
+
+ if (session.streamSrc.getVideoTracks().length==0){
+ warnlog("NO VIDEO TRACK INCLUDED");
+ }
+
+ if (session.streamSrc.getAudioTracks().length==0){
+ warnlog("NO AUDIO TRACK INCLUDED");
+ }
+
+
+ var container = document.createElement("div");
+ container.id = "container";
+
+ if (session.cleanOutput){
+ container.style.height = "100%";
+ v.style.maxWidth = "100%";
+ v.style.boxShadow = "none";
+ }
+
+ container.className = "vidcon";
+ getById("gridlayout").appendChild(container);
+
+ v.className = "tile";
+
+ v.muted = true;
+ v.autoplay = true;
+ v.controls = false;
+ v.setAttribute("playsinline","");
+ v.id = "videosource"; // could be set to UUID in the future
+ v.oncanplay = null;
+ container.appendChild(v);
+
+ if (session.nopreview){
+ v.style.display="none";
+ container.style.display="none";
+ }
+
+ changeAudioOutputDevice(v);
+
+ if (session.mirrored && session.flipped){
+ v.style.transform = "scaleX(1) scaleY(-1) ";
+ } else if (session.mirrored){
+ v.style.transform = "scaleX(1) ";
+ } else if (session.flipped){
+ v.style.transform = "scaleY(-1) scaleX(-1)";
+ } else {
+ v.style.transform = "scaleX(-1) ";
+ }
+
+ var bigPlayButton = document.getElementById("bigPlayButton");
+ if (bigPlayButton){
+ bigPlayButton.parentNode.removeChild(bigPlayButton);
+ }
+
+ session.videoElement = v;
+
+ if (session.streamID){
+ session.videoElement.dataset.sid = session.streamID;
+ }
+
+ if (session.director){
+ // audio is not mucked with
+ } else if (session.scene!==false){
+ setTimeout(function(){updateMixer();},1);
+ } else if (session.roomid!==false){
+ if (session.roomid===""){
+ if (!(session.view) || (session.view==="")){
+
+
+ if (session.fullscreen){
+ session.windowed = false;
+ } else {
+ v.className = "myVideo";
+ session.windowed = true;
+ }
+ getById("mutespeakerbutton").classList.add("advanced");
+
+ applyMirror(session.mirrorExclude, 'videosource');
+
+ container.style.width="100%";
+ //container.style.height="100%";
+
+ container.style.alignItems = "center";
+ container.backgroundColor = "#666";
+
+ setTimeout(function (){dragElement(v);},1000);
+ play();
+ } else {
+ session.windowed = false;
+ applyMirror(session.mirrorExclude, 'videosource');
+ play();
+ setTimeout(function(){updateMixer();},1);
+ }
+ } else {
+ //session.cbr=0; // we're just going to override it
+ if (session.stereo==5){ // not a scene or director, so we will assume its a guest. changing to stereo=3
+ session.stereo=3;
+ }
+ session.windowed = false;
+ applyMirror(session.mirrorExclude, 'videosource');
+
+ setTimeout(function(){updateMixer();},1);
+ }
+ } else {
+
+
+ if (session.fullscreen){
+ session.windowed = false;
+ } else {
+ v.className = "myVideo";
+ session.windowed = true;
+ }
+ getById("mutespeakerbutton").classList.add("advanced");
+
+ applyMirror(session.mirrorExclude, 'videosource');
+
+ container.style.width="100%";
+ //container.style.height="100%";
+ //container.style.display = "flex";
+
+ container.style.alignItems = "center";
+ container.backgroundColor = "#666";
+
+ setTimeout(function (){dragElement(v);},1000);
+
+ }
+
+ v.onpause = (event) => { // prevent things from pausing; human or other
+ if (!((event.ctrlKey) || (event.metaKey) )){
+ log("Video paused; auto playing");
+ event.currentTarget.play().then(_ => {
+ log("playing");
+ }).catch(warnlog);
+ }
+ };
+
+ v.addEventListener('click', function(e) {
+ log("click");
+ try {
+ if ((e.ctrlKey)||(e.metaKey)){
+ e.preventDefault();
+
+ var [menu, innerMenu] = statsMenuCreator();
+
+ menu.interval = setInterval(printMyStats,3000, innerMenu);
+
+ printMyStats(innerMenu);
+ e.stopPropagation();
+ return false;
+ }
+ } catch(e){errorlog(e);}
+ });
+
+ v.touchTimeOut = null;
+ v.touchLastTap = 0;
+ v.touchCount = 0;
+ v.addEventListener('touchend', function(event) {
+ log("touched");
+
+ document.ontouchup = null;
+ document.onmouseup = null;
+ document.onmousemove = null;
+ document.ontouchmove = null;
+
+ var currentTime = new Date().getTime();
+ var tapLength = currentTime - v.touchLastTap;
+ clearTimeout(v.touchTimeOut);
+ if (tapLength < 500 && tapLength > 0) {
+ ///
+ log("double touched");
+ v.touchCount+=1;
+ event.preventDefault();
+ if (v.touchCount<5){
+ v.touchLastTap = currentTime;
+ return false;
+ }
+ v.touchLastTap = 0;
+ v.touchCount=0;
+
+ var [menu, innerMenu] = statsMenuCreator();
+
+ menu.interval = setInterval(printMyStats,3000, innerMenu);
+
+ printMyStats(innerMenu);
+ event.stopPropagation();
+ return false;
+ //////
+ } else {
+ v.touchCount=1;
+ v.touchLastTap = currentTime;
+
+ v.touchTimeOut = setTimeout(function(vv) {
+ clearTimeout(vv.touchTimeOut);
+ vv.touchLastTap = 0;
+ vv.touchCount=0;
+ }, 5000, v);
+
+ }
+
+ });
+
+ try{
+ var m = getById("mainmenu");
+ m.remove();
+ } catch (e){}
+
+ var added = "";
+ if (session.defaultPassword===false){
+ if (session.password){
+ added="&pw="+session.password;
+ }
+ }
+
+ var pie = "";
+ if (session.pie){
+ if (session.pie!==true){
+ pie = "&pie="+session.pie;
+ }
+ }
+
+ getById("reshare").href = "https://"+location.host+location.pathname+"?view="+session.streamID+added+pie;
+ getById("reshare").text = "https://"+location.host+location.pathname+"?view="+session.streamID+added+pie;
+ getById("reshare").style.width = ((getById("reshare").text.length + 1)*1.15 * 8) + 'px';
+ pokeIframeAPI('started-camera');
+
+
+
+ if (session.videoMutedFlag){
+ session.videoMuted = true;
+ toggleVideoMute(true);
+ }
+
+ clearInterval(session.updateLocalStatsInterval);
+ session.updateLocalStatsInterval = setInterval(function(){updateLocalStats();},3000);
+
+ session.title=title;
+ session.seeding=true;
+ session.seedStream();
+
+};
+
+
+session.publishScreen = function(constraints, title="Screen Sharing Session", audioList=[], audio=true){ // webcam stream is used to generated an SDP
+ log("SCREEN SHARE SETUP");
+ if (!navigator.mediaDevices.getDisplayMedia){
+ setTimeout(function(){warnUser("Sorry, your browser is not supported. Please use the desktop versions of Firefox or Chrome instead");},1);
+ return false;
+ }
+ if (navigator.userAgent.toLowerCase().indexOf(' electron/') > -1) {
+ if (!ElectronDesktopCapture){
+ if (!(session.cleanOutput && session.cleanish==false)){
+ warnUser("Your Electron app does not support Screen Capture. Update your Electron Capture app and then enable Elevated Privileges to access screen-sharing.");
+ }
+ return false;
+ }
+ }
+
+ var streams = [];
+ for (var i=1; i{
+ streams.push(stream);
+ }).catch(errorlog);
+ }
+ }
+
+ if (session.audioDevice === 0 ){
+ constraints.audio = false;
+ }
+
+ log(constraints);
+ return navigator.mediaDevices.getDisplayMedia(constraints).then(function (stream){
+ /// RETURN stream for preview? rather than jumping right in.
+ session.screenShareState=true;
+ try {
+ stream.getVideoTracks()[0].onended = function () {
+ session.screenShareState=false;
+ pokeIframeAPI("screen-share-ended");
+ grabScreen();
+ };
+ } catch(e){log("No Video selected; screensharing?");}
+
+ // OR, jump right in, and let user change from there
+ if (session.roomid!==false){
+ if ((session.roomid==="") && ((!(session.view)) || (session.view===""))){
+
+ } else {
+ getById("head3").className = 'advanced';
+
+ log("ROOMID EANBLED");
+ log("Update Mixer Event on REsize SET");
+ window.addEventListener("resize", updateMixer);
+ window.addEventListener("orientationchange", updateMixer);
+ joinRoom(session.roomid);
+ }
+
+ } else {
+ getById("head3").className = '';
+ getById("logoname").style.display = 'none';
+ }
+
+ if (urlParams.has('permaid')){
+ updateURL("permaid="+session.streamID);
+ } else {
+ updateURL("push="+session.streamID);
+ }
+
+ log("adding tracks");
+ for (var i=0; i{
+ stream.addTrack(track);
+ });
+ }
+ streams = null;
+ if (session.audioDevice !== 0){
+ if (stream.getAudioTracks().length==0){
+ if (!(session.cleanOutput)){
+ if (navigator.userAgent.toLowerCase().indexOf(' electron/') > -1){
+ // Electron has no audio.
+ } else {
+ setTimeout(function(){warnUser("No Audio Source was detected.\n\nIf you were wanting to capture an Application's Audio, please see:\nhttps://docs.obs.ninja/help/guides-and-how-tos#audio for some guides.");},300);
+ }
+ }
+ }
+ }
+
+
+
+ try {
+ session.streamSrc = stream;
+ } catch (e){errorlog(e);}
+
+ toggleMute(true);
+
+ var v = document.createElement("video");
+
+ session.videoElement = v;
+
+
+ if (session.streamID){
+ session.videoElement.dataset.sid = session.streamID;
+ }
+
+
+ var container = document.createElement("div");
+ container.id = "container";
+
+ if (session.cleanOutput){
+ container.style.height = "100%";
+ v.style.maxWidth = "100%";
+ v.style.boxShadow = "none";
+ }
+
+ container.className = "vidcon";
+ getById("gridlayout").appendChild(container);
+
+ if (session.nopreview){
+ v.style.display="none";
+ container.style.display="none";
+ }
+
+ container.appendChild(v);
+
+
+ v.className = "tile";
+
+ changeAudioOutputDevice(v);
+
+ if (session.director){
+ } else if (session.scene!==false){
+ setTimeout(function(){updateMixer();},1);
+ } else if (session.roomid!==false){
+ if (session.roomid===""){
+ if (!(session.view) || (session.view==="")){
+
+ if (session.fullscreen){
+ session.windowed = false;
+ } else {
+ v.className = "myVideo";
+ session.windowed = true;
+ }
+ getById("mutespeakerbutton").classList.add("advanced");
+
+ if (session.mirrored && session.flipped){
+ v.style.transform = " scaleX(-1) scaleY(-1) translate(0, 50%)";
+ v.classList.add("mirrorControl");
+ } else if (session.mirrored){
+ v.style.transform = "scaleX(-1) translate(0, -50%)";
+ v.classList.add("mirrorControl");
+ } else if (session.flipped){
+ v.style.transform = "scaleY(-1) translate(0, 50%)";
+ v.classList.remove("mirrorControl");
+ } else {
+ v.style.transform = " translate(0, -50%)";
+ v.classList.remove("mirrorControl");
+ }
+
+ container.style.width="100%";
+ //container.style.height="100%";
+ container.style.alignItems = "center";
+ container.backgroundColor = "#666";
+
+ setTimeout(function (){dragElement(v);},1000);
+ play();
+ } else {
+ play();
+ setTimeout(function(){updateMixer();},1);
+ }
+ } else {
+ setTimeout(function(){updateMixer();},1);
+ }
+ } else {
+
+ if (session.fullscreen){
+ session.windowed = false;
+ } else {
+ v.className = "myVideo";
+ session.windowed = true;
+ }
+ getById("mutespeakerbutton").classList.add("advanced");
+
+ if (session.mirrored && session.flipped){
+ v.style.transform = " scaleX(-1) scaleY(-1) translate(0, 50%)";
+ v.classList.add("mirrorControl");
+ } else if (session.mirrored){
+ v.style.transform = "scaleX(-1) translate(0, -50%)";
+ v.classList.add("mirrorControl");
+ } else if (session.flipped){
+ v.style.transform = "scaleY(-1) translate(0, 50%)";
+ v.classList.remove("mirrorControl");
+ } else {
+ v.style.transform = " translate(0, -50%)";
+ v.classList.remove("mirrorControl");
+ }
+
+ container.style.width="100%";
+ //container.style.height="100%";
+ container.style.alignItems = "center";
+ container.backgroundColor = "#666";
+ }
+
+ v.autoplay = true;
+ v.controls = false;
+ v.setAttribute("playsinline","");
+ v.muted = true;
+ v.id = "videosource";
+
+ //if (!v.srcObject || v.srcObject.id !== stream.id) {
+ // v.srcObject = stream;
+ v.srcObject = outboundAudioPipeline(session.streamSrc);
+ //}
+
+ v.onpause = (event) => { // prevent things from pausing; human or other
+ if (!((event.ctrlKey) || (event.metaKey) )){
+ log("Video paused; auto playing");
+ event.currentTarget.play().then(_ => {
+ log("playing");
+ }).catch(warnlog);
+ }
+ };
+
+ v.addEventListener('click', function(e) { // show stats of video if double clicked
+ log("click");
+ try {
+ if ((e.ctrlKey)||(e.metaKey)){
+ e.preventDefault();
+
+ var [menu, innerMenu] = statsMenuCreator();
+
+ menu.interval = setInterval(printMyStats,3000, innerMenu);
+
+ printMyStats(innerMenu);
+ e.stopPropagation();
+ return false;
+ }
+ } catch(e){errorlog(e);}
+ });
+
+ try{
+ var m = getById("mainmenu");
+ m.remove();
+ } catch (e){}
+
+ var pie = "";
+ if (session.pie){
+ if (session.pie!==true){
+ pie = "&pie="+session.pie;
+ }
+ }
+
+ getById("reshare").href = "https://"+location.host+location.pathname+"?view="+session.streamID+pie;
+ getById("reshare").text = "https://"+location.host+location.pathname+"?view="+session.streamID+pie;
+ getById("reshare").style.width = ((getById("reshare").text.length + 1)*1.15 * 8) + 'px';
+
+
+ if (session.videoMutedFlag){
+ session.videoMuted = true;
+ toggleVideoMute(true);
+ }
+
+ clearInterval(session.updateLocalStatsInterval);
+ session.updateLocalStatsInterval = setInterval(function(){updateLocalStats();},3000);
+
+ session.title=title;
+ session.seeding=true;
+ session.seedStream();
+
+ pokeIframeAPI('started-screenshare');
+
+ return true;
+ }).catch(function(err){
+ warnlog(err); /* handle the error */
+ if (navigator.userAgent.toLowerCase().indexOf(' electron/') > -1) {
+ if (!ElectronDesktopCapture){
+ if (!(session.cleanOutput)) {
+ warnUser("Your Electron app does not support Screen Capture. Update your Electron Capture app and then enable Elevated Privileges to access screen-sharing.");
+ }
+ return false;
+ }
+ }
+ if ((err.name == "NotAllowedError") || (err.name == "PermissionDeniedError")){
+ // User Stopped it.
+ session.screenShareState=false;
+ pokeIframeAPI("screen-share-ended");
+ return false;
+ } else {
+ if (audio==true){
+ constraints.audio=false;
+ if (!(session.cleanOutput)){
+ setTimeout(function(){warnUser(err);},1); // TypeError: Failed to execute 'getDisplayMedia' on 'MediaDevices': Audio capture is not supported
+ }
+ return session.publishScreen(constraints, title, audioList, false);
+ } else {
+ if (!(session.cleanOutput)){
+ setTimeout(function(){warnUser(err);},1); // TypeError: Failed to execute 'getDisplayMedia' on 'MediaDevices': Audio capture is not supported
+ }
+ return false;
+ }
+
+ }
+ });
+
+};
+
+session.publishFile = function(ele, event, title="Video File Sharing Session"){ // webcam stream is used to generated an SDP
+ log("FILE SHARE SETUP");
+
+ if (session.transcript){
+ setTimeout(function(){setupClosedCaptions();},0);
+ }
+
+ var files = [];
+ for (var i = 0; i < ele.files.length; i++){ // changing from a FileList to an Array. Arrays are easier to modify later on
+ files.push(ele.files[i]);
+ }
+ log(files);
+ //var type = file.type;
+
+ var fileURL = URL.createObjectURL(files[0]);
+ var container = document.createElement("div");
+ container.id = "container";
+
+
+
+ container.className = "vidcon";
+ var v = document.createElement("video");
+
+ if (session.cleanOutput){
+ container.style.height = "100%";
+ v.style.maxWidth = "100%";
+ v.style.boxShadow = "none";
+ }
+
+ if (session.streamID){
+ v.dataset.sid = session.streamID;
+ }
+
+ getById("gridlayout").appendChild(container);
+
+ if (session.roomid!==false){
+ if ((session.roomid==="") && ((!(session.view)) || (session.view===""))){
+
+ } else {
+ log("ROOMID EANBLED");
+ log("Update Mixer Event on REsize SET");
+ window.addEventListener("resize", updateMixer);
+ window.addEventListener("orientationchange", updateMixer);
+ getById("head3").className = 'advanced';
+
+ joinRoom(session.roomid);
+ }
+
+ } else {
+ getById("head3").className = '';
+ getById("logoname").style.display = 'none';
+ }
+ getById("head1").className = 'advanced';
+
+ if (urlParams.has('permaid')){
+ updateURL("permaid="+session.streamID);
+ } else {
+ updateURL("push="+session.streamID);
+ }
+
+ getById("head1").className = 'advanced';
+ getById("head2").className = 'advanced';
+
+ if (!(session.cleanOutput)){
+ getById("chatbutton").className="float";
+ getById("hangupbutton").className="float";
+ getById("controlButtons").style.display="flex";
+ getById("helpbutton").style.display = "inherit";
+ getById("reportbutton").style.display = "";
+ } else {
+ getById("controlButtons").style.display="none";
+ }
+
+ var bigPlayButton = document.getElementById("bigPlayButton");
+ if (bigPlayButton){
+ bigPlayButton.parentNode.removeChild(bigPlayButton);
+ }
+
+
+
+ v.autoplay = false;
+ v.controls = true;
+ v.muted = false;
+
+ if (files.length ==1){ // we don't want to do the complex logic if there is just one video
+ v.loop = true;
+ } else {
+ v.loop = false; // triggers the complex track/rtc logic.
+ }
+
+ v.setAttribute("playsinline","");
+ v.src = fileURL;
+
+ try {
+ session.streamSrc=v.captureStream();
+ } catch (e){
+ errorlog(e);
+ return;
+ }
+
+ v.className = "tile clean";
+ v.id = "videosource"; // could be set to UUID in the future
+ v.playlist = files;
+
+ v.addEventListener('ended',myHandler,false); // only fires if the video doesn't loop.
+
+
+ function myHandler(e) {
+ log("MY HANDLER TRIGGERED");
+ var vid = getById("videosource");
+ log(vid.playlist);
+ vid.playlist.unshift(vid.playlist.pop());
+ vid.src = URL.createObjectURL(vid.playlist[0]);
+ vid.onloadeddata = function(){
+ session.streamSrc=vid.captureStream();
+
+ session.streamSrc.getTracks().forEach(function(track){
+ for (UUID in session.pcs){
+ var senders = session.pcs[UUID].getSenders();
+ 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 (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();
+ }
+ vid.load();
+ log(session.streamSrc);
+ vid.play().then(_ => {
+ log("playing");
+ }).catch(warnlog);
+
+ }
+
+ // no preview doesn't work, so just stop it from doing its thing.
+
+
+ container.appendChild(v);
+ changeAudioOutputDevice(v);
+
+ if (session.mirrored && session.flipped){
+ v.style.transform = "scaleX(1) scaleY(-1) ";
+ } else if (session.mirrored){
+ v.style.transform = "scaleX(1) ";
+ } else if (session.flipped){
+ v.style.transform = "scaleY(-1) scaleX(-1)";
+ } else {
+ v.style.transform = "scaleX(-1) ";
+ }
+
+ session.mirrorExclude=true;
+
+ if (session.director){
+ } else if (session.scene!==false){
+ setTimeout(function(){updateMixer();},1);
+ } else if (session.roomid!==false){
+ if (session.roomid===""){
+ if (!(session.view) || (session.view==="")){
+
+ if (session.fullscreen){
+ session.windowed = false;
+ } else {
+ v.className = "myVideo clean";
+ session.windowed = true;
+ }
+ getById("mutespeakerbutton").classList.add("advanced");
+
+ applyMirror(session.mirrorExclude, 'videosource');
+
+ container.style.width="100%";
+ //container.style.height="100%";
+
+ container.style.alignItems = "center";
+ container.backgroundColor = "#666";
+
+ play();
+ } else {
+ session.windowed = false;
+ applyMirror(session.mirrorExclude, 'videosource');
+ play();
+ setTimeout(function(){updateMixer();},1);
+ }
+ } else {
+ //session.cbr=0; // we're just going to override it
+ if (session.stereo==5){
+ session.stereo=3;
+ }
+ session.windowed = false;
+ applyMirror(session.mirrorExclude, 'videosource');
+ setTimeout(function(){updateMixer();},1);
+ }
+ } else {
+
+
+ if (session.fullscreen){
+ session.windowed = false;
+ } else {
+ v.className = "myVideo clean";
+ session.windowed = true;
+ }
+ getById("mutespeakerbutton").classList.add("advanced");
+
+ applyMirror(session.mirrorExclude, 'videosource');
+
+ container.style.width="100%";
+ //container.style.height="100%";
+ //container.style.display = "flex";
+
+ container.style.alignItems = "center";
+ container.backgroundColor = "#666";
+
+ }
+
+
+ v.addEventListener('click', function(e){
+ log("click");
+ try {
+ if ((e.ctrlKey)||(e.metaKey)){
+ e.preventDefault();
+
+ var [menu, innerMenu] = statsMenuCreator();
+
+ menu.interval = setInterval(printMyStats,3000, innerMenu);
+
+ printMyStats(innerMenu);
+ e.stopPropagation();
+ return false;
+ }
+ } catch(e){errorlog(e);}
+ });
+
+
+ v.touchTimeOut = null;
+ v.touchLastTap = 0;
+ v.touchCount = 0;
+ v.addEventListener('touchend', function(event) {
+ log("touched");
+
+ document.ontouchup = null;
+ document.onmouseup = null;
+ document.onmousemove = null;
+ document.ontouchmove = null;
+
+ var currentTime = new Date().getTime();
+ var tapLength = currentTime - v.touchLastTap;
+ clearTimeout(v.touchTimeOut);
+ if (tapLength < 500 && tapLength > 0) {
+ ///
+ log("double touched");
+ v.touchCount+=1;
+ event.preventDefault();
+ if (v.touchCount<5){
+ v.touchLastTap = currentTime;
+ return false;
+ }
+ v.touchLastTap = 0;
+ v.touchCount=0;
+
+ var [menu, innerMenu] = statsMenuCreator();
+
+ menu.interval = setInterval(printMyStats,3000, innerMenu);
+
+ printMyStats(innerMenu);
+ event.stopPropagation();
+ return false;
+ //////
+ } else {
+ v.touchCount=1;
+ v.touchTimeOut = setTimeout(function(vv) {
+ clearTimeout(vv.touchTimeOut);
+ vv.touchLastTap = 0;
+ vv.touchCount=0;
+ }, 5000, v);
+ v.touchLastTap = currentTime;
+ }
+
+ });
+
+ try{
+ var m = getById("mainmenu");
+ m.remove();
+ } catch (e){}
+
+ var pie = "";
+ if (session.pie){
+ if (session.pie!==true){
+ pie = "&pie="+session.pie;
+ }
+ }
+
+ getById("reshare").href = "https://"+location.host+location.pathname+"?view="+session.streamID+pie;
+ getById("reshare").text = "https://"+location.host+location.pathname+"?view="+session.streamID+pie;
+ getById("reshare").style.width = ((getById("reshare").text.length + 1)*1.15 * 8) + 'px';
+ pokeIframeAPI('started-fileshare');
+
+ clearInterval(session.updateLocalStatsInterval);
+ session.updateLocalStatsInterval = setInterval(function(){updateLocalStats();},3000);
+
+ session.title=title;
+ session.seeding=true;
+
+ if (session.videoMutedFlag){
+ session.videoMuted = true;
+ toggleVideoMute(true);
+ }
+
+ session.seedStream();
+};
+
+
+function tryAgain(event) { // audio or video agnostic track reconnect ------------not actually in use,. maybe out of date
+ log("TRY AGAIN TRIGGERED");
+ warnlog(event);
+}
+
+
+function enterPressedClick(event, ele) {
+ if (event.keyCode === 13) {
+ event.preventDefault();
+ ele.click();
+ }
+}
+
+function enterPressed(event, callback) {
+ // Number 13 is the "Enter" key on the keyboard
+ if (event.keyCode === 13) {
+ event.preventDefault();
+ callback();
+ }
+}
+
+
+function dragElement(elmnt) {
+ var millis = Date.now();
+ try {
+ var input = getById("zoomSlider");
+ var stream = elmnt.srcObject;
+ try {
+ var track0 = stream.getVideoTracks();
+ } catch (e) {
+ return;
+ }
+
+ if (!(track0.length)) {
+ return;
+ }
+
+ track0 = track0[0];
+ if (track0.getCapabilities) {
+ var capabilities = track0.getCapabilities();
+ var settings = track0.getSettings();
+
+ // Check whether zoom is supported or not.
+ if (!('zoom' in capabilities)) {
+ log('Zoom is not supported by ' + track0.label);
+ return;
+ }
+
+ // Map zoom to a slider element.
+ input.min = capabilities.zoom.min;
+ input.max = capabilities.zoom.max;
+ input.step = capabilities.zoom.step;
+ input.value = settings.zoom;
+ }
+ } catch (e) {
+ errorlog(e);
+ return;
+ }
+
+ log("drag on");
+ elmnt.onmousedown = dragMouseDown;
+ elmnt.onclick = onvideoclick;
+ elmnt.ontouchstart = dragMouseDown;
+
+ var pos0 = 1;
+
+ function onvideoclick(e) {
+ log(e);
+ log("onvideoclick");
+ e = e || window.event;
+ e.preventDefault();
+ return false;
+ }
+
+ function dragMouseDown(e) {
+ log(e);
+ log("dragMouseDown");
+
+ //closeDragElement(null);
+
+ //elmnt.controls = false;
+ e = e || window.event;
+ e.preventDefault();
+
+ pos0 = input.value;
+ if (e.type == 'touchstart' || e.type == 'touchmove' || e.type == 'touchend' || e.type == 'touchcancel') {
+ var touch = e.touches[0] || e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
+ pos3 = touch.clientX;
+ pos4 = touch.clientY;
+ } else if (e.type == 'mousedown' || e.type == 'mouseup' || e.type == 'mousemove' || e.type == 'mouseover' || e.type == 'mouseout' || e.type == 'mouseenter' || e.type == 'mouseleave') {
+ pos3 = e.clientX;
+ pos4 = e.clientY;
+ }
+ document.ontouchup = closeDragElement;
+ document.onmouseup = closeDragElement;
+
+ document.ontouchmove = elementDrag;
+ document.onmousemove = elementDrag;
+ }
+
+ function elementDrag(e) {
+ e = e || window.event;
+ e.preventDefault();
+ // calculate the new cursor position:
+
+ if (Date.now() - millis < 50) {
+ return;
+ }
+ millis = Date.now();
+
+ if (e.type == 'touchstart' || e.type == 'touchmove' || e.type == 'touchend' || e.type == 'touchcancel') {
+ var touch = e.touches[0] || e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
+ pos1 = touch.clientX;
+ pos2 = touch.clientY;
+ } else if (e.type == 'mousedown' || e.type == 'mouseup' || e.type == 'mousemove' || e.type == 'mouseover' || e.type == 'mouseout' || e.type == 'mouseenter' || e.type == 'mouseleave') {
+ pos1 = e.clientX;
+ pos2 = e.clientY;
+ }
+
+ var zoom = parseFloat((pos4 - pos2) * 2 / elmnt.offsetHeight);
+
+ if (zoom > 1) {
+ zoom = 1.0;
+ } else if (zoom < -1) {
+ zoom = -1.0;
+ }
+ input.value = zoom * (input.max - input.min) + input.min;
+ if (input.value != pos0) {
+ track0.applyConstraints({
+ advanced: [{
+ zoom: input.value
+ }]
+ });
+ }
+ }
+
+ function closeDragElement(e) {
+ log(e);
+ log("closeDragElement");
+ //if (e!==null){
+ // elmnt.controls=true;
+ //}
+ /* stop moving when mouse button is released:*/
+ document.ontouchup = null;
+ document.onmouseup = null;
+ document.onmousemove = null;
+ document.ontouchmove = null;
+ }
+}
+
+function previewIframe(iframesrc) { // this is pretty important if you want to avoid camera permission popup problems. You can also call it automatically via: loadIframe();"> , but don't call it before the page loads.
+
+ var iframe = document.createElement("iframe");
+ iframe.allow = "autoplay;camera;microphone";
+ iframe.allowtransparency = "true";
+ iframe.allowfullscreen = "true";
+ iframe.style.width = "100%";
+ iframe.style.height = "100%";
+ iframe.style.border = "10px dashed rgb(64 65 62)";
+
+ if (iframesrc == "") {
+ iframesrc = "./";
+ }
+
+
+ if (iframesrc.startsWith("https://") || iframesrc.startsWith("http://")){
+ var domain = (new URL(iframesrc));
+ domain = domain.hostname;
+ log(domain);
+ if ((domain=="www.youtube.com") || (domain=="youtube.com")){
+ var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
+ var match = iframesrc.match(regExp);
+ var vidid = (match&&match[7].length==11)? match[7] : false;
+
+ if(vidid){
+ iframesrc = "https://www.youtube.com/embed/"+vidid+"?autoplay=1&modestbranding=1";
+ log(iframesrc);
+ }
+ } else if (domain=="www.twitch.tv"){
+ var vidid = iframesrc.split('/').pop().split('#')[0].split('?')[0];
+ if (vidid){
+ iframesrc = "https://player.twitch.tv/?channel="+vidid+"&parent="+location.hostname;
+ log(iframesrc);
+ }
+ } else if (domain=="twitch.tv"){
+ var vidid = iframesrc.split('/').pop().split('#')[0].split('?')[0];
+ if (vidid){
+ iframesrc = "https://player.twitch.tv/?channel="+vidid+"&parent="+location.hostname;
+ log(iframesrc);
+ }
+ }
+
+ }
+
+ iframe.src = iframesrc;
+ getById("previewIframe").innerHTML = "";
+ getById("previewIframe").style.width = "640px";
+ getById("previewIframe").style.height = "360px";
+ getById("previewIframe").style.margin = "auto";
+ getById("previewIframe").appendChild(iframe);
+}
+
+function loadIframe(iframesrc) { // this is pretty important if you want to avoid camera permission popup problems. You can also call it automatically via: loadIframe();"> , but don't call it before the page loads.
+
+ var iframe = document.createElement("iframe");
+ iframe.allow = "autoplay;camera;microphone";
+ iframe.allowtransparency = "true";
+ iframe.allowfullscreen = "true";
+ iframe.style.width = "100%";
+ iframe.style.height = "100%";
+ iframe.style.border = "10px dashed rgb(64 65 62)";
+
+ if (iframesrc == "") {
+ iframesrc = "./";
+ iframe.style.border = "0";
+ }
+
+ if (iframesrc.startsWith("https://obs.ninja/")){
+ iframe.style.border = "0";
+ } else if (iframesrc.startsWith("https://youtube.com/")){
+ iframe.style.border = "0";
+ } else if (iframesrc.startsWith("https://www.youtube.com/")){
+ iframe.style.border = "0";
+ } else if (iframesrc.startsWith("https://youtube.com/")){
+ iframe.style.border = "0";
+ } else if (iframesrc.startsWith("https://player.twitch.tv/")){
+ iframe.style.border = "0";
+ } else if (iframesrc.startsWith("https://meshcast.io/")){
+ iframe.style.border = "0";
+ }
+
+ if (document.getElementById("mainmenu")) {
+ var m = getById("mainmenu");
+ m.remove();
+ }
+ iframe.src = iframesrc;
+ return iframe
+}
+
+function dropDownButtonAction(ele) {
+ var ele = getById("dropButton");
+ if (ele) {
+ ele.parentNode.removeChild(ele);
+ getById('container-5').classList.remove('advanced');
+ getById('container-8').classList.remove('advanced');
+ getById('container-6').classList.remove('advanced');
+ getById('container-7').classList.remove('advanced');
+ }
+}
+
+function updateConstraintSliders() {
+ log("updateConstraintSliders");
+ if (session.roomid !== false && session.roomid !== "" && session.director !== true && session.forceMediaSettings == false) {
+ if (session.controlRoomBitrate !== false) {
+ listCameraSettings();
+ }
+ if (session.effects!==false){
+ if ((iOS) || (iPad)){
+ } else {
+ getById("effectsDiv3").style.display = "block";
+ getById("effectSelector3").value = (parseInt(session.effects) || 0) +"";
+ }
+ }
+ } else {
+ listAudioSettings();
+ listCameraSettings();
+ if ((iOS) || (iPad)){
+ } else {
+ if (session.effects!==false){
+ getById("effectsDiv3").style.display = "block";
+ try{
+ getById("effectSelector3").value = (parseInt(session.effects) || 0) +"";
+ } catch(E){}
+ }
+ }
+ }
+ //checkIfPIP(); // this doesn't actually work on iOS still, so whatever.
+}
+
+function checkIfPIP() {
+ try {
+ if (session.videoElement && ((session.videoElement.webkitSupportsPresentationMode && typeof session.videoElement.webkitSetPresentationMode === "function") || (document.pictureInPictureEnabled || !videoElement.disablePictureInPicture))) {
+ // Toggle PiP when the user clicks the button.
+
+ getById("pIpStartButton").addEventListener("click", function(event) {
+ // if ( (document.pictureInPictureEnabled || !videoElement.disablePictureInPicture)){
+ //session.videoElement.requestPictureInPicture();
+ // } else {
+ session.videoElement.webkitSetPresentationMode(session.videoElement.webkitPresentationMode === "picture-in-picture" ? "inline" : "picture-in-picture");
+ // }
+ });
+ getById("pIpStartButton").style.display = "inline-block";
+ }
+ } catch (e) {
+ errorlog(e);
+ }
+}
+
+function listAudioSettingsPrep() {
+ try {
+ var tracks = session.streamSrc.getAudioTracks();
+ if (!tracks.length) {
+ warnlog("session.streamSrc contains no audio tracks");
+ return;
+ }
+ } catch (e) {
+ warnlog(e);
+ return;
+ }
+
+ var data = [];
+
+ for (var i = 0; i < tracks.length; i += 1) {
+ track0 = tracks[i];
+ var trackSet = {};
+
+ if (track0.getCapabilities) {
+ trackSet.audioConstraints = track0.getCapabilities();
+ }
+
+ if (track0.getSettings) {
+ trackSet.currentAudioConstraints = track0.getSettings();
+ }
+
+ trackSet.trackLabel = "unknown or none";
+ if (track0.label) {
+ trackSet.trackLabel = track0.label;
+ }
+
+ if (i == 0) {
+ trackSet.equalizer = session.equalizer; // only supporting the first track at the moment.
+ } else {
+ trackSet.equalizer = false;
+ }
+
+ if (i == 0) {
+ trackSet.lowcut = session.lowcut; // only supporting the first track at the moment.
+ } else {
+ trackSet.lowcut = false;
+ }
+
+ data.push(trackSet);
+ }
+ return data;
+}
+
+function listVideoSettingsPrep() {
+ try {
+ var track0 = session.streamSrc.getVideoTracks();
+ if (track0.length) {
+ track0 = track0[0];
+ if (track0.getCapabilities) {
+ session.cameraConstraints = track0.getCapabilities();
+ }
+ log(session.cameraConstraints);
+ }
+ } catch (e) {
+ warnlog(e);
+ return;
+ }
+
+ try {
+ if (track0.getSettings) {
+ session.currentCameraConstraints = track0.getSettings();
+ }
+ } catch (e) {
+ warnlog(e);
+ return;
+ }
+ var msg = {};
+ msg.trackLabel = "unknown or none";
+ if (track0.label) {
+ msg.trackLabel = track0.label;
+ }
+ msg.currentCameraConstraints = session.currentCameraConstraints;
+ msg.cameraConstraints = session.cameraConstraints;
+ return msg;
+}
+
+
+var Final_transcript = "";
+var Interim_transcript = "";
+var Recognition = null;
+
+if ("webkitSpeechRecognition" in window) {
+ var SpeechRecognition = webkitSpeechRecognition;
+} else if ("SpeechRecognition" in window) {
+ var SpeechRecognition = window.SpeechRecognition;
+} else {
+ var SpeechRecognition = false;
+}
+
+var TranscriptionCounter = 0;
+
+function setupClosedCaptions() {
+ log("CLOSED CAPTIONING SETUP");
+ if (SpeechRecognition) {
+ Recognition = new SpeechRecognition();
+
+ Recognition.lang = session.transcript;
+
+ Recognition.continuous = true;
+ Recognition.interimResults = true;
+ Recognition.maxAlternatives = 0;
+
+ Recognition.onstart = function() {
+ log("started transcription");
+ };
+ Recognition.onerror = function(event) {
+ errorlog(event);
+ try {
+ Recognition.stop();
+ } catch (e) {}
+ setTimeout(function() {
+ setupClosedCaptions();
+ }, 0); // restart it if it fails.
+ };
+ Recognition.onend = function(e) {
+ warnlog(e);
+ log("Stopped transcription");
+ setTimeout(function() {
+ setupClosedCaptions();
+ }, 0); // restart it if it fails.
+ };
+
+ Recognition.onresult = function(event) {
+
+ Interim_transcript = '';
+ if (typeof(event.results) == 'undefined') {
+ log(event);
+ return;
+ }
+ for (var i = event.resultIndex; i < event.results.length; ++i) {
+ if (event.results[i].isFinal) {
+ Final_transcript += event.results[i][0].transcript;
+ } else {
+ Interim_transcript += event.results[i][0].transcript;
+ }
+ }
+
+ if (Final_transcript.length > 0) {
+ log("FINAL:" + Final_transcript);
+ try {
+ var data = {};
+ data.isFinal = true;
+ data.transcript = Final_transcript;
+ data.counter = TranscriptionCounter;
+ session.sendMessage(data);
+ TranscriptionCounter += 1;
+ Final_transcript = "";
+ Interim_transcript = "";
+ } catch (e) {
+ errorlog(e);
+ }
+
+ } else {
+ try {
+ var data = {};
+ data.isFinal = false;
+ data.transcript = Interim_transcript;
+ data.counter = TranscriptionCounter;
+ session.sendMessage(data);
+ } catch (e) {
+ errorlog(e);
+ Interim_transcript = "";
+ }
+ }
+ };
+
+ Recognition.start();
+ }
+}
+
+
+function requestVideoRecord(ele) {
+ var UUID = ele.dataset.UUID
+ if (ele.classList.contains("pressed")) {
+ var msg = {};
+ msg.requestVideoRecord = false;
+ msg.UUID = UUID;
+ session.sendRequest(msg, msg.UUID);
+ ele.classList.remove("pressed");
+ } else {
+ var msg = {};
+ msg.requestVideoRecord = true;
+ msg.UUID = UUID;
+ window.focus();
+ var bitrate = prompt("What bitrate would you like to record at? (kbps)", 6000);
+ if (bitrate) {
+ msg.value = bitrate;
+ session.sendRequest(msg, msg.UUID);
+ ele.classList.add("pressed");
+ }
+ }
+}
+
+function changeOrderDirector(value) {
+ if (session.order==false){
+ session.order=0;
+ }
+ session.order += parseInt(value) || 0;
+
+ var elements = document.querySelectorAll('[data-action-type="order-value-director"]');
+ //log(elements);
+ if (elements[0]){
+ elements[0].innerText = parseInt(session.order) || 0;
+ }
+
+ var data = {};
+ data = {};
+ data.order = session.order;
+ session.sendPeers(data);
+}
+
+
+
+function changeOrder(value, UUID) {
+ var msg = {};
+ msg.changeOrder = value;
+ msg.UUID = UUID;
+ session.sendRequest(msg, msg.UUID);
+}
+
+function requestVideoHack(keyname, value, UUID) {
+ var msg = {};
+ msg.requestVideoHack = true;
+ msg.keyname = keyname;
+ msg.value = value;
+ msg.UUID = UUID;
+ session.sendRequest(msg, msg.UUID);
+}
+
+function requestAudioHack(keyname, value, UUID, track = 0) { // updateCameraConstraints
+ var msg = {};
+ msg.requestAudioHack = true;
+ msg.keyname = keyname;
+ msg.value = value;
+ msg.UUID = UUID;
+ msg.track = track;
+ session.sendRequest(msg, msg.UUID);
+}
+
+function requestChangeEQ(keyname, value, UUID, track = 0) { // updateCameraConstraints
+ var msg = {};
+ msg.requestChangeEQ = true;
+ msg.keyname = keyname;
+ msg.value = value;
+ msg.UUID = UUID;
+ msg.track = track;
+ session.sendRequest(msg, msg.UUID);
+}
+
+function requestChangeLowcut(value, UUID, track = 0) { // updateCameraConstraints
+ var msg = {};
+ msg.requestChangeLowcut = true;
+ msg.value = value;
+ msg.UUID = UUID;
+ msg.track = track;
+ session.sendRequest(msg, msg.UUID);
+}
+
+function toggleSystemPip(vid) {
+ if (vid.webkitSupportsPresentationMode && (typeof vid.webkitSetPresentationMode === "function")) {
+ vid.webkitSetPresentationMode(
+ vid.webkitPresentationMode === "picture-in-picture"
+ ? "inline"
+ : "picture-in-picture"
+ );
+ } else {
+ if (document.pictureInPictureElemen) {
+ document.exitPictureInPicture();
+ vid.requestPictureInPicture();
+ } else {
+ vid.requestPictureInPicture();
+ }
+
+ }
+}
+
+function updateDirectorsAudio(dataN, UUID) {
+ var audioEle = document.createElement("div");
+ getById("advanced_audio_director_" + UUID).innerHTML = "";
+ getById("advanced_audio_director_" + UUID).className = "";
+
+ //log(dataN);
+ if (!dataN.length) {
+ return;
+ }
+
+ for (var n = 0; n < dataN.length; n += 1) {
+ var data = dataN[n];
+
+ if (data.trackLabel) {
+ var label = document.createElement("span");
+ label.innerText = data.trackLabel;
+ label.style.marginBottom = "10px";
+ label.style.display = "block";
+ audioEle.appendChild(label);
+ }
+ if (n !== 0) {
+ //var label = document.createElement("span");
+ //label.innerText = "Coming Soon";
+ //audioEle.appendChild(label);
+ continue; // remove to more than one audio device (assuming other fixes are applied)
+ }
+
+
+ if (data.lowcut) {
+ var label = document.createElement("label");
+ var i = "Low_Cut";
+ label.id = "label_" + i;
+ label.htmlFor = "constraints_" + i;
+ label.innerText = "low cut:";
+
+ var input = document.createElement("input");
+ input.min = 50;
+ input.max = 150;
+
+ input.type = "range";
+ input.dataset.keyname = i;
+ input.dataset.labelname = label.innerText;
+ input.dataset.track = n;
+ input.dataset.UUID = UUID;
+ input.id = "constraints_" + i;
+ input.style = "display:block; width:100%;";
+ input.name = "constraints_" + i;
+ input.style.margin = "8px 0";
+
+ input.onchange = function(e) {
+ getById("label_" + e.target.dataset.keyname).innerText = e.target.dataset.labelname + " " + e.target.value;
+ requestChangeLowcut(parseInt(e.target.value), e.target.dataset.UUID, parseInt(e.target.dataset.track));
+ };
+
+ audioEle.appendChild(label);
+ audioEle.appendChild(input);
+ }
+
+ if (data.equalizer) {
+ var label = document.createElement("label");
+ var i = "Low_EQ";
+ label.id = "label_" + i;
+ label.htmlFor = "constraints_" + i;
+ label.innerText = "low EQ:";
+
+ var input = document.createElement("input");
+ input.min = -50;
+ input.max = 50;
+
+ input.type = "range";
+ input.dataset.keyname = i;
+ input.dataset.labelname = label.innerText;
+ input.dataset.track = n;
+ input.dataset.UUID = UUID;
+ input.id = "constraints_" + i;
+ input.style = "display:block; width:100%;";
+ input.name = "constraints_" + i;
+ input.style.margin = "8px 0";
+
+ input.onchange = function(e) {
+ getById("label_" + e.target.dataset.keyname).innerText = e.target.dataset.labelname + " " + e.target.value;
+ //changeLowEQ( e.target.value);
+ requestChangeEQ("low", parseInt(e.target.value), e.target.dataset.UUID, parseInt(e.target.dataset.track));
+ };
+
+ audioEle.appendChild(label);
+ audioEle.appendChild(input);
+
+ var label = document.createElement("label");
+ var i = "Mid_EQ";
+ label.id = "label_" + i;
+ label.htmlFor = "constraints_" + i;
+ label.innerText = "mid EQ:";
+
+ var input = document.createElement("input");
+ input.min = -50;
+ input.max = 50;
+
+ input.type = "range";
+ input.dataset.keyname = i;
+ input.dataset.labelname = label.innerText;
+ input.dataset.track = n;
+ input.dataset.UUID = UUID;
+ input.id = "constraints_" + i;
+ input.style = "display:block; width:100%;";
+ input.name = "constraints_" + i;
+ input.style.margin = "8px 0";
+
+
+ input.onchange = function(e) {
+ getById("label_" + e.target.dataset.keyname).innerText = e.target.dataset.labelname + " " + e.target.value;
+ //changeMidEQ( e.target.value);
+ requestChangeEQ("mid", parseInt(e.target.value), e.target.dataset.UUID, parseInt(e.target.dataset.track));
+ };
+
+ audioEle.appendChild(label);
+ audioEle.appendChild(input);
+
+
+ var label = document.createElement("label");
+ var i = "High_EQ";
+ label.id = "label_" + i;
+ label.htmlFor = "constraints_" + i;
+ label.innerText = "high EQ:";
+
+ var input = document.createElement("input");
+ input.min = -50;
+ input.max = 50;
+
+ input.type = "range";
+ input.dataset.keyname = i;
+ input.dataset.labelname = label.innerText;
+ input.dataset.track = n;
+ input.dataset.UUID = UUID;
+ input.id = "constraints_" + i;
+ input.style = "display:block; width:100%;";
+ input.name = "constraints_" + i;
+ input.style.margin = "8px 0";
+
+ input.onchange = function(e) {
+ getById("label_" + e.target.dataset.keyname).innerText = e.target.dataset.labelname + " " + e.target.value;
+ requestChangeEQ("high", parseInt(e.target.value), e.target.dataset.UUID, parseInt(e.target.dataset.track));
+ };
+
+ audioEle.appendChild(label);
+ audioEle.appendChild(input);
+ }
+ for (var i in data.audioConstraints) {
+ try {
+ log(i);
+ log(data.audioConstraints[i]);
+ if ((typeof data.audioConstraints[i] === 'object') && (data.audioConstraints[i] !== null) && ("max" in data.audioConstraints[i]) && ("min" in data.audioConstraints[i])) {
+ if (i === "aspectRatio") {
+ continue;
+ } else if (i === "width") {
+ continue;
+ } else if (i === "height") {
+ continue;
+ } else if (i === "frameRate") {
+ continue;
+ } else if (i === "latency") {
+ continue;
+ } else if (i === "sampleRate") {
+ continue;
+ } else if (i === "channelCount") {
+ continue;
+ }
+
+ var label = document.createElement("label");
+ label.id = "label_" + i;
+ label.htmlFor = "constraints_" + i;
+ label.innerText = i + ":";
+
+ var input = document.createElement("input");
+ input.min = data.audioConstraints[i].min;
+ input.max = data.audioConstraints[i].max;
+
+ if (parseFloat(input.min) == parseFloat(input.max)) {
+ continue;
+ }
+
+ if (i in data.currentAudioConstraints) {
+ input.value = data.currentAudioConstraints[i];
+ label.innerText = i + ": " + data.currentAudioConstraints[i];
+ label.title = "Previously was: " + data.currentAudioConstraints[i];
+ input.title = "Previously was: " + data.currentAudioConstraints[i];
+ } else {
+ label.innerText = i;
+ }
+ if ("step" in data.audioConstraints[i]) {
+ input.step = data.audioConstraints[i].step;
+ }
+ input.type = "range";
+ input.dataset.keyname = i;
+ input.dataset.track = n;
+ input.dataset.UUID = UUID;
+ input.id = "constraints_" + i;
+ input.style = "display:block; width:100%;";
+ input.name = "constraints_" + i;
+
+
+ input.onchange = function(e) {
+ getById("label_" + e.target.dataset.keyname).innerText = e.target.dataset.keyname + ": " + e.target.value;
+ //updateAudioConstraints(e.target.dataset.keyname, e.target.value);
+ requestAudioHack(e.target.dataset.keyname, e.target.value, e.target.dataset.UUID, e.target.dataset.track);
+ };
+
+ audioEle.appendChild(label);
+ audioEle.appendChild(input);
+ } else if ((typeof data.audioConstraints[i] === 'object') && (data.audioConstraints[i] !== null)) {
+ if (i == "resizeMode") {
+ continue;
+ }
+
+ var div = document.createElement("div");
+ var label = document.createElement("label");
+ label.id = "label_" + i;
+ label.htmlFor = "constraints_" + i;
+ label.innerText = i + ":";
+ label.style = "display:inline-block; padding:0;margin: 5px 0px 9px;";
+ label.dataset.keyname = i;
+ var input = document.createElement("select");
+ var c = document.createElement("option");
+
+ if (data.audioConstraints[i].length > 1) {
+ for (var opts in data.audioConstraints[i]) {
+ log(opts);
+ var opt = new Option(data.audioConstraints[i][opts], data.audioConstraints[i][opts]);
+ input.options.add(opt);
+ if (i in data.currentAudioConstraints) {
+ if (data.audioConstraints[i][opts] == data.currentAudioConstraints[i]) {
+ opt.selected = true;
+ }
+ }
+ }
+ } else if (i.toLowerCase == "torch") {
+ var opt = new Option("Off", false);
+ input.options.add(opt);
+ opt = new Option("On", true);
+ input.options.add(opt);
+ } else {
+ continue;
+ }
+
+ input.id = "constraints_" + i;
+ input.className = "constraintCameraInput";
+ input.name = "constraints_" + i;
+ input.style = "display:inline; padding:2px; margin:0 10px;";
+ input.dataset.keyname = i;
+ input.dataset.track = n;
+ input.dataset.UUID = UUID;
+ input.onchange = function(e) {
+ //getById("label_"+e.target.dataset.keyname).innerText =e.target.dataset.keyname+": "+e.target.value;
+ //updateAudioConstraints(e.target.dataset.keyname, e.target.value);
+ requestAudioHack(e.target.dataset.keyname, e.target.value, e.target.dataset.UUID, e.target.dataset.track);
+ log(e.target.dataset.keyname, e.target.value);
+ };
+ audioEle.appendChild(div);
+ div.appendChild(label);
+ div.appendChild(input);
+ } else if (typeof data.audioConstraints[i] === 'boolean') {
+
+ var div = document.createElement("div");
+ var label = document.createElement("label");
+ label.id = "label_" + i;
+ label.htmlFor = "constraints_" + i;
+ label.innerText = i + ":";
+ label.style = "display:inline-block; padding:0;margin: 5px 0px 9px;";
+ label.dataset.keyname = i;
+ var input = document.createElement("select");
+ var c = document.createElement("option");
+
+ var opt = new Option("Off", false);
+ input.options.add(opt);
+ opt = new Option("On", true);
+ input.options.add(opt);
+
+ input.id = "constraints_" + i;
+ input.className = "constraintCameraInput";
+ input.name = "constraints_" + i;
+ input.style = "display:inline; padding:2px; margin:0 10px;";
+ input.dataset.keyname = i;
+ input.dataset.track = n;
+ input.dataset.UUID = UUID;
+ input.onchange = function(e) {
+ //getById("label_"+e.target.dataset.keyname).innerText =e.target.dataset.keyname+": "+e.target.value;
+ //updateAudioConstraints(e.target.dataset.keyname, e.target.value);
+ requestAudioHack(e.target.dataset.keyname, e.target.value, e.target.dataset.UUID, e.target.dataset.track);
+ log(e.target.dataset.keyname, e.target.value);
+ };
+ audioEle.appendChild(div);
+ div.appendChild(label);
+ div.appendChild(input);
+ }
+ } catch (e) {
+ errorlog(e);
+ }
+ }
+ getById("advanced_audio_director_" + UUID).appendChild(audioEle);
+ }
+}
+
+function updateDirectorsVideo(data, UUID) {
+ var videoEle = document.createElement("div");
+ if (data.trackLabel) {
+ var label = document.createElement("span");
+ label.innerText = data.trackLabel;
+ label.style.marginBottom = "10px";
+ label.style.display = "block";
+ videoEle.appendChild(label);
+ }
+
+
+ for (var i in data.cameraConstraints) {
+ try {
+ log(i);
+ log(data.cameraConstraints[i]);
+ if ((typeof data.cameraConstraints[i] === 'object') && (data.cameraConstraints[i] !== null) && ("max" in data.cameraConstraints[i]) && ("min" in data.cameraConstraints[i])) {
+ if (i === "aspectRatio") {
+ continue;
+ } else if (i === "width") {
+ continue;
+ } else if (i === "height") {
+ continue;
+ } else if (i === "frameRate") {
+ continue;
+ } else if (i === "latency") {
+ continue;
+ } else if (i === "sampleRate") {
+ continue;
+ } else if (i === "channelCount") {
+ continue;
+ }
+
+ var label = document.createElement("label");
+ label.id = "label_" + i;
+ label.htmlFor = "constraints_" + i;
+ label.innerText = i + ":";
+
+ var input = document.createElement("input");
+ input.min = data.cameraConstraints[i].min;
+ input.max = data.cameraConstraints[i].max;
+
+ if (parseFloat(input.min) == parseFloat(input.max)) {
+ continue;
+ }
+
+
+ if (i in data.currentCameraConstraints) {
+ input.value = data.currentCameraConstraints[i];
+ label.innerText = i + ": " + data.currentCameraConstraints[i];
+ label.title = "Previously was: " + data.currentCameraConstraints[i];
+ input.title = "Previously was: " + data.currentCameraConstraints[i];
+ } else {
+ label.innerText = i;
+ }
+ if ("step" in data.cameraConstraints[i]) {
+ input.step = data.cameraConstraints[i].step;
+ }
+ input.type = "range";
+ input.dataset.keyname = i;
+ input.id = "constraints_" + i;
+ input.style = "display:block; width:100%;margin: 8px 0;";
+ input.name = "constraints_" + i;
+
+
+ input.onchange = function(e) {
+ getById("label_" + e.target.dataset.keyname).innerText = e.target.dataset.keyname + ": " + e.target.value;
+ //updateVideoConstraints(e.target.dataset.keyname, e.target.value);
+ requestVideoHack(e.target.dataset.keyname, e.target.value, UUID);
+ };
+
+
+ videoEle.appendChild(label);
+ videoEle.appendChild(input);
+ } else if ((typeof data.cameraConstraints[i] === 'object') && (data.cameraConstraints[i] !== null)) {
+ if (i == "resizeMode") {
+ continue;
+ }
+
+ var div = document.createElement("div");
+ var label = document.createElement("label");
+ label.id = "label_" + i;
+ label.htmlFor = "constraints_" + i;
+ label.innerText = i + ":";
+ label.style = "display:inline-block; padding:0;margin: 5px 0px 9px;";
+ label.dataset.keyname = i;
+ var input = document.createElement("select");
+ var c = document.createElement("option");
+
+ if (data.cameraConstraints[i].length > 1) {
+ for (var opts in data.cameraConstraints[i]) {
+ log(opts);
+ var opt = new Option(data.cameraConstraints[i][opts], data.cameraConstraints[i][opts]);
+ input.options.add(opt);
+ if (i in data.currentCameraConstraints) {
+ if (data.cameraConstraints[i][opts] == data.currentCameraConstraints[i]) {
+ opt.selected = true;
+ }
+ }
+ }
+ } else if (i.toLowerCase == "torch") {
+ var opt = new Option("Off", false);
+ input.options.add(opt);
+ opt = new Option("On", true);
+ input.options.add(opt);
+ } else {
+ continue;
+ }
+
+ input.id = "constraints_" + i;
+ input.className = "constraintCameraInput";
+ input.name = "constraints_" + i;
+ input.style = "display:inline; padding:2px; margin:0 10px;";
+ input.dataset.keyname = i;
+ input.onchange = function(e) {
+ //getById("label_"+e.target.dataset.keyname).innerText =e.target.dataset.keyname+": "+e.target.value;
+ //updateVideoConstraints(e.target.dataset.keyname, e.target.value);
+ requestVideoHack(e.target.dataset.keyname, e.target.value, UUID);
+ log(e.target.dataset.keyname, e.target.value);
+ };
+ videoEle.appendChild(div);
+ div.appendChild(label);
+ div.appendChild(input);
+ } else if (typeof data.cameraConstraints[i] === 'boolean') {
+
+ var div = document.createElement("div");
+ var label = document.createElement("label");
+ label.id = "label_" + i;
+ label.htmlFor = "constraints_" + i;
+ label.innerText = i + ":";
+ label.style = "display:inline-block; padding:0;margin: 5px 0px 9px;";
+ label.dataset.keyname = i;
+ var input = document.createElement("select");
+ var c = document.createElement("option");
+
+ var opt = new Option("Off", false);
+ input.options.add(opt);
+ opt = new Option("On", true);
+ input.options.add(opt);
+
+ input.id = "constraints_" + i;
+ input.className = "constraintCameraInput";
+ input.name = "constraints_" + i;
+ input.style = "display:inline; padding:2px; margin:0 10px;";
+ input.dataset.keyname = i;
+ input.onchange = function(e) {
+ //getById("label_"+e.target.dataset.keyname).innerText =e.target.dataset.keyname+": "+e.target.value;
+ //updateVideoConstraints(e.target.dataset.keyname, e.target.value);
+ requestVideoHack(e.target.dataset.keyname, e.target.value, UUID);
+ log(e.target.dataset.keyname, e.target.value);
+ };
+ videoEle.appendChild(div);
+ div.appendChild(label);
+ div.appendChild(input);
+ }
+ } catch (e) {
+ errorlog(e);
+ }
+ }
+
+ getById("advanced_video_director_" + UUID).innerHTML = "";
+ getById("advanced_video_director_" + UUID).appendChild(videoEle);
+ getById("advanced_video_director_" + UUID).className = "";
+}
+
+///////
+
+function listAudioSettings() {
+ getById("popupSelector_constraints_audio").innerHTML = "";
+ try {
+ var track0 = session.streamSrc.getAudioTracks();
+ if (track0.length) {
+ track0 = track0[0];
+ if (track0.getCapabilities) {
+ session.audioConstraints = track0.getCapabilities();
+ }
+ log(session.audioConstraints);
+ } else {
+ warnlog("session.streamSrc contains no audio tracks");
+ return;
+ }
+ } catch (e) {
+ warnlog("session.streamSrc contains no audio tracks");
+ errorlog(e);
+ return;
+ }
+ try {
+ if (track0.getSettings) {
+ session.currentAudioConstraints = track0.getSettings();
+ }
+ } catch (e) {
+ errorlog(e);
+ }
+ //////
+
+ if (session.lowcut) {
+ if (getById("popupSelector_constraints_audio").style.display == "none") {
+ getById("advancedOptionsAudio").style.display = "inline-block";
+ }
+
+ var label = document.createElement("label");
+ var i = "Low_Cut";
+ label.id = "label_" + i;
+ label.htmlFor = "constraints_" + i;
+ label.innerText = "Low Cut:";
+
+ var input = document.createElement("input");
+ input.min = 50;
+ input.max = 400;
+
+ input.type = "range";
+ input.dataset.keyname = i;
+ input.dataset.labelname = label.innerHTML;
+ input.id = "constraints_" + i;
+ input.style = "display:block; width:100%;";
+ input.name = "constraints_" + i;
+
+ for (var webAudio in session.webAudios) {
+ if (session.webAudios[webAudio].lowcut1.frequency) {
+ input.value = session.webAudios[webAudio].lowcut1.frequency.value;
+ label.innerHTML += " " + session.webAudios[webAudio].lowcut1.frequency.value;
+ }
+ }
+
+ input.onchange = function(e) {
+ getById("label_" + e.target.dataset.keyname).innerHTML = e.target.dataset.labelname + " " + e.target.value;
+ changeLowCut(e.target.value, 0);
+ };
+
+ getById("popupSelector_constraints_audio").appendChild(label);
+ getById("popupSelector_constraints_audio").appendChild(input);
+ }
+
+ if (session.equalizer) {
+ if (getById("popupSelector_constraints_audio").style.display == "none") {
+ getById("advancedOptionsAudio").style.display = "inline-block";
+ }
+
+ var label = document.createElement("label");
+ var i = "Low_EQ";
+ label.id = "label_" + i;
+ label.htmlFor = "constraints_" + i;
+ label.innerHTML = "Low EQ:";
+
+ var input = document.createElement("input");
+ input.min = -50;
+ input.max = 50;
+
+ input.type = "range";
+ input.dataset.keyname = i;
+ input.dataset.labelname = label.innerHTML;
+ input.id = "constraints_" + i;
+ input.style = "display:block; width:100%;";
+ input.name = "constraints_" + i;
+
+ for (var webAudio in session.webAudios) {
+ if (session.webAudios[webAudio].lowEQ.gain) {
+ input.value = session.webAudios[webAudio].lowEQ.gain.value;
+ label.innerHTML += " " + session.webAudios[webAudio].lowEQ.gain.value;
+ }
+ }
+
+ input.onchange = function(e) {
+ getById("label_" + e.target.dataset.keyname).innerHTML = e.target.dataset.labelname + " " + e.target.value;
+ changeLowEQ(e.target.value, 0);
+ };
+
+ getById("popupSelector_constraints_audio").appendChild(label);
+ getById("popupSelector_constraints_audio").appendChild(input);
+ //
+ if (getById("popupSelector_constraints_audio").style.display == "none") {
+ getById("advancedOptionsAudio").style.display = "inline-block";
+ }
+
+ var label = document.createElement("label");
+ var i = "Mid_EQ";
+ label.id = "label_" + i;
+ label.htmlFor = "constraints_" + i;
+ label.innerHTML = "Mid EQ:";
+
+ var input = document.createElement("input");
+ input.min = -50;
+ input.max = 50;
+
+ input.type = "range";
+ input.dataset.keyname = i;
+ input.dataset.labelname = label.innerHTML;
+ input.id = "constraints_" + i;
+ input.style = "display:block; width:100%;";
+ input.name = "constraints_" + i;
+
+
+ for (var webAudio in session.webAudios) {
+ if (session.webAudios[webAudio].midEQ.gain) {
+ input.value = session.webAudios[webAudio].midEQ.gain.value;
+ label.innerHTML += " " + session.webAudios[webAudio].midEQ.gain.value;
+ }
+ }
+
+
+ input.onchange = function(e) {
+ getById("label_" + e.target.dataset.keyname).innerHTML = e.target.dataset.labelname + " " + e.target.value;
+ changeMidEQ(e.target.value, 0);
+ };
+
+ getById("popupSelector_constraints_audio").appendChild(label);
+ getById("popupSelector_constraints_audio").appendChild(input);
+ //
+ if (getById("popupSelector_constraints_audio").style.display == "none") {
+ getById("advancedOptionsAudio").style.display = "inline-block";
+ }
+
+ var label = document.createElement("label");
+ var i = "High_EQ";
+ label.id = "label_" + i;
+ label.htmlFor = "constraints_" + i;
+ label.innerHTML = "High EQ:";
+
+ var input = document.createElement("input");
+ input.min = -50;
+ input.max = 50;
+
+
+ input.type = "range";
+ input.dataset.keyname = i;
+ input.dataset.labelname = label.innerHTML;
+ input.id = "constraints_" + i;
+ input.style = "display:block; width:100%;";
+ input.name = "constraints_" + i;
+
+ for (var webAudio in session.webAudios) {
+ if (session.webAudios[webAudio].highEQ.gain) {
+ input.value = session.webAudios[webAudio].highEQ.gain.value;
+ label.innerHTML += " " + session.webAudios[webAudio].highEQ.gain.value;
+ }
+ }
+
+
+ input.onchange = function(e) {
+ getById("label_" + e.target.dataset.keyname).innerHTML = e.target.dataset.labelname + " " + e.target.value;
+ changeHighEQ(e.target.value, 0);
+ };
+
+ getById("popupSelector_constraints_audio").appendChild(label);
+ getById("popupSelector_constraints_audio").appendChild(input);
+ }
+ ////////
+ for (var i in session.audioConstraints) {
+ try {
+ log(i);
+ log(session.audioConstraints[i]);
+ if ((typeof session.audioConstraints[i] === 'object') && (session.audioConstraints[i] !== null) && ("max" in session.audioConstraints[i]) && ("min" in session.audioConstraints[i])) {
+ if (i === "aspectRatio") {
+ continue;
+ } else if (i === "width") {
+ continue;
+ } else if (i === "height") {
+ continue;
+ } else if (i === "frameRate") {
+ continue;
+ } else if (i === "latency") {
+ continue;
+ } else if (i === "sampleRate") {
+ continue;
+ } else if (i === "channelCount") {
+ continue;
+ }
+
+ var label = document.createElement("label");
+ label.id = "label_" + i;
+ label.htmlFor = "constraints_" + i;
+ label.innerHTML = i + ":";
+
+
+ var input = document.createElement("input");
+ input.min = session.audioConstraints[i].min;
+ input.max = session.audioConstraints[i].max;
+
+ if (parseFloat(input.min) == parseFloat(input.max)) {
+ continue;
+ }
+
+ if (getById("popupSelector_constraints_audio").style.display == "none") {
+ getById("advancedOptionsAudio").style.display = "inline-block";
+ }
+
+
+ if (i in session.currentAudioConstraints) {
+ input.value = session.currentAudioConstraints[i];
+ label.innerHTML = i + ": " + session.currentAudioConstraints[i];
+ label.title = "Previously was: " + session.currentAudioConstraints[i];
+ input.title = "Previously was: " + session.currentAudioConstraints[i];
+ } else {
+ label.innerHTML = i;
+ }
+ if ("step" in session.audioConstraints[i]) {
+ input.step = session.audioConstraints[i].step;
+ }
+ input.type = "range";
+ input.dataset.keyname = i;
+ input.id = "constraints_" + i;
+ input.style = "display:block; width:100%;";
+ input.name = "constraints_" + i;
+
+
+ input.onchange = function(e) {
+ getById("label_" + e.target.dataset.keyname).innerHTML = e.target.dataset.keyname + ": " + e.target.value;
+ //updateAudioConstraints(e.target.dataset.keyname, e.target.value);
+ applyAudioHack(e.target.dataset.keyname, e.target.value);
+ };
+
+
+ getById("popupSelector_constraints_audio").appendChild(label);
+ getById("popupSelector_constraints_audio").appendChild(input);
+ } else if ((typeof session.audioConstraints[i] === 'object') && (session.audioConstraints[i] !== null)) {
+ if (i == "resizeMode") {
+ continue;
+ }
+
+ var div = document.createElement("div");
+ var label = document.createElement("label");
+ label.id = "label_" + i;
+ label.htmlFor = "constraints_" + i;
+ label.innerHTML = i + ":";
+ label.style = "display:inline-block; padding:0;margin: 15px 0px 29px;";
+ label.dataset.keyname = i;
+ var input = document.createElement("select");
+ var c = document.createElement("option");
+
+ if (session.audioConstraints[i].length > 1) {
+ for (var opts in session.audioConstraints[i]) {
+ log(opts);
+ var opt = new Option(session.audioConstraints[i][opts], session.audioConstraints[i][opts]);
+ input.options.add(opt);
+
+ if (i in session.currentAudioConstraints) {
+ if (session.audioConstraints[i][opts] == session.currentAudioConstraints[i]) {
+ opt.selected = true;
+ }
+ }
+
+ }
+ } else if (i.toLowerCase == "torch") {
+ var opt = new Option("Off", false);
+ input.options.add(opt);
+ opt = new Option("On", true);
+ input.options.add(opt);
+ } else {
+ continue;
+ }
+
+ if (getById("popupSelector_constraints_audio").style.display == "none") {
+ getById("advancedOptionsAudio").style.display = "inline-block";
+ }
+
+ input.id = "constraints_" + i;
+ input.className = "constraintCameraInput";
+ input.name = "constraints_" + i;
+ input.style = "display:inline; padding:2px; margin:0 10px;";
+ input.dataset.keyname = i;
+ input.onchange = function(e) {
+ //getById("label_"+e.target.dataset.keyname).innerHTML =e.target.dataset.keyname+": "+e.target.value;
+ //updateAudioConstraints(e.target.dataset.keyname, e.target.value);
+ applyAudioHack(e.target.dataset.keyname, e.target.value);
+ log(e.target.dataset.keyname, e.target.value);
+ };
+ getById("popupSelector_constraints_audio").appendChild(div);
+ div.appendChild(label);
+ div.appendChild(input);
+ } else if (typeof session.audioConstraints[i] === 'boolean') {
+
+ var div = document.createElement("div");
+ var label = document.createElement("label");
+ label.id = "label_" + i;
+ label.htmlFor = "constraints_" + i;
+ label.innerHTML = i + ":";
+ label.style = "display:inline-block; padding:0;margin: 15px 0px 29px;";
+ label.dataset.keyname = i;
+ var input = document.createElement("select");
+ var c = document.createElement("option");
+
+ var opt = new Option("Off", false);
+ input.options.add(opt);
+ opt = new Option("On", true);
+ input.options.add(opt);
+
+ if (getById("popupSelector_constraints_audio").style.display == "none") {
+ getById("advancedOptionsAudio").style.display = "inline-block";
+ }
+
+ input.id = "constraints_" + i;
+ input.className = "constraintCameraInput";
+ input.name = "constraints_" + i;
+ input.style = "display:inline; padding:2px; margin:0 10px;";
+ input.dataset.keyname = i;
+ input.onchange = function(e) {
+ //getById("label_"+e.target.dataset.keyname).innerHTML =e.target.dataset.keyname+": "+e.target.value;
+ //updateAudioConstraints(e.target.dataset.keyname, e.target.value);
+ applyAudioHack(e.target.dataset.keyname, e.target.value);
+ log(e.target.dataset.keyname, e.target.value);
+ };
+ getById("popupSelector_constraints_audio").appendChild(div);
+ div.appendChild(label);
+ div.appendChild(input);
+ }
+ } catch (e) {
+ errorlog(e);
+ }
+
+ }
+}
+
+
+function applyAudioHack(constraint, value = null) {
+ if (value == parseFloat(value)) {
+ value = parseFloat(value);
+ value = {
+ exact: value
+ };
+ } else if (value == "true") {
+ value = true;
+ } else if (value == "false") {
+ value = false;
+ }
+ log(constraint);
+ ////////////////
+ try {
+ var track0 = session.streamSrc.getAudioTracks();
+ if (track0.length) {
+ track0 = track0[0];
+ if (track0.getCapabilities) {
+ session.audioConstraints = track0.getCapabilities();
+ }
+ log(session.audioConstraints);
+ } else {
+ warnlog("session.streamSrc contains no audio tracks");
+ return;
+ }
+ } catch (e) {
+ warnlog("session.streamSrc contains no audio tracks");
+ errorlog(e);
+ return;
+ }
+ try {
+ if (track0.getSettings) {
+ session.currentAudioConstraints = track0.getSettings();
+ }
+ } catch (e) {
+ errorlog(e);
+ }
+ ////////
+
+ var new_constraints = Object.assign(track0.getSettings(), {
+ [constraint]: value
+ }, );
+ new_constraints = {
+ audio: new_constraints
+ , video: false
+ };
+ log(new_constraints);
+ activatedPreview = false;
+ enumerateDevices().then(gotDevices2).then(function() {
+ grabAudio("videosource", "#audioSource3", null, new_constraints);
+ });
+
+}
+
+function updateAudioConstraints(constraint, value = null) { // this is what it SHOULD be, but this doesn't work yet.
+ var track0 = session.streamSrc.getAudioTracks();
+ track0 = track0[0];
+ if (value == parseFloat(value)) {
+ value = parseFloat(value);
+ } else if (value == "true") {
+ value = true;
+ } else if (value == "false") {
+ value = false;
+ }
+ log({
+ advanced: [{
+ [constraint]: value
+ }]
+ });
+ track0.applyConstraints({
+ advanced: [{
+ [constraint]: value
+ }]
+ });
+ return;
+
+}
+
+function listCameraSettings() {
+ getById("popupSelector_constraints_video").innerHTML = "";
+
+ if (session.controlRoomBitrate===true){
+ session.controlRoomBitrate = session.totalRoomBitrate;
+ }
+
+ if (session.roomid && (session.view !== "") && (session.controlRoomBitrate!==false)) {
+ log("LISTING OPTION FOR BITRATE CONTROL");
+ var i = "room video bitrate (kbps)";
+ var label = document.createElement("label");
+ label.id = "label_" + i;
+ label.htmlFor = "constraints_" + i;
+ label.innerHTML = i + ":";
+ label.title = "If you're on a slow network, you can improve frame rate and audio quality by reducing the amount of video data that others send you";
+
+ var input = document.createElement("input");
+ input.min = 0;
+ input.max = parseInt(session.totalRoomBitrate);
+
+ if (getById("popupSelector_constraints_video").style.display == "none") {
+ getById("advancedOptionsCamera").style.display = "inline-block";
+ }
+
+ input.value = session.controlRoomBitrate;
+ label.innerHTML = i + ": " + session.controlRoomBitrate;
+
+ input.type = "range";
+ input.dataset.keyname = i;
+ input.id = "constraints_" + i;
+ input.style = "display:block; width:100%;";
+ input.name = "constraints_" + i;
+ input.title = "If you're on a slow network, you can improve frame rate and audio quality by reducing the amount of video data that others send you";
+
+
+ input.onchange = function(e) {
+ getById("label_" + e.target.dataset.keyname).innerHTML = e.target.dataset.keyname + ": " + e.target.value;
+
+ if (e.target.value > session.totalRoomBitrate) {
+ return;
+ } else {
+ session.controlRoomBitrate = parseInt(e.target.value);
+ }
+ updateMixer();
+ };
+
+
+ getById("popupSelector_constraints_video").appendChild(label);
+ getById("popupSelector_constraints_video").appendChild(input);
+
+ }
+ try {
+ var track0 = session.streamSrc.getVideoTracks();
+ if (track0.length) {
+ track0 = track0[0];
+ if (track0.getCapabilities) {
+ session.cameraConstraints = track0.getCapabilities();
+ }
+ log(session.cameraConstraints);
+ }
+ } catch (e) {
+ errorlog(e);
+ return;
+ }
+
+ try {
+
+ if (track0.getSettings) {
+ session.currentCameraConstraints = track0.getSettings();
+ }
+ } catch (e) {
+ errorlog(e);
+ }
+
+ for (var i in session.cameraConstraints) {
+ try {
+ log(i);
+ log(session.cameraConstraints[i]);
+ if ((typeof session.cameraConstraints[i] === 'object') && (session.cameraConstraints[i] !== null) && ("max" in session.cameraConstraints[i]) && ("min" in session.cameraConstraints[i])) {
+ if (i === "aspectRatio") {
+ continue;
+ } else if (i === "width") {
+ continue;
+ } else if (i === "height") {
+ continue;
+ } else if (i === "frameRate") {
+ continue;
+ }
+
+
+ var label = document.createElement("label");
+ label.id = "label_" + i;
+ label.htmlFor = "constraints_" + i;
+ label.innerHTML = i + ":";
+
+ var input = document.createElement("input");
+ input.min = session.cameraConstraints[i].min;
+ input.max = session.cameraConstraints[i].max;
+
+ if (parseFloat(input.min) == parseFloat(input.max)) {
+ continue;
+ }
+
+ if (getById("popupSelector_constraints_video").style.display == "none") {
+ getById("advancedOptionsCamera").style.display = "inline-block";
+ }
+
+ if (i in session.currentCameraConstraints) {
+ input.value = session.currentCameraConstraints[i];
+ label.innerHTML = i + ": " + session.currentCameraConstraints[i];
+ label.title = "Previously was: " + session.currentCameraConstraints[i];
+ input.title = "Previously was: " + session.currentCameraConstraints[i];
+ } else {
+ label.innerHTML = i;
+ }
+ if ("step" in session.cameraConstraints[i]) {
+ input.step = session.cameraConstraints[i].step;
+ }
+ input.type = "range";
+ input.dataset.keyname = i;
+ input.id = "constraints_" + i;
+ input.style = "display:block; width:100%;";
+ input.name = "constraints_" + i;
+
+
+ input.onchange = function(e) {
+ getById("label_" + e.target.dataset.keyname).innerHTML = e.target.dataset.keyname + ": " + e.target.value;
+ updateCameraConstraints(e.target.dataset.keyname, e.target.value);
+ };
+
+
+ getById("popupSelector_constraints_video").appendChild(label);
+ getById("popupSelector_constraints_video").appendChild(input);
+ } else if ((typeof session.cameraConstraints[i] === 'object') && (session.cameraConstraints[i] !== null)) {
+ if (i == "resizeMode") {
+ continue;
+ }
+
+ var div = document.createElement("div");
+ var label = document.createElement("label");
+ label.id = "label_" + i;
+ label.htmlFor = "constraints_" + i;
+ label.innerHTML = i + ":";
+ label.style = "display:inline-block; padding:0;margin: 15px 0px 29px;";
+ label.dataset.keyname = i;
+ var input = document.createElement("select");
+ var c = document.createElement("option");
+
+ if (session.cameraConstraints[i].length > 1) {
+ for (var opts in session.cameraConstraints[i]) {
+ log(opts);
+ var opt = new Option(session.cameraConstraints[i][opts], session.cameraConstraints[i][opts]);
+ input.options.add(opt);
+ if (i in session.currentCameraConstraints) {
+ if (session.cameraConstraints[i][opts] == session.currentCameraConstraints[i]) {
+ opt.selected = true;
+ }
+ }
+ }
+ } else if (i.toLowerCase == "torch") {
+ var opt = new Option("Off", false);
+ input.options.add(opt);
+ opt = new Option("On", true);
+ input.options.add(opt);
+ } else {
+ continue;
+ }
+
+ if (getById("popupSelector_constraints_video").style.display == "none") {
+ getById("advancedOptionsCamera").style.display = "inline-block";
+ }
+
+ input.id = "constraints_" + i;
+ input.className = "constraintCameraInput";
+ input.name = "constraints_" + i;
+ input.style = "display:inline; padding:2px; margin:0 10px;";
+ input.dataset.keyname = i;
+ input.onchange = function(e) {
+ //getById("label_"+e.target.dataset.keyname).innerHTML =e.target.dataset.keyname+": "+e.target.value;
+ updateCameraConstraints(e.target.dataset.keyname, e.target.value);
+ log(e.target.dataset.keyname, e.target.value);
+ };
+ getById("popupSelector_constraints_video").appendChild(div);
+ div.appendChild(label);
+ div.appendChild(input);
+ } else if (typeof session.cameraConstraints[i] === 'boolean') {
+
+ var div = document.createElement("div");
+ var label = document.createElement("label");
+ label.id = "label_" + i;
+ label.htmlFor = "constraints_" + i;
+ label.innerHTML = i + ":";
+ label.style = "display:inline-block; padding:0;margin: 15px 0px 29px;";
+ label.dataset.keyname = i;
+ var input = document.createElement("select");
+ var c = document.createElement("option");
+
+ var opt = new Option("Off", false);
+ input.options.add(opt);
+ opt = new Option("On", true);
+ input.options.add(opt);
+
+ if (getById("popupSelector_constraints_video").style.display == "none") {
+ getById("advancedOptionsCamera").style.display = "inline-block";
+ }
+
+ input.id = "constraints_" + i;
+ input.className = "constraintCameraInput";
+ input.name = "constraints_" + i;
+ input.style = "display:inline; padding:2px; margin:0 10px;";
+ input.dataset.keyname = i;
+ input.onchange = function(e) {
+ //getById("label_"+e.target.dataset.keyname).innerHTML =e.target.dataset.keyname+": "+e.target.value;
+ updateCameraConstraints(e.target.dataset.keyname, e.target.value);
+ log(e.target.dataset.keyname, e.target.value);
+ };
+ getById("popupSelector_constraints_video").appendChild(div);
+ div.appendChild(label);
+ div.appendChild(input);
+ }
+ } catch (e) {
+ errorlog(e);
+ }
+
+ }
+}
+
+function updateCameraConstraints(constraint, value = null) {
+ var track0 = session.streamSrc.getVideoTracks();
+ track0 = track0[0];
+ if (value == parseFloat(value)) {
+ value = parseFloat(value);
+ } else if (value == "true") {
+ value = true;
+ } else if (value == "false") {
+ value = false;
+ }
+ log({
+ advanced: [{
+ [constraint]: value
+ }]
+ });
+ track0.applyConstraints({
+ advanced: [{
+ [constraint]: value
+ }]
+ });
+ return;
+
+}
+
+function setupWebcamSelection(stream = null) {
+ log("setup webcam");
+
+ if (stream) {
+ log(getById("previewWebcam"));
+ session.streamSrc = stream;
+ getById("previewWebcam").srcObject = outboundAudioPipeline(session.streamSrc);
+ } else {
+ log("THIS IS NO STREAM??");
+ }
+
+ if (!session.videoElement) {
+ session.videoElement = getById("previewWebcam");
+ }
+
+ try {
+ return enumerateDevices().then(gotDevices).then(function() {
+
+ if (getById("webcamquality").elements && parseInt(getById("webcamquality").elements.namedItem("resolution").value) == 3) {
+ if (session.maxframerate===false){
+ session.maxframerate = 30;
+ session.maxframerate_q2 = true;
+ }
+ } else if (session.maxframerate_q2){
+ session.maxframerate = false;
+ session.maxframerate_q2 = false;
+ }
+
+ var audioSelect = getById('audioSource');
+ var videoSelect = getById('videoSourceSelect');
+ var outputSelect = getById('outputSource');
+
+ audioSelect.onchange = function() {
+
+ var gowebcam = getById("gowebcam");
+ if (gowebcam) {
+ gowebcam.disabled = true;
+ gowebcam.dataset.ready = "true";
+ gowebcam.style.backgroundColor = "#DDDDDD";
+ gowebcam.style.fontWeight = "normal";
+ gowebcam.innerHTML = "Waiting for Camera to load";
+ miniTranslate(gowebcam, "waiting-for-camera-to-load");
+ }
+ activatedPreview = false;
+ grabAudio();
+ };
+ videoSelect.onchange = function() {
+
+ var gowebcam = getById("gowebcam");
+ if (gowebcam) {
+ gowebcam.disabled = true;
+ gowebcam.dataset.ready = "true";
+ gowebcam.style.backgroundColor = "#DDDDDD";
+ gowebcam.style.fontWeight = "normal";
+ gowebcam.innerHTML = "Waiting for Camera to load";
+ miniTranslate(gowebcam, "waiting-for-camera-to-load");
+ }
+ warnlog("video source changed");
+
+ activatedPreview = false;
+ if (session.quality !== false) {
+ grabVideo(session.quality);
+ } else {
+ session.quality_wb = parseInt(getById("webcamquality").elements.namedItem("resolution").value);
+ grabVideo(session.quality_wb);
+ }
+ };
+
+ outputSelect.onchange = function() {
+
+ if ((iOS) || (iPad)) {
+ return;
+ }
+ try{
+ session.sink = outputSelect.options[outputSelect.selectedIndex].value;
+ } catch(e){errorlog(e);}
+
+ if (!session.sink){return;}
+
+ try{
+ getById("previewWebcam").setSinkId(session.sink).then(() => {
+ log("New Output Device:" + session.sink);
+ }).catch(error => {
+ errorlog("6597");
+ errorlog(error);
+ //setTimeout(function(){warnUser("Failed to change audio output destination.");},1);
+ });
+ } catch(e){errorlog(e);}
+ }
+
+ getById("webcamquality").onchange = function() {
+ var gowebcam = getById("gowebcam");
+ if (gowebcam) {
+ gowebcam.disabled = true;
+ gowebcam.dataset.ready = "true";
+ gowebcam.style.backgroundColor = "#DDDDDD";
+ gowebcam.style.fontWeight = "normal";
+ gowebcam.innerHTML = "Waiting for Camera to load";
+ miniTranslate(gowebcam, "waiting-for-camera-to-load");
+ }
+
+ if (parseInt(getById("webcamquality").elements.namedItem("resolution").value) == 2) {
+ if (session.maxframerate===false){
+ session.maxframerate = 30;
+ session.maxframerate_q2 = true;
+ }
+ } else if (session.maxframerate_q2){
+ session.maxframerate = false;
+ session.maxframerate_q2 = false;
+ }
+
+ activatedPreview = false;
+ session.quality_wb = parseInt(getById("webcamquality").elements.namedItem("resolution").value);
+ grabVideo(session.quality_wb);
+ };
+
+ if ((session.audioDevice) && (session.audioDevice !== 1)) { // change from Auto to Selected Audio Device
+ log("SETTING AUDIO DEVICE!!");
+ activatedPreview = false;
+ grabAudio();
+ }
+
+ if (session.videoDevice === 0) {
+ if (session.autostart) {
+ publishWebcam(); // no need to mirror as there is no video...
+ return;
+ } else {
+ var gowebcam = getById("gowebcam");
+ if (gowebcam) {
+ gowebcam.disabled = false;
+ gowebcam.dataset.ready = "true";
+ gowebcam.innerHTML = "START";
+ miniTranslate(gowebcam, "start");
+ }
+ return;
+ }
+ } else {
+ log("GRabbing video: " + session.quality);
+ activatedPreview = false;
+ if (session.quality !== false) {
+ grabVideo(session.quality);
+ } else {
+ session.quality_wb = parseInt(getById("webcamquality").elements.namedItem("resolution").value);
+ grabVideo(session.quality_wb);
+ }
+ }
+
+ if ((iOS) || (iPad)) {
+ return;
+ }
+ try {
+ if (outputSelect.selectedIndex >= 0) {
+ session.sink = outputSelect.options[outputSelect.selectedIndex].value;
+ }
+ } catch(e){errorlog(e);}
+
+ if (document.getElementById("previewWebcam") && document.getElementById("previewWebcam").setSinkId) {
+ if (session.sink) {
+ getById("previewWebcam").setSinkId(session.sink).then(() => {}).catch(error => {
+ warnlog("6665");
+ warnlog(error);
+ });
+ }
+ }
+
+ }).catch(e => {
+ errorlog(e);
+ });
+ } catch (e) {
+ errorlog(e);
+ }
+}
+
+Promise.wait = function(ms) {
+ return new Promise(function(resolve) {
+ setTimeout(resolve, ms);
+ });
+};
+
+Promise.prototype.timeout = function(ms) {
+ return Promise.race([
+ this, Promise.wait(ms).then(function() {
+ var errormsg = new Error("Time Out\nDid you accept camera permissions in time? Please do so first.\n\nOtherwise, do you have NDI Tools installed? Maybe try uninstalling it.\n\nPlease also ensure your camera and audio device are correctly connected and not already in use. You may also need to refresh the page.");
+ errormsg.name = "timedOut";
+ errormsg.message = "Time Out\nDid you accept camera permissions in time? Please do so first.\n\nOtherwise, do you have NDI Tools installed? Maybe try uninstalling it.\n\nPlease also ensure your camera and audio device are correctly connected and not already in use. You may also need to refresh the page."
+ throw errormsg;
+
+ })
+ ])
+};
+
+
+function shareWebsite(autostart=false){
+
+ if (session.iframeSrc){
+ session.iframeSrc = false;
+ session.iframeEle = null;
+ getById("websitesharetoggle").classList.add("la-window-maximize");
+ getById("websitesharetoggle").classList.remove("la-window-close");
+
+ getById("websitesharebutton").classList.remove("float2");
+ getById("websitesharebutton").classList.add("float");
+
+ var data = {};
+ data.iframeSrc = false;
+ for (var UUID in session.pcs){
+ if (session.pcs[UUID].allowIframe===true){
+ session.sendMessage(data, UUID);
+ }
+ }
+ return
+ }
+ if (autostart===false){
+ window.focus();
+ var iframeURL = prompt("Enter a website URL to share", "https://www.youtube.com/watch?v=dQw4w9WgXcQ");
+ } else {
+ var iframeURL = autostart;
+ }
+ if (!iframeURL){
+ return;
+ }
+ if (iframeURL == session.iframeSrc){return;}
+
+ if (!(iframeURL.startsWith("https://") || iframeURL.startsWith("http://"))){
+ iframeURL = "https://"+iframeURL;
+ }
+
+ var domain = new URL(iframeURL);
+ domain = domain.hostname;
+ log(domain);
+ if ((domain=="www.youtube.com") || (domain=="youtube.com")){
+ var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/;
+ var match = iframeURL.match(regExp);
+ var vidid = (match&&match[7].length==11)? match[7] : false;
+
+ if(vidid){
+ iframeURL = "https://www.youtube.com/embed/"+vidid+"?autoplay=1&modestbranding=1";
+ log(iframeURL);
+ }
+ } else if (domain=="www.twitch.tv"){
+ var vidid = iframeURL.split('/').pop().split('#')[0].split('?')[0];
+ if (vidid){
+ iframeURL = "https://player.twitch.tv/?channel="+vidid+"&parent="+location.hostname;
+ log(iframeURL);
+ }
+ } else if (domain=="twitch.tv"){
+ var vidid = iframeURL.split('/').pop().split('#')[0].split('?')[0];
+ if (vidid){
+ iframeURL = "https://player.twitch.tv/?channel="+vidid+"&parent="+location.hostname;
+ log(iframeURL);
+ }
+ }
+
+
+
+ session.iframeSrc = iframeURL;
+
+ var iframe = document.createElement("iframe");
+ iframe.allow="autoplay;camera;microphone;fullscreen;picture-in-picture";
+ iframe.allowtransparency="true";
+ iframe.allowfullscreen ="true";
+ iframe.src = session.iframeSrc;
+ iframe.id = "iframe_source"
+ session.iframeEle = iframe;
+
+ getById("websitesharetoggle").classList.remove("la-window-maximize");
+ getById("websitesharetoggle").classList.add("la-window-close");
+
+ getById("websitesharebutton").classList.add("float2");
+ getById("websitesharebutton").classList.remove("float");
+
+ var data = {};
+ data.iframeSrc = iframeURL;
+ for (var UUID in session.pcs){
+ if (session.pcs[UUID].allowIframe===true){
+ session.sendMessage(data, UUID);
+ }
+ }
+}
+
+function createIframePopup() {
+
+ if (session.screenShareElement) {
+ session.screenShareElement.contentWindow.postMessage({
+ "close": true
+ }, '*');
+ session.screenShareElement.parentNode.removeChild(session.screenShareElement);
+ session.screenShareElement = false;
+ updateMixer();
+ getById("screenshare2button").classList.add("float");
+ getById("screenshare2button").classList.remove("float2");
+ return;
+ }
+
+ if (session.queue || session.transferred){
+ getById("screenshare2button").classList.add("advanced");
+ getById("screensharebutton").classList.remove("advanced");
+ toggleScreenShare();
+ return;
+ } // can't secondary-screen share if in a queue.
+
+ if (session.screenshareid) {
+ var iFrameID = session.screenshareid;
+ } else {
+ var iFrameID = session.streamID.substring(0, 12) + "_" + session.generateStreamID(5);
+ }
+
+ if (session.exclude) {
+ session.exclude.push(iFrameID);
+ } else {
+ session.exclude = [];
+ session.exclude.push(iFrameID);
+ }
+
+ var iframe = document.createElement("iframe");
+ iframe.allow = "autoplay";
+ iframe.allowtransparency = "true";
+
+ var extras = "";
+ if (session.password){
+ extras += "&password=" + session.password; // encodeURIComponent(
+ }
+
+ if (session.privacy){
+ extras += "&privacy";
+ }
+
+ if (session.screensharequality!==false){
+ extras += "&q="+session.screensharequality;
+ } else if (session.quality){
+ extras += "&q="+session.quality;
+ } else {
+ extras += "&q=0";
+ }
+
+ if (session.screensharefps!==false){
+ extras += "&maxframerate="+session.screensharefps;
+ }
+
+ if (session.muted){
+ iframe.src = "./?audiodevice=1&screenshare&transparent&cleanish&noheader&autostart&view&muted&room=" + session.roomid + "&push=" + iFrameID + extras;
+ } else {
+ iframe.src = "./?audiodevice=1&screenshare&transparent&cleanish&noheader&autostart&view&room=" + session.roomid + "&push=" + iFrameID + extras;
+ }
+
+ iframe.style.width = "100%";
+ iframe.style.height = "100%";
+ iframe.style.overflow = "hidden";
+ iframe.id = "screensharesource";
+ iframe.style.zIndex = "0";
+
+
+ session.screenShareElement = iframe;
+ session.screenShareElement.dataset.doNotMove = true;
+
+
+ document.getElementById("main").appendChild(iframe);
+
+
+ updateMixer();
+ getById("screenshare2button").classList.add("float2");
+ getById("screenshare2button").classList.remove("float");
+
+ return; // ignore the rest.
+}
+
+function previewWebcam() {
+
+ if (session.taintedSession === null) {
+ log("STILL WAITING ON HASH TO VALIDATE");
+ setTimeout(function() {
+ previewWebcam();
+ }, 1000);
+ return;
+ } else if (session.taintedSession === true) {
+ warnlog("HASH FAILED; PASSWORD NOT VALID");
+ return;
+ } else {
+ log("NOT TAINTED");
+ }
+
+ if (activatedPreview == true) {
+ log("activeated preview return 1");
+ return;
+ }
+ activatedPreview = true;
+
+ if (session.audioDevice === 0) { // OFF
+ var constraint = {
+ audio: false
+ };
+ } else if ((session.echoCancellation !== false) && (session.autoGainControl !== false) && (session.noiseSuppression !== false)) { // AUTO
+ var constraint = {
+ audio: true
+ };
+ } else { // Disable Echo Cancellation and stuff for the PREVIEW (DEFAULT CAM/MIC)
+ var constraint = {
+ audio: {}
+ };
+ if (session.echoCancellation !== false) { // if not disabled, we assume it's on
+ constraint.audio.echoCancellation = true;
+ } else {
+ constraint.audio.echoCancellation = false;
+ }
+ if (session.autoGainControl !== false) {
+ constraint.audio.autoGainControl = true;
+ } else {
+ constraint.audio.autoGainControl = false;
+ }
+ if (session.noiseSuppression !== false) {
+ constraint.audio.noiseSuppression = true;
+ } else {
+ constraint.audio.noiseSuppression = false;
+ }
+ }
+
+ if (session.videoDevice === 0) {
+ constraint.video = false;
+ } else {
+ constraint.video = true;
+ }
+
+ if ((constraint.video === false) && (constraint.audio === false)){
+
+ if (session.autostart) {
+ publishWebcam(); // no need to mirror as there is no video...
+ return;
+ } else {
+ var gowebcam = document.getElementById("gowebcam");
+ getById("getPermissions").style.display = "none";
+ if (gowebcam) {
+ gowebcam.style.display = "";
+ gowebcam.disabled = false;
+ gowebcam.dataset.ready = "true";
+ gowebcam.innerHTML = "START";
+ miniTranslate(gowebcam, "start");
+ }
+ }
+ return;
+ }
+
+ enumerateDevices().then(function(devices) {
+ log("enumeratated");
+ log(devices);
+ var vtrue = false;
+ var atrue = false;
+ devices.forEach(function(device) {
+ if (device.kind === 'audioinput') {
+ atrue = true;
+ } else if (device.kind === 'videoinput') {
+ vtrue = true;
+ }
+ });
+ if (atrue === false) {
+ constraint.audio = false;
+ }
+ if (vtrue === false) {
+ constraint.video = false;
+ }
+ setTimeout(function(constraint) {
+ requestBasicPermissions(constraint);
+ }, 0, constraint);
+ }).catch((error) => {
+ log("enumeratated failed. Seeking permissions.");
+ setTimeout(function(constraint) {
+ requestBasicPermissions(constraint);
+ }, 0, constraint);
+ });
+
+}
+
+function requestBasicPermissions(constraint = {
+ video: true
+ , audio: true
+}) {
+ if (session.taintedSession === null) {
+ log("STILL WAITING ON HASH TO VALIDATE");
+ setTimeout(function(constraint) {
+ requestBasicPermissions(constraint);
+ }, 1000, constraint);
+ return;
+ } else if (session.taintedSession === true) {
+ warnlog("HASH FAILED; PASSWORD NOT VALID");
+ return;
+ } else {
+ log("NOT TAINTED 1");
+ }
+ setTimeout(function() {
+ getById("getPermissions").style.display = "none";
+ getById("gowebcam").style.display = "";
+ }, 0);
+ log("REQUESTING BASIC PERMISSIONS");
+
+ try {
+ var timerBasicCheck = null;
+ if (!(session.cleanOutput)) {
+ log("Setting Timer for getUserMedia");
+ timerBasicCheck = setTimeout(function() {
+ if (!(session.cleanOutput)) {
+ warnUser("Camera Access Request Timed Out\nDid you accept camera permissions? Please do so first.\n\nOtherwise, do you have NDI Tools installed? Maybe try uninstalling NDI tools.\n\nPlease also ensure that your camera and audio devices are correctly connected and not already in use. You may also need to refresh the page.");
+ }
+ }, 10000);
+ }
+
+ if (session.audioInputChannels) {
+ if (constraint.audio === true) {
+ constraint.audio = {};
+ constraint.audio.channelCount = session.audioInputChannels;
+ } else if (constraint.audio) {
+ constraint.audio.channelCount = session.audioInputChannels;
+ }
+ }
+
+ log("CONSTRAINT");
+ log(constraint);
+ navigator.mediaDevices.getUserMedia(constraint).then(function(stream) { // Apple needs thi to happen before I can access EnumerateDevices.
+ log("got first stream");
+ clearTimeout(timerBasicCheck);
+ setupWebcamSelection(stream);
+ }).catch(function(err) {
+ clearTimeout(timerBasicCheck);
+ warnlog("some error with GetUSERMEDIA");
+ errorlog(err); /* handle the error */
+ if (err.name == "NotFoundError" || err.name == "DevicesNotFoundError") {
+ //required track is missing
+ } else if (err.name == "NotReadableError" || err.name == "TrackStartError") {
+ //webcam or mic are already in use
+ } else if (err.name == "OverconstrainedError" || err.name == "ConstraintNotSatisfiedError") {
+ //constraints can not be satisfied by avb. devices
+ } else if (err.name == "NotAllowedError" || err.name == "PermissionDeniedError") {
+ //permission denied in browser
+ if (!(session.cleanOutput)) {
+ setTimeout(function() {
+ warnUser("Permissions denied. Please ensure you have allowed the mic/camera permissions.");
+ }, 1);
+ }
+ return;
+ } else if (err.name == "TypeError" || err.name == "TypeError") {
+ //empty constraints object
+ } else {
+ //permission denied in browser
+ if (!(session.cleanOutput)) {
+ setTimeout(function() {
+ warnUser(err);
+ }, 1);
+ }
+ }
+ errorlog("trying to list webcam again");
+ setupWebcamSelection();
+ });
+ } catch (e) {
+ errorlog(e);
+ if (!(session.cleanOutput)) {
+ if (window.isSecureContext) {
+ warnUser("An error has occured when trying to access the webcam or microphone. The reason is not known.");
+ } else if ((iOS) || (iPad)) {
+ warnUser("iOS version 13.4 and up is generally recommended; older than iOS 11 is not supported.");
+ } else {
+ warnUser("Error acessing camera or microphone.\n\nThe website may be loaded in an insecure context.\n\nPlease see: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia");
+ }
+ }
+ }
+}
+
+
+function copyFunction(copyText) {
+
+ try {
+ copyText.select();
+ copyText.setSelectionRange(0, 99999);
+ document.execCommand("copy");
+ } catch (e) {
+ var dummy = document.createElement('input');
+ document.body.appendChild(dummy);
+ dummy.value = copyText;
+ dummy.select();
+ document.execCommand('copy');
+ document.body.removeChild(dummy);
+ return false;
+ }
+}
+
+function generateQRPage() {
+ var pass = sanitizePassword(getById("invite_password").value);
+ if (pass.length) {
+ return session.generateHash(pass + session.salt, 4).then(function(hash) {
+ generateQRPageCallback(hash);
+ });
+ } else {
+ generateQRPageCallback("");
+ }
+}
+
+function updateLinkWebP(arg, input) {
+ if (input.checked){
+ if (!((getById("director_block_" + arg).dataset.raw.includes("&broadcast")) || (getById("director_block_" + arg).dataset.raw.includes("?broadcast")))){
+ getById("broadcastSlider").checked=true;
+ updateLink(arg, getById("broadcastSlider"));
+ }
+ }
+ updateLink(arg, input);
+}
+
+function updateLink(arg, input) {
+ log(input.dataset.param);
+ if (input.checked) {
+
+ getById("director_block_" + arg).dataset.raw += input.dataset.param;
+
+ var string = getById("director_block_" + arg).dataset.raw;
+
+ if (getById("obfuscate_director_" + arg).checked) {
+ string = obfuscateURL(string);
+ }
+
+
+ getById("director_block_" + arg).href = string;
+ getById("director_block_" + arg).innerText = string;
+ } else {
+ var string = getById("director_block_" + arg).dataset.raw + "&";
+ string = string.replace(input.dataset.param + "&", "&");
+ string = string.substring(0, string.length - 1);
+ getById("director_block_" + arg).dataset.raw = string;
+
+ if (getById("obfuscate_director_" + arg).checked) {
+ string = obfuscateURL(string);
+ }
+
+ getById("director_block_" + arg).href = string;
+ getById("director_block_" + arg).innerText = string;
+ }
+ saveDirectorSettings();
+}
+
+
+function updateLinkInverse(arg, input) {
+ log(input.dataset.param);
+ if (!(input.checked)) {
+
+ getById("director_block_" + arg).dataset.raw += input.dataset.param;
+
+ var string = getById("director_block_" + arg).dataset.raw;
+
+ if (getById("obfuscate_director_" + arg).checked) {
+ string = obfuscateURL(string);
+ }
+
+
+ getById("director_block_" + arg).href = string;
+ getById("director_block_" + arg).innerText = string;
+ } else {
+ var string = getById("director_block_" + arg).dataset.raw + "&";
+ string = string.replace(input.dataset.param + "&", "&");
+ string = string.substring(0, string.length - 1);
+ getById("director_block_" + arg).dataset.raw = string;
+
+ if (getById("obfuscate_director_" + arg).checked) {
+ string = obfuscateURL(string);
+ }
+
+ getById("director_block_" + arg).href = string;
+ getById("director_block_" + arg).innerText = string;
+ }
+}
+
+function updateLinkScene(arg, input) {
+ var string = getById("director_block_" + arg).dataset.raw;
+
+ if (input.checked) {
+ string = changeParam(string, "scene", "0");
+ } else {
+ string = changeParam(string, "scene", "1");
+ }
+ getById("director_block_" + arg).dataset.raw = string;
+
+ if (getById("obfuscate_director_" + arg).checked) {
+ string = obfuscateURL(string);
+ }
+
+ getById("director_block_" + arg).href = string;
+ getById("director_block_" + arg).innerText = string;
+}
+
+function resetGen() {
+ getById("gencontent").style.display = "block";
+ getById("gencontent2").style.display = "none";
+ getById("gencontent2").className = ""; //container-inner
+ getById("gencontent").className = "container-inner"; //
+ getById("gencontent2").innerHTML = "";
+ getById("videoname4").focus();
+}
+
+function generateQRPageCallback(hash) {
+ try {
+ var title = getById("videoname4").value;
+ if (title.length) {
+ title = title.replace(/[\W]+/g, "_").replace(/_+/g, '_'); // but not what others might get.
+ title = "&label=" + title;
+ }
+ var sid = session.generateStreamID();
+
+ var viewstr = "";
+ var sendstr = "";
+
+ if (getById("invite_bitrate").checked) {
+ viewstr += "&bitrate=20000";
+ }
+ if (getById("invite_vp9").checked) {
+ viewstr += "&codec=vp9";
+ }
+ if (getById("invite_stereo").checked) {
+ viewstr += "&stereo";
+ sendstr += "&stereo";
+ }
+ if (getById("invite_automic").checked) {
+ sendstr += "&audiodevice=1";
+ }
+ if (getById("invite_hidescreen").checked) {
+ sendstr += "&webcam";
+ }
+
+ if (getById("invite_remotecontrol").checked) { //
+ var remote_gen_id = session.generateStreamID();
+ sendstr += "&remote=" + remote_gen_id; // security
+ viewstr += "&remote=" + remote_gen_id;
+ }
+
+ if (getById("invite_joinroom").value.trim().length) {
+ sendstr += "&room=" + getById("invite_joinroom").value.trim();
+ viewstr += "&scene&room=" + getById("invite_joinroom").value.trim();
+ }
+
+ if (getById("invite_password").value.trim().length) {
+ sendstr += "&hash=" + hash;
+ viewstr += "&password=" + getById("invite_password").value.trim();
+ }
+
+
+ if (getById("invite_group_chat_type").value) { // 0 is default
+ if (getById("invite_group_chat_type").value == 1) { // no video
+ sendstr += "&novideo";
+ } else if (getById("invite_group_chat_type").value == 2) { // no view or audio
+ sendstr += "&view";
+ }
+ }
+
+ if (getById("invite_quality").value) {
+ if (getById("invite_quality").value == 0) {
+ sendstr += "&quality=0";
+ } else if (getById("invite_quality").value == 1) {
+ sendstr += "&quality=1";
+ } else if (getById("invite_quality").value == 2) {
+ sendstr += "&quality=2";
+ }
+ }
+
+ var pie = "";
+ if (session.pie){
+ if (session.pie!==true){
+ pie = "&pie="+session.pie;
+ }
+ }
+
+ sendstr = 'https://' + location.host + location.pathname + '?push=' + sid + sendstr + title + pie;
+
+ if (getById("invite_obfuscate").checked) {
+ sendstr = obfuscateURL(sendstr);
+ }
+
+ viewstr = 'https://' + location.host + location.pathname + '?view=' + sid + viewstr + title + pie;
+ getById("gencontent").style.display = "none";
+ getById("gencontent").className = ""; //
+ getById("gencontent2").style.display = "block";
+ getById("gencontent2").className = "container-inner"; //
+ getById("gencontent2").innerHTML = ' \
+ and don\'t forget theOBS Browser Source Link: ' + viewstr + ' \
+ \
+ This invite link and OBS ingestion link are reusable. Only one person may use a specific invite at a time. Create Another Invite Link ';
+ var qrcode = new QRCode(getById("qrcode"), {
+ width: 300
+ , height: 300
+ , colorDark: "#000000"
+ , colorLight: "#FFFFFF"
+ , useSVG: false
+ });
+ qrcode.makeCode(sendstr);
+ setTimeout(function() {
+ getById("qrcode").title = "";
+ if (getById("qrcode").getElementsByTagName('img').length) {
+ getById("qrcode").getElementsByTagName('img')[0].style.cursor = "none";
+ }
+ }, 100); // i really hate the title overlay that the qrcode function makes
+
+ } catch (e) {
+ errorlog(e);
+ }
+}
+
+
+if (session.view) {
+ getById("main").className = "";
+ getById("credits").style.display = 'none';
+ try {
+ if (session.label === false) {
+ if (document.title == "") {
+ document.title = "View=" + session.view.toString();
+ } else {
+ document.title += ", View=" + session.view.toString();
+ }
+ }
+ } catch (e) {
+ errorlog(e);
+ };
+}
+
+
+function initSceneList(UUID){
+ Object.keys(session.sceneList).forEach((scene, index) => {
+ if (getById("container_" + UUID).querySelectorAll('[data-scene="'+scene+'"]').length){return;} // already exists.
+ var newScene = document.createElement("div");
+ newScene.innerHTML = ' Scene: '+scene+' ';
+ getById("container_" + UUID).appendChild(newScene);
+ });
+}
+
+function updateSceneList(scene){
+ if (!session.director){return;}
+ if (scene in session.sceneList){return;}
+ if ((parseInt(scene)+"")===scene){
+ if ((parseInt(scene)>=0) && (parseInt(scene)<=8)){
+ return;
+ }
+ }
+ session.sceneList[scene] = true;
+ for (var UUID in session.rpcs){
+ var newScene = document.createElement("span");
+ newScene.innerHTML = ' Scene: '+scene+' ';
+ getById("container_" + UUID).appendChild(newScene);
+ }
+
+ if (session.showDirector){
+ if (document.getElementById("container_director")){
+ var newScene = document.createElement("div");
+ newScene.innerHTML = ' Scene: '+scene+' ';
+ getById("container_director").appendChild(newScene);
+ }
+ }
+}
+
+function safariVersion() {
+ try {
+ var ver = navigator.appVersion.split("Version/");
+ if (ver.length > 1) {
+ ver = ver[1].split(" Safari");
+ }
+ if (ver.length > 1) {
+ ver = ver[0].split(".");
+ }
+ if (ver.length > 1) {
+ ver = parseInt(ver[0]);
+ } else {
+ ver = 0;
+ }
+ } catch (e) {
+ return 0;
+ }
+ return ver;
+}
+
+if ((session.view) && (session.roomid === false)) {
+ getById("container-4").className = 'column columnfade';
+ getById("container-3").className = 'column columnfade';
+ getById("container-2").className = 'column columnfade';
+ getById("container-1").className = 'column columnfade';
+ //getById("header").className = 'advanced';
+ getById("info").className = 'advanced';
+ getById("header").className = 'advanced';
+ getById("head1").className = 'advanced';
+ getById("head2").className = 'advanced';
+ getById("head3").className = 'advanced';
+
+
+ getById("mainmenu").style.backgroundRepeat = "no-repeat";
+ getById("mainmenu").style.backgroundPosition = "bottom center";
+ getById("mainmenu").style.minHeight = "300px";
+ getById("mainmenu").style.backgroundSize = "100px 100px";
+ getById("mainmenu").innerHTML = '';
+
+ setTimeout(function() {
+ try {
+ if ((session.view) && (!(session.cleanOutput))) {
+ if (document.getElementById("mainmenu")) {
+ getById("mainmenu").style.backgroundImage = "url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8c3ZnIHdpZHRoPSI0MHB4IiBoZWlnaHQ9IjQwcHgiIHZpZXdCb3g9IjAgMCA0MCA0MCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWw6c3BhY2U9InByZXNlcnZlIiBzdHlsZT0iZmlsbC1ydWxlOmV2ZW5vZGQ7Y2xpcC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjEuNDE0MjE7IiB4PSIwcHgiIHk9IjBweCI+CiAgICA8ZGVmcz4KICAgICAgICA8c3R5bGUgdHlwZT0idGV4dC9jc3MiPjwhW0NEQVRBWwogICAgICAgICAgICBALXdlYmtpdC1rZXlmcmFtZXMgc3BpbiB7CiAgICAgICAgICAgICAgZnJvbSB7CiAgICAgICAgICAgICAgICAtd2Via2l0LXRyYW5zZm9ybTogcm90YXRlKDBkZWcpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHRvIHsKICAgICAgICAgICAgICAgIC13ZWJraXQtdHJhbnNmb3JtOiByb3RhdGUoLTM1OWRlZykKICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICAgICAgQGtleWZyYW1lcyBzcGluIHsKICAgICAgICAgICAgICBmcm9tIHsKICAgICAgICAgICAgICAgIHRyYW5zZm9ybTogcm90YXRlKDBkZWcpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICAgIHRvIHsKICAgICAgICAgICAgICAgIHRyYW5zZm9ybTogcm90YXRlKC0zNTlkZWcpCiAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgICAgIHN2ZyB7CiAgICAgICAgICAgICAgICAtd2Via2l0LXRyYW5zZm9ybS1vcmlnaW46IDUwJSA1MCU7CiAgICAgICAgICAgICAgICAtd2Via2l0LWFuaW1hdGlvbjogc3BpbiAxLjVzIGxpbmVhciBpbmZpbml0ZTsKICAgICAgICAgICAgICAgIC13ZWJraXQtYmFja2ZhY2UtdmlzaWJpbGl0eTogaGlkZGVuOwogICAgICAgICAgICAgICAgYW5pbWF0aW9uOiBzcGluIDEuNXMgbGluZWFyIGluZmluaXRlOwogICAgICAgICAgICB9CiAgICAgICAgXV0+PC9zdHlsZT4KICAgIDwvZGVmcz4KICAgIDxnIGlkPSJvdXRlciI+CiAgICAgICAgPGc+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMCwwQzIyLjIwNTgsMCAyMy45OTM5LDEuNzg4MTMgMjMuOTkzOSwzLjk5MzlDMjMuOTkzOSw2LjE5OTY4IDIyLjIwNTgsNy45ODc4MSAyMCw3Ljk4NzgxQzE3Ljc5NDIsNy45ODc4MSAxNi4wMDYxLDYuMTk5NjggMTYuMDA2MSwzLjk5MzlDMTYuMDA2MSwxLjc4ODEzIDE3Ljc5NDIsMCAyMCwwWiIgc3R5bGU9ImZpbGw6YmxhY2s7Ii8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8cGF0aCBkPSJNNS44NTc4Niw1Ljg1Nzg2QzcuNDE3NTgsNC4yOTgxNSA5Ljk0NjM4LDQuMjk4MTUgMTEuNTA2MSw1Ljg1Nzg2QzEzLjA2NTgsNy40MTc1OCAxMy4wNjU4LDkuOTQ2MzggMTEuNTA2MSwxMS41MDYxQzkuOTQ2MzgsMTMuMDY1OCA3LjQxNzU4LDEzLjA2NTggNS44NTc4NiwxMS41MDYxQzQuMjk4MTUsOS45NDYzOCA0LjI5ODE1LDcuNDE3NTggNS44NTc4Niw1Ljg1Nzg2WiIgc3R5bGU9ImZpbGw6cmdiKDIxMCwyMTAsMjEwKTsiLz4KICAgICAgICA8L2c+CiAgICAgICAgPGc+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMCwzMi4wMTIyQzIyLjIwNTgsMzIuMDEyMiAyMy45OTM5LDMzLjgwMDMgMjMuOTkzOSwzNi4wMDYxQzIzLjk5MzksMzguMjExOSAyMi4yMDU4LDQwIDIwLDQwQzE3Ljc5NDIsNDAgMTYuMDA2MSwzOC4yMTE5IDE2LjAwNjEsMzYuMDA2MUMxNi4wMDYxLDMzLjgwMDMgMTcuNzk0MiwzMi4wMTIyIDIwLDMyLjAxMjJaIiBzdHlsZT0iZmlsbDpyZ2IoMTMwLDEzMCwxMzApOyIvPgogICAgICAgIDwvZz4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggZD0iTTI4LjQ5MzksMjguNDkzOUMzMC4wNTM2LDI2LjkzNDIgMzIuNTgyNCwyNi45MzQyIDM0LjE0MjEsMjguNDkzOUMzNS43MDE5LDMwLjA1MzYgMzUuNzAxOSwzMi41ODI0IDM0LjE0MjEsMzQuMTQyMUMzMi41ODI0LDM1LjcwMTkgMzAuMDUzNiwzNS43MDE5IDI4LjQ5MzksMzQuMTQyMUMyNi45MzQyLDMyLjU4MjQgMjYuOTM0MiwzMC4wNTM2IDI4LjQ5MzksMjguNDkzOVoiIHN0eWxlPSJmaWxsOnJnYigxMDEsMTAxLDEwMSk7Ii8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8cGF0aCBkPSJNMy45OTM5LDE2LjAwNjFDNi4xOTk2OCwxNi4wMDYxIDcuOTg3ODEsMTcuNzk0MiA3Ljk4NzgxLDIwQzcuOTg3ODEsMjIuMjA1OCA2LjE5OTY4LDIzLjk5MzkgMy45OTM5LDIzLjk5MzlDMS43ODgxMywyMy45OTM5IDAsMjIuMjA1OCAwLDIwQzAsMTcuNzk0MiAxLjc4ODEzLDE2LjAwNjEgMy45OTM5LDE2LjAwNjFaIiBzdHlsZT0iZmlsbDpyZ2IoMTg3LDE4NywxODcpOyIvPgogICAgICAgIDwvZz4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggZD0iTTUuODU3ODYsMjguNDkzOUM3LjQxNzU4LDI2LjkzNDIgOS45NDYzOCwyNi45MzQyIDExLjUwNjEsMjguNDkzOUMxMy4wNjU4LDMwLjA1MzYgMTMuMDY1OCwzMi41ODI0IDExLjUwNjEsMzQuMTQyMUM5Ljk0NjM4LDM1LjcwMTkgNy40MTc1OCwzNS43MDE5IDUuODU3ODYsMzQuMTQyMUM0LjI5ODE1LDMyLjU4MjQgNC4yOTgxNSwzMC4wNTM2IDUuODU3ODYsMjguNDkzOVoiIHN0eWxlPSJmaWxsOnJnYigxNjQsMTY0LDE2NCk7Ii8+CiAgICAgICAgPC9nPgogICAgICAgIDxnPgogICAgICAgICAgICA8cGF0aCBkPSJNMzYuMDA2MSwxNi4wMDYxQzM4LjIxMTksMTYuMDA2MSA0MCwxNy43OTQyIDQwLDIwQzQwLDIyLjIwNTggMzguMjExOSwyMy45OTM5IDM2LjAwNjEsMjMuOTkzOUMzMy44MDAzLDIzLjk5MzkgMzIuMDEyMiwyMi4yMDU4IDMyLjAxMjIsMjBDMzIuMDEyMiwxNy43OTQyIDMzLjgwMDMsMTYuMDA2MSAzNi4wMDYxLDE2LjAwNjFaIiBzdHlsZT0iZmlsbDpyZ2IoNzQsNzQsNzQpOyIvPgogICAgICAgIDwvZz4KICAgICAgICA8Zz4KICAgICAgICAgICAgPHBhdGggZD0iTTI4LjQ5MzksNS44NTc4NkMzMC4wNTM2LDQuMjk4MTUgMzIuNTgyNCw0LjI5ODE1IDM0LjE0MjEsNS44NTc4NkMzNS43MDE5LDcuNDE3NTggMzUuNzAxOSw5Ljk0NjM4IDM0LjE0MjEsMTEuNTA2MUMzMi41ODI0LDEzLjA2NTggMzAuMDUzNiwxMy4wNjU4IDI4LjQ5MzksMTEuNTA2MUMyNi45MzQyLDkuOTQ2MzggMjYuOTM0Miw3LjQxNzU4IDI4LjQ5MzksNS44NTc4NloiIHN0eWxlPSJmaWxsOnJnYig1MCw1MCw1MCk7Ii8+CiAgICAgICAgPC9nPgogICAgPC9nPgo8L3N2Zz4K')";
+ getById("mainmenu").innerHTML = 'Attempting to load video stream. ';
+ getById("mainmenu").innerHTML += 'The stream is not available yet or an error occured. Retry Manually ';
+
+ }
+ }
+ } catch (e) {
+ errorlog("Error handling QR Code failure");
+ }
+ }, 15000);
+
+ log("auto playing");
+ var SafariVer = safariVersion();
+ if ((iPad || iOS) && navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1 && SafariVer > 13) { // Modern iOS doesn't need pop up
+ play();
+ } else if (navigator.userAgent.indexOf('Safari') != -1 && navigator.userAgent.indexOf('Chrome') == -1) { // Safari on Desktop does require pop up
+ if (!(session.cleanOutput)) {
+ warnUser("Safari requires us to ask for an audio permission to use peer-to-peer technology. You will need to accept it in a moment if asked to view this live video", 20000);
+ }
+ navigator.mediaDevices.getUserMedia({
+ audio: true
+ }).then(function() {
+ closeModal();
+ play();
+ }).catch(function() {
+ play();
+ });
+ } else { // everything else is OK.
+ play();
+ }
+} else if (session.roomid) {
+ try {
+ if (session.label === false) {
+ if (document.title == "") {
+ document.title = "Room=" + session.roomid.toString();
+ } else {
+ document.title += ": " + session.roomid.toString();
+ }
+ }
+ } catch (e) {
+ errorlog(e);
+ };
+
+}
+
+
+var vis = (function() {
+ var stateKey, eventKey, keys = {
+ hidden: "visibilitychange"
+ , webkitHidden: "webkitvisibilitychange"
+ , mozHidden: "mozvisibilitychange"
+ , msHidden: "msvisibilitychange"
+ };
+ for (stateKey in keys) {
+ if (stateKey in document) {
+ eventKey = keys[stateKey];
+ break;
+ }
+ }
+ return function(c) {
+ if (c) {
+ document.addEventListener(eventKey, c);
+ //document.addEventListener("blur", c);
+ //document.addEventListener("focus", c);
+ }
+ return !document[stateKey];
+ };
+})();
+
+(function rightclickmenuthing() { // right click menu
+ "use strict";
+
+ function clickInsideElement(e, className) {
+ var el = e.srcElement || e.target;
+
+ if (el.classList.contains(className)) {
+ return el;
+ } else {
+ while (el = el.parentNode) {
+ if (el.classList && el.classList.contains(className)) {
+ return el;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ function getPosition(event2) {
+ var posx = 0;
+ var posy = 0;
+
+ if (!event2) var event = window.event;
+
+ if (event2.pageX || event2.pageY) {
+ posx = event2.pageX;
+ posy = event2.pageY;
+ } else if (event2.clientX || event2.clientY) {
+ posx = event2.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
+ posy = event2.clientY + document.body.scrollTop + document.documentElement.scrollTop;
+ }
+
+ return {
+ x: posx
+ , y: posy
+ };
+ }
+ var contextMenuClassName = "context-menu";
+ var contextMenuItemClassName = "context-menu__item";
+ var contextMenuLinkClassName = "context-menu__link";
+ var contextMenuActive = "context-menu--active";
+
+ var taskItemClassName = "task";
+ var taskItemInContext;
+
+ var clickCoords;
+ var clickCoordsX;
+ var clickCoordsY;
+
+ var menu = getById("context-menu");
+ var menuItems = menu.querySelectorAll(".context-menu__item");
+ var menuState = 0;
+ var menuWidth;
+ var menuHeight;
+ var menuPosition;
+ var menuPositionX;
+ var menuPositionY;
+
+ var windowWidth;
+ var windowHeight;
+
+ function init() {
+ contextListener();
+ clickListener();
+ keyupListener();
+ resizeListener();
+ }
+
+ function contextListener() {
+ document.addEventListener("contextmenu", function(e) {
+ taskItemInContext = clickInsideElement(e, taskItemClassName);
+
+ if (taskItemInContext) {
+ e.preventDefault();
+ toggleMenuOn();
+ positionMenu(e);
+ } else {
+ taskItemInContext = null;
+ toggleMenuOff();
+ }
+ });
+ }
+
+ function clickListener() {
+ document.addEventListener("click", function(e) {
+ var clickeElIsLink = clickInsideElement(e, contextMenuLinkClassName);
+
+ if (clickeElIsLink) {
+ e.preventDefault();
+ menuItemListener(clickeElIsLink);
+ } else {
+ var button = e.which || e.button;
+ if (button === 1) {
+ toggleMenuOff();
+ }
+ }
+ });
+ }
+
+ function keyupListener() {
+ window.onkeyup = function(e) {
+ // if ( e.keyCode === 27 ) {
+ // toggleMenuOff();
+ // }
+ if (e.altKey && e.shiftKey && e.keyCode === 67 /* C */) {
+ toggleControlBar();
+ }
+ };
+ }
+
+ function resizeListener() {
+ //window.onresize = function(e) {
+ // toggleMenuOff();
+ // };
+ }
+
+ function toggleMenuOn() {
+ if (menuState !== 1) {
+ menuState = 1;
+ menu.classList.add(contextMenuActive);
+ }
+ }
+
+ function toggleMenuOff() {
+ if (menuState !== 0) {
+ menuState = 0;
+ menu.classList.remove(contextMenuActive);
+ }
+ }
+
+ function toggleControlBar() {
+ if (getById("controlButtons").style.display != 'none') {
+ // Dont hardcode style here. Copy it over to data-style before changing to none;
+ getById("controlButtons").dataset.style = getById("controlButtons").style.display;
+ getById("controlButtons").style.display = 'none';
+ } else {
+ // Copy the style over from the data-style attribute.
+ getById("controlButtons").style.display = getById("controlButtons").dataset.style;
+ };
+ }
+
+ function positionMenu(e) {
+ clickCoords = getPosition(e);
+ clickCoordsX = clickCoords.x;
+ clickCoordsY = clickCoords.y;
+
+ menuWidth = menu.offsetWidth + 4;
+ menuHeight = menu.offsetHeight + 4;
+
+ windowWidth = window.innerWidth;
+ windowHeight = window.innerHeight;
+
+ if ((windowWidth - clickCoordsX) < menuWidth) {
+ menu.style.left = windowWidth - menuWidth + "px";
+ } else {
+ menu.style.left = clickCoordsX + "px";
+ }
+
+ if ((windowHeight - clickCoordsY) < menuHeight) {
+ menu.style.top = windowHeight - menuHeight + "px";
+ } else {
+ menu.style.top = clickCoordsY + "px";
+ }
+ }
+
+ function menuItemListener(link) {
+ if (link.getAttribute("data-action") == "Open") {
+ window.open(taskItemInContext.value);
+ } else {
+ // nothing needed
+ }
+ log("Task ID - " + taskItemInContext + ", Task action - " + link.getAttribute("data-action"));
+ toggleMenuOff();
+ }
+
+ init();
+
+})();
+
+document.addEventListener("dragstart", event => {
+ var url = event.target.href || event.target.value;
+ if (!url || !url.startsWith('https://')) return;
+ if (event.target.dataset.drag != "1") {
+ return;
+ }
+ //event.target.ondragend = function(){event.target.blur();}
+
+ var streamId = url.split('view=');
+ var label = url.split('label=');
+
+ if (session.label !== false) {
+ url += '&layer-name=' + session.label;
+ } else {
+ url += '&layer-name=OBS.Ninja';
+ }
+ if (streamId.length > 1) url += ': ' + streamId[1].split('&')[0];
+ if (label.length > 1) url += ' - ' + decodeURI(label[1].split('&')[0]);
+
+ try {
+ if (document.getElementById("videosource")) {
+ var video = getById('videosource');
+ if (typeof(video.videoWidth) == "undefined") {
+ url += '&layer-width=1920'; // this isn't always 100% correct, as the resolution can fluxuate, but it is probably good enough
+ url += '&layer-height=1080';
+ } else if ((parseInt(video.videoWidth) < 360) || (video.videoHeight < 640)) {
+ url += '&layer-width=1920'; // this isn't always 100% correct, as the resolution can fluxuate, but it is probably good enough
+ url += '&layer-height=1080';
+ } else {
+ url += '&layer-width=' + video.videoWidth; // this isn't always 100% correct, as the resolution can fluxuate, but it is probably good enough
+ url += '&layer-height=' + video.videoHeight;
+ }
+ } else {
+ url += '&layer-width=1920'; // this isn't always 100% correct, as the resolution can fluxuate, but it is probably good enough
+ url += '&layer-height=1080';
+ }
+ } catch (error) {
+ url += '&layer-width=1920'; // this isn't always 100% correct, as the resolution can fluxuate, but it is probably good enough
+ url += '&layer-height=1080';
+ }
+
+ event.dataTransfer.setDragImage( getById('dragImage'), 24, 24);
+ event.dataTransfer.setData("text/uri-list", encodeURI(url));
+ //event.dataTransfer.setData("url", encodeURI(url));
+
+});
+
+function popupMessage(e, message = "Copied to Clipboard") { // right click menu
+
+ var posx = 0;
+ var posy = 0;
+
+ if (!e) var e = window.event;
+
+ if (e.pageX || e.pageY) {
+ posx = e.pageX;
+ posy = e.pageY;
+ } else if (e.clientX || e.clientY) {
+ posx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
+ posy = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
+ }
+
+ posx += 10;
+
+
+ var menu = getById("messagePopup");
+ menu.innerHTML = "" + message + " ";
+ var menuState = 0;
+ var menuWidth;
+ var menuHeight;
+ var menuPosition;
+ var menuPositionX;
+ var menuPositionY;
+
+ var windowWidth;
+ var windowHeight;
+
+ if (menuState !== 1) {
+ menuState = 1;
+ menu.classList.add("context-menu--active");
+ }
+
+ menuWidth = menu.offsetWidth + 4;
+ menuHeight = menu.offsetHeight + 4;
+
+ windowWidth = window.innerWidth;
+ windowHeight = window.innerHeight;
+
+ if ((windowWidth - posx) < menuWidth) {
+ menu.style.left = windowWidth - menuWidth + "px";
+ } else {
+ menu.style.left = posx + "px";
+ }
+
+ if ((windowHeight - posy) < menuHeight) {
+ menu.style.top = windowHeight - menuHeight + "px";
+ } else {
+ menu.style.top = posy + "px";
+ }
+
+ function toggleMenuOff() {
+ if (menuState !== 0) {
+ menuState = 0;
+ menu.classList.remove("context-menu--active");
+ }
+ }
+ setTimeout(function() {
+ toggleMenuOff();
+ }, 1000);
+ event.preventDefault();
+}
+
+function timeSince(date) {
+
+ var seconds = Math.floor((new Date() - date) / 1000);
+
+ var interval = seconds / 31536000;
+
+ if (interval > 1) {
+ return Math.floor(interval) + " years";
+ }
+ interval = seconds / 2592000;
+ if (interval > 1) {
+ return Math.floor(interval) + " months";
+ }
+ interval = seconds / 86400;
+ if (interval > 1) {
+ return Math.floor(interval) + " days";
+ }
+ interval = seconds / 3600;
+ if (interval > 1) {
+ return Math.floor(interval) + " hours";
+ }
+ interval = seconds / 60;
+ if (interval > 1) {
+ return Math.floor(interval) + " minutes";
+ }
+ return "Seconds ago";
+}
+var chatUpdateTimeout = null;
+var messageList = []
+
+function sendChatMessage(chatMsg = false) { // filtered + visual
+ var data = {};
+ if (chatMsg === false) {
+ var msg = document.getElementById('chatInput').value;
+ } else {
+ var msg = chatMsg;
+ }
+ //msg = sanitizeChat(msg);
+ if (msg == "") {
+ return;
+ }
+
+ if (msg.trim()==="/list"){
+ var listMsg = null;
+ for (var UUID in session.rpcs){
+ if (session.rpcs[UUID].label){
+ listMsg = UUID+": "+session.rpcs[UUID].label
+ } else if (session.directorUUID === UUID){
+ listMsg = UUID+": Director";
+ } else {
+ listMsg = UUID+": Unknown User";
+ }
+ var data = {};
+ data.msg = listMsg;
+ data.label = false;
+ data.type = "alert";
+ data.time = Date.now();
+ messageList.push(data);
+ }
+ for (var UUID in session.pcs){
+ if (UUID in session.rpcs){continue;}
+ if (session.pcs[UUID].label){
+ listMsg = UUID+"; "+session.pcs[UUID].label
+ } else if (session.directorUUID === UUID){
+ listMsg = UUID+"; Director";
+ } else {
+ listMsg = UUID+"; Unknown User";
+ }
+ var data = {};
+ data.msg = listMsg;
+ data.label = false;
+ data.type = "alert";
+ data.time = Date.now();
+ messageList.push(data);
+ }
+ if (listMsg===null){
+ data.msg = "No other users are connected to you";
+ data.label = false;
+ data.type = "alert";
+ data.time = Date.now();
+ messageList.push(data);
+ }
+ } else if (msg.startsWith("\/msg ")){
+ var msg = msg.split("\/msg ")[1];
+ msg = msg.split(" ");
+ uid = msg.shift().toLowerCase();
+ msg = msg.join(" ");
+ if (msg == ""){return;}
+ var sent = false;
+ for (var UUID in session.rpcs){
+ if (UUID.startsWith(uid)){
+ sendChat(msg, UUID); // send message to peers
+ var data = {};
+ data.time = Date.now();
+ data.msg = sanitizeChat(msg); // this is what the other person should see
+ data.label = false;
+ data.type = "sent";
+ messageList.push(data);
+ sent=true;
+ } else if (session.rpcs[UUID].label && session.rpcs[UUID].label.toLowerCase().startsWith(uid)){
+ sendChat(msg, UUID); // send message to peers
+ var data = {};
+ data.time = Date.now();
+ data.msg = sanitizeChat(msg); // this is what the other person should see
+ data.label = false;
+ data.type = "sent";
+ messageList.push(data);
+ sent=true;
+ } else if ((session.directorUUID === UUID) && "director".startsWith(uid)){
+ sendChat(msg, UUID); // send message to peers
+ var data = {};
+ data.time = Date.now();
+ data.msg = sanitizeChat(msg); // this is what the other person should see
+ data.label = false;
+ data.type = "sent";
+ messageList.push(data);
+ sent=true;
+ }
+ }
+ for (var UUID in session.pcs){
+ if (UUID in session.rpcs){continue;}
+ if (UUID.startsWith(uid)){
+ sendChat(msg, UUID); // send message to peers
+ var data = {};
+ data.time = Date.now();
+ data.msg = sanitizeChat(msg); // this is what the other person should see
+ data.label = false;
+ data.type = "sent";
+ messageList.push(data);
+ sent=true;
+ } else if (session.pcs[UUID].label && session.pcs[UUID].label.toLowerCase().startsWith(uid)){
+ sendChat(msg, UUID); // send message to peers
+ var data = {};
+ data.time = Date.now();
+ data.msg = sanitizeChat(msg); // this is what the other person should see
+ data.label = false;
+ data.type = "sent";
+ messageList.push(data);
+ sent=true;
+ } else if ((session.directorUUID === UUID) && "director".startsWith(uid)){
+ sendChat(msg, UUID); // send message to peers
+ var data = {};
+ data.time = Date.now();
+ data.msg = sanitizeChat(msg); // this is what the other person should see
+ data.label = false;
+ data.type = "sent";
+ messageList.push(data);
+ sent=true;
+ }
+ }
+ if (sent == false){
+ var data = {};
+ data.msg = "No user found. Message not sent.";
+ data.label = false;
+ data.type = "alert";
+ data.time = Date.now();
+ messageList.push(data);
+ updateMessages();
+ return;
+ }
+ } else if (msg.startsWith("\/")){
+ data.msg = "Unknown command. Try '/list' or '/msg username message'.";
+ data.label = false;
+ data.type = "alert";
+ data.time = Date.now();
+ messageList.push(data);
+ updateMessages();
+ return;
+ } else if (session.directorChat===true){
+ if (session.directorUUID){
+ sendChat(msg, session.directorUUID); // send message to peers
+ var data = {};
+ data.time = Date.now();
+ data.msg = sanitizeChat(msg); // this is what the other person should see
+ data.label = false;
+ data.type = "sent";
+ messageList.push(data);
+ }
+ } else {
+ sendChat(msg); // send message to peers
+ data.time = Date.now();
+ data.msg = sanitizeChat(msg); // this is what the other person should see
+ data.label = false;
+ data.type = "sent";
+ messageList.push(data);
+ }
+ document.getElementById('chatInput').value = "";
+
+ messageList = messageList.slice(-100);
+ if (session.broadcastChannel !== false) {
+ log(session.broadcastChannel);
+ session.broadcastChannel.postMessage(data);
+ }
+ updateMessages();
+}
+
+function toggleQualityDirector(bitrate, UUID, ele = null) { // ele is specific to the button in the director's room
+ var eles = ele.parentNode.childNodes;
+ for (var i=0;i ";
+ } else {
+ data.label = "" + data.label + ": ";
+ }
+ label = label+":";
+ } else if (director) {
+ data.label = "Director: ";
+ label = "Director:";
+ } else {
+ if (session.director){
+ data.label = "Someone: ";
+ } else {
+ data.label = "";
+ }
+ label = "";
+ }
+ data.type = "recv";
+
+ if (overlay) {
+ if (!(session.cleanOutput && session.cleanish==false)){
+ var textOverlay = getById("overlayMsgs");
+ if (textOverlay) {
+ var spanOverlay = document.createElement("span");
+ spanOverlay.innerHTML = "" + label + " " + msg + " ";
+ textOverlay.appendChild(spanOverlay);
+ textOverlay.style.display = "block";
+ var showtime = msg.length * 200 + 3000;
+ if (showtime > 8000) {
+ showtime = 8000;
+ }
+ setTimeout(function(ele) {
+ ele.parentNode.removeChild(ele);
+ }, showtime, spanOverlay);
+ }
+ }
+ }
+
+ if (isIFrame) {
+ parent.postMessage({
+ "gotChat": data
+ }, "*");
+ }
+
+ if (session.chatbutton===false){return;} // messages can still appear as overlays ^
+
+ messageList.push(data);
+ messageList = messageList.slice(-100);
+
+ if (session.beepToNotify) {
+ playtone();
+ }
+ updateMessages();
+
+ if (session.chat == false) {
+ getById("chattoggle").className = "las la-comments my-float toggleSize puslate";
+ getById("chatbutton").className = "float";
+
+ if (getById("chatNotification").value) {
+ getById("chatNotification").value = getById("chatNotification").value + 1;
+ } else {
+ getById("chatNotification").value = 1;
+ }
+ getById("chatNotification").classList.add("notification");
+
+ }
+
+
+ if (session.broadcastChannel !== false) {
+ session.broadcastChannel.postMessage(data); /* send */
+ }
+
+}
+
+function updateClosedCaptions(msg, label, UUID) {
+ msg.counter = parseInt(msg.counter);
+ var transcript = sanitizeChat(msg.transcript); // keep it clean.
+ if (transcript == "") {
+ return;
+ }
+ transcript = transcript.toUpperCase();
+
+ if (label) {
+ label = sanitizeLabel(label);
+ label = "" + label + ": ";
+ } else {
+ label = "";
+ }
+
+ var textOverlay = getById("overlayMsgs");
+ if (textOverlay) {
+ if (document.getElementById(UUID + "_" + msg.counter)) {
+ var spanOverlay = document.getElementById(UUID + "_" + msg.counter);
+ } else {
+ var spanOverlay = document.createElement("span");
+ spanOverlay.id = UUID + "_" + msg.counter;
+ textOverlay.appendChild(spanOverlay);
+ textOverlay.style.height = "auto";
+ textOverlay.style.textAlign = "left";
+ textOverlay.style.display = "block";
+ textOverlay.style.position = "relative";
+ }
+ spanOverlay.innerHTML = label + transcript + " ";
+
+ spanOverlay.style.fontSize = (parseInt(session.labelsize || 100) / 100.0 * 4.5) + "vh";
+ spanOverlay.style.lineHeight = (parseInt(session.labelsize || 100) / 100 * 6) + "vh";
+ spanOverlay.style.margin = (parseInt(session.labelsize || 100) / 100.0 * 0.75) + "vh";
+
+ if (msg.isFinal) {
+ var showtime = 3000;
+ clearTimeout(spanOverlay.timeout);
+ spanOverlay.timeout = setTimeout(function(ele) {
+ ele.parentNode.removeChild(ele);
+ }, showtime, spanOverlay);
+ } else {
+ clearTimeout(spanOverlay.timeout);
+ spanOverlay.timeout = setTimeout(function(ele) {
+ ele.parentNode.removeChild(ele);
+ }, 30000, spanOverlay);
+ }
+
+ }
+}
+
+function updateMessages() {
+ if (session.chatbutton===false){return;}
+ document.getElementById("chatBody").innerHTML = "";
+ for (i in messageList) {
+
+ var time = timeSince(messageList[i].time) || "";
+ var msg = document.createElement("div");
+ //console.log(messageList[i].msg); // Display received messages for View-Only clients.
+ /////////////////////////////
+ if (messageList[i].type == "sent") {
+ msg.innerHTML = messageList[i].msg + " - " + time + " ";
+ msg.classList.add("outMessage");
+ } else if (messageList[i].type == "recv") {
+ var label = "";
+ if (messageList[i].label) {
+ label = messageList[i].label;
+ }
+ msg.innerHTML = label + messageList[i].msg + " - " + time + " ";
+ msg.classList.add("inMessage");
+ } else if (messageList[i].type == "alert") {
+ msg.innerHTML = messageList[i].msg + " - " + time + " ";
+ msg.classList.add("inMessage");
+ } else {
+ msg.innerHTML = messageList[i].msg;
+ msg.classList.add("outMessage");
+ }
+
+ document.getElementById("chatBody").appendChild(msg);
+ }
+ if (chatUpdateTimeout) {
+ clearInterval(chatUpdateTimeout);
+ }
+ document.getElementById("chatBody").scrollTop = document.getElementById("chatBody").scrollHeight;
+ chatUpdateTimeout = setTimeout(function() {
+ updateMessages();
+ }, 60000);
+}
+
+function EnterButtonChat(event) {
+ // Number 13 is the "Enter" key on the keyboard
+ var key = event.which || event.keyCode;
+ if (key === 13) {
+ // Cancel the default action, if needed
+ event.preventDefault();
+ // Trigger the button element with a click
+ sendChatMessage();
+ }
+}
+
+function showCustomizer(arg, ele) {
+ //getById("directorLinksButton").innerHTML=' LINKS (GUEST INVITES & SCENES) '
+ getById("showCustomizerButton1").style.backgroundColor = "";
+ getById("showCustomizerButton2").style.backgroundColor = "";
+ getById("showCustomizerButton3").style.backgroundColor = "";
+ getById("showCustomizerButton4").style.backgroundColor = "";
+ getById("showCustomizerButton1").style.boxShadow = "";
+ getById("showCustomizerButton2").style.boxShadow = "";
+ getById("showCustomizerButton3").style.boxShadow = "";
+ getById("showCustomizerButton4").style.boxShadow = "";
+
+
+ if (getById("customizeLinks" + arg).style.display != "none") {
+ getById("customizeLinks").style.display = "none";
+ getById("customizeLinks" + arg).style.display = "none";
+ } else {
+ //directorLinks").style.display="none";
+ getById("showCustomizerButton" + arg).style.backgroundColor = "#1e0000";
+ getById("showCustomizerButton" + arg).style.boxShadow = "inset 0px 0px 1px #b90000";
+ getById("customizeLinks1").style.display = "none";
+ getById("customizeLinks3").style.display = "none";
+ getById("customizeLinks").style.display = "block";
+ getById("customizeLinks" + arg).style.display = "block";
+ }
+}
+
+
+var defaultRecordingBitrate = false;
+
+function recordVideo(target, event, videoKbps = false) { // event.currentTarget,this.parentNode.parentNode.dataset.UUID
+
+ var UUID = target.dataset.UUID;
+ var video = session.rpcs[UUID].videoElement;
+ var audioKbps = false;
+
+ if (event === null) {
+ if (defaultRecordingBitrate === null) {
+ updateLocalRecordButton(UUID, -1);
+ //target.style.backgroundColor = null;
+ //target.innerHTML = ' record local ';
+ return;
+ }
+ } else if ((event.ctrlKey) || (event.metaKey)) {
+ updateLocalRecordButton(UUID, -3);
+ //target.innerHTML = ' ARMED ';
+ //target.style.backgroundColor = "#BF3F3F";
+ Callbacks.push([recordVideo, target, null, false]);
+ log("Record Video queued");
+ defaultRecordingBitrate = false;
+ return;
+ } else {
+ defaultRecordingBitrate = false;
+ }
+
+ log("Record Video Clicked");
+ if ("recording" in video) {
+ log("ALREADY RECORDING!");
+ //target.style.backgroundColor = null;
+ //target.innerHTML = ' record local ';
+ updateLocalRecordButton(UUID, -2);
+ video.recorder.stop();
+ session.requestRateLimit(35, UUID); // 100kbps
+ if (session.audiobitrate===false){
+ session.requestAudioRateLimit(-1,UUID);
+ }
+
+ var elements = document.querySelectorAll('[data-action-type="change-quality2"][data--u-u-i-d="' + UUID + '"]');
+ if (elements[0]) {
+ elements[0].classList.add("pressed");
+ }
+ var elements = document.querySelectorAll('[data-action-type="change-quality1"][data--u-u-i-d="' + UUID + '"]');
+ if (elements[0]) {
+ elements[0].classList.remove("pressed");
+ }
+ var elements = document.querySelectorAll('[data-action-type="change-quality3"][data--u-u-i-d="' + UUID + '"]');
+ if (elements[0]) {
+ elements[0].classList.remove("pressed");
+ }
+ return;
+ } else {
+ updateLocalRecordButton(UUID, 0);
+ //target.style.backgroundColor = "#FCC";
+ //target.innerHTML = " Download ";
+ video.recording = true;
+ }
+
+ video.recorder = {};
+
+ if (videoKbps == false) {
+ if (defaultRecordingBitrate == false) {
+ videoKbps = 4000; // 4mbps recording bitrate
+ window.focus();
+ videoKbps = prompt("Press OK to start recording. Press again to stop and download.\n\nWarning: Keep this browser tab active to continue recording.\n\nYou can change the default video bitrate if desired below (kbps)", videoKbps);
+ if (videoKbps === null) {
+ //target.style.backgroundColor = null;
+ //target.innerHTML = ' record local ';
+ updateLocalRecordButton(UUID, -1);
+ target.style.backgroundColor = "";
+ delete(video.recorder);
+ delete(video.recording);
+ defaultRecordingBitrate = null;
+ return;
+ }
+ videoKbps = parseInt(videoKbps);
+ defaultRecordingBitrate = videoKbps;
+ } else {
+ videoKbps = defaultRecordingBitrate;
+ }
+ }
+
+ if (videoKbps <= 0) {
+ audioKbps = videoKbps * (-1);
+ videoKbps = false;
+ if (session.audiobitrate===false){
+ if ((audioKbps>0) && (audioKbps>=128)){
+ session.requestAudioRateLimit(128,UUID); // no point going higher
+ } else if (audioKbps==0){
+ session.requestAudioRateLimit(256,UUID); // PCM
+ } else {
+ session.requestAudioRateLimit(parseInt(audioKbps),UUID); // exact? sure. why not.
+ }
+ }
+ } else if (videoKbps < 50) { // this just makes sure you can't set 0 on the record bitrate.
+ videoKbps = 50;
+ session.requestRateLimit(parseInt(videoKbps * 0.8), UUID); // 3200kbps transfer bitrate. Less than the recording bitrate, to avoid waste.
+ } else {
+ session.requestRateLimit(parseInt(videoKbps * 0.8), UUID); // 3200kbps transfer bitrate. Less than the recording bitrate, to avoid waste.
+
+ if (videoKbps>4000){
+ if (session.audiobitrate===false){
+ if (session.pcm){
+ session.requestAudioRateLimit(256,UUID);
+ } else {
+ session.requestAudioRateLimit(128,UUID);
+ }
+ }
+ } else if (videoKbps>2500){
+ if (session.audiobitrate===false){
+ if (session.pcm){
+ session.requestAudioRateLimit(256,UUID);
+ } else {
+ session.requestAudioRateLimit(80,UUID);
+ }
+ }
+ }
+
+ }
+
+ var timestamp = Date.now();
+ var filename = "";
+ if (session.rpcs[UUID].label || session.rpcs[UUID].streamID) {
+ filename = session.rpcs[UUID].label || session.rpcs[UUID].streamID;
+ filename = filename.replace(/[\W]+/g, "_");
+ filename = filename.substring(0, 200);
+ }
+
+ filename += "_" + timestamp.toString();
+
+ var cancell = false;
+ if (typeof video.srcObject === "undefined" || !video.srcObject) {
+ return;
+ }
+
+ const {readable, writable} = new TransformStream({
+ transform: (chunk, ctrl) => chunk.arrayBuffer().then(b => ctrl.enqueue(new Uint8Array(b)))
+ });
+ readable.pipeTo(streamSaver.createWriteStream(filename + '.webm'));
+ var writer = writable.getWriter();
+ video.recorder.writer = writer;
+ video.recorder.stop = function() {
+ if (!video.recording) {
+ errorlog("ALREADY STOPPED");
+ updateLocalRecordButton(UUID, -1);
+ return;
+ }
+ video.recording = false;
+ updateLocalRecordButton(UUID, -2);
+ try {
+ if (video.recorder.mediaRecorder.state !== "inactive") {
+ video.recorder.mediaRecorder.stop();
+ }
+ } catch (e) {
+ errorlog(e);
+ }
+
+ session.requestRateLimit(35, UUID); // 100kbps
+ if (session.audiobitrate===false){
+ session.requestAudioRateLimit(-1,UUID);
+ }
+ var elements = document.querySelectorAll('[data-action-type="change-quality2"][data--u-u-i-d="' + UUID + '"]');
+ if (elements[0]) {
+ elements[0].classList.add("pressed");
+ }
+ var elements = document.querySelectorAll('[data-action-type="change-quality1"][data--u-u-i-d="' + UUID + '"]');
+ if (elements[0]) {
+ elements[0].classList.remove("pressed");
+ }
+ var elements = document.querySelectorAll('[data-action-type="change-quality3"][data--u-u-i-d="' + UUID + '"]');
+ if (elements[0]) {
+ elements[0].classList.remove("pressed");
+ }
+
+ cancell = true;
+ // log('Recorded Blobs: ', recordedBlobs);
+ // download();
+ setTimeout(() => {
+ writer.close();
+ updateLocalRecordButton(UUID, -1);
+ delete(video.recorder);
+ delete(video.recording);
+ }, 1200);
+ };
+
+ let options = {};
+
+ if (videoKbps) {
+ options.mimeType = "video/webm";
+ if (session.pcm){
+ options.mimeType += ";codecs=pcm";
+ }
+ if (videoKbps < 1000) {
+ options.videoBitsPerSecond = parseInt(videoKbps * 1024); // 100 kbps audio
+ } else {
+ options.bitsPerSecond = parseInt(videoKbps * 1024); // 100 to 132 kbps audio
+ }
+ video.recorder.mediaRecorder = new MediaRecorder(video.srcObject, options);
+ } else {
+ options.mimeType = "audio/webm";
+ if (audioKbps == 0) {
+ if (MediaRecorder.isTypeSupported("audio/webm;codecs=pcm")) {
+ options.mimeType = "audio/webm;codecs=pcm";
+ }
+ } else {
+ options.bitsPerSecond = parseInt(audioKbps * 1024);
+ }
+ var stream = new MediaStream();
+ video.srcObject.getAudioTracks().forEach((track) => {
+ stream.addTrack(track, video.srcObject);
+ });
+ video.recorder.mediaRecorder = new MediaRecorder(stream, options);
+ }
+ log(options);
+
+ function download() {
+ const blob = new Blob(recordedBlobs, {
+ type: "video/webm"
+ });
+ const url = window.URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.style.display = 'none';
+ a.href = url;
+ a.download = filename + ".webm";
+ document.body.appendChild(a);
+ a.click();
+ setTimeout(() => {
+ document.body.removeChild(a);
+ window.URL.revokeObjectURL(url);
+ }, 100);
+ }
+
+ function handleDataAvailable(event) {
+ if (event.data && event.data.size > 0) {
+ //recordedBlobs.push(event.data);
+ writer.write(event.data); ////////////
+ if (video.recording) {
+ updateLocalRecordButton(UUID, (parseInt((Date.now() - timestamp) / 1000) || 0));
+ }
+ }
+ }
+
+ video.recorder.mediaRecorder.ondataavailable = handleDataAvailable;
+
+ video.recorder.mediaRecorder.onerror = function(event) {
+ errorlog(event);
+ video.recorder.stop();
+ session.requestRateLimit(35, UUID);
+ if (!(session.cleanOutput)) {
+ setTimeout(function() {
+ warnUser("an error occured with the media recorder; stopping recording");
+ }, 1);
+ }
+ };
+
+ video.srcObject.ended = function(event) {
+ video.recorder.stop();
+ session.requestRateLimit(35, UUID);
+ if (!(session.cleanOutput)) {
+ setTimeout(function() {
+ warnUser("stream ended! stopping recording");
+ }, 1);
+ }
+ };
+
+
+ setTimeout(function(v) {
+ v.recorder.mediaRecorder.start(1000);
+ }, 500, video); // 100ms chunks
+
+ return;
+}
+
+function updateRemoteRecordButton(UUID, recorder) {
+ var elements = document.querySelectorAll('[data-action-type="recorder-remote"][data--u-u-i-d="' + UUID + '"]');
+ if (elements[0]) {
+ var time = parseInt(recorder) || 0;
+ if (time == -3) {
+ elements[0].classList.remove("pressed");
+ elements[0].disabled = true;
+ elements[0].innerHTML = ' Not Supported';
+ if (!(session.cleanOutput)) {
+ setTimeout(function() {
+ warnUser('The remote browser does not support recording.\n\nPerhaps try local recording instead.');
+ }, 0);
+ }
+
+ } else if (time == -2) {
+ elements[0].classList.add("pressed");
+ elements[0].innerHTML = ' stopping...';
+ } else if (time == -1) {
+ elements[0].classList.remove("pressed");
+ elements[0].innerHTML = ' Record Remote ';
+ } else {
+ var minutes = Math.floor(time / 60);
+ var seconds = time - minutes * 60;
+ elements[0].classList.add("pressed");
+ elements[0].innerHTML = ' ' + minutes + "m : " + (seconds + "").padStart(2, '0') + "s";
+ }
+ }
+}
+
+function updateLocalRecordButton(UUID, recorder) {
+ var elements = document.querySelectorAll('[data-action-type="recorder-local"][data--u-u-i-d="' + UUID + '"]');
+ if (elements[0]) {
+ var time = parseInt(recorder) || 0;
+
+ //target.innerHTML = ' ARMED ';
+ //
+ if (time == -3) {
+ elements[0].classList.add("pressed");
+ elements[0].innerHTML = ' ARMED ';
+ elements[0].style.backgroundColor = "#BF3F3F";
+ } else if (time == -2) {
+ elements[0].classList.add("pressed");
+ elements[0].innerHTML = ' stopping...';
+ elements[0].style.backgroundColor = "";
+ } else if (time == -1) {
+ elements[0].classList.remove("pressed");
+ elements[0].innerHTML = ' Record Local ';
+ elements[0].style.backgroundColor = "";
+ } else {
+ var minutes = Math.floor(time / 60);
+ var seconds = time - minutes * 60;
+ elements[0].classList.add("pressed");
+ elements[0].innerHTML = ' ' + minutes + "m : " + (seconds + "").padStart(2, '0') + "s";
+ elements[0].style.backgroundColor = "";
+ }
+ }
+}
+
+function recordLocalVideoToggle() {
+ var ele = getById("recordLocalbutton");
+ if (ele.dataset.state == "0") {
+ ele.dataset.state = "1";
+ ele.style.backgroundColor = "red";
+ ele.innerHTML = ' ';
+ if ("recording" in session.videoElement) {
+
+ } else {
+ recordLocalVideo("start");
+ }
+
+ if (session.director){
+ var elements = document.querySelectorAll('[data-action-type="recorder-local"][data-sid="' + session.streamID + '"]');
+ if (elements[0]) {
+ elements[0].classList.add("pressed");
+ elements[0].innerHTML = ' Record ';
+ }
+ }
+
+ } else {
+ if ("recording" in session.videoElement) {
+ recordLocalVideo("stop");
+ }
+ ele.dataset.state = "0";
+ ele.style.backgroundColor = "";
+ ele.innerHTML = ' ';
+
+ if (session.director){
+ var elements = document.querySelectorAll('[data-action-type="recorder-local"][data-sid="' + session.streamID + '"]');
+ if (elements[0]) {
+ elements[0].classList.remove("pressed");
+ elements[0].innerHTML = ' Record ';
+ }
+ }
+ }
+
+}
+
+function setupSensorData(pollrate = 30) {
+ session.sensors = {};
+ session.sensors.data = {};
+ session.sensors.data.sensors = true;
+
+ if (window.Accelerometer) {
+ session.sensors.data.acc = {};
+ session.sensors.Accelerometer = new Accelerometer({
+ frequency: pollrate
+ });
+ session.sensors.Accelerometer.addEventListener('reading', e => {
+ session.sensors.data.acc.x = session.sensors.Accelerometer.x;
+ session.sensors.data.acc.y = session.sensors.Accelerometer.y;
+ session.sensors.data.acc.z = session.sensors.Accelerometer.z;
+ session.sensors.data.acc.t = parseInt(Math.round(session.sensors.Accelerometer.timestamp));
+ });
+ session.sensors.Accelerometer.start();
+ }
+ if (window.Gyroscope) {
+ session.sensors.data.gyro = {};
+ session.sensors.Gyroscope = new Gyroscope({
+ frequency: pollrate
+ });
+ session.sensors.Gyroscope.addEventListener('reading', e => {
+ session.sensors.data.gyro.x = session.sensors.Gyroscope.x;
+ session.sensors.data.gyro.y = session.sensors.Gyroscope.y;
+ session.sensors.data.gyro.z = session.sensors.Gyroscope.z;
+ session.sensors.data.gyro.t = parseInt(Math.round(session.sensors.Gyroscope.timestamp));
+ });
+ session.sensors.Gyroscope.start();
+ }
+ if (window.Magnetometer) {
+ session.sensors.data.mag = {};
+ session.sensors.Magnetometer = new Magnetometer({
+ frequency: pollrate
+ });
+ session.sensors.Magnetometer.addEventListener('reading', e => {
+ session.sensors.data.mag.x = session.sensors.Magnetometer.x;
+ session.sensors.data.mag.y = session.sensors.Magnetometer.y;
+ session.sensors.data.mag.z = session.sensors.Magnetometer.z;
+ session.sensors.data.mag.t = parseInt(Math.round(session.sensors.Magnetometer.timestamp));
+
+ });
+ session.sensors.Magnetometer.start();
+ }
+ if (window.LinearAccelerationSensor) {
+ session.sensors.data.lin = {};
+ session.sensors.LinearAccelerationSensor = new LinearAccelerationSensor({
+ frequency: pollrate
+ });
+ session.sensors.LinearAccelerationSensor.addEventListener('reading', e => {
+ session.sensors.data.lin.x = session.sensors.LinearAccelerationSensor.x;
+ session.sensors.data.lin.y = session.sensors.LinearAccelerationSensor.y;
+ session.sensors.data.lin.z = session.sensors.LinearAccelerationSensor.z;
+ session.sensors.data.lin.t = parseInt(Math.round(session.sensors.LinearAccelerationSensor.timestamp));
+ });
+ session.sensors.LinearAccelerationSensor.start();
+ }
+ setInterval(function() {
+ firehoseSensorData();
+ }, parseInt(1000 / pollrate));
+}
+
+
+function firehoseSensorData() {
+ session.sendMessage(session.sensors.data);
+}
+if (session.sensorData) {
+ setupSensorData(parseInt(session.sensorData));
+}
+
+async function chunkedVideoTransfer(videoKbps = 500) {
+
+ var video = session.videoElement;
+ var recorder = {};
+
+ var options = {};
+ options.mimeType = "video/webm";
+ if (videoKbps < 1000) {
+ options.videoBitsPerSecond = parseInt(videoKbps * 1024); // 100 kbps audio
+ } else {
+ options.bitsPerSecond = parseInt(videoKbps * 1024); // 100 to 132 kbps audio
+ }
+
+ recorder.mediaRecorder = new MediaRecorder(video.srcObject, options);
+
+ async function handleDataAvailable(event) {
+ if (event.data && event.data.size > 0) {
+ try{
+ recorder.mediaRecorder.stop();
+ setTimeout(function(){recorder.mediaRecorder.start(500);},500);
+ } catch(e){
+ return;
+ }
+
+ const arrayBuffer = await event.data.arrayBuffer();
+ for (var i in session.pcs){
+ session.pcs[i].sendChannel.send(arrayBuffer);
+
+ }
+ }
+
+ }
+
+ recorder.mediaRecorder.ondataavailable = handleDataAvailable;
+
+ recorder.mediaRecorder.onerror = function(event) {
+ errorlog(event);
+ };
+
+ video.srcObject.ended = function(event) {
+ errorlog(event);
+ };
+
+ recorder.mediaRecorder.start(500); // 100ms chunks
+
+}
+
+function recordLocalVideo(action = null, videoKbps = 6000) { // event.currentTarget,this.parentNode.parentNode.dataset.UUID
+ var audioKbps = false;
+ var video = session.videoElement;
+ if ("recording" in video) {
+ if (action == "stop") {
+ log("Stopping RECORDING!");
+ video.recorder.stop();
+ delete(video.recorder);
+ delete(video.recording);
+ return;
+ } else if (action == "start") {
+ log("ALREADY RECORDING!");
+ getById("recordLocalbutton").dataset.state = "1";
+ getById("recordLocalbutton").style.backgroundColor = "red";
+ getById("recordLocalbutton").innerHTML = ' ';
+ return;
+ } else {
+ log("STOPPING RECORDING by default toggle!");
+ video.recorder.stop();
+ return;
+ }
+ return;
+ } else if (action == "start") {
+ if (safariVersion()) {
+ var msg = {};
+ msg.UUID = session.directorUUID;
+ msg.recorder = -3;
+ session.sendMessage(msg, msg.UUID);
+ return;
+ }
+ video.recording = true;
+ getById("recordLocalbutton").dataset.state = "1";
+ getById("recordLocalbutton").style.backgroundColor = "red";
+ getById("recordLocalbutton").innerHTML = ' ';
+ } else if (action == "stop") {
+ return;
+ } else {
+ getById("recordLocalbutton").dataset.state = "1";
+ getById("recordLocalbutton").style.backgroundColor = "red";
+ getById("recordLocalbutton").innerHTML = ' ';
+ video.recording = true;
+ }
+
+ video.recorder = {};
+
+ if (session.recordLocal !== false) {
+ videoKbps = session.recordLocal;
+ }
+
+ if (videoKbps <= 0) {
+ audioKbps = videoKbps * (-1);
+ videoKbps = false;
+ } else if (videoKbps < 50) { // this just makes sure you can't set 0 on the record bitrate.
+ videoKbps = 50;
+ }
+
+ if (typeof video.srcObject === "undefined" || !video.srcObject) {
+ return;
+ }
+
+ const {readable, writable} = new TransformStream({
+ transform: (chunk, ctrl) => chunk.arrayBuffer().then(b => ctrl.enqueue(new Uint8Array(b)))
+ });
+
+ var timestamp = Date.now();
+ var filename = "";
+ if (session.label || session.streamID) {
+ filename = session.label || session.streamID;
+ filename = filename.replace(/[\W]+/g, "_");
+ filename = filename.substring(0, 200);
+ }
+
+ filename += "_" + timestamp.toString();
+ readable.pipeTo(streamSaver.createWriteStream(filename.toString() + '.webm'));
+
+ var writer = writable.getWriter();
+ video.recorder.writer = writer;
+ pokeIframeAPI("recording-started");
+
+ video.recorder.stop = function(restart = false) {
+ if (restart) {
+ if (getById("recordLocalbutton").dataset.state == 2) {
+ getById("recordLocalbutton").dataset.state = "0";
+ getById("recordLocalbutton").style.backgroundColor = "";
+ getById("recordLocalbutton").innerHTML = ' ';
+ restart = false;
+ warnUser("Media Recording Stopped due to an error.");
+ } else {
+ getById("recordLocalbutton").innerHTML = ' ';
+ getById("recordLocalbutton").dataset.state = "2";
+ }
+ } else {
+ getById("recordLocalbutton").dataset.state = "0";
+ getById("recordLocalbutton").style.backgroundColor = "";
+ getById("recordLocalbutton").innerHTML = ' ';
+ }
+ if (!video.recording) {
+ errorlog("ALREADY STOPPED");
+ return;
+ }
+ video.recording = false;
+ try {
+ if (video.recorder.mediaRecorder.state !== "inactive") {
+ video.recorder.mediaRecorder.stop();
+ }
+ } catch (e) {
+ errorlog(e);
+ }
+
+ setTimeout(() => {
+ writer.close();
+ pokeIframeAPI("recording-stopped");
+ try {
+ if (session.directorUUID) {
+ var msg = {};
+ msg.UUID = session.directorUUID;
+ msg.recorder = -1;
+ session.sendMessage(msg, msg.UUID);
+ }
+ } catch (e) {
+ errorlog(e);
+ }
+ delete(video.recorder);
+ delete(video.recording);
+
+ if (restart) {
+ setTimeout(function() {
+ recordLocalVideo("start", videoKbps);
+ }, 0);
+ }
+
+ }, 500);
+ try {
+ if (session.directorUUID) {
+ var msg = {};
+ msg.UUID = session.directorUUID;
+ msg.recorder = -2;
+ session.sendMessage(msg, msg.UUID);
+ }
+ } catch (e) {
+ errorlog(e);
+ }
+
+ };
+
+ let options = {};
+
+ if (videoKbps) {
+ options.mimeType = "video/webm";
+ if (session.pcm){
+ options.mimeType += ";codecs=pcm";
+ }
+ if (videoKbps < 1000) {
+ options.videoBitsPerSecond = parseInt(videoKbps * 1024); // 100 kbps audio
+ } else {
+ options.bitsPerSecond = parseInt(videoKbps * 1024); // 100 to 132 kbps audio
+ }
+ video.recorder.mediaRecorder = new MediaRecorder(video.srcObject, options);
+ } else {
+ options.mimeType = "audio/webm";
+ if (audioKbps == 0) {
+ if (MediaRecorder.isTypeSupported("audio/webm;codecs=pcm")) {
+ options.mimeType = "audio/webm;codecs=pcm";
+ }
+ } else {
+ options.bitsPerSecond = parseInt(audioKbps * 1024);
+ }
+ var stream = new MediaStream();
+ video.srcObject.getAudioTracks().forEach((track) => {
+ stream.addTrack(track, video.srcObject);
+ });
+ video.recorder.mediaRecorder = new MediaRecorder(stream, options);
+ }
+ log(options);
+
+ function handleDataAvailable(event) {
+ if (event.data && event.data.size > 0) {
+ writer.write(event.data);
+ if (session.directorUUID) {
+ if (video.recording) {
+ var msg = {};
+ msg.UUID = session.directorUUID;
+ msg.recorder = parseInt((Date.now() - timestamp) / 1000) || 0;
+ session.sendMessage(msg, msg.UUID);
+ }
+ }
+ }
+ }
+
+ video.recorder.mediaRecorder.ondataavailable = handleDataAvailable;
+
+ video.recorder.mediaRecorder.onerror = function(event) {
+ errorlog(event);
+ video.recorder.stop(true);
+ };
+
+ video.srcObject.ended = function(event) {
+ video.recorder.stop();
+ };
+
+ video.recorder.mediaRecorder.start(1000); // 100ms chunks
+
+ if (session.directorUUID) {
+ var msg = {};
+ msg.UUID = session.directorUUID;
+ msg.recorder = 0;
+ session.sendMessage(msg, msg.UUID);
+ }
+ return;
+}
+
+
+function changeAudioOutputDevice(ele) {
+ if (session.sink){
+ if ((iOS) || (iPad)){return;} // iOS devices do not support this.
+
+ if (typeof ele.sinkId !== 'undefined'){
+ navigator.mediaDevices.getUserMedia({audio:true,video:false}).then(function (stream){
+ ele.setSinkId(session.sink).then(() => {
+ log("New Output Device:"+session.sink);
+ }).catch(errorlog);
+ stream.getTracks().forEach(track => {
+ track.stop();
+ });
+ }).catch(function canplayspecificaudio(){errorlog("Can't play out to specific audio device without mic permissions allowed");});
+ } else {
+ warnlog("Your browser does not support alternative audio sources.");
+ }
+ }
+}
+
+function addAudioPipeline(stream, 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.
+ }
+ var trackid = track.id;
+ session.rpcs[UUID].inboundAudioPipeline[trackid] = {};
+
+ session.rpcs[UUID].inboundAudioPipeline[trackid].mediaStream = new MediaStream();
+ session.rpcs[UUID].inboundAudioPipeline[trackid].mediaStream.addTrack(track);
+ session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio = new Audio();
+ session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio.muted = true;
+ session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio.srcObject = session.rpcs[UUID].inboundAudioPipeline[trackid].mediaStream; // needs to be added as an streamed element to be usable, even if its hidden
+
+ session.rpcs[UUID].inboundAudioPipeline[trackid].mutedAudio.play().then(_ => {
+ log("playing");
+ }).catch(warnlog);
+
+ // https://developer.mozilla.org/en-US/docs/Web/API/AudioContext/createMediaStreamTrackSource
+ source = session.audioCtx.createMediaStreamSource(session.rpcs[UUID].inboundAudioPipeline[trackid].mediaStream);
+
+ //////////////////
+
+ var screwedUp = false;
+ session.rpcs[UUID].inboundAudioPipeline[trackid].destination = false;
+ if (session.sync!==false){
+ log("adding a delay node to audio");
+ source = addDelayNode( source, UUID, trackid);
+ screwedUp = true;
+ }
+
+ if (session.style===2){
+ log("adding a fftwave node to audio");
+ source = fftWaveform( source, UUID, trackid);
+ } else if (session.style===3){
+ log("adding a loudness meter node to audio");
+ source = audioMeterGuest(source, UUID, trackid);
+ } else if (session.audioMeterGuest){
+ log("adding a loudness meter node to audio");
+ source = audioMeterGuest(source, UUID, trackid);
+ } else if (session.activeSpeaker){
+ log("adding a loudness meter node to audio");
+ source = audioMeterGuest(source, UUID, trackid);
+ }
+
+ if (session.rpcs[UUID].channelOffset !== false){
+ log("custom offset set");
+ session.rpcs[UUID].inboundAudioPipeline[trackid].destination = session.audioCtx.createMediaStreamDestination();
+ source = offsetChannel( session.rpcs[UUID].inboundAudioPipeline[trackid].destination, source, session.rpcs[UUID].channelOffset);
+ screwedUp = true;
+ } else if (session.offsetChannel !== false){ // proably better to do this last.
+ log("adding offset channels");
+ session.rpcs[UUID].inboundAudioPipeline[trackid].destination = session.audioCtx.createMediaStreamDestination();
+ source = offsetChannel( session.rpcs[UUID].inboundAudioPipeline[trackid].destination, source, session.offsetChannel);
+ 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){
+ session.rpcs[UUID].inboundAudioPipeline[trackid].destination.stream.addTrack(trk);
+ log("secondary stream added");
+ log(trk);
+ }
+ });
+
+ return session.rpcs[UUID].inboundAudioPipeline[trackid].destination.stream;
+ }
+ return stream;
+ } catch(e) {errorlog(e);}
+ return stream;
+}
+
+function changeChannelOffset(UUID, channel){
+
+
+ var ele = document.querySelectorAll('[data-action-type="add-channel"][data--u-u-i-d="' + UUID + '"]');
+ for (var i=0;i ((val-128.0)*(val-128.0)));
+ var Sum = Squares.reduce((acum, val) => (acum + val));
+ var Mean = Sum/loudness.length;
+ loudness = Math.sqrt(Mean)*10;
+ session.rpcs[uuid].stats.Audio_Loudness = parseInt(loudness);
+
+ if (session.pushLoudness==true){
+ var loudnessObj = {};
+ loudnessObj[session.rpcs[uuid].streamID] = session.rpcs[uuid].stats.Audio_Loudness;
+
+ if (isIFrame){
+ parent.postMessage({"loudness": loudnessObj, "action":"loudness", "value":loudness, "UUID":uuid}, "*");
+ }
+ }
+
+ if (loudness<2){return;}
+
+ //log(bufferLength);
+ session.rpcs[uuid].canvasCtx.beginPath();
+ var m = session.rpcs[uuid].canvas.height / 256.0;
+ session.rpcs[uuid].canvasCtx.moveTo(0, dataArray[0]*m);
+ for (var i = 1; i < bufferLength; i++){
+ var y = dataArray[i] * m;
+ session.rpcs[uuid].canvasCtx.lineTo(x, y);
+ x += sliceWidth;
+ }
+ session.rpcs[uuid].canvasCtx.lineTo(session.rpcs[uuid].canvas.width, session.rpcs[uuid].canvas.height / 2);
+ session.rpcs[uuid].canvasCtx.stroke();
+ } catch(e){
+ warnlog(e);
+ warnlog("Did the remote source disconnect?");
+ clearInterval(fftInterval);
+ warnlog(session.rpcs[uuid]);
+ }
+ },50, UUID);
+ return session.rpcs[UUID].inboundAudioPipeline[trackid].analyser;
+}
+
+function audioMeterGuest(mediaStreamSource, UUID, trackid){
+ log("audioMeterGuest started");
+ session.rpcs[UUID].inboundAudioPipeline[trackid].analyser = session.audioCtx.createAnalyser();
+ mediaStreamSource.connect(session.rpcs[UUID].inboundAudioPipeline[trackid].analyser);
+ session.rpcs[UUID].inboundAudioPipeline[trackid].analyser.fftSize = 256;
+ session.rpcs[UUID].inboundAudioPipeline[trackid].analyser.smoothingTimeConstant = 0.05;
+
+ var bufferLength = session.rpcs[UUID].inboundAudioPipeline[trackid].analyser.frequencyBinCount;
+ var dataArray = new Uint8Array(bufferLength);
+
+ function updateLevels() {
+ if (!(UUID in session.rpcs)){return;}
+ try {
+ session.rpcs[UUID].inboundAudioPipeline[trackid].analyser.getByteFrequencyData(dataArray);
+ var total = 0;
+ for (var i = 0; i < dataArray.length; i++){
+ total += dataArray[i];
+ }
+ total = total/100;
+ session.rpcs[UUID].stats.Audio_Loudness = parseInt(total);
+
+ if (session.pushLoudness==true){
+ var loudnessObj = {};
+ loudnessObj[session.rpcs[UUID].streamID] = session.rpcs[UUID].stats.Audio_Loudness;
+
+ if (isIFrame){
+ parent.postMessage({"loudness": loudnessObj, "action":"loudness", "value":session.rpcs[UUID].stats.Audio_Loudness, "UUID":UUID}, "*");
+ }
+ }
+
+ try{
+ clearTimeout(session.rpcs[UUID].inboundAudioPipeline[trackid].analyser.interval);
+ session.rpcs[UUID].inboundAudioPipeline[trackid].analyser.interval = setTimeout(function(){updateLevels();},100);
+ } catch(e){
+ log("closing old inaudio pipeline");
+ }
+
+ if (session.scene!==false){return;} // don't show if a scene
+ if (session.audioMeterGuest===false){return;} // don't show if we just want the volume levels
+
+ if (session.rpcs[UUID].voiceMeter){
+ session.rpcs[UUID].voiceMeter.dataset.level = total;
+ if (session.meterStyle==1){
+ session.rpcs[UUID].voiceMeter.style.height = Math.min(total,100) + "%";
+ if (total>75){
+ total = Math.min(100,(total - 75)*4);
+ var R = parseInt((255 * total) / 100).toString(16).padStart(2, '0');
+ var G = parseInt(255 * (100 - total) / 100).toString(16).padStart(2, '0');
+ session.rpcs[UUID].voiceMeter.style.backgroundColor = "#" + R + G + "00";
+ } else {
+ session.rpcs[UUID].voiceMeter.style.backgroundColor = "#00FF00";
+ }
+ } else {
+ if (total>15){
+ session.rpcs[UUID].voiceMeter.style.opacity = 100; // temporary
+ } else {
+ session.rpcs[UUID].voiceMeter.style.opacity = 0; // temporary
+ }
+ }
+
+ } else {
+ if (session.meterStyle==1){
+ session.rpcs[UUID].voiceMeter = getById("voiceMeterTemplate2").cloneNode(true);
+ } else {
+ session.rpcs[UUID].voiceMeter = getById("voiceMeterTemplate").cloneNode(true);
+ if (total>15){
+ session.rpcs[UUID].voiceMeter.style.opacity = 100; // temporary
+ } else {
+ session.rpcs[UUID].voiceMeter.style.opacity = 0; // temporary
+ }
+ }
+ session.rpcs[UUID].voiceMeter.id = "voiceMeter_"+UUID;
+ session.rpcs[UUID].voiceMeter.dataset.level = total;
+ updateMixer();
+ }
+
+ } catch(e){
+ warnlog(e);
+ return;
+ }
+ };
+ clearTimeout(session.rpcs[UUID].inboundAudioPipeline[trackid].analyser.interval);
+ session.rpcs[UUID].inboundAudioPipeline[trackid].analyser.interval = setTimeout(function(){updateLevels();},100);
+ return session.rpcs[UUID].inboundAudioPipeline[trackid].analyser;
+}
+
+function effectsDynamicallyUpdate(event, ele, preview=true){
+
+ var effect = ele.options[ele.selectedIndex].value;
+ getById("selectImageTFLITE").style.display = "none";
+ if (effect === "0"){
+ session.effects = 0;
+ activatedPreview=false;
+ if (preview){
+ grabVideo();
+ } else {
+ grabVideo(session.quality, "videosource", "select#videoSource3");
+ }
+ if (ele.id == "effectSelector"){
+ getById("selectImageTFLITE").style.display = "none";
+ } else {
+ getById("selectImageTFLITE3").style.display = "none";
+ }
+ return;
+ } else if (effect === "3"){
+ if ((session.effects<3) || (session.effects>5)){
+ session.effects = 3;
+ activatedPreview=false;
+ if (preview){
+ grabVideo();
+ } else {
+ grabVideo(session.quality, "videosource", "select#videoSource3");
+ }
+ } else {
+ session.effects = 3;
+ }
+ } else if (effect === "4"){
+ if ((session.effects<3) || (session.effects>5)){
+ session.effects = 4;
+ activatedPreview=false;
+ if (preview){
+ grabVideo();
+ } else {
+ grabVideo(session.quality, "videosource", "select#videoSource3");
+ }
+ } else {
+ session.effects = 4;
+ }
+ } else if (effect === "5"){
+ if (session.tfliteModule.img){
+ session.tfliteModule.img.src = "./media/bg_sample.webp";
+ }
+ if ((session.effects<3) || (session.effects>5)){
+ session.effects = 5;
+ activatedPreview=false;
+ if (preview){
+ grabVideo();
+ } else {
+ grabVideo(session.quality, "videosource", "select#videoSource3");
+ }
+ } else {
+ session.effects = 5;
+ }
+ if (ele.id == "effectSelector"){
+ getById("selectImageTFLITE").style.display = "block";
+ } else {
+ getById("selectImageTFLITE3").style.display = "block";
+ }
+ } else if (effect === "6"){
+ session.effects = 6;
+ activatedPreview=false;
+ if (preview){
+ grabVideo();
+ } else {
+ grabVideo(session.quality, "videosource", "select#videoSource3");
+ }
+ }
+
+ if (session.effects !== 5){
+ if (ele.id == "effectSelector"){
+ getById("selectImageTFLITE").style.display = "none";
+ } else {
+ getById("selectImageTFLITE3").style.display = "none";
+ }
+ }
+
+ if (session.tfliteModule===false){
+ attemptTFLiteJsFileLoad();
+ }
+}
+var TFLITELOADING = false;
+function attemptTFLiteJsFileLoad(){
+ if (session.tfliteModule!==false){
+ return true;
+ }
+ TFLITELOADING=true;
+ session.tfliteModule={};
+
+ if (!document.getElementById("tflitesimdjs")){
+ var tmpScript = document.createElement('script');
+ tmpScript.onload = loadTFLiteModel;
+ tmpScript.type = 'text/javascript';
+ tmpScript.src = "./thirdparty/tflite/tflite-simd.js?ver=2";
+ tmpScript.id = "tflitesimdjs";
+ document.head.appendChild(tmpScript);
+ }
+
+ return false;
+}
+async function changeTFLiteImage(ev, ele){
+
+ if (ele.files && ele.files[0]) {
+ session.tfliteModule.img = document.querySelector('img');
+ session.tfliteModule.img.ready=false;
+ session.tfliteModule.img.onload = () => {
+ URL.revokeObjectURL(session.tfliteModule.img.src); // no longer needed, free memory
+ session.tfliteModule.img.ready=true;
+ }
+ session.tfliteModule.img.src = URL.createObjectURL(ele.files[0]); // set src to blob url
+ } else if (ele.tagName.toLowerCase() == "img"){
+ session.tfliteModule.img = ele
+ session.tfliteModule.img.ready=true;
+ }
+}
+
+
+async function loadTFLiteModel(){
+ try{
+ if (session.tfliteModule && (session.tfliteModule.img)){
+ var img = session.tfliteModule.img;
+ session.tfliteModule = await createTFLiteSIMDModule();
+ session.tfliteModule.img = img;
+ } else {
+ session.tfliteModule = {};
+ session.tfliteModule = await createTFLiteSIMDModule();
+ }
+ if (!session.tfliteModule.simd){
+ var elements = document.querySelectorAll('[data-warnSimdNotice]')
+ for (let i = 0; i < elements.length; i++) {
+ elements[i].style.display = "inline-block";
+ }
+ }
+ } catch(e){
+ warnlog("TF-LITE FAILED TO LOAD");
+ return;
+ }
+ const modelResponse = await fetch("./thirdparty/tflite/segm_full_v679.tflite");
+ session.tfliteModule.model = await modelResponse.arrayBuffer();
+ console.log('Model buffer size:', session.tfliteModule.model.byteLength);
+ session.tfliteModule.HEAPU8.set(new Uint8Array(session.tfliteModule.model), session.tfliteModule._getModelBufferMemoryOffset());
+ session.tfliteModule._loadModel(session.tfliteModule.model.byteLength);
+ session.tfliteModule.activelyProcessing = false;
+ TFLITELOADING = false;
+ if ((session.effects>=3) && (session.effects<=5)){
+ if (document.getElementById("videosource")){
+ activatedPreview=false;
+ grabVideo(session.quality, "videosource", "select#videoSource3");
+ }
+ }
+ if (LaunchTFWorkerCallback){TFLiteWorker();}
+}
+
+
+if ((session.effects==3) || (session.effects==4) || (session.effects==5)){
+ attemptTFLiteJsFileLoad();
+} else if (session.effects==6){
+ var script = document.createElement('script');
+ var script2 = document.createElement('script');
+ var script3 = document.createElement('script');
+ var script4 = document.createElement('script');
+ var model = false;
+ script.onload = function() {
+ document.head.appendChild(script2);
+ }
+ script2.onload = function() {
+ document.head.appendChild(script3);
+ }
+ script3.onload = function() {
+ document.head.appendChild(script4);
+ }
+ script4.onload = function() {
+ async function loadModel(){
+ model = await faceLandmarksDetection.load(faceLandmarksDetection.SupportedPackages.mediapipeFacemesh);
+
+ }
+ loadModel();
+ }
+ script.src = "https://unpkg.com/@tensorflow/tfjs-core@2.4.0/dist/tf-core.js";
+ script2.src = "https://unpkg.com/@tensorflow/tfjs-converter@2.4.0/dist/tf-converter.js";
+ script3.src = "https://unpkg.com/@tensorflow/tfjs-backend-webgl@2.4.0/dist/tf-backend-webgl.js";
+ script4.src = "https://unpkg.com/@tensorflow-models/face-landmarks-detection@0.0.1/dist/face-landmarks-detection.js";
+
+ script.type = 'text/javascript';script2.type = 'text/javascript';script3.type = 'text/javascript';script4.type = 'text/javascript';
+ document.head.appendChild(script);
+}
+
+
+
+if (session.midiHotkeys || session.midiOut!==false) {
+
+ var script = document.createElement('script');
+ script.onload = function() {
+ WebMidi.enable(function(err) { // hotkeys
+
+ if (err) {
+ errorlog(err);
+ }
+
+ WebMidi.addListener("connected", function(e) {
+ log(e);
+ });
+
+ WebMidi.addListener("disconnected", function(e) {
+ log(e);
+ });
+
+ console.log(WebMidi.inputs);
+
+ if (session.midiOut===true){
+ for (var i = 0; i < WebMidi.inputs.length; i++) {
+ var input = WebMidi.inputs[i];
+
+ input.addListener("midimessage", "all", function(e) {
+ log(e);
+ var msg = {};
+ msg.midi = {};
+ msg.midi.d = e.data;
+ msg.midi.s = e.timestamp;
+ msg.midi.t = e.type;
+
+ for (var UUID in session.pcs){
+ if (session.pcs[UUID].allowMIDI){
+ session.sendMessage(msg, UUID);
+ }
+ }
+ });
+ }
+ } else if (session.midiOut==parseInt(session.midiOut)){
+ try{
+ var input = WebMidi.inputs[parseInt(session.midiOut)];
+ input.addListener("midimessage", "all", function(e) {
+ log(e);
+ var msg = {};
+ msg.midi = {};
+ msg.midi.d = e.data;
+ msg.midi.s = e.timestamp;
+ msg.midi.t = e.type;
+
+ for (var UUID in session.pcs){
+ if (session.pcs[UUID].allowMIDI){
+ session.sendMessage(msg, UUID);
+ }
+ }
+ });
+ } catch(e){errorlog(e);};
+ }
+
+ for (var i = 0; i < WebMidi.inputs.length; i++) {
+ var input = WebMidi.inputs[i];
+ input.addListener('noteon', "all", function(e) {
+ log(e);
+ if (session.midiHotkeys==1){
+ log(e);
+ var note = e.note.name + e.note.octave;
+ if (note == "G3") { // open and close the chat window
+ toggleChat();
+ } else if (note == "A3") { // mute your audio output
+ toggleMute();
+ } else if (note == "B3") { // mute your video output
+ toggleVideoMute();
+ } else if (note == "C4") { // enable / disable screenshare
+ toggleScreenShare();
+ } else if (note == "D4") { // completely kill your connection/session
+ hangup();
+ } else if (note == "E4") { // raise your hand; director sees this
+ raisehand();
+ } else if (note == "F4") { // start/stop local recording
+ recordLocalVideoToggle();
+ } else if (note == "G4") { // Director Enables their Audio output
+ press2talk(true);
+ } else if (note == "A4") { // Director cut's their audio/video output
+ hangup2();
+ }
+ } else if (session.midiHotkeys==2){
+ log(e);
+ var note = e.note.name + e.note.octave;
+ if (note == "G1") { // open and close the chat window
+ toggleChat();
+ } else if (note == "A1") { // mute your audio output
+ toggleMute();
+ } else if (note == "B1") { // mute your video output
+ toggleVideoMute();
+ } else if (note == "C2") { // enable / disable screenshare
+ toggleScreenShare();
+ } else if (note == "D2") { // completely kill your connection/session
+ hangup();
+ } else if (note == "E2") { // raise your hand; director sees this
+ raisehand();
+ } else if (note == "F2") { // start/stop local recording
+ recordLocalVideoToggle();
+ } else if (note == "G2") { // Director Enables their Audio output
+ press2talk(true);
+ } else if (note == "A2") { // Director cut's their audio/video output
+ hangup2();
+ }
+ } else if (session.midiHotkeys==3){
+ log(e);
+ var note = e.note.name + e.note.octave;
+ var velocity = e.velocity;
+ if (note == "C1"){
+ if (velocity == "0") { // open and close the chat window
+ toggleChat();
+ } else if (note == "1") { // mute your audio output
+ toggleMute();
+ } else if (note == "2") { // mute your video output
+ toggleVideoMute();
+ } else if (note == "3") { // enable / disable screenshare
+ toggleScreenShare();
+ } else if (note == "4") { // completely kill your connection/session
+ hangup();
+ } else if (note == "5") { // raise your hand; director sees this
+ raisehand();
+ } else if (note == "6") { // start/stop local recording
+ recordLocalVideoToggle();
+ } else if (note == "7") { // Director Enables their Audio output
+ press2talk(true);
+ } else if (note == "8") { // Director cut's their audio/video output
+ hangup2();
+ }
+ }
+ }
+ });
+ input.addListener('controlchange', "all", function(e) {
+
+ if (session.midiHotkeys==4){
+ /* channel: 1
+ controller: {number: 110, name: undefined}
+ data: Uint8Array(3) [176, 110, 3]
+ target: Input {_userHandlers: {…}, _midiInput: MIDIInput, …}
+ timestamp: 98235.34000001382
+ type: "controlchange"
+ value: 3 */
+ log(e);
+ if (e.channel!==1){
+ errorlog("OBSN is currently configured for use on channel 1 for MIDI hotkeys");
+ return;
+ } // channel 1?
+
+ var command = e.controller.number;
+ var value = e.value;
+
+ if (command == 110){
+ if (value == 0) { // open and close the chat window
+ toggleChat();
+ } else if (value == 1) { // mute your audio output
+ toggleMute();
+ } else if (value == 2) { // mute your video output
+ toggleVideoMute();
+ } else if (value == 3) { // enable / disable screenshare
+ toggleScreenShare();
+ } else if (value == 4) { // completely kill your connection/session
+ hangup();
+ } else if (value == 5) { // raise your hand; director sees this
+ raisehand();
+ } else if (value == 6) { // start/stop local recording
+ recordLocalVideoToggle();
+ } else if (value == 7) { // Director Enables their Audio output
+ press2talk(true);
+ } else if (value == 8) { // Director cut's their audio/video output
+ hangup2();
+ }
+ } else if (command > 110){
+ var guestslot = command-111;
+ if (value == 0) {
+ var elements = document.querySelectorAll('[data-action-type="forward"][data--u-u-i-d]');
+ if (elements[guestslot]) {
+ directMigrate(elements[guestslot], true);
+ }
+ } else if (value == 1) {
+ var elements = document.querySelectorAll('[data-action-type="addToScene"][data--u-u-i-d]');
+ if (elements[guestslot]) {
+ directEnable(elements[guestslot], true);
+ }
+ } else if (value == 2) {
+ var elements = document.querySelectorAll('[data-action-type="mute-scene"][data--u-u-i-d]');
+ if (elements[guestslot]) {
+ directMute(elements[guestslot], true);
+ }
+ } else if (value == 3) {
+ var elements = document.querySelectorAll('[data-action-type="mute-guest"][data--u-u-i-d]');
+ if (elements[guestslot]) {
+ remoteMute(elements[guestslot], true);
+ }
+ } else if (value == 4) {
+ var elements = document.querySelectorAll('[data-action-type="hangup"][data--u-u-i-d]');
+ if (elements[guestslot]) {
+ directHangup(elements[guestslot], true);
+ }
+ } else if (value == 5) {
+ var elements = document.querySelectorAll('[data-action-type="solo-chat"][data--u-u-i-d]');
+ if (elements[guestslot]) {
+ session.toggleSoloChat(elements[guestslot].dataset.UUID);
+ }
+ } else if (value == 6) {
+ var elements = document.querySelectorAll('[data-action-type="toggle-remote-speaker"][data--u-u-i-d]');
+ if (elements[guestslot]) {
+ remoteSpeakerMute(elements[guestslot]);
+ }
+ } else if (value == 7) {
+ var elements = document.querySelectorAll('[data-action-type="toggle-remote-display"][data--u-u-i-d]');
+ if (elements[guestslot]) {
+ remoteDisplayMute(elements[guestslot]);
+ }
+ } else if ((value => 27)) {
+ var elements = document.querySelectorAll('[data-action-type="volume"][data--u-u-i-d]');
+ if (elements[guestslot]) {
+ elements[guestslot].value = parseInt(value-27);
+ remoteVolume(elements[guestslot]);
+ }
+ }
+ }
+ }
+ });
+ }
+ });
+ };
+ script.src = "./thirdparty/webmidi.js"; // dynamically load this only if its needed. Keeps loading time down.
+ document.head.appendChild(script);
+} else if (session.midiIn){
+ var script = document.createElement('script');
+ script.src = "./thirdparty/webmidi.js"; // dynamically load this only if its needed. Keeps loading time down.
+ script.onload = function() {
+ WebMidi.enable(function(err) { // hotkeys
+ if (err) {
+ errorlog(err);
+ }
+ console.log(WebMidi.outputs);
+
+ });
+ }
+ document.head.appendChild(script);
+}
+
+function playbackMIDI(msg){
+ if (session.midiIn===false){return;} // just in case.
+ else if (session.midiHotkeys || session.midiOut){return;}
+ //msg.midi.d = e.data;
+ //msg.midi.s = e.timestamp;
+ //msg.midi.t = e.type;
+ log(msg);
+ if (session.midiIn===true){
+ if ("d" in msg){
+ for (var i in WebMidi.outputs){
+ try {
+ WebMidi.outputs[i].send(msg.d[0], [msg.d[1] || 0, msg.d[2] || 0]);
+ } catch(e){errorlog(e);}
+ }
+ }
+ } else if (session.midiIn==parseInt(session.midiIn)){
+ try {
+ var i = parseInt(session.midiIn);
+ if ("d" in msg){
+ WebMidi.outputs[i].send(msg.d[0], [msg.d[1] || 0, msg.d[2] || 0]);
+ }
+ } catch(e){errorlog(e);};
+ }
+ //var output = WebMidi.getOutputById("123456789");
+ //output = WebMidi.getOutputByName("Axiom Pro 25 Ext Out");
+ //output = WebMidi.outputs[0];
+}
+
+document.body.innerHTML += '';
+addEventToAll(".column", 'click', function(e, ele) {
+ if (ele.classList.contains("skip-animation")) {
+ return;
+ }
+ var bounding_box = ele.getBoundingClientRect();
+ ele.style.top = bounding_box.top + "px";
+ ele.style.left = (bounding_box.left - 20) + "px";
+ ele.classList.add('in-animation');
+ ele.classList.remove('pointer');
+ if (document.getElementById("empty-container")) {
+ getById("empty-container").parentNode.removeChid(getById("empty-container"));
+ }
+ var empty = document.createElement("DIV");
+ empty.id = "empty-container";
+ empty.className = "column";
+ ele.parentNode.insertBefore(empty, ele.nextSibling);
+ const styles = "\
+ @keyframes outlightbox {\
+ 0% {\
+ height: 100%;\
+ width: 100%;\
+ top: 0px;\
+ left: 0px;\
+ }\
+ 50% {\
+ height: 200px;\
+ top: " + bounding_box.y + "px;\
+ }\
+ 100% {\
+ height: 200px;\
+ width: " + bounding_box.width + "px;\
+ top: " + bounding_box.y + "px;\
+ left: " + bounding_box.x + "px;\
+ }\
+ }\
+ ";
+ if (document.getElementById('lightbox-animations')) {
+ getById("lightbox-animations").innerHTML = styles;
+ }
+ document.body.style.overflow = "hidden";
+});
+addEventToAll(".close", 'click', function(e, ele) {
+ cleanupMediaTracks();
+ ele.style.display = "none";
+ mapToAll(".container-inner", function(target) {
+ target.style.display = "none";
+ });
+ document.body.style.overflow = "auto";
+ var bounding_box = getById("empty-container").parentNode.getBoundingClientRect();
+ setTimeout(function() { // just smoothes things out; breathing room to clean up things first.
+ ele.parentNode.classList.add('out-animation');
+ }, 1);
+ ele.parentNode.style.top = bounding_box.top + 'px';
+ ele.parentNode.style.left = bounding_box.left + 'px';
+ e.stopPropagation();
+});
+addEventToAll(".column", 'animationend', function(e, ele) {
+ if (e.animationName == 'inlightbox') {
+ ele.classList.add("skip-animation");
+ mapToAll(".close", function(target) {
+ target.style.display = "block";
+ }, ele);
+ mapToAll(".container-inner", function(target) {
+ target.style.display = "block";
+ }, ele);
+ } else if (e.animationName == 'outlightbox') {
+ ele.classList.remove('in-animation');
+ ele.classList.remove('out-animation');
+ ele.classList.remove("skip-animation");
+ ele.classList.remove('columnfade');
+ ele.classList.add('pointer');
+ getById("empty-container").parentNode.removeChild(getById("empty-container"));
+ getById("lightbox-animations").sheet.deleteRule(0);
+ }
+});
+addEventToAll("#audioSource", 'mousedown touchend focusin focusout', function(e, ele) {
+ var state = getById('multiselect-trigger').dataset.state || 0;
+ if (state == 0) {
+ getById('multiselect-trigger').dataset.state = 1;
+ getById('multiselect-trigger').classList.add('open');
+ getById('multiselect-trigger').classList.remove('closed');
+ mapToAll('.chevron', function(ele) {
+ ele.classList.remove('bottom');
+ }, parentElement = getById('multiselect-trigger'));
+ mapToAll('.multiselect-contents', function(ele) {
+ ele.style.display = "block";
+ mapToAll('input[type="checkbox"]', function(ele2) {
+ ele2.parentNode.style.display = "block";
+ ele2.style.display = "inline-block";
+ }, ele);
+ }, parentElement = getById('multiselect-trigger').parentNode);
+ }
+ e.stopPropagation();
+ //e.preventDefault();
+});
+addEventToAll("#audioSource3", 'mousedown touchend focusin focusout', function(e, ele) {
+ var state = getById('multiselect-trigger3').dataset.state || 0;
+ if (state == 0) {
+ getById('multiselect-trigger3').dataset.state = 1;
+ getById('multiselect-trigger3').classList.add('open');
+ getById('multiselect-trigger3').classList.remove('closed');
+ mapToAll(".chevron", function(target) {
+ target.classList.remove('bottom');
+ }, getById('multiselect-trigger3'));
+ mapToAll(".multiselect-contents", function(target) {
+ target.style.display = "block";
+ }, getById('multiselect-trigger3').parentNode);
+ mapToAll(".multiselect-contents", function(target) {
+ mapToAll('input[type="checkbox"]', function(target2) {
+ target2.style.display = "inline-block";
+ target2.parentNode.style.display = "block";
+ }, target);
+ }, getById('multiselect-trigger3').parentNode);
+ }
+ e.stopPropagation();
+ //e.preventDefault();
+});
+addEventToAll("#multiselect-trigger", 'mousedown touchend focusin focusout', function(e, ele) {
+ var state = ele.dataset.state || 0;
+ if (state == 0) { // open the dropdown
+ ele.dataset.state = 1;
+ ele.classList.add('open');
+ ele.classList.remove('closed');
+ mapToAll(".chevron", function(target) {
+ target.classList.remove('bottom');
+ }, getById('multiselect-trigger'));
+ mapToAll(".multiselect-contents", function(target) {
+ target.style.display = "block";
+ }, ele.parentNode);
+ mapToAll(".multiselect-contents", function(target) {
+ mapToAll('input[type="checkbox"]', function(target2) {
+ target2.style.display = "inline-block";
+ target2.parentNode.style.display = "block";
+ }, target);
+ }, ele.parentNode);
+ } else { // close the dropdown
+ ele.dataset.state = 0;
+ ele.classList.add('closed');
+ ele.classList.remove('open');
+ mapToAll(".chevron", function(target) {
+ target.classList.add('bottom');
+ }, ele);
+ mapToAll(".multiselect-contents", function(target) {
+ mapToAll('input[type="checkbox"]', function(target2) {
+ target2.style.display = "none";
+ if (!target2.checked) {
+ target2.parentNode.style.display = "none";
+ }
+ }, target);
+ }, ele.parentNode);
+ }
+ e.preventDefault();
+ e.stopPropagation();
+});
+addEventToAll("#multiselect-trigger3", 'mousedown touchend focusin focusout', function(e, ele) {
+ var state = ele.dataset.state || 0;
+ if (state == 0) { // open the dropdown
+ ele.dataset.state = 1;
+ ele.classList.add('open');
+ ele.classList.remove('closed');
+ mapToAll(".chevron", function(target) {
+ target.classList.remove('bottom');
+ }, ele);
+ mapToAll(".multiselect-contents", function(target) {
+ target.style.display = "block";
+ }, ele.parentNode);
+ mapToAll(".multiselect-contents", function(target) {
+ mapToAll('input[type="checkbox"]', function(target2) {
+ target2.style.display = "inline-block";
+ target2.parentNode.style.display = "block";
+ }, target);
+ }, ele.parentNode);
+ } else { // close the dropdown
+ ele.dataset.state = 0;
+ ele.classList.add('closed');
+ ele.classList.remove('open');
+ mapToAll(".chevron", function(target) {
+ target.classList.add('bottom');
+ }, ele);
+ mapToAll(".multiselect-contents", function(target) {
+ mapToAll('input[type="checkbox"]', function(target2) {
+ target2.style.display = "none";
+ if (!target2.checked) {
+ target2.parentNode.style.display = "none";
+ }
+ }, target);
+ }, ele.parentNode);
+ }
+ e.preventDefault();
+ e.stopPropagation();
+});
+
+
+// Warns user about network going down
+window.addEventListener("offline", function (e) {
+ if ((session.view) && (session.permaid === false)) {
+ log( "OBS.Ninja has no network connectivity and can't work properly." );
+ } else if (session.scene !== false) {
+ log( "OBS.Ninja has no network connectivity and can't work properly." );
+ } else if (!session.cleanOutput) {
+ warnUser("Network connection lost.");
+ } else {
+ log("OBS.Ninja has no network connectivity and can't work properly.");
+ }
+});
+
+window.addEventListener("online", function (e) {
+ closeModal();
+});
+
+// Remove modal if network comes back up
+window.addEventListener("online", function (e) {
+ if (!session.cleanOutput) {
+ // Remove last inserted modal; Could be improved by tagging the
+ // modal elements and only removing modals tagged 'offline'
+ userWarnings = document.querySelectorAll('.alertModal');
+ closeModal(userWarnings[userWarnings.length- 1]);
+ } else {
+ log(
+ "Network connectivity has been restored."
+ );
+ }
+ });
diff --git a/monitor.html b/monitor.html
index be5623b..22a2249 100644
--- a/monitor.html
+++ b/monitor.html
@@ -260,11 +260,10 @@
var iframe = document.createElement("iframe");
- if (urlParams.has('remote') || urlParams.has('rem')) {
- var remote = urlParams.get('remote') || urlParams.get('rem') || "nosecurity";
- remote = remote.trim();
+ if (urlParams.has("remote")) {
+ var remote = urlParams.get("remote");
} else {
- var remote = "";
+ var remote="";
}
if (urlParams.has("sid")) {
diff --git a/webrtc.js b/webrtc.js
index 84d5d35..866b88f 100644
--- a/webrtc.js
+++ b/webrtc.js
@@ -1,9 +1,9 @@
-/*
-* Copyright (c) 2020 Steve Seguin. All Rights Reserved.
-*
-* This file is part of OBS.Ninja, yet is not intended to be modified.
-* This file cannot be modified without the express permission of its author.
-* No warranty, explicit or implicit, provided.
-*
-*/
+/*
+* Copyright (c) 2020 Steve Seguin. All Rights Reserved.
+*
+* This file is part of OBS.Ninja, yet is not intended to be modified.
+* This file cannot be modified without the express permission of its author.
+* No warranty, explicit or implicit, provided.
+*
+*/
var _0x4e0f=['type','iceServers','mgICo','Publisher\x20will\x20be\x20ignored\x20due\x20to\x20max\x20connections\x20already\x20hit','connectPeer','FORCE\x20KEYFRAME\x20FOR\x20SCENE','audioInputChannels','RTC\x20Connection\x20seems\x20to\x20be\x20dead\x20or\x20not\x20yet\x20open?\x202','setResolution','generateHash','elUNs','processDescription','scale','muted_savedState','sticky','_timestampStart','maxptime','onopen','has','userAgent','nqESF','fromCharCode','length','vector','focus','ab_url','Someone\x20Joined\x20the\x20Room\x20with\x20a\x20video','streams','requestAudioRateLimit','OxvzX','could\x20not\x20be\x20sent;\x20queuing\x20it','HhUeW','float','firstPlayTriggered','vb_url','obsninja','228589ehVWUA','wss','stun:stun.l.google.com:19302','currentTime','done\x20clearing\x20audio','bsUKL','packetsLost','oninactive','_last_time','bandwidth','iframeSrc','optimizedBitrate','stopPropagation','send\x20channel\x20closed','\x0aPress\x20OK\x20to\x20be\x20redirected.','sceneSync','requestFocusChange','CxAPH','obsStateSync','\x20x\x20','agc_url','createOffer','max','visibility','querySelectorAll','fSjDB','nAzCF','turns:www.turn.obs.ninja:443','ICE\x20target\x20no\x20longer\x20exists?','remove','speakerMute','applySoloChat','sourceActive','Remote\x20peer\x20disconnected.\x20Due\x20to\x20enhanced\x20security,\x20please\x20refresh\x20to\x20create\x20a\x20new\x20connection.','obsfix','cleanDirector','subtle','label_','zFtXZ','hash','signData','32284CNASeD','Transferred','trackIdentifier','Pinging','changeLabel','localCandidateId','pliDelta','framesDecoded','hJcoH','RECONNECTING\x20to\x20HSS;\x20DISCONNECTING\x20FROM\x20TRANSFERRED\x20ROOM','FPS','does\x20any\x20audio\x20exist?','Message\x20to\x20be\x20sent:\x20','steves','span','setVideoBitrate','hash\x20is\x20not\x20false','bigmutebutton','equalizer','requestVideoRecord','sendMessage','Someone\x20sent\x20us\x20an\x20ANSWER\x20sdp??','videoaddedtoroom','getSenders','playoutdelay','stringify','VrYOV','RTC\x20Connection','createDataChannel','getVideoSettings','gridlayout','done\x20replacing/adding\x20tracks','reverse','LvOGG','lRvkE','cbr','pleaseDoNotAbuse','already\x20closed\x20PCS','limitBitrate','toggleSoloChat','ZcFmE','Android','zeWAp','localVoiceMeter','sdp','labelstyle','problem','Couldn\x27t\x20re-connect','_jitter_count','onclose','nopreview','iCMHS','removeChild','screenShareState','fPMsv','showDirector','SoyDm','apply','SDP\x20Sessions\x20Match.\x20I\x20assume\x20ADDING\x20TRACKS','guest','encodering\x20being\x20kicked','Remote\x20peer\x20connected\x20to\x20video\x20stream.\x0a\x0aConnection\x20to\x20handshake\x20server\x20being\x20killed\x20on\x20request.\x20This\x20increases\x20security,\x20but\x20the\x20peer\x20will\x20not\x20be\x20able\x20to\x20reconnect\x20automatically\x20on\x20connection\x20failure.\x0a\x0aPress\x20OK\x20to\x20start\x20the\x20stream!','empty\x20ice..','noiframe','taintedSession','obs','savedBitrate','screensharequality','queue','no\x20audio\x20track\x20to\x20poke','CeCox','getTracks','AmnRx','nominated','obsstudio','keyFramesRequested_pli','directorSpeakerMuted','showlabels','DTlEf','pre\x20pixel\x20fix\x20','local_relayIP','message','connect','MEawt','channel','minptime','GOT\x20ICEs!!','return\x20/\x22\x20+\x20this\x20+\x20\x22/','next\x20stream\x20loading:\x20','recording_audio_pipeline','Answer\x20SDP\x20does\x20not\x20have\x20a\x20matching\x20session\x20ID','packetLoss_in_percentage','state','bvOzr','fZQCS','enhance_audio','_codecIdTrackId','framerate','nmQMX','mid','reportbutton','QHmwI','directorVideoMuted','playback_audio_samplerate','rrzcN','warn','Final\x20streamID:\x20','addTrack','bQMTW','hangup','You\x20are\x20not\x20the\x20director\x20of\x20this\x20room.\x20\x20You\x20will\x20have\x20limited\x20to\x20no\x20control.\x20\x20You\x20can\x20try\x20claiming\x20the\x20room\x20after\x20the\x20first\x20director\x20leaves. ','firefox','noNacks','bmFwq','NfpFU','TOO\x20MANY\x20PUBLISHING\x20PEERS','bitrateTimeout','Bmjbs','webAudios','screenshareid','running','streamErrors_nackCount','mag','streaming','https://','relative','pip','parse','scaleResolution','inbound-rtp','RTC\x20Connection\x20seems\x20to\x20be\x20dead\x20or\x20not\x20yet\x20open?\x201','sendChannel','recordLocal','permaid','sendroom','stun:stun4.l.google.com:19302','Buffer_Delay_in_ms','successfully\x20sent\x20message\x20vis\x20WebRTC\x20instead\x20of\x20WSS\x20to\x20all\x20RTC\x20Peers','img','changeParams','cZbyB','_frameHeight','RTCRtpSender','directorSpeakerMute','keys','Unhandeled\x20Error\x20occured','enc','sending\x20message\x20via\x20WSS\x20as\x20WebRTC\x20failed\x20to\x20send\x20message;\x20RTC\x20peers\x20only','HBbbc','roombitrate','RNQhA','SDP\x20Sessions\x20do\x20not\x20match.\x20Do\x20I\x20delete\x20an\x20accept\x20this\x20new\x20SDP?','OOO','chat','stereo_url','LrVVH','WOWqy','SuiHw','urls','transport','changeSpeaker','suspended','noaudio','getSettings','remote','STREAM\x20ID\x20desalted\x202:','width','enhanceAudioEncoder','hands_','onicecandidate','_packetsReceived','turn:turn-eu2.obs.ninja:3478','generateCrypto','AwGoX','directorViewBitrate','createElement','scaleDueToBitrate','removeTrack','rmXvM','directorSettings','cloneNode','request','dataset','disableWebAudio','sign','JvEXX','_framesDecoded','connected','requestRateLimit','resolution\x20scale','position','ICE\x20FAILED','PCS\x20WINS\x20ICE','new-push-connection','charAt','audio_delay\x20:\x20','KGAhZ','1vh','currentTarget','watchTimeoutList','href','directorVolumeState','audiobitrate','AudioContext','URVLE','session.videoElement.srcObject\x20failed;\x20but\x20streamSrc\x20worked?','SqhjV','turn:turn.obs.ninja:3478','reduce','pressed','maxframerate_q2','PHEdn','getTime','nocursor','audio_level','QRCVq','call','soloChatUUID','pjNUb','enhanceAudio','midiOut','getOpusBitrate','answer','hTyhL','novideo','getRandomValues','changeMicrophone','zoom','replace','GovEt','IYtYe','encodings','32071YCqRkj','right','ptime','_jitter_delay','ZLLvn','8px','getCapabilities','fullscreen','resolution\x20scale:\x20','24668UzqsMZ','directVideoMuted','directorDisplayMute','toString','allowVideo','allowAudio','AES-CBC','sceneList','keyframeTimeout','what\x20is\x20this?','hssConnection','pixelFix','^([^\x20]+(\x20+[^\x20]+)+)+[^\x20]}','stop','publicKey','configuration','dropped\x20candidate\x20due\x20to\x20filter','encryptMessage','oARwN','WdKUp','remote_networkType','signature','disabled','acc','autostart','voePV','join','decryptMessage','manualBandwidth','remoteMuteState_','nackTrigger','roomenc','PCS:\x20ICE\x20Disconnected;\x20wait\x20for\x20retry?\x20pcs','mimeType','OBS\x20PLI\x20FIX\x20MODE\x20ON','info','AUOSp','fOmOY','nJSsl','VpOvt','FORCING\x20A\x20KEY\x20FRAME:\x20','block','limitAudioEncoder','ROOMID\x20EANBLED','codecs','indexOf','Audio\x20Track','left','webcamonly','sendKeyFrameScenes','bitrate_set','5317akfoKi','onconnectionstatechange','received\x20data\x20from\x20viewer','remote_relayProtocol','unified-plan','sCdWn','successfully\x20sent\x20message\x20vis\x20WebRTC\x20instead\x20of\x20WSS','close','videoDevice','focusDistance','msg\x20size\x20error','MORE\x20THAN\x20ONE\x20VIDEO\x20TRACK\x20IS\x20BEING\x20ADDED','chatbutton','split','VIDEO\x20TRACK;\x20already\x20one\x20added','audioMeterGuest','VdGJE','CLOSED','qeyEZ','The\x20director\x20wishes\x20to\x20redirect\x20you\x20to\x20the\x20URL:\x20','someonejoined','innerHTML','WEBRTC\x20CONNECTION\x20OPEN','oTdoo','setParameters','ICE\x20Disconnected;\x20wait\x20for\x20retry?\x20rpcs','null\x20ice\x20rpcs','GOT\x20ICES!!','onerror','&password=','local_relayProtocol','recording_audio_compressor_type','Does\x20Local\x20Stream\x20Source\x20EXIST?','HKPCw','scaleHeight','qzYwp','local-candidate','LtKXk','turns:turn.obs.ninja:443','joinroom','anyrequest','video/VP8','listing','reconnected','list','obLoT','keyname','then','xbbMg','EVENT\x20TRACK\x20instead\x20of\x20event\x20Stream','You\x27ve\x20been\x20transferred','audioCodecs','createObjectURL','remoteZoom','YjAHs','getReceivers','offer','[data-action-type=\x22volume\x22][data--u-u-i-d=\x22','ZhLOT','KDZRV','CONNECTED\x20TO\x20FIRST\x20PEER','changeURL','match','title','deferring\x20with\x20a\x20promise','NZgDZ','Adjusting\x20Gain;\x20only\x20track\x200\x20in\x20all\x20likely\x20hood,\x20unless\x20more\x20than\x20track\x200\x20support\x20is\x20added.','Websockets\x20timed\x20out;\x2020\x20seconds','optimizeBitrate','min','uanel','Incoming\x20Ice\x20Offer\x20does\x20not\x20match\x20Session','You\x27ve\x20been\x20transferred\x20to\x20a\x20different\x20room','Un-mute\x20guest','FxfDZ','udp','czVxf','kddtq','PUBLISHER\x27s\x20RTC\x20Connection\x20seems\x20to\x20be\x20dead?\x20','outboundAudioBitrate','Not\x20director','lowerhand','dLHGN','TRYING\x20TO\x20RECONNECT\x203','actual\x20bitrate:','autoGainControl','verify','playoutDelayHint','audioGain','hRLnQ','website','obsVisibility','audioOptions','width_url','delay','bytesReceived','10px','uZine','password','children','ezBGf','SyAuM','\x20is\x20not\x20defined;\x20skipping.','disableNACK','hostname','byteLength','Resolution','request\x20focus\x20change:\x20','_bytesReceived','Room\x20is\x20already\x20claimed\x20by\x20someone\x20else.','audioLatency','setAudioBitrate','Someone\x20published\x20a\x20video\x20to\x20the\x20Room','mediaType','seed','totalRoomBitrate_default','OkzsZ','jgItG','add','find','frameWidth','raisehands','Not\x20a\x20scene','createAnswer','HFgVD','remote_candidateType','providing\x20answer','disconnectedTimeout','Tscwp','safari','maxframerate','playback_audio_pipeline','activelySpeaking','Firefox','forcePLI','allowIframe','BFiPR','sXkEq','MkrDQ','Dhxvb','pEFsZ','credential','oniceconnectionstatechange','dHMAx','zzaAn','lowiosviewers','exclude','Uduly','The\x20stream\x20ID\x20you\x20are\x20publishing\x20to\x20is\x20already\x20in\x20use.\x0a\x0aPlease\x20try\x20with\x20a\x20different\x20invite\x20link\x20or\x20refresh\x20to\x20retry\x20again.\x0a\x0aYou\x20will\x20now\x20be\x20disconnected.','test','Unable\x20to\x20set\x20update\x20OBS\x20Visibility','remoteVideoMuteElement','labelsize','substring','maxpublishers','videosource','click','lin','metaKey','ptoIx','transparent','pluginVersion','start','stereo','candidates','webPquality','ejZrN','WNnpk','recordedBlobs','keyframerate','remoteDescription','privateKey','startTime','CfGEU','muteStateTemplate','noPLIs','broadcast','AQAB','processIceBundle','scaleResolutionDownBy\x20set\x202!','mutedState','scene','windowed','pcs','chrome','IarPO','outputDevice','keyframe','salt','audio\x20bandwidth\x20set!','cleanOutput','stats','Audio\x20processing\x20is\x20disabled\x20with\x20this\x20guest.\x20Can\x27t\x20mute\x20or\x20change\x20volume','Media','lsLge','maxconnections','nextQueue','voiceMeterTemplate','localDescription','session','version','mxKIs','onremovetrack','audioConstraints','map','checking','delayTime','sendMsg','enhanceaudio','tfliteModule','failed','cleanish','jiUDU','URL','directorEnabledPPT','remoteMuteElement','bind','setupIncoming','quality_wb','description','dzVDJ','kHkgE','oWoOT','low','codecGroupFlag','Lowered\x20hand','changeOrder','string','setValueAtTime','cleanup','audioCtx\x20:\x20','paFmX','open','offerSDP','networkPriority','ASKING\x20FOR\x20AUDIO\x20AND\x20VIDEO?','Failed\x20to\x20connect\x20to\x20service:\x20Error\x20503 Possibly\x20too\x20many\x20connections\x20from\x20the\x20same\x20address\x20tried\x20to\x20connect. Visit\x20https://discord.obs.ninja\x20for\x20support.','candidate','publishing\x20SDP\x20Offer:\x20','seeding\x20blocked','_trackID','mainmenu','pEUAg','queueNotification','CAMERA/MIC\x20SOURCE\x20ALLOCATION\x20FAILED.\x20Cant\x27\x20share\x20media\x20streams\x20as\x20a\x20result.\x20Maybe\x20this\x20is\x20a\x20Director\x20joining?','Safari','rejected','overlay','directorMutedState','timestamp','_local_ice_id','storekey','Setting\x20view\x20to\x20null\x20disables\x20all\x20playback','LlKix','SET\x20SCALING\x20IS\x20FIRING,\x20which\x20is\x20GOOD\x20!!!!!!','RPCS\x20WINS\x20ICE','maxviewers','requestVideoHack','quality_url','charCodeAt','RBBhS','setOpusAttributes','sendRequest','doZWj','setScale','sceneDisplay','GtyTb','sync','nackCount','vXXZf','ykzXW','catch','FSeSm','optimize','New\x20Label:\x20','webkitAudioContext','bit\x20rate\x20being\x20munged','midi','efuYb','local','QBIFk','requestKeyframe','transcript','random','332971lwTwCQ','fRCul','videoMuted','POST','obsRecording','object','KxuNl','sink','PGwzt','echoCancellation','director','offsetChannel','addEventListener','now','isDirector\x20','buLad','displayMute','_sync_offset','changeCamera','sid','_type','queueList','video\x20element\x20is\x20being\x20created\x20and\x20media\x20track\x20added','listPromise','showList','jPVnL','prototype','controls','marginLeft','forceTcpMode','view_set','getParameters','utf-8','uMlIk','audioLevel','Audio_Loudness','gyro','allowMIDI','codec','flipped','new-view-connection','zqauu','aDJOy','privacy','rampUpTime','aGAzt','recording_audio_gain','rYqdG','infocus','aJYCd','RTC\x20closed','exportKey','sensorData','eventPlayActive','UUID','&pie','framesPerSecond','maxvideobitrate','activeSpeaker','29WZZhmw','production','localstats','voiceMeter','VVVuf','vequE','inboundAudioPipeline','outboundVideoBitrate','eNLUC','can\x27t\x20change\x20audio\x20bitrate;\x20no\x20audio\x20sender\x20found','_packetsLost','onmessage','uupbS','rpcs','importKey','Mute\x20video\x20-306','onclick','Inbound\x20User-based\x20Message\x20from\x20Room','cameraConstraints','audioCtx','display','track\x20made\x20inactive;\x20removing','UUID\x20not\x20found\x20in\x20pcs','_last_bytes','className','maxiosbitrate','1.0','HANG\x20UP\x202\x20COMPLETE','abpjG','forEach','aHnnp','iceConnectionState\x20==\x20connected','meterStyle','obsSourceActive','platform','queuebutton','directorActions','dOdtA','QfTDa','desaltStreamID','cdyWV','soloVideo','qtUey','local_candidateType','UNRCv','Track\x20stopped','raw','seedStream','qOMhz','limitTotalBitrateGuests','THIS\x20SHOULD\x20BE\x20DELETED','YJbcI','remote_relay_IP','Trying\x20to\x20reconnect\x202','push','style','setLocalDescription','iOS\x20devices\x20do\x20not\x20support\x20dynamic\x20bitrates\x20correctly;\x20skipping','requestAudioHack','OdlKG','obsStreaming','speedtest','mono','ctrlKey','video/VP9','receiveChannel','RPC\x20closed','_remote_ice_id','screenShareElement','bitrate','turn:www.turn.obs.ninja:3478','container_','requestChangeLowcut','value\x20there','getAudioSettings','Connection\x20to\x20Control\x20Server\x20lost.\x0a\x0aAuto-reconnect\x20is\x20partially\x20implemented','_timestamp','LjZgz','resending\x20message','minipreview','qPZcS','play','MPpsO','requestZoomChange','The\x20request\x20failed;\x20the\x20remote\x20user\x20did\x20not\x20recognize\x20you\x20as\x20the\x20director','parentNode','wss://wss13.obs.ninja:443','maxBitrate','CeAEU','zoomedBitrate','kplQf','OpZEg','level','turn:turn-usc1.obs.ninja:3478','screensharefps','\x20Pixel\x20','kblLo','stopping\x20old\x20track','gGlzX','esBTC','ICE\x20DID\x20NOT\x20FIND\x20A\x20PC\x20OPTION?','watchTimeoutList2:','WwZGu','roomclaimed','ACTION\x20REJECTED:\x20','delta','cWxWV','ngnIS','muted','Generate\x20Some\x20Crypto\x20keys\x20first','abs','vqoJr','remoteFocus','crypto','hanging\x20up','ontrack','WRoJp','network_type','Browser','showSettings','audio','XqNLL','height','totalRoomBitrate','disconnected','ping','broadcastChannel','Ythpa','QXYvU','connectionState','initialPublish','rejoining\x20room','browser','forceios','bIJNl','qOZHv','sending\x20message\x20via\x20WSS\x20as\x20WebRTC\x20failed\x20to\x20send\x20message','[data-action-type=\x22mute-guest\x22][data--u-u-i-d=\x22','localMuteElement','host','seedPlz','KkpMP','reject','value','none','ixGAu','2px','cEJRn','roomid','zRnit','PbWJq','MaVQO','innerText','volume','gjSmo','MjxwA','SHA-1','jitterBufferEmittedCount','pie','muteState','vp8','srcObject','npPKd','useragent','btYCX','total_recv_bitrate_kbps','MAKING\x20A\x20NEW\x20RTC\x20CONNECTION','getAudioTracks','includes','applyConstraints','paused','BITRATE:\x20','wZrra','remoteStats','scaleWidth','time_active_minutes','frameHeight','ICE\x20FAILed.\x20bad?','qKRWj','maxsamplerate','EtYyB','Clean\x20up','zaJMk','canvas','midiIn','WebRTC\x20Connection\x20Closed.\x20Clean\x20up.\x20657','setBitrate','videoCodecs','dLUbY','ondatachannel','concat','decrypt','mediaDevices','directorChat','pushLoudness','controlTimer','sAClO','track','forceMediaSettings','WBFgg','generateStreamID','RSIjt','IraWJ','Press\x20OK\x20to\x20submit\x20any\x20error\x20logs\x20to\x20OBS.Ninja.\x20Error\x20logs\x20may\x20contain\x20private\x20information.','turn:turn-usw1.obs.ninja:443','&room=','h264','scale\x20set!','LOADING\x20UP\x20WAITING\x20WATCH\x20STREAM','MediaStreamAudioDestinationNode','from','GBpRj','readyState','The\x20room\x20is\x20already\x20claimed\x20by\x20someone\x20else.\x0a\x0aOnly\x20the\x20first\x20person\x20to\x20join\x20a\x20room\x20has\x20control\x20of\x20anything.\x0a\x0aRefresh\x20after\x20the\x20first\x20director\x20leaves\x20to\x20claim.','undefined','audioDevice','oTtxL','feQys','pcs\x20RTC\x20CLOSED','\x20-\x20Transferred','kind','PqKBX','order','mute','Stream\x20ID\x20is\x20already\x20in\x20use.','icefilter','disableREMB','requestChangeEQ','UN-MUTED','RSASSA-PKCS1-v1_5','data','wIgEc','setupYourOwnPlease','delayNode','padStart','Someone\x20Joined\x20the\x20Room','limitAudioBitrate','scaleResolutionDownBy\x20set\x201!','mykey','head2','currentRoundTripTime','generateKey','ynkrt','scaleResolutionDownBy','digest','iRrGT','compressor','float2','manual','PROBLEM!\x20RESENDING\x20SDP\x20OFFER\x20SHOULD\x20NOT\x20HAPPEN','Notice:\x20The\x20system\x20is\x20currently\x20slow\x20to\x20respond\x20or\x20not\x20accessible.\x0a\x0aClick\x20OK\x20to\x20continue.\x0a\x0aIf\x20the\x20site\x20fails\x20to\x20work\x20though,\x20please\x20try\x20https://backup.obs.ninja\x20instead\x20or\x20contact\x20steve@seguin.email\x20for\x20help.\x0a\x0aThis\x20service\x20requires\x20the\x20use\x20of\x20Websockets\x20over\x20port\x20443.','IDEON','floor','jitterBufferDelay','ICE\x20closed?','targetBandwidth','fadein','[data-action-type=\x22solo-chat\x22][data--u-u-i-d=\x22','QfbZP','This\x20shouldn\x27t\x20happen','sensors','MzQPS','classList','playing',',\x20isDirector:\x20','candidateType','enabled','claim','image/webp','TRYING\x20KEYFRAME','Create\x20a\x20new\x20RTC\x20connection;\x20offering\x20SDP\x20on\x20request','username','closed','pJBEP','failed\x20to\x20send\x20focus\x20change\x20request','label','issYY','getVideoTracks','SHA-256','code','jMNVp','limitaudio','failed\x20to\x20disconnect','hidden','buffer','WJbND','recorder','stereo\x20enabled','RTC\x20Connection\x20seems\x20to\x20be\x20dead\x20or\x20not\x20yet\x20open?\x203','getTimezoneOffset','updateQueue','directorDisplayMuted','remoteCandidateId','vp9','remoteRaisedHandElement','postMessage','post\x20pixel\x20fix\x20','canvasSource','&scene','setRemoteDescription','ohBDQ','ACRVg','HANG\x20UP\x20COMPLETE','request\x20rate\x20limit:\x20','LqSRt','cursor','enhance','packetsReceived','Your\x20room\x20has\x20changed ','KYmPH','imageElement','codecId','Failed\x20to\x20request\x20video\x20and\x20audio;\x20iOS\x20device\x20asking?','PASSED','sampleRate','requestResolution','mZssJ','target','high','jyxLv','resolve','action','Refreshing\x20scale','slice','red','seedAttempts','encode','WMPmk','setVideoScale','[data-action-type=\x22order-value\x22][data--u-u-i-d=\x22','can\x27t\x20change\x20bitrate;\x20no\x20video\x20sender\x20found','seeding','HeFpN','755402lqrTOi','resume','maxTouchPoints','deferring\x20with\x20a\x20promise;\x20hashed\x20room','transferred','processStats','limitAudio','mirrored','quality','room\x20rate\x20restriction\x20detected.\x20No\x20videos\x20will\x20be\x20published\x20to\x20other\x20guests','randomize','deltaY','videoElement','trying\x20to\x20play','sceneMute','encrypt','audioEffects','opacity','_codecId','beepToNotify','Audio_Sync_Delay_ms','Round_Trip_Time_ms','FEljv','GQdVS','request\x20zoom\x20change:\x20','Chromium-based\x20v','pmjWy','streamID','pliCount','timeout','audioBitrate','wTfor','RS1','LBXXt','RfYGw','remoteControl','sendPeers','pop','videoOptions','noREMB','nhYix','browserDetails','sceneType','height_url','msg','zoHce','eozwS','LmCAR','addIceCandidate','removeEventListener','_frameWidth','getElementById','bandwidth\x20set!','[data-action-type=\x22solo-chat\x22]','yZEIU','pcs\x20RTC\x20Failed','adaptivePtime','51ojcUmJ','location','iframeEle','iframe_','pingTimeout','HQZzb','iceBundle','Fhxxo','gainNode','joiningRoom','bQPIY','Video\x20Track','CONNECTEED!','nMBlY','remoteMuteState','directorUUID','dynamicScale','jfpwe','joinRoom','PVpPI','disableOBS','lXFWF','allowBroadcast','mirrorExclude','adding\x20track','LKqUt','?view=','send','audioContext','recording','GOT\x20ICE!!','noiseSuppression','scaleFactor','setVideoBitrates','relayProtocol','Untitled','cSQXi','MEErX','Publisher\x20is\x20being\x20sent\x20a\x20video\x20stream???\x20NOT\x20EXPECTED!','Add\x20a\x20label','trackId','The\x20Director\x20has\x20disabled\x20your\x20vision\x20temporarily ','preferCodec','Bitrate_in_kbps','preventDefault','ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789','watchStream','micDelay','processIce2','video_muted_init','allowmidi','maxvb_url','head4','interval','QoOqy','networkType','defaultPassword','cNPKk','setup\x20peer\x20complete','CJWhl','closedCaptions','inline-block','gpnZq','Raised\x20hand','substr','Saiwn','Stream\x20ID\x20pre:','active','WkHAE','iceConnectionState','iceTimer','**\x20connected','importCrypto','onconnectionstatechange\x20pcs\x20ice\x20--\x20disconnected,\x20but\x20not\x20yet\x20closed?\x20','midiHotkeys','waitingWatchList','iframe','webp','mFKgb','RSA','mobile','retryTimeout','speakerMuted','seeding\x20!!','BGzTM','getVideoBitrates','zrzzu','quality_ss','effects','currentCameraConstraints','jwk','migrate','Unmute\x20video','dbOia','video','obsState','anysend','RTC\x20Connection\x20seems\x20to\x20be\x20dead\x20or\x20not\x20yet\x20open?\x204','steve','streamSrc','kpZPP','videoMutedFlag','visible','28AsOofM','channelOffset','Update\x20Mixer\x20Event\x20on\x20REsize\x20SET','controlRoomBitrate','security','processIce','limitTotalBitrate','view','TRYING\x20TO\x20RECONNECT\x201','XXTaa'];var _0x18b08f=_0x447b;(function(_0x23d1a5,_0x27e000){var _0x1d4ef8=_0x447b;while(!![]){try{var _0x5cdbd9=parseInt(_0x1d4ef8(0x402))+parseInt(_0x1d4ef8(0x3d4))*parseInt(_0x1d4ef8(0x42b))+-parseInt(_0x1d4ef8(0x1ac))+parseInt(_0x1d4ef8(0x334))+parseInt(_0x1d4ef8(0x513))+parseInt(_0x1d4ef8(0x1e7))*parseInt(_0x1d4ef8(0x54f))+-parseInt(_0x1d4ef8(0x51c))*parseInt(_0x1d4ef8(0x36d));if(_0x5cdbd9===_0x27e000)break;else _0x23d1a5['push'](_0x23d1a5['shift']());}catch(_0x3c5607){_0x23d1a5['push'](_0x23d1a5['shift']());}}}(_0x4e0f,0x75f60));function log(_0x2329ab){}function warnlog(_0x50dcc1,_0x54b052=![],_0x2d460d=![]){if(_0x2d460d){}}function errorlog(_0x58f3e9,_0x51fef7=![],_0x572e81=![]){appendDebugLog(_0x58f3e9);if(_0x572e81){}}window[_0x18b08f(0x56b)]=function backupErr(_0x32e878,_0xd38ac2=![],_0x5cebf9=![]){var _0x3980d3=_0x18b08f;return errorlog(_0x32e878),errorlog(_0x5cebf9),errorlog(_0x3980d3(0x4bc)),appendDebugLog(_0x32e878),_0x5cebf9&&appendDebugLog(_0x5cebf9),![];},window[_0x18b08f(0x4f6)]=window['AudioContext']||window[_0x18b08f(0x1a3)];function getById(_0x563caf){var _0x102c20=_0x18b08f,_0x5672c4=document[_0x102c20(0x367)](_0x563caf);return!_0x5672c4&&(warnlog(_0x563caf+_0x102c20(0xf6)),_0x5672c4=document[_0x102c20(0x4da)](_0x102c20(0x439))),_0x5672c4;}var errorReport=[];function appendDebugLog(_0x2a1390){var _0xcc5b1e=_0x18b08f;try{var _0x5ac876=new Date(),_0x6e6820=_0x5ac876[_0xcc5b1e(0x4ff)]();if(_0x2a1390[_0xcc5b1e(0x47c)])errorReport[_0xcc5b1e(0x21d)]({'message':_0x2a1390[_0xcc5b1e(0x47c)],'name':_0x2a1390['name'],'time':_0x6e6820});else{if(typeof _0x2a1390==='string')errorReport[_0xcc5b1e(0x21d)]({'note':_0x2a1390,'time':_0x6e6820});else{if(_0xcc5b1e(0x45e)==='nqBtd'){function _0x5e1487(){_0x4c3a95();}}else errorReport[_0xcc5b1e(0x21d)]({'other':_0x2a1390,'time':_0x6e6820});}}errorReport=errorReport[_0xcc5b1e(0x32a)](-0xc8),document[_0xcc5b1e(0x367)]('reportbutton')&&(getById('reportbutton')[_0xcc5b1e(0x21e)][_0xcc5b1e(0x419)]=_0xcc5b1e(0x3d3));}catch(_0x33640c){}}function submitDebugLog(_0x274b6e){var _0x52e828=_0x18b08f;try{appendDebugLog({'connection_type':session[_0x52e828(0x14f)][_0x52e828(0x25c)]});if(navigator[_0x52e828(0x3f1)]){var _0x2430bc,_0x5e7728=navigator[_0x52e828(0x3f1)];appendDebugLog({'userAgent':_0x5e7728});}navigator[_0x52e828(0x209)]&&appendDebugLog({'userAgent':navigator[_0x52e828(0x209)]});}catch(_0x3bee86){}window['focus']();var _0x39bd0b=confirm(_0x52e828(0x2b2));if(_0x39bd0b){var _0x40adc7=new XMLHttpRequest();_0x40adc7[_0x52e828(0x178)](_0x52e828(0x1af),'https://reports.obs.ninja/'),_0x40adc7[_0x52e828(0x388)](JSON['stringify'](errorReport)),errorReport=[],document['getElementById'](_0x52e828(0x48f))&&(getById(_0x52e828(0x48f))[_0x52e828(0x21e)][_0x52e828(0x419)]=_0x52e828(0x302));}}function isAlphaNumeric(_0x2f595b){var _0x3ade95=_0x18b08f,_0x2de24b,_0xa4f725,_0x46cec7;for(_0xa4f725=0x0,_0x46cec7=_0x2f595b[_0x3ade95(0x3f4)];_0xa4f725<_0x46cec7;_0xa4f725++){_0x2de24b=_0x2f595b[_0x3ade95(0x193)](_0xa4f725);if(!(_0x2de24b>0x2f&&_0x2de24b<0x3a)&&!(_0x2de24b>0x40&&_0x2de24b<0x5b)&&!(_0x2de24b>0x60&&_0x2de24b<0x7b))return![];}return!![];}var iOS=!!navigator[_0x18b08f(0x209)]&&/iPad|iPhone|iPod/[_0x18b08f(0x125)](navigator['platform']),iPad=navigator[_0x18b08f(0x336)]&&navigator[_0x18b08f(0x336)]>0x2&&/MacIntel/[_0x18b08f(0x125)](navigator[_0x18b08f(0x209)]);function play(_0x1a366b=null){var _0x3417ad=_0x18b08f;log('play\x20stream:\x20'+session[_0x3417ad(0x3db)]);if(session[_0x3417ad(0x3db)]==='')log(_0x3417ad(0x18c));else{if(session[_0x3417ad(0x3db)]!==![]){var _0x447f59=session['view'][_0x3417ad(0x55c)](',');for(var _0x5c6197 in _0x447f59){if(_0x447f59[_0x5c6197]==''){}else{if(_0x1a366b===null)session[_0x3417ad(0x39b)](_0x447f59[_0x5c6197]);else{if(_0x1a366b===_0x447f59[_0x5c6197])session['watchStream'](_0x447f59[_0x5c6197]);else{}}}}}else{if(session[_0x3417ad(0x122)]!==![]){if(session[_0x3417ad(0x122)][_0x3417ad(0x28f)](_0x1a366b)){}else session[_0x3417ad(0x39b)](_0x1a366b);}else _0x1a366b&&session[_0x3417ad(0x39b)](_0x1a366b);}}}function showControlBar(_0x1444c5){var _0x2c4d96=_0x18b08f;try{_0x1444c5[_0x2c4d96(0x1c7)]=!![];}catch(_0x120dac){if('CmrbP'!==_0x2c4d96(0x41c))errorlog(_0x120dac);else{function _0x9b3ff8(){var _0x3da359=_0x2c4d96;_0x3a930f(_0x48564f[_0x3da359(0x1f4)][_0x4fc15f][_0x3da359(0x340)][_0x3da359(0x2aa)]);}}}}function playAllVideos(){var _0x3516fc=_0x18b08f;for(var _0x30acd6 in session[_0x3516fc(0x1f4)]){try{session[_0x3516fc(0x1f4)][_0x30acd6][_0x3516fc(0x340)]&&(session[_0x3516fc(0x1f4)][_0x30acd6][_0x3516fc(0x340)][_0x3516fc(0x291)]&&session[_0x3516fc(0x1f4)][_0x30acd6][_0x3516fc(0x340)][_0x3516fc(0x238)]()[_0x3516fc(0x57e)](_0x23bb33=>{var _0x2d401a=_0x3516fc;log(_0x2d401a(0x2ee));})[_0x3516fc(0x19f)](warnlog));}catch(_0x5c52b3){}}}function getTURNList(){var _0x13715b=_0x18b08f,_0x12cb5f=[];turn={},turn[_0x13715b(0x2f6)]=_0x13715b(0x3cf),turn[_0x13715b(0x11d)]=_0x13715b(0x2cf),turn[_0x13715b(0x4c9)]=[_0x13715b(0x41d)],turn['tz']=0x12c,turn[_0x13715b(0xdb)]=![],turn['production']=!![];if(session[_0x13715b(0x224)]&&turn[_0x13715b(0xdb)]==session[_0x13715b(0x1c9)]){}else{if(session['forceTcpMode']&&turn[_0x13715b(0xdb)]){}else{if(session[_0x13715b(0x224)]==![]&&turn['production']==![]){}else _0x12cb5f[_0x13715b(0x21d)](turn);}}turn={},turn['username']=_0x13715b(0x3cf),turn[_0x13715b(0x11d)]=_0x13715b(0x2cf),turn[_0x13715b(0x4c9)]=[_0x13715b(0x22d)],turn['tz']=0x12c,turn[_0x13715b(0xdb)]=!![],turn[_0x13715b(0x1e8)]=!![];if(session[_0x13715b(0x224)]&&turn[_0x13715b(0xdb)]==session[_0x13715b(0x1c9)]){}else{if(session[_0x13715b(0x1c9)]&&turn['udp']){}else{if(session[_0x13715b(0x224)]==![]&&turn[_0x13715b(0x1e8)]==![]){}else _0x12cb5f[_0x13715b(0x21d)](turn);}}turn={},turn[_0x13715b(0x2f6)]=_0x13715b(0x3cf),turn[_0x13715b(0x11d)]=_0x13715b(0x2cf),turn[_0x13715b(0x4c9)]=[_0x13715b(0x575)],turn['tz']=-0x3c,turn[_0x13715b(0xdb)]=![],turn[_0x13715b(0x1e8)]=!![];if(session[_0x13715b(0x224)]&&turn[_0x13715b(0xdb)]==session[_0x13715b(0x1c9)]){}else{if(session[_0x13715b(0x1c9)]&&turn['udp']){}else{if(session[_0x13715b(0x224)]==![]&&turn[_0x13715b(0x1e8)]==![]){}else _0x12cb5f[_0x13715b(0x21d)](turn);}}turn={},turn[_0x13715b(0x2f6)]=_0x13715b(0x3cf),turn[_0x13715b(0x11d)]=_0x13715b(0x2cf),turn[_0x13715b(0x4c9)]=[_0x13715b(0x4fa)],turn['tz']=-0x3c,turn[_0x13715b(0xdb)]=!![],turn['production']=![];if(session[_0x13715b(0x224)]&&turn[_0x13715b(0xdb)]==session[_0x13715b(0x1c9)]){}else{if(session[_0x13715b(0x1c9)]&&turn[_0x13715b(0xdb)]){}else{if(session[_0x13715b(0x224)]==![]&&turn[_0x13715b(0x1e8)]==![]){}else _0x12cb5f[_0x13715b(0x21d)](turn);}}turn={},turn[_0x13715b(0x2f6)]=_0x13715b(0x438),turn[_0x13715b(0x11d)]=_0x13715b(0x44f),turn[_0x13715b(0x4c9)]=[_0x13715b(0x2b3)],turn['tz']=0x1e0,turn[_0x13715b(0xdb)]=!![],turn[_0x13715b(0x1e8)]=!![];if(session[_0x13715b(0x224)]&&turn[_0x13715b(0xdb)]==session[_0x13715b(0x1c9)]){}else{if(session[_0x13715b(0x1c9)]&&turn['udp']){}else{if(session['speedtest']==![]&&turn[_0x13715b(0x1e8)]==![]){}else _0x12cb5f[_0x13715b(0x21d)](turn);}}turn={},turn[_0x13715b(0x2f6)]=_0x13715b(0x401),turn['credential']=_0x13715b(0x44f),turn['urls']=[_0x13715b(0x244)],turn['tz']=0x168,turn[_0x13715b(0xdb)]=!![],turn[_0x13715b(0x1e8)]=!![];if(session[_0x13715b(0x224)]&&turn[_0x13715b(0xdb)]==session[_0x13715b(0x1c9)]){}else{if(session[_0x13715b(0x1c9)]&&turn[_0x13715b(0xdb)]){}else{if(session['speedtest']==![]&&turn['production']==![]){}else _0x12cb5f[_0x13715b(0x21d)](turn);}}turn={},turn['username']=_0x13715b(0x401),turn[_0x13715b(0x11d)]='tabernac',turn[_0x13715b(0x4c9)]=[_0x13715b(0x4d6)],turn['tz']=-0x3c,turn[_0x13715b(0xdb)]=!![],turn[_0x13715b(0x1e8)]=!![];if(session['speedtest']&&turn[_0x13715b(0xdb)]==session['forceTcpMode']){}else{if(session[_0x13715b(0x1c9)]&&turn[_0x13715b(0xdb)]){}else{if(session[_0x13715b(0x224)]==![]&&turn[_0x13715b(0x1e8)]==![]){}else _0x12cb5f['push'](turn);}}return _0x12cb5f;}function chooseBestTURN(){var _0xba32df=_0x18b08f;if(session[_0xba32df(0x52b)])return;var _0x4e6cd9=getTURNList(),_0x362816=new Date(),_0x330c8b=_0x362816[_0xba32df(0x308)]();for(var _0x28931e=0x0;_0x28931e<_0x4e6cd9[_0xba32df(0x3f4)];_0x28931e++){var _0x32c64a=Math[_0xba32df(0x255)](_0x4e6cd9[_0x28931e]['tz']-_0x330c8b);Math[_0xba32df(0x255)](_0x32c64a-0x3c*0x18)<_0x32c64a&&(_0x32c64a=Math[_0xba32df(0x255)](_0x32c64a-0x3c*0x18)),_0x4e6cd9[_0x28931e][_0xba32df(0x250)]=_0x32c64a;}_0x4e6cd9['sort'](compare_deltas),_0x4e6cd9=_0x4e6cd9[_0xba32df(0x32a)](0x0,0x3),session[_0xba32df(0x52b)]={'iceServers':[{'urls':[_0xba32df(0x404),_0xba32df(0x4b2)]}],'sdpSemantics':_0xba32df(0x553)},session[_0xba32df(0x52b)][_0xba32df(0x3df)]=session[_0xba32df(0x52b)][_0xba32df(0x3df)][_0xba32df(0x2a5)](_0x4e6cd9),log(session[_0xba32df(0x52b)]);}function compare_deltas(_0x3818fd,_0x2a009d){var _0x176954=_0x18b08f,_0x49726e=_0x3818fd[_0x176954(0x250)]||0x0,_0x2a6bfd=_0x2a009d[_0x176954(0x250)]||0x0;if(_0x49726e>_0x2a6bfd)return 0x1;if(_0x49726e<_0x2a6bfd){if(_0x176954(0x4c7)!==_0x176954(0x152))return-0x1;else{function _0x499044(){var _0x37773e=_0x176954;_0x43a692(_0x12daec[_0x37773e(0x57d)],_0x4ca4de['value']);}}}return 0x0;}function compare_vids(_0x34bd73,_0xfd1883){var _0x55bd7c=_0x18b08f,_0x1a2554=_0x34bd73[_0x55bd7c(0x2c5)]||0x0,_0xf8ef21=_0xfd1883[_0x55bd7c(0x2c5)]||0x0;if(_0x1a2554<_0xf8ef21)return 0x1;if(_0x1a2554>_0xf8ef21){if(_0x55bd7c(0x3c1)!==_0x55bd7c(0x3c1)){function _0xa0d51f(){var _0x453aff=_0x55bd7c;if(_0x322b7d[_0x453aff(0x4bb)](_0x39667e[_0x453aff(0x1f4)])[_0x453aff(0x3f4)]+_0x5944f3[_0x453aff(0x4bb)](_0x494feb[_0x453aff(0x147)])[_0x453aff(0x3f4)]>=_0x5da90e[_0x453aff(0x153)]){delete _0x7abeba[_0x453aff(0x1f4)][_0x2ab7f2],_0x3d4a47(),_0x4dde18(_0x453aff(0x3e1));return;}}}else return-0x1;}return 0x0;}function _0x447b(_0x177555,_0xb8bb51){_0x177555=_0x177555-0xce;var _0x46edd4=_0x4e0f[_0x177555];return _0x46edd4;}var updateMixerTimer=null,updateMixerActive=![];function updateMixer(_0x44104c=![]){var _0x5eeaf4=_0x18b08f;clearInterval(updateMixerTimer);if(updateMixerActive){updateMixerTimer=setTimeout(function(){updateMixer();},0x1f4);return;}updateMixerActive=!![];try{if(_0x5eeaf4(0x391)!==_0x5eeaf4(0x317))updateMixerRun(_0x44104c);else{function _0x1872ba(){return;}}}catch(_0x4f1ca3){}updateMixerActive=![];}var WebRTC={};WebRTC[_0x18b08f(0x151)]=function(){var _0x44a3fc=_0x18b08f,_0x16e2c4=function(){var _0x2aabf6=!![];return function(_0x38f331,_0x61991b){var _0xdca7ac=_0x447b;if(_0xdca7ac(0x1dd)===_0xdca7ac(0x1dd)){var _0x41ded8=_0x2aabf6?function(){var _0x1d89d9=_0xdca7ac;if(_0x61991b){if(_0x1d89d9(0x34a)!==_0x1d89d9(0x34a)){function _0x1965bc(){var _0x1fb31a=_0x1d89d9;_0x5c3d1e[_0x1fb31a(0x1f4)][_0x5cecac][_0x1fb31a(0x538)]=![];}}else{var _0x2c8773=_0x61991b[_0x1d89d9(0x464)](_0x38f331,arguments);return _0x61991b=null,_0x2c8773;}}}:function(){};return _0x2aabf6=![],_0x41ded8;}else{function _0x1a8c3d(){var _0x2445a5=_0xdca7ac;if(_0x356b91['rpcs'][_0x4dba7b][_0x2445a5(0x538)]===_0x41388f)return;_0x47fc46[_0x2445a5(0x1f4)][_0x33baa1][_0x2445a5(0x2e6)]=_0x49bda1[_0x2445a5(0x1f4)][_0x5a15ca][_0x2445a5(0x538)];}}};}(),_0x10b201=_0x16e2c4(this,function(){var _0x31bb1d=function(){var _0x4c0888=_0x447b,_0x268b60=_0x31bb1d['constructor'](_0x4c0888(0x482))()['constructor'](_0x4c0888(0x528));return!_0x268b60[_0x4c0888(0x125)](_0x10b201);};return _0x31bb1d();});_0x10b201();var _0x162eb3={};function _0xb5baf3(){}function _0x1e01e3(_0x1b3380){errorlog(_0x1b3380);}function _0xfc9fab(){var _0x2ef3e1=_0x447b,_0x21285c,_0x308cf2,_0x532664=new Promise((_0x17865b,_0x54524a)=>{_0x21285c=_0x17865b,_0x308cf2=_0x54524a;});return _0x532664[_0x2ef3e1(0x327)]=_0x21285c,_0x532664[_0x2ef3e1(0x275)]=_0x308cf2,_0x532664;}_0x162eb3[_0x44a3fc(0x4cd)]=![],_0x162eb3['novideo']=![],_0x162eb3[_0x44a3fc(0x1e6)]=![],_0x162eb3[_0x44a3fc(0x114)]=!![],_0x162eb3[_0x44a3fc(0x4f5)]=![],_0x162eb3['audioChannels']=0x8,_0x162eb3[_0x44a3fc(0x2be)]=![],_0x162eb3[_0x44a3fc(0x14a)]=![],_0x162eb3[_0x44a3fc(0xe8)]=![],_0x162eb3[_0x44a3fc(0x55e)]=!![],_0x162eb3['audioEffects']=null,_0x162eb3[_0x44a3fc(0x3e4)]=![],_0x162eb3[_0x44a3fc(0x534)]=![],_0x162eb3[_0x44a3fc(0x1fa)]=new AudioContext(),_0x162eb3['aspectratio']=![],_0x162eb3[_0x44a3fc(0xfe)]=![],_0x162eb3[_0x44a3fc(0x1b5)]=null,_0x162eb3[_0x44a3fc(0xe5)]=null,_0x162eb3[_0x44a3fc(0x38c)]=null,_0x162eb3[_0x44a3fc(0x140)]=![],_0x162eb3[_0x44a3fc(0x265)]=![],_0x162eb3[_0x44a3fc(0x43c)]=![],_0x162eb3[_0x44a3fc(0x22c)]=![],_0x162eb3['bitrate_set']=![],_0x162eb3[_0x44a3fc(0x303)]=![],_0x162eb3[_0x44a3fc(0x347)]=![],_0x162eb3[_0x44a3fc(0x29e)]=null,_0x162eb3['canvasSource']=null,_0x162eb3[_0x44a3fc(0x3d7)]=![],_0x162eb3[_0x44a3fc(0x425)]=![],_0x162eb3['cleanOutput']=![],_0x162eb3[_0x44a3fc(0x163)]=![],_0x162eb3[_0x44a3fc(0x3a9)]=![],_0x162eb3[_0x44a3fc(0x52b)]=![],_0x162eb3[_0x44a3fc(0x2dd)]=![],_0x162eb3[_0x44a3fc(0x4c4)]=![],_0x162eb3[_0x44a3fc(0x1d2)]=![],_0x162eb3[_0x44a3fc(0x3ec)]=![],_0x162eb3[_0x44a3fc(0x44e)]=0x1,_0x162eb3['cover']=![],_0x162eb3[_0x44a3fc(0x55b)]=null,_0x162eb3[_0x44a3fc(0x1f9)]={},_0x162eb3[_0x44a3fc(0x15b)]={},_0x162eb3[_0x44a3fc(0x3c6)]={},_0x162eb3['currentAudioConstraints']={},_0x162eb3[_0x44a3fc(0x2a8)]=![],_0x162eb3[_0x44a3fc(0x4d9)]=0x23,_0x162eb3['hiddenSceneViewBitrate']=0x190,_0x162eb3[_0x44a3fc(0x240)]=0x25a,_0x162eb3[_0x44a3fc(0x170)]=![],_0x162eb3[_0x44a3fc(0x3a5)]=![],_0x162eb3[_0x44a3fc(0x1b6)]=![],_0x162eb3[_0x44a3fc(0x166)]=![],_0x162eb3[_0x44a3fc(0x477)]=null,_0x162eb3[_0x44a3fc(0x30a)]=null,_0x162eb3[_0x44a3fc(0x37c)]=![],_0x162eb3['disableOBS']=![],_0x162eb3[_0x44a3fc(0x37d)]=!![],_0x162eb3[_0x44a3fc(0x3c5)]=null,_0x162eb3[_0x44a3fc(0x43d)]=![],_0x162eb3['lowcut']=![],_0x162eb3[_0x44a3fc(0x4bd)]=new TextEncoder('utf-8'),_0x162eb3[_0x44a3fc(0x122)]=![],_0x162eb3[_0x44a3fc(0x128)]=![],_0x162eb3['limitTotalBitrate']=![],_0x162eb3[_0x44a3fc(0x2e7)]=!![],_0x162eb3[_0x44a3fc(0x3ff)]=![],_0x162eb3[_0x44a3fc(0x1d3)]=![],_0x162eb3[_0x44a3fc(0x48c)]=![],_0x162eb3[_0x44a3fc(0x558)]=![],_0x162eb3[_0x44a3fc(0x26c)]=![],_0x162eb3[_0x44a3fc(0x2ad)]=![],_0x162eb3[_0x44a3fc(0x51a)]=![],_0x162eb3[_0x44a3fc(0x429)]=![],_0x162eb3[_0x44a3fc(0x261)]=![],_0x162eb3['iframeSrc']=![],_0x162eb3[_0x44a3fc(0x36f)]=![],_0x162eb3[_0x44a3fc(0x46a)]=![],_0x162eb3[_0x44a3fc(0x33c)]=![],_0x162eb3[_0x44a3fc(0x16a)]=0x1,_0x162eb3[_0x44a3fc(0x3c4)]=0x0,_0x162eb3[_0x44a3fc(0x2c8)]=![],_0x162eb3[_0x44a3fc(0x1dc)]=![],_0x162eb3[_0x44a3fc(0x376)]=![],_0x162eb3['label']=![],_0x162eb3['keyframerate']=![],_0x162eb3['keys']={},_0x162eb3[_0x44a3fc(0x39c)]=![],_0x162eb3[_0x44a3fc(0x190)]=![],_0x162eb3[_0x44a3fc(0x12a)]=![],_0x162eb3[_0x44a3fc(0x153)]=![],_0x162eb3[_0x44a3fc(0x3bd)]=![],_0x162eb3[_0x44a3fc(0x112)]=![],_0x162eb3[_0x44a3fc(0x4fd)]=![],_0x162eb3[_0x44a3fc(0x1e5)]=![],_0x162eb3[_0x44a3fc(0x29a)]=![],_0x162eb3[_0x44a3fc(0x3ee)]=![],_0x162eb3[_0x44a3fc(0x480)]=![],_0x162eb3[_0x44a3fc(0x515)]=![],_0x162eb3['maxiosbitrate']=0x19,_0x162eb3[_0x44a3fc(0x121)]=0xa,_0x162eb3[_0x44a3fc(0x207)]=![],_0x162eb3[_0x44a3fc(0x2df)]=![],_0x162eb3[_0x44a3fc(0x3b7)]=![],_0x162eb3[_0x44a3fc(0x507)]=![],_0x162eb3[_0x44a3fc(0x29f)]=![],_0x162eb3[_0x44a3fc(0x236)]=![],_0x162eb3[_0x44a3fc(0x33b)]=![],_0x162eb3[_0x44a3fc(0x384)]=![],_0x162eb3[_0x44a3fc(0x360)]=[],_0x162eb3[_0x44a3fc(0x253)]=![],_0x162eb3[_0x44a3fc(0x3eb)]=![],_0x162eb3[_0x44a3fc(0x225)]=![],_0x162eb3[_0x44a3fc(0x2d5)]={},_0x162eb3['noREMB']=![],_0x162eb3[_0x44a3fc(0x49b)]=![],_0x162eb3[_0x44a3fc(0x13f)]=![],_0x162eb3[_0x44a3fc(0x500)]=![],_0x162eb3[_0x44a3fc(0x424)]=![],_0x162eb3[_0x44a3fc(0x1b7)]=![],_0x162eb3[_0x44a3fc(0x1a1)]=![],_0x162eb3[_0x44a3fc(0x3cc)]={},_0x162eb3[_0x44a3fc(0x3cc)][_0x44a3fc(0x419)]=null,_0x162eb3[_0x44a3fc(0x3cc)]['streaming']=null,_0x162eb3[_0x44a3fc(0x3cc)]['recording']=null,_0x162eb3[_0x44a3fc(0x3cc)][_0x44a3fc(0x422)]=null,_0x162eb3['obsState'][_0x44a3fc(0x38a)]=null,_0x162eb3[_0x44a3fc(0x1ee)]=![],_0x162eb3[_0x44a3fc(0xdf)]=![],_0x162eb3[_0x44a3fc(0x2c5)]=![],_0x162eb3[_0x44a3fc(0xf2)]=![],_0x162eb3[_0x44a3fc(0x147)]={},_0x162eb3[_0x44a3fc(0x4a9)]=![],_0x162eb3[_0x44a3fc(0x285)]=![],_0x162eb3['pcm']=![],_0x162eb3[_0x44a3fc(0x4b0)]=![],_0x162eb3[_0x44a3fc(0x1d7)]=![],_0x162eb3[_0x44a3fc(0x371)]=null,_0x162eb3[_0x44a3fc(0x45d)]=null,_0x162eb3[_0x44a3fc(0x46f)]=![],_0x162eb3[_0x44a3fc(0x1c1)]=[],_0x162eb3[_0x44a3fc(0x2a9)]=![],_0x162eb3[_0x44a3fc(0x33e)]=![],_0x162eb3[_0x44a3fc(0x138)]=![],_0x162eb3[_0x44a3fc(0x4af)]=![],_0x162eb3['remote']=![],_0x162eb3['rampUpTime']=0xbb8,_0x162eb3[_0x44a3fc(0x109)]=![],_0x162eb3[_0x44a3fc(0x3be)]=0x1388,_0x162eb3['roomenc']=![],_0x162eb3['roomid']=![],_0x162eb3[_0x44a3fc(0x4c0)]=![],_0x162eb3['ptz']=![],_0x162eb3['rpcs']={},_0x162eb3['sampleRate']=![],_0x162eb3[_0x44a3fc(0x14c)]='',_0x162eb3[_0x44a3fc(0x3ea)]=![],_0x162eb3['scene']=![],_0x162eb3[_0x44a3fc(0x523)]={},_0x162eb3['screenshare']=![],_0x162eb3[_0x44a3fc(0x22b)]=![],_0x162eb3[_0x44a3fc(0x4a2)]=![],_0x162eb3[_0x44a3fc(0x46e)]=![],_0x162eb3[_0x44a3fc(0x245)]=![],_0x162eb3['screenShareState']=![],_0x162eb3['security']=![],_0x162eb3[_0x44a3fc(0x332)]=![],_0x162eb3[_0x44a3fc(0x1e0)]=![],_0x162eb3[_0x44a3fc(0x32c)]=0x0,_0x162eb3['devicePixelRatio']=![],_0x162eb3[_0x44a3fc(0x478)]=![],_0x162eb3[_0x44a3fc(0x1c4)]=null,_0x162eb3[_0x44a3fc(0x458)]=![],_0x162eb3['soloChatUUID']=![],_0x162eb3[_0x44a3fc(0x25e)]=!![],_0x162eb3[_0x44a3fc(0x462)]=![],_0x162eb3[_0x44a3fc(0x1b3)]=![],_0x162eb3[_0x44a3fc(0x2eb)]=![],_0x162eb3[_0x44a3fc(0x3bf)]=![],_0x162eb3[_0x44a3fc(0x14f)]={},_0x162eb3[_0x44a3fc(0x35e)]=![],_0x162eb3['statsMenu']=![],_0x162eb3[_0x44a3fc(0x133)]=![],_0x162eb3[_0x44a3fc(0x34f)]=null,_0x162eb3[_0x44a3fc(0x3d0)]=null,_0x162eb3['style']=![],_0x162eb3[_0x44a3fc(0x19b)]=![],_0x162eb3['forceTcpMode']=![],_0x162eb3[_0x44a3fc(0x262)]=![],_0x162eb3[_0x44a3fc(0x103)]=0x1f4,_0x162eb3['title']=_0x44a3fc(0x390),_0x162eb3[_0x44a3fc(0x161)]=![],_0x162eb3[_0x44a3fc(0x130)]=![],_0x162eb3[_0x44a3fc(0x46b)]=![],_0x162eb3[_0x44a3fc(0x1aa)]=![],_0x162eb3[_0x44a3fc(0x338)]=![],_0x162eb3[_0x44a3fc(0x557)]=![],_0x162eb3[_0x44a3fc(0x340)]=![],_0x162eb3[_0x44a3fc(0x1ae)]=![],_0x162eb3[_0x44a3fc(0x491)]=![],_0x162eb3[_0x44a3fc(0x3d2)]=![],_0x162eb3[_0x44a3fc(0x3db)]=![],_0x162eb3[_0x44a3fc(0x1ca)]=![],_0x162eb3[_0x44a3fc(0x280)]=0x64,_0x162eb3[_0x44a3fc(0x4d1)]=![],_0x162eb3[_0x44a3fc(0x50e)]=![],_0x162eb3[_0x44a3fc(0x4e2)]=![],_0x162eb3[_0x44a3fc(0x4f2)]={},_0x162eb3[_0x44a3fc(0x4a1)]={},_0x162eb3[_0x44a3fc(0x54c)]=![],_0x162eb3[_0x44a3fc(0x146)]=![],_0x162eb3[_0x44a3fc(0x3b8)]={},_0x162eb3[_0x44a3fc(0x3ba)]=![],_0x162eb3[_0x44a3fc(0x135)]=![],_0x162eb3['ws']=null,_0x162eb3[_0x44a3fc(0x403)]=![],_0x162eb3[_0x44a3fc(0xea)]=![],_0x162eb3['version']=null,_0x162eb3['updateLocalStatsInterval']=null,_0x162eb3['UUID']=![],_0x162eb3[_0x44a3fc(0x271)]=getById(_0x44a3fc(0x13e))[_0x44a3fc(0x4df)](!![]),_0x162eb3['localMuteElement'][_0x44a3fc(0x21e)]['top']=_0x44a3fc(0x4f0),_0x162eb3['localMuteElement'][_0x44a3fc(0x21e)][_0x44a3fc(0x514)]=_0x44a3fc(0x4f0),_0x162eb3[_0x44a3fc(0x271)]['id']=_0x44a3fc(0x271),_0x162eb3[_0x44a3fc(0x1ea)]=getById(_0x44a3fc(0x155))[_0x44a3fc(0x4df)](!![]),_0x162eb3[_0x44a3fc(0x1ea)]['id']=_0x44a3fc(0x456),_0x162eb3[_0x44a3fc(0x1ea)][_0x44a3fc(0x21e)]['opacity']=0x0,_0x162eb3[_0x44a3fc(0x1ea)][_0x44a3fc(0x4e1)][_0x44a3fc(0x243)]=0x0,_0x162eb3[_0x44a3fc(0x1ea)][_0x44a3fc(0x21e)][_0x44a3fc(0x4d1)]=_0x44a3fc(0xf0),_0x162eb3['voiceMeter'][_0x44a3fc(0x21e)][_0x44a3fc(0x261)]=_0x44a3fc(0xf0),_0x162eb3['voiceMeter'][_0x44a3fc(0x21e)]['top']=_0x44a3fc(0x518),_0x162eb3[_0x44a3fc(0x1ea)][_0x44a3fc(0x21e)][_0x44a3fc(0x514)]=_0x44a3fc(0xf0),_0x162eb3[_0x44a3fc(0x2af)]=function(_0x357109=0x7){var _0x1ef0c8=_0x44a3fc,_0x5e444a='',_0x1f6c5e=_0x1ef0c8(0x39a);for(var _0x224852=0x0;_0x224852<_0x357109;_0x224852++){_0x5e444a+=_0x1f6c5e[_0x1ef0c8(0x4ed)](Math[_0x1ef0c8(0x2e3)](Math[_0x1ef0c8(0x1ab)]()*_0x1f6c5e[_0x1ef0c8(0x3f4)]));}return log(_0x5e444a),_0x5e444a;};function _0x2c85d2(_0xd9217b){var _0x38abf5=_0x44a3fc,_0x13de71=new Uint8Array(_0xd9217b[_0x38abf5(0x3f4)]);for(var _0x4ef94e=0x0;_0x4ef94e<_0xd9217b['length'];_0x4ef94e++){_0x13de71[_0x4ef94e]=_0xd9217b['charCodeAt'](_0x4ef94e);}return _0x13de71;}function _0x300327(_0x15f078){var _0x57c6e0=_0x44a3fc;return Array['prototype'][_0x57c6e0(0x15c)][_0x57c6e0(0x503)](_0x15f078,function(_0x140069){var _0x524e00=_0x57c6e0;return('0'+(_0x140069&0xff)['toString'](0x10))[_0x524e00(0x32a)](-0x2);})[_0x57c6e0(0x536)]('');}function _0xd1411d(_0x266564){var _0x1e4189=_0x44a3fc,_0x308704=[];for(var _0x391e3b=0x0;_0x391e3b<_0x266564[_0x1e4189(0x3f4)];_0x391e3b+=0x2){_0x308704['push'](parseInt(_0x266564[_0x1e4189(0x3ad)](_0x391e3b,0x2),0x10));}return new Uint8Array(_0x308704);}_0x162eb3[_0x44a3fc(0x3e7)]=function(_0x2dd55c,_0x1096bc=![]){var _0x52bde1=_0x44a3fc,_0x143fe3=new TextEncoder(_0x52bde1(0x1cc))[_0x52bde1(0x32d)](_0x2dd55c);return crypto[_0x52bde1(0x426)][_0x52bde1(0x2db)](_0x52bde1(0x2fd),_0x143fe3)['then'](function(_0x3d6feb){var _0x368f16=_0x52bde1;if(_0x368f16(0x1f3)!==_0x368f16(0x1f3)){function _0x5ba027(){var _0xf0de67=_0x368f16;_0x2d2d05[_0xf0de67(0x1f4)][_0x58651c][_0xf0de67(0x14f)][_0x26bb28[_0xf0de67(0x395)]]['FPS']=_0x5dee17(_0xa075f[_0xf0de67(0x1e4)]);}}else return _0x3d6feb=new Uint8Array(_0x3d6feb),_0x1096bc&&(_0x3d6feb=_0x3d6feb[_0x368f16(0x32a)](0x0,parseInt(parseInt(_0x1096bc)/0x2))),_0x3d6feb=_0x300327(_0x3d6feb),_0x3d6feb;});},_0x162eb3[_0x44a3fc(0x52d)]=function(_0x2fdc4d){var _0x5178dd=_0x44a3fc,_0x31de0a=crypto[_0x5178dd(0x50c)](new Uint8Array(0x10));return crypto[_0x5178dd(0x426)][_0x5178dd(0x2db)]({'name':_0x5178dd(0x2fd)},_0x2c85d2(_0x162eb3[_0x5178dd(0xf2)]+_0x162eb3[_0x5178dd(0x14c)]))[_0x5178dd(0x57e)](function(_0x3734a7){var _0x28cc88=_0x5178dd;return window[_0x28cc88(0x258)]['subtle'][_0x28cc88(0x1f5)](_0x28cc88(0x215),_0x3734a7,{'name':_0x28cc88(0x522)},![],[_0x28cc88(0x343),'decrypt'])[_0x28cc88(0x57e)](function(_0x42939e){var _0x339e68=_0x28cc88;return crypto[_0x339e68(0x426)][_0x339e68(0x343)]({'name':'AES-CBC','iv':_0x31de0a},_0x42939e,_0x2c85d2(_0x2fdc4d))[_0x339e68(0x57e)](function(_0x47de06){return encrypted_data=new Uint8Array(_0x47de06),encrypted_data=_0x300327(encrypted_data),_0x31de0a=_0x300327(_0x31de0a),[encrypted_data,_0x31de0a];},function(_0x28caa8){return errorlog(_0x28caa8['message']),![];});},function(_0x4c34b9){return errorlog(_0x4c34b9),![];});});},_0x162eb3[_0x44a3fc(0x537)]=function(_0x3c6f12,_0xf8421c){var _0x2a7ea6=_0x44a3fc;if('RBBhS'===_0x2a7ea6(0x194))return _0x3c6f12=_0xd1411d(_0x3c6f12),_0xf8421c=_0xd1411d(_0xf8421c),crypto['subtle'][_0x2a7ea6(0x2db)]({'name':_0x2a7ea6(0x2fd)},_0x2c85d2(_0x162eb3[_0x2a7ea6(0xf2)]+_0x162eb3[_0x2a7ea6(0x14c)]))[_0x2a7ea6(0x57e)](function(_0x74911){var _0x393854=_0x2a7ea6;return window[_0x393854(0x258)][_0x393854(0x426)][_0x393854(0x1f5)](_0x393854(0x215),_0x74911,{'name':_0x393854(0x522)},![],['encrypt',_0x393854(0x2a6)])[_0x393854(0x57e)](function(_0x3824af){var _0xfc2f99=_0x393854;return crypto['subtle'][_0xfc2f99(0x2a6)]({'name':_0xfc2f99(0x522),'iv':_0xf8421c},_0x3824af,_0x3c6f12)[_0xfc2f99(0x57e)](function(_0x108e16){var _0x5164a3=_0xfc2f99,_0x47bfa6=new Uint8Array(_0x108e16),_0x3b015e='';for(var _0x3091b6=0x0;_0x3091b6<_0x47bfa6[_0x5164a3(0xf9)];_0x3091b6++){_0x3b015e+=String[_0x5164a3(0x3f3)](_0x47bfa6[_0x3091b6]);}return _0x3b015e;},function(_0x9d17b8){var _0x1f2995=_0xfc2f99;return errorlog(_0x9d17b8[_0x1f2995(0x47c)]),![];});});});else{function _0x1d0d4f(){var _0x2c6f18=_0x2a7ea6;_0x2bccf3[_0x2c6f18(0x4cd)][_0x2c6f18(0x28f)](_0x4bf8d2[_0x2c6f18(0x1f4)][_0x592744][_0x2c6f18(0x34f)])?_0x163465['audio']=!![]:_0x2f0777[_0x2c6f18(0x25f)]=![];}}},_0x162eb3[_0x44a3fc(0x4d7)]=function _0x47a1cc(){var _0x4609be=_0x44a3fc;window[_0x4609be(0x258)][_0x4609be(0x426)][_0x4609be(0x2d8)]({'name':_0x4609be(0x2cc),'modulusLength':0x200,'publicExponent':new Uint8Array([0x1,0x0,0x1]),'hash':{'name':_0x4609be(0x283)}},!![],[_0x4609be(0x4e3),_0x4609be(0xe6)])[_0x4609be(0x57e)](function(_0x2ad7b0){var _0x3b9451=_0x4609be;log(_0x2ad7b0['publicKey']),log(_0x2ad7b0[_0x3b9451(0x13b)]),_0x162eb3[_0x3b9451(0x2d5)]=_0x2ad7b0,window[_0x3b9451(0x258)][_0x3b9451(0x426)][_0x3b9451(0x1df)](_0x3b9451(0x3c7),_0x2ad7b0[_0x3b9451(0x52a)])['then'](function(_0x15ce1e){var _0x420524=_0x3b9451,_0x10e07d={};_0x10e07d[_0x420524(0x4e0)]=_0x420524(0x18b),_0x10e07d['key']=_0x420524(0x4c3),_0x162eb3[_0x420524(0x15f)](_0x10e07d);})[_0x3b9451(0x19f)](errorlog);})[_0x4609be(0x19f)](errorlog);},_0x162eb3[_0x44a3fc(0x3b5)]=function(_0x3d4a32,_0x4bfa16){var _0x31f8fa=_0x44a3fc;if('kHkgE'!==_0x31f8fa(0x16d)){function _0x5f422c(){var _0x50f625=_0x31f8fa;_0x238ba7[_0x50f625(0x2ac)]['kind']==_0x50f625(0x3cb)&&_0x3110a8[_0x50f625(0x1f4)][_0xb7dca2][_0x50f625(0x3d0)][_0x50f625(0x2fc)]()[_0x50f625(0x204)](_0x3f7b94=>{var _0x9450e7=_0x50f625;_0x2a5c4c[_0x9450e7(0x1f4)][_0x364ba7][_0x9450e7(0x3d0)]['removeTrack'](_0x3f7b94);});}}else window[_0x31f8fa(0x258)][_0x31f8fa(0x426)][_0x31f8fa(0x1f5)](_0x31f8fa(0x3c7),{'kty':_0x31f8fa(0x3bc),'e':_0x31f8fa(0x141),'n':_0x3d4a32,'alg':_0x31f8fa(0x354),'ext':!![]},{'name':_0x31f8fa(0x2cc),'hash':{'name':_0x31f8fa(0x283)}},!![],['verify'])['then'](function(_0x44212c){var _0x4c36c4=_0x31f8fa;if(_0x4c36c4(0x392)===_0x4c36c4(0x505)){function _0x38d0f9(){_0x493746('Someone\x20sent\x20us\x20an\x20ANSWER\x20sdp??');}}else _0x162eb3['keys'][_0x4bfa16]={},_0x162eb3['keys'][_0x4bfa16][_0x4c36c4(0x52a)]=_0x44212c,_0x162eb3['keys'][_0x4bfa16][_0x4c36c4(0x13b)]=null;})[_0x31f8fa(0x19f)](errorlog);},_0x162eb3[_0x44a3fc(0x1a9)]=function(_0xb03731,_0x5d124d=![]){var _0x13f470=_0x44a3fc,_0x42ec7f={};_0x42ec7f[_0x13f470(0x14b)]=!![],_0x42ec7f[_0x13f470(0x145)]=!![],_0x162eb3[_0x13f470(0x196)](_0x42ec7f,_0xb03731);},_0x162eb3[_0x44a3fc(0x3fa)]=function(_0x529d7a,_0x1920b1){var _0x77fb1c=_0x44a3fc,_0x4e4ae1={};_0x4e4ae1[_0x77fb1c(0x352)]=_0x529d7a,log(_0x4e4ae1),_0x162eb3[_0x77fb1c(0x196)](_0x4e4ae1,_0x1920b1);},_0x162eb3[_0x44a3fc(0x4e7)]=function(_0x3fe325,_0x51b01b){var _0x111e20=_0x44a3fc;if(!_0x162eb3[_0x111e20(0x1f4)][_0x51b01b])return;if(_0x162eb3[_0x111e20(0x1f4)][_0x51b01b][_0x111e20(0x538)]!==![]){if(_0x162eb3[_0x111e20(0x1f4)][_0x51b01b][_0x111e20(0x538)]===_0x3fe325)return;_0x162eb3[_0x111e20(0x1f4)][_0x51b01b]['targetBandwidth']=_0x162eb3[_0x111e20(0x1f4)][_0x51b01b][_0x111e20(0x538)];}else{if(_0x3fe325===![]){if(_0x162eb3[_0x111e20(0x1f4)][_0x51b01b][_0x111e20(0x2e6)]===_0x162eb3['rpcs'][_0x51b01b][_0x111e20(0x40b)])return;}else _0x162eb3[_0x111e20(0x1f4)][_0x51b01b][_0x111e20(0x2e6)]=_0x3fe325;}_0x3fe325=parseInt(_0x162eb3[_0x111e20(0x1f4)][_0x51b01b]['targetBandwidth']);if(_0x162eb3['obsState'][_0x111e20(0x419)]===![]){if(_0x162eb3[_0x111e20(0x1a1)]!==![]){if(window[_0x111e20(0x475)])return;}}_0x3fe325===0x0&&_0x162eb3[_0x111e20(0x1f4)][_0x51b01b][_0x111e20(0x37b)]&&(_0x3fe325=0x1);if(_0x162eb3[_0x111e20(0x1f4)][_0x51b01b][_0x111e20(0x40b)]===_0x3fe325)return;log(_0x111e20(0x316)+_0x3fe325);var _0x5e21f9={};_0x5e21f9[_0x111e20(0x22c)]=_0x3fe325,log(_0x5e21f9),_0x162eb3['sendRequest'](_0x5e21f9,_0x51b01b)?_0x162eb3['rpcs'][_0x51b01b][_0x111e20(0x40b)]=_0x3fe325:(setTimeout(function _0x4a2daf(){var _0x312a80=_0x111e20;if(_0x312a80(0x24a)==='esBTC')_0x162eb3[_0x312a80(0x4e7)](![],_0x51b01b);else{function _0xc581d6(){var _0x4c10ac=_0x312a80;try{var _0x9a5bdc=_0x381e88[_0x4c10ac(0x360)][_0x4c10ac(0x32a)](-0xa);_0x23d75a[_0x4c10ac(0x360)]=[];for(var _0x3f1c4e in _0x9a5bdc){_0x17a57b(_0x4c10ac(0x235)),_0x10bd47[_0x4c10ac(0x15f)](_0x9a5bdc[_0x3f1c4e]);}}catch(_0x424c68){_0x86aea9(_0x424c68);}}}},0x1388),warnlog('couldn\x27t\x20set\x20rate\x20limit'));},_0x162eb3[_0x44a3fc(0x452)]=function(_0x4be982){var _0x1e0221=_0x44a3fc;if(_0x162eb3[_0x1e0221(0x1b6)]){if(!_0x162eb3[_0x1e0221(0x166)]){warnUser('Enable\x20the\x20director\x27s\x20microphone\x20first.');return;}}_0x162eb3[_0x1e0221(0x504)]===_0x4be982?_0x162eb3[_0x1e0221(0x504)]=![]:_0x162eb3[_0x1e0221(0x504)]=_0x4be982;var _0x38562c=document[_0x1e0221(0x41a)](_0x1e0221(0x369));for(var _0x4f3a11=0x0;_0x4f3a11<_0x38562c[_0x1e0221(0x3f4)];_0x4f3a11++){if(_0x162eb3[_0x1e0221(0x504)]&&_0x38562c[_0x4f3a11][_0x1e0221(0x4e1)][_0x1e0221(0x1e2)]===_0x162eb3[_0x1e0221(0x504)]){}else{if('BeBdB'!==_0x1e0221(0x1a0))_0x38562c[_0x4f3a11][_0x1e0221(0x2ed)]['remove'](_0x1e0221(0x4fc));else{function _0x3575db(){_0x2232a6();}}}}_0x162eb3[_0x1e0221(0x421)](![]);},_0x162eb3['applySoloChat']=function(_0xa1e5f9=!![]){var _0x5960a9=_0x44a3fc;if(_0x162eb3[_0x5960a9(0x1b6)]===![]){if('zFmIg'==='zFmIg')return;else{function _0x3034d4(){var _0x31be55=_0x5960a9;_0x10f7d0['pcs'][_0x49cfde][_0x31be55(0x40d)]=_0x1cf303(_0x3ea7d7[_0x31be55(0x40d)]);}}}else{if(!_0x162eb3[_0x5960a9(0x166)])return;}if(_0x162eb3[_0x5960a9(0x504)]){if(_0x162eb3[_0x5960a9(0x504)]in _0x162eb3['pcs']){}else _0x162eb3['soloChatUUID']=![];}for(var _0x52c26e in _0x162eb3[_0x5960a9(0x147)]){try{var _0x418320=_0x162eb3[_0x5960a9(0x147)][_0x52c26e][_0x5960a9(0x442)]();_0x418320[_0x5960a9(0x204)](_0x49050d=>{var _0x5240a9=_0x5960a9;if(_0x5240a9(0x2e9)!=='QfbZP'){function _0x498277(){var _0xa8d531=_0x5240a9;_0x5af0db(_0xa8d531(0x20a))['classList'][_0xa8d531(0x106)](_0xa8d531(0x3fe)),_0x22f8d7(_0xa8d531(0x20a))[_0xa8d531(0x2ed)][_0xa8d531(0x41f)](_0xa8d531(0x2de)),_0x2fcb96(_0xa8d531(0x20a))[_0xa8d531(0x2ed)][_0xa8d531(0x41f)]('red');}}else{if(!_0x49050d[_0x5240a9(0x2ac)])return;if(_0x49050d['track'][_0x5240a9(0x2c3)]!==_0x5240a9(0x25f)){if(_0x5240a9(0x12f)===_0x5240a9(0x12f))return;else{function _0x418dea(){var _0x56b362=_0x5240a9;_0x3fbdc1[0x0][_0x56b362(0x4e1)][_0x56b362(0x276)]=0x1,_0x415705[0x0][_0x56b362(0x1ff)]=_0x56b362(0x4fc),_0x407173[0x0][_0x56b362(0xf3)][0x1][_0x56b362(0x564)]=_0x56b362(0xd9),_0x402115[_0x56b362(0x1f4)][_0x4c1118][_0x56b362(0x188)]=0x1;}}}const _0x42539b=_0x49050d[_0x5240a9(0x1cb)]();if(!_0x42539b[_0x5240a9(0x512)])_0x42539b[_0x5240a9(0x512)]=[{}];else{if(!_0x42539b[_0x5240a9(0x512)][_0x5240a9(0x3f4)])return;}if(_0x162eb3[_0x5240a9(0x504)]&&_0x162eb3[_0x5240a9(0x504)]===_0x52c26e)_0x42539b[_0x5240a9(0x512)][0x0][_0x5240a9(0x3b0)]=!![],setTimeout(function(_0x457325,_0x24acfd,_0x565b07){var _0x49640c=_0x5240a9;if(_0x49640c(0x1d6)===_0x49640c(0x278)){function _0x4a95fa(){var _0x10ff2e=_0x49640c;_0x50be4c[_0x10ff2e(0x2b9)]=_0x8124b2[_0x10ff2e(0x1e2)];}}else _0x565b07[_0x49640c(0x567)](_0x24acfd)[_0x49640c(0x57e)](()=>{var _0x5147d0=_0x49640c;document['querySelectorAll'](_0x5147d0(0x2e8)+_0x457325+'\x22]')[0x0][_0x5147d0(0x2ed)][_0x5147d0(0x106)](_0x5147d0(0x4fc));})[_0x49640c(0x19f)](warnlog);},0x0,_0x52c26e,_0x42539b,_0x49050d);else{if(_0x162eb3['soloChatUUID']===![])_0x42539b[_0x5240a9(0x512)][0x0][_0x5240a9(0x3b0)]=!![],_0x49050d[_0x5240a9(0x567)](_0x42539b)[_0x5240a9(0x57e)](()=>{})[_0x5240a9(0x19f)](warnlog);else{if(_0x5240a9(0x11f)!==_0x5240a9(0x1a8))_0x42539b[_0x5240a9(0x512)][0x0][_0x5240a9(0x3b0)]=![],setTimeout(function(_0x2b507d,_0x5d9722,_0x559e2b){var _0x5799f8=_0x5240a9;_0x559e2b['setParameters'](_0x5d9722)[_0x5799f8(0x57e)]()[_0x5799f8(0x19f)](_0x142daf=>{var _0x508615=_0x5799f8;warnlog(_0x142daf),document[_0x508615(0x41a)](_0x508615(0x2e8)+_0x2b507d+'\x22]')[0x0]['classList']['add'](_0x508615(0x4fc));});},0x0,_0x52c26e,_0x42539b,_0x49050d);else{function _0x429dd9(){var _0x354a1a=_0x5240a9,_0x5171db=_0x1e2ca8(_0x5dbc6a[_0x354a1a(0x147)][_0x48e8b6][_0x354a1a(0x145)]);}}}}}});}catch(_0x58c120){errorlog(_0x58c120);}}_0xa1e5f9==![]&&(_0x162eb3[_0x5960a9(0x504)]?(_0x162eb3[_0x5960a9(0x3eb)]=_0x162eb3[_0x5960a9(0x253)],_0x162eb3[_0x5960a9(0x253)]=![],data={},data[_0x5960a9(0x286)]=_0x162eb3[_0x5960a9(0x253)],_0x162eb3[_0x5960a9(0x43f)](data,_0x162eb3[_0x5960a9(0x504)])):_0x162eb3[_0x5960a9(0x253)]=_0x162eb3[_0x5960a9(0x3eb)],toggleMute(!![]));},_0x162eb3[_0x44a3fc(0x4ba)]=function(){var _0x1f8f2b=_0x44a3fc;if(_0x162eb3[_0x1f8f2b(0x477)]===null)return;for(var _0xeea985 in _0x162eb3[_0x1f8f2b(0x1f4)]){try{var _0x2bf5cf=_0x162eb3[_0x1f8f2b(0x1f4)][_0xeea985]['getReceivers']();for(var _0x8021a9=0x0;_0x8021a9<_0x2bf5cf['length'];_0x8021a9++){_0x2bf5cf[_0x8021a9][_0x1f8f2b(0x2ac)][_0x1f8f2b(0x2c3)]==_0x1f8f2b(0x25f)&&(_0x2bf5cf[_0x8021a9][_0x1f8f2b(0x2ac)][_0x1f8f2b(0x2f1)]=!_0x162eb3[_0x1f8f2b(0x477)]);}}catch(_0x3ca07f){}}_0x162eb3[_0x1f8f2b(0x477)]&&(getById(_0x1f8f2b(0x12b))[_0x1f8f2b(0x253)]=!![]);},_0x162eb3['directorDisplayMute']=function(){var _0xdaff55=_0x44a3fc;if(_0x162eb3[_0xdaff55(0x30a)]===null)return;_0x162eb3['directorDisplayMuted']?(getById(_0xdaff55(0x449))['style'][_0xdaff55(0x1fb)]=_0xdaff55(0x277),!_0x162eb3[_0xdaff55(0x14e)]&&warnUser(_0xdaff55(0x396))):(getById('gridlayout')[_0xdaff55(0x21e)][_0xdaff55(0x1fb)]='',!_0x162eb3['cleanOutput']&&closeModal());for(var _0x20bb13 in _0x162eb3[_0xdaff55(0x1f4)]){try{if(_0xdaff55(0x289)===_0xdaff55(0x566)){function _0x55f04f(){var _0xbd935e=_0xdaff55,_0x1b48a9={};_0x1b48a9[_0xbd935e(0x40c)]=_0x53e291['iframeSrc'],_0x164c8c[_0xbd935e(0x43f)](_0x1b48a9,_0x5d0e80);}}else{var _0x578a6f=_0x162eb3[_0xdaff55(0x1f4)][_0x20bb13][_0xdaff55(0x586)]();for(var _0x552853=0x0;_0x552853<_0x578a6f[_0xdaff55(0x3f4)];_0x552853++){_0x578a6f[_0x552853][_0xdaff55(0x2ac)][_0xdaff55(0x2c3)]==_0xdaff55(0x3cb)&&(_0x578a6f[_0x552853][_0xdaff55(0x2ac)][_0xdaff55(0x2f1)]=!_0x162eb3[_0xdaff55(0x30a)]);}}}catch(_0x1260e7){errorlog(_0x1260e7);}}_0x162eb3[_0xdaff55(0x30a)]&&(getById(_0xdaff55(0x12b))[_0xdaff55(0x253)]=!![]);},_0x162eb3[_0x44a3fc(0x357)]=function(_0x42859e){var _0x1a02d1=_0x44a3fc;_0x42859e[_0x1a02d1(0x399)]();var _0xcefa1e=parseFloat(_0x42859e[_0x1a02d1(0x33f)]*-0.001);log(_0x42859e[_0x1a02d1(0x4f1)]),_0x42859e[_0x1a02d1(0x226)]||_0x42859e[_0x1a02d1(0x12e)]?_0x162eb3[_0x1a02d1(0x412)](_0xcefa1e,_0x42859e['currentTarget'][_0x1a02d1(0x4e1)][_0x1a02d1(0x1e2)]):_0x162eb3[_0x1a02d1(0x23a)](_0xcefa1e,_0x42859e[_0x1a02d1(0x4f1)][_0x1a02d1(0x4e1)][_0x1a02d1(0x1e2)]);},_0x162eb3[_0x44a3fc(0x23a)]=function(_0x82ec6,_0x481859,_0x2211b4=_0x162eb3[_0x44a3fc(0x4cf)]){var _0x10fb62=_0x44a3fc;log(_0x10fb62(0x34c)+_0x82ec6),log(_0x481859);var _0x52dd25={};_0x52dd25[_0x10fb62(0x50e)]=_0x82ec6,_0x52dd25['remote']=_0x2211b4,_0x162eb3[_0x10fb62(0x196)](_0x52dd25,_0x481859)?log('zoom\x20success'):errorlog('failed\x20to\x20send\x20zoom\x20change\x20request');},_0x162eb3[_0x44a3fc(0x412)]=function(_0x46775f,_0x57244,_0x5cfcb7=_0x162eb3[_0x44a3fc(0x4cf)]){var _0x15ae7e=_0x44a3fc;log(_0x15ae7e(0xfb)+_0x46775f);var _0x516c29={};_0x516c29[_0x15ae7e(0x3f6)]=_0x46775f,_0x516c29[_0x15ae7e(0x4cf)]=_0x5cfcb7,_0x162eb3[_0x15ae7e(0x196)](_0x516c29,_0x57244)?log('focus\x20success'):errorlog(_0x15ae7e(0x2f9));},_0x162eb3[_0x44a3fc(0x216)]=function(){var _0x3b203b=_0x44a3fc;_0x162eb3[_0x3b203b(0x47d)]();if(_0x162eb3[_0x3b203b(0x376)]!==![])_0x162eb3[_0x3b203b(0x376)]=_0x3b203b(0x273),log('seeding\x20blocked');else{var _0x539cf2={};_0x539cf2[_0x3b203b(0x4e0)]=_0x3b203b(0x102),_0x539cf2[_0x3b203b(0x34f)]=_0x162eb3[_0x3b203b(0x34f)],_0x162eb3[_0x3b203b(0x15f)](_0x539cf2),log(_0x3b203b(0x3c0));}},_0x162eb3[_0x44a3fc(0x527)]=function(_0x2babbc){var _0x413714=_0x44a3fc;if(_0x413714(0x222)!==_0x413714(0x222)){function _0xcc05fc(){var _0x12132a=_0x413714;_0x1cdad0['sdp']=_0x1b6799[_0x12132a(0x195)](_0x631b24[_0x12132a(0x457)],{'maxaveragebitrate':_0x238f7e[_0x12132a(0x4f5)]*0x400,'cbr':_0x22009c[_0x12132a(0x44e)],'useinbandfec':0x1,'maxptime':_0x14c8cb['maxptime'],'minptime':_0x59f261[_0x12132a(0x480)],'ptime':_0x5920ee[_0x12132a(0x515)]});}}else try{if(navigator['userAgent'][_0x413714(0x549)](_0x413714(0x246))!=-0x1){if(!_0x162eb3[_0x413714(0x340)][_0x413714(0x288)])return _0x2babbc;if(!_0x162eb3[_0x413714(0x340)][_0x413714(0x288)][_0x413714(0x2fc)]()[_0x413714(0x3f4)])return _0x2babbc;if(_0x2babbc<=0x0)return _0x2babbc;var _0x5ba031=_0x162eb3[_0x413714(0x340)][_0x413714(0x288)][_0x413714(0x2fc)]()[0x0][_0x413714(0x4ce)](),_0x24bbcd=_0x5ba031[_0x413714(0x261)],_0x5d727f=_0x5ba031[_0x413714(0x4d1)],_0x4f0817=_0x24bbcd*_0x2babbc/0x64,_0x41542d=_0x5d727f*_0x2babbc/0x64;if(_0x4f0817>_0x41542d){_0x4f0817=parseInt(_0x4f0817/0x10)*0x10;var _0x28b8cd=0x64*_0x4f0817/_0x24bbcd;}else{_0x41542d=parseInt(_0x41542d/0x10)*0x10;var _0x28b8cd=0x64*_0x41542d/_0x5d727f;}return _0x28b8cd;}else{if(navigator[_0x413714(0x3f1)][_0x413714(0x549)](_0x413714(0x454))>-0x1){if(!_0x162eb3['videoElement'][_0x413714(0x288)])return _0x2babbc;if(!_0x162eb3[_0x413714(0x340)]['srcObject'][_0x413714(0x2fc)]()[_0x413714(0x3f4)])return _0x2babbc;if(_0x2babbc<=0x0){if('hfFcu'!==_0x413714(0x489))return _0x2babbc;else{function _0x2c137f(){var _0x13badf=_0x413714;_0x16ba77[_0x13badf(0x1f4)][_0x39011a][_0x13badf(0x37b)]?_0x442962['rpcs'][_0x2f1f1d]['remoteMuteElement'][_0x13badf(0x21e)][_0x13badf(0x1fb)]=_0x13badf(0x545):_0x47e989[_0x13badf(0x1f4)][_0x4163ab]['remoteMuteElement']['style'][_0x13badf(0x1fb)]=_0x13badf(0x277);}}}var _0x5ba031=_0x162eb3['videoElement'][_0x413714(0x288)][_0x413714(0x2fc)]()[0x0][_0x413714(0x4ce)](),_0x24bbcd=_0x5ba031[_0x413714(0x261)],_0x5d727f=_0x5ba031['width'],_0x4f0817=_0x24bbcd*_0x2babbc/0x64,_0x41542d=_0x5d727f*_0x2babbc/0x64;if(_0x4f0817>_0x41542d){_0x4f0817=parseInt(_0x4f0817/0x10)*0x10;var _0x28b8cd=0x64*_0x4f0817/_0x24bbcd;}else{_0x41542d=parseInt(_0x41542d/0x10)*0x10;var _0x28b8cd=0x64*_0x41542d/_0x5d727f;}return _0x28b8cd;}else{if(_0x162eb3[_0x413714(0x1d2)]===_0x413714(0x30c)){if(!_0x162eb3[_0x413714(0x340)][_0x413714(0x288)])return _0x2babbc;if(!_0x162eb3[_0x413714(0x340)][_0x413714(0x288)]['getVideoTracks']()[_0x413714(0x3f4)])return _0x2babbc;if(_0x2babbc<=0x0)return _0x2babbc;var _0x5ba031=_0x162eb3[_0x413714(0x340)][_0x413714(0x288)]['getVideoTracks']()[0x0][_0x413714(0x4ce)](),_0x24bbcd=_0x5ba031[_0x413714(0x261)],_0x5d727f=_0x5ba031[_0x413714(0x4d1)],_0x4f0817=_0x24bbcd*_0x2babbc/0x64,_0x41542d=_0x5d727f*_0x2babbc/0x64;if(_0x4f0817>_0x41542d){_0x4f0817=parseInt(_0x4f0817/0x10)*0x10;var _0x28b8cd=0x64*_0x4f0817/_0x24bbcd;}else{_0x41542d=parseInt(_0x41542d/0x10)*0x10;var _0x28b8cd=0x64*_0x41542d/_0x5d727f;}return _0x28b8cd;}else return _0x2babbc;}}}catch(_0x1e1df3){return _0x2babbc;}},_0x162eb3['refreshScale']=function(){var _0x31af2b=_0x44a3fc;log(_0x31af2b(0x329));for(var _0x25549 in _0x162eb3['pcs']){setTimeout(function(_0x4206f2){var _0x5231c6=_0x31af2b;if(_0x162eb3[_0x5231c6(0x147)][_0x4206f2][_0x5231c6(0x4ab)]!==![])log(_0x5231c6(0x4e8)),_0x162eb3[_0x5231c6(0x3e6)](_0x4206f2,_0x162eb3[_0x5231c6(0x147)][_0x4206f2]['scaleWidth'],_0x162eb3['pcs'][_0x4206f2][_0x5231c6(0x571)]);else _0x162eb3[_0x5231c6(0x147)][_0x4206f2][_0x5231c6(0x3ea)]!==![]&&(log('scale\x20scale'),_0x162eb3[_0x5231c6(0x198)](_0x4206f2,_0x162eb3[_0x5231c6(0x147)][_0x4206f2][_0x5231c6(0x3ea)]));},0x0,_0x25549);}},_0x162eb3[_0x44a3fc(0x198)]=function(_0x45b819,_0xd45b22){var _0x421b1d=_0x44a3fc;warnlog(_0x421b1d(0x18e));if(_0x162eb3[_0x421b1d(0x147)][_0x45b819][_0x421b1d(0x3ea)]!==_0xd45b22){_0x162eb3[_0x421b1d(0x147)][_0x45b819][_0x421b1d(0x3ea)]=_0xd45b22;try{if(safariVersion()<=0xd&&(iOS||iPad))log(_0x421b1d(0x220));else{if((adapter[_0x421b1d(0x35d)][_0x421b1d(0x26b)]===_0x421b1d(0x148)||adapter[_0x421b1d(0x35d)][_0x421b1d(0x26b)]===_0x421b1d(0x111)||adapter[_0x421b1d(0x35d)][_0x421b1d(0x26b)]===_0x421b1d(0x49a)&&adapter[_0x421b1d(0x35d)][_0x421b1d(0x158)]>=0x40)&&_0x421b1d(0x4b9)in window&&_0x421b1d(0x567)in window['RTCRtpSender'][_0x421b1d(0x1c6)]){if('jOBuT'!==_0x421b1d(0xe9)){var _0x484af6=_0x162eb3[_0x421b1d(0x147)][_0x45b819][_0x421b1d(0x442)]()[_0x421b1d(0x107)](function(_0x3e7cfb){var _0x29f896=_0x421b1d;return _0x3e7cfb[_0x29f896(0x2ac)]&&_0x3e7cfb[_0x29f896(0x2ac)]['kind']==_0x29f896(0x3cb);});if(!_0x484af6){warnlog(_0x421b1d(0x331));return;}var _0x30e575=_0x484af6[_0x421b1d(0x1cb)]();(!_0x30e575[_0x421b1d(0x512)]||_0x30e575['encodings'][_0x421b1d(0x3f4)]==0x0)&&(_0x30e575[_0x421b1d(0x512)]=[{}]);_0x162eb3[_0x421b1d(0x147)][_0x45b819][_0x421b1d(0x4ab)]&&(_0x162eb3['pcs'][_0x45b819][_0x421b1d(0x4ab)]<_0xd45b22&&(_0xd45b22=_0x162eb3[_0x421b1d(0x147)][_0x45b819][_0x421b1d(0x4ab)]));_0x162eb3['pcs'][_0x45b819]['scaleDueToBitrate']&&_0x162eb3[_0x421b1d(0x147)][_0x45b819][_0x421b1d(0x4db)]<_0xd45b22&&(_0xd45b22=_0x162eb3[_0x421b1d(0x147)][_0x45b819]['scaleDueToBitrate']);_0xd45b22=_0x162eb3[_0x421b1d(0x527)](_0xd45b22);if(_0xd45b22<=0x0)_0x30e575[_0x421b1d(0x512)][0x0][_0x421b1d(0x2da)]=0x1;else{if(_0x421b1d(0xdc)===_0x421b1d(0xdc))_0x30e575[_0x421b1d(0x512)][0x0]['scaleResolutionDownBy']=0x64/_0xd45b22;else{function _0x537030(){var _0x33fcf9=_0x421b1d;_0x33fcf9(0x305)in _0x3b11e6['rpcs'][this[_0x33fcf9(0x1e2)]][_0x33fcf9(0x340)]&&_0x4bbc2b[_0x33fcf9(0x1f4)][this[_0x33fcf9(0x1e2)]][_0x33fcf9(0x340)][_0x33fcf9(0x305)][_0x33fcf9(0x529)]();}}}_0x484af6[_0x421b1d(0x567)](_0x30e575)[_0x421b1d(0x57e)](()=>{var _0x2cbba1=_0x421b1d;if(_0x2cbba1(0x281)!==_0x2cbba1(0x1c5))log(_0x2cbba1(0x2b6)),log(_0x484af6[_0x2cbba1(0x1cb)]()),pokeIframeAPI(_0x2cbba1(0x32f),_0xd45b22,_0x45b819);else{function _0x82089f(){var _0x3186e0=_0x2cbba1;_0x3821ea['seedAttempts']=_0x50f629(_0x44799f[_0x3186e0(0x32c)])+0x1,_0x5426ae(function(){var _0x2f846f=_0x3186e0;_0x57faf7[_0x2f846f(0x216)]();},0x1388);}}})[_0x421b1d(0x19f)](warnlog),_0x162eb3[_0x421b1d(0x147)][_0x45b819][_0x421b1d(0x14f)]['scaleFactor']=parseInt(_0xd45b22)+'%';return;}else{function _0x11bc39(){var _0x59f5ff=_0x421b1d;if(_0x414a9c[_0x59f5ff(0x1a1)]!==![]){if(_0x5f5d56[_0x59f5ff(0x475)])return;}}}}}}catch(_0x52dff3){errorlog(_0x52dff3);}}},_0x162eb3[_0x44a3fc(0x322)]=function(_0x44668b,_0x51638b,_0x281589){var _0x1a4dda=_0x44a3fc;if(!_0x162eb3[_0x1a4dda(0x1f4)][_0x44668b])return;var _0x516cae=![];_0x162eb3[_0x1a4dda(0x1f4)][_0x44668b][_0x1a4dda(0x295)]!=_0x51638b&&(_0x162eb3[_0x1a4dda(0x1f4)][_0x44668b][_0x1a4dda(0x295)]=_0x51638b,_0x516cae=!![]);_0x162eb3[_0x1a4dda(0x1f4)][_0x44668b][_0x1a4dda(0x571)]!=_0x281589&&(_0x162eb3[_0x1a4dda(0x1f4)][_0x44668b]['scaleHeight']=_0x281589,_0x516cae=!![]);log(_0x51638b+'\x20'+_0x281589);if(_0x516cae){var _0x108448={};_0x108448[_0x1a4dda(0x1e2)]=_0x44668b,_0x108448[_0x1a4dda(0x322)]={'w':_0x51638b,'h':_0x281589},warnlog(_0x1a4dda(0x322)),warnlog(_0x108448),_0x162eb3[_0x1a4dda(0x196)](_0x108448,_0x44668b);}_0x162eb3[_0x1a4dda(0x1f4)][_0x44668b][_0x1a4dda(0x14f)]['Requested_resolution']=parseInt(_0x51638b)+_0x1a4dda(0x415)+parseInt(_0x281589);},_0x162eb3[_0x44a3fc(0x3e6)]=function(_0x315489,_0x4621c9,_0xc36059){var _0x41bdfb=_0x44a3fc;_0x162eb3[_0x41bdfb(0x147)][_0x315489][_0x41bdfb(0x295)]=_0x4621c9,_0x162eb3[_0x41bdfb(0x147)][_0x315489][_0x41bdfb(0x571)]=_0xc36059;if(safariVersion()<=0xd&&(iOS||iPad))return;if((adapter[_0x41bdfb(0x35d)][_0x41bdfb(0x26b)]===_0x41bdfb(0x148)||adapter[_0x41bdfb(0x35d)][_0x41bdfb(0x26b)]===_0x41bdfb(0x111)||adapter['browserDetails'][_0x41bdfb(0x26b)]===_0x41bdfb(0x49a)&&adapter[_0x41bdfb(0x35d)][_0x41bdfb(0x158)]>=0x40)&&_0x41bdfb(0x4b9)in window&&_0x41bdfb(0x567)in window[_0x41bdfb(0x4b9)][_0x41bdfb(0x1c6)]){var _0x82fe72=_0x162eb3['pcs'][_0x315489][_0x41bdfb(0x442)]()[_0x41bdfb(0x107)](function(_0x544e74){var _0x56bbdd=_0x41bdfb;return _0x544e74[_0x56bbdd(0x2ac)]&&_0x544e74[_0x56bbdd(0x2ac)][_0x56bbdd(0x2c3)]=='video';});if(!_0x82fe72){warnlog(_0x41bdfb(0x331));return;}var _0x396f4e=_0x82fe72[_0x41bdfb(0x1cb)]();if(!_0x396f4e[_0x41bdfb(0x512)]||_0x396f4e[_0x41bdfb(0x512)][_0x41bdfb(0x3f4)]==0x0){if(_0x41bdfb(0x3c3)!=='cxNjE')_0x396f4e[_0x41bdfb(0x512)]=[{}];else{function _0x3630af(){var _0x145e82=_0x41bdfb;!_0x5a2755[_0x145e82(0x14e)]&&_0x47fb1f(function(){var _0x5c807c=_0x145e82;_0x59ec13(_0x5c807c(0x423));},0x1);}}}if(_0x162eb3['videoElement']){if(_0x41bdfb(0x110)!==_0x41bdfb(0x110)){function _0x4f181d(){var _0x31aa13=_0x41bdfb;_0x2a52e4(_0x31aa13(0x10a));}}else{var _0x485b2f=_0x162eb3[_0x41bdfb(0x340)][_0x41bdfb(0x288)][_0x41bdfb(0x2fc)]();if(_0x485b2f['length'])var _0x156c2c=_0x162eb3[_0x41bdfb(0x340)][_0x41bdfb(0x288)][_0x41bdfb(0x2fc)]()[0x0][_0x41bdfb(0x4ce)](),_0x2db320=_0x156c2c[_0x41bdfb(0x261)],_0x64e30a=_0x156c2c['width'];else return;}}else return;var _0x2a8957=0x64*_0x4621c9/_0x64e30a,_0x2c5758=0x64*_0xc36059/_0x2db320;log(_0x2a8957+_0x41bdfb(0x415)+_0x2c5758);var _0x49d21a=0x64;if(_0x2a8957>_0x2c5758)_0x49d21a=_0x2c5758;else{if(_0x41bdfb(0x4e4)!==_0x41bdfb(0x2f8))_0x49d21a=_0x2a8957;else{function _0x574ae5(){var _0x250767=_0x41bdfb;_0x439ef4[_0x250767(0x52d)](_0x3bebfe[_0x250767(0x444)](_0x4a42db[_0x250767(0x134)]))[_0x250767(0x57e)](function(_0x50f850){var _0x40aa3e=_0x250767;_0x2d1b75[_0x40aa3e(0x134)]=_0x50f850[0x0],_0x52ade3[_0x40aa3e(0x3f5)]=_0x50f850[0x1],_0x2e0113[_0x40aa3e(0x577)](_0x6a3c9c);});}}}_0x49d21a>0x64&&(_0x49d21a=0x64);log(_0x41bdfb(0x51b)+_0x49d21a),_0x162eb3[_0x41bdfb(0x147)][_0x315489][_0x41bdfb(0x4ab)]=_0x49d21a;var _0x5a25ab=0x64;log('session.pcs[UUID].scale\x20=\x20'+_0x162eb3[_0x41bdfb(0x147)][_0x315489]['scale']);_0x162eb3['pcs'][_0x315489][_0x41bdfb(0x3ea)]&&(_0x5a25ab=_0x162eb3[_0x41bdfb(0x147)][_0x315489]['scale']);if(_0x5a25ab>_0x49d21a){if('UKnxJ'===_0x41bdfb(0x11a)){function _0x23190b(){_0x802b6(_0xd9d63b);}}else _0x5a25ab=_0x49d21a;}_0x162eb3[_0x41bdfb(0x147)][_0x315489][_0x41bdfb(0x4ab)]&&(_0x162eb3['pcs'][_0x315489][_0x41bdfb(0x4ab)]<_0x5a25ab&&(_0x5a25ab=_0x162eb3[_0x41bdfb(0x147)][_0x315489][_0x41bdfb(0x4ab)]));_0x162eb3[_0x41bdfb(0x147)][_0x315489][_0x41bdfb(0x4db)]&&_0x162eb3['pcs'][_0x315489]['scaleDueToBitrate']<_0x5a25ab&&(_0x5a25ab=_0x162eb3['pcs'][_0x315489][_0x41bdfb(0x4db)]);log('pre\x20pixel\x20fix\x20'+_0x5a25ab),_0x5a25ab=_0x162eb3[_0x41bdfb(0x527)](_0x5a25ab),log(_0x41bdfb(0x30f)+_0x5a25ab);_0x5a25ab<=0x0?_0x396f4e['encodings'][0x0][_0x41bdfb(0x2da)]=0x1:_0x396f4e[_0x41bdfb(0x512)][0x0][_0x41bdfb(0x2da)]=0x64/_0x5a25ab;_0x82fe72[_0x41bdfb(0x567)](_0x396f4e)[_0x41bdfb(0x57e)](()=>{var _0xfd4f99=_0x41bdfb;log(_0xfd4f99(0x2b6)),log(_0x396f4e),pokeIframeAPI(_0xfd4f99(0x32f),_0x5a25ab,_0x315489);})[_0x41bdfb(0x19f)](warnlog),_0x162eb3[_0x41bdfb(0x147)][_0x315489][_0x41bdfb(0x14f)][_0x41bdfb(0x38d)]=parseInt(_0x5a25ab)+'%';return;}},_0x162eb3[_0x44a3fc(0x116)]=function(_0x3b4c9e=null,_0x3a4e27=null){var _0x3fb432=_0x44a3fc;_0x3a4e27&&_0x3a4e27[_0x3fb432(0x40e)]();log(_0x3fb432(0x544)+_0x3b4c9e);if(iOS||iPad)log(_0x3fb432(0x220));else{if((adapter[_0x3fb432(0x35d)][_0x3fb432(0x26b)]==='chrome'||adapter[_0x3fb432(0x35d)]['browser']===_0x3fb432(0x111)||adapter[_0x3fb432(0x35d)][_0x3fb432(0x26b)]===_0x3fb432(0x49a)&&adapter[_0x3fb432(0x35d)]['version']>=0x40)&&_0x3fb432(0x4b9)in window&&_0x3fb432(0x567)in window[_0x3fb432(0x4b9)][_0x3fb432(0x1c6)]){if(_0x3b4c9e==null){for(_0x3b4c9e in _0x162eb3[_0x3fb432(0x147)]){_0x162eb3[_0x3fb432(0x116)](_0x3b4c9e);}return![];}if(!(_0x3b4c9e in _0x162eb3['pcs']))return![];_0x162eb3['pcs'][_0x3b4c9e][_0x3fb432(0x139)]&&(_0x162eb3[_0x3fb432(0x147)][_0x3b4c9e][_0x3fb432(0x524)]&&(clearTimeout(_0x162eb3[_0x3fb432(0x147)][_0x3b4c9e][_0x3fb432(0x524)]),_0x162eb3[_0x3fb432(0x147)][_0x3b4c9e]['keyframeTimeout']=null),_0x162eb3[_0x3fb432(0x147)][_0x3b4c9e]['keyframeTimeout']=setTimeout(function(){var _0x3a8b41=_0x3fb432;if(_0x3a8b41(0x4dd)!==_0x3a8b41(0x4dd)){function _0x5246da(){var _0x55ae56=_0x3a8b41;_0xa65b95[_0x55ae56(0x1f4)][_0x431d78][_0x55ae56(0x14f)][_0x55ae56(0x446)][_0x55ae56(0x212)]=_0x29e455[_0x55ae56(0x2f0)];}}else _0x162eb3[_0x3a8b41(0x116)](_0x3b4c9e);},parseInt(_0x162eb3[_0x3fb432(0x147)][_0x3b4c9e]['keyframerate'])));try{var _0x13fcc8=_0x162eb3[_0x3fb432(0x147)][_0x3b4c9e][_0x3fb432(0x442)]()[_0x3fb432(0x107)](function(_0x266d98){var _0x170845=_0x3fb432;return _0x266d98[_0x170845(0x2ac)]&&_0x266d98[_0x170845(0x2ac)]['kind']==_0x170845(0x3cb);});if(!_0x13fcc8)return warnlog('can\x27t\x20change\x20bitrate;\x20no\x20video\x20sender\x20found'),![];var _0x1db818=_0x13fcc8[_0x3fb432(0x1cb)]();if(!_0x1db818[_0x3fb432(0x512)]||_0x1db818['encodings'][_0x3fb432(0x3f4)]==0x0){if(_0x3fb432(0x4ef)===_0x3fb432(0x260)){function _0x3c891b(){var _0x2a8201=_0x3fb432,_0x55d3ab=_0x513f6f[_0x2a8201(0x4bb)](_0x8ee752[_0x2a8201(0x3b8)]);for(var _0x181825 in _0x55d3ab){_0x24b9b2(_0x2a8201(0x2b7)+_0x55d3ab[_0x181825]),_0xb2fcf3[_0x2a8201(0x39b)](_0x55d3ab[_0x181825]);}}}else _0x1db818['encodings']=[{}];}var _0x33ac02=![];_0x1db818[_0x3fb432(0x512)][0x0][_0x3fb432(0x2da)]=0xa,_0x13fcc8[_0x3fb432(0x567)](_0x1db818)[_0x3fb432(0x57e)](()=>{var _0x34d742=_0x3fb432;log(_0x34d742(0x2d4));var _0x5f4fd4=_0x162eb3[_0x34d742(0x147)][_0x3b4c9e]['scaleResolution'],_0x4170c6=0x64;if(!_0x5f4fd4){if('EaDfb'!==_0x34d742(0x572))_0x5f4fd4=_0x4170c6;else{function _0x4dc6e7(){var _0x28de2c=_0x34d742,_0x28d015=_0x3b7bb1[_0x28de2c(0x41a)]('[data-action-type=\x22mute-guest\x22][data--u-u-i-d=\x22'+_0x56e067+'\x22]');_0x28d015[0x0]&&(_0x28d015[0x0][_0x28de2c(0x532)]=!![],_0x28d015[0x0][_0x28de2c(0xcf)]=_0x28de2c(0x150));var _0x28d015=_0x2473c3[_0x28de2c(0x41a)](_0x28de2c(0x588)+_0x381087+'\x22]');_0x28d015[0x0]&&(_0x28d015[0x0][_0x28de2c(0x532)]=!![],_0x28d015[0x0][_0x28de2c(0xcf)]=_0x28de2c(0x150),_0x28d015[0x0]['style'][_0x28de2c(0x345)]=0.2);}}}_0x162eb3[_0x34d742(0x147)][_0x3b4c9e][_0x34d742(0x3ea)]&&(_0x4170c6=_0x162eb3[_0x34d742(0x147)][_0x3b4c9e][_0x34d742(0x3ea)]);_0x4170c6>_0x5f4fd4&&(_0x4170c6=_0x5f4fd4);_0x162eb3[_0x34d742(0x147)][_0x3b4c9e][_0x34d742(0x4ab)]&&(_0x162eb3[_0x34d742(0x147)][_0x3b4c9e]['scaleResolution']<_0x4170c6&&(_0x4170c6=_0x162eb3[_0x34d742(0x147)][_0x3b4c9e][_0x34d742(0x4ab)]));_0x162eb3[_0x34d742(0x147)][_0x3b4c9e][_0x34d742(0x4db)]&&_0x162eb3[_0x34d742(0x147)][_0x3b4c9e]['scaleDueToBitrate']<_0x4170c6&&(_0x4170c6=_0x162eb3[_0x34d742(0x147)][_0x3b4c9e][_0x34d742(0x4db)]);log(_0x34d742(0x47a)+_0x4170c6),_0x4170c6=_0x162eb3[_0x34d742(0x527)](_0x4170c6);var _0x2ee398=_0x13fcc8[_0x34d742(0x1cb)]();_0x2ee398['encodings'][0x0][_0x34d742(0x2da)]=0x64/_0x4170c6,log(_0x34d742(0x201)),_0x13fcc8['setParameters'](_0x2ee398)[_0x34d742(0x57e)](()=>{var _0x530916=_0x34d742;log(_0x530916(0x143));})['catch'](warnlog);})[_0x3fb432(0x19f)](warnlog);}catch(_0x540b74){errorlog(_0x540b74);}}}return![];},_0x162eb3[_0x44a3fc(0x4d2)]=function(_0x34caae){var _0x22aa9e=_0x44a3fc;log('enhacing\x20audio\x20encoder');var _0x19a187=_0x162eb3[_0x22aa9e(0x147)][_0x34caae][_0x22aa9e(0x442)]()[_0x22aa9e(0x107)](function(_0x16a0d8){var _0x432530=_0x22aa9e;return _0x16a0d8[_0x432530(0x2ac)]&&_0x16a0d8[_0x432530(0x2ac)][_0x432530(0x2c3)]==_0x432530(0x25f);});if(!_0x19a187)return log('no\x20audio\x20track\x20to\x20poke'),![];var _0x402f77=_0x19a187[_0x22aa9e(0x1cb)]();(!_0x402f77[_0x22aa9e(0x512)]||_0x402f77['encodings'][_0x22aa9e(0x3f4)]==0x0)&&(_0x402f77[_0x22aa9e(0x512)]=[{}]);try{_0x402f77[_0x22aa9e(0x512)][0x0][_0x22aa9e(0x17a)]=_0x22aa9e(0x325),_0x402f77[_0x22aa9e(0x512)][0x0]['priority']=_0x22aa9e(0x325),_0x402f77[_0x22aa9e(0x512)][0x0][_0x22aa9e(0x36c)]=!![],_0x19a187[_0x22aa9e(0x567)](_0x402f77)['then'](()=>{var _0x5829ff=_0x22aa9e;log(_0x5829ff(0x406)),pokeIframeAPI(_0x5829ff(0x4d2),!![],_0x34caae);});}catch(_0x238587){errorlog(_0x238587);}},_0x162eb3[_0x44a3fc(0x546)]=function(_0x468ed1,_0x2ade9e=0x7d00,_0x44d6fc=0x3e8){var _0x50d96c=_0x44a3fc;if('wIgEc'!==_0x50d96c(0x2ce)){function _0x399edf(){var _0x4e30ac=_0x50d96c;delete _0x35313f[_0x4e30ac(0x1f4)][_0x2a362a],_0x5f5329(),_0x157716('Publisher\x20will\x20be\x20ignored\x20due\x20to\x20max\x20connections\x20already\x20hit');return;}}else{log(_0x50d96c(0x467));var _0x1236c9=_0x162eb3[_0x50d96c(0x147)][_0x468ed1][_0x50d96c(0x442)]()[_0x50d96c(0x107)](function(_0x864004){var _0x200a3e=_0x50d96c;return _0x864004[_0x200a3e(0x2ac)]&&_0x864004[_0x200a3e(0x2ac)][_0x200a3e(0x2c3)]=='audio';});if(!_0x1236c9)return log('no\x20audio\x20track\x20to\x20poke'),![];var _0x3062dc=_0x1236c9[_0x50d96c(0x1cb)]();(!_0x3062dc[_0x50d96c(0x512)]||_0x3062dc[_0x50d96c(0x512)][_0x50d96c(0x3f4)]==0x0)&&(_0x3062dc[_0x50d96c(0x512)]=[{}]),_0x3062dc[_0x50d96c(0x512)][0x0][_0x50d96c(0x23e)]=_0x2ade9e,_0x1236c9['setParameters'](_0x3062dc)[_0x50d96c(0x57e)](()=>{pokeIframeAPI('setAudioBitrate',_0x2ade9e,_0x468ed1),_0x44d6fc>0x0&&setTimeout(function(){var _0x4c8880=_0x447b;try{if(_0x468ed1 in _0x162eb3[_0x4c8880(0x147)])var _0x3e7013=_0x162eb3[_0x4c8880(0x147)][_0x468ed1][_0x4c8880(0x442)]()[_0x4c8880(0x107)](function(_0x26499a){var _0x5db805=_0x4c8880;return _0x26499a[_0x5db805(0x2ac)]&&_0x26499a[_0x5db805(0x2ac)][_0x5db805(0x2c3)]=='audio';});else return![];if(!_0x3e7013)return log(_0x4c8880(0x470)),![];var _0x342576=_0x3e7013[_0x4c8880(0x1cb)]();delete _0x342576[_0x4c8880(0x512)][0x0][_0x4c8880(0x23e)],_0x3e7013[_0x4c8880(0x567)](_0x342576)[_0x4c8880(0x57e)](()=>{var _0x42b75a=_0x4c8880;log(_0x42b75a(0x406));});}catch(_0x44e636){errorlog(_0x44e636);}},_0x44d6fc,_0x468ed1);});}},_0x162eb3[_0x44a3fc(0x2d3)]=function(_0x3225c3,_0x393feb){var _0x3839e8=_0x44a3fc;_0x393feb=parseInt(_0x393feb);try{var _0x3fcc02=_0x162eb3[_0x3839e8(0x147)][_0x3225c3][_0x3839e8(0x442)]()['find'](function(_0x564db5){var _0x24bf5b=_0x3839e8;if(_0x24bf5b(0x2e2)===_0x24bf5b(0x2e2))return _0x564db5[_0x24bf5b(0x2ac)]&&_0x564db5[_0x24bf5b(0x2ac)][_0x24bf5b(0x2c3)]==_0x24bf5b(0x25f);else{function _0x77adb(){var _0x1162b7=_0x24bf5b,_0x53861c=_0x3f0b8b(_0xbcdee6[_0x1162b7(0x2ac)]);_0x53861c<_0x3d0fe3[_0x1162b7(0x3f4)]&&(_0x5b9011=_0x4fab63[_0x53861c],_0x354dd8(_0x570026[_0x1162b7(0x57d)],_0x1bc501[_0x1162b7(0x276)]));}}});if(!_0x3fcc02){if(_0x3839e8(0x3a6)!=='cNPKk'){function _0x427415(){var _0x5df09d=_0x3839e8;_0x3e7460[_0x5df09d(0x39b)](_0x31293d[_0x42f815]);}}else{warnlog(_0x3839e8(0x1f0));return;}}var _0x3d0c03=_0x3fcc02['getParameters']();if(!_0x3d0c03[_0x3839e8(0x512)]||_0x3d0c03[_0x3839e8(0x512)][_0x3839e8(0x3f4)]==0x0){if('yZEIU'===_0x3839e8(0x36a))_0x3d0c03[_0x3839e8(0x512)]=[{}];else{function _0x1262cd(){var _0x12426a=_0x3839e8,_0x3c8edb=_0x5f4cf8[_0x12426a(0x508)](_0x4f5ed6[_0x12426a(0x16b)][_0x12426a(0x457)])||0x0;_0x5da45e[_0x12426a(0x16b)][_0x12426a(0x457)]=_0x21fb28[_0x12426a(0x38e)](_0x598677[_0x12426a(0x16b)][_0x12426a(0x457)],{'min':_0x61ec4f(_0x4c57ac/0xa)||0x1,'max':_0x3e3b43(_0xe2c2d7+_0x3c8edb/0x400)}),_0x44e02b[_0x12426a(0x147)][_0x1e28c3[_0x12426a(0x1e2)]][_0x12426a(0x2a1)]=_0x26b91c;}}}if(_0x393feb<0x0)_0x3d0c03['encodings'][0x0][_0x3839e8(0x3b0)]==![]&&(_0x3d0c03[_0x3839e8(0x512)][0x0]['active']=!![]),safariVersion()<=0xd&&(iOS||iPad)?(_0x393feb=0x20,_0x162eb3['audiobitrate']&&(_0x393feb=_0x162eb3[_0x3839e8(0x4f5)]),_0x3d0c03[_0x3839e8(0x512)][0x0][_0x3839e8(0x23e)]=_0x393feb*0x400):delete _0x3d0c03[_0x3839e8(0x512)][0x0][_0x3839e8(0x23e)];else _0x393feb===0x0?_0x3d0c03['encodings'][0x0][_0x3839e8(0x3b0)]=![]:(_0x3d0c03[_0x3839e8(0x512)][0x0][_0x3839e8(0x3b0)]==![]&&(_0x3d0c03['encodings'][0x0][_0x3839e8(0x3b0)]=!![]),_0x3d0c03[_0x3839e8(0x512)][0x0][_0x3839e8(0x23e)]=_0x393feb*0x400);_0x3fcc02[_0x3839e8(0x567)](_0x3d0c03)['then'](()=>{var _0x154f60=_0x3839e8;pokeIframeAPI(_0x154f60(0xff),_0x393feb,_0x3225c3),log(_0x154f60(0x14d));})[_0x3839e8(0x19f)](warnlog);}catch(_0x48cd5f){if(_0x3839e8(0x2ff)!==_0x3839e8(0x1db))errorlog(_0x48cd5f);else{function _0x335718(){var _0x27897c=_0x3839e8;_0x50b24d[_0x27897c(0x39b)](_0x465f36);}}}},_0x162eb3[_0x44a3fc(0xd4)]=function(_0x62ca04){var _0x171245=_0x44a3fc;if(_0x162eb3[_0x171245(0x40c)]&&_0x162eb3[_0x171245(0x147)][_0x62ca04][_0x171245(0x117)]===!![])_0x162eb3[_0x171245(0x451)](_0x62ca04,0x0),_0x162eb3['pcs'][_0x62ca04][_0x171245(0x40d)]===0x0&&(_0x162eb3[_0x171245(0x147)][_0x62ca04][_0x171245(0xeb)]===![]?_0x162eb3[_0x171245(0x2d3)](_0x62ca04,0x0):_0x162eb3[_0x171245(0x2d3)](_0x62ca04,-0x1));else{if(_0x162eb3[_0x171245(0x147)][_0x62ca04]&&_0x162eb3[_0x171245(0x147)][_0x62ca04][_0x171245(0x40d)]!==![]){if(_0x162eb3[_0x171245(0x147)][_0x62ca04][_0x171245(0xeb)]===![]){var _0x3374db=_0x162eb3[_0x171245(0x147)][_0x62ca04][_0x171245(0x40d)];_0x162eb3[_0x171245(0x147)][_0x62ca04][_0x171245(0x46d)]&&_0x162eb3['pcs'][_0x62ca04][_0x171245(0x46d)]>0x0&&(_0x162eb3[_0x171245(0x147)][_0x62ca04][_0x171245(0x46d)]<_0x162eb3[_0x171245(0x147)][_0x62ca04][_0x171245(0x40d)]&&(_0x3374db=_0x162eb3[_0x171245(0x147)][_0x62ca04][_0x171245(0x46d)])),_0x162eb3[_0x171245(0x451)](_0x62ca04,_0x3374db),_0x162eb3[_0x171245(0x147)][_0x62ca04][_0x171245(0x40d)]===0x0&&_0x162eb3[_0x171245(0x2d3)](_0x62ca04,0x0);}else _0x162eb3['pcs'][_0x62ca04][_0x171245(0x40d)]===0x0&&_0x162eb3[_0x171245(0x2d3)](_0x62ca04,-0x1);}}},_0x162eb3[_0x44a3fc(0x218)]=function(_0x703b8=0x0,_0x5074a5=![]){var _0x2af263=_0x44a3fc;if('OyJsU'!==_0x2af263(0x377)){if(_0x162eb3['limitTotalBitrate']){var _0xb9e8e1=_0x703b8;warnlog(_0xb9e8e1);var _0xe9cb0a=0x0;for(var _0x18ce69 in _0x162eb3[_0x2af263(0x147)]){if(_0x5074a5===_0x18ce69)continue;var _0x4b112d=_0x162eb3['pcs'][_0x18ce69][_0x2af263(0x442)]()[_0x2af263(0x107)](function(_0x5a04df){var _0x36fbd2=_0x2af263;return _0x5a04df[_0x36fbd2(0x2ac)]&&_0x5a04df[_0x36fbd2(0x2ac)][_0x36fbd2(0x2c3)]==_0x36fbd2(0x3cb);});if(!_0x4b112d)continue;var _0x724ffe=_0x4b112d[_0x2af263(0x1cb)]();if(!_0x724ffe[_0x2af263(0x512)]||_0x724ffe[_0x2af263(0x512)][_0x2af263(0x3f4)]==0x0){if(_0x2af263(0x4c6)!=='LrVVH'){function _0x3f05a1(){var _0x19dcdc=_0x2af263;_0x46bba6[_0x19dcdc(0x223)]=_0x5b52f9[_0x19dcdc(0x3cc)][_0x19dcdc(0x4a6)];}}else{_0xb9e8e1+=_0x162eb3[_0x2af263(0x147)][_0x18ce69][_0x2af263(0x2a1)]||0x9c4,warnlog(_0xb9e8e1),_0xe9cb0a+=0x1;continue;}}if(_0x724ffe[_0x2af263(0x512)][0x0][_0x2af263(0x3b0)]==![])continue;_0x724ffe['encodings'][0x0][_0x2af263(0x23e)]?(_0xb9e8e1+=parseInt(_0x724ffe['encodings'][0x0][_0x2af263(0x23e)])/0x400,warnlog(_0xb9e8e1)):(_0xb9e8e1+=_0x162eb3[_0x2af263(0x147)][_0x18ce69][_0x2af263(0x2a1)]||0x9c4,warnlog(_0xb9e8e1)),_0xe9cb0a+=0x1;}if(!_0xb9e8e1)return![];var _0x33ae49=parseFloat(_0xb9e8e1/_0x162eb3[_0x2af263(0x3da)]);if(_0x33ae49>0x1)for(var _0x18ce69 in _0x162eb3[_0x2af263(0x147)]){if(_0x2af263(0x2ec)===_0x2af263(0x2ec)){if(_0x5074a5===_0x18ce69)continue;var _0x4b112d=_0x162eb3[_0x2af263(0x147)][_0x18ce69][_0x2af263(0x442)]()['find'](function(_0x198041){var _0x3a765d=_0x2af263;return _0x198041['track']&&_0x198041[_0x3a765d(0x2ac)][_0x3a765d(0x2c3)]==_0x3a765d(0x3cb);});if(!_0x4b112d)continue;var _0x724ffe=_0x4b112d[_0x2af263(0x1cb)]();if(!_0x724ffe[_0x2af263(0x512)]||_0x724ffe[_0x2af263(0x512)]['length']==0x0){var _0x49d733=_0x162eb3[_0x2af263(0x147)][_0x18ce69]['setBitrate']||0x9c4;_0x162eb3[_0x2af263(0x451)](_0x18ce69,parseInt(_0x49d733/_0x33ae49),!![]),errorlog(parseInt(_0x49d733/_0x33ae49));continue;}if(_0x724ffe[_0x2af263(0x512)][0x0][_0x2af263(0x3b0)]==![])continue;if(_0x724ffe[_0x2af263(0x512)][0x0][_0x2af263(0x23e)]){if(_0x2af263(0x4c1)===_0x2af263(0x1d5)){function _0x834b3e(){var _0x3269a6=_0x2af263;_0x102002['pcs'][_0x9a73da][_0x3269a6(0x506)]=!![];}}else errorlog(parseInt(parseInt(_0x724ffe[_0x2af263(0x512)][0x0][_0x2af263(0x23e)])/0x400/_0x33ae49)),_0x162eb3['limitBitrate'](_0x18ce69,parseInt(parseInt(_0x724ffe['encodings'][0x0][_0x2af263(0x23e)])/0x400/_0x33ae49),!![]);}else{var _0x49d733=_0x162eb3[_0x2af263(0x147)][_0x18ce69][_0x2af263(0x2a1)]||0x9c4;errorlog(parseInt(_0x49d733/_0x33ae49)),_0x162eb3[_0x2af263(0x451)](_0x18ce69,parseInt(_0x49d733/_0x33ae49),!![]);}}else{function _0xadd5d(){var _0x3ea2bc=_0x2af263;try{_0x53aeda[_0x3ea2bc(0x1f4)][_0x2f097f]['stats'][_0x3ea2bc(0x53f)][_0x3ea2bc(0x1b6)]=!![];}catch(_0x49f417){}}}}return parseInt(_0x703b8/_0x33ae49);}else return![];}else{function _0x3783a9(){var _0x46b97f=_0x2af263;_0x48dcf3(_0x46b97f(0x459)),_0x3e38a3[_0x46b97f(0x147)][_0x4b0d83['UUID']][_0x46b97f(0x556)](),delete _0x2dea10[_0x46b97f(0x147)][_0x223dbe[_0x46b97f(0x1e2)]],_0x13dc6c[_0x46b97f(0x421)](),_0x491014();}}},_0x162eb3['limitBitrate']=function(_0x4c7c35,_0x15cbc9,_0xb903f0=![]){var _0x5d731b=_0x44a3fc;_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x49f)]&&(clearInterval(_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x49f)]),_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x49f)]=null);if(_0x15cbc9===null){if(_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x46d)]===![])return;_0x15cbc9=_0x162eb3[_0x5d731b(0x147)][_0x4c7c35]['savedBitrate'];}_0x15cbc9=parseInt(_0x15cbc9);_0x162eb3[_0x5d731b(0x1e5)]&&(_0x15cbc9>_0x162eb3[_0x5d731b(0x1e5)]&&(_0x15cbc9=_0x162eb3['maxvideobitrate']));_0x162eb3['pcs'][_0x4c7c35][_0x5d731b(0x46d)]=_0x15cbc9;if(_0x162eb3[_0x5d731b(0x147)][_0x4c7c35]['optimizedBitrate']!==![]){if(_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0xeb)]===![]){if('RfYGw'===_0x5d731b(0x356))_0x15cbc9>_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x40d)]&&(_0x162eb3[_0x5d731b(0x147)][_0x4c7c35]['savedBitrate']=_0x15cbc9,_0x15cbc9=parseInt(_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x40d)])||0x0);else{function _0x4dfa8d(){var _0xbb7b6a=_0x5d731b;_0x548275[_0xbb7b6a(0x179)](_0x5ab2c6[_0xbb7b6a(0x1e2)]);}}}}_0xb903f0===![]&&(_0x162eb3[_0x5d731b(0x3da)]&&(_0x15cbc9=_0x162eb3[_0x5d731b(0x218)](_0x15cbc9,_0x4c7c35)));if(_0x15cbc9==0x0){if(_0x5d731b(0x52e)===_0x5d731b(0x52e)){var _0x1bbe40=Date[_0x5d731b(0x1b9)]()-_0x162eb3['pcs'][_0x4c7c35][_0x5d731b(0x13c)];_0x1bbe40<_0x162eb3[_0x5d731b(0x1d8)]&&(_0x15cbc9=0x23,_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x49f)]=setTimeout(function(_0x5772f0){_0x162eb3['limitBitrate'](_0x5772f0,null);},_0x1bbe40,_0x4c7c35));}else{function _0x3646dc(){var _0x3ffb43=_0x5d731b;_0x53c188['rpcs'][_0x417506][_0x3ffb43(0x2c5)]=_0x39f941(_0x49463b[_0x3ffb43(0x2c5)])||0x0;_0x1aa08a in _0x12a93a[_0x3ffb43(0x147)]&&(_0xb0c226[_0x3ffb43(0x147)][_0x54a4bc][_0x3ffb43(0x2c5)]=_0x1d54d4(_0x44c946[_0x3ffb43(0x2c5)])||0x0);if(_0x1b0331['director']){var _0x2947b7=_0x51d476[_0x3ffb43(0x41a)](_0x3ffb43(0x330)+_0xa6aeb3+'\x22]');_0x2947b7[0x0]&&(_0x2947b7[0x0][_0x3ffb43(0x27f)]=_0x3feaf1(_0x44ef1b[_0x3ffb43(0x2c5)])||0x0);}_0x5ae623=!![];}}}try{if(safariVersion()<=0xd&&(iOS||iPad)){log('iOS\x20devices\x20do\x20not\x20support\x20dynamic\x20bitrates\x20correctly;\x20skipping');if(_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x466)]==!![]&&_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x26c)]==![])return;var _0x4431a9=_0x162eb3[_0x5d731b(0x147)][_0x4c7c35]['getSenders']()[_0x5d731b(0x107)](function(_0x2a5d91){var _0x5b2acf=_0x5d731b;return _0x2a5d91[_0x5b2acf(0x2ac)]&&_0x2a5d91[_0x5b2acf(0x2ac)][_0x5b2acf(0x2c3)]==_0x5b2acf(0x3cb);});if(!_0x4431a9){warnlog(_0x5d731b(0x331));return;}var _0x3f8ed=_0x4431a9[_0x5d731b(0x1cb)]();(!_0x3f8ed[_0x5d731b(0x512)]||_0x3f8ed[_0x5d731b(0x512)][_0x5d731b(0x3f4)]==0x0)&&(_0x3f8ed[_0x5d731b(0x512)]=[{}]);if(_0x15cbc9<0x0){_0x3f8ed[_0x5d731b(0x512)][0x0][_0x5d731b(0x3b0)]==![]&&(_0x3f8ed[_0x5d731b(0x512)][0x0]['active']=!![]);_0x15cbc9=0x9c4;if(_0x162eb3['bitrate']){if(_0x5d731b(0x2c4)!==_0x5d731b(0x2c4)){function _0x420400(){var _0x5d8fa7=_0x5d731b;return _0x990a23[_0x5d8fa7(0x2ac)]&&_0x493e8f['track'][_0x5d8fa7(0x2c3)]==_0x5d8fa7(0x3cb);}}else _0x15cbc9=_0x162eb3['bitrate'];}_0x162eb3[_0x5d731b(0x1e5)]&&(_0x15cbc9>_0x162eb3[_0x5d731b(0x1e5)]&&(_0x15cbc9=_0x162eb3[_0x5d731b(0x1e5)])),_0x3f8ed[_0x5d731b(0x512)][0x0][_0x5d731b(0x23e)]=_0x15cbc9*0x400;}else{if(_0x15cbc9===0x0)_0x3f8ed[_0x5d731b(0x512)][0x0][_0x5d731b(0x3b0)]=![];else{if(_0x3f8ed[_0x5d731b(0x512)][0x0][_0x5d731b(0x3b0)]==![]){if(_0x5d731b(0x242)===_0x5d731b(0x242))_0x3f8ed[_0x5d731b(0x512)][0x0][_0x5d731b(0x3b0)]=!![];else{function _0x3285aa(){var _0x1cb6a1=_0x5d731b;_0x1b55a4[_0x1cb6a1(0x21d)](_0x2ca3e5);}}}_0x3f8ed['encodings'][0x0][_0x5d731b(0x23e)]=_0x15cbc9*0x400;}}_0x4431a9[_0x5d731b(0x567)](_0x3f8ed)['then'](()=>{var _0x2188c0=_0x5d731b;pokeIframeAPI(_0x2188c0(0x43a),_0x15cbc9,_0x4c7c35),log(_0x2188c0(0x368));})['catch'](warnlog);return;}else{if((iOS||iPad)&&(_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x466)]==!![]&&_0x162eb3[_0x5d731b(0x147)][_0x4c7c35]['forceios']==![])){var _0x2437df=0x64;_0x162eb3['pcs'][_0x4c7c35]['scale']&&(_0x2437df=_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x3ea)]),_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x4ab)]&&_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x4ab)]<_0x2437df&&(_0x2437df=_0x162eb3[_0x5d731b(0x147)][_0x4c7c35]['scaleResolution']),_0x162eb3[_0x5d731b(0x147)][_0x4c7c35]['scaleDueToBitrate']=0x64/0x3,_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x4db)]<_0x2437df&&(_0x2437df=_0x162eb3['pcs'][_0x4c7c35]['scaleDueToBitrate']),_0x2437df=_0x162eb3[_0x5d731b(0x527)](_0x2437df),_0x3f8ed['encodings'][0x0][_0x5d731b(0x2da)]=0x64/_0x2437df,_0x4431a9[_0x5d731b(0x567)](_0x3f8ed)['then'](()=>{log('iOS\x20guest\x20SCALE\x20set!'),pokeIframeAPI('setVideoScale',_0x2437df,_0x4c7c35);})[_0x5d731b(0x19f)](warnlog),_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x14f)]['scaleFactor']=parseInt(_0x2437df)+'%';}else{if((adapter[_0x5d731b(0x35d)][_0x5d731b(0x26b)]==='chrome'||adapter[_0x5d731b(0x35d)]['browser']===_0x5d731b(0x111)||adapter[_0x5d731b(0x35d)]['browser']===_0x5d731b(0x49a)&&adapter[_0x5d731b(0x35d)][_0x5d731b(0x158)]>=0x40)&&_0x5d731b(0x4b9)in window&&_0x5d731b(0x567)in window[_0x5d731b(0x4b9)][_0x5d731b(0x1c6)]){var _0x4431a9=_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x442)]()[_0x5d731b(0x107)](function(_0x1f6d23){var _0x333c25=_0x5d731b;return _0x1f6d23[_0x333c25(0x2ac)]&&_0x1f6d23[_0x333c25(0x2ac)][_0x333c25(0x2c3)]==_0x333c25(0x3cb);});if(!_0x4431a9){warnlog(_0x5d731b(0x331));return;}var _0x3f8ed=_0x4431a9['getParameters']();(!_0x3f8ed[_0x5d731b(0x512)]||_0x3f8ed[_0x5d731b(0x512)][_0x5d731b(0x3f4)]==0x0)&&(_0x3f8ed['encodings']=[{}]);if(_0x15cbc9<0x0)_0x3f8ed[_0x5d731b(0x512)][0x0][_0x5d731b(0x3b0)]==![]&&(_0x3f8ed['encodings'][0x0]['active']=!![]),delete _0x3f8ed[_0x5d731b(0x512)][0x0][_0x5d731b(0x23e)];else _0x15cbc9===0x0?_0x3f8ed[_0x5d731b(0x512)][0x0][_0x5d731b(0x3b0)]=![]:(_0x3f8ed[_0x5d731b(0x512)][0x0][_0x5d731b(0x3b0)]==![]&&(_0x3f8ed[_0x5d731b(0x512)][0x0][_0x5d731b(0x3b0)]=!![]),_0x3f8ed[_0x5d731b(0x512)][0x0][_0x5d731b(0x23e)]=_0x15cbc9*0x400);var _0x2437df=0x64;_0x162eb3[_0x5d731b(0x147)][_0x4c7c35]['scale']&&(_0x2437df=_0x162eb3['pcs'][_0x4c7c35][_0x5d731b(0x3ea)]);_0x162eb3[_0x5d731b(0x147)][_0x4c7c35]['scaleResolution']&&_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x4ab)]<_0x2437df&&(_0x2437df=_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x4ab)]);if(_0x15cbc9<0x0)_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x4db)]=0x64;else{if(_0x15cbc9>=0x259)_0x162eb3['pcs'][_0x4c7c35][_0x5d731b(0x4db)]=0x64;else{if(_0x162eb3['pcs'][_0x4c7c35][_0x5d731b(0x145)]===![]&&_0x162eb3[_0x5d731b(0x37c)]!==_0x4c7c35&&_0x162eb3[_0x5d731b(0x460)])_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x4db)]=0x64;else{if(_0x15cbc9>=0xc9)_0x162eb3[_0x5d731b(0x3bd)]?_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x4db)]=0x64/2.5:_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x4db)]=0x64/0x2;else _0x15cbc9>=0x51?_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x4db)]=0x64/0x3:_0x162eb3[_0x5d731b(0x147)][_0x4c7c35]['scaleDueToBitrate']=0x64/0x4;}}}_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x4db)]<_0x2437df&&(_0x2437df=_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x4db)]);_0x2437df=_0x162eb3[_0x5d731b(0x527)](_0x2437df),_0x3f8ed['encodings'][0x0][_0x5d731b(0x2da)]=0x64/_0x2437df,_0x4431a9[_0x5d731b(0x567)](_0x3f8ed)[_0x5d731b(0x57e)](()=>{var _0xaf7aec=_0x5d731b;log(_0xaf7aec(0x368)),pokeIframeAPI('setVideoBitrate',_0x15cbc9,_0x4c7c35),pokeIframeAPI(_0xaf7aec(0x32f),_0x2437df,_0x4c7c35);})[_0x5d731b(0x19f)](warnlog),_0x162eb3[_0x5d731b(0x147)][_0x4c7c35][_0x5d731b(0x14f)][_0x5d731b(0x38d)]=parseInt(_0x2437df)+'%';return;}}}}catch(_0x341117){if(_0x5d731b(0x256)!==_0x5d731b(0x197))errorlog(_0x341117);else{function _0x45f46e(){return _0x40771b;}}}};function _0x2bcdde(_0x15f873,_0x54ab28=0x2710){var _0x3e8c8b=_0x44a3fc;_0x54ab28=parseInt(_0x54ab28);if(_0x162eb3[_0x3e8c8b(0x4f5)]){if('HeFpN'===_0x3e8c8b(0x333))_0x54ab28+=_0x162eb3[_0x3e8c8b(0x4f5)];else{function _0x274470(){var _0x2bf93f=_0x3e8c8b;if(_0x5ea87c[_0x2bf93f(0x37c)]===_0x40aa44['UUID'])_0x46626d[_0x2bf93f(0x179)](_0x5247d6[_0x2bf93f(0x1e2)]);else _0x2293a8[_0x2bf93f(0x1b6)]&&(_0x112bc1['UUID']in _0x218ab8['rpcs']&&_0xa37a34[_0x2bf93f(0x179)](_0x23fdfd[_0x2bf93f(0x1e2)]));}}}else{if(_0x162eb3[_0x3e8c8b(0x1b6)]&&_0x162eb3['stereo']==0x5)_0x54ab28+=0x20;else _0x162eb3[_0x3e8c8b(0x133)]&&_0x162eb3[_0x3e8c8b(0x133)]!=0x3?_0x54ab28+=0x100:_0x54ab28+=0x20;}return log(_0x3e8c8b(0xe4)+_0x54ab28),_0x54ab28<0x1&&(_0x54ab28=0x1),_0x15f873=CodecsHandler[_0x3e8c8b(0x38e)](_0x15f873,{'min':parseInt(_0x54ab28/0xa)||0x1,'max':_0x54ab28},_0x162eb3[_0x3e8c8b(0x1d2)]),_0x15f873;}return _0x162eb3[_0x44a3fc(0x42a)]=function(_0x22597e,_0x2b6c7e){var _0x482da7=_0x44a3fc;log(_0x22597e),_0x162eb3['mykey']==={}&&log(_0x482da7(0x254)),window[_0x482da7(0x258)][_0x482da7(0x426)][_0x482da7(0x4e3)]({'name':_0x482da7(0x2cc)},_0x162eb3[_0x482da7(0x2d5)]['privateKey'],_0x162eb3[_0x482da7(0x4bd)]['encode'](_0x22597e))[_0x482da7(0x57e)](function(_0x57acb9){var _0x3515cb=_0x482da7;_0x57acb9=new Uint8Array(_0x57acb9),_0x57acb9=_0x57acb9[_0x3515cb(0x4fb)]((_0x209d34,_0x4c5a99)=>_0x209d34+_0x4c5a99[_0x3515cb(0x51f)](0x10)[_0x3515cb(0x2d1)](0x2,'0'),''),_0x2b6c7e(_0x22597e,_0x57acb9),log(JSON[_0x3515cb(0x444)](_0x57acb9));})[_0x482da7(0x19f)](errorlog);},_0x162eb3['verifyData']=function(_0x5f424c,_0x5d4d8d){var _0x3bf540=_0x44a3fc;_0x5f424c[_0x3bf540(0x531)]=new Uint8Array(_0x5f424c['signature'][_0x3bf540(0xce)](/.{1,2}/g)[_0x3bf540(0x15c)](_0x24a8cd=>parseInt(_0x24a8cd,0x10)));if(_0x162eb3[_0x3bf540(0x4bb)][_0x5d4d8d]['publicKey'])return window[_0x3bf540(0x258)]['subtle']['verify']({'name':_0x3bf540(0x2cc)},_0x162eb3[_0x3bf540(0x4bb)][_0x5d4d8d][_0x3bf540(0x52a)],_0x5f424c[_0x3bf540(0x531)],_0x162eb3[_0x3bf540(0x4bd)][_0x3bf540(0x32d)](_0x5f424c[_0x3bf540(0x2cd)]))[_0x3bf540(0x57e)](function(_0x470cac){return log(_0x470cac),_0x470cac;})[_0x3bf540(0x19f)](function(_0x45ed04){return errorlog(_0x45ed04),![];});},_0x162eb3['desaltStreamID']=function(_0x4ada52){var _0x51e7b0=_0x44a3fc;if(_0x162eb3[_0x51e7b0(0xf2)]){if(_0x51e7b0(0x540)!==_0x51e7b0(0x473))return _0x162eb3[_0x51e7b0(0x429)]!==![]?(log(_0x51e7b0(0x43b)),_0x4ada52=_0x4ada52[_0x51e7b0(0x32a)](0x0,-0x1*_0x162eb3[_0x51e7b0(0x429)][_0x51e7b0(0x3f4)]),_0x4ada52):(log(_0x51e7b0(0x3af)+_0x4ada52),_0x162eb3['generateHash'](_0x162eb3[_0x51e7b0(0xf2)]+_0x162eb3[_0x51e7b0(0x14c)],0x6)['then'](function(_0x3b454d){var _0x316abc=_0x51e7b0;return _0x162eb3[_0x316abc(0x429)]=_0x3b454d,log(_0x4ada52),_0x4ada52=_0x4ada52[_0x316abc(0x32a)](0x0,-0x1*_0x162eb3[_0x316abc(0x429)][_0x316abc(0x3f4)]),log(_0x316abc(0x495)+_0x4ada52),_0x4ada52;}));else{function _0x288a7a(){var _0x43a7bc=_0x51e7b0;_0x5ad719[_0x43a7bc(0x34f)]=_0x3d5bd7[_0x43a7bc(0x34f)][_0x43a7bc(0x129)](0x0,0x18)+_0x434fe5['hash']['substring'](0x0,0x6);var _0x2fa821=_0x1d2396['stringify'](_0x4ed7f5);if(_0x2fa821[_0x43a7bc(0x3f4)]>0x3a98){_0x5e55a9(_0x43a7bc(0x559));return;}_0x12c94c['ws'][_0x43a7bc(0x388)](_0x2fa821);}}}return _0x4ada52;},_0x162eb3[_0x44a3fc(0x309)]=function(){var _0x321cad=_0x44a3fc;if(!_0x162eb3[_0x321cad(0x46f)])return;if(!_0x162eb3[_0x321cad(0x1b6)]){if('aGrqL'===_0x321cad(0x16e)){function _0x5b7958(){return;}}else return;}_0x162eb3[_0x321cad(0x1c1)][_0x321cad(0x3f4)]?(_0x162eb3[_0x321cad(0x1c1)][_0x321cad(0x3f4)]>0xa?getById(_0x321cad(0x183))['innerHTML']='‼':getById(_0x321cad(0x183))[_0x321cad(0x564)]=_0x162eb3['queueList'][_0x321cad(0x3f4)],getById(_0x321cad(0x183))[_0x321cad(0x2ed)][_0x321cad(0x106)](_0x321cad(0x183))):(getById(_0x321cad(0x183))[_0x321cad(0x564)]='',getById(_0x321cad(0x183))[_0x321cad(0x2ed)][_0x321cad(0x41f)](_0x321cad(0x183)));},_0x162eb3[_0x44a3fc(0x154)]=function(){var _0x1cd5d7=_0x44a3fc;if(!_0x162eb3[_0x1cd5d7(0x46f)]){if(_0x1cd5d7(0x252)==='ngnIS')return;else{function _0xab50b5(){var _0x4c8d37=_0x1cd5d7;_0x55c4bc['rpcs'][_0x52c33a][_0x4c8d37(0x167)]['style'][_0x4c8d37(0x1fb)]=_0x4c8d37(0x277);}}}if(!_0x162eb3['director'])return;if(_0x162eb3[_0x1cd5d7(0x1c1)][_0x1cd5d7(0x3f4)]==0x0){getById(_0x1cd5d7(0x20a))['classList'][_0x1cd5d7(0x106)](_0x1cd5d7(0x2de)),getById(_0x1cd5d7(0x20a))[_0x1cd5d7(0x2ed)][_0x1cd5d7(0x106)](_0x1cd5d7(0x32b)),getById('queuebutton')[_0x1cd5d7(0x2ed)][_0x1cd5d7(0x41f)](_0x1cd5d7(0x3fe)),setTimeout(function(){var _0x376d11=_0x1cd5d7;getById(_0x376d11(0x20a))[_0x376d11(0x2ed)]['add']('float'),getById(_0x376d11(0x20a))['classList'][_0x376d11(0x41f)](_0x376d11(0x2de)),getById(_0x376d11(0x20a))[_0x376d11(0x2ed)][_0x376d11(0x41f)]('red');},0x32);return;}var _0x354a40=_0x162eb3['queueList'][_0x1cd5d7(0x359)]();getById(_0x1cd5d7(0x20a))[_0x1cd5d7(0x2ed)]['add'](_0x1cd5d7(0x2de)),getById(_0x1cd5d7(0x20a))['classList'][_0x1cd5d7(0x41f)]('float'),setTimeout(function(){var _0x54e0f7=_0x1cd5d7;getById(_0x54e0f7(0x20a))[_0x54e0f7(0x2ed)][_0x54e0f7(0x106)](_0x54e0f7(0x3fe)),getById(_0x54e0f7(0x20a))[_0x54e0f7(0x2ed)][_0x54e0f7(0x41f)]('float2');},0xc8),_0x162eb3[_0x1cd5d7(0x309)](),_0x162eb3[_0x1cd5d7(0x39b)](_0x354a40),log(_0x1cd5d7(0x483)+_0x354a40);},_0x162eb3[_0x44a3fc(0x264)]=function(){var _0x2f802c=_0x44a3fc;if(_0x162eb3[_0x2f802c(0x285)]){if(_0x2f802c(0xf1)===_0x2f802c(0x493)){function _0x1c5144(){var _0x44b831=_0x2f802c;_0x187ea1(_0x9cb730),_0x13b52d(_0x44b831(0x24b));}}else return;}clearTimeout(_0x162eb3[_0x2f802c(0x371)]);if(!_0x162eb3['ws']||_0x162eb3['ws']['readyState']!==0x1)return;_0x162eb3[_0x2f802c(0x371)]=setTimeout(function(){var _0x584b04=_0x2f802c;log(_0x584b04(0x42e));var _0x529f46={};_0x529f46[_0x584b04(0x4e0)]=_0x584b04(0x264),_0x162eb3['sendMsg'](_0x529f46);},0xbb8);},_0x162eb3[_0x44a3fc(0x39b)]=function(_0x24e6c5){var _0x9beaee=_0x44a3fc;_0x162eb3['connect']();if(_0x24e6c5[_0x9beaee(0x3f4)]>0x0){var _0x19b0b6={};_0x19b0b6[_0x9beaee(0x4e0)]=_0x9beaee(0x238),_0x19b0b6[_0x9beaee(0x34f)]=_0x24e6c5,_0x162eb3['sendMsg'](_0x19b0b6),_0x162eb3[_0x9beaee(0x3b8)][_0x24e6c5]=!![];}else log('stream\x20ID\x20is\x200\x20length');},_0x162eb3[_0x44a3fc(0x37f)]=function _0x21766c(_0x390a80){var _0x4bc49b=_0x44a3fc;_0x162eb3['connect']();var _0xcdea3c={};return _0xcdea3c['request']='joinroom',_0x162eb3[_0x4bc49b(0x1b6)]&&(_0xcdea3c[_0x4bc49b(0x2f2)]=!![]),_0x162eb3[_0x4bc49b(0x285)]&&(_0xcdea3c[_0x4bc49b(0x34f)]=_0x162eb3['streamID']),_0x162eb3[_0x4bc49b(0x376)]===![]&&(_0x162eb3[_0x4bc49b(0x376)]=!![]),_0x162eb3[_0x4bc49b(0xf2)]?_0x162eb3[_0x4bc49b(0x429)]?_0x162eb3[_0x4bc49b(0x3e7)](_0x390a80+_0x162eb3['password']+_0x162eb3[_0x4bc49b(0x14c)],0x10)[_0x4bc49b(0x57e)](function(_0x16b5db){var _0x891f43=_0x4bc49b;if('UTeNX'!=='VKwws'){if(_0x162eb3[_0x891f43(0x285)]){if(_0x891f43(0x323)!==_0x891f43(0x323)){function _0x4e6932(){_0x59f428('Answer\x20SDP\x20does\x20not\x20have\x20a\x20matching\x20session\x20ID');return;}}else _0x162eb3[_0x891f43(0x53b)]=_0x16b5db;}return _0xcdea3c[_0x891f43(0x27b)]=_0x16b5db,_0x162eb3[_0x891f43(0x15f)](_0xcdea3c),_0x162eb3[_0x891f43(0x1c3)]=_0xfc9fab(),log(_0x891f43(0x337)),_0x162eb3[_0x891f43(0x1c3)];}else{function _0x50cbd6(){var _0x8d6d1b=_0x891f43;_0x3fca81[_0x8d6d1b(0x1f4)][this[_0x8d6d1b(0x1e2)]][_0x8d6d1b(0x340)][_0x8d6d1b(0x21e)][_0x8d6d1b(0x1fb)]=_0x8d6d1b(0x277);}}}):_0x162eb3[_0x4bc49b(0x3e7)](_0x162eb3[_0x4bc49b(0xf2)]+_0x162eb3[_0x4bc49b(0x14c)],0x6)['then'](function(_0x4d7bad){var _0x2300bd=_0x4bc49b;return _0x162eb3[_0x2300bd(0x429)]=_0x4d7bad,log('hash\x20is\x20'+_0x4d7bad),log(_0x2300bd(0x26a)),_0x162eb3['joinRoom'](_0x390a80);}):(_0x162eb3[_0x4bc49b(0x285)]&&(_0x162eb3['roomenc']=_0x390a80),_0xcdea3c[_0x4bc49b(0x27b)]=_0x390a80,_0x162eb3[_0x4bc49b(0x15f)](_0xcdea3c),_0x162eb3[_0x4bc49b(0x1c3)]=_0xfc9fab(),log(_0x4bc49b(0xd0)),_0x162eb3[_0x4bc49b(0x1c3)]);},_0x162eb3['sendMsg']=function(_0x317136){var _0x4716df=_0x44a3fc;_0x162eb3[_0x4716df(0x285)]&&(_0x162eb3[_0x4716df(0x1e2)]?_0x317136[_0x4716df(0x2b9)]=_0x162eb3[_0x4716df(0x1e2)]:(_0x162eb3['UUID']=_0x162eb3[_0x4716df(0x2af)](0x14),_0x317136['from']=_0x162eb3[_0x4716df(0x1e2)]),_0x162eb3[_0x4716df(0x1b6)]&&(_0x317136[_0x4716df(0x1b6)]=!![]),!(_0x4716df(0x27b)in _0x317136)&&(_0x162eb3[_0x4716df(0x53b)]&&(_0x317136[_0x4716df(0x27b)]=_0x162eb3[_0x4716df(0x53b)])));clearTimeout(_0x162eb3[_0x4716df(0x371)]);try{if(_0x162eb3[_0x4716df(0xf2)]){if(_0x317136[_0x4716df(0x34f)]){if(_0x4716df(0x353)==='wTfor'){if(_0x162eb3[_0x4716df(0x429)]!==![]){if(typeof _0x162eb3['ws']!==_0x4716df(0x1b1)||_0x162eb3['ws'][_0x4716df(0x2bb)]!==0x1)log(_0x317136,_0x4716df(0x3fc)),_0x162eb3['msg'][_0x4716df(0x21d)](_0x317136);else{_0x317136[_0x4716df(0x34f)]=_0x317136[_0x4716df(0x34f)][_0x4716df(0x129)](0x0,0x18)+_0x162eb3[_0x4716df(0x429)][_0x4716df(0x129)](0x0,0x6);var _0x5ec857=JSON[_0x4716df(0x444)](_0x317136);if(_0x5ec857[_0x4716df(0x3f4)]>0x3a98){if(_0x4716df(0x407)!==_0x4716df(0x407)){function _0x21abb1(){return;}}else{errorlog(_0x4716df(0x559));return;}}_0x162eb3['ws']['send'](_0x5ec857);}}else return _0x162eb3['generateHash'](_0x162eb3[_0x4716df(0xf2)]+_0x162eb3[_0x4716df(0x14c)],0x6)['then'](function(_0x512e05){var _0x4d25d6=_0x4716df;_0x162eb3[_0x4d25d6(0x429)]=_0x512e05;if(typeof _0x162eb3['ws']!==_0x4d25d6(0x1b1)||_0x162eb3['ws']['readyState']!==0x1){if('GvIxe'!=='OCvbC')log(_0x317136,'could\x20not\x20be\x20sent;\x20queuing\x20it'),_0x162eb3['msg'][_0x4d25d6(0x21d)](_0x317136);else{function _0x56313b(){var _0x238523=_0x4d25d6;_0x29d3be[_0x238523(0x4bb)][_0x5cdefc]={},_0x35e1ad['keys'][_0x39b3a2][_0x238523(0x52a)]=_0x4f57db,_0x1b206b[_0x238523(0x4bb)][_0x46eb4b][_0x238523(0x13b)]=null;}}}else{_0x317136[_0x4d25d6(0x34f)]=_0x317136[_0x4d25d6(0x34f)][_0x4d25d6(0x129)](0x0,0x18)+_0x162eb3[_0x4d25d6(0x429)][_0x4d25d6(0x129)](0x0,0x6);var _0x4ee0e7=JSON[_0x4d25d6(0x444)](_0x317136);if(_0x4ee0e7[_0x4d25d6(0x3f4)]>0x3a98){errorlog(_0x4d25d6(0x559));return;}_0x162eb3['ws']['send'](_0x4ee0e7);}});}else{function _0x545db1(){var _0x30b124=_0x4716df;_0x4cb646[_0x30b124(0x512)][0x0]['active']=![];}}}else{if(_0x4716df(0x2ab)==='sAClO'){if(typeof _0x162eb3['ws']!==_0x4716df(0x1b1)||_0x162eb3['ws']['readyState']!==0x1)log(_0x317136,'could\x20not\x20be\x20sent;\x20queuing\x20it'),_0x162eb3[_0x4716df(0x360)][_0x4716df(0x21d)](_0x317136);else{var _0x5ec857=JSON[_0x4716df(0x444)](_0x317136);if(_0x5ec857[_0x4716df(0x3f4)]>0x3a98){errorlog(_0x4716df(0x559));return;}_0x162eb3['ws'][_0x4716df(0x388)](_0x5ec857);}}else{function _0x3d9419(){var _0x2b292f=_0x4716df;_0x90f258[_0x2b292f(0x1f4)][_0x3524c0][_0x2b292f(0x340)][_0x2b292f(0x253)]=_0xfbed03[_0x2b292f(0x1f4)][_0x52a22f][_0x2b292f(0x144)];}}}}else{if(typeof _0x162eb3['ws']!==_0x4716df(0x1b1)||_0x162eb3['ws'][_0x4716df(0x2bb)]!==0x1)log(_0x317136,'could\x20not\x20be\x20sent;\x20queuing\x20it'),_0x162eb3[_0x4716df(0x360)][_0x4716df(0x21d)](_0x317136);else{var _0x5ec857=JSON[_0x4716df(0x444)](_0x317136);if(_0x5ec857[_0x4716df(0x3f4)]>0x3a98){errorlog(_0x4716df(0x559));return;}_0x162eb3['ws']['send'](_0x5ec857);}}}catch(_0x44f9e0){errorlog(_0x44f9e0);}},_0x162eb3[_0x44a3fc(0x47d)]=function _0x5a374e(_0x38ec87=![]){var _0x417729=_0x44a3fc;if(_0x162eb3[_0x417729(0x46b)]===!![]){log('tainted');return;}if(_0x162eb3['ws']!==null){log('already\x20connected');return;}_0x162eb3[_0x417729(0x403)]==![]&&(_0x162eb3[_0x417729(0x403)]=_0x417729(0x23d)),_0x162eb3['ws']=new WebSocket(_0x162eb3[_0x417729(0x403)]),_0x38ec87==![]&&(_0x162eb3[_0x417729(0x351)]=setTimeout(function(){var _0x5135ac=_0x417729;pokeIframeAPI(_0x5135ac(0x526),_0x5135ac(0x351)),errorlog(_0x5135ac(0xd3)),!_0x162eb3[_0x5135ac(0x14e)]&&(!window['obsstudio']&&setTimeout(function(){var _0x42d7e1=_0x5135ac;warnUser(_0x42d7e1(0x2e1));},0x1));},0x7530)),_0x162eb3['ws'][_0x417729(0x3ef)]=function _0x1d171c(){var _0xed77cb=_0x417729;clearTimeout(_0x162eb3[_0xed77cb(0x371)]),clearInterval(_0x162eb3[_0xed77cb(0x351)]),log('connected\x20to\x20video\x20server'),checkConnection();if(_0x162eb3[_0xed77cb(0x338)]){if(_0xed77cb(0x4bf)===_0xed77cb(0x4bf)){errorlog(_0xed77cb(0x434));for(_0x2fe5c0 in _0x162eb3['rpcs']){if(_0xed77cb(0x574)===_0xed77cb(0x574))try{_0x162eb3[_0xed77cb(0x1f4)][_0x2fe5c0][_0xed77cb(0x556)]();}catch(_0x2637ba){}else{function _0x1d1055(){var _0x54e93c=_0xed77cb;_0x25da93[_0x54e93c(0x3cc)][_0x54e93c(0x419)]===![]&&(_0x29a6e8=!![]),_0x42474d[_0x54e93c(0xeb)]=_0x49a647[_0x54e93c(0x3cc)][_0x54e93c(0x419)];}}}for(_0x2fe5c0 in _0x162eb3[_0xed77cb(0x147)]){try{_0x162eb3[_0xed77cb(0x147)][_0x2fe5c0]['close']();}catch(_0x2aa02d){}}_0x162eb3[_0xed77cb(0x338)]=![];}else{function _0x23644a(){var _0x1e770d=_0xed77cb;_0x4245c9[_0x1e770d(0x147)][_0x321f89][_0x1e770d(0x383)]=!![],_0x51a8ef(function(){_0x5651b1();},0x3e8);}}}if(_0x162eb3[_0xed77cb(0x360)]!==[])try{var _0x2b2c35=_0x162eb3[_0xed77cb(0x360)][_0xed77cb(0x32a)](-0xa);_0x162eb3[_0xed77cb(0x360)]=[];for(var _0x20b377 in _0x2b2c35){log(_0xed77cb(0x235)),_0x162eb3[_0xed77cb(0x15f)](_0x2b2c35[_0x20b377]);}}catch(_0x23d4a5){errorlog(_0x23d4a5);}if(_0x38ec87==!![]){pokeIframeAPI(_0xed77cb(0x526),_0xed77cb(0x57a));_0x162eb3[_0xed77cb(0x332)]&&_0x162eb3[_0xed77cb(0x216)]();if(_0x162eb3[_0xed77cb(0x27b)]!==![]){if(_0x162eb3[_0xed77cb(0x27b)]===''&&(!_0x162eb3[_0xed77cb(0x3db)]||_0x162eb3[_0xed77cb(0x3db)]==='')){}else log(_0xed77cb(0x547)),log(_0xed77cb(0x3d6)),joinRoom(_0x162eb3[_0xed77cb(0x27b)]);}else{var _0x23fe3e=Object[_0xed77cb(0x4bb)](_0x162eb3[_0xed77cb(0x3b8)]);for(var _0x2fe5c0 in _0x23fe3e){log(_0xed77cb(0x2b7)+_0x23fe3e[_0x2fe5c0]),_0x162eb3['watchStream'](_0x23fe3e[_0x2fe5c0]);}}}else pokeIframeAPI(_0xed77cb(0x526),_0xed77cb(0x4e6));},_0x162eb3[_0x417729(0x358)]=function(_0x3a58ac,_0x57f75a=![]){var _0x217a1b=_0x417729,_0x42f0e9=[];for(var _0x246d4d in _0x162eb3[_0x217a1b(0x147)]){if(_0x57f75a&&_0x57f75a!==_0x246d4d)continue;try{if(_0x217a1b(0x510)===_0x217a1b(0x510))_0x162eb3['pcs'][_0x246d4d][_0x217a1b(0x4ae)]['send'](JSON['stringify'](_0x3a58ac)),_0x42f0e9[_0x217a1b(0x21d)](_0x246d4d);else{function _0x1edf5a(){var _0x4f297c=_0x217a1b;_0x536528[_0x4f297c(0x1f4)][_0x25c0c7[_0x4f297c(0x37c)]][_0x4f297c(0x14f)][_0x4f297c(0x53f)]&&(_0x2a040e[_0x4f297c(0x1f4)][_0x9e9bbb['directorUUID']]['stats'][_0x4f297c(0x53f)][_0x4f297c(0x1b6)]=!![]);}}}catch(_0x591750){warnlog(_0x217a1b(0x4ad));}if(_0x57f75a&&_0x57f75a===_0x246d4d){if(_0x217a1b(0x35c)===_0x217a1b(0x326)){function _0x2b5dde(){return;}}else return;}}for(var _0x246d4d in _0x162eb3[_0x217a1b(0x1f4)]){if(_0x57f75a&&_0x57f75a!==_0x246d4d)continue;if(_0x42f0e9[_0x217a1b(0x28f)](_0x246d4d))continue;try{_0x162eb3[_0x217a1b(0x1f4)][_0x246d4d][_0x217a1b(0x228)][_0x217a1b(0x388)](JSON[_0x217a1b(0x444)](_0x3a58ac));}catch(_0x2c4fa0){warnlog(_0x217a1b(0x3e5));}}},_0x162eb3['anysend']=function(_0x2189d9,_0x2a731b=![]){var _0x294997=_0x417729,_0x1041d0=![];if(_0x294997(0x1e2)in _0x2189d9)_0x1041d0=_0x162eb3[_0x294997(0x43f)](_0x2189d9,_0x2189d9['UUID']),_0x1041d0?(log(_0x2189d9),log(_0x294997(0x555))):(log(_0x294997(0x26f)),_0x162eb3['sendMsg'](_0x2189d9));else _0x2a731b?(_0x1041d0=_0x162eb3[_0x294997(0x43f)](_0x2189d9),_0x1041d0?(log(_0x2189d9),log('successfully\x20sent\x20message\x20vis\x20WebRTC\x20instead\x20of\x20WSS\x20to\x20all\x20RTC\x20Peers')):(log('sending\x20message\x20via\x20WSS\x20as\x20WebRTC\x20failed\x20to\x20send\x20message;\x20RTC\x20peers\x20only'),_0x162eb3['sendMsg'](_0x2189d9))):(_0x162eb3[_0x294997(0x15f)](_0x2189d9),log('sending\x20message\x20to\x20server'));},_0x162eb3['anyrequest']=function(_0x492208,_0x1f3580=![]){var _0x3864d1=_0x417729,_0x216b0a=![];if(_0x3864d1(0x1e2)in _0x492208)_0x216b0a=_0x162eb3[_0x3864d1(0x196)](_0x492208,_0x492208[_0x3864d1(0x1e2)]),_0x216b0a?log('successfully\x20sent\x20message\x20vis\x20WebRTC\x20instead\x20of\x20WSS'):(log(_0x3864d1(0x26f)),_0x162eb3['sendMsg'](_0x492208));else _0x1f3580?(_0x216b0a=_0x162eb3['sendRequest'](_0x492208),_0x216b0a?log(_0x3864d1(0x4b4)):(log(_0x3864d1(0x4be)),_0x162eb3[_0x3864d1(0x15f)](_0x492208))):(_0x162eb3[_0x3864d1(0x15f)](_0x492208),log('sending\x20message\x20to\x20server'));},_0x162eb3[_0x417729(0x414)]=function(){var _0x234c3a=_0x417729;if(_0x162eb3[_0x234c3a(0x381)]===![]){if('GQdVS'===_0x234c3a(0x34b)){var _0x99f276={},_0x1d4cf8=![];_0x162eb3[_0x234c3a(0x3cc)][_0x234c3a(0x419)]!==null&&(_0x162eb3[_0x234c3a(0x3cc)][_0x234c3a(0x419)]===![]&&(_0x1d4cf8=!![]),_0x99f276['obsVisibility']=_0x162eb3[_0x234c3a(0x3cc)][_0x234c3a(0x419)]);_0x162eb3[_0x234c3a(0x3cc)][_0x234c3a(0x422)]!==null&&(_0x99f276['obsSourceActive']=_0x162eb3[_0x234c3a(0x3cc)][_0x234c3a(0x422)]);_0x162eb3[_0x234c3a(0x3cc)][_0x234c3a(0x38a)]!==null&&(_0x99f276['obsRecording']=_0x162eb3[_0x234c3a(0x3cc)][_0x234c3a(0x38a)]);_0x162eb3[_0x234c3a(0x3cc)]['streaming']!==null&&(_0x99f276[_0x234c3a(0x223)]=_0x162eb3['obsState']['streaming']);for(var _0x50f6c6 in _0x162eb3[_0x234c3a(0x1f4)]){if(_0x162eb3[_0x234c3a(0x1a1)]!==![]){var _0x17d3c1=parseInt(_0x162eb3['rpcs'][_0x50f6c6][_0x234c3a(0x2e6)]);_0x1d4cf8&&((_0x17d3c1>_0x162eb3[_0x234c3a(0x1a1)]||_0x17d3c1<0x0)&&(_0x17d3c1=_0x162eb3[_0x234c3a(0x1a1)])),_0x162eb3['rpcs'][_0x50f6c6][_0x234c3a(0x40b)]!==_0x17d3c1?(_0x99f276[_0x234c3a(0x22c)]=_0x17d3c1,warnlog(_0x234c3a(0x437)),warnlog(_0x99f276),_0x162eb3[_0x234c3a(0x196)](_0x99f276,_0x50f6c6)?_0x162eb3[_0x234c3a(0x1f4)][_0x50f6c6]['bandwidth']=_0x17d3c1:errorlog('Unable\x20to\x20set\x20update\x20OBS\x20Visibility')):(warnlog(_0x234c3a(0x437)),warnlog(_0x99f276),_0x162eb3['sendRequest'](_0x99f276,_0x50f6c6));}else warnlog('Message\x20to\x20be\x20sent:\x20'),warnlog(_0x99f276),_0x162eb3[_0x234c3a(0x196)](_0x99f276,_0x50f6c6);}}else{function _0x39f348(){var _0x5ce54a=_0x234c3a;_0x139e9b[_0x5ce54a(0x376)]=!![];}}}},_0x162eb3['sceneSync']=function(_0x4c5c9a){var _0x44b076=_0x417729;if(_0x44b076(0x3a8)!==_0x44b076(0x3a8)){function _0x4fbbe0(){var _0x113ab0=_0x44b076;try{_0x36a22d(_0x5c0ee9),_0x45876c['setResolution'](_0x30b26d[_0x113ab0(0x1e2)],_0xc65aaf[_0x113ab0(0x322)]['w'],_0x22d5a4['requestResolution']['h']);}catch(_0x231e67){_0x18e71c(_0x231e67);}}}else{if(!_0x162eb3['rpcs'][_0x4c5c9a]['videoElement'])return;var _0x889057={};_0x889057[_0x44b076(0x199)]=_0x162eb3[_0x44b076(0x1f4)][_0x4c5c9a][_0x44b076(0x340)]['style'][_0x44b076(0x1fb)]!=_0x44b076(0x277),_0x889057[_0x44b076(0x342)]=_0x162eb3[_0x44b076(0x1f4)][_0x4c5c9a]['videoElement'][_0x44b076(0x253)];if(_0x162eb3[_0x44b076(0x1a1)]!==![]){var _0x2eb34d=parseInt(_0x162eb3[_0x44b076(0x1f4)][_0x4c5c9a][_0x44b076(0x2e6)]);_0x889057[_0x44b076(0x199)]===![]&&((_0x2eb34d>_0x162eb3[_0x44b076(0x1a1)]||_0x2eb34d<0x0)&&(_0x2eb34d=_0x162eb3[_0x44b076(0x1a1)])),_0x162eb3[_0x44b076(0x1f4)][_0x4c5c9a]['bandwidth']!==_0x2eb34d?(_0x889057[_0x44b076(0x22c)]=_0x2eb34d,_0x162eb3[_0x44b076(0x196)](_0x889057,_0x4c5c9a)?_0x162eb3[_0x44b076(0x1f4)][_0x4c5c9a][_0x44b076(0x40b)]=_0x2eb34d:errorlog(_0x44b076(0x126))):_0x162eb3['sendRequest'](_0x889057,_0x4c5c9a);}else _0x162eb3[_0x44b076(0x196)](_0x889057,_0x4c5c9a);}},_0x162eb3[_0x417729(0x20b)]=function(_0x4cbeee){var _0x25ca02=_0x417729;if(_0x25ca02(0x328)in _0x4cbeee){if(_0x25ca02(0x324)in _0x4cbeee){if(_0x25ca02(0x145)in _0x4cbeee){if(_0x162eb3[_0x25ca02(0x145)]!==![]){var _0x264052=![];for(var _0x4b54d3 in _0x162eb3[_0x25ca02(0x1f4)]){if(_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x34f)]===_0x4cbeee[_0x25ca02(0x324)]){if(_0x25ca02(0x276)in _0x4cbeee){if(_0x4cbeee[_0x25ca02(0x328)]==_0x25ca02(0x2c6)){if(_0x4cbeee[_0x25ca02(0x276)]==0x0)log(_0x25ca02(0x1f6)),_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)]&&(_0x162eb3['rpcs'][_0x4b54d3]['videoElement'][_0x25ca02(0x253)]=!![],_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x144)]=!![]);else{log(_0x25ca02(0x3c9));if(_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3]['videoElement']){if(_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x21e)]['display']==_0x25ca02(0x277)){if(_0x25ca02(0x16c)===_0x25ca02(0x16c))_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x144)]=![],_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x253)]=!![];else{function _0x575f50(){var _0x37a5b8=_0x25ca02;'ip'in _0x3bfd1b&&(_0x4ae3cc[_0x37a5b8(0x1f4)][_0x1bf725][_0x37a5b8(0x14f)][_0x37a5b8(0x446)][_0x37a5b8(0x21b)]=_0x21d48['ip']),_0x38858b['rpcs'][_0x4ce964][_0x37a5b8(0x14f)][_0x37a5b8(0x446)][_0x37a5b8(0x552)]=_0x174019['relayProtocol'];}}}else _0x162eb3['rpcs'][_0x4b54d3][_0x25ca02(0x144)]=![],_0x162eb3['rpcs'][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x253)]=![];}}_0x162eb3[_0x25ca02(0x411)](_0x4b54d3);}else{if(_0x4cbeee[_0x25ca02(0x328)]==_0x25ca02(0x1fb)){if(_0x162eb3[_0x25ca02(0x3db)])return;;if(_0x162eb3[_0x25ca02(0x145)]===_0x4cbeee['scene']){if(_0x162eb3[_0x25ca02(0x35e)]==0x2){if('rPjKz'===_0x25ca02(0x13d)){function _0x1bbceb(){var _0x58a485=_0x25ca02;_0x3c1c58(_0x4f579d,_0x294c5e[_0x58a485(0x305)]);}}else{if(_0x4cbeee[_0x25ca02(0x276)]==0x0){if(_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3]['videoElement']){if(_0x25ca02(0x57f)==='xbbMg')_0x162eb3['rpcs'][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x253)]=!![],_0x162eb3['rpcs'][_0x4b54d3][_0x25ca02(0x340)]['style'][_0x25ca02(0x1fb)]&&_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x21e)][_0x25ca02(0x1fb)]!==_0x25ca02(0x277)&&(_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3]['videoElement'][_0x25ca02(0x21e)][_0x25ca02(0x1fb)]=_0x25ca02(0x277),_0x264052=!![]);else{function _0xc50e33(){var _0x156851=_0x25ca02,_0x3e13ca=new _0x432120(_0x5cca70),_0x391f2e='';for(var _0x65083f=0x0;_0x65083f<_0x3e13ca[_0x156851(0xf9)];_0x65083f++){_0x391f2e+=_0x1de68c[_0x156851(0x3f3)](_0x3e13ca[_0x65083f]);}return _0x391f2e;}}}}else{if(_0x25ca02(0x4fe)===_0x25ca02(0x137)){function _0x4c18bc(){var _0x1ba9a7=_0x25ca02;_0x56508e['getElementById'](_0x1ba9a7(0x22e)+this[_0x1ba9a7(0x1e2)])&&_0x14bf8a(_0x1ba9a7(0x22e)+this['UUID'])[_0x1ba9a7(0x23c)][_0x1ba9a7(0x45f)](_0x4c26d8(_0x1ba9a7(0x22e)+this[_0x1ba9a7(0x1e2)]));}}else{for(var _0x294b66 in _0x162eb3[_0x25ca02(0x1f4)]){if(_0x294b66!==_0x4b54d3){if(_0x25ca02(0xd6)!==_0x25ca02(0xd6)){function _0x46a32b(){var _0x4c5da3=_0x25ca02;_0x36a2f9[_0x4c5da3(0x21d)](_0x5c132b);}}else _0x162eb3[_0x25ca02(0x1f4)][_0x294b66]['videoElement']&&(_0x162eb3[_0x25ca02(0x1f4)][_0x294b66][_0x25ca02(0x340)]['muted']=!![],_0x162eb3[_0x25ca02(0x1f4)][_0x294b66][_0x25ca02(0x340)][_0x25ca02(0x21e)][_0x25ca02(0x1fb)]&&_0x162eb3[_0x25ca02(0x1f4)][_0x294b66][_0x25ca02(0x340)][_0x25ca02(0x21e)][_0x25ca02(0x1fb)]!==_0x25ca02(0x277)&&(_0x162eb3['rpcs'][_0x294b66][_0x25ca02(0x340)][_0x25ca02(0x21e)][_0x25ca02(0x1fb)]=_0x25ca02(0x277),_0x264052=!![]));}}_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)]&&(_0x162eb3['rpcs'][_0x4b54d3][_0x25ca02(0x340)]['style'][_0x25ca02(0x1fb)]&&_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x21e)][_0x25ca02(0x1fb)]!=='block'&&(_0x162eb3['rpcs'][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x21e)][_0x25ca02(0x1fb)]=_0x25ca02(0x545),_0x264052=!![]),_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x144)]===null?_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3]['videoElement']['muted']=![]:_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x253)]=_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x144)],_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x2aa)]&&clearInterval(_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x2aa)]),_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x1c7)]=![],_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)]['controlTimer']=setTimeout(showControlBar[_0x25ca02(0x168)](null,_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)]),0xbb8));}}}}else{if(_0x162eb3[_0x25ca02(0x35e)]==0x1){if(_0x4cbeee[_0x25ca02(0x276)]==0x0)_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)]&&(_0x162eb3['rpcs'][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x21e)][_0x25ca02(0x1fb)]&&_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x21e)][_0x25ca02(0x1fb)]!==_0x25ca02(0x277)&&(_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x21e)][_0x25ca02(0x1fb)]='none',_0x264052=!![]));else{for(var _0x294b66 in _0x162eb3[_0x25ca02(0x1f4)]){_0x294b66!==_0x4b54d3&&(_0x162eb3['rpcs'][_0x294b66][_0x25ca02(0x340)][_0x25ca02(0x21e)][_0x25ca02(0x1fb)]&&_0x162eb3['rpcs'][_0x294b66][_0x25ca02(0x340)]['style'][_0x25ca02(0x1fb)]!==_0x25ca02(0x277)&&(_0x162eb3[_0x25ca02(0x1f4)][_0x294b66][_0x25ca02(0x340)][_0x25ca02(0x21e)][_0x25ca02(0x1fb)]=_0x25ca02(0x277),_0x264052=!![]));}_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)]&&(_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x21e)][_0x25ca02(0x1fb)]&&_0x162eb3['rpcs'][_0x4b54d3]['videoElement'][_0x25ca02(0x21e)][_0x25ca02(0x1fb)]!==_0x25ca02(0x545)&&(_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x21e)][_0x25ca02(0x1fb)]='block',_0x264052=!![]),_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x2aa)]&&clearInterval(_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x2aa)]),_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3]['videoElement'][_0x25ca02(0x1c7)]=![],_0x162eb3['rpcs'][_0x4b54d3][_0x25ca02(0x340)]['controlTimer']=setTimeout(showControlBar[_0x25ca02(0x168)](null,_0x162eb3['rpcs'][_0x4b54d3][_0x25ca02(0x340)]),0xbb8));}}else{if(_0x4cbeee[_0x25ca02(0x276)]==0x0){if('bbnXU'===_0x25ca02(0x32e)){function _0x15626e(){var _0x2737f8=_0x25ca02,_0x4af0b1=_0x380694[_0x2737f8(0x444)](_0x58f737);if(_0x4af0b1[_0x2737f8(0x3f4)]>0x3a98){_0x314015(_0x2737f8(0x559));return;}_0x3f5675['ws'][_0x2737f8(0x388)](_0x4af0b1);}}else{if(_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)]){if(_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x21e)][_0x25ca02(0x1fb)]&&_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x21e)][_0x25ca02(0x1fb)]!==_0x25ca02(0x277)){if(_0x25ca02(0x44c)!==_0x25ca02(0x313))_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3]['videoElement'][_0x25ca02(0x21e)][_0x25ca02(0x1fb)]=_0x25ca02(0x277),_0x264052=!![];else{function _0x27156c(){var _0x4e2368=_0x25ca02;_0x2bc082[_0x4e2368(0x4e0)]='transferred',_0x42ac92[_0x4e2368(0x53b)]=_0x4efb86[_0x4e2368(0x27b)];var _0x4ca7fb={};_0x4ca7fb[_0x4e2368(0x4e0)]=_0x4e2368(0x576),_0x4ca7fb[_0x4e2368(0x27b)]=_0x51c537[_0x4e2368(0x53b)],_0x4ca7fb['streamID']=_0x180b46[_0x4e2368(0x34f)],_0x445097[_0x4e2368(0x15f)](_0x4ca7fb);}}}_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x253)]=!![];}}}else _0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)]&&(_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3]['videoElement'][_0x25ca02(0x21e)][_0x25ca02(0x1fb)]&&_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x21e)][_0x25ca02(0x1fb)]!=='block'&&(_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x21e)][_0x25ca02(0x1fb)]=_0x25ca02(0x545),_0x264052=!![]),_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x144)]===null?_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x253)]=![]:_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x253)]=_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x144)],_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3]['videoElement'][_0x25ca02(0x2aa)]&&clearInterval(_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x2aa)]),_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x1c7)]=![],_0x162eb3['rpcs'][_0x4b54d3][_0x25ca02(0x340)]['controlTimer']=setTimeout(showControlBar[_0x25ca02(0x168)](null,_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3]['videoElement']),0xbb8));}}}_0x162eb3[_0x25ca02(0x411)](_0x4b54d3);}else _0x4cbeee['action']=='volume'&&(log(parseInt(_0x4cbeee[_0x25ca02(0x276)])/0x64),_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)]&&(_0x162eb3[_0x25ca02(0x1f4)][_0x4b54d3][_0x25ca02(0x340)][_0x25ca02(0x280)]=parseInt(_0x4cbeee[_0x25ca02(0x276)])/0x64,log(_0x25ca02(0x2cb))));}}}}_0x264052&&updateMixer();}}else{if(_0x4cbeee[_0x25ca02(0x328)]==_0x25ca02(0x3c8)){}else{if(_0x4cbeee[_0x25ca02(0x328)]==_0x25ca02(0x498)){}}}}}},_0x162eb3['ws'][_0x417729(0x1f2)]=function(_0x30bc55){var _0x1b8812=_0x417729;clearTimeout(_0x162eb3[_0x1b8812(0x371)]);var _0xcf8f5b=JSON[_0x1b8812(0x4aa)](_0x30bc55[_0x1b8812(0x2cd)]);_0x1b8812(0x34f)in _0xcf8f5b&&(_0xcf8f5b[_0x1b8812(0x34f)]=_0x162eb3['desaltStreamID'](_0xcf8f5b[_0x1b8812(0x34f)]));if(_0x162eb3[_0x1b8812(0x285)]){if(_0x1b8812(0x49c)!==_0x1b8812(0x205)){if(_0x1b8812(0x1e2)in _0xcf8f5b){if(_0x162eb3[_0x1b8812(0x1e2)]){if(_0xcf8f5b[_0x1b8812(0x1e2)]!==_0x162eb3[_0x1b8812(0x1e2)])return;}else return;delete _0xcf8f5b[_0x1b8812(0x1e2)];}if('roomid'in _0xcf8f5b){if(!_0x162eb3[_0x1b8812(0x53b)])return;if('request'in _0xcf8f5b){if(_0xcf8f5b[_0x1b8812(0x4e0)]===_0x1b8812(0x3c8)){if('roomid'in _0xcf8f5b){if(_0x1b8812(0x37a)==='nMBlY'){if(_0x1b8812(0x324)in _0xcf8f5b){if(_0xcf8f5b['target']==_0x162eb3[_0x1b8812(0x1e2)]){_0xcf8f5b[_0x1b8812(0x4e0)]=_0x1b8812(0x338),_0x162eb3[_0x1b8812(0x53b)]=_0xcf8f5b[_0x1b8812(0x27b)];var _0x257e1b={};_0x257e1b[_0x1b8812(0x4e0)]='joinroom',_0x257e1b[_0x1b8812(0x27b)]=_0x162eb3[_0x1b8812(0x53b)],_0x257e1b[_0x1b8812(0x34f)]=_0x162eb3[_0x1b8812(0x34f)],_0x162eb3[_0x1b8812(0x15f)](_0x257e1b);}else return;}else return;}else{function _0x31e83d(){var _0x305e48=_0x1b8812;return _0x1a9401[_0x305e48(0x285)]&&(_0x57847d[_0x305e48(0x53b)]=_0x1e8204),_0x9477af['roomid']=_0x3aa49e,_0x436ddb[_0x305e48(0x15f)](_0x309412),_0x33ca6f[_0x305e48(0x1c3)]=_0x437b89(),_0x222fd1('deferring\x20with\x20a\x20promise'),_0x491cdc['listPromise'];}}}else return;}else{if(_0xcf8f5b[_0x1b8812(0x27b)]!==_0x162eb3[_0x1b8812(0x53b)])return;}}else{if(_0xcf8f5b[_0x1b8812(0x27b)]!==_0x162eb3[_0x1b8812(0x53b)])return;}delete _0xcf8f5b[_0x1b8812(0x27b)];}'director'in _0xcf8f5b&&(_0xcf8f5b[_0x1b8812(0x2b9)]&&(_0x162eb3[_0x1b8812(0x37c)]=_0xcf8f5b[_0x1b8812(0x2b9)]),delete _0xcf8f5b[_0x1b8812(0x1b6)]);_0x1b8812(0x2b9)in _0xcf8f5b&&(_0xcf8f5b[_0x1b8812(0x1e2)]=_0xcf8f5b['from'],delete _0xcf8f5b[_0x1b8812(0x2b9)]);if(_0x1b8812(0x4e0)in _0xcf8f5b){if(_0xcf8f5b['request']===_0x1b8812(0x238)){if(_0x1b8812(0x34f)in _0xcf8f5b){if(_0xcf8f5b[_0x1b8812(0x34f)]===_0x162eb3['streamID'])_0xcf8f5b[_0x1b8812(0x4e0)]=_0x1b8812(0x179);else return;}}else{if(_0xcf8f5b[_0x1b8812(0x4e0)]===_0x1b8812(0x102)){if(_0x162eb3[_0x1b8812(0x1ca)]){if(_0x162eb3['view_set'][_0x1b8812(0x28f)](_0xcf8f5b['streamID'])){play(_0xcf8f5b[_0x1b8812(0x34f)]);return;}else return;}else{if(_0x162eb3['view']){if(_0x162eb3[_0x1b8812(0x3db)]!==_0xcf8f5b[_0x1b8812(0x34f)])return;else{play(_0xcf8f5b[_0x1b8812(0x34f)]);return;}}}}else{if(_0xcf8f5b[_0x1b8812(0x4e0)]===_0x1b8812(0x576)){if(_0x1b8812(0x34f)in _0xcf8f5b){if(_0x162eb3['view_set']){if(_0x162eb3[_0x1b8812(0x1ca)][_0x1b8812(0x28f)](_0xcf8f5b[_0x1b8812(0x34f)]))play(_0xcf8f5b[_0x1b8812(0x34f)]);else{}}else{if(_0x162eb3[_0x1b8812(0x3db)]){if(_0x162eb3[_0x1b8812(0x3db)]!==_0xcf8f5b['streamID']){}else play(_0xcf8f5b[_0x1b8812(0x34f)]);}else play(_0xcf8f5b[_0x1b8812(0x34f)]);}}_0xcf8f5b[_0x1b8812(0x4e0)]=_0x1b8812(0x179);}}}}}else{function _0xc8e002(){var _0x5c437d=_0x1b8812;_0x254181[_0x5c437d(0x512)][0x0][_0x5c437d(0x2da)]=0x1;}}}if(_0xcf8f5b[_0x1b8812(0x4e0)]){if(_0xcf8f5b['request']==_0x1b8812(0x179)){if(_0x162eb3[_0x1b8812(0x46f)]){if(_0x162eb3[_0x1b8812(0x37c)]===_0xcf8f5b[_0x1b8812(0x1e2)])_0x162eb3[_0x1b8812(0x179)](_0xcf8f5b[_0x1b8812(0x1e2)]);else _0x162eb3[_0x1b8812(0x1b6)]&&(_0xcf8f5b[_0x1b8812(0x1e2)]in _0x162eb3[_0x1b8812(0x1f4)]&&_0x162eb3[_0x1b8812(0x179)](_0xcf8f5b['UUID']));}else _0x162eb3[_0x1b8812(0x179)](_0xcf8f5b[_0x1b8812(0x1e2)]);}else{if(_0xcf8f5b[_0x1b8812(0x4e0)]==_0x1b8812(0x579)){log(_0xcf8f5b[_0x1b8812(0x57b)]);if(_0x1b8812(0x1b6)in _0xcf8f5b)_0x162eb3[_0x1b8812(0x37c)]=_0xcf8f5b[_0x1b8812(0x1b6)],_0x162eb3[_0x1b8812(0x37c)]in _0x162eb3[_0x1b8812(0x147)]&&(_0x162eb3[_0x1b8812(0x147)][_0x162eb3[_0x1b8812(0x37c)]][_0x1b8812(0x14f)][_0x1b8812(0x53f)]&&(_0x162eb3[_0x1b8812(0x147)][_0x162eb3[_0x1b8812(0x37c)]][_0x1b8812(0x14f)][_0x1b8812(0x53f)][_0x1b8812(0x1b6)]=!![])),_0x162eb3[_0x1b8812(0x37c)]in _0x162eb3[_0x1b8812(0x1f4)]&&(_0x162eb3[_0x1b8812(0x1f4)][_0x162eb3['directorUUID']][_0x1b8812(0x14f)][_0x1b8812(0x53f)]&&(_0x162eb3[_0x1b8812(0x1f4)][_0x162eb3[_0x1b8812(0x37c)]][_0x1b8812(0x14f)][_0x1b8812(0x53f)][_0x1b8812(0x1b6)]=!![]));else{if(_0x1b8812(0x26e)===_0x1b8812(0x26e))_0x162eb3['directorUUID']=![];else{function _0x2810e6(){var _0x1ae8e7=_0x1b8812;return _0x578d10[_0x1ae8e7(0x2ac)]&&_0x6df833[_0x1ae8e7(0x2ac)]['kind']==_0x1ae8e7(0x25f);}}}_0x1b8812(0x2f2)in _0xcf8f5b&&(_0xcf8f5b[_0x1b8812(0x2f2)]==![]&&(!_0x162eb3['cleanOutput']&&(setTimeout(function(){var _0x466b02=_0x1b8812;warnUser(_0x466b02(0x2bc));},0x1),getById(_0x1b8812(0x3a1))[_0x1b8812(0x564)]=_0x1b8812(0x499)))),_0x162eb3[_0x1b8812(0x1c3)]['resolve'](_0xcf8f5b[_0x1b8812(0x57b)]);}else{if(_0xcf8f5b[_0x1b8812(0x4e0)]==_0x1b8812(0x338)){_0x162eb3[_0x1b8812(0x1c1)]=[],_0x162eb3[_0x1b8812(0x338)]=!![],log(_0x1b8812(0x581));if(!_0x162eb3[_0x1b8812(0x1b6)]){if(_0x1b8812(0x47e)!==_0x1b8812(0x453))_0x162eb3[_0x1b8812(0x46f)]=![];else{function _0x21606f(){return;}}}log(_0xcf8f5b['list']);if(_0x1b8812(0x1b6)in _0xcf8f5b){_0x162eb3['directorUUID']=_0xcf8f5b[_0x1b8812(0x1b6)];if(_0x162eb3['directorUUID']in _0x162eb3[_0x1b8812(0x147)]){if(_0x1b8812(0xdd)===_0x1b8812(0xdd))_0x162eb3[_0x1b8812(0x147)][_0x162eb3[_0x1b8812(0x37c)]][_0x1b8812(0x14f)]['info']&&(_0x162eb3[_0x1b8812(0x147)][_0x162eb3[_0x1b8812(0x37c)]]['stats'][_0x1b8812(0x53f)][_0x1b8812(0x1b6)]=!![]);else{function _0xdeb42e(){return;}}}_0x162eb3[_0x1b8812(0x37c)]in _0x162eb3['rpcs']&&(_0x162eb3['rpcs'][_0x162eb3[_0x1b8812(0x37c)]]['stats'][_0x1b8812(0x53f)]&&(_0x162eb3['rpcs'][_0x162eb3[_0x1b8812(0x37c)]][_0x1b8812(0x14f)][_0x1b8812(0x53f)][_0x1b8812(0x1b6)]=!![]));}else _0x162eb3[_0x1b8812(0x37c)]=![];for(_0x2500b8 in _0x162eb3['rpcs']){try{_0x162eb3['rpcs'][_0x2500b8]['close'](),delete _0x162eb3['rpcs'][_0x2500b8];}catch(_0xaa7a50){}}for(_0x2500b8 in _0x162eb3[_0x1b8812(0x147)]){try{_0x162eb3[_0x1b8812(0x147)][_0x2500b8][_0x1b8812(0x556)](),delete _0x162eb3[_0x1b8812(0x147)][_0x2500b8],applySceneState();}catch(_0x4743c6){}}getChatMessage(_0x1b8812(0xd8),label=![],director=![],overlay=!![]),getById(_0x1b8812(0x2d6))[_0x1b8812(0x564)]=_0x1b8812(0x31b);_0x162eb3[_0x1b8812(0x2fa)]?document[_0x1b8812(0xcf)]=_0x162eb3[_0x1b8812(0x2fa)]+_0x1b8812(0x2c2):document[_0x1b8812(0xcf)]=_0x1b8812(0x42c);_0x162eb3[_0x1b8812(0x262)]=_0x162eb3['totalRoomBitrate_default'],updateMixer(),updateUserList(),log('Members\x20in\x20Room'),log(_0xcf8f5b[_0x1b8812(0x57b)]);for(var _0x2500b8 in _0xcf8f5b['list']){if(_0x1b8812(0x1e2)in _0xcf8f5b[_0x1b8812(0x57b)][_0x2500b8]){if(_0x1b8812(0x34f)in _0xcf8f5b[_0x1b8812(0x57b)][_0x2500b8]){if(_0xcf8f5b['list'][_0x2500b8]['UUID']in _0x162eb3[_0x1b8812(0x1f4)])log('RTC\x20already\x20connected');else{var _0x5b36a1=_0x162eb3[_0x1b8812(0x20e)](_0xcf8f5b[_0x1b8812(0x57b)][_0x2500b8][_0x1b8812(0x34f)]);log(_0x1b8812(0x4d0)+_0x5b36a1);if(_0x162eb3[_0x1b8812(0x46f)]){if(_0x162eb3[_0x1b8812(0x37c)]===_0xcf8f5b[_0x1b8812(0x57b)][_0x2500b8]['UUID']){if(_0x1b8812(0x239)===_0x1b8812(0x4a0)){function _0x4b9cc8(){var _0x52f2d6=_0x1b8812;_0x27e5e1[_0x52f2d6(0xcf)]=_0x27a6f4[_0x52f2d6(0xf8)],_0x1ba8e5();}}else play(_0x5b36a1);}else _0x162eb3[_0x1b8812(0x1c1)][_0x1b8812(0x3f4)]<0x1388&&(!_0x162eb3['queueList']['includes'](_0x5b36a1)&&_0x162eb3[_0x1b8812(0x1c1)][_0x1b8812(0x21d)](_0x5b36a1));}else play(_0x5b36a1);}}}}_0x162eb3[_0x1b8812(0x309)]();}else{if(_0xcf8f5b[_0x1b8812(0x4e0)]==_0x1b8812(0x24e)){if(_0x1b8812(0x570)!==_0x1b8812(0x274))log(_0xcf8f5b),_0x1b8812(0x1b6)in _0xcf8f5b?(_0x162eb3[_0x1b8812(0x37c)]=_0xcf8f5b[_0x1b8812(0x1b6)],_0x162eb3[_0x1b8812(0x37c)]in _0x162eb3['pcs']&&(_0x162eb3['pcs'][_0x162eb3[_0x1b8812(0x37c)]][_0x1b8812(0x14f)][_0x1b8812(0x53f)]&&(_0x162eb3[_0x1b8812(0x147)][_0x162eb3[_0x1b8812(0x37c)]][_0x1b8812(0x14f)][_0x1b8812(0x53f)][_0x1b8812(0x1b6)]=!![])),_0x162eb3[_0x1b8812(0x37c)]in _0x162eb3[_0x1b8812(0x1f4)]&&(_0x162eb3[_0x1b8812(0x1f4)][_0x162eb3[_0x1b8812(0x37c)]]['stats'][_0x1b8812(0x53f)]&&(_0x162eb3[_0x1b8812(0x1f4)][_0x162eb3[_0x1b8812(0x37c)]]['stats'][_0x1b8812(0x53f)][_0x1b8812(0x1b6)]=!![]))):(_0x162eb3[_0x1b8812(0x37c)]=![],errorlog(_0x1b8812(0x2ea))),updateUserList();else{function _0xc02cac(){var _0x435b33=_0x1b8812;_0x2cca08[_0x435b33(0x1f4)][_0x547888][_0x435b33(0x14f)]['info']['muted']=_0x411416[_0x435b33(0x1f4)][_0x3624a8][_0x435b33(0x37b)];}}}else{if(_0xcf8f5b[_0x1b8812(0x4e0)]==_0x1b8812(0x4b1)){log(_0x1b8812(0x1f8)),log(_0xcf8f5b);try{_0x1b8812(0x1b6)in _0xcf8f5b&&(_0xcf8f5b[_0x1b8812(0x1b6)]==!![]&&_0x162eb3[_0x1b8812(0x20b)](_0xcf8f5b));}catch(_0x3cee1a){errorlog(_0x3cee1a);}}else{if(_0xcf8f5b[_0x1b8812(0x4e0)]==_0x1b8812(0x563)){if(_0x1b8812(0x541)===_0x1b8812(0x23f)){function _0x4d0526(){_0x14fbec['video']=!![];}}else{_0xcf8f5b[_0x1b8812(0x1b6)]&&(_0x162eb3[_0x1b8812(0x37c)]=_0xcf8f5b['UUID'],_0x162eb3[_0x1b8812(0x37c)]in _0x162eb3[_0x1b8812(0x147)]&&(_0x162eb3[_0x1b8812(0x147)][_0x162eb3[_0x1b8812(0x37c)]]['stats'][_0x1b8812(0x53f)]&&(_0x162eb3['pcs'][_0x162eb3[_0x1b8812(0x37c)]]['stats']['info'][_0x1b8812(0x1b6)]=!![])),_0x162eb3[_0x1b8812(0x37c)]in _0x162eb3['rpcs']&&(_0x162eb3[_0x1b8812(0x1f4)][_0x162eb3[_0x1b8812(0x37c)]][_0x1b8812(0x14f)][_0x1b8812(0x53f)]&&(_0x162eb3[_0x1b8812(0x1f4)][_0x162eb3[_0x1b8812(0x37c)]][_0x1b8812(0x14f)][_0x1b8812(0x53f)]['director']=!![])),updateUserList());if('streamID'in _0xcf8f5b){log(_0x1b8812(0x3f8));if(_0x162eb3['queue']){if(_0x162eb3[_0x1b8812(0x37c)]===_0xcf8f5b['UUID'])play(_0x5b36a1);else _0x162eb3[_0x1b8812(0x1c1)][_0x1b8812(0x3f4)]<0x1388&&(!_0x162eb3[_0x1b8812(0x1c1)][_0x1b8812(0x28f)](_0xcf8f5b[_0x1b8812(0x34f)])&&(_0x162eb3[_0x1b8812(0x1c1)][_0x1b8812(0x21d)](_0xcf8f5b[_0x1b8812(0x34f)]),_0x162eb3[_0x1b8812(0x309)]()));}else play(_0xcf8f5b[_0x1b8812(0x34f)]);}else log(_0x1b8812(0x2d2));}}else{if(_0xcf8f5b['request']==_0x1b8812(0x441)){log(_0x1b8812(0x100)),log(_0xcf8f5b);if(_0x162eb3[_0x1b8812(0x46f)]){if(_0x162eb3[_0x1b8812(0x37c)]===_0xcf8f5b[_0x1b8812(0x1e2)])play(_0x5b36a1);else _0x162eb3[_0x1b8812(0x1c1)][_0x1b8812(0x3f4)]<0x1388&&(!_0x162eb3[_0x1b8812(0x1c1)][_0x1b8812(0x28f)](_0xcf8f5b[_0x1b8812(0x34f)])&&(_0x162eb3['queueList'][_0x1b8812(0x21d)](_0xcf8f5b[_0x1b8812(0x34f)]),_0x162eb3[_0x1b8812(0x309)]()));}else play(_0xcf8f5b[_0x1b8812(0x34f)]);}else{if(_0xcf8f5b[_0x1b8812(0x4e0)]=='alert'){errorlog(_0xcf8f5b);if(_0x162eb3[_0x1b8812(0x145)]===![]){if(_0x1b8812(0x47c)in _0xcf8f5b){if(_0xcf8f5b[_0x1b8812(0x47c)]===_0x1b8812(0x2c7))_0x162eb3[_0x1b8812(0x32c)]<0x2?(_0x162eb3['seedAttempts']=parseInt(_0x162eb3[_0x1b8812(0x32c)])+0x1,setTimeout(function(){var _0x79649b=_0x1b8812;_0x162eb3[_0x79649b(0x216)]();},0x1388)):(hangup(),!_0x162eb3[_0x1b8812(0x14e)]&&setTimeout(function(){var _0x261ad7=_0x1b8812;warnUser(_0x261ad7(0x124));},0x1));else _0xcf8f5b[_0x1b8812(0x47c)]===_0x1b8812(0xfd)?!_0x162eb3['cleanOutput']&&(setTimeout(function(){var _0x4d7dad=_0x1b8812;if(_0x4d7dad(0x382)==='pxCrg'){function _0x570b60(){var _0x34c703=_0x4d7dad,_0x482afc={};_0x482afc[_0x34c703(0x186)]=_0x34c703(0xe1),_0x474ad8['sendMessage'](_0x482afc,_0x446099);}}else warnUser(_0x4d7dad(0x2bc));},0x1),getById(_0x1b8812(0x3a1))[_0x1b8812(0x564)]=_0x1b8812(0x499)):!_0x162eb3[_0x1b8812(0x14e)]&&setTimeout(function(){warnUser(_0xcf8f5b['message']);},0x1);}}}else{if(_0xcf8f5b[_0x1b8812(0x4e0)]==_0x1b8812(0x494)){if(_0x1b8812(0x3ab)!==_0x1b8812(0x3ab)){function _0x4f5a39(){var _0x5b875a=_0x1b8812;if(_0x3e0616[_0x5b875a(0x147)][_0x19752e][_0x5b875a(0x46d)]===![])return;_0x1e66c3=_0x191955['pcs'][_0x587053]['savedBitrate'];}}else _0x1b8812(0x47c)in _0xcf8f5b&&warnlog(_0xcf8f5b['message']);}else log(_0xcf8f5b);}}}}}}}}}else{if(_0xcf8f5b[_0x1b8812(0x16b)])_0x1b8812(0x34f)in _0xcf8f5b&&(_0xcf8f5b[_0x1b8812(0x34f)]in _0x162eb3[_0x1b8812(0x4f2)]&&(clearTimeout(_0x162eb3[_0x1b8812(0x4f2)][_0xcf8f5b[_0x1b8812(0x34f)]]),delete _0x162eb3[_0x1b8812(0x4f2)][_0xcf8f5b[_0x1b8812(0x34f)]])),_0x162eb3['processDescription'](_0xcf8f5b);else{if(_0xcf8f5b[_0x1b8812(0x17d)])log(_0x1b8812(0x38b)),_0x162eb3[_0x1b8812(0x3d9)](_0xcf8f5b);else{if(_0xcf8f5b[_0x1b8812(0x134)])log(_0x1b8812(0x56a)),_0x162eb3[_0x1b8812(0x142)](_0xcf8f5b);else{if(_0xcf8f5b[_0x1b8812(0x4e0)]==_0x1b8812(0x175)){warnlog(_0x1b8812(0x29c));if(_0xcf8f5b[_0x1b8812(0x1e2)]in _0x162eb3[_0x1b8812(0x147)]){if(_0x1b8812(0x304)!==_0x1b8812(0x361))warnlog('problem'),_0x162eb3[_0x1b8812(0x147)][_0xcf8f5b[_0x1b8812(0x1e2)]][_0x1b8812(0x556)](),delete _0x162eb3[_0x1b8812(0x147)][_0xcf8f5b[_0x1b8812(0x1e2)]],_0x162eb3['applySoloChat'](),applySceneState();else{function _0x242463(){var _0x24a542=_0x1b8812;_0x1e525c[_0x24a542(0x1b6)]=!![];}}}_0xcf8f5b[_0x1b8812(0x1e2)]in _0x162eb3[_0x1b8812(0x1f4)]&&(warnlog(_0x1b8812(0x459)),_0x162eb3[_0x1b8812(0x1f4)][_0xcf8f5b[_0x1b8812(0x1e2)]][_0x1b8812(0x556)](),delete _0x162eb3[_0x1b8812(0x1f4)][_0xcf8f5b[_0x1b8812(0x1e2)]]);}else log(_0x1b8812(0x525),_0xcf8f5b);}}}}},_0x162eb3['ws'][_0x417729(0x45c)]=function(_0x1ad044){var _0x70787=_0x417729;clearTimeout(_0x162eb3[_0x70787(0x371)]),pokeIframeAPI(_0x70787(0x526),'closed');try{if('code'in _0x1ad044){if(_0x1ad044[_0x70787(0x2fe)]==0x1f7){if(_0x38ec87==![]){clearInterval(_0x162eb3[_0x70787(0x351)]);if(!_0x162eb3['cleanOutput']){if('cmLSK'===_0x70787(0x241)){function _0x56ebdc(){var _0x51f6bc=_0x70787;_0x2ea79d(_0x51f6bc(0x560));}}else warnUser(_0x70787(0x17c),0x7530);}}}}}catch(_0x37f01f){errorlog(_0x37f01f);}errorlog(_0x70787(0x232));if(_0x162eb3[_0x70787(0x3d8)]==![]){if(_0x70787(0x34e)!==_0x70787(0x34e)){function _0x449c5b(){_0x311041+=0x20;}}else try{_0x162eb3['ws'][_0x70787(0x2bb)]===WebSocket[_0x70787(0x560)]&&(_0x162eb3['ws']=null,setTimeout(()=>{var _0x5d3132=_0x70787;_0x162eb3[_0x5d3132(0x47d)](!![]);},0x1388));}catch(_0x14da25){errorlog(_0x14da25);}}};},_0x162eb3['sendMessage']=function(_0x440eac,_0x376385=null){var _0x438b97=_0x44a3fc;_0x440eac=JSON[_0x438b97(0x444)](_0x440eac);if(_0x376385==null){for(var _0x4e23fe in _0x162eb3[_0x438b97(0x147)]){try{_0x162eb3['pcs'][_0x4e23fe][_0x438b97(0x4ae)]['send'](_0x440eac);}catch(_0x219ae1){warnlog(_0x438b97(0x3ce));}}return!![];}else try{return _0x162eb3[_0x438b97(0x147)][_0x376385][_0x438b97(0x4ae)][_0x438b97(0x388)](_0x440eac),!![];}catch(_0x51a2fa){return warnlog(_0x438b97(0x307)),![];}return![];},_0x162eb3[_0x44a3fc(0x196)]=function(_0xb9f792,_0x2cd391=null){var _0x5c3513=_0x44a3fc,_0x135fa0=JSON[_0x5c3513(0x444)](_0xb9f792);if(_0x2cd391==null)for(var _0x270f7d in _0x162eb3[_0x5c3513(0x1f4)]){try{_0x162eb3[_0x5c3513(0x1f4)][_0x270f7d][_0x5c3513(0x228)][_0x5c3513(0x388)](_0x135fa0);}catch(_0x2bdfc7){log(_0x5c3513(0xde));}}else try{return _0x162eb3['rpcs'][_0x2cd391][_0x5c3513(0x228)]['send'](_0x135fa0),!![];}catch(_0x507392){return log('PUBLISHER\x27s\x20RTC\x20Connection\x20seems\x20to\x20be\x20dead?\x20'),![];}},_0x162eb3[_0x44a3fc(0x1e9)]=function(){setTimeout(function(){var _0x299153=_0x447b;_0x162eb3[_0x299153(0x1e9)];},0xbb8);},_0x162eb3[_0x44a3fc(0x584)]=function(_0x21d452){var _0x26ba28=_0x44a3fc;try{var _0x460789=_0x162eb3[_0x26ba28(0x3d0)][_0x26ba28(0x2fc)]();_0x460789=_0x460789[0x0];if(_0x460789[_0x26ba28(0x519)]){var _0x1bfe5c=_0x460789['getCapabilities']();_0x162eb3[_0x26ba28(0x50e)]==![]&&(_0x162eb3[_0x26ba28(0x50e)]=_0x1bfe5c[_0x26ba28(0x50e)][_0x26ba28(0xd5)]);_0x162eb3[_0x26ba28(0x50e)]+=_0x21d452;if(_0x162eb3[_0x26ba28(0x50e)]>_0x1bfe5c[_0x26ba28(0x50e)]['max'])_0x162eb3['zoom']=_0x1bfe5c[_0x26ba28(0x50e)][_0x26ba28(0x418)];else _0x162eb3[_0x26ba28(0x50e)]<_0x1bfe5c[_0x26ba28(0x50e)][_0x26ba28(0xd5)]&&(_0x162eb3[_0x26ba28(0x50e)]=_0x1bfe5c[_0x26ba28(0x50e)][_0x26ba28(0xd5)]);_0x460789[_0x26ba28(0x290)]({'advanced':[{'zoom':_0x162eb3[_0x26ba28(0x50e)]}]});}}catch(_0xb4f0d7){if('kpZPP'!==_0x26ba28(0x3d1)){function _0x2259cc(){var _0x370dd1=_0x26ba28;_0x13d8c2[_0x370dd1(0x1f4)][_0x5bc059]['videoElement'][_0x370dd1(0x253)]=![];}}else errorlog(_0xb4f0d7);}},_0x162eb3[_0x44a3fc(0x498)]=function(){var _0x313c49=_0x44a3fc;_0x162eb3['taintedSession']=!![],warnlog(_0x313c49(0x259));try{var _0x1b931e={};_0x1b931e['videoMuted']=!![],_0x162eb3[_0x313c49(0x43f)](_0x1b931e);}catch(_0x3a9133){}try{if('gvUXx'===_0x313c49(0x455)){function _0x19f42a(){var _0x148939=_0x313c49;_0x1d89b0[_0x148939(0x179)](_0x19df99[_0x148939(0x1e2)]);}}else _0x162eb3['ws'][_0x313c49(0x556)]();}catch(_0x532480){}try{recordLocalVideo(_0x313c49(0x529));}catch(_0x2f023b){}try{if('zrzES'===_0x313c49(0x3a3)){function _0x55ad38(){var _0x37052b=_0x313c49;_0x2eeda9[_0x37052b(0x196)](_0x2616c2,_0x41064c);}}else{_0x162eb3[_0x313c49(0x310)]&&_0x162eb3['canvasSource'][_0x313c49(0x288)]['getTracks']()[_0x313c49(0x204)](function(_0x251ebf){var _0x90778=_0x313c49;_0x251ebf[_0x90778(0x529)](),_0x162eb3[_0x90778(0x340)][_0x90778(0x288)][_0x90778(0x4dc)](_0x251ebf),log(_0x90778(0x248));});_0x162eb3[_0x313c49(0x340)][_0x313c49(0x288)][_0x313c49(0x472)]()[_0x313c49(0x204)](function(_0x1c85dd){var _0x2873d7=_0x313c49;_0x1c85dd[_0x2873d7(0x529)](),_0x162eb3[_0x2873d7(0x340)][_0x2873d7(0x288)][_0x2873d7(0x4dc)](_0x1c85dd),log(_0x2873d7(0x248));}),_0x162eb3['streamSrc']['getTracks']()[_0x313c49(0x204)](function(_0x35d4b8){var _0x36559f=_0x313c49;_0x35d4b8[_0x36559f(0x529)](),_0x162eb3['videoElement'][_0x36559f(0x288)][_0x36559f(0x4dc)](_0x35d4b8),log('stopping\x20old\x20track');});for(i in _0x162eb3[_0x313c49(0x1f4)]){_0x162eb3[_0x313c49(0x1f4)][i][_0x313c49(0x340)]&&(_0x162eb3[_0x313c49(0x1f4)][i]['videoElement'][_0x313c49(0x38a)]&&(_0x162eb3[_0x313c49(0x1f4)][i][_0x313c49(0x340)]['recorder']['writer']['close'](),_0x162eb3['rpcs'][i][_0x313c49(0x340)][_0x313c49(0x38a)]=![])),_0x162eb3[_0x313c49(0x1f4)][i][_0x313c49(0x556)](),_0x162eb3[_0x313c49(0x1f4)][i]=null,delete _0x162eb3[_0x313c49(0x1f4)][i];}for(i in _0x162eb3[_0x313c49(0x147)]){_0x162eb3['pcs'][i][_0x313c49(0x556)](),_0x162eb3[_0x313c49(0x147)][i]=null,delete _0x162eb3[_0x313c49(0x147)][i],applySceneState();}}}catch(_0xc55495){errorlog('failed\x20to\x20disconnect');}setTimeout(function(){var _0x56b6d7=_0x313c49;if(_0x56b6d7(0x413)===_0x56b6d7(0x490)){function _0x49df5a(){var _0x43995b=_0x56b6d7;_0x554a46(_0x43995b(0x23b),0x1388);}}else{for(i in _0x162eb3){try{delete _0x162eb3[i];}catch(_0x31cbc3){}}delete _0x162eb3;}},0x4b0),hangupComplete(),log(_0x313c49(0x315));},_0x162eb3['hangupDirector']=function(){var _0x20310e=_0x44a3fc;_0x162eb3[_0x20310e(0x46b)]=!![],_0x162eb3[_0x20310e(0x460)]=![],warnlog(_0x20310e(0x259));try{_0x162eb3[_0x20310e(0x340)]['srcObject'][_0x20310e(0x472)]()[_0x20310e(0x204)](function(_0xe9a340){var _0x2a6a09=_0x20310e;_0xe9a340[_0x2a6a09(0x529)](),_0x162eb3[_0x2a6a09(0x340)][_0x2a6a09(0x288)][_0x2a6a09(0x4dc)](_0xe9a340),log('stopping\x20old\x20track');}),_0x162eb3['streamSrc']['getTracks']()[_0x20310e(0x204)](function(_0x32fe2c){var _0x3e43bf=_0x20310e;_0x32fe2c[_0x3e43bf(0x529)](),_0x162eb3['streamSrc'][_0x3e43bf(0x4dc)](_0x32fe2c),log(_0x3e43bf(0x248));});for(UUID in _0x162eb3[_0x20310e(0x147)]){var _0x4c1be1=_0x162eb3['pcs'][UUID][_0x20310e(0x442)]();_0x4c1be1['forEach'](_0x59db96=>{var _0x420cea=_0x20310e;_0x59db96[_0x420cea(0x2ac)]&&(_0x59db96[_0x420cea(0x2ac)][_0x420cea(0x2f1)]=![]);});}var _0x5c4c19={};_0x5c4c19[_0x20310e(0x1ae)]=!![],_0x162eb3[_0x20310e(0x43f)](_0x5c4c19);}catch(_0x2611fc){errorlog(_0x20310e(0x301));}log(_0x20310e(0x202));},_0x162eb3[_0x44a3fc(0x257)]=function(_0x3f6d50){var _0x449823=_0x44a3fc;try{var _0x55449d=_0x162eb3['streamSrc'][_0x449823(0x2fc)]();_0x55449d=_0x55449d[0x0];if(_0x55449d[_0x449823(0x519)]){var _0x3ccecf=_0x55449d['getCapabilities']();_0x162eb3[_0x449823(0x558)]==![]&&(_0x162eb3['focusDistance']=_0x3ccecf[_0x449823(0x558)][_0x449823(0xd5)]);_0x162eb3['focusDistance']+=_0x3f6d50;if(_0x162eb3[_0x449823(0x558)]>_0x3ccecf[_0x449823(0x558)][_0x449823(0x418)])_0x162eb3[_0x449823(0x558)]=_0x3ccecf[_0x449823(0x558)][_0x449823(0x418)];else _0x162eb3[_0x449823(0x558)]<_0x3ccecf[_0x449823(0x558)]['min']&&(_0x162eb3[_0x449823(0x558)]=_0x3ccecf['focusDistance'][_0x449823(0xd5)]);_0x55449d[_0x449823(0x290)]({'advanced':[{'focusMode':_0x449823(0x2df),'focusDistance':_0x162eb3[_0x449823(0x558)]}]});}}catch(_0x9e079f){errorlog(_0x9e079f);}},_0x162eb3[_0x44a3fc(0x417)]=function(_0xddb402){var _0x1b6520=_0x44a3fc;_0x162eb3[_0x1b6520(0x147)][_0xddb402][_0x1b6520(0x417)]()['then'](_0x51acd5=>{var _0x10ec20=_0x1b6520;log('create\x20offer\x20worked');if(safariVersion()<=0xd&&(iOS||iPad)){}else{if(_0x162eb3[_0x10ec20(0x133)]==0x3||_0x162eb3[_0x10ec20(0x133)]==0x5||_0x162eb3[_0x10ec20(0x133)]==0x1)_0x51acd5[_0x10ec20(0x457)]=CodecsHandler[_0x10ec20(0x195)](_0x51acd5['sdp'],{'stereo':0x1}),log(_0x10ec20(0x306));else{if(iOS||iPad){}else _0x162eb3[_0x10ec20(0x133)]==0x4&&(_0x51acd5[_0x10ec20(0x457)]=CodecsHandler[_0x10ec20(0x195)](_0x51acd5[_0x10ec20(0x457)],{'stereo':0x2}),log(_0x10ec20(0x306)));}}_0x162eb3[_0x10ec20(0x147)][_0xddb402][_0x10ec20(0x21f)](_0x51acd5)[_0x10ec20(0x57e)](function(){var _0x4be3ef=_0x10ec20;log(_0x4be3ef(0x17e)+_0xddb402);var _0x2f1f3d={};_0x2f1f3d[_0x4be3ef(0x1e2)]=_0xddb402,_0x2f1f3d['streamID']=_0x162eb3[_0x4be3ef(0x34f)],_0x2f1f3d[_0x4be3ef(0x16b)]=_0x162eb3[_0x4be3ef(0x147)][_0xddb402][_0x4be3ef(0x156)],_0x2f1f3d[_0x4be3ef(0x157)]=_0x162eb3[_0x4be3ef(0x147)][_0xddb402][_0x4be3ef(0x157)],_0x162eb3[_0x4be3ef(0xf2)]?_0x162eb3[_0x4be3ef(0x52d)](JSON[_0x4be3ef(0x444)](_0x2f1f3d[_0x4be3ef(0x16b)]))[_0x4be3ef(0x57e)](function(_0x3d4245){var _0x362d74=_0x4be3ef;_0x2f1f3d[_0x362d74(0x16b)]=_0x3d4245[0x0],_0x2f1f3d['vector']=_0x3d4245[0x1],_0x162eb3[_0x362d74(0x3cd)](_0x2f1f3d);}):_0x162eb3[_0x4be3ef(0x3cd)](_0x2f1f3d);})[_0x10ec20(0x19f)](errorlog);})[_0x1b6520(0x19f)](errorlog);},_0x162eb3[_0x44a3fc(0x54d)]=function(){var _0x1a39f7=_0x44a3fc;for(var _0x5b9a32 in _0x162eb3[_0x1a39f7(0x147)]){_0x162eb3['pcs'][_0x5b9a32][_0x1a39f7(0x145)]!==![]?(_0x162eb3[_0x1a39f7(0x116)](_0x5b9a32),log(_0x1a39f7(0x3e3))):log(_0x1a39f7(0x10a));}},_0x162eb3[_0x44a3fc(0x179)]=function(_0x55308e){var _0x1953f6=_0x44a3fc;if(_0x1953f6(0x41b)===_0x1953f6(0x3bb)){function _0x15a3f3(){var _0x33faec=_0x1953f6;_0x516223=_0x4784d0[_0x33faec(0x218)](_0x11b7e3,_0x4b5700);}}else{if(_0x55308e in _0x162eb3['pcs']){errorlog(_0x1953f6(0x2e0));try{_0x162eb3[_0x1953f6(0x147)][_0x55308e]['close']();}catch(_0x102355){errorlog(_0x1953f6(0x450));}_0x162eb3[_0x1953f6(0x147)][_0x55308e]=null,delete _0x162eb3['pcs'][_0x55308e],_0x162eb3[_0x1953f6(0x421)](),applySceneState();}else log(_0x1953f6(0x2f5));if(_0x162eb3[_0x1953f6(0x190)]!==![]){if(Object[_0x1953f6(0x4bb)](_0x162eb3['pcs'])['length']>_0x162eb3[_0x1953f6(0x190)]){delete _0x162eb3['pcs'][_0x55308e],_0x162eb3['applySoloChat'](),warnlog('Viewer\x20will\x20be\x20ignored\x20due\x20to\x20max\x20connections\x20already\x20hit'),applySceneState();return;}}else{if(_0x162eb3[_0x1953f6(0x153)]!==![]){if(Object[_0x1953f6(0x4bb)](_0x162eb3[_0x1953f6(0x1f4)])[_0x1953f6(0x3f4)]+Object[_0x1953f6(0x4bb)](_0x162eb3[_0x1953f6(0x147)])['length']>_0x162eb3['maxconnections']){delete _0x162eb3[_0x1953f6(0x147)][_0x55308e],_0x162eb3['applySoloChat'](),warnlog('Publisher\x20will\x20be\x20ignored\x20due\x20to\x20max\x20connections\x20already\x20hit'),applySceneState();return;}}}_0x162eb3[_0x1953f6(0x147)][_0x55308e]=new RTCPeerConnection(_0x162eb3[_0x1953f6(0x52b)]);if(_0x162eb3[_0x1953f6(0x3d8)]){if(Object[_0x1953f6(0x4bb)](_0x162eb3[_0x1953f6(0x147)])[_0x1953f6(0x3f4)]>0x1){delete _0x162eb3[_0x1953f6(0x147)][_0x55308e],_0x162eb3[_0x1953f6(0x421)](),applySceneState();return;}}_0x162eb3['pcs'][_0x55308e][_0x1953f6(0x199)]=null,_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x342)]=null,_0x162eb3[_0x1953f6(0x147)][_0x55308e]['obsVisibility']=null,_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x208)]=null,_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x223)]=null,_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x1b0)]=null,_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x40d)]=![],_0x162eb3[_0x1953f6(0x147)][_0x55308e]['savedBitrate']=![],_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x49f)]=null,_0x162eb3['pcs'][_0x55308e][_0x1953f6(0x2a1)]=![],_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x157)]=_0x162eb3[_0x1953f6(0x2af)](),_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x14f)]={},_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x466)]=![],_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x33a)]=![],_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x506)]=![],_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x26c)]=![],_0x162eb3['pcs'][_0x55308e][_0x1953f6(0x520)]=!![],_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x521)]=!![],_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x117)]=!![],_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x1d1)]=![],_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x383)]=![],_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x1e2)]=_0x55308e,_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x3ea)]=![],_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x4db)]=![],_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x295)]=![],_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x571)]=![],_0x162eb3['pcs'][_0x55308e][_0x1953f6(0x4ab)]=![],_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x145)]=![],_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x4ae)]=_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x447)](_0x1953f6(0x4ae)),_0x162eb3[_0x1953f6(0x147)][_0x55308e]['sendChannel'][_0x1953f6(0x1e2)]=_0x55308e,_0x162eb3[_0x1953f6(0x147)][_0x55308e]['keyframerate']=![],_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x524)]=null,_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x2fa)]=![],_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x2c5)]=![],_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x13c)]=Date[_0x1953f6(0x1b9)](),_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x4ae)][_0x1953f6(0x3ef)]=()=>{var _0x510b17=_0x1953f6;log('send\x20channel\x20open\x20pcs'),msg={},msg[_0x510b17(0x53f)]={},msg[_0x510b17(0x53f)][_0x510b17(0x2fa)]=_0x162eb3[_0x510b17(0x2fa)],msg[_0x510b17(0x53f)]['order']=_0x162eb3[_0x510b17(0x2c5)],msg[_0x510b17(0x53f)][_0x510b17(0x253)]=_0x162eb3[_0x510b17(0x253)];_0x162eb3[_0x510b17(0x504)]&&_0x162eb3[_0x510b17(0x504)]!==_0x55308e&&(msg['info']['muted']=!![]);msg[_0x510b17(0x53f)][_0x510b17(0x477)]=_0x162eb3[_0x510b17(0x477)],msg[_0x510b17(0x53f)]['directorDisplayMuted']=_0x162eb3[_0x510b17(0x30a)],msg['info'][_0x510b17(0x491)]=_0x162eb3['directorVideoMuted'],msg['info'][_0x510b17(0x39e)]=_0x162eb3[_0x510b17(0x1ae)];_0x162eb3[_0x510b17(0x1b6)]&&(msg[_0x510b17(0x4de)]={},msg[_0x510b17(0x4de)][_0x510b17(0x262)]=_0x162eb3[_0x510b17(0x262)]);msg[_0x510b17(0x53f)][_0x510b17(0xed)]=_0x162eb3[_0x510b17(0x4d1)],msg[_0x510b17(0x53f)][_0x510b17(0x35f)]=_0x162eb3[_0x510b17(0x261)],msg[_0x510b17(0x53f)][_0x510b17(0x192)]=_0x162eb3[_0x510b17(0x33c)],msg['info'][_0x510b17(0x3a0)]=_0x162eb3['maxvideobitrate'],msg[_0x510b17(0x53f)]['maxviewers_url']=_0x162eb3[_0x510b17(0x190)],msg[_0x510b17(0x53f)][_0x510b17(0x4c5)]=_0x162eb3[_0x510b17(0x133)],msg[_0x510b17(0x53f)]['aec_url']=_0x162eb3['echoCancellation'],msg['info'][_0x510b17(0x416)]=_0x162eb3[_0x510b17(0xe5)],msg[_0x510b17(0x53f)]['denoise_url']=_0x162eb3['noiseSuppression'],msg['info'][_0x510b17(0x158)]=_0x162eb3['version'],msg[_0x510b17(0x53f)][_0x510b17(0x1da)]=_0x162eb3[_0x510b17(0xe8)],msg[_0x510b17(0x53f)][_0x510b17(0x56e)]=_0x162eb3['compressor'],msg[_0x510b17(0x53f)]['recording_audio_ctx_latency']=_0x162eb3[_0x510b17(0xfe)],msg[_0x510b17(0x53f)]['recording_audio_pipeline']=!_0x162eb3['disableWebAudio'],msg[_0x510b17(0x53f)][_0x510b17(0x113)]=_0x162eb3[_0x510b17(0x344)],msg[_0x510b17(0x53f)][_0x510b17(0x492)]=_0x162eb3[_0x510b17(0x321)],msg[_0x510b17(0x53f)]['playback_audio_volume_meter']=_0x162eb3[_0x510b17(0x55e)];try{if(navigator[_0x510b17(0x3f1)]){var _0x4ed2bc,_0x4df75c=navigator[_0x510b17(0x3f1)];msg[_0x510b17(0x53f)][_0x510b17(0x28a)]=_0x4df75c;}navigator[_0x510b17(0x209)]&&(msg[_0x510b17(0x53f)]['platform']=navigator[_0x510b17(0x209)]);if(safariVersion())msg['info'][_0x510b17(0x25d)]=_0x510b17(0x185);else{if(getChromeVersion()>0x3c)msg[_0x510b17(0x53f)][_0x510b17(0x25d)]=_0x510b17(0x34d)+getChromeVersion();else _0x4df75c[_0x510b17(0x549)](_0x510b17(0x115))&&(msg['info'][_0x510b17(0x25d)]=_0x510b17(0x115));}}catch(_0x4c3f51){};_0x162eb3[_0x510b17(0x43f)](msg,_0x55308e),pokeIframeAPI(_0x510b17(0x4ec),!![],_0x55308e),updateUserList();},_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x4ae)]['onclose']=()=>{var _0x483a61=_0x1953f6;pokeIframeAPI(_0x483a61(0x4ec),![],_0x55308e),_0x162eb3[_0x483a61(0x264)](),warnlog(_0x483a61(0x40f));try{_0x162eb3[_0x483a61(0x147)][_0x55308e][_0x483a61(0x556)](),_0x162eb3['pcs'][_0x55308e]=null,delete _0x162eb3[_0x483a61(0x147)][_0x55308e],applySceneState();}catch(_0x35f5ea){}},_0x162eb3['pcs'][_0x55308e][_0x1953f6(0x4ae)][_0x1953f6(0x1f2)]=_0x3fc91c=>{var _0x44b3a4=_0x1953f6;log(_0x44b3a4(0x551));var _0x252667=JSON[_0x44b3a4(0x4aa)](_0x3fc91c[_0x44b3a4(0x2cd)]);_0x252667[_0x44b3a4(0x1e2)]=_0x55308e;if(_0x252667[_0x44b3a4(0x16b)]){_0x162eb3[_0x44b3a4(0x3e9)](_0x252667);return;}else{if(_0x252667[_0x44b3a4(0x17d)]){log(_0x44b3a4(0x38b)),_0x162eb3['processIce'](_0x252667);return;}else{if(_0x252667[_0x44b3a4(0x134)]){log(_0x44b3a4(0x481)),_0x162eb3[_0x44b3a4(0x142)](_0x252667);return;}}}warnlog(_0x252667);if(_0x44b3a4(0x53f)in _0x252667){_0x162eb3[_0x44b3a4(0x147)][_0x55308e][_0x44b3a4(0x14f)][_0x44b3a4(0x53f)]=_0x252667['info'];_0x44b3a4(0x2fa)in _0x252667[_0x44b3a4(0x53f)]&&(typeof _0x252667[_0x44b3a4(0x53f)][_0x44b3a4(0x2fa)]==_0x44b3a4(0x173)?_0x162eb3[_0x44b3a4(0x147)][_0x55308e]['label']=sanitizeLabel(_0x252667[_0x44b3a4(0x53f)]['label']):_0x162eb3[_0x44b3a4(0x147)][_0x55308e][_0x44b3a4(0x2fa)]=![]);if(_0x55308e===_0x162eb3[_0x44b3a4(0x37c)])try{_0x162eb3[_0x44b3a4(0x147)][_0x55308e][_0x44b3a4(0x14f)][_0x44b3a4(0x53f)][_0x44b3a4(0x1b6)]=!![];}catch(_0x46fe73){}}_0x44b3a4(0x40d)in _0x252667&&(_0x162eb3['pcs'][_0x55308e][_0x44b3a4(0x40d)]=parseInt(_0x252667[_0x44b3a4(0x40d)]));_0x44b3a4(0x352)in _0x252667&&_0x162eb3[_0x44b3a4(0x2d3)](_0x55308e,_0x252667[_0x44b3a4(0x352)]);if('requestStats'in _0x252667){log(_0x252667);if(_0x162eb3[_0x44b3a4(0x37c)]===_0x55308e){var _0x262389={};for(var _0x530908 in _0x162eb3[_0x44b3a4(0x147)]){if(_0x44b3a4(0x10c)===_0x44b3a4(0x10c)){if(_0x530908===_0x55308e)continue;_0x262389[_0x530908]=_0x162eb3[_0x44b3a4(0x147)][_0x530908][_0x44b3a4(0x14f)];}else{function _0xa60376(){var _0x494bd8=_0x44b3a4;_0x5c1dd9=_0x29182e[_0x494bd8(0x340)]['srcObject'];}}}var _0x3ff848={};_0x3ff848[_0x44b3a4(0x294)]=_0x262389,_0x162eb3[_0x44b3a4(0x43f)](_0x3ff848,_0x55308e);}else{if(_0x44b3a4(0x4cf)in _0x252667){if(_0x252667[_0x44b3a4(0x4cf)]===_0x162eb3[_0x44b3a4(0x4cf)]&&_0x162eb3[_0x44b3a4(0x4cf)]){var _0x262389={};for(var _0x530908 in _0x162eb3[_0x44b3a4(0x147)]){if(_0x530908===_0x55308e)continue;_0x262389[_0x530908]=_0x162eb3[_0x44b3a4(0x147)][_0x530908]['stats'];}var _0x3ff848={};_0x3ff848[_0x44b3a4(0x294)]=_0x262389,_0x162eb3[_0x44b3a4(0x43f)](_0x3ff848,_0x55308e);}}}}if('requestResolution'in _0x252667)try{log(_0x252667),_0x162eb3['setResolution'](_0x252667[_0x44b3a4(0x1e2)],_0x252667[_0x44b3a4(0x322)]['w'],_0x252667[_0x44b3a4(0x322)]['h']);}catch(_0x3a62d4){errorlog(_0x3a62d4);}if(_0x44b3a4(0x14b)in _0x252667){if(_0x252667['scene']){if(_0x162eb3[_0x44b3a4(0x37c)]===_0x55308e)_0x162eb3[_0x44b3a4(0x54d)]();else{if('zQaSU'!==_0x44b3a4(0x511))errorlog(_0x44b3a4(0xe0));else{function _0x49848a(){var _0x3bc86b=_0x44b3a4;_0x56e7e7[_0x3bc86b(0x17d)]=_0x2a07e0['parse'](_0x542cc6),_0x1c9aa3['processIce2'](_0x67736);}}}}else _0x162eb3[_0x44b3a4(0x116)](_0x55308e);}if('chat'in _0x252667){var _0x334bc7=![],_0x4b0a09=![];if(_0x162eb3[_0x44b3a4(0x37c)]===_0x55308e){_0x334bc7=!![];if(_0x44b3a4(0x187)in _0x252667){if(_0x252667[_0x44b3a4(0x187)]==!![]){if(_0x44b3a4(0x445)===_0x44b3a4(0x445))_0x4b0a09=!![];else{function _0x404aeb(){var _0x3bdb3d=_0x44b3a4;_0x1808f3[_0x3bdb3d(0x39d)](_0x212d4f);}}}}}log(_0x44b3a4(0x1ba)+_0x334bc7),getChatMessage(_0x252667[_0x44b3a4(0x4c4)],_0x162eb3['pcs'][_0x55308e][_0x44b3a4(0x2fa)],_0x334bc7,_0x4b0a09);}if(_0x44b3a4(0x2c5)in _0x252667){_0x162eb3[_0x44b3a4(0x147)][_0x55308e][_0x44b3a4(0x2c5)]=parseInt(_0x252667['order'])||0x0;_0x55308e in _0x162eb3['rpcs']&&(_0x162eb3[_0x44b3a4(0x1f4)][_0x55308e][_0x44b3a4(0x2c5)]=_0x162eb3[_0x44b3a4(0x147)][_0x55308e][_0x44b3a4(0x2c5)]);if(_0x162eb3[_0x44b3a4(0x1b6)]){var _0x11d474=document['querySelectorAll'](_0x44b3a4(0x330)+_0x55308e+'\x22]');log(_0x11d474),_0x11d474[0x0]&&(_0x11d474[0x0][_0x44b3a4(0x27f)]=parseInt(_0x252667[_0x44b3a4(0x2c5)])||0x0);}updateMixer();}if(_0x44b3a4(0x3ea)in _0x252667){if(_0x44b3a4(0x3ca)===_0x44b3a4(0x3ca))_0x162eb3[_0x44b3a4(0x198)](_0x55308e,_0x252667[_0x44b3a4(0x3ea)]);else{function _0x5f58d9(){_0x15e19b['encodings'][0x0]['active']=![];}}}_0x44b3a4(0x186)in _0x252667&&(_0x162eb3[_0x44b3a4(0x1b6)]&&(!(_0x162eb3[_0x44b3a4(0x14e)]||_0x162eb3[_0x44b3a4(0x425)])&&warnUser(_0x44b3a4(0x23b),0x1388)),errorlog(_0x44b3a4(0x24f)+_0x252667[_0x44b3a4(0x186)]+',\x20isDirector:\x20'+_0x162eb3[_0x44b3a4(0x1b6)]));if(_0x55308e!==_0x162eb3['directorUUID']){if(_0x44b3a4(0x159)!==_0x44b3a4(0x159)){function _0x1d3680(){var _0x739ff6=_0x44b3a4;_0x24f044[_0x739ff6(0x1f4)][_0x3dbf7e]['order']=0x0;}}else{if('requestAudioHack'in _0x252667){var _0x3ff848={};_0x3ff848[_0x44b3a4(0x186)]=_0x44b3a4(0x221),_0x162eb3['sendMessage'](_0x3ff848,_0x55308e);}else{if(_0x44b3a4(0x43e)in _0x252667){var _0x3ff848={};_0x3ff848[_0x44b3a4(0x186)]=_0x44b3a4(0x43e),_0x162eb3[_0x44b3a4(0x43f)](_0x3ff848,_0x55308e);}else{if(_0x44b3a4(0x172)in _0x252667){var _0x3ff848={};_0x3ff848['rejected']=_0x44b3a4(0x172),_0x162eb3['sendMessage'](_0x3ff848,_0x55308e);}else{if(_0x44b3a4(0x58c)in _0x252667){var _0x3ff848={};_0x3ff848[_0x44b3a4(0x186)]=_0x44b3a4(0x58c),_0x162eb3['sendMessage'](_0x3ff848,_0x55308e);}else{if(_0x44b3a4(0x42f)in _0x252667){var _0x3ff848={};_0x3ff848[_0x44b3a4(0x186)]='changeLabel',_0x162eb3[_0x44b3a4(0x43f)](_0x3ff848,_0x55308e);}else{if(_0x44b3a4(0x2ca)in _0x252667){var _0x3ff848={};_0x3ff848[_0x44b3a4(0x186)]=_0x44b3a4(0x2ca),_0x162eb3[_0x44b3a4(0x43f)](_0x3ff848,_0x55308e);}else{if(_0x44b3a4(0xe1)in _0x252667){var _0x3ff848={};_0x3ff848[_0x44b3a4(0x186)]=_0x44b3a4(0xe1),_0x162eb3[_0x44b3a4(0x43f)](_0x3ff848,_0x55308e);}else{if(_0x44b3a4(0x498)in _0x252667){var _0x3ff848={};_0x3ff848[_0x44b3a4(0x186)]=_0x44b3a4(0x498),_0x162eb3['sendMessage'](_0x3ff848,_0x55308e);}else{if(_0x44b3a4(0x1bc)in _0x252667){var _0x3ff848={};_0x3ff848['rejected']=_0x44b3a4(0x1bc),_0x162eb3[_0x44b3a4(0x43f)](_0x3ff848,_0x55308e);}else{if('speakerMute'in _0x252667){var _0x3ff848={};_0x3ff848[_0x44b3a4(0x186)]=_0x44b3a4(0x420),_0x162eb3[_0x44b3a4(0x43f)](_0x3ff848,_0x55308e);}else{if('volume'in _0x252667){var _0x3ff848={};_0x3ff848[_0x44b3a4(0x186)]=_0x44b3a4(0x280),_0x162eb3[_0x44b3a4(0x43f)](_0x3ff848,_0x55308e);}}}}}}}}}}}}}else{if(_0x55308e===_0x162eb3[_0x44b3a4(0x37c)]){if('requestAudioHack'in _0x252667){var _0x386b56=_0x162eb3[_0x44b3a4(0x3d0)][_0x44b3a4(0x28e)]();if(_0x386b56['length']){if(_0x44b3a4(0x2ac)in _0x252667){if(_0x44b3a4(0x52f)===_0x44b3a4(0x1cd)){function _0xccea3d(){_0x42496a(_0x5a7cb4);}}else{var _0x1af131=parseInt(_0x252667[_0x44b3a4(0x2ac)]);_0x1af131<_0x386b56[_0x44b3a4(0x3f4)]&&(_0x386b56=_0x386b56[_0x1af131],applyAudioHack(_0x252667[_0x44b3a4(0x57d)],_0x252667[_0x44b3a4(0x276)]));}}else _0x386b56=_0x386b56[0x0],applyAudioHack(_0x252667[_0x44b3a4(0x57d)],_0x252667[_0x44b3a4(0x276)]);}}if('requestVideoRecord'in _0x252667){if(_0x252667[_0x44b3a4(0x43e)]){if(_0x162eb3[_0x44b3a4(0x340)]){var _0x3043cc=0x1770;if(_0x252667['value']){if(_0x44b3a4(0x118)!==_0x44b3a4(0x2c0))_0x3043cc=parseInt(_0x252667[_0x44b3a4(0x276)]);else{function _0x1c910c(){var _0x254185=_0x44b3a4;_0x42fc4f[_0x254185(0x1f4)][_0x4208b3]['remoteMuteElement']['style'][_0x254185(0x1fb)]=_0x254185(0x545);}}}recordLocalVideo(_0x44b3a4(0x132),_0x3043cc);}}else _0x162eb3[_0x44b3a4(0x340)]&&recordLocalVideo('stop');}if('changeOrder'in _0x252667){_0x162eb3['order']==![]&&(_0x162eb3['order']=0x0);_0x162eb3[_0x44b3a4(0x2c5)]+=parseInt(_0x252667[_0x44b3a4(0x172)])||0x0;var _0x3ff848={};_0x3ff848={},_0x3ff848['order']=_0x162eb3[_0x44b3a4(0x2c5)],_0x162eb3[_0x44b3a4(0x358)](_0x3ff848),updateMixer();}if(_0x44b3a4(0x58c)in _0x252667){window[_0x44b3a4(0x3f6)]();var _0x3dc25f=confirm(_0x44b3a4(0x562)+_0x252667[_0x44b3a4(0x58c)]+_0x44b3a4(0x410));_0x3dc25f&&(window[_0x44b3a4(0x36e)][_0x44b3a4(0x4f3)]=_0x252667[_0x44b3a4(0x58c)]);;}if(_0x44b3a4(0x42f)in _0x252667){if(_0x44b3a4(0x276)in _0x252667){if(typeof _0x252667[_0x44b3a4(0x276)]==_0x44b3a4(0x173)){_0x162eb3[_0x44b3a4(0x2fa)]=sanitizeLabel(_0x252667[_0x44b3a4(0x276)]),log(_0x44b3a4(0x1a2)+_0x162eb3[_0x44b3a4(0x2fa)]);if(_0x162eb3['director']){var _0x11d474=getById(_0x44b3a4(0x427)+_0x55308e);_0x162eb3[_0x44b3a4(0x2fa)]?_0x11d474[_0x44b3a4(0x27f)]=_0x162eb3[_0x44b3a4(0x2fa)]:_0x11d474[_0x44b3a4(0x27f)]='Add\x20a\x20label';}else _0x162eb3[_0x44b3a4(0x478)]&&updateMixer();if(!_0x162eb3[_0x44b3a4(0x1b6)]){if(_0x44b3a4(0x105)!==_0x44b3a4(0x249))_0x162eb3[_0x44b3a4(0x2fa)]?document[_0x44b3a4(0xcf)]=_0x162eb3[_0x44b3a4(0x2fa)]:document['title']=location['hostname'];else{function _0xee61e3(){var _0x4b64ab=_0x44b3a4;_0x392018[_0x4b64ab(0x145)]=_0x2b369f[_0x4b64ab(0x145)];}}}var _0x4308a5=encodeURIComponent(_0x162eb3[_0x44b3a4(0x2fa)]);urlParams[_0x44b3a4(0x3f0)]('l')?updateURL('l='+_0x4308a5,!![],![]):updateURL('label='+_0x4308a5,!![],![]);var _0x3ff848={};_0x3ff848[_0x44b3a4(0x42f)]=!![],_0x3ff848[_0x44b3a4(0x276)]=_0x162eb3['label'],_0x162eb3[_0x44b3a4(0x43f)](_0x3ff848);}else{_0x162eb3[_0x44b3a4(0x2fa)]=![];var _0x3ff848={};_0x3ff848[_0x44b3a4(0x42f)]=!![],_0x3ff848[_0x44b3a4(0x276)]=_0x162eb3[_0x44b3a4(0x2fa)],_0x162eb3['sendMessage'](_0x3ff848);if(_0x162eb3[_0x44b3a4(0x1b6)]){var _0x11d474=getById(_0x44b3a4(0x427)+_0x55308e);_0x11d474[_0x44b3a4(0x27f)]=_0x44b3a4(0x394);}else{if(_0x162eb3[_0x44b3a4(0x478)])document[_0x44b3a4(0xcf)]=location[_0x44b3a4(0xf8)],updateMixer();else{if(_0x44b3a4(0x27e)===_0x44b3a4(0x211)){function _0x28e2d5(){var _0x1dff38=_0x44b3a4;_0xadbc11['crypto'][_0x1dff38(0x426)][_0x1dff38(0x1f5)]('jwk',{'kty':'RSA','e':_0x1dff38(0x141),'n':_0x343998,'alg':_0x1dff38(0x354),'ext':!![]},{'name':_0x1dff38(0x2cc),'hash':{'name':_0x1dff38(0x283)}},!![],[_0x1dff38(0xe6)])['then'](function(_0x396d76){var _0x4f758c=_0x1dff38;_0x1c6fa7[_0x4f758c(0x4bb)][_0x220110]={},_0x5eff78[_0x4f758c(0x4bb)][_0x30a927][_0x4f758c(0x52a)]=_0x396d76,_0x1a18b4[_0x4f758c(0x4bb)][_0xcc984a]['privateKey']=null;})[_0x1dff38(0x19f)](_0x504446);}}else document['title']=location[_0x44b3a4(0xf8)];}}}}}if(_0x44b3a4(0x2ca)in _0x252667){if(_0x252667[_0x44b3a4(0x57d)]==_0x44b3a4(0x16f))changeLowEQ(parseFloat(_0x252667[_0x44b3a4(0x276)]),_0x252667[_0x44b3a4(0x2ac)]);else{if(_0x252667[_0x44b3a4(0x57d)]==_0x44b3a4(0x48e))changeMidEQ(parseFloat(_0x252667[_0x44b3a4(0x276)]),_0x252667[_0x44b3a4(0x2ac)]);else _0x252667[_0x44b3a4(0x57d)]==_0x44b3a4(0x325)&&changeHighEQ(parseFloat(_0x252667['value']),_0x252667[_0x44b3a4(0x2ac)]);}}if(_0x44b3a4(0xe1)in _0x252667){if('MjxwA'===_0x44b3a4(0x282))_0x162eb3[_0x44b3a4(0x109)]&&lowerhand();else{function _0x22daae(){var _0x1303e1=_0x44b3a4;delete _0x5b7fab[_0x1303e1(0x1f4)][_0xba0138],_0x2d65bd(),_0x98f19b(_0x1303e1(0x3e1));return;}}}if(_0x44b3a4(0x231)in _0x252667){var _0x3ff848={};_0x3ff848[_0x44b3a4(0x1e2)]=_0x55308e,_0x3ff848[_0x44b3a4(0xec)]=listAudioSettingsPrep(),sendMediaDevices(_0x3ff848[_0x44b3a4(0x1e2)]),_0x162eb3[_0x44b3a4(0x43f)](_0x3ff848,_0x3ff848['UUID']);}if(_0x44b3a4(0x448)in _0x252667){if(_0x44b3a4(0x28b)===_0x44b3a4(0x28b)){var _0x3ff848={};_0x3ff848[_0x44b3a4(0x1e2)]=_0x55308e,_0x3ff848[_0x44b3a4(0x35a)]=listVideoSettingsPrep(),sendMediaDevices(_0x3ff848[_0x44b3a4(0x1e2)]),_0x162eb3['sendMessage'](_0x3ff848,_0x3ff848[_0x44b3a4(0x1e2)]);}else{function _0x4a638f(){return;}}}'changeSpeaker'in _0x252667&&changeAudioOutputDeviceById(_0x252667[_0x44b3a4(0x4cb)],_0x55308e);_0x44b3a4(0x50d)in _0x252667&&changeAudioDeviceById(_0x252667[_0x44b3a4(0x50d)],_0x55308e);_0x44b3a4(0x1be)in _0x252667&&changeVideoDeviceById(_0x252667[_0x44b3a4(0x1be)],_0x55308e);_0x44b3a4(0x191)in _0x252667&&updateCameraConstraints(_0x252667['keyname'],_0x252667[_0x44b3a4(0x276)]);_0x44b3a4(0x22f)in _0x252667&&changeLowCut(parseFloat(_0x252667[_0x44b3a4(0x276)]),_0x252667['track']);_0x44b3a4(0x22f)in _0x252667&&changeLowCut(parseFloat(_0x252667['value']),_0x252667[_0x44b3a4(0x2ac)]);if(_0x44b3a4(0x498)in _0x252667){if(_0x44b3a4(0x3dd)===_0x44b3a4(0x3dd))_0x162eb3[_0x44b3a4(0x498)]();else{function _0x41d82d(){var _0x475e89=_0x44b3a4;_0x356604[_0x475e89(0x147)][_0x12f7d7][_0x475e89(0x26c)]=!![];}}}if(_0x44b3a4(0x2c6)in _0x252667){}if(_0x44b3a4(0x280)in _0x252667){var _0x37e456=parseInt(_0x252667['volume'])/0x64||0x0;_0x162eb3[_0x44b3a4(0xe8)]=parseInt(_0x252667[_0x44b3a4(0x280)])||0x0;for(var _0x75492f in _0x162eb3[_0x44b3a4(0x4a1)]){log(_0x44b3a4(0xd2)),_0x162eb3[_0x44b3a4(0x4a1)][_0x75492f][_0x44b3a4(0x375)]['gain'][_0x44b3a4(0x174)](_0x37e456,_0x162eb3['webAudios'][_0x75492f][_0x44b3a4(0x389)][_0x44b3a4(0x405)]);}}if(_0x44b3a4(0xee)in _0x252667){if(_0x44b3a4(0x136)===_0x44b3a4(0x1eb)){function _0x128898(){_0x1e9d37(_0x164f9d['limitAudioEncoder'],0x3e8,_0x380b7a,0x7d00,0x0);}}else{var _0x2c8ea8=parseFloat(_0x252667[_0x44b3a4(0xee)]/0x3e8)||0x0;_0x162eb3[_0x44b3a4(0x39c)]=parseInt(_0x252667[_0x44b3a4(0xee)])||0x0;for(var _0x75492f in _0x162eb3[_0x44b3a4(0x4a1)]){_0x162eb3[_0x44b3a4(0x4a1)][_0x75492f][_0x44b3a4(0x39c)][_0x44b3a4(0x15e)][_0x44b3a4(0x174)](_0x2c8ea8,_0x162eb3[_0x44b3a4(0x4a1)][_0x75492f][_0x44b3a4(0x389)][_0x44b3a4(0x405)]);}}}_0x44b3a4(0x420)in _0x252667&&(_0x252667[_0x44b3a4(0x420)]?(_0x162eb3['directorSpeakerMuted']=!![],_0x162eb3[_0x44b3a4(0x4ba)]()):(_0x162eb3['directorSpeakerMuted']=![],_0x162eb3[_0x44b3a4(0x4ba)]()));if(_0x44b3a4(0x1bc)in _0x252667){if(_0x44b3a4(0x266)===_0x44b3a4(0x266))_0x252667[_0x44b3a4(0x1bc)]?(_0x162eb3[_0x44b3a4(0x30a)]=!![],_0x162eb3['directorDisplayMute']()):(_0x162eb3['directorDisplayMuted']=![],_0x162eb3['directorDisplayMute']());else{function _0x16a7f4(){var _0x408452=_0x44b3a4;_0x1d24de(_0x408452(0x10e));var _0x65d684={};_0x65d684[_0x408452(0x1e2)]=_0x4a3b27[_0x408452(0x1e2)],_0x65d684[_0x408452(0x16b)]=_0x34ff42[_0x408452(0x1f4)][_0x44b6c3['UUID']][_0x408452(0x156)],_0x65d684['session']=_0x38b9db[_0x408452(0x1f4)][_0x926230[_0x408452(0x1e2)]]['session'],_0x2a94fd[_0x408452(0xf2)]?_0xfee6de[_0x408452(0x52d)](_0x430fd5[_0x408452(0x444)](_0x65d684[_0x408452(0x16b)]))[_0x408452(0x57e)](function(_0x49a60b){var _0x4d4f2a=_0x408452;_0x65d684['description']=_0x49a60b[0x0],_0x65d684[_0x4d4f2a(0x3f5)]=_0x49a60b[0x1],_0x289700[_0x4d4f2a(0x577)](_0x65d684);}):_0x39665a[_0x408452(0x577)](_0x65d684);}}}_0x44b3a4(0x4b6)in _0x252667&&applyNewParams(_0x252667[_0x44b3a4(0x4b6)]);}}if(_0x44b3a4(0x50e)in _0x252667){if(_0x44b3a4(0x589)===_0x44b3a4(0x589)){if(_0x162eb3[_0x44b3a4(0x4cf)]){if(_0x44b3a4(0x4cf)in _0x252667)_0x252667[_0x44b3a4(0x4cf)]===_0x162eb3[_0x44b3a4(0x4cf)]&&_0x162eb3['remote']&&_0x162eb3[_0x44b3a4(0x584)](parseFloat(_0x252667['zoom']));else{if(_0x55308e===_0x162eb3['directorUUID'])_0x162eb3[_0x44b3a4(0x584)](parseFloat(_0x252667[_0x44b3a4(0x50e)]));else return;}}}else{function _0x38d9a6(){var _0x8f2d27=_0x44b3a4;_0x749a32(_0x8f2d27(0x22e)+this[_0x8f2d27(0x1e2)])[_0x8f2d27(0x23c)][_0x8f2d27(0x45f)](_0x56c285(_0x8f2d27(0x22e)+this[_0x8f2d27(0x1e2)]));}}}if(_0x44b3a4(0x3f6)in _0x252667){if(_0x162eb3[_0x44b3a4(0x4cf)]){if(_0x44b3a4(0x4cf)in _0x252667)_0x252667[_0x44b3a4(0x4cf)]===_0x162eb3['remote']&&_0x162eb3[_0x44b3a4(0x4cf)]&&_0x162eb3[_0x44b3a4(0x257)](parseFloat(_0x252667[_0x44b3a4(0x3f6)]));else{if(_0x55308e===_0x162eb3[_0x44b3a4(0x37c)])_0x162eb3['remoteFocus'](parseFloat(_0x252667[_0x44b3a4(0x3f6)]));else return;}}}manageSceneState(_0x252667,_0x55308e);'bitrate'in _0x252667&&_0x162eb3[_0x44b3a4(0x451)](_0x55308e,_0x252667[_0x44b3a4(0x22c)]);if(_0x44b3a4(0x25f)in _0x252667&&_0x44b3a4(0x3cb)in _0x252667){log(_0x44b3a4(0x17b));_0x252667['audio']==![]&&(_0x162eb3[_0x44b3a4(0x147)][_0x55308e][_0x44b3a4(0x521)]=![]);_0x252667[_0x44b3a4(0x3cb)]==![]&&(_0x162eb3[_0x44b3a4(0x147)][_0x55308e][_0x44b3a4(0x520)]=![]);'broadcast'in _0x252667&&_0x252667[_0x44b3a4(0x140)]==!![]&&(_0x162eb3['pcs'][_0x55308e][_0x44b3a4(0x383)]=!![],setTimeout(function(){makeImages();},0x3e8));if(_0x44b3a4(0x3b9)in _0x252667&&_0x252667[_0x44b3a4(0x3b9)]==![]){if(_0x44b3a4(0x362)===_0x44b3a4(0x55f)){function _0x3d8c37(){_0x2674bf(_0x4563e6);}}else _0x162eb3[_0x44b3a4(0x147)][_0x55308e][_0x44b3a4(0x117)]=![];}_0x44b3a4(0x39f)in _0x252667&&_0x252667[_0x44b3a4(0x1a5)]!==![]&&(_0x162eb3[_0x44b3a4(0x147)][_0x55308e][_0x44b3a4(0x1d1)]=_0x252667[_0x44b3a4(0x39f)]);if(_0x44b3a4(0x466)in _0x252667){if(_0x252667[_0x44b3a4(0x466)]==!![]){if(_0x44b3a4(0x24d)!==_0x44b3a4(0x488))_0x162eb3[_0x44b3a4(0x147)][_0x55308e]['guest']=!![];else{function _0xcbd1ef(){_0x2eb555['video']=![];}}}}'forceios'in _0x252667&&(_0x252667[_0x44b3a4(0x26c)]===!![]&&(_0x162eb3[_0x44b3a4(0x147)][_0x55308e][_0x44b3a4(0x26c)]=!![]));if('director'in _0x252667){if(_0x252667[_0x44b3a4(0x1b6)]==!![]){if(_0x44b3a4(0x4f9)===_0x44b3a4(0x561)){function _0x8bfcb4(){var _0x160d78=_0x44b3a4;_0x341470[_0x160d78(0x1fa)][_0x160d78(0x335)]();}}else(iOS||iPad)&&(_0x162eb3[_0x44b3a4(0x147)][_0x55308e][_0x44b3a4(0x26c)]==!![]&&(_0x162eb3[_0x44b3a4(0x147)][_0x55308e][_0x44b3a4(0x466)]=!![]));}}_0x44b3a4(0x300)in _0x252667&&(_0x252667[_0x44b3a4(0x300)]==!![]&&(_0x162eb3[_0x44b3a4(0x147)][_0x55308e]['limitAudio']=!![]));_0x44b3a4(0x160)in _0x252667&&(_0x252667[_0x44b3a4(0x160)]==!![]&&(_0x162eb3['pcs'][_0x55308e][_0x44b3a4(0x506)]=!![]));_0x44b3a4(0x139)in _0x252667&&(_0x162eb3['pcs'][_0x55308e][_0x44b3a4(0x139)]=_0x252667[_0x44b3a4(0x139)],_0x162eb3['pcs'][_0x55308e]['keyframerate']&&setTimeout(function(){var _0x4e972a=_0x44b3a4;_0x162eb3[_0x4e972a(0x116)](_0x55308e);},0x1388));if(_0x44b3a4(0x145)in _0x252667){if(_0x252667[_0x44b3a4(0x145)]!==![]){try{if(typeof _0x252667[_0x44b3a4(0x145)]===_0x44b3a4(0x173))_0x162eb3[_0x44b3a4(0x147)][_0x55308e][_0x44b3a4(0x145)]=_0x252667['scene'][_0x44b3a4(0x50f)](/[\W]+/g,'_');else{if(_0x44b3a4(0x2ba)===_0x44b3a4(0x2ba))_0x162eb3[_0x44b3a4(0x147)][_0x55308e][_0x44b3a4(0x145)]=(parseInt(_0x252667[_0x44b3a4(0x145)])||0x0)+'';else{function _0x32cde9(){var _0x2f0fff=_0x44b3a4;_0x3e890c[_0x2f0fff(0x17d)]=_0xcbc957['candidates'][_0x122645],_0x474dfc[_0x2f0fff(0x39d)](_0x38c1ee);}}}_0x162eb3[_0x44b3a4(0x147)][_0x55308e]['stats'][_0x44b3a4(0x145)]=_0x162eb3[_0x44b3a4(0x147)][_0x55308e][_0x44b3a4(0x145)],updateSceneList(_0x162eb3[_0x44b3a4(0x147)][_0x55308e][_0x44b3a4(0x145)]);}catch(_0x57aeaa){errorlog(_0x57aeaa);}_0x162eb3[_0x44b3a4(0x1b6)]==!![]&&_0x162eb3[_0x44b3a4(0x462)]==![]&&(_0x162eb3['pcs'][_0x55308e]['allowAudio']=![],_0x162eb3[_0x44b3a4(0x147)][_0x55308e]['allowVideo']=![],_0x162eb3[_0x44b3a4(0x147)][_0x55308e]['allowIframe']=![]);}}if(_0x162eb3[_0x44b3a4(0x1b6)]==!![]){if(_0x162eb3[_0x44b3a4(0x147)][_0x55308e][_0x44b3a4(0x145)])var _0x50f767=getDirectorSettings(_0x162eb3['pcs'][_0x55308e][_0x44b3a4(0x145)]);else var _0x50f767=getDirectorSettings(![]);var _0x3ff848={};_0x3ff848[_0x44b3a4(0x4de)]=_0x50f767,_0x162eb3[_0x44b3a4(0x43f)](_0x3ff848,_0x55308e);}_0x162eb3[_0x44b3a4(0x269)](_0x55308e);}},_0x162eb3[_0x1953f6(0x269)]=function(_0x9b4a61){var _0x33474e=_0x1953f6;if(_0x9b4a61 in _0x162eb3[_0x33474e(0x147)]){}else{errorlog(_0x33474e(0x1fd));return;}if(_0x162eb3[_0x33474e(0x147)][_0x9b4a61][_0x33474e(0x117)]===!![]){if(_0x162eb3[_0x33474e(0x40c)]){var _0x31bb47={};_0x31bb47[_0x33474e(0x40c)]=_0x162eb3[_0x33474e(0x40c)],_0x162eb3[_0x33474e(0x43f)](_0x31bb47,_0x9b4a61);}}log(_0x33474e(0x56f)),log(_0x162eb3['streamSrc']);var _0x4165df=null;if(_0x162eb3[_0x33474e(0x340)][_0x33474e(0x288)])_0x4165df=_0x162eb3[_0x33474e(0x340)][_0x33474e(0x288)];else{if(_0x162eb3[_0x33474e(0x3d0)]&&_0x162eb3['streamSrc'][_0x33474e(0x472)]())errorlog(_0x33474e(0x4f8)),log(_0x162eb3[_0x33474e(0x3d0)][_0x33474e(0x472)]()),_0x4165df=_0x162eb3[_0x33474e(0x3d0)];else{warnlog(_0x33474e(0x184));return;}}_0x4165df[_0x33474e(0x472)]()['forEach'](_0x1e207f=>{var _0x43bd0a=_0x33474e;_0x162eb3['pcs'][_0x9b4a61][_0x43bd0a(0x521)]==!![]&&(_0x1e207f[_0x43bd0a(0x2c3)]==_0x43bd0a(0x25f)&&_0x162eb3['pcs'][_0x9b4a61][_0x43bd0a(0x496)](_0x1e207f,_0x4165df));if(_0x162eb3[_0x43bd0a(0x147)][_0x9b4a61][_0x43bd0a(0x520)]==!![]){if(_0x1e207f[_0x43bd0a(0x2c3)]==_0x43bd0a(0x3cb)){if(_0x43bd0a(0x2d9)!==_0x43bd0a(0x2d9)){function _0x40f910(){var _0x29b807=_0x43bd0a;_0x459032['rpcs'][_0x4e2d12]=null,delete _0x2895af[_0x29b807(0x1f4)][_0x1a58b8];}}else _0x162eb3[_0x43bd0a(0x147)][_0x9b4a61][_0x43bd0a(0x466)]==!![]&&_0x162eb3[_0x43bd0a(0x4c0)]===0x0?log(_0x43bd0a(0x33d)):(_0x162eb3[_0x43bd0a(0x147)][_0x9b4a61][_0x43bd0a(0x496)](_0x1e207f,_0x4165df),setTimeout(function(_0x55b0d7){var _0x1a8e76=_0x43bd0a;_0x162eb3[_0x1a8e76(0xd4)](_0x55b0d7);},_0x162eb3[_0x43bd0a(0x1d8)],_0x9b4a61));}}}),log(_0x33474e(0x436)),_0x4165df[_0x33474e(0x28e)]()['length']&&(_0x162eb3[_0x33474e(0x421)](),log('starting\x20kicker'),_0x162eb3[_0x33474e(0x147)][_0x9b4a61]['limitAudio']===!![]&&setTimeout(_0x162eb3[_0x33474e(0x546)],0x3e8,_0x9b4a61,0x7d00,0x0),_0x162eb3[_0x33474e(0x147)][_0x9b4a61][_0x33474e(0x506)]===!![]&&setTimeout(_0x162eb3[_0x33474e(0x4d2)],0x3e8,_0x9b4a61));},_0x162eb3[_0x1953f6(0x147)][_0x55308e]['onnegotiationneeded']=function(_0x2a5870){var _0x3ffe31=_0x1953f6;if(_0x3ffe31(0x203)===_0x3ffe31(0x203))_0x162eb3[_0x3ffe31(0x417)](_0x55308e);else{function _0x599c73(){var _0x5bc3f5=_0x3ffe31;_0xc0db9(_0x5bc3f5(0x3e5));}}},_0x162eb3['pcs'][_0x55308e][_0x1953f6(0x25a)]=_0x4529e2=>{var _0x1d9d2b=_0x1953f6;errorlog(_0x1d9d2b(0x393));},_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x3b3)]=null,_0x162eb3['pcs'][_0x55308e]['iceBundle']=[],_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x4d4)]=function(_0x338b2d){var _0xcc1a8b=_0x1953f6;if(_0xcc1a8b(0x25b)===_0xcc1a8b(0x25b)){if(_0x338b2d[_0xcc1a8b(0x17d)]==null){log(_0xcc1a8b(0x469));return;}try{if(_0x162eb3[_0xcc1a8b(0x2c8)]){if(_0x338b2d[_0xcc1a8b(0x17d)][_0xcc1a8b(0x17d)][_0xcc1a8b(0x549)](_0x162eb3[_0xcc1a8b(0x2c8)])===-0x1){log(_0xcc1a8b(0x52c));return;}else log(_0x338b2d['candidate']);}}catch(_0x8d2a2c){errorlog(_0x8d2a2c);}if(_0x162eb3[_0xcc1a8b(0x147)][_0x55308e][_0xcc1a8b(0x3b3)]!==null){_0x162eb3[_0xcc1a8b(0x147)][_0x55308e][_0xcc1a8b(0x373)][_0xcc1a8b(0x21d)](_0x338b2d['candidate']);return;}_0x162eb3[_0xcc1a8b(0x147)][_0x55308e][_0xcc1a8b(0x373)][_0xcc1a8b(0x21d)](_0x338b2d[_0xcc1a8b(0x17d)]),_0x162eb3[_0xcc1a8b(0x147)][_0x55308e][_0xcc1a8b(0x3b3)]=setTimeout(function(_0x456b3b){var _0x36113f=_0xcc1a8b;_0x162eb3[_0x36113f(0x147)][_0x456b3b][_0x36113f(0x3b3)]=null;var _0x5182a7={};_0x5182a7[_0x36113f(0x1e2)]=_0x456b3b,_0x5182a7[_0x36113f(0x3de)]=_0x36113f(0x1a7),_0x5182a7[_0x36113f(0x134)]=_0x162eb3[_0x36113f(0x147)][_0x456b3b][_0x36113f(0x373)],_0x5182a7['session']=_0x162eb3[_0x36113f(0x147)][_0x456b3b][_0x36113f(0x157)],_0x162eb3['pcs'][_0x456b3b][_0x36113f(0x373)]=[],_0x162eb3[_0x36113f(0xf2)]?_0x162eb3[_0x36113f(0x52d)](JSON[_0x36113f(0x444)](_0x5182a7[_0x36113f(0x134)]))[_0x36113f(0x57e)](function(_0x28605b){var _0x284138=_0x36113f;if(_0x284138(0x21a)!==_0x284138(0x21a)){function _0x14b393(){_0x4e1f0e=_0x2d28a3;}}else _0x5182a7[_0x284138(0x134)]=_0x28605b[0x0],_0x5182a7[_0x284138(0x3f5)]=_0x28605b[0x1],_0x162eb3[_0x284138(0x3cd)](_0x5182a7);}):_0x162eb3[_0x36113f(0x3cd)](_0x5182a7);},0xc8,_0x55308e);}else{function _0x57c7e8(){var _0x1ce460=_0xcc1a8b;_0x495d01[_0x1ce460(0x53f)][_0x1ce460(0x25d)]=_0x1ce460(0x185);}}},_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x11e)]=function(_0x1f5392){var _0x3b7328=_0x1953f6;try{if(_0x3b7328(0x27d)!==_0x3b7328(0x27d)){function _0x3e563b(){var _0x3c7034=_0x3b7328;_0x94c21f[_0x3c7034(0x116)](_0x5eff18);}}else{if(this['iceConnectionState']==_0x3b7328(0x2f7)){if(_0x3b7328(0x3fd)===_0x3b7328(0x50a)){function _0x498cb2(){var _0x32871e=_0x3b7328;_0x2419bb[_0x32871e(0x3eb)]=_0x2be78f[_0x32871e(0x253)],_0x59baa8[_0x32871e(0x253)]=![],_0x6a74cb={},_0x11aa1c[_0x32871e(0x286)]=_0x16ce4f[_0x32871e(0x253)],_0x20823d['sendMessage'](_0x44aeab,_0x1d111e['soloChatUUID']);}}else log(_0x3b7328(0x2e5));}else{if(this['iceConnectionState']=='disconnected')log(_0x3b7328(0x53c));else{if(this[_0x3b7328(0x3b2)]=='failed')log(_0x3b7328(0x298));else this[_0x3b7328(0x3b2)]==_0x3b7328(0x4e6)?(log(_0x3b7328(0x206)),_0x162eb3[_0x3b7328(0x147)][_0x55308e]['getSenders']()[_0x3b7328(0x204)](_0x1eccec=>{var _0x2a5398=_0x3b7328;if(!_0x1eccec['track'])return;if(_0x1eccec[_0x2a5398(0x2ac)]['kind']===_0x2a5398(0x3cb)){_0x162eb3[_0x2a5398(0x147)][_0x55308e]['videoCodecs']=_0x1eccec[_0x2a5398(0x1cb)]()[_0x2a5398(0x548)],log(_0x162eb3['pcs'][_0x55308e][_0x2a5398(0x2a2)]);return;}else{if(_0x1eccec[_0x2a5398(0x2ac)]['kind']===_0x2a5398(0x25f)){_0x162eb3['pcs'][_0x55308e][_0x2a5398(0x582)]=_0x1eccec[_0x2a5398(0x1cb)]()[_0x2a5398(0x548)],log(_0x162eb3[_0x2a5398(0x147)][_0x55308e]['audioCodecs']);return;}}})):log(this['iceConnectionState']);}}}}catch(_0x5a5188){errorlog(_0x5a5188);}},_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x550)]=function(_0x5d2e1c){var _0x28cef1=_0x1953f6;switch(_0x162eb3[_0x28cef1(0x147)][_0x55308e][_0x28cef1(0x268)]){case'connected':log(_0x28cef1(0x379));if(_0x162eb3[_0x28cef1(0x3d8)]){if(_0x162eb3['ws']['readyState']!==0x1){_0x162eb3['ws'][_0x28cef1(0x556)]();break;}_0x162eb3['ws'][_0x28cef1(0x556)](),setTimeout(function(){var _0x2bdda6=_0x28cef1;_0x162eb3[_0x2bdda6(0x14e)]!=!![]&&warnUser('Remote\x20peer\x20connected\x20to\x20video\x20stream.\x0a\x0aConnection\x20to\x20handshake\x20server\x20being\x20killed\x20on\x20request.\x20This\x20increases\x20security,\x20but\x20the\x20peer\x20will\x20not\x20be\x20able\x20to\x20reconnect\x20automatically\x20on\x20connection\x20failure.\x0a\x0aPress\x20OK\x20to\x20start\x20the\x20stream!');},0x1);}break;case _0x28cef1(0x263):log(_0x28cef1(0x3b6));break;case _0x28cef1(0x162):warnlog(_0x28cef1(0x36b)),_0x162eb3['pcs'][_0x55308e][_0x28cef1(0x556)](),_0x162eb3[_0x28cef1(0x147)][_0x55308e]=null;_0x162eb3[_0x28cef1(0x3d8)]&&(!_0x162eb3[_0x28cef1(0x14e)]&&setTimeout(function(){var _0x23bf4f=_0x28cef1;warnUser(_0x23bf4f(0x423));},0x1));delete _0x162eb3[_0x28cef1(0x147)][_0x55308e],_0x162eb3[_0x28cef1(0x421)](),applySceneState();break;case _0x28cef1(0x2f7):warnlog(_0x28cef1(0x2c1)),_0x162eb3['pcs'][_0x55308e]=null;if(_0x162eb3[_0x28cef1(0x3d8)]){if(_0x28cef1(0x502)===_0x28cef1(0x3e0)){function _0x54c416(){var _0x54565e=_0x28cef1;_0x31e6c8(_0x54565e(0x529));}}else!_0x162eb3[_0x28cef1(0x14e)]&&setTimeout(function _0x5d05ff(){var _0x43b246=_0x28cef1;warnUser(_0x43b246(0x423));},0x1);}delete _0x162eb3[_0x28cef1(0x147)][_0x55308e],_0x162eb3[_0x28cef1(0x421)](),applySceneState();break;}},_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x45c)]=function(_0x336b1a){var _0x141b12=_0x1953f6;warnlog(_0x141b12(0x2a0)),_0x162eb3[_0x141b12(0x147)][_0x55308e]=null,delete _0x162eb3[_0x141b12(0x147)][_0x55308e],_0x162eb3['applySoloChat'](),applySceneState();},_0x162eb3[_0x1953f6(0x147)][_0x55308e][_0x1953f6(0x3ef)]=function _0x2f6f39(){var _0x39d2f1=_0x1953f6;log(_0x39d2f1(0x565));};}},_0x162eb3[_0x44a3fc(0x3e9)]=function(_0x262daa){var _0x101628=_0x44a3fc;if(_0x162eb3[_0x101628(0xf2)])_0x101628(0x3f5)in _0x262daa&&_0x162eb3[_0x101628(0x537)](_0x262daa[_0x101628(0x16b)],_0x262daa[_0x101628(0x3f5)])[_0x101628(0x57e)](function(_0x377477){var _0x52d91e=_0x101628;_0x262daa[_0x52d91e(0x16b)]=JSON[_0x52d91e(0x4aa)](_0x377477);if(_0x262daa[_0x52d91e(0x16b)]['type']==_0x52d91e(0x587))_0x162eb3[_0x52d91e(0x169)](_0x262daa),_0x162eb3['connectPeer'](_0x262daa);else try{var _0x12359e=_0x162eb3[_0x52d91e(0x1e5)];if((iOS||iPad)&&_0x162eb3['pcs'][_0x262daa['UUID']][_0x52d91e(0x466)]==!![]&&_0x162eb3[_0x52d91e(0x147)][_0x262daa[_0x52d91e(0x1e2)]][_0x52d91e(0x26c)]==![]){if(_0x12359e===![]||_0x12359e>_0x162eb3[_0x52d91e(0x200)]){var _0xb32814=Object[_0x52d91e(0x4bb)](_0x162eb3[_0x52d91e(0x147)])[_0x52d91e(0x3f4)];_0xb32814>0x3?_0x12359e=_0x162eb3[_0x52d91e(0x121)]:_0x12359e=_0x162eb3[_0x52d91e(0x200)];}_0x262daa[_0x52d91e(0x16b)][_0x52d91e(0x457)]=CodecsHandler[_0x52d91e(0x397)](_0x262daa[_0x52d91e(0x16b)][_0x52d91e(0x457)],_0x52d91e(0x287)),_0x262daa[_0x52d91e(0x16b)][_0x52d91e(0x457)]=CodecsHandler[_0x52d91e(0x38e)](_0x262daa[_0x52d91e(0x16b)][_0x52d91e(0x457)],{'min':parseInt(_0x12359e/0x2)||0x1,'max':_0x12359e}),_0x12359e=![];}else _0x162eb3[_0x52d91e(0x147)][_0x262daa[_0x52d91e(0x1e2)]][_0x52d91e(0x466)]==!![]&&(_0x12359e!==![]?_0x162eb3[_0x52d91e(0x4c0)]!==![]&&(_0x162eb3[_0x52d91e(0x4c0)]<_0x12359e&&(_0x12359e=_0x162eb3['roombitrate'])):_0x12359e=_0x162eb3[_0x52d91e(0x4c0)]);if(_0x12359e){var _0x22228d=CodecsHandler[_0x52d91e(0x3c2)](_0x262daa[_0x52d91e(0x16b)][_0x52d91e(0x457)])||0x9c4;log('BITRATE:\x20'+_0x22228d);if(_0x22228d>_0x12359e){var _0x3cd884=CodecsHandler['getOpusBitrate'](_0x262daa[_0x52d91e(0x16b)][_0x52d91e(0x457)])||0x0;_0x262daa[_0x52d91e(0x16b)][_0x52d91e(0x457)]=CodecsHandler[_0x52d91e(0x38e)](_0x262daa[_0x52d91e(0x16b)][_0x52d91e(0x457)],{'min':parseInt(_0x12359e/0xa)||0x1,'max':parseInt(_0x12359e+_0x3cd884/0x400)}),_0x162eb3[_0x52d91e(0x147)][_0x262daa[_0x52d91e(0x1e2)]]['setBitrate']=_0x12359e;}else _0x162eb3[_0x52d91e(0x147)][_0x262daa[_0x52d91e(0x1e2)]]['setBitrate']=_0x22228d;}else{if(_0x162eb3['outboundVideoBitrate']!==![]){var _0x22228d=CodecsHandler[_0x52d91e(0x3c2)](_0x262daa[_0x52d91e(0x16b)]['sdp']);if(_0x22228d===![]){var _0x3cd884=CodecsHandler[_0x52d91e(0x508)](_0x262daa[_0x52d91e(0x16b)][_0x52d91e(0x457)])||0x0;_0x262daa[_0x52d91e(0x16b)][_0x52d91e(0x457)]=CodecsHandler[_0x52d91e(0x38e)](_0x262daa[_0x52d91e(0x16b)][_0x52d91e(0x457)],{'min':parseInt(_0x162eb3[_0x52d91e(0x1ee)]/0xa)||0x1,'max':parseInt(_0x162eb3[_0x52d91e(0x1ee)]+_0x3cd884/0x400)});}else _0x162eb3[_0x52d91e(0x147)][_0x262daa[_0x52d91e(0x1e2)]][_0x52d91e(0x2a1)]=_0x22228d;}else _0x162eb3[_0x52d91e(0x147)][_0x262daa[_0x52d91e(0x1e2)]][_0x52d91e(0x2a1)]=CodecsHandler[_0x52d91e(0x3c2)](_0x262daa[_0x52d91e(0x16b)]['sdp']);}_0x162eb3[_0x52d91e(0xdf)]&&(_0x262daa[_0x52d91e(0x16b)][_0x52d91e(0x457)]=CodecsHandler[_0x52d91e(0x195)](_0x262daa[_0x52d91e(0x16b)][_0x52d91e(0x457)],{'maxaveragebitrate':_0x162eb3[_0x52d91e(0xdf)]*0x400,'cbr':_0x162eb3[_0x52d91e(0x44e)]}));if(_0x52d91e(0x157)in _0x262daa&&_0x262daa[_0x52d91e(0x157)]!=_0x162eb3[_0x52d91e(0x147)][_0x262daa[_0x52d91e(0x1e2)]][_0x52d91e(0x157)]){errorlog(_0x52d91e(0x485));return;}_0x162eb3['pcs'][_0x262daa[_0x52d91e(0x1e2)]][_0x52d91e(0x312)](_0x262daa[_0x52d91e(0x16b)])[_0x52d91e(0x57e)]()['catch'](errorlog);}catch(_0x27ef17){errorlog(_0x27ef17);}});else{if(_0x101628(0x27c)!=='ogWxJ'){if(_0x262daa[_0x101628(0x16b)]['type']=='offer')_0x162eb3[_0x101628(0x169)](_0x262daa),_0x162eb3[_0x101628(0x3e2)](_0x262daa);else try{var _0x313ea9=_0x162eb3[_0x101628(0x1e5)];if((iOS||iPad)&&_0x162eb3['pcs'][_0x262daa['UUID']][_0x101628(0x466)]==!![]&&_0x162eb3[_0x101628(0x147)][_0x262daa[_0x101628(0x1e2)]][_0x101628(0x26c)]==![]){if(_0x313ea9===![]||_0x313ea9>_0x162eb3[_0x101628(0x200)]){var _0x3e39fb=Object[_0x101628(0x4bb)](_0x162eb3[_0x101628(0x147)])['length'];_0x3e39fb>0x3?_0x313ea9=_0x162eb3['lowiosviewers']:_0x313ea9=_0x162eb3[_0x101628(0x200)];}_0x262daa[_0x101628(0x16b)]['sdp']=CodecsHandler[_0x101628(0x397)](_0x262daa[_0x101628(0x16b)]['sdp'],_0x101628(0x287)),_0x262daa[_0x101628(0x16b)][_0x101628(0x457)]=CodecsHandler[_0x101628(0x38e)](_0x262daa[_0x101628(0x16b)][_0x101628(0x457)],{'min':parseInt(_0x313ea9/0x2)||0x1,'max':_0x313ea9}),_0x313ea9=![];}else _0x162eb3['pcs'][_0x262daa[_0x101628(0x1e2)]][_0x101628(0x466)]==!![]&&(_0x313ea9!==![]?_0x162eb3[_0x101628(0x4c0)]!==![]&&(_0x162eb3[_0x101628(0x4c0)]<_0x313ea9&&(_0x313ea9=_0x162eb3['roombitrate'])):_0x313ea9=_0x162eb3[_0x101628(0x4c0)]);if(_0x313ea9){var _0x5ede7a=CodecsHandler['getVideoBitrates'](_0x262daa[_0x101628(0x16b)]['sdp'])||0x9c4;log(_0x101628(0x292)+_0x5ede7a);if(_0x5ede7a>_0x313ea9){var _0x56274f=CodecsHandler[_0x101628(0x508)](_0x262daa[_0x101628(0x16b)][_0x101628(0x457)])||0x0;_0x262daa[_0x101628(0x16b)][_0x101628(0x457)]=CodecsHandler[_0x101628(0x38e)](_0x262daa[_0x101628(0x16b)][_0x101628(0x457)],{'min':parseInt(_0x313ea9/0xa)||0x1,'max':parseInt(_0x313ea9+_0x56274f/0x400)});}}else{if(_0x162eb3[_0x101628(0x1ee)]!==![]){var _0x5ede7a=CodecsHandler[_0x101628(0x3c2)](_0x262daa[_0x101628(0x16b)][_0x101628(0x457)]);if(_0x5ede7a===![]){var _0x56274f=CodecsHandler[_0x101628(0x508)](_0x262daa[_0x101628(0x16b)][_0x101628(0x457)])||0x0;_0x262daa[_0x101628(0x16b)][_0x101628(0x457)]=CodecsHandler[_0x101628(0x38e)](_0x262daa[_0x101628(0x16b)][_0x101628(0x457)],{'min':parseInt(_0x162eb3[_0x101628(0x1ee)]/0xa)||0x1,'max':parseInt(_0x162eb3[_0x101628(0x1ee)]+_0x56274f/0x400)});}}}_0x162eb3['outboundAudioBitrate']&&(_0x262daa['description'][_0x101628(0x457)]=CodecsHandler[_0x101628(0x195)](_0x262daa[_0x101628(0x16b)]['sdp'],{'maxaveragebitrate':_0x162eb3[_0x101628(0xdf)]*0x400,'cbr':_0x162eb3[_0x101628(0x44e)]}));if(_0x101628(0x157)in _0x262daa&&_0x262daa[_0x101628(0x157)]!=_0x162eb3['pcs'][_0x262daa[_0x101628(0x1e2)]][_0x101628(0x157)]){errorlog(_0x101628(0x485));return;}_0x162eb3[_0x101628(0x147)][_0x262daa[_0x101628(0x1e2)]]['setRemoteDescription'](_0x262daa[_0x101628(0x16b)])[_0x101628(0x57e)]()[_0x101628(0x19f)](errorlog);}catch(_0xccc154){errorlog(_0xccc154);}}else{function _0x46d421(){var _0x1b4522=_0x101628;_0x8ef5f[_0x1b4522(0x1e2)]=_0x3f8e4d,_0x46a477(_0x1b4522(0x56a)),_0x2dd2b1['processIceBundle'](_0x287bda);}}}},_0x162eb3[_0x44a3fc(0x3d9)]=function(_0x1a087e){var _0x249697=_0x44a3fc;_0x162eb3[_0x249697(0xf2)]&&_0x249697(0x3f5)in _0x1a087e?_0x162eb3['decryptMessage'](_0x1a087e[_0x249697(0x17d)],_0x1a087e[_0x249697(0x3f5)])['then'](function(_0xbd1c19){var _0x465099=_0x249697;_0x1a087e[_0x465099(0x17d)]=JSON[_0x465099(0x4aa)](_0xbd1c19),_0x162eb3['processIce2'](_0x1a087e);}):_0x162eb3[_0x249697(0x39d)](_0x1a087e);},_0x162eb3[_0x44a3fc(0x39d)]=function(_0x2a1548){var _0x3467e8=_0x44a3fc;try{if(_0x162eb3[_0x3467e8(0x2c8)]){if(_0x2a1548[_0x3467e8(0x17d)][_0x3467e8(0x17d)][_0x3467e8(0x549)](_0x162eb3[_0x3467e8(0x2c8)])===-0x1){log(_0x3467e8(0x52c)),log(_0x2a1548[_0x3467e8(0x17d)]);return;}else log(_0x3467e8(0x320)),log(_0x2a1548[_0x3467e8(0x17d)]);}}catch(_0x557016){errorlog(_0x557016);}if(_0x2a1548[_0x3467e8(0x17d)]&&_0x3467e8(0x17d)in _0x2a1548[_0x3467e8(0x17d)]&&_0x2a1548[_0x3467e8(0x17d)]['candidate']=='')return;if(_0x2a1548['UUID']in _0x162eb3[_0x3467e8(0x147)]&&_0x2a1548[_0x3467e8(0x3de)]==_0x3467e8(0x4cf)){log(_0x3467e8(0x4eb));if(!(_0x2a1548[_0x3467e8(0x1e2)]in _0x162eb3['pcs'])){errorlog(_0x3467e8(0x41e));return;}if('session'in _0x2a1548&&_0x162eb3[_0x3467e8(0x147)][_0x2a1548[_0x3467e8(0x1e2)]][_0x3467e8(0x157)]!=_0x2a1548[_0x3467e8(0x157)]){errorlog(_0x3467e8(0xd7));return;}_0x162eb3['pcs'][_0x2a1548[_0x3467e8(0x1e2)]][_0x3467e8(0x364)](_0x2a1548[_0x3467e8(0x17d)])[_0x3467e8(0x57e)]()[_0x3467e8(0x19f)](function(_0x51d653){errorlog(_0x51d653),errorlog(_0x2a1548);});}else{if(_0x2a1548[_0x3467e8(0x1e2)]in _0x162eb3[_0x3467e8(0x1f4)]&&_0x2a1548[_0x3467e8(0x3de)]==_0x3467e8(0x1a7)){log(_0x3467e8(0x18f));if(!(_0x2a1548[_0x3467e8(0x1e2)]in _0x162eb3['rpcs'])){errorlog(_0x3467e8(0x41e));return;}if(_0x3467e8(0x157)in _0x2a1548&&_0x162eb3['rpcs'][_0x2a1548['UUID']][_0x3467e8(0x157)]!=_0x2a1548['session']){errorlog(_0x3467e8(0xd7));return;}if(_0x162eb3[_0x3467e8(0x1f4)][_0x2a1548['UUID']]===null)return;_0x162eb3[_0x3467e8(0x1f4)][_0x2a1548[_0x3467e8(0x1e2)]]['addIceCandidate'](_0x2a1548[_0x3467e8(0x17d)])[_0x3467e8(0x57e)]()['catch'](function(_0xbd56ae){errorlog(_0xbd56ae),errorlog(_0x2a1548);});}else{if(_0x3467e8(0x177)!==_0x3467e8(0x386))errorlog(_0x2a1548),errorlog('ICE\x20DID\x20NOT\x20FIND\x20A\x20PC\x20OPTION?');else{function _0x50072d(){var _0x47493d=_0x3467e8;_0xfc5bef[_0x47493d(0x1f4)][_0x2ff6ce][_0x47493d(0x340)][_0x47493d(0x21e)]['display']=_0x47493d(0x545),_0x265e03=!![];}}}}},_0x162eb3['processIceBundle']=function(_0x32d3d2){var _0x48600c=_0x44a3fc;if(_0x162eb3['password']&&_0x48600c(0x3f5)in _0x32d3d2)_0x162eb3[_0x48600c(0x537)](_0x32d3d2[_0x48600c(0x134)],_0x32d3d2[_0x48600c(0x3f5)])[_0x48600c(0x57e)](function(_0x5d58f5){var _0x48cde2=_0x48600c;_0x32d3d2['candidates']=JSON[_0x48cde2(0x4aa)](_0x5d58f5);var _0xc79381={};_0xc79381[_0x48cde2(0x1e2)]=_0x32d3d2['UUID'],_0xc79381[_0x48cde2(0x3de)]=_0x32d3d2[_0x48cde2(0x3de)];for(var _0x433c51=0x0;_0x433c51<_0x32d3d2[_0x48cde2(0x134)]['length'];_0x433c51++){_0xc79381[_0x48cde2(0x17d)]=_0x32d3d2[_0x48cde2(0x134)][_0x433c51],_0x162eb3[_0x48cde2(0x39d)](_0xc79381);}});else{var _0x2d2690={};_0x2d2690[_0x48600c(0x1e2)]=_0x32d3d2['UUID'],_0x2d2690[_0x48600c(0x3de)]=_0x32d3d2[_0x48600c(0x3de)];for(var _0x49b2ee=0x0;_0x49b2ee<_0x32d3d2['candidates'][_0x48600c(0x3f4)];_0x49b2ee++){_0x2d2690[_0x48600c(0x17d)]=_0x32d3d2['candidates'][_0x49b2ee],_0x162eb3['processIce2'](_0x2d2690);}}},_0x162eb3[_0x44a3fc(0x3e2)]=function(_0x591f07){var _0x136723=_0x44a3fc;_0x162eb3[_0x136723(0x1f4)][_0x591f07[_0x136723(0x1e2)]][_0x136723(0x312)](_0x591f07[_0x136723(0x16b)])[_0x136723(0x57e)](function(){var _0x51132c=_0x136723;if(_0x162eb3[_0x51132c(0x1f4)][_0x591f07[_0x51132c(0x1e2)]]['remoteDescription'][_0x51132c(0x3de)]===_0x51132c(0x587))_0x162eb3[_0x51132c(0x1f4)][_0x591f07[_0x51132c(0x1e2)]][_0x51132c(0x10b)]()[_0x51132c(0x57e)](function(_0x47f31a){var _0x4570f7=_0x51132c;if(!_0x162eb3[_0x4570f7(0x1b6)]&&_0x162eb3[_0x4570f7(0x133)]==0x5)_0x47f31a[_0x4570f7(0x457)]=CodecsHandler[_0x4570f7(0x195)](_0x47f31a[_0x4570f7(0x457)],{'stereo':0x1,'maxaveragebitrate':(_0x162eb3[_0x4570f7(0x4f5)]||0x100)*0x400,'cbr':_0x162eb3[_0x4570f7(0x44e)],'useinbandfec':0x1,'maxptime':_0x162eb3[_0x4570f7(0x3ee)],'minptime':_0x162eb3['minptime'],'ptime':_0x162eb3[_0x4570f7(0x515)]});else{if(_0x162eb3[_0x4570f7(0x133)]==0x1||_0x162eb3[_0x4570f7(0x133)]==0x2||_0x162eb3[_0x4570f7(0x133)]==0x5){if(_0x4570f7(0x149)!==_0x4570f7(0x149)){function _0x3cb7a4(){var _0x59c50d=_0x4570f7;return _0x4e58aa=new _0x4045d4(_0x71ea66),_0x4418af&&(_0x52e7d1=_0x3b1cb4[_0x59c50d(0x32a)](0x0,_0x1cb132(_0x4f3db5(_0x246a27)/0x2))),_0x47a17c=_0x6da532(_0x5ea86c),_0x4169ec;}}else _0x47f31a[_0x4570f7(0x457)]=CodecsHandler[_0x4570f7(0x195)](_0x47f31a[_0x4570f7(0x457)],{'stereo':0x1,'maxaveragebitrate':(_0x162eb3[_0x4570f7(0x4f5)]||0x100)*0x400,'cbr':_0x162eb3[_0x4570f7(0x44e)],'useinbandfec':0x1,'maxptime':_0x162eb3[_0x4570f7(0x3ee)],'minptime':_0x162eb3[_0x4570f7(0x480)],'ptime':_0x162eb3[_0x4570f7(0x515)]});}else{if(_0x162eb3['stereo']==0x4)_0x47f31a['sdp']=CodecsHandler[_0x4570f7(0x195)](_0x47f31a['sdp'],{'stereo':0x2,'maxaveragebitrate':(_0x162eb3[_0x4570f7(0x4f5)]||0x100)*0x400,'cbr':_0x162eb3[_0x4570f7(0x44e)],'useinbandfec':0x1,'maxptime':_0x162eb3[_0x4570f7(0x3ee)],'minptime':_0x162eb3[_0x4570f7(0x480)],'ptime':_0x162eb3[_0x4570f7(0x515)]});else _0x162eb3[_0x4570f7(0x4f5)]&&(_0x47f31a[_0x4570f7(0x457)]=CodecsHandler[_0x4570f7(0x195)](_0x47f31a[_0x4570f7(0x457)],{'maxaveragebitrate':_0x162eb3[_0x4570f7(0x4f5)]*0x400,'cbr':_0x162eb3['cbr'],'useinbandfec':0x1,'maxptime':_0x162eb3[_0x4570f7(0x3ee)],'minptime':_0x162eb3[_0x4570f7(0x480)],'ptime':_0x162eb3[_0x4570f7(0x515)]}));}}if(_0x162eb3['codec'])_0x47f31a[_0x4570f7(0x457)]=CodecsHandler[_0x4570f7(0x397)](_0x47f31a['sdp'],_0x162eb3['codec']);else _0x162eb3[_0x4570f7(0x140)]!==![]&&(_0x47f31a[_0x4570f7(0x457)]=CodecsHandler[_0x4570f7(0x397)](_0x47f31a[_0x4570f7(0x457)],_0x4570f7(0x2b5)));_0x162eb3[_0x4570f7(0x49b)]&&(log(_0x47f31a[_0x4570f7(0x457)]),_0x47f31a[_0x4570f7(0x457)]=CodecsHandler['disableNACK'](_0x47f31a[_0x4570f7(0x457)]));_0x162eb3[_0x4570f7(0x13f)]&&(_0x47f31a[_0x4570f7(0x457)]=CodecsHandler['disablePLI'](_0x47f31a[_0x4570f7(0x457)]));_0x162eb3[_0x4570f7(0x35b)]&&(_0x47f31a[_0x4570f7(0x457)]=CodecsHandler[_0x4570f7(0x2c9)](_0x47f31a[_0x4570f7(0x457)]));if(_0x162eb3[_0x4570f7(0x1f4)][_0x591f07[_0x4570f7(0x1e2)]]['manualBandwidth'])log('bit\x20rate\x20being\x20munged'),_0x47f31a[_0x4570f7(0x457)]=_0x2bcdde(_0x47f31a[_0x4570f7(0x457)],_0x162eb3['rpcs'][_0x591f07[_0x4570f7(0x1e2)]][_0x4570f7(0x538)]);else _0x162eb3[_0x4570f7(0x22c)]&&(log(_0x4570f7(0x1a4)),_0x47f31a[_0x4570f7(0x457)]=_0x2bcdde(_0x47f31a[_0x4570f7(0x457)],_0x162eb3[_0x4570f7(0x22c)]));return _0x162eb3[_0x4570f7(0x1f4)][_0x591f07[_0x4570f7(0x1e2)]][_0x4570f7(0x21f)](_0x47f31a);})[_0x51132c(0x57e)](function _0x3bc531(){var _0x57265b=_0x51132c;log(_0x57265b(0x10e));var _0x2b4f2b={};_0x2b4f2b[_0x57265b(0x1e2)]=_0x591f07[_0x57265b(0x1e2)],_0x2b4f2b[_0x57265b(0x16b)]=_0x162eb3['rpcs'][_0x591f07[_0x57265b(0x1e2)]][_0x57265b(0x156)],_0x2b4f2b[_0x57265b(0x157)]=_0x162eb3[_0x57265b(0x1f4)][_0x591f07['UUID']][_0x57265b(0x157)],_0x162eb3['password']?_0x162eb3[_0x57265b(0x52d)](JSON['stringify'](_0x2b4f2b[_0x57265b(0x16b)]))[_0x57265b(0x57e)](function(_0x1f718){var _0x548a85=_0x57265b;_0x2b4f2b[_0x548a85(0x16b)]=_0x1f718[0x0],_0x2b4f2b[_0x548a85(0x3f5)]=_0x1f718[0x1],_0x162eb3['anyrequest'](_0x2b4f2b);}):_0x162eb3[_0x57265b(0x577)](_0x2b4f2b);})[_0x51132c(0x19f)](errorlog);else _0x162eb3['rpcs'][_0x591f07[_0x51132c(0x1e2)]][_0x51132c(0x13a)][_0x51132c(0x3de)]===_0x51132c(0x509)&&errorlog(_0x51132c(0x440));})[_0x136723(0x19f)](errorlog);},_0x162eb3[_0x44a3fc(0x169)]=function(_0x487cb5){var _0x4f7b4e=_0x44a3fc,_0x4f97d2=_0x487cb5[_0x4f7b4e(0x1e2)];if(_0x4f97d2 in _0x162eb3[_0x4f7b4e(0x1f4)]){log('RTC\x20connection\x20is\x20ALREADY\x20ready;\x20we\x20can\x20already\x20accept\x20answers'),log(_0x487cb5);if(_0x4f7b4e(0x157)in _0x487cb5){if(_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x157)]==_0x487cb5[_0x4f7b4e(0x157)]){if(_0x4f7b4e(0x4b7)!==_0x4f7b4e(0x4b7)){function _0x2e3ae7(){var _0x299ff7=_0x4f7b4e;_0xa1c77b[_0x299ff7(0x147)][_0x9bc98c]['iceTimer']=null;var _0x47a71a={};_0x47a71a['UUID']=_0x549a9c,_0x47a71a[_0x299ff7(0x3de)]=_0x299ff7(0x1a7),_0x47a71a[_0x299ff7(0x134)]=_0x1d88d0[_0x299ff7(0x147)][_0x12cef1]['iceBundle'],_0x47a71a[_0x299ff7(0x157)]=_0x686ed5[_0x299ff7(0x147)][_0x57fc8c]['session'],_0x5f0b64[_0x299ff7(0x147)][_0x5ebf3d][_0x299ff7(0x373)]=[],_0x56294d[_0x299ff7(0xf2)]?_0x51acac[_0x299ff7(0x52d)](_0x685ddf[_0x299ff7(0x444)](_0x47a71a[_0x299ff7(0x134)]))[_0x299ff7(0x57e)](function(_0x3bebca){var _0x4276e9=_0x299ff7;_0x47a71a[_0x4276e9(0x134)]=_0x3bebca[0x0],_0x47a71a[_0x4276e9(0x3f5)]=_0x3bebca[0x1],_0x27a545[_0x4276e9(0x3cd)](_0x47a71a);}):_0x50e4e9[_0x299ff7(0x3cd)](_0x47a71a);}}else{log(_0x4f7b4e(0x465));return;}}else warnlog(_0x4f7b4e(0x4c2));}}else log(_0x4f7b4e(0x28d));try{for(var _0x5c9c8a in _0x162eb3[_0x4f7b4e(0x1f4)]){if(_0x162eb3[_0x4f7b4e(0x1f4)][_0x5c9c8a][_0x4f7b4e(0x34f)]==_0x487cb5[_0x4f7b4e(0x34f)]){_0x162eb3['rpcs'][_0x5c9c8a][_0x4f7b4e(0x340)]&&(_0x162eb3[_0x4f7b4e(0x1f4)][_0x5c9c8a][_0x4f7b4e(0x340)][_0x4f7b4e(0x21e)][_0x4f7b4e(0x1fb)]=_0x4f7b4e(0x277));_0x162eb3[_0x4f7b4e(0x1f4)][_0x5c9c8a]=null,delete _0x162eb3[_0x4f7b4e(0x1f4)][_0x5c9c8a],warnlog(_0x4f7b4e(0x229));if(_0x162eb3[_0x4f7b4e(0x1b6)]){if('YjAHs'!==_0x4f7b4e(0x585)){function _0x4bd232(){var _0x456ce3=_0x4f7b4e;_0x44269b[_0x456ce3(0x2fe)]==0x1f7&&(_0x51811d==![]&&(_0x3816e6(_0x54965f[_0x456ce3(0x351)]),!_0x1259e8[_0x456ce3(0x14e)]&&_0x22228f('Failed\x20to\x20connect\x20to\x20service:\x20Error\x20503 Possibly\x20too\x20many\x20connections\x20from\x20the\x20same\x20address\x20tried\x20to\x20connect. Visit\x20https://discord.obs.ninja\x20for\x20support.',0x7530)));}}else try{document[_0x4f7b4e(0x367)](_0x4f7b4e(0x22e)+_0x5c9c8a)&&getById(_0x4f7b4e(0x22e)+_0x5c9c8a)['parentNode'][_0x4f7b4e(0x45f)](getById('container_'+_0x5c9c8a));}catch(_0x246eb9){errorlog(_0x246eb9);}}}}document[_0x4f7b4e(0x367)](_0x4f7b4e(0x181))&&document[_0x4f7b4e(0x367)](_0x4f7b4e(0x181))[_0x4f7b4e(0x23c)][_0x4f7b4e(0x45f)](document['getElementById'](_0x4f7b4e(0x181)));}catch(_0x12aee5){errorlog(_0x12aee5);}if(_0x162eb3[_0x4f7b4e(0x12a)]!==![]){if(Object[_0x4f7b4e(0x4bb)](_0x162eb3[_0x4f7b4e(0x1f4)])[_0x4f7b4e(0x3f4)]>=_0x162eb3[_0x4f7b4e(0x12a)]){delete _0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2],updateUserList(),warnlog(_0x4f7b4e(0x3e1));return;}}else{if(_0x162eb3[_0x4f7b4e(0x153)]!==![]){if(Object[_0x4f7b4e(0x4bb)](_0x162eb3[_0x4f7b4e(0x1f4)])[_0x4f7b4e(0x3f4)]+Object[_0x4f7b4e(0x4bb)](_0x162eb3['pcs'])[_0x4f7b4e(0x3f4)]>=_0x162eb3[_0x4f7b4e(0x153)]){if('ZpjDD'===_0x4f7b4e(0xf4)){function _0x438a05(){var _0x3b1dd3=_0x4f7b4e;_0x2f56d1[_0x3b1dd3(0x116)](_0x45a731);}}else{delete _0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2],updateUserList(),warnlog(_0x4f7b4e(0x3e1));return;}}}}if(_0x162eb3[_0x4f7b4e(0x46f)]){if(_0x162eb3[_0x4f7b4e(0x1b6)])!(_0x4f97d2 in _0x162eb3[_0x4f7b4e(0x147)])&&_0x162eb3['offerSDP'](_0x4f97d2);else{if(_0x162eb3[_0x4f7b4e(0x37c)]!==_0x4f97d2)return;}}_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2]=new RTCPeerConnection(_0x162eb3[_0x4f7b4e(0x52b)]);if(_0x162eb3[_0x4f7b4e(0x3d8)]){if(Object[_0x4f7b4e(0x4bb)](_0x162eb3['rpcs'])[_0x4f7b4e(0x3f4)]>0x1){warnlog(_0x4f7b4e(0x49e)),log(_0x162eb3[_0x4f7b4e(0x1f4)]),delete _0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2],updateUserList();return;}else warnlog(_0x4f7b4e(0x58b));}_0x487cb5[_0x4f7b4e(0x34f)]in _0x162eb3[_0x4f7b4e(0x3b8)]&&delete _0x162eb3[_0x4f7b4e(0x3b8)][_0x487cb5[_0x4f7b4e(0x34f)]];_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x34f)]=_0x487cb5[_0x4f7b4e(0x34f)];_0x487cb5[_0x4f7b4e(0x157)]?_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x157)]=_0x487cb5[_0x4f7b4e(0x157)]:_0x162eb3['rpcs'][_0x4f97d2][_0x4f7b4e(0x157)]=null;_0x162eb3['rpcs'][_0x4f97d2]['activelySpeaking']=![],_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x14f)]={},_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x14f)][_0x4f7b4e(0x1cf)]=![],_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2]['bandwidth']=-0x1,_0x162eb3['rpcs'][_0x4f97d2][_0x4f7b4e(0x3d5)]=![],_0x162eb3['rpcs'][_0x4f97d2]['targetBandwidth']=-0x1,_0x162eb3['rpcs'][_0x4f97d2][_0x4f7b4e(0x538)]=![],_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x340)]=![],_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x31d)]=![],_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x1ea)]=![],_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x1ae)]=![],_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2]['directorVideoMuted']=![],_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x37b)]=![],_0x162eb3['rpcs'][_0x4f97d2][_0x4f7b4e(0x167)]=![],_0x162eb3['rpcs'][_0x4f97d2][_0x4f7b4e(0x144)]=null,_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x2d0)]={},_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2]['scaleHeight']=![],_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x295)]=![],_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x3d0)]=null,_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x4f4)]=0x64,_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2]['directorMutedState']=0x0,_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x19c)]=0x0,_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x350)]=0x0,_0x162eb3['rpcs'][_0x4f97d2][_0x4f7b4e(0x2fa)]=![],_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2]['order']=![],_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2]['canvasCtx']=null,_0x162eb3['rpcs'][_0x4f97d2][_0x4f7b4e(0x29e)]=null,_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x1ed)]={},_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2]['iframeSrc']=![],_0x162eb3['rpcs'][_0x4f97d2]['iframeEle']=![],_0x162eb3['rpcs'][_0x4f97d2][_0x4f7b4e(0x13c)]=Date[_0x4f7b4e(0x1b9)]();var _0x1b0808='';_0x162eb3[_0x4f7b4e(0x170)]&&(_0x1b0808=_0x162eb3[_0x4f7b4e(0x170)]);if(_0x162eb3[_0x4f7b4e(0x1b6)]){if(_0x4f7b4e(0x18d)!==_0x4f7b4e(0x18d)){function _0x6757ae(){var _0x40e18d=_0x4f7b4e;_0x501ab5[_0x40e18d(0x367)](_0x40e18d(0x22e)+this[_0x40e18d(0x1e2)])&&_0x423947('container_'+this[_0x40e18d(0x1e2)])[_0x40e18d(0x23c)][_0x40e18d(0x45f)](_0x4c6999(_0x40e18d(0x22e)+this[_0x40e18d(0x1e2)]));}}else{var _0x29d2b7='';_0x162eb3['pie']&&(_0x162eb3[_0x4f7b4e(0x285)]!==!![]?_0x29d2b7='&pie='+_0x162eb3['pie']:_0x29d2b7=_0x4f7b4e(0x1e3));var _0x4d6a24='';if(_0x162eb3[_0x4f7b4e(0xf2)]){if('RIMsk'==='RIMsk')_0x162eb3[_0x4f7b4e(0x3a5)]===![]&&(_0x4d6a24=_0x4f7b4e(0x56c)+_0x162eb3['password']);else{function _0x38384e(){return;}}}createControlBox(_0x4f97d2,_0x4f7b4e(0x4a7)+location[_0x4f7b4e(0x272)]+location['pathname']+_0x4f7b4e(0x387)+_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x34f)]+_0x4f7b4e(0x311)+_0x1b0808+_0x4f7b4e(0x2b4)+_0x162eb3[_0x4f7b4e(0x27b)]+_0x4d6a24+_0x29d2b7,_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x34f)]);}}_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x1e2)]=_0x4f97d2;if(_0x4f7b4e(0x34f)in _0x487cb5){_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x34f)]=_0x487cb5['streamID'];try{if(_0x162eb3[_0x4f7b4e(0x1ca)]){if(_0x162eb3[_0x4f7b4e(0x1ca)]['includes'](_0x162eb3['rpcs'][_0x4f97d2][_0x4f7b4e(0x34f)])){if(_0x162eb3[_0x4f7b4e(0x54e)]!==![]){let _0x13daed=_0x162eb3[_0x4f7b4e(0x1ca)][_0x4f7b4e(0x549)](_0x162eb3['rpcs'][_0x4f97d2]['streamID']);_0x162eb3[_0x4f7b4e(0x54e)][_0x4f7b4e(0x3f4)]>_0x13daed&&(_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x538)]=parseInt(_0x162eb3[_0x4f7b4e(0x54e)][_0x13daed]),_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x538)]<=0x0&&(_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x538)]=![]));}}}}catch(_0x389cc7){errorlog(_0x389cc7);}}_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x45c)]=function(_0x1de84c){var _0x3aa45e=_0x4f7b4e;try{var _0x112d07=this[_0x3aa45e(0x34f)];}catch(_0x25e56a){}if(!_0x162eb3[_0x3aa45e(0x1b6)]){if(_0x162eb3[_0x3aa45e(0x145)]!==![]||_0x162eb3[_0x3aa45e(0x27b)]!==![])try{if(_0x3aa45e(0x123)!=='Uduly'){function _0x28af4c(){var _0xd0df47=_0x3aa45e;_0x62a70d['encodings'][0x0][_0xd0df47(0x3b0)]=!![];}}else _0x162eb3[_0x3aa45e(0x1f4)][this[_0x3aa45e(0x1e2)]][_0x3aa45e(0x340)]&&(_0x162eb3[_0x3aa45e(0x1f4)][this[_0x3aa45e(0x1e2)]][_0x3aa45e(0x340)][_0x3aa45e(0x21e)][_0x3aa45e(0x1fb)]=_0x3aa45e(0x277)),setTimeout(function(){updateMixer();},0x1);}catch(_0x10ad29){}}try{document[_0x3aa45e(0x367)]('container_'+this[_0x3aa45e(0x1e2)])&&getById(_0x3aa45e(0x22e)+this[_0x3aa45e(0x1e2)])[_0x3aa45e(0x23c)][_0x3aa45e(0x45f)](getById(_0x3aa45e(0x22e)+this[_0x3aa45e(0x1e2)]));}catch(_0x2602bd){errorlog(_0x2602bd);}try{this[_0x3aa45e(0x3d0)]&&this[_0x3aa45e(0x3d0)]['getTracks']()[_0x3aa45e(0x204)](function(_0x4b75ec){var _0x3a4907=_0x3aa45e;_0x4b75ec[_0x3a4907(0x529)]();});}catch(_0x21714b){errorlog(_0x21714b);}try{this[_0x3aa45e(0x228)][_0x3aa45e(0x556)]();}catch(_0x2db421){errorlog(_0x2db421);}try{_0x162eb3[_0x3aa45e(0x1f4)][this[_0x3aa45e(0x1e2)]]=null,delete _0x162eb3[_0x3aa45e(0x1f4)][this['UUID']];}catch(_0x207ea7){errorlog(_0x207ea7);}warnlog(_0x3aa45e(0x229));try{_0x162eb3[_0x3aa45e(0x39b)](_0x112d07);}catch(_0xa6af72){errorlog(_0x3aa45e(0x45a)),errorlog(_0xa6af72);}updateUserList();},_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x3b3)]=null,_0x162eb3['rpcs'][_0x4f97d2][_0x4f7b4e(0x373)]=[],_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x4d4)]=function(_0x32e380){var _0x61f007=_0x4f7b4e;if(_0x32e380['candidate']==null){log(_0x61f007(0x569));return;}try{if(_0x162eb3[_0x61f007(0x2c8)]){if(_0x32e380[_0x61f007(0x17d)][_0x61f007(0x17d)][_0x61f007(0x549)](_0x162eb3['icefilter'])===-0x1){log(_0x61f007(0x52c));return;}else log(_0x32e380[_0x61f007(0x17d)]);}}catch(_0x5add9a){errorlog(_0x5add9a);}if(_0x162eb3[_0x61f007(0x1f4)][_0x4f97d2]['iceTimer']!==null){if(_0x61f007(0x58a)==='nKxun'){function _0x457964(){_0x26c88e('successfully\x20requested\x20audio\x20and\x20video');}}else{_0x162eb3[_0x61f007(0x1f4)][_0x4f97d2][_0x61f007(0x373)][_0x61f007(0x21d)](_0x32e380[_0x61f007(0x17d)]);return;}}_0x162eb3[_0x61f007(0x1f4)][_0x4f97d2][_0x61f007(0x373)][_0x61f007(0x21d)](_0x32e380[_0x61f007(0x17d)]),_0x162eb3['rpcs'][_0x4f97d2]['iceTimer']=setTimeout(function(){var _0x16b5e2=_0x61f007;if(!(_0x4f97d2 in _0x162eb3[_0x16b5e2(0x1f4)]))return;_0x162eb3[_0x16b5e2(0x1f4)][_0x4f97d2][_0x16b5e2(0x3b3)]=null;if(_0x162eb3[_0x16b5e2(0x1f4)][_0x4f97d2]['iceBundle']==[])return;var _0x38b7d1={};_0x38b7d1[_0x16b5e2(0x1e2)]=_0x4f97d2,_0x38b7d1[_0x16b5e2(0x3de)]=_0x16b5e2(0x4cf),_0x38b7d1['candidates']=_0x162eb3[_0x16b5e2(0x1f4)][_0x4f97d2][_0x16b5e2(0x373)],_0x38b7d1['session']=_0x162eb3['rpcs'][_0x4f97d2][_0x16b5e2(0x157)],_0x162eb3[_0x16b5e2(0x1f4)][_0x4f97d2]['iceBundle']=[],_0x162eb3[_0x16b5e2(0xf2)]?_0x162eb3[_0x16b5e2(0x52d)](JSON[_0x16b5e2(0x444)](_0x38b7d1[_0x16b5e2(0x134)]))['then'](function(_0x3d61bb){var _0x26cdc3=_0x16b5e2;_0x38b7d1[_0x26cdc3(0x134)]=_0x3d61bb[0x0],_0x38b7d1[_0x26cdc3(0x3f5)]=_0x3d61bb[0x1],_0x162eb3[_0x26cdc3(0x577)](_0x38b7d1);}):_0x162eb3[_0x16b5e2(0x577)](_0x38b7d1);},0x190);},_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x550)]=function(_0x3a0ac9){var _0x13d76f=_0x4f7b4e;switch(this[_0x13d76f(0x268)]){case'new':log('new');case _0x13d76f(0x15d):log(_0x13d76f(0x15d));case _0x13d76f(0x4e6):log(_0x13d76f(0x3b4));if(_0x162eb3['security']){if(_0x162eb3['ws'][_0x13d76f(0x2bb)]!==0x1){_0x162eb3['ws'][_0x13d76f(0x556)]();break;}_0x162eb3['ws'][_0x13d76f(0x556)](),setTimeout(function(){var _0x22edc0=_0x13d76f;_0x162eb3[_0x22edc0(0x14e)]!=!![]&&warnUser(_0x22edc0(0x468));},0x1);}break;case _0x13d76f(0x263):warnlog(_0x13d76f(0x568));break;case _0x13d76f(0x162):warnlog('FAIL\x20rpcs');try{var _0x146ce1=this[_0x13d76f(0x34f)];}catch(_0x2cc4e8){}try{this[_0x13d76f(0x3d0)]&&this[_0x13d76f(0x3d0)][_0x13d76f(0x472)]()[_0x13d76f(0x204)](function(_0x1d3d05){var _0x534ff9=_0x13d76f;_0x1d3d05[_0x534ff9(0x529)](),log(_0x534ff9(0x214));});}catch(_0xed7b49){warnlog(_0xed7b49);}if(_0x162eb3['director'])try{_0x13d76f(0x305)in _0x162eb3[_0x13d76f(0x1f4)][this['UUID']]['videoElement']&&_0x162eb3['rpcs'][this['UUID']][_0x13d76f(0x340)][_0x13d76f(0x305)]['stop']();}catch(_0x4512de){warnlog(_0x4512de);}try{if(_0x13d76f(0x2ae)!==_0x13d76f(0x2ae)){function _0x14ac95(){var _0x4a0641=_0x13d76f;_0x1fe6ff[_0x4a0641(0x1f4)][_0x161847][_0x4a0641(0x340)][_0x4a0641(0x288)]=_0x5739bf[_0x4a0641(0x1f4)][_0x11abb2][_0x4a0641(0x3d0)];}}else document[_0x13d76f(0x367)](_0x13d76f(0x22e)+this[_0x13d76f(0x1e2)])&&getById(_0x13d76f(0x22e)+this['UUID'])[_0x13d76f(0x23c)][_0x13d76f(0x45f)](getById(_0x13d76f(0x22e)+this[_0x13d76f(0x1e2)]));}catch(_0x30d692){warnlog(_0x30d692);}_0x162eb3[_0x13d76f(0x1f4)][this[_0x13d76f(0x1e2)]][_0x13d76f(0x556)](),_0x162eb3[_0x13d76f(0x1f4)][this[_0x13d76f(0x1e2)]]=null,delete _0x162eb3[_0x13d76f(0x1f4)][this[_0x13d76f(0x1e2)]];!_0x162eb3['director']&&setTimeout(function(){updateMixer();},0x1);if(typeof _0x146ce1==_0x13d76f(0x2bd))break;try{warnlog(_0x13d76f(0x21c)),_0x146ce1 in _0x162eb3[_0x13d76f(0x4f2)]&&clearTimeout(_0x162eb3[_0x13d76f(0x4f2)][_0x146ce1]),_0x162eb3['watchTimeoutList'][_0x146ce1]=setTimeout(function(_0x38f954){var _0x56e281=_0x13d76f;delete _0x162eb3[_0x56e281(0x4f2)][_0x38f954],_0x162eb3[_0x56e281(0x39b)](_0x38f954);},_0x162eb3['retryTimeout'],_0x146ce1);}catch(_0x2bd461){errorlog(_0x2bd461);}break;case _0x13d76f(0x2f7):warnlog(_0x13d76f(0x1de));try{if(_0x13d76f(0x433)===_0x13d76f(0x380)){function _0x183f81(){var _0x375617=_0x13d76f;_0x5934dd[_0x375617(0x27f)]=_0x5ac3e7[_0x375617(0x1f4)][_0x396eb8][_0x375617(0x2fa)];}}else var _0x146ce1=this[_0x13d76f(0x34f)];}catch(_0x186176){};try{this[_0x13d76f(0x3d0)]&&this[_0x13d76f(0x3d0)][_0x13d76f(0x472)]()[_0x13d76f(0x204)](function(_0x1b58e2){var _0x567b79=_0x13d76f;if(_0x567b79(0x372)===_0x567b79(0x372))_0x1b58e2['stop'](),log(_0x567b79(0x214));else{function _0x554f38(){var _0x1ba764=_0x567b79;_0x177181[_0x1ba764(0x512)]=[{}];}}});}catch(_0x506583){}if(_0x162eb3[_0x13d76f(0x1b6)])try{_0x13d76f(0x305)in _0x162eb3[_0x13d76f(0x1f4)][this['UUID']]['videoElement']&&_0x162eb3[_0x13d76f(0x1f4)][this['UUID']][_0x13d76f(0x340)][_0x13d76f(0x305)][_0x13d76f(0x529)]();}catch(_0x25600e){errorlog(_0x25600e);}try{document['getElementById'](_0x13d76f(0x22e)+this['UUID'])&&getById(_0x13d76f(0x22e)+this['UUID'])[_0x13d76f(0x23c)][_0x13d76f(0x45f)](getById(_0x13d76f(0x22e)+this['UUID']));}catch(_0x169c57){errorlog(_0x169c57);}_0x162eb3[_0x13d76f(0x1f4)][this[_0x13d76f(0x1e2)]][_0x13d76f(0x556)](),_0x162eb3[_0x13d76f(0x1f4)][this[_0x13d76f(0x1e2)]]=null,delete _0x162eb3['rpcs'][this[_0x13d76f(0x1e2)]];!_0x162eb3[_0x13d76f(0x1b6)]&&setTimeout(function(){updateMixer();},0x1);if(typeof _0x146ce1==_0x13d76f(0x2bd))break;try{errorlog(_0x13d76f(0xe3)),_0x146ce1 in _0x162eb3[_0x13d76f(0x4f2)]&&clearTimeout(_0x162eb3[_0x13d76f(0x4f2)][_0x146ce1]),_0x162eb3[_0x13d76f(0x4f2)][_0x146ce1]=setTimeout(function(_0x541621){var _0x38751f=_0x13d76f;delete _0x162eb3[_0x38751f(0x4f2)][_0x541621],_0x162eb3[_0x38751f(0x39b)](_0x541621);},_0x162eb3['retryTimeout'],_0x146ce1);}catch(_0x3573d4){errorlog(_0x3573d4);}break;}},_0x162eb3['rpcs'][_0x4f97d2][_0x4f7b4e(0x11e)]=function(){var _0x54bc0f=_0x4f7b4e;if(_0x54bc0f(0xf5)!==_0x54bc0f(0x2a3))try{if(this[_0x54bc0f(0x3b2)]==_0x54bc0f(0x2f7))errorlog(_0x54bc0f(0x560));else{if(this[_0x54bc0f(0x3b2)]=='disconnected')warnlog('ICE\x20DISCONNECTED'),_0x162eb3[_0x54bc0f(0x1f4)][_0x4f97d2][_0x54bc0f(0x340)][_0x54bc0f(0x21e)][_0x54bc0f(0x345)]='0',_0x162eb3[_0x54bc0f(0x1f4)][_0x4f97d2]['disconnectedTimeout']=setTimeout(function(_0x34cac0){updateMixer();},0x1f4,_0x4f97d2);else this[_0x54bc0f(0x3b2)]==_0x54bc0f(0x162)?errorlog(_0x54bc0f(0x4ea)):(log('ICE:\x20'+this['iceConnectionState']),'opacity'in _0x162eb3[_0x54bc0f(0x1f4)][_0x4f97d2][_0x54bc0f(0x340)][_0x54bc0f(0x21e)]?_0x162eb3['rpcs'][_0x4f97d2][_0x54bc0f(0x340)]['style'][_0x54bc0f(0x345)]=='0'&&(_0x162eb3[_0x54bc0f(0x1f4)][_0x4f97d2]['videoElement'][_0x54bc0f(0x21e)][_0x54bc0f(0x345)]='1',updateMixer()):_0x162eb3[_0x54bc0f(0x1f4)][_0x4f97d2][_0x54bc0f(0x340)][_0x54bc0f(0x21e)][_0x54bc0f(0x345)]='1',_0x162eb3[_0x54bc0f(0x1f4)][_0x4f97d2][_0x54bc0f(0x10f)]&&clearTimeout(_0x162eb3[_0x54bc0f(0x1f4)][_0x4f97d2][_0x54bc0f(0x10f)]));}}catch(_0x4d9064){}else{function _0x4690d9(){var _0x30f96e=_0x54bc0f;_0x39df70['rpcs'][_0x3280a3][_0x30f96e(0x340)][_0x30f96e(0x21e)][_0x30f96e(0x1fb)]=_0x30f96e(0x277),_0x443f40=!![];}}},_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x2a4)]=function(_0x473cff){var _0x1a52d6=_0x4f7b4e;_0x162eb3['rpcs'][_0x4f97d2][_0x1a52d6(0x228)]=_0x473cff[_0x1a52d6(0x47f)],_0x162eb3['rpcs'][_0x4f97d2][_0x1a52d6(0x228)][_0x1a52d6(0x1e2)]=_0x4f97d2,_0x162eb3['rpcs'][_0x4f97d2][_0x1a52d6(0x228)][_0x1a52d6(0x3ef)]=_0x4781be=>{var _0x156cc8=_0x1a52d6,_0x211197={};_0x211197[_0x156cc8(0x140)]=![];if(_0x162eb3[_0x156cc8(0x50b)]!==![])_0x162eb3['novideo'][_0x156cc8(0x28f)](_0x162eb3[_0x156cc8(0x1f4)][_0x4f97d2]['streamID'])?_0x211197['video']=!![]:_0x211197[_0x156cc8(0x3cb)]=![];else{if(_0x162eb3[_0x156cc8(0x140)]!==![]){if(_0x162eb3[_0x156cc8(0x140)]!==null){if(_0x162eb3[_0x156cc8(0x1f4)][_0x4f97d2]['streamID']===_0x162eb3[_0x156cc8(0x140)])_0x162eb3[_0x156cc8(0x3ba)]?(_0x211197[_0x156cc8(0x140)]=!![],_0x211197[_0x156cc8(0x3cb)]=![]):_0x211197['video']=!![];else{if(_0x156cc8(0x4c8)===_0x156cc8(0xda)){function _0x200e7f(){var _0x505ada=_0x156cc8;_0x876f95[_0x505ada(0x147)][_0x279a17][_0x505ada(0x14f)][_0x505ada(0x53f)][_0x505ada(0x1b6)]=!![];}}else _0x211197[_0x156cc8(0x3cb)]=![];}}else _0x162eb3[_0x156cc8(0x37c)]&&(_0x4f97d2==_0x162eb3[_0x156cc8(0x37c)]?_0x162eb3[_0x156cc8(0x3ba)]?(_0x211197[_0x156cc8(0x3cb)]=![],_0x211197[_0x156cc8(0x140)]=!![]):_0x211197[_0x156cc8(0x3cb)]=!![]:_0x211197[_0x156cc8(0x3cb)]=![]);}else{if(_0x162eb3['exclude']!==![])_0x162eb3[_0x156cc8(0x122)][_0x156cc8(0x28f)](_0x162eb3[_0x156cc8(0x1f4)][_0x4f97d2][_0x156cc8(0x34f)])?_0x211197[_0x156cc8(0x3cb)]=![]:_0x211197[_0x156cc8(0x3cb)]=!![];else{if(_0x156cc8(0x29b)!==_0x156cc8(0x29b)){function _0x1c9945(){var _0xe97a4b=_0x156cc8;_0x2ab697[_0xe97a4b(0x376)]=_0xe97a4b(0x273),_0x3e9c7b(_0xe97a4b(0x17f));}}else _0x211197[_0x156cc8(0x3cb)]=!![];}}}_0x162eb3[_0x156cc8(0x29f)]&&(_0x211197[_0x156cc8(0x39f)]=_0x162eb3[_0x156cc8(0x29f)]);try{_0x211197[_0x156cc8(0x53f)]={},_0x211197[_0x156cc8(0x53f)][_0x156cc8(0x2fa)]=_0x162eb3[_0x156cc8(0x2fa)],_0x211197[_0x156cc8(0x53f)]['order']=_0x162eb3[_0x156cc8(0x2c5)],_0x211197['info'][_0x156cc8(0x4c5)]=_0x162eb3[_0x156cc8(0x133)],_0x211197[_0x156cc8(0x53f)][_0x156cc8(0x400)]=_0x162eb3[_0x156cc8(0x22c)],_0x211197[_0x156cc8(0x53f)][_0x156cc8(0x3f7)]=_0x162eb3[_0x156cc8(0x4f5)],_0x211197[_0x156cc8(0x53f)]['codec_url']=_0x162eb3['codec'],_0x211197[_0x156cc8(0x53f)][_0x156cc8(0x158)]=_0x162eb3['version'],_0x211197[_0x156cc8(0x53f)][_0x156cc8(0x26c)]=_0x162eb3['forceios'],_0x211197[_0x156cc8(0x53f)][_0x156cc8(0x48a)]=_0x162eb3[_0x156cc8(0x319)],_0x211197[_0x156cc8(0x53f)][_0x156cc8(0x515)]=_0x162eb3['ptime'],_0x211197['info']['minptime']=_0x162eb3[_0x156cc8(0x480)],_0x211197[_0x156cc8(0x53f)][_0x156cc8(0x3ee)]=_0x162eb3['maxptime'];if(navigator[_0x156cc8(0x3f1)]){var _0x103aad,_0x30a57b=navigator[_0x156cc8(0x3f1)];_0x211197[_0x156cc8(0x53f)][_0x156cc8(0x28a)]=_0x30a57b;}navigator[_0x156cc8(0x209)]&&(_0x211197[_0x156cc8(0x53f)]['platform']=navigator['platform']);if(window[_0x156cc8(0x475)]){_0x211197[_0x156cc8(0x53f)][_0x156cc8(0x46c)]=window[_0x156cc8(0x475)][_0x156cc8(0x131)];if(_0x162eb3['obsState']){if('HEOCa'===_0x156cc8(0x4d8)){function _0x503c86(){var _0x48c0ca=_0x156cc8;_0x34aee6['encodings'][0x0][_0x48c0ca(0x3b0)]==![]&&(_0x34d103[_0x48c0ca(0x512)][0x0][_0x48c0ca(0x3b0)]=!![]),_0x34867e[_0x48c0ca(0x512)][0x0][_0x48c0ca(0x23e)]=_0x2c12d5*0x400;}}else{var _0x3d0e32=![];_0x162eb3['obsState']['visibility']!==null&&(_0x211197[_0x156cc8(0xeb)]=_0x162eb3[_0x156cc8(0x3cc)][_0x156cc8(0x419)],_0x162eb3[_0x156cc8(0x3cc)][_0x156cc8(0x419)]===![]&&(_0x3d0e32=!![]));_0x162eb3[_0x156cc8(0x3cc)][_0x156cc8(0x422)]!==null&&(_0x211197[_0x156cc8(0x208)]=_0x162eb3[_0x156cc8(0x3cc)][_0x156cc8(0x422)]);if(_0x162eb3[_0x156cc8(0x3cc)]['recording']!==null){if('ljlJq'!==_0x156cc8(0x1b2))_0x211197['obsRecording']=_0x162eb3[_0x156cc8(0x3cc)][_0x156cc8(0x38a)];else{function _0x1f668c(){var _0x2dca4e=_0x156cc8;_0x55a2d4[_0x2dca4e(0x147)][_0x15f2f5][_0x2dca4e(0x4ae)][_0x2dca4e(0x388)](_0x2206ae);}}}if(_0x162eb3[_0x156cc8(0x3cc)][_0x156cc8(0x4a6)]!==null){if(_0x156cc8(0x247)===_0x156cc8(0x247))_0x211197[_0x156cc8(0x223)]=_0x162eb3[_0x156cc8(0x3cc)]['streaming'];else{function _0x3fdef8(){var _0x19381e=_0x156cc8;_0x5e9e80['pcs'][_0x13ffc2][_0x19381e(0x556)](),delete _0x167f4b['pcs'][_0x32f38d],_0x575cb3();}}}}}if(_0x162eb3[_0x156cc8(0x1a1)]!==![]){if('IraWJ'!==_0x156cc8(0x2b1)){function _0x56708b(){var _0x233cc5=_0x156cc8;_0x2088a5[_0x233cc5(0x1f4)][_0x4934dd][_0x233cc5(0x14f)][_0x233cc5(0x446)][_0x233cc5(0x530)]=_0x25bf73[_0x233cc5(0x3a4)];}}else _0x211197[_0x156cc8(0x40d)]=parseInt(_0x162eb3[_0x156cc8(0x1a1)]),_0x3d0e32&&(_0x162eb3[_0x156cc8(0x1f4)][_0x4f97d2][_0x156cc8(0x40b)]=_0x211197['optimizedBitrate']);}}else _0x211197[_0x156cc8(0x53f)][_0x156cc8(0x46c)]=![];}catch(_0x382aff){};_0x162eb3[_0x156cc8(0x4cd)]!==![]?_0x162eb3[_0x156cc8(0x4cd)][_0x156cc8(0x28f)](_0x162eb3[_0x156cc8(0x1f4)][_0x4f97d2]['streamID'])?_0x211197[_0x156cc8(0x25f)]=!![]:_0x211197['audio']=![]:_0x211197['audio']=!![];_0x211197[_0x156cc8(0x3b9)]=![];if(_0x162eb3[_0x156cc8(0x46a)]!==![])_0x162eb3[_0x156cc8(0x46a)][_0x156cc8(0x28f)](_0x162eb3['rpcs'][_0x4f97d2]['streamID'])?_0x211197[_0x156cc8(0x3b9)]=!![]:_0x211197[_0x156cc8(0x3b9)]=![];else{if(_0x156cc8(0x314)!==_0x156cc8(0x461))_0x211197['iframe']=!![];else{function _0x2b3434(){_0x484e00('failed\x20to\x20disconnect');}}}_0x211197[_0x156cc8(0x466)]=![],_0x211197[_0x156cc8(0x145)]=![],_0x211197[_0x156cc8(0x1b6)]=![],_0x211197[_0x156cc8(0x139)]=_0x162eb3[_0x156cc8(0x139)],_0x211197[_0x156cc8(0x160)]=![],_0x211197[_0x156cc8(0x300)]=![],_0x211197[_0x156cc8(0x26c)]=![];_0x162eb3[_0x156cc8(0x319)]&&(_0x211197[_0x156cc8(0x160)]=!![]);if(_0x162eb3[_0x156cc8(0x1b6)])_0x211197[_0x156cc8(0x1b6)]=!![],_0x211197[_0x156cc8(0x26c)]=_0x162eb3[_0x156cc8(0x26c)];else{if(_0x162eb3[_0x156cc8(0x145)]!==![]){if('EqEYW'===_0x156cc8(0x29d)){function _0x24f808(){_0x57bc9e(_0x4d768c);}}else _0x211197[_0x156cc8(0x145)]=_0x162eb3[_0x156cc8(0x145)];}else{if(_0x162eb3[_0x156cc8(0x27b)]!==![]&&_0x162eb3['roomid']!==''){if(_0x156cc8(0x120)!==_0x156cc8(0x120)){function _0x108fe3(){var _0x4d862d=_0x156cc8;_0x336e49[_0x4d862d(0x134)]=_0xc3c3e3[0x0],_0x2d20e9['vector']=_0x3d3586[0x1],_0x4cb181[_0x4d862d(0x3cd)](_0x2effed);}}else _0x211197[_0x156cc8(0x26c)]=_0x162eb3[_0x156cc8(0x26c)],_0x211197[_0x156cc8(0x466)]=!![];}}}_0x162eb3[_0x156cc8(0x196)](_0x211197,_0x4f97d2)?log('successfully\x20requested\x20audio\x20and\x20video'):errorlog(_0x156cc8(0x31f)),pokeIframeAPI(_0x156cc8(0x1d4),!![],_0x4f97d2);},_0x162eb3[_0x1a52d6(0x1f4)][_0x4f97d2][_0x1a52d6(0x228)][_0x1a52d6(0x1f2)]=_0x372b1d=>{var _0x5ddf82=_0x1a52d6;if(typeof _0x372b1d[_0x5ddf82(0x2cd)]==_0x5ddf82(0x1b1)){if(!_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x31d)])_0x162eb3['rpcs'][_0x4f97d2][_0x5ddf82(0x31d)]=document[_0x5ddf82(0x4da)](_0x5ddf82(0x4b5)),_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x31d)][_0x5ddf82(0x4d1)]=0x10,_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x31d)]['height']=0x9,_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x31d)][_0x5ddf82(0x4e1)][_0x5ddf82(0x1e2)]=_0x4f97d2,_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2]['imageElement'][_0x5ddf82(0x302)]=![],_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x31d)][_0x5ddf82(0x1b8)](_0x5ddf82(0x12c),function(_0x14782d){var _0x4ac7d0=_0x5ddf82;log('clicked');try{if(_0x14782d[_0x4ac7d0(0x226)]||_0x14782d['metaKey']){_0x14782d[_0x4ac7d0(0x399)]();var _0xd59c8c=_0x14782d[_0x4ac7d0(0x4f1)][_0x4ac7d0(0x4e1)][_0x4ac7d0(0x1e2)];if(_0x4ac7d0(0x14f)in _0x162eb3['rpcs'][_0xd59c8c]){var [_0x2ddb75,_0x27298c]=statsMenuCreator();printViewStats(_0x27298c,_0xd59c8c),_0x2ddb75[_0x4ac7d0(0x3a2)]=setInterval(printViewStats,0xbb8,_0x27298c,_0xd59c8c);}return _0x14782d[_0x4ac7d0(0x40e)](),![];}}catch(_0x1bc6a8){errorlog(_0x1bc6a8);}}),updateMixer();else _0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x31d)][_0x5ddf82(0x302)]&&(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2]['imageElement']['hidden']=![],_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x31d)][_0x5ddf82(0x21e)][_0x5ddf82(0x419)]=_0x5ddf82(0x3d3));_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2]['imageElement']['src']=window[_0x5ddf82(0x165)][_0x5ddf82(0x583)](new Blob([new Uint8Array(_0x372b1d[_0x5ddf82(0x2cd)])],{'type':_0x5ddf82(0x2f3)}));return;}var _0x58cc22=JSON[_0x5ddf82(0x4aa)](_0x372b1d[_0x5ddf82(0x2cd)]);_0x58cc22['UUID']=_0x4f97d2;var _0x33935f=![],_0x18d207=![];if('rejected'in _0x58cc22){if(_0x162eb3[_0x5ddf82(0x1b6)]){if(!(_0x162eb3[_0x5ddf82(0x14e)]||_0x162eb3[_0x5ddf82(0x425)])){if('wZrra'===_0x5ddf82(0x293))warnUser(_0x5ddf82(0x23b),0x1388);else{function _0xf584d2(){var _0xe600=_0x5ddf82;if(_0x47a663[_0xe600(0x17d)][_0xe600(0x17d)][_0xe600(0x549)](_0x3a415a['icefilter'])===-0x1){_0x1984f6(_0xe600(0x52c));return;}else _0x16818a(_0x40d12d[_0xe600(0x17d)]);}}}}errorlog(_0x5ddf82(0x24f)+_0x58cc22[_0x5ddf82(0x186)]+',\x20isDirector:\x20'+_0x162eb3[_0x5ddf82(0x1b6)]);}if(_0x5ddf82(0x16b)in _0x58cc22)_0x162eb3[_0x5ddf82(0x3e9)](_0x58cc22);else{if(_0x5ddf82(0x17d)in _0x58cc22)_0x58cc22[_0x5ddf82(0x1e2)]=_0x4f97d2,log(_0x5ddf82(0x38b)),_0x162eb3[_0x5ddf82(0x3d9)](_0x58cc22);else{if(_0x5ddf82(0x134)in _0x58cc22)_0x58cc22[_0x5ddf82(0x1e2)]=_0x4f97d2,log(_0x5ddf82(0x56a)),_0x162eb3[_0x5ddf82(0x142)](_0x58cc22);else{if(_0x5ddf82(0x40c)in _0x58cc22)try{_0x162eb3['rpcs'][_0x4f97d2][_0x5ddf82(0x40c)]=_0x58cc22[_0x5ddf82(0x40c)]||![];if(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2]['iframeSrc']==![])_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2]['iframeEle']=![],_0x33935f=!![];else{if(_0x162eb3['broadcast']!==![]){if(_0x162eb3['broadcast']!==null){if(_0x162eb3['rpcs'][_0x4f97d2][_0x5ddf82(0x34f)]===_0x162eb3[_0x5ddf82(0x140)]){if(_0x162eb3[_0x5ddf82(0x46a)]===![]){_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x36f)]=loadIframe(_0x58cc22[_0x5ddf82(0x40c)]),_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x36f)]['id']='iframe_'+_0x4f97d2,_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x36f)][_0x5ddf82(0x4e1)][_0x5ddf82(0x1e2)]=_0x4f97d2,_0x33935f=!![];if(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x34f)]){if(_0x5ddf82(0x1a6)===_0x5ddf82(0x1a6))_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x36f)][_0x5ddf82(0x4e1)][_0x5ddf82(0x1bf)]=_0x162eb3['rpcs'][_0x4f97d2][_0x5ddf82(0x34f)];else{function _0x1e888d(){var _0x167c52=_0x5ddf82;_0x262535[_0x167c52(0x1b6)]&&(!(_0x80e37b[_0x167c52(0x14e)]||_0x4f61de['cleanDirector'])&&_0x781f5(_0x167c52(0x23b),0x1388)),_0x1418fa(_0x167c52(0x24f)+_0x8f602[_0x167c52(0x186)]+_0x167c52(0x2ef)+_0x2d7cde[_0x167c52(0x1b6)]);}}}}else _0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x34f)]in _0x162eb3[_0x5ddf82(0x46a)]&&(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2]['iframeEle']=loadIframe(_0x58cc22[_0x5ddf82(0x40c)]),_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x36f)]['id']=_0x5ddf82(0x370)+_0x4f97d2,_0x162eb3['rpcs'][_0x4f97d2][_0x5ddf82(0x36f)][_0x5ddf82(0x4e1)][_0x5ddf82(0x1e2)]=_0x4f97d2,_0x33935f=!![],_0x162eb3['rpcs'][_0x4f97d2]['streamID']&&(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x36f)][_0x5ddf82(0x4e1)][_0x5ddf82(0x1bf)]=_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x34f)]));}}else{if(_0x162eb3[_0x5ddf82(0x37c)]){if(_0x4f97d2==_0x162eb3[_0x5ddf82(0x37c)]){if(_0x162eb3['noiframe']===![])_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x36f)]=loadIframe(_0x58cc22[_0x5ddf82(0x40c)]),_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x36f)]['id']=_0x5ddf82(0x370)+_0x4f97d2,_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x36f)][_0x5ddf82(0x4e1)][_0x5ddf82(0x1e2)]=_0x4f97d2,_0x33935f=!![],_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x34f)]&&(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x36f)]['dataset']['sid']=_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x34f)]);else _0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x34f)]in _0x162eb3[_0x5ddf82(0x46a)]&&(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x36f)]=loadIframe(_0x58cc22['iframeSrc']),_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x36f)]['id']=_0x5ddf82(0x370)+_0x4f97d2,_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2]['iframeEle'][_0x5ddf82(0x4e1)][_0x5ddf82(0x1e2)]=_0x4f97d2,_0x33935f=!![],_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x34f)]&&(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x36f)]['dataset'][_0x5ddf82(0x1bf)]=_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x34f)]));}}}}else{if(_0x162eb3[_0x5ddf82(0x46a)]===![])_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x36f)]=loadIframe(_0x58cc22['iframeSrc']),_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x36f)]['id']=_0x5ddf82(0x370)+_0x4f97d2,_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x36f)]['dataset']['UUID']=_0x4f97d2,_0x33935f=!![],_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x34f)]&&(_0x162eb3['rpcs'][_0x4f97d2]['iframeEle'][_0x5ddf82(0x4e1)][_0x5ddf82(0x1bf)]=_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x34f)]);else _0x162eb3['rpcs'][_0x4f97d2][_0x5ddf82(0x34f)]in _0x162eb3[_0x5ddf82(0x46a)]&&(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x36f)]=loadIframe(_0x58cc22[_0x5ddf82(0x40c)]),_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x36f)]['id']=_0x5ddf82(0x370)+_0x4f97d2,_0x162eb3['rpcs'][_0x4f97d2][_0x5ddf82(0x36f)]['dataset']['UUID']=_0x4f97d2,_0x33935f=!![],_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x34f)]&&(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2]['iframeEle'][_0x5ddf82(0x4e1)][_0x5ddf82(0x1bf)]=_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x34f)]));}}}catch(_0x12fa27){errorlog(_0x12fa27);}}}}if(_0x5ddf82(0x4c4)in _0x58cc22){var _0x17ed15=![],_0x622fe3=![];if(_0x162eb3[_0x5ddf82(0x37c)]===_0x4f97d2){_0x17ed15=!![];if(_0x5ddf82(0x187)in _0x58cc22){if(_0x58cc22['overlay']==!![]){if(_0x5ddf82(0x517)===_0x5ddf82(0x517))_0x622fe3=!![];else{function _0x366407(){var _0xffe64=_0x5ddf82;_0x4dae77[_0xffe64(0xcf)]=_0x37d7fd['label']+'\x20-\x20Transferred';}}}}}if(_0x162eb3[_0x5ddf82(0x1b6)]){if(_0x58cc22[_0x5ddf82(0x4c4)]==_0x5ddf82(0x3ac))_0x162eb3['beepToNotify']&&playtone(),getById('hands_'+_0x4f97d2)[_0x5ddf82(0x21e)][_0x5ddf82(0x1fb)]=_0x5ddf82(0x545),_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x30d)]['style'][_0x5ddf82(0x1fb)]=_0x5ddf82(0x3aa);else _0x58cc22['chat']==_0x5ddf82(0x171)&&(getById(_0x5ddf82(0x4d3)+_0x4f97d2)[_0x5ddf82(0x21e)]['display']=_0x5ddf82(0x277),_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x30d)][_0x5ddf82(0x21e)]['display']=_0x5ddf82(0x277));}log(_0x5ddf82(0x1ba)+_0x17ed15),getChatMessage(_0x58cc22[_0x5ddf82(0x4c4)],_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2]['label'],_0x17ed15,_0x622fe3);}if(_0x5ddf82(0x1aa)in _0x58cc22){log(_0x58cc22);if(_0x162eb3[_0x5ddf82(0x3a9)]){if(_0x5ddf82(0x44d)==='cSukY'){function _0x2cce1f(){var _0x2efb51=_0x5ddf82;return _0x2ca20e[_0x2efb51(0x2ac)]&&_0x300445[_0x2efb51(0x2ac)][_0x2efb51(0x2c3)]==_0x2efb51(0x3cb);}}else updateClosedCaptions(_0x58cc22,_0x162eb3['rpcs'][_0x4f97d2][_0x5ddf82(0x2fa)],_0x4f97d2);}}_0x5ddf82(0xec)in _0x58cc22&&(_0x162eb3['director']&&updateDirectorsAudio(_0x58cc22[_0x5ddf82(0xec)],_0x4f97d2));_0x5ddf82(0x35a)in _0x58cc22&&(_0x162eb3[_0x5ddf82(0x1b6)]&&updateDirectorsVideo(_0x58cc22[_0x5ddf82(0x35a)],_0x4f97d2));_0x5ddf82(0x2a7)in _0x58cc22&&(_0x162eb3[_0x5ddf82(0x1b6)]&&gotDevicesRemote(_0x58cc22['mediaDevices'],_0x4f97d2));_0x5ddf82(0xe1)in _0x58cc22&&(_0x162eb3[_0x5ddf82(0x37c)]===_0x4f97d2&&(_0x162eb3[_0x5ddf82(0x109)]&&lowerhand()));if(_0x5ddf82(0x1dc)in _0x58cc22){log(_0x58cc22);if(_0x162eb3[_0x5ddf82(0x37c)]===_0x4f97d2){if(_0x58cc22[_0x5ddf82(0x1dc)]!==![]){if(_0x58cc22[_0x5ddf82(0x1dc)]===!![])_0x162eb3['infocus']=!![];else{if(_0x5ddf82(0x11b)==='AVMXj'){function _0x19bb9f(){var _0x3ab14b=_0x5ddf82;_0x43ab9a=!![],_0x3ab14b(0x187)in _0x5d76b9&&(_0x625dc4[_0x3ab14b(0x187)]==!![]&&(_0x35dbb7=!![]));}}else for(var _0x5a1578 in _0x162eb3['rpcs']){if(_0x5ddf82(0x542)===_0x5ddf82(0xd1)){function _0x26647b(){_0x50655e=0x0;}}else{if(_0x162eb3[_0x5ddf82(0x1f4)][_0x5a1578][_0x5ddf82(0x34f)]===_0x58cc22['infocus']){_0x162eb3['infocus']=_0x5a1578;break;}}}}}else _0x162eb3[_0x5ddf82(0x1dc)]=![];_0x33935f=!![],mustUpdateuserList=!![];}}if(_0x5ddf82(0x2eb)in _0x58cc22){_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x14f)][_0x5ddf82(0x2eb)]={};if('lin'in _0x58cc22){if(_0x5ddf82(0x554)!==_0x5ddf82(0x554)){function _0x4968d9(){var _0x3036b8=_0x5ddf82;_0x276ab0[_0x3036b8(0x4a1)][_0x232300]['micDelay']['delayTime'][_0x3036b8(0x174)](_0x44c2d3,_0x581627[_0x3036b8(0x4a1)][_0xa2dff6][_0x3036b8(0x389)]['currentTime']);}}else _0x162eb3['rpcs'][_0x4f97d2][_0x5ddf82(0x14f)][_0x5ddf82(0x2eb)][_0x5ddf82(0x12d)]=_0x58cc22[_0x5ddf82(0x12d)];}_0x5ddf82(0x533)in _0x58cc22&&(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x14f)][_0x5ddf82(0x2eb)][_0x5ddf82(0x533)]=_0x58cc22['acc']);_0x5ddf82(0x1d0)in _0x58cc22&&(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x14f)][_0x5ddf82(0x2eb)][_0x5ddf82(0x1d0)]=_0x58cc22[_0x5ddf82(0x1d0)]);if(_0x5ddf82(0x4a5)in _0x58cc22){if('QfTDa'!==_0x5ddf82(0x20d)){function _0x50dfec(){var _0x19fbca=_0x5ddf82;_0x565afe[_0x19fbca(0x1e2)]=_0x4a5550,_0x16cf70(_0x19fbca(0x38b)),_0x1d8b2f[_0x19fbca(0x3d9)](_0x148d55);}}else _0x162eb3['rpcs'][_0x4f97d2][_0x5ddf82(0x14f)]['sensors'][_0x5ddf82(0x4a5)]=_0x58cc22[_0x5ddf82(0x4a5)];}isIFrame&&parent[_0x5ddf82(0x30e)]({'sensors':_0x58cc22},'*');}_0x5ddf82(0x1a5)in _0x58cc22&&playbackMIDI(_0x58cc22['midi']);_0x5ddf82(0x305)in _0x58cc22&&updateRemoteRecordButton(_0x4f97d2,_0x58cc22['recorder']);if(_0x5ddf82(0x53f)in _0x58cc22){if(_0x5ddf82(0x2dc)==='hDPZX'){function _0x441460(){if(_0x134a57){}}}else{warnlog(_0x58cc22),_0x162eb3['rpcs'][_0x4f97d2][_0x5ddf82(0x14f)][_0x5ddf82(0x53f)]=_0x58cc22[_0x5ddf82(0x53f)];if(_0x5ddf82(0x2fa)in _0x58cc22[_0x5ddf82(0x53f)]){if(typeof _0x58cc22[_0x5ddf82(0x53f)][_0x5ddf82(0x2fa)]==_0x5ddf82(0x173))_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x2fa)]=sanitizeLabel(_0x58cc22['info'][_0x5ddf82(0x2fa)]);else{if(_0x5ddf82(0x471)!==_0x5ddf82(0x471)){function _0x1f7322(){var _0x191151=_0x5ddf82;_0x3db3c9(_0x191151(0x235)),_0x197bf5[_0x191151(0x15f)](_0x1c2e4b[_0x1e8a77]);}}else _0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x2fa)]=![];}if(_0x162eb3[_0x5ddf82(0x1b6)]){var _0x3665d2=getById(_0x5ddf82(0x427)+_0x4f97d2);_0x3665d2&&(_0x3665d2[_0x5ddf82(0x21e)][_0x5ddf82(0x3fe)]=_0x5ddf82(0x54b),_0x3665d2[_0x5ddf82(0x21e)]['top']=_0x5ddf82(0x279),_0x3665d2[_0x5ddf82(0x21e)][_0x5ddf82(0x1c8)]='5px',_0x3665d2[_0x5ddf82(0x21e)][_0x5ddf82(0x4e9)]=_0x5ddf82(0x4a8),_0x3665d2['style'][_0x5ddf82(0x318)]='pointer',_0x3665d2[_0x5ddf82(0x4e1)][_0x5ddf82(0x1e2)]=_0x4f97d2,_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x2fa)]?_0x3665d2[_0x5ddf82(0x27f)]=_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x2fa)]:_0x3665d2[_0x5ddf82(0x27f)]=_0x5ddf82(0x394),_0x3665d2[_0x5ddf82(0x1f7)]=function(_0x395400){var _0x213bbb=_0x5ddf82,_0x331f84=_0x395400[_0x213bbb(0x324)]['innerText'];if(_0x162eb3[_0x213bbb(0x1f4)][_0x395400['target'][_0x213bbb(0x4e1)][_0x213bbb(0x1e2)]]['label']===![]){if(_0x213bbb(0x4f7)!==_0x213bbb(0xe2))_0x331f84='';else{function _0x21fce1(){var _0x3489e5=_0x213bbb;_0x3d75a9[_0x3489e5(0x2ac)]&&(_0x489aa7[_0x3489e5(0x2ac)][_0x3489e5(0x2f1)]=![]);}}}window[_0x213bbb(0x3f6)]();var _0x12c746=prompt('Enter\x20a\x20new\x20Display\x20Name\x20for\x20this\x20stream',_0x331f84);if(_0x12c746!==null){_0x12c746==''?(_0x12c746=![],_0x395400[_0x213bbb(0x324)][_0x213bbb(0x27f)]='Add\x20a\x20label'):_0x395400[_0x213bbb(0x324)]['innerText']=_0x12c746;var _0x1c306d={};_0x1c306d[_0x213bbb(0x1e2)]=_0x395400[_0x213bbb(0x324)][_0x213bbb(0x4e1)]['UUID'],_0x1c306d[_0x213bbb(0x42f)]=!![],_0x1c306d[_0x213bbb(0x276)]=_0x12c746,_0x162eb3[_0x213bbb(0x196)](_0x1c306d,_0x1c306d[_0x213bbb(0x1e2)]);}});}}if(_0x5ddf82(0x2c5)in _0x58cc22[_0x5ddf82(0x53f)]){_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2]['order']=parseInt(_0x58cc22[_0x5ddf82(0x53f)][_0x5ddf82(0x2c5)])||0x0;if(_0x162eb3[_0x5ddf82(0x1b6)]){var _0xd954c9=document[_0x5ddf82(0x41a)](_0x5ddf82(0x330)+_0x4f97d2+'\x22]');_0xd954c9[0x0]&&(_0xd954c9[0x0][_0x5ddf82(0x27f)]=_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x2c5)]);}}else _0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x2c5)]=0x0;if(_0x162eb3[_0x5ddf82(0x1b6)]){if('recording_audio_pipeline'in _0x58cc22[_0x5ddf82(0x53f)]){if(_0x58cc22[_0x5ddf82(0x53f)][_0x5ddf82(0x484)]==![]){var _0xd954c9=document[_0x5ddf82(0x41a)](_0x5ddf82(0x270)+_0x4f97d2+'\x22]');if(_0xd954c9[0x0]){if(_0x5ddf82(0x267)===_0x5ddf82(0x237)){function _0x57be9f(){var _0x3a7ca6=_0x5ddf82;_0xa99c80[_0x3a7ca6(0x27b)]=_0x2f7985[_0x3a7ca6(0x53b)];}}else _0xd954c9[0x0][_0x5ddf82(0x532)]=!![],_0xd954c9[0x0][_0x5ddf82(0xcf)]=_0x5ddf82(0x150);}var _0xd954c9=document[_0x5ddf82(0x41a)](_0x5ddf82(0x588)+_0x4f97d2+'\x22]');_0xd954c9[0x0]&&(_0xd954c9[0x0][_0x5ddf82(0x532)]=!![],_0xd954c9[0x0][_0x5ddf82(0xcf)]=_0x5ddf82(0x150),_0xd954c9[0x0][_0x5ddf82(0x21e)][_0x5ddf82(0x345)]=0.2);}}if(_0x5ddf82(0x1da)in _0x58cc22[_0x5ddf82(0x53f)]){if(_0x5ddf82(0x20f)===_0x5ddf82(0x57c)){function _0x2db658(){var _0x3a2d03=_0x5ddf82;_0x1f7c9b[_0x3a2d03(0x147)][_0x17d52e][_0x3a2d03(0x145)]!==![]?(_0x32b15f[_0x3a2d03(0x116)](_0x283ab4),_0x4ba147(_0x3a2d03(0x3e3))):_0x186aa8(_0x3a2d03(0x10a));}}else{if(_0x58cc22[_0x5ddf82(0x53f)][_0x5ddf82(0x1da)]!==![]){var _0x10fcdb=parseInt(_0x58cc22[_0x5ddf82(0x53f)][_0x5ddf82(0x1da)])||0x0;if(_0x10fcdb===0x0){var _0xd954c9=document[_0x5ddf82(0x41a)](_0x5ddf82(0x270)+_0x4f97d2+'\x22]');_0xd954c9[0x0]&&(_0xd954c9[0x0][_0x5ddf82(0x4e1)][_0x5ddf82(0x276)]=0x1,_0xd954c9[0x0][_0x5ddf82(0x1ff)]=_0x5ddf82(0x4fc),_0xd954c9[0x0][_0x5ddf82(0xf3)][0x1]['innerHTML']='Un-mute\x20guest',_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x188)]=0x1);}else{var _0xd954c9=document[_0x5ddf82(0x41a)](_0x5ddf82(0x588)+_0x4f97d2+'\x22]');_0xd954c9[0x0]&&(_0xd954c9[0x0][_0x5ddf82(0x276)]=_0x10fcdb,_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x4f4)]=_0x10fcdb,remoteVolumeUI(_0xd954c9[0x0]));}}}}}_0x5ddf82(0x253)in _0x58cc22[_0x5ddf82(0x53f)]&&(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2]['remoteMuteState']=_0x58cc22[_0x5ddf82(0x53f)][_0x5ddf82(0x253)],_0x162eb3[_0x5ddf82(0x145)]===![]&&(_0x162eb3[_0x5ddf82(0x27b)]&&(!_0x162eb3[_0x5ddf82(0x14e)]&&(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x167)]?_0x162eb3['rpcs'][_0x4f97d2][_0x5ddf82(0x37b)]?_0x162eb3['rpcs'][_0x4f97d2][_0x5ddf82(0x167)][_0x5ddf82(0x21e)][_0x5ddf82(0x1fb)]=_0x5ddf82(0x545):_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x167)][_0x5ddf82(0x21e)][_0x5ddf82(0x1fb)]=_0x5ddf82(0x277):(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x167)]=getById(_0x5ddf82(0x13e))[_0x5ddf82(0x4df)](!![]),_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x167)]['id']=_0x5ddf82(0x539)+_0x4f97d2,_0x162eb3['rpcs'][_0x4f97d2][_0x5ddf82(0x37b)]?_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x167)][_0x5ddf82(0x21e)][_0x5ddf82(0x1fb)]=_0x5ddf82(0x545):_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x167)][_0x5ddf82(0x21e)]['display']=_0x5ddf82(0x277),_0x33935f=!![])))));_0x5ddf82(0x477)in _0x58cc22[_0x5ddf82(0x53f)]&&(_0x162eb3[_0x5ddf82(0x1b6)]&&(_0x58cc22['info'][_0x5ddf82(0x477)]&&updateRemoteSpeakerMute(_0x4f97d2)));if(_0x5ddf82(0x30a)in _0x58cc22[_0x5ddf82(0x53f)]){if(_0x5ddf82(0x299)!==_0x5ddf82(0x299)){function _0xa7cea4(){var _0x4e9050=_0x5ddf82;_0x4609a3(_0x417f82[_0x4e9050(0x351)]),!_0x1ad414[_0x4e9050(0x14e)]&&_0x2a354c(_0x4e9050(0x17c),0x7530);}}else _0x162eb3[_0x5ddf82(0x1b6)]&&(_0x58cc22[_0x5ddf82(0x53f)][_0x5ddf82(0x30a)]&&updateRemoteDisplayMute(_0x4f97d2));}if(_0x5ddf82(0x491)in _0x58cc22[_0x5ddf82(0x53f)]){if(_0x162eb3['director']){if(_0x58cc22[_0x5ddf82(0x53f)][_0x5ddf82(0x491)]){if('FqrUX'===_0x5ddf82(0x164)){function _0x148794(){var _0x446412=_0x5ddf82;_0x417668[_0x446412(0x584)](_0x507fca(_0xfdd51e[_0x446412(0x50e)]));}}else updateDirectorVideoMute(_0x4f97d2);}}else _0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x491)]=_0x58cc22[_0x5ddf82(0x53f)]['directorVideoMuted'],_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2]['directorVideoMuted']&&(_0x4f97d2 in _0x162eb3[_0x5ddf82(0x1f4)]&&_0x162eb3[_0x5ddf82(0x4e7)](0x0,_0x4f97d2));}_0x5ddf82(0x39e)in _0x58cc22[_0x5ddf82(0x53f)]&&(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x1ae)]=_0x58cc22[_0x5ddf82(0x53f)][_0x5ddf82(0x39e)],_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x1ae)]&&(_0x162eb3[_0x5ddf82(0x1b6)]&&(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x127)][_0x5ddf82(0x21e)][_0x5ddf82(0x1fb)]=_0x5ddf82(0x545))));if(_0x4f97d2===_0x162eb3[_0x5ddf82(0x37c)])try{_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x14f)]['info'][_0x5ddf82(0x1b6)]=!![];}catch(_0x496f22){}mustUpdateuserList=!![];}}if(_0x5ddf82(0x4de)in _0x58cc22){if(_0x5ddf82(0x217)!==_0x5ddf82(0x1b4)){if(_0x162eb3[_0x5ddf82(0x37c)]===_0x4f97d2){_0x5ddf82(0x262)in _0x58cc22[_0x5ddf82(0x4de)]&&(_0x162eb3[_0x5ddf82(0x262)]=parseInt(_0x58cc22[_0x5ddf82(0x4de)][_0x5ddf82(0x262)])||0x0,_0x33935f=!![]);if(_0x58cc22[_0x5ddf82(0x4de)][_0x5ddf82(0x210)]){if(_0x58cc22['directorSettings'][_0x5ddf82(0x210)]===_0x162eb3[_0x5ddf82(0x34f)])_0x162eb3['infocus']=!![];else for(var _0x5a1578 in _0x162eb3[_0x5ddf82(0x1f4)]){if(_0x162eb3[_0x5ddf82(0x1f4)][_0x5a1578]['streamID']===_0x58cc22['directorSettings'][_0x5ddf82(0x210)]){if(_0x5ddf82(0x3b1)!=='xCgHZ'){_0x162eb3['infocus']=_0x5a1578;break;}else{function _0x1d6cbb(){var _0x235516=_0x5ddf82;_0x1a54b1[_0x235516(0x1f4)][_0xe9935][_0x235516(0x340)]&&(_0x5c7a29[_0x235516(0x1f4)][_0x2cb79f]['videoElement']['recording']&&(_0x41cdb0[_0x235516(0x1f4)][_0x5452fc][_0x235516(0x340)]['recorder']['writer'][_0x235516(0x556)](),_0x54ae20[_0x235516(0x1f4)][_0xe0c05b]['videoElement']['recording']=![])),_0x2899fa[_0x235516(0x1f4)][_0x2a9ad2][_0x235516(0x556)](),_0x1facd8[_0x235516(0x1f4)][_0xa6d46e]=null,delete _0x14ae3a[_0x235516(0x1f4)][_0x201682];}}}}_0x33935f=!![],mustUpdateuserList=!![];}if(_0x162eb3[_0x5ddf82(0x145)]!==![]){if(_0x58cc22[_0x5ddf82(0x4de)][_0x5ddf82(0x145)])for(var _0x5a1578 in _0x58cc22[_0x5ddf82(0x4de)][_0x5ddf82(0x145)]){setTimeout(function(_0x15783d){var _0x4f3e2e=_0x5ddf82;if(_0x4f3e2e(0x26d)!=='bIJNl'){function _0x386e38(){var _0x39cec5=_0x4f3e2e;if(_0x15554a['bitrate_set']!==![]){let _0x112792=_0x167594[_0x39cec5(0x1ca)][_0x39cec5(0x549)](_0x435256[_0x39cec5(0x1f4)][_0x3f3b02][_0x39cec5(0x34f)]);_0x1ad274['bitrate_set'][_0x39cec5(0x3f4)]>_0x112792&&(_0x126535[_0x39cec5(0x1f4)][_0xc4a886][_0x39cec5(0x538)]=_0x838f1d(_0x3e9e1e[_0x39cec5(0x54e)][_0x112792]),_0x4f4db7[_0x39cec5(0x1f4)][_0x2f8bc1][_0x39cec5(0x538)]<=0x0&&(_0x373a5e[_0x39cec5(0x1f4)][_0x4bbec6]['manualBandwidth']=![]));}}}else _0x162eb3[_0x4f3e2e(0x20b)](_0x15783d);},0x3e8,_0x58cc22[_0x5ddf82(0x4de)][_0x5ddf82(0x145)][_0x5a1578]);}if(_0x58cc22['directorSettings'][_0x5ddf82(0x2c6)])for(var _0x5a1578 in _0x58cc22[_0x5ddf82(0x4de)][_0x5ddf82(0x2c6)]){setTimeout(function(_0x3c2715){var _0x2d0027=_0x5ddf82;_0x162eb3[_0x2d0027(0x20b)](_0x3c2715);},0x3e8,_0x58cc22[_0x5ddf82(0x4de)][_0x5ddf82(0x2c6)][_0x5a1578]);}}}}else{function _0x43b25f(){_0x128008(_0x2ab4f1);}}}_0x162eb3[_0x5ddf82(0x37c)]===_0x4f97d2&&(_0x162eb3['scene']!==![]&&(_0x5ddf82(0x328)in _0x58cc22&&_0x162eb3[_0x5ddf82(0x20b)](_0x58cc22)));if('order'in _0x58cc22){_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x2c5)]=parseInt(_0x58cc22[_0x5ddf82(0x2c5)])||0x0;_0x4f97d2 in _0x162eb3['pcs']&&(_0x162eb3[_0x5ddf82(0x147)][_0x4f97d2][_0x5ddf82(0x2c5)]=parseInt(_0x58cc22[_0x5ddf82(0x2c5)])||0x0);if(_0x162eb3[_0x5ddf82(0x1b6)]){var _0xd954c9=document[_0x5ddf82(0x41a)](_0x5ddf82(0x330)+_0x4f97d2+'\x22]');if(_0xd954c9[0x0]){if(_0x5ddf82(0x463)==='SoyDm')_0xd954c9[0x0][_0x5ddf82(0x27f)]=parseInt(_0x58cc22[_0x5ddf82(0x2c5)])||0x0;else{function _0x5648b8(){var _0x5cc745=_0x5ddf82;_0x3ffbe1[_0x5cc745(0x23a)](_0x4b5b9f,_0x5da69f[_0x5cc745(0x4f1)]['dataset'][_0x5cc745(0x1e2)]);}}}}_0x33935f=!![];}if(_0x5ddf82(0x42f)in _0x58cc22){log('Change\x20Label');if('value'in _0x58cc22){log(_0x5ddf82(0x230));if(typeof _0x58cc22['value']=='string'){if(_0x5ddf82(0x1ef)!==_0x5ddf82(0x1ef)){function _0x2cbe22(){var _0x27ebaf=_0x5ddf82;_0x30a583['roombitrate']!==![]&&(_0x31f1fd[_0x27ebaf(0x4c0)]<_0x3df95b&&(_0x320c96=_0x313423['roombitrate']));}}else{_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2]['label']=sanitizeLabel(_0x58cc22[_0x5ddf82(0x276)]);_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x2fa)][_0x5ddf82(0x3f4)]==0x0&&(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2]['label']=![]);if(_0x162eb3[_0x5ddf82(0x1b6)]){var _0xd954c9=getById(_0x5ddf82(0x427)+_0x4f97d2);if(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2]['label']){if(_0x5ddf82(0x374)===_0x5ddf82(0x374))_0xd954c9['innerText']=_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2]['label'];else{function _0x296059(){var _0x3a5f2e=_0x5ddf82;_0x22cd66[_0x3a5f2e(0x16b)][_0x3a5f2e(0x457)]=_0x1b8b9f['setOpusAttributes'](_0x3d60db[_0x3a5f2e(0x16b)]['sdp'],{'maxaveragebitrate':_0x550783[_0x3a5f2e(0xdf)]*0x400,'cbr':_0x2c0567[_0x3a5f2e(0x44e)]});}}}else{if(_0x5ddf82(0x104)===_0x5ddf82(0x119)){function _0x45cf29(){var _0x218ead=_0x5ddf82;_0x37c900[0x0][_0x218ead(0x276)]=_0x51cd14,_0x22dcde[_0x218ead(0x1f4)][_0x506010][_0x218ead(0x4f4)]=_0x909f63,_0x1e2d1c(_0x49c1db[0x0]);}}else _0xd954c9[_0x5ddf82(0x27f)]=_0x5ddf82(0x394);}}else _0x162eb3[_0x5ddf82(0x478)]&&(_0x33935f=!![]);}}else{_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x2fa)]=![];if(_0x162eb3[_0x5ddf82(0x1b6)]){var _0xd954c9=getById(_0x5ddf82(0x427)+_0x4f97d2);_0xd954c9[_0x5ddf82(0x27f)]=_0x5ddf82(0x394);}else _0x162eb3[_0x5ddf82(0x478)]&&(_0x33935f=!![]);}mustUpdateuserList=!![];}}if(_0x5ddf82(0x286)in _0x58cc22){if('VpOvt'===_0x5ddf82(0x543)){log(_0x58cc22),_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x37b)]=_0x58cc22['muteState'],_0x162eb3[_0x5ddf82(0x4e7)](![],_0x4f97d2);if(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2]['stats'][_0x5ddf82(0x53f)]){if(_0x5ddf82(0x2bf)===_0x5ddf82(0x2bf))_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x14f)]['info'][_0x5ddf82(0x253)]=_0x162eb3['rpcs'][_0x4f97d2][_0x5ddf82(0x37b)];else{function _0x103c26(){var _0x23710f=_0x5ddf82;if(_0x3941c6['soloChatUUID']in _0x1841aa[_0x23710f(0x147)]){}else _0x403cf9[_0x23710f(0x504)]=![];}}}_0x162eb3[_0x5ddf82(0x145)]===![]&&(_0x162eb3[_0x5ddf82(0x27b)]&&(!_0x162eb3[_0x5ddf82(0x14e)]&&(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x167)]?_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x37b)]?_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x167)][_0x5ddf82(0x21e)]['display']=_0x5ddf82(0x545):_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2]['remoteMuteElement'][_0x5ddf82(0x21e)][_0x5ddf82(0x1fb)]='none':(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2]['remoteMuteElement']=getById(_0x5ddf82(0x13e))[_0x5ddf82(0x4df)](!![]),_0x162eb3['rpcs'][_0x4f97d2][_0x5ddf82(0x167)]['id']=_0x5ddf82(0x539)+_0x4f97d2,_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x37b)]?_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x167)][_0x5ddf82(0x21e)][_0x5ddf82(0x1fb)]=_0x5ddf82(0x545):_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x167)][_0x5ddf82(0x21e)][_0x5ddf82(0x1fb)]=_0x5ddf82(0x277),_0x33935f=!![]),mustUpdateuserList=!![])));}else{function _0x1c3652(){var _0x154f72=_0x5ddf82,_0x48853c=_0x34ecd0[0x0];_0x48853c[_0x154f72(0x2fa)]!=_0x154f72(0x2b8)&&(_0x4e649c[_0x154f72(0x1f4)][_0x56f848][_0x154f72(0x340)][_0x154f72(0x288)]=_0x32605f(_0x2537f1[_0x154f72(0x1f4)][_0x1c592e][_0x154f72(0x3d0)],_0x311887,_0x48853c));}}}if('requestSceneUpdate'in _0x58cc22){var _0x56a447=getChromeVersion();_0x56a447&&(_0x56a447<0x50&&(_0x33935f=!![]));}_0x5ddf82(0x1ae)in _0x58cc22&&(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x1ae)]=_0x58cc22[_0x5ddf82(0x1ae)],!_0x162eb3[_0x5ddf82(0x1b6)]?(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x1ae)]&&(_0x162eb3[_0x5ddf82(0x4e7)](0x0,_0x4f97d2),_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x31d)]&&(_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x31d)][_0x5ddf82(0x302)]=!![],_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2]['imageElement']['style'][_0x5ddf82(0x419)]=_0x5ddf82(0x302))),_0x33935f=!![]):_0x162eb3['rpcs'][_0x4f97d2][_0x5ddf82(0x1ae)]?_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2][_0x5ddf82(0x127)][_0x5ddf82(0x21e)][_0x5ddf82(0x1fb)]=_0x5ddf82(0x3aa):_0x162eb3[_0x5ddf82(0x1f4)][_0x4f97d2]['remoteVideoMuteElement'][_0x5ddf82(0x21e)][_0x5ddf82(0x1fb)]='none',mustUpdateuserList=!![]);if(_0x5ddf82(0x51d)in _0x58cc22){if(!_0x162eb3[_0x5ddf82(0x1b6)]){if('target'in _0x58cc22){if(_0x162eb3[_0x5ddf82(0x37c)]===_0x4f97d2){var _0x319206=_0x58cc22[_0x5ddf82(0x324)];if(_0x319206===!![])_0x162eb3[_0x5ddf82(0x491)]=_0x58cc22['directVideoMuted'];else _0x319206 in _0x162eb3[_0x5ddf82(0x1f4)]&&(_0x162eb3[_0x5ddf82(0x1f4)][_0x319206]['directorVideoMuted']=_0x58cc22[_0x5ddf82(0x51d)],_0x162eb3[_0x5ddf82(0x1f4)][_0x319206][_0x5ddf82(0x491)]&&(_0x319206 in _0x162eb3[_0x5ddf82(0x1f4)]&&_0x162eb3[_0x5ddf82(0x4e7)](0x0,_0x319206)),_0x33935f=!![]);}}}mustUpdateuserList=!![];}_0x5ddf82(0x294)in _0x58cc22&&remoteStats(_0x58cc22);if(_0x33935f)setTimeout(function(){updateMixer(),updateUserList();},0x1);else mustUpdateuserList&&updateUserList();},_0x162eb3[_0x1a52d6(0x1f4)][_0x4f97d2][_0x1a52d6(0x228)][_0x1a52d6(0x45c)]=()=>{var _0x4dfdec=_0x1a52d6;log('rpc\x20datachannel\x20closed');try{var _0x1bf00b=_0x162eb3[_0x4dfdec(0x1f4)][_0x4f97d2]['streamID'];}catch(_0x25878e){}try{_0x162eb3[_0x4dfdec(0x1f4)][_0x4f97d2]['close']();}catch(_0x18772d){if(_0x4dfdec(0x19d)!==_0x4dfdec(0x2fb))errorlog(_0x4dfdec(0x450));else{function _0x186555(){var _0x21b738=_0x4dfdec;return _0x1d881f[_0x21b738(0x426)][_0x21b738(0x2a6)]({'name':_0x21b738(0x522),'iv':_0x987d81},_0x4a5b3e,_0x5c18d9)[_0x21b738(0x57e)](function(_0x35110a){var _0x2d63ea=_0x21b738,_0x499320=new _0x24795c(_0x35110a),_0x1691f0='';for(var _0x2c7884=0x0;_0x2c7884<_0x499320[_0x2d63ea(0xf9)];_0x2c7884++){_0x1691f0+=_0x6f9677['fromCharCode'](_0x499320[_0x2c7884]);}return _0x1691f0;},function(_0x2a9577){var _0x42ff43=_0x21b738;return _0x38e590(_0x2a9577[_0x42ff43(0x47c)]),![];});}}}try{if(_0x4dfdec(0x3ae)!==_0x4dfdec(0x3ae)){function _0xd5988(){_0x5dd19c(_0x5a269f);}}else _0x162eb3[_0x4dfdec(0x1f4)][_0x4f97d2][_0x4dfdec(0x3d0)]&&_0x162eb3[_0x4dfdec(0x1f4)][_0x4f97d2][_0x4dfdec(0x3d0)][_0x4dfdec(0x472)]()[_0x4dfdec(0x204)](function(_0x81d280){var _0xa7b67=_0x4dfdec;_0x81d280['stop'](),log(_0xa7b67(0x214));});}catch(_0x4ba8b8){}if(_0x162eb3['director'])try{_0x4dfdec(0x305)in _0x162eb3[_0x4dfdec(0x1f4)][_0x4f97d2][_0x4dfdec(0x340)]&&_0x162eb3[_0x4dfdec(0x1f4)][_0x4f97d2]['videoElement'][_0x4dfdec(0x305)][_0x4dfdec(0x529)]();}catch(_0x279f2b){warnlog(_0x279f2b);}try{document[_0x4dfdec(0x367)](_0x4dfdec(0x22e)+_0x4f97d2)&&getById(_0x4dfdec(0x22e)+_0x4f97d2)[_0x4dfdec(0x23c)][_0x4dfdec(0x45f)](getById(_0x4dfdec(0x22e)+_0x4f97d2));}catch(_0x596437){if(_0x4dfdec(0x213)===_0x4dfdec(0x213))warnlog(_0x596437);else{function _0x2cd67c(){var _0x3ed36e=_0x4dfdec;_0x353ffe['queueList'][_0x3ed36e(0x21d)](_0x39e339['streamID']),_0x306cb1[_0x3ed36e(0x309)]();}}}try{if('voePV'===_0x4dfdec(0x535))_0x162eb3['rpcs'][_0x4f97d2]=null,delete _0x162eb3[_0x4dfdec(0x1f4)][_0x4f97d2];else{function _0x597c2a(){var _0x16829f=_0x4dfdec;_0x68200f(_0x5bc7f4),_0x52ce08(_0x16829f(0x4b4));}}}catch(_0x49052a){}!_0x162eb3[_0x4dfdec(0x1b6)]&&setTimeout(function(){updateMixer();},0x1);if(typeof _0x1bf00b==_0x4dfdec(0x2bd))return;try{warnlog(_0x4dfdec(0x3dc));if(_0x1bf00b in _0x162eb3[_0x4dfdec(0x4f2)]){if(_0x4dfdec(0x48d)===_0x4dfdec(0x48d))log('watchTimeoutList:'+_0x1bf00b),clearTimeout(_0x162eb3[_0x4dfdec(0x4f2)][_0x1bf00b]);else{function _0xf63df5(){var _0x304bd8=_0x4dfdec;_0x4dde48[_0x304bd8(0x147)][_0x27c220[_0x304bd8(0x37c)]]['stats'][_0x304bd8(0x53f)]&&(_0x3c32a6[_0x304bd8(0x147)][_0x1b72ae[_0x304bd8(0x37c)]][_0x304bd8(0x14f)][_0x304bd8(0x53f)][_0x304bd8(0x1b6)]=!![]);}}}_0x162eb3[_0x4dfdec(0x4f2)][_0x1bf00b]=setTimeout(function(_0x4799d8){var _0x462c25=_0x4dfdec;delete _0x162eb3[_0x462c25(0x4f2)][_0x4799d8],log(_0x462c25(0x24c)+_0x4799d8),_0x162eb3[_0x462c25(0x39b)](_0x4799d8);},_0x162eb3['retryTimeout'],_0x1bf00b);}catch(_0x5a1b22){errorlog(_0x5a1b22);}pokeIframeAPI(_0x4dfdec(0x1d4),![],_0x4f97d2),updateUserList();};},_0x162eb3[_0x4f7b4e(0x443)]=function(_0x2a8350){var _0x32e078=_0x4f7b4e;try{var _0x47ba09=_0x162eb3[_0x32e078(0x303)]||0x0;_0x47ba09=parseFloat(_0x47ba09);if(_0x162eb3[_0x32e078(0x303)]!==![]){var _0x154206=_0x162eb3[_0x32e078(0x1f4)][_0x2a8350][_0x32e078(0x586)]()[_0x32e078(0x44b)](),_0x3b32c6=0x0;_0x154206[_0x32e078(0x204)](function(_0x131dce){var _0x2bb969=_0x32e078;try{if('aGAzt'===_0x2bb969(0x1d9))for(var _0x306d13 in _0x162eb3[_0x2bb969(0x1f4)][_0x2a8350][_0x2bb969(0x14f)]){if(typeof _0x162eb3[_0x2bb969(0x1f4)][_0x2a8350][_0x2bb969(0x14f)][_0x306d13]==_0x2bb969(0x1b1)&&_0x2bb969(0x180)in _0x162eb3[_0x2bb969(0x1f4)][_0x2a8350][_0x2bb969(0x14f)][_0x306d13]&&_0x162eb3['rpcs'][_0x2a8350][_0x2bb969(0x14f)][_0x306d13][_0x2bb969(0x180)]===_0x131dce[_0x2bb969(0x2ac)]['id']&&_0x2bb969(0x4b3)in _0x162eb3[_0x2bb969(0x1f4)][_0x2a8350][_0x2bb969(0x14f)][_0x306d13]){var _0x2c4a72=0x0;_0x162eb3['rpcs'][_0x2a8350][_0x2bb969(0x14f)][_0x306d13]['_sync_offset']?_0x2c4a72=_0x162eb3[_0x2bb969(0x1f4)][_0x2a8350][_0x2bb969(0x14f)][_0x306d13][_0x2bb969(0x1bd)]:_0x162eb3['rpcs'][_0x2a8350][_0x2bb969(0x14f)][_0x306d13][_0x2bb969(0x1bd)]=0x0;_0x2c4a72+=_0x47ba09-_0x162eb3['rpcs'][_0x2a8350][_0x2bb969(0x14f)][_0x306d13]['Buffer_Delay_in_ms'];_0x2c4a72>_0x47ba09&&(_0x2c4a72=_0x47ba09);if(_0x162eb3[_0x2bb969(0x1f4)][_0x2a8350][_0x2bb969(0x14f)][_0x306d13][_0x2bb969(0x1c0)]==_0x2bb969(0x25f)){if(_0x131dce[_0x2bb969(0x2ac)]['id']in _0x162eb3['rpcs'][_0x2a8350][_0x2bb969(0x2d0)]){log('updating\x20audio\x20delay');var _0x43bbb7=_0x3b32c6-_0x162eb3[_0x2bb969(0x1f4)][_0x2a8350]['stats'][_0x306d13][_0x2bb969(0x4b3)]+_0x162eb3[_0x2bb969(0x19b)];_0x43bbb7<0x0&&(_0x43bbb7=0x0),log(_0x2bb969(0x4ee)+_0x43bbb7),log(_0x2bb969(0x176)+_0x162eb3[_0x2bb969(0x1fa)][_0x2bb969(0x405)]),_0x162eb3['rpcs'][_0x2a8350]['delayNode'][_0x131dce[_0x2bb969(0x2ac)]['id']]['delayTime']['setValueAtTime'](parseFloat(_0x43bbb7/0x3e8),_0x162eb3[_0x2bb969(0x1fa)][_0x2bb969(0x405)]+0x1),_0x162eb3[_0x2bb969(0x1f4)][_0x2a8350][_0x2bb969(0x14f)][_0x306d13][_0x2bb969(0x348)]=_0x43bbb7;}}else _0x162eb3[_0x2bb969(0x1f4)][_0x2a8350][_0x2bb969(0x14f)][_0x306d13][_0x2bb969(0x1c0)]==_0x2bb969(0x3cb)&&(_0x3b32c6=_0x162eb3[_0x2bb969(0x1f4)][_0x2a8350][_0x2bb969(0x14f)][_0x306d13][_0x2bb969(0x4b3)],_0x2c4a72<0x0&&(_0x2c4a72=0x0),_0x162eb3[_0x2bb969(0x1f4)][_0x2a8350][_0x2bb969(0x14f)][_0x306d13][_0x2bb969(0x1bd)]=_0x2c4a72,_0x131dce[_0x2bb969(0xe7)]=parseFloat(_0x2c4a72/0x3e8));}}else{function _0x155a18(){var _0x1de9ed=_0x2bb969;if(typeof _0x504867['ws']!=='object'||_0x3ab8cd['ws'][_0x1de9ed(0x2bb)]!==0x1)_0x1e1f9c(_0x30f930,'could\x20not\x20be\x20sent;\x20queuing\x20it'),_0x426235[_0x1de9ed(0x360)][_0x1de9ed(0x21d)](_0x51d9cc);else{var _0xcd0392=_0x379657[_0x1de9ed(0x444)](_0x49c70c);if(_0xcd0392[_0x1de9ed(0x3f4)]>0x3a98){_0x576050(_0x1de9ed(0x559));return;}_0x5c25d1['ws'][_0x1de9ed(0x388)](_0xcd0392);}}}}catch(_0x2aa9c7){errorlog(_0x2aa9c7);}});}}catch(_0x30a121){errorlog('device\x20does\x20not\x20support\x20playout\x20delay');}},_0x162eb3[_0x4f7b4e(0x339)]=function(_0x25823a){var _0x542172=_0x4f7b4e;if(!(_0x25823a in _0x162eb3[_0x542172(0x1f4)]))return;try{_0x162eb3[_0x542172(0x1f4)][_0x25823a]['videoElement'][_0x542172(0x291)]&&(log(_0x542172(0x341)),_0x162eb3[_0x542172(0x1f4)][_0x25823a][_0x542172(0x340)][_0x542172(0x238)]()[_0x542172(0x57e)](_0x4423fb=>{var _0x501c4e=_0x542172;log(_0x501c4e(0x2ee)),firstPlayTriggered=!![];})[_0x542172(0x19f)](warnlog));}catch(_0x499baf){};try{_0x162eb3['rpcs'][_0x25823a]['getStats']()[_0x542172(0x57e)](function(_0x26c3ba){var _0x537bbc=_0x542172;setTimeout(_0x162eb3[_0x537bbc(0x339)],0xbb8,_0x25823a),!_0x162eb3[_0x537bbc(0x1f4)][_0x25823a][_0x537bbc(0x14f)][_0x537bbc(0x446)]&&(_0x162eb3[_0x537bbc(0x1f4)][_0x25823a][_0x537bbc(0x14f)][_0x537bbc(0x446)]={}),_0x26c3ba['forEach'](_0x2fa6d8=>{var _0x5af592=_0x537bbc;if(_0x2fa6d8[_0x5af592(0x3de)]=='candidate-pair'&&_0x2fa6d8[_0x5af592(0x474)]==!![])_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x5af592(0x446)][_0x5af592(0x18a)]=_0x2fa6d8[_0x5af592(0x430)],_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x5af592(0x446)]['_remote_ice_id']=_0x2fa6d8[_0x5af592(0x30b)],_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x5af592(0x446)][_0x5af592(0x349)]=_0x2fa6d8[_0x5af592(0x2d7)]*0x3e8;else{if(_0x2fa6d8[_0x5af592(0x3de)]==_0x5af592(0x2ac)&&_0x2fa6d8['remoteSource']==!![]){if(_0x2fa6d8['id']in _0x162eb3[_0x5af592(0x1f4)][_0x25823a]['stats']){_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8['id']]['_trackID']=_0x2fa6d8[_0x5af592(0x42d)],_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8['id']][_0x5af592(0x4b3)]=parseInt(0x3e8*(parseFloat(_0x2fa6d8[_0x5af592(0x2e4)])-_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8['id']][_0x5af592(0x516)])/(parseInt(_0x2fa6d8[_0x5af592(0x284)])-_0x162eb3['rpcs'][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8['id']][_0x5af592(0x45b)]))||0x0,_0x162eb3['rpcs'][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8['id']][_0x5af592(0x516)]=parseFloat(_0x2fa6d8[_0x5af592(0x2e4)])||0x0,_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8['id']][_0x5af592(0x45b)]=parseInt(_0x2fa6d8[_0x5af592(0x284)])||0x0;if(_0x5af592(0x108)in _0x2fa6d8){if('frameHeight'in _0x2fa6d8){if(_0x5af592(0x428)==='rqIAh'){function _0x4f7df1(){_0x5181ad(_0xddbf56);}}else _0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8['id']][_0x5af592(0xfa)]=_0x2fa6d8[_0x5af592(0x108)]+'\x20x\x20'+_0x2fa6d8[_0x5af592(0x297)],_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8['id']][_0x5af592(0x366)]=_0x2fa6d8[_0x5af592(0x108)],_0x162eb3[_0x5af592(0x1f4)][_0x25823a]['stats'][_0x2fa6d8['id']][_0x5af592(0x4b8)]=_0x2fa6d8['frameHeight'];}}}else{var _0x238eb9={};_0x238eb9[_0x5af592(0x516)]=parseFloat(_0x2fa6d8[_0x5af592(0x2e4)])||0x0,_0x238eb9[_0x5af592(0x45b)]=parseInt(_0x2fa6d8['jitterBufferEmittedCount'])||0x0,_0x238eb9[_0x5af592(0x4b3)]=0x0,_0x238eb9[_0x5af592(0x180)]=_0x2fa6d8['trackIdentifier'],_0x162eb3['rpcs'][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8['id']]=_0x238eb9;}}else{if(_0x2fa6d8[_0x5af592(0x3de)]=='remote-candidate'){if(_0x5af592(0x1ad)===_0x5af592(0x1ad)){if(_0x5af592(0x22a)in _0x162eb3['rpcs'][_0x25823a][_0x5af592(0x14f)][_0x5af592(0x446)]&&_0x162eb3[_0x5af592(0x1f4)][_0x25823a]['stats']['RTC\x20Connection'][_0x5af592(0x22a)]!=_0x2fa6d8['id'])return;_0x5af592(0x38f)in _0x2fa6d8&&('ip'in _0x2fa6d8&&(_0x162eb3[_0x5af592(0x1f4)][_0x25823a]['stats'][_0x5af592(0x446)][_0x5af592(0x21b)]=_0x2fa6d8['ip']),_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x5af592(0x446)][_0x5af592(0x552)]=_0x2fa6d8[_0x5af592(0x38f)]);_0x5af592(0x2f0)in _0x2fa6d8&&(_0x162eb3['rpcs'][_0x25823a][_0x5af592(0x14f)][_0x5af592(0x446)][_0x5af592(0x10d)]=_0x2fa6d8[_0x5af592(0x2f0)]);if(_0x5af592(0x3a4)in _0x2fa6d8){if('KYmPH'===_0x5af592(0x31c))_0x162eb3['rpcs'][_0x25823a]['stats']['RTC\x20Connection'][_0x5af592(0x530)]=_0x2fa6d8[_0x5af592(0x3a4)];else{function _0x3e3b7a(){_0xf8b4e3=!![];}}}}else{function _0xa0fd3e(){var _0x23b507=_0x5af592;_0x4b8b37(_0x23b507(0x53c));}}}else{if(_0x2fa6d8[_0x5af592(0x3de)]==_0x5af592(0x573)){if(_0x5af592(0x18a)in _0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x5af592(0x446)]&&_0x162eb3['rpcs'][_0x25823a][_0x5af592(0x14f)][_0x5af592(0x446)]['_local_ice_id']!=_0x2fa6d8['id'])return;_0x5af592(0x38f)in _0x2fa6d8&&('ip'in _0x2fa6d8&&(_0x162eb3['rpcs'][_0x25823a]['stats'][_0x5af592(0x446)][_0x5af592(0x47b)]=_0x2fa6d8['ip']),_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x5af592(0x446)][_0x5af592(0x56d)]=_0x2fa6d8['relayProtocol']);_0x5af592(0x2f0)in _0x2fa6d8&&(_0x162eb3['rpcs'][_0x25823a][_0x5af592(0x14f)][_0x5af592(0x446)][_0x5af592(0x212)]=_0x2fa6d8[_0x5af592(0x2f0)]);if(_0x5af592(0x3a4)in _0x2fa6d8){if(_0x5af592(0x19a)!==_0x5af592(0x19a)){function _0x39cc5c(){var _0x5837de=_0x5af592;_0x4ba063(_0x28bf66[_0x5837de(0x457)]),_0x21b30c[_0x5837de(0x457)]=_0x2fb5c6[_0x5837de(0xf7)](_0x81feec['sdp']);}}else _0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x5af592(0x446)][_0x5af592(0x530)]=_0x2fa6d8[_0x5af592(0x3a4)];}}else{if(_0x2fa6d8[_0x5af592(0x3de)]==_0x5af592(0x4ca)){_0x5af592(0xef)in _0x2fa6d8&&('_bytesReceived'in _0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x5af592(0x446)]&&(_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x5af592(0x446)][_0x5af592(0x233)]&&(_0x2fa6d8[_0x5af592(0x189)]&&(_0x162eb3[_0x5af592(0x1f4)][_0x25823a]['stats'][_0x5af592(0x446)][_0x5af592(0x28c)]=parseInt(0x8*(_0x2fa6d8[_0x5af592(0xef)]-_0x162eb3[_0x5af592(0x1f4)][_0x25823a]['stats'][_0x5af592(0x446)][_0x5af592(0xfc)])/(_0x2fa6d8['timestamp']-_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)]['RTC\x20Connection']['_timestamp']))))),_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x5af592(0x446)]['_bytesReceived']=_0x2fa6d8[_0x5af592(0xef)]);if(_0x5af592(0x189)in _0x2fa6d8){_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)]['RTC\x20Connection'][_0x5af592(0x233)]=_0x2fa6d8[_0x5af592(0x189)];if(!_0x162eb3[_0x5af592(0x1f4)][_0x25823a]['stats'][_0x5af592(0x446)][_0x5af592(0x3ed)])_0x162eb3[_0x5af592(0x1f4)][_0x25823a]['stats'][_0x5af592(0x446)][_0x5af592(0x3ed)]=_0x2fa6d8[_0x5af592(0x189)];else{if(_0x5af592(0x2b0)===_0x5af592(0x1ec)){function _0x2cf164(){var _0x486454=_0x5af592;_0x5aa2b6[_0x486454(0x512)][0x0][_0x486454(0x3b0)]=![];}}else _0x162eb3['rpcs'][_0x25823a][_0x5af592(0x14f)][_0x5af592(0x446)][_0x5af592(0x296)]=parseInt((_0x2fa6d8['timestamp']-_0x162eb3['rpcs'][_0x25823a]['stats'][_0x5af592(0x446)]['_timestampStart'])/0x258)/0x64;}}}else{if(_0x2fa6d8[_0x5af592(0x3de)]==_0x5af592(0x4ac)&&_0x5af592(0x395)in _0x2fa6d8){_0x162eb3[_0x5af592(0x1f4)][_0x25823a]['stats'][_0x2fa6d8[_0x5af592(0x395)]]=_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]]||{},_0x162eb3[_0x5af592(0x1f4)][_0x25823a]['stats'][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x398)]=parseInt(0x8*(_0x2fa6d8[_0x5af592(0xef)]-_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x1fe)])/(_0x2fa6d8[_0x5af592(0x189)]-_0x162eb3['rpcs'][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]]['_last_time'])),_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x1fe)]=_0x2fa6d8[_0x5af592(0xef)]||_0x162eb3['rpcs'][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8['trackId']][_0x5af592(0x1fe)],_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x40a)]=_0x2fa6d8['timestamp']||_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8['trackId']][_0x5af592(0x40a)],_0x162eb3[_0x5af592(0x1f4)][_0x25823a]['stats'][_0x5af592(0x346)]=_0x2fa6d8[_0x5af592(0x31e)],_0x162eb3['rpcs'][_0x25823a][_0x5af592(0x14f)][_0x5af592(0x48b)]=_0x2fa6d8['trackId'];if(_0x2fa6d8[_0x5af592(0x101)]==_0x5af592(0x3cb)){_0x162eb3[_0x5af592(0x1f4)][_0x25823a]['stats'][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x3de)]=_0x5af592(0x378),_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x1c0)]='video';if(_0x162eb3[_0x5af592(0x424)]&&'codec'in _0x162eb3['rpcs'][_0x25823a][_0x5af592(0x14f)]&&_0x162eb3['rpcs'][_0x25823a][_0x5af592(0x14f)][_0x5af592(0x1d2)]==_0x5af592(0x578)){_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x431)]=_0x2fa6d8[_0x5af592(0x350)]-_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8['trackId']][_0x5af592(0x476)]||0x0,_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x53a)]=_0x2fa6d8[_0x5af592(0x19c)]-_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x4a4)]+_0x162eb3[_0x5af592(0x1f4)][_0x25823a]['stats'][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x53a)]||0x0,log(_0x5af592(0x53e));if(_0x162eb3['rpcs'][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x431)]===0x0&&_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]]['nackTrigger']>=_0x162eb3['obsfix'])_0x162eb3[_0x5af592(0x1a9)](_0x25823a),_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]]['nackTrigger']=0x0,log(_0x5af592(0x2f4));else _0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]]['pliDelta']>0x0&&(_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x53a)]=0x0);}else{if(_0x162eb3[_0x5af592(0x424)]&&_0x5af592(0x1d2)in _0x162eb3[_0x5af592(0x1f4)][_0x25823a]['stats']&&_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x5af592(0x1d2)]==_0x5af592(0x227)){_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x431)]=_0x2fa6d8[_0x5af592(0x350)]-_0x162eb3['rpcs'][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]]['keyFramesRequested_pli']||0x0,_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x53a)]=_0x2fa6d8[_0x5af592(0x19c)]-_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x4a4)]+_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8['trackId']][_0x5af592(0x53a)]||0x0,log(_0x5af592(0x53e));if(_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x431)]===0x0&&_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x53a)]>=_0x162eb3[_0x5af592(0x424)]*0x4)_0x162eb3[_0x5af592(0x1a9)](_0x25823a),_0x162eb3['rpcs'][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x53a)]=0x0,log(_0x5af592(0x2f4));else _0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8['trackId']][_0x5af592(0x431)]>0x0&&(_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8['trackId']][_0x5af592(0x53a)]=0x0);}}_0x162eb3['rpcs'][_0x25823a]['stats'][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x476)]=_0x2fa6d8[_0x5af592(0x350)]||0x0,_0x162eb3[_0x5af592(0x1f4)][_0x25823a]['stats'][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x4a4)]=_0x2fa6d8[_0x5af592(0x19c)]||0x0;if(_0x5af592(0x1e4)in _0x2fa6d8){if(_0x5af592(0x49d)===_0x5af592(0x19e)){function _0x2a1d57(){var _0x1d2d87=_0x5af592;_0x361ac6[_0x1d2d87(0x53f)][_0x1d2d87(0x30a)]&&_0x1c3500(_0x4e6f77);}}else _0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x435)]=parseInt(_0x2fa6d8[_0x5af592(0x1e4)]);}else{if(_0x5af592(0x432)in _0x2fa6d8&&_0x2fa6d8['timestamp']){var _0x2ef192=0x0,_0x1465a4=0x0;try{_0x2ef192=_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x4e5)],_0x1465a4=_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x233)];}catch(_0x445372){}_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x435)]=parseInt(0xa*(_0x2fa6d8[_0x5af592(0x432)]-_0x2ef192)/(_0x2fa6d8[_0x5af592(0x189)]/0x3e8-_0x1465a4))/0xa,_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8['trackId']][_0x5af592(0x4e5)]=_0x2fa6d8[_0x5af592(0x432)],_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]]['_timestamp']=_0x2fa6d8[_0x5af592(0x189)]/0x3e8;}}}else{if(_0x2fa6d8[_0x5af592(0x101)]==_0x5af592(0x25f)){_0x162eb3['rpcs'][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x3de)]=_0x5af592(0x54a),_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x1c0)]=_0x5af592(0x25f);if(_0x5af592(0x1ce)in _0x2fa6d8){if(_0x5af592(0x3fb)==='Rpahq'){function _0x23be84(){var _0x2fb7bd=_0x5af592;_0x30fdb3[_0x2fb7bd(0x2ac)][_0x2fb7bd(0x2f1)]=![];}}else _0x162eb3['rpcs'][_0x25823a]['stats'][_0x2fa6d8['trackId']][_0x5af592(0x501)]=parseInt(parseFloat(_0x2fa6d8['audioLevel'])*0x2710)/0x2710;}}}_0x5af592(0x408)in _0x2fa6d8&&_0x5af592(0x31a)in _0x2fa6d8&&(!(_0x5af592(0x1f1)in _0x162eb3['rpcs'][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]])&&(_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x1f1)]=_0x2fa6d8['packetsLost']),!(_0x5af592(0x4d5)in _0x162eb3[_0x5af592(0x1f4)][_0x25823a]['stats'][_0x2fa6d8[_0x5af592(0x395)]])&&(_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x4d5)]=_0x2fa6d8['packetsReceived']),!(_0x5af592(0x486)in _0x162eb3['rpcs'][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]])&&(_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x486)]=0x0),_0x162eb3[_0x5af592(0x1f4)][_0x25823a]['stats'][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x486)]=_0x162eb3['rpcs'][_0x25823a]['stats'][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x486)]*0.35+0.65*((_0x2fa6d8[_0x5af592(0x408)]-_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x1f1)])*0x64)/(_0x2fa6d8[_0x5af592(0x31a)]-_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x4d5)]+(_0x2fa6d8[_0x5af592(0x408)]-_0x162eb3['rpcs'][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x1f1)]))||0x0,_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]]['_packetsReceived']=_0x2fa6d8[_0x5af592(0x31a)],_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x2fa6d8[_0x5af592(0x395)]][_0x5af592(0x1f1)]=_0x2fa6d8[_0x5af592(0x408)]);}else{if('_codecId'in _0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)]&&_0x2fa6d8['id']==_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x5af592(0x346)]){_0x5af592(0x53d)in _0x2fa6d8&&(_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x5af592(0x48b)]]?_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x162eb3[_0x5af592(0x1f4)][_0x25823a]['stats'][_0x5af592(0x48b)]][_0x5af592(0x1d2)]=_0x2fa6d8['mimeType']:(_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x162eb3[_0x5af592(0x1f4)][_0x25823a]['stats'][_0x5af592(0x48b)]]={},_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x5af592(0x48b)]][_0x5af592(0x1d2)]=_0x2fa6d8[_0x5af592(0x53d)]));if(_0x5af592(0x297)in _0x2fa6d8){if(_0x5af592(0x108)in _0x2fa6d8){if(_0x5af592(0x3e8)!=='elUNs'){function _0x55d2bf(){var _0x51a5c1=_0x5af592;_0x458da3[_0x51a5c1(0x147)][_0x170144[_0x51a5c1(0x37c)]][_0x51a5c1(0x14f)]['info']&&(_0x48d4fd[_0x51a5c1(0x147)][_0x5e54db[_0x51a5c1(0x37c)]][_0x51a5c1(0x14f)][_0x51a5c1(0x53f)][_0x51a5c1(0x1b6)]=!![]);}}else _0x162eb3[_0x5af592(0x1f4)][_0x25823a][_0x5af592(0x14f)][_0x5af592(0xfa)]=parseInt(_0x2fa6d8[_0x5af592(0x108)])+_0x5af592(0x415)+parseInt(_0x2fa6d8[_0x5af592(0x297)]);}}}}}}}}}}),_0x162eb3[_0x537bbc(0x303)]!==![]&&_0x162eb3[_0x537bbc(0x443)](_0x25823a),setTimeout(function(){var _0x1706e2=_0x537bbc;_0x162eb3[_0x1706e2(0x4ba)](),_0x162eb3[_0x1706e2(0x51e)]();},0x0);});}catch(_0x4f7832){errorlog(_0x4f7832);}},_0x162eb3[_0x4f7b4e(0x1f4)][_0x4f97d2][_0x4f7b4e(0x25a)]=_0x195194=>{var _0x3f4ad9=_0x4f7b4e;log('New\x20ON\x20TRACK\x20event');if(_0x162eb3[_0x3f4ad9(0x303)]!==![]){if('DTlEf'!==_0x3f4ad9(0x479)){function _0x38ab12(){_0x20395c('already\x20closed\x20PCS');}}else _0x162eb3[_0x3f4ad9(0x443)](_0x4f97d2);}_0x162eb3[_0x3f4ad9(0x4ba)](),_0x162eb3[_0x3f4ad9(0x51e)]();if(_0x195194['streams']&&_0x195194[_0x3f4ad9(0x3f9)][0x0]){_0x195194[_0x3f4ad9(0x3f9)][0x0][_0x3f4ad9(0x15a)]=function(_0x3e4f4b){var _0x2bbc46=_0x3f4ad9;try{if(_0x2bbc46(0x182)===_0x2bbc46(0x20c)){function _0x3da866(){var _0x3b0fcf=_0x2bbc46;_0x2a100b(_0x3b0fcf(0x28d));}}else warnlog('Track\x20was\x20removed'),_0x162eb3[_0x2bbc46(0x1f4)][_0x4f97d2][_0x2bbc46(0x3d0)][_0x2bbc46(0x2fc)]()[_0x2bbc46(0x204)](_0x4fcf5e=>{var _0x31cd4f=_0x2bbc46;_0x4fcf5e['id']==_0x3e4f4b[_0x31cd4f(0x2ac)]['id']&&_0x162eb3[_0x31cd4f(0x1f4)][_0x4f97d2]['streamSrc']['removeTrack'](_0x4fcf5e);}),_0x162eb3[_0x2bbc46(0x1f4)][_0x4f97d2][_0x2bbc46(0x340)]['srcObject']=_0x162eb3[_0x2bbc46(0x1f4)][_0x4f97d2][_0x2bbc46(0x3d0)],setTimeout(function(){updateMixer();},0x1);}catch(_0x503d5b){}},_0x195194[_0x3f4ad9(0x3f9)][0x0][_0x3f4ad9(0x409)]=function(_0x1c2e84){var _0x4293f5=_0x3f4ad9;try{warnlog(_0x4293f5(0x1fc)),_0x162eb3[_0x4293f5(0x1f4)][_0x4f97d2][_0x4293f5(0x3d0)][_0x4293f5(0x2fc)]()[_0x4293f5(0x204)](_0x4d1d72=>{var _0x417a27=_0x4293f5;_0x4d1d72['id']==_0x1c2e84[_0x417a27(0x2ac)]['id']&&_0x162eb3[_0x417a27(0x1f4)][_0x4f97d2][_0x417a27(0x3d0)][_0x417a27(0x4dc)](_0x4d1d72);}),_0x162eb3[_0x4293f5(0x1f4)][_0x4f97d2][_0x4293f5(0x340)][_0x4293f5(0x288)]=_0x162eb3[_0x4293f5(0x1f4)][_0x4f97d2][_0x4293f5(0x3d0)];}catch(_0x1fe405){};};var _0x58321f=_0x195194['streams'][0x0][_0x3f4ad9(0x2fc)]()[_0x3f4ad9(0x3f4)];_0x58321f>0x1&&errorlog(_0x3f4ad9(0x55a));}if(_0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2]['videoElement']){if(_0x195194[_0x3f4ad9(0x3f9)]&&_0x195194[_0x3f4ad9(0x3f9)][0x0]){if(!_0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2][_0x3f4ad9(0x3d0)]){if(_0x3f4ad9(0x234)===_0x3f4ad9(0x234))_0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2][_0x3f4ad9(0x3d0)]=_0x195194[_0x3f4ad9(0x3f9)][0x0];else{function _0x6054a3(){var _0x10caa2=_0x3f4ad9;_0x10eab1[_0x10caa2(0x147)][_0x239d13['directorUUID']][_0x10caa2(0x14f)][_0x10caa2(0x53f)]['director']=!![];}}}else{var _0x4d8413=![];_0x195194[_0x3f4ad9(0x3f9)][0x0]['getTracks']()[_0x3f4ad9(0x204)](_0x29ebfe=>{var _0x1da702=_0x3f4ad9;_0x4d8413&&(warnlog(_0x1da702(0x55d)),warnlog(_0x29ebfe)),_0x29ebfe[_0x1da702(0x2c3)]==_0x1da702(0x3cb)&&(_0x162eb3['rpcs'][_0x4f97d2][_0x1da702(0x3d0)][_0x1da702(0x2fc)]()[_0x1da702(0x204)](_0x135695=>{var _0x46571f=_0x1da702;_0x162eb3['rpcs'][_0x4f97d2][_0x46571f(0x3d0)][_0x46571f(0x4dc)](_0x135695);}),_0x4d8413=!![]),log(_0x1da702(0x385)),_0x162eb3['rpcs'][_0x4f97d2][_0x1da702(0x3d0)][_0x1da702(0x496)](_0x29ebfe);});}try{if(_0x3f4ad9(0x251)===_0x3f4ad9(0x1bb)){function _0x80aab0(){_0x3b3c5b(_0x427c96),_0x3d4399(_0xa0f94f);}}else _0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2][_0x3f4ad9(0x340)][_0x3f4ad9(0x288)]=_0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2][_0x3f4ad9(0x3d0)];}catch(_0x27dea1){errorlog('4722');}log(_0x3f4ad9(0x44a));}else{if(_0x195194[_0x3f4ad9(0x2ac)]){if('oylvJ'===_0x3f4ad9(0x27a)){function _0x538e78(){_0x5f5576(_0x549eaa);}}else{warnlog(_0x3f4ad9(0x580));!_0x162eb3['rpcs'][_0x4f97d2][_0x3f4ad9(0x3d0)]?_0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2][_0x3f4ad9(0x3d0)]=new MediaStream():_0x195194[_0x3f4ad9(0x2ac)][_0x3f4ad9(0x2c3)]==_0x3f4ad9(0x3cb)&&_0x162eb3['rpcs'][_0x4f97d2][_0x3f4ad9(0x3d0)][_0x3f4ad9(0x2fc)]()['forEach'](_0x4ce975=>{var _0x3f9769=_0x3f4ad9;_0x162eb3[_0x3f9769(0x1f4)][_0x4f97d2][_0x3f9769(0x3d0)][_0x3f9769(0x4dc)](_0x4ce975);});_0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2][_0x3f4ad9(0x3d0)]['addTrack'](_0x195194[_0x3f4ad9(0x2ac)]);try{_0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2][_0x3f4ad9(0x340)][_0x3f4ad9(0x288)]=_0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2][_0x3f4ad9(0x3d0)];}catch(_0x341ba4){errorlog('4722');}}}else{if(_0x3f4ad9(0x11c)!==_0x3f4ad9(0x355))errorlog('NO\x20TRACK??\x20--\x20not\x20expected');else{function _0x102f03(){_0x60d1fd(_0x5d89bd);}}}}setTimeout(function(){updateMixer();},0x1);}else{log(_0x3f4ad9(0x1c2));var _0x39a3d1=document[_0x3f4ad9(0x4da)]('video');_0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2][_0x3f4ad9(0x340)]=_0x39a3d1,_0x39a3d1[_0x3f4ad9(0x4e1)][_0x3f4ad9(0x1e2)]=_0x4f97d2,_0x39a3d1['id']='videosource_'+_0x4f97d2;_0x162eb3['rpcs'][_0x4f97d2]['streamID']&&(_0x39a3d1['dataset'][_0x3f4ad9(0x1bf)]=_0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2][_0x3f4ad9(0x34f)]);setupIncomingVideoTracking(_0x39a3d1,_0x4f97d2);if(_0x195194['streams']&&_0x195194['streams'][0x0]){var _0x2d9d09=_0x195194[_0x3f4ad9(0x3f9)][0x0];_0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2][_0x3f4ad9(0x3d0)]=_0x195194[_0x3f4ad9(0x3f9)][0x0],_0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2][_0x3f4ad9(0x340)][_0x3f4ad9(0x288)]=_0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2][_0x3f4ad9(0x3d0)],log(_0x3f4ad9(0x44a));}else{if(_0x195194[_0x3f4ad9(0x2ac)]){if(_0x3f4ad9(0x3f2)!==_0x3f4ad9(0x363))warnlog(_0x3f4ad9(0x580)),!_0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2][_0x3f4ad9(0x3d0)]&&(_0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2][_0x3f4ad9(0x3d0)]=new MediaStream()),_0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2]['streamSrc'][_0x3f4ad9(0x496)](_0x195194[_0x3f4ad9(0x2ac)]),_0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2][_0x3f4ad9(0x340)][_0x3f4ad9(0x288)]=_0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2][_0x3f4ad9(0x3d0)];else{function _0x16ea2a(){var _0x3971af=_0x3f4ad9;if(_0x3b17d5[_0x3971af(0x475)])return;}}}}if(_0x162eb3['scale']){var _0x40fa09={};_0x40fa09[_0x3f4ad9(0x3ea)]=parseInt(_0x162eb3[_0x3f4ad9(0x3ea)]),log(_0x40fa09),_0x162eb3[_0x3f4ad9(0x196)](_0x40fa09,_0x4f97d2);}}if(_0x162eb3['audioEffects']===!![]){var _0x574586=function(_0x1143cf){var _0x2b3453=_0x3f4ad9;if(_0x2b3453(0x497)!==_0x2b3453(0x497)){function _0x2cc3d3(){var _0x10e5fc=_0x2b3453;_0x3f13b1['webp']?(_0x2d3d28['broadcast']=!![],_0x52e8ef['video']=![]):_0x5259ac[_0x10e5fc(0x3cb)]=!![];}}else{var _0x5700a6=function(_0x2d2d1b){var _0x59f6ff=_0x2b3453;if(!_0x162eb3['rpcs'][_0x2d2d1b])return;var _0x8aa3a3=_0x162eb3['rpcs'][_0x2d2d1b][_0x59f6ff(0x340)][_0x59f6ff(0x253)];_0x162eb3[_0x59f6ff(0x1f4)][_0x2d2d1b][_0x59f6ff(0x340)][_0x59f6ff(0x253)]=![],_0x162eb3[_0x59f6ff(0x1f4)][_0x2d2d1b][_0x59f6ff(0x340)][_0x59f6ff(0x365)](_0x59f6ff(0x238),_0x5700a6);_0x162eb3[_0x59f6ff(0x1fa)][_0x59f6ff(0x487)]==_0x59f6ff(0x4cc)&&_0x162eb3[_0x59f6ff(0x1fa)][_0x59f6ff(0x335)]();var _0x1432d8=_0x162eb3[_0x59f6ff(0x1f4)][_0x2d2d1b][_0x59f6ff(0x3d0)][_0x59f6ff(0x28e)]();if(_0x1432d8[_0x59f6ff(0x3f4)]){var _0x46c622=_0x1432d8[0x0];if(_0x46c622[_0x59f6ff(0x2fa)]!=_0x59f6ff(0x2b8)){if('jfpwe'!==_0x59f6ff(0x37e)){function _0x315050(){var _0x52ba77=_0x59f6ff;_0x252aaf[_0x31c2c4][_0x52ba77(0x2ac)]['enabled']=!_0x2ac1b3[_0x52ba77(0x30a)];}}else _0x162eb3[_0x59f6ff(0x1f4)][_0x2d2d1b][_0x59f6ff(0x340)][_0x59f6ff(0x288)]=addAudioPipeline(_0x162eb3[_0x59f6ff(0x1f4)][_0x2d2d1b][_0x59f6ff(0x3d0)],_0x2d2d1b,_0x46c622);}}else _0x162eb3[_0x59f6ff(0x1f4)][_0x2d2d1b]['videoElement'][_0x59f6ff(0x288)]=_0x162eb3['rpcs'][_0x2d2d1b][_0x59f6ff(0x3d0)];_0x162eb3[_0x59f6ff(0x1f4)][_0x2d2d1b][_0x59f6ff(0x340)][_0x59f6ff(0x253)]=_0x8aa3a3,delete _0x162eb3[_0x59f6ff(0x1f4)][_0x2d2d1b][_0x59f6ff(0x1e1)],_0x59f6ff(0x1e1)in _0x162eb3[_0x59f6ff(0x1f4)][_0x2d2d1b]&&errorlog(_0x59f6ff(0x219));};return _0x5700a6(_0x1143cf);}};_0x162eb3[_0x3f4ad9(0x1fa)]['state']==_0x3f4ad9(0x4a3)&&(_0x162eb3[_0x3f4ad9(0x3ff)]=!![]);if(_0x3f4ad9(0x1e1)in _0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2]){}else _0x162eb3[_0x3f4ad9(0x3ff)]==![]?_0x162eb3['rpcs'][_0x4f97d2][_0x3f4ad9(0x1e1)]=setInterval(function(_0x2b2a5a){var _0x5daa3e=_0x3f4ad9;log('..\x20waiting\x20for\x20user\x20gesture'),_0x162eb3[_0x5daa3e(0x1f4)][_0x2b2a5a]&&(_0x162eb3[_0x5daa3e(0x3ff)]&&(clearInterval(_0x162eb3['rpcs'][_0x2b2a5a][_0x5daa3e(0x1e1)]),_0x162eb3[_0x5daa3e(0x1f4)][_0x2b2a5a][_0x5daa3e(0x340)]['addEventListener'](_0x5daa3e(0x238),_0x574586(_0x2b2a5a))));},0x3e8,_0x4f97d2):(!_0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2][_0x3f4ad9(0x1e1)]&&(_0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2]['eventPlayActive']=!![]),_0x162eb3[_0x3f4ad9(0x1f4)][_0x4f97d2][_0x3f4ad9(0x340)][_0x3f4ad9(0x1b8)](_0x3f4ad9(0x238),_0x574586(_0x4f97d2)));}_0x162eb3[_0x3f4ad9(0x4ba)](),_0x162eb3[_0x3f4ad9(0x51e)](),updateUserList();},log(_0x4f7b4e(0x3a7));},_0x162eb3;}();
\ No newline at end of file