mirror of
https://github.com/eliasstepanik/vdo.ninja.git
synced 2026-01-11 21:58:35 +00:00
transfer and room settings expanded
This commit is contained in:
parent
944033c683
commit
7659b6ec3e
72
index.html
72
index.html
@ -67,7 +67,7 @@
|
||||
<link itemprop="url" href="./media/vdoNinja_logo_full.png" />
|
||||
</span>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/CodecsHandler.js?ver=34"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=327"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./webrtc.js?ver=328"></script>
|
||||
<input id="zoomSlider" type="range" style="display: none;" />
|
||||
<div id="header">
|
||||
|
||||
@ -1624,8 +1624,28 @@
|
||||
<span style="margin-left: 6px;" id="trbSettingInputFeedback"></span>-kbps
|
||||
<input id="trbSettingInput" type="range" min="0" max="4000" value="500" onchange="changeTRB(this);" oninput="getById('trbSettingInputFeedback').innerHTML = this.value;" style="width:100%;display:block;" />
|
||||
<span style="margin: 20px 0 0 0;display:block" id='highlightDirectorSpan' title="Only the director's video will be visible to guests and within group scenes">
|
||||
<label for="highlightDirector">Highlight Director (only video guests will see)</label>
|
||||
<input id="highlightDirector" style="width: 15px; height: 15px; margin:10px;" name="highlightDirector" data-value="0" data-action-type="solo-video" type="checkbox" onchange="requestInfocus(this);" />
|
||||
<label for="highlightDirector">Highlight Director (only video guests will see)</label>
|
||||
</span>
|
||||
<span style="margin: 5px 0 0 0;display:block" id='enableCodirector' title="Allow for remote co-directors">
|
||||
<span id="coDirectorEnableSpan">
|
||||
<input id="coDirectorEnable" style="width: 15px; height: 15px; margin:10px;" name="coDirectorEnable" data-value="0" data-action-type="codirector" type="checkbox" onchange="toggleCoDirector(this);" />
|
||||
<label for="coDirectorEnable">Allow for remote co-directors</label>
|
||||
</span>
|
||||
<span style="margin:0;display:none;" id='codirectorSettings'>
|
||||
<div>
|
||||
<input id="codirectorSettings_transfer" style="width: 15px; height: 15px; margin:10px;" name="codirectorSettings_transfer" data-value="0" data-action-type="codirector_transfer" type="checkbox" onchange="toggleCoDirector_transfer(this);" />
|
||||
<label for="codirectorSettings_transfer">Allow co-directors to transfer guests</label>
|
||||
</div>
|
||||
<div style="display:none;">
|
||||
<input id="codirectorSettings_changeurl" style="width: 15px; height: 15px; margin:10px; " name="codirectorSettings_changeurl" data-value="0" data-action-type="codirector_changeurl" type="checkbox" onchange="toggleCoDirector_changeurl(this);" />
|
||||
<label for="codirectorSettings_changeurl">Allow co-directors to change a guest's URL</label>
|
||||
</div>
|
||||
<div style="margin:8px;">
|
||||
<label for="codirectorSettings_invite">Basic co-director invite link:</label>
|
||||
<input id="codirectorSettings_invite" style="display:block;width: 100%;margin: 3px 0; padding: 4px 5px 3px 5px; border: 1px solid black;" name="codirectorSettings_invite" value="some URL here" type="text" />
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -1817,41 +1837,41 @@
|
||||
///// The following lets you set the defaults
|
||||
|
||||
// session.webcamonly // true,false
|
||||
// session.stereo // 0,1,2,3
|
||||
// session.stereo // 0,1,2,3,4,5
|
||||
// session.audiobitrate // int in kbps
|
||||
// session.view // "xxxx"
|
||||
// session.remote
|
||||
// session.optimize
|
||||
// session.disableOBS
|
||||
// session.audio
|
||||
// session.video
|
||||
// session.forceios
|
||||
// session.nocursor
|
||||
// session.view // "xxxx" ; the stream ID or a list of Stream IDs to Connect to. Not the same as &noaudio/&novideo. Set to "" (empty) if you don't wish to connect to any.
|
||||
// session.remote // See docs, but allows for remote stats monitoring and remote focus/zoom control
|
||||
// session.optimize // Whether to optimize invisible scenes in OBS. See docs.vdo.ninja
|
||||
// session.disableOBS // If true, will disable any OBS-specific events/functions.
|
||||
// session.noaudio // False by default, otherwise specify a list [] of stream IDs to allow. Listing none allows no incoming audio streams
|
||||
// session.novideo // False by default, otherwise specify a list [] of stream IDs to allow. Listing none allows no incoming video streams
|
||||
// session.forceios // If true, will allow iOS devices to send H264 video to other guests in a room
|
||||
// session.nocursor // hides the cursor using CSS
|
||||
// session.codec // default codec; maybe h264 is useful? the default is up to the browser normally
|
||||
// session.scale
|
||||
// session.scale // By default, scale is self-optimizing, but you can set a value of 1 to 100 to choose the playback scale of all incoming video streams
|
||||
// session.bitrate // int in kbps -- you can set the default max target bitrate here
|
||||
// session.totalRoomBitrate = 500; // int, kbps -- you can set the default quality of the group room here
|
||||
// session.height // int
|
||||
// session.width // int
|
||||
// session.quality // int -- if setting == 0, then than the default resolution will be 1080p, instead of 720p
|
||||
// session.sink
|
||||
// session.offsetChannel //2 int
|
||||
// session.height // int ; height to publish a video stream at. Will fail if not supported by the camera
|
||||
// session.width // int ; see above
|
||||
// session.quality // int -- if setting == 0, then than the default resolution will be 1080p, instead of 720p60 (q=1) , while q=2 = 360p30.
|
||||
// session.sink // Output device to playback audio to. see the docs
|
||||
// session.offsetChannel // int
|
||||
// session.audioChannels // int
|
||||
// session.security
|
||||
// session.framerate // int
|
||||
// session.sync
|
||||
// session.buffer // int in milliseconds
|
||||
// session.roomid // "yyyy"
|
||||
// session.scene
|
||||
// session.title // "zzzz"
|
||||
// session.security // true to disable the wss connection after the first peer connection is made
|
||||
// session.framerate // int ; publishing frame rate. will fail if camera does not support it.
|
||||
// session.sync // see the docs
|
||||
// session.buffer // int in milliseconds ; see the docs
|
||||
// session.roomid // "yyyy" -- the room name to use. alphanumeric.
|
||||
// session.scene // the scene name. Scene 0, 1, ... 8, or any custom scene name is supported. STRING value. Needed to have a clean view link of a guest stream
|
||||
// session.title // "zzzz" ; sets the title of the browser page.
|
||||
// session.introOnClean = true; // this will load the page with the webcam selection screen if &push or &room is in the URL; no need to use &webcam.
|
||||
</script>
|
||||
<script type="text/javascript" crossorigin="anonymous" src="./thirdparty/aes.js"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="lib-js" src="./lib.js?ver=205"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="lib-js" src="./lib.js?ver=206"></script>
|
||||
<!--
|
||||
// If you wish to change branding, blank offers a good clean start.
|
||||
<script type="text/javascript" id="main-js" src="./main.js" data-translation="blank"></script>
|
||||
-->
|
||||
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=277"></script>
|
||||
<script type="text/javascript" crossorigin="anonymous" id="main-js" src="./main.js?ver=278"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
510
lib.js
510
lib.js
@ -56,7 +56,7 @@ var miscTranslations = {
|
||||
"allowed-chars" : "Allowed chars",
|
||||
"transfer" : "transfer",
|
||||
"armed" : "armed",
|
||||
"transfer-guest-to-room" : "Transfer guests to room:\n\n(Please note rooms must share the same password)",
|
||||
"transfer-guest-to-room" : "Transfer guests to room:\n\n(Please note: rooms must share the same password)",
|
||||
"transfer-guest-to-url" :"Transfer guests to new website URL.\n\n(Guests will be prompted to accept)",
|
||||
"change-url" : "change URL",
|
||||
"mute-in-scene" : "mute in scene",
|
||||
@ -70,7 +70,9 @@ var miscTranslations = {
|
||||
"unhide" : "unhide guest",
|
||||
"hide-guest": "hide guest",
|
||||
"confirm-disconnect-users": "Are you sure you wish to disconnect these users?",
|
||||
"confirm-disconnect-user": "Are you sure you wish to disconnect this user?"
|
||||
"confirm-disconnect-user": "Are you sure you wish to disconnect this user?",
|
||||
"enter-new-codirector-password": "Enter a co-director password to use",
|
||||
"control-room-co-director": "Control Room: Co-Director"
|
||||
};
|
||||
|
||||
// function log(msg){ // uncomment to enable logging.
|
||||
@ -348,7 +350,7 @@ async function delay(ms) {
|
||||
}
|
||||
|
||||
var Prompts = {};
|
||||
async function promptAlt(inputText, block=false, asterix=false){
|
||||
async function promptAlt(inputText, block=false, asterix=false, value=false){
|
||||
var result = null;
|
||||
if (session.beepToNotify){
|
||||
playtone();
|
||||
@ -373,12 +375,14 @@ async function promptAlt(inputText, block=false, asterix=false){
|
||||
if (asterix){
|
||||
type = "password";
|
||||
}
|
||||
|
||||
|
||||
modalTemplate =
|
||||
`<div id="modal_${promptID}" class="promptModal" style="z-index:${zindex + 2}">
|
||||
<div class="promptModalInner">
|
||||
<span id="close_${promptID}" class='modalClose' data-pid="${promptID}">×</span>
|
||||
<span class='promptModalMessage'>${inputText}</span>
|
||||
<input id="input_${promptID}" data-pid="${promptID}" type="${type}" class="largeTextEntry" />
|
||||
<input id="input_${promptID}" data-pid="${promptID}" type="${type}" class="largeTextEntry" />
|
||||
<button id="submit_${promptID}" data-pid="${promptID}" style="width:120px; background-color: #fff; position: relative;border: 1px solid #999; margin: 0 0 0 55px;" data-translate='ok'>✔ OK</button>
|
||||
<button id="cancel_${promptID}" data-pid="${promptID}" style="width:120px; background-color: #fff; position: relative;border: 1px solid #999; margin: 0;" data-translate='cancel'>❌ Cancel</button>
|
||||
</div>
|
||||
@ -390,6 +394,10 @@ async function promptAlt(inputText, block=false, asterix=false){
|
||||
|
||||
document.getElementById("input_"+promptID).focus();
|
||||
|
||||
if (value!==false){
|
||||
document.getElementById("input_"+promptID).value = value;
|
||||
}
|
||||
|
||||
document.getElementById("input_"+promptID).addEventListener("keyup", function(event) {
|
||||
if (event.key === "Enter") {
|
||||
var pid = event.target.dataset.pid;
|
||||
@ -431,6 +439,102 @@ async function promptAlt(inputText, block=false, asterix=false){
|
||||
return result;
|
||||
}
|
||||
|
||||
async function promptTransfer(value=null, bcmode = null, updateurl = null){
|
||||
var result = {room:null};
|
||||
if (session.beepToNotify){
|
||||
playtone();
|
||||
}
|
||||
await new Promise((resolve, reject) => {
|
||||
var promptID = "pid_"+Math.random().toString(36).substr(2, 9);
|
||||
Prompts[promptID] = {};
|
||||
Prompts[promptID].resolve = resolve;
|
||||
Prompts[promptID].reject = reject;
|
||||
|
||||
var zindex = 30 + document.querySelectorAll('.promptModal').length;
|
||||
var backdropClass = "modalBackdrop";
|
||||
|
||||
var inputText = "<font style='font-size:1.2em'>"+(miscTranslations["transfer-guest-to-room"].replace("\n","</font><br /><font>"))+"</font>";
|
||||
inputText = inputText.replace(/\n/g,"<br />");
|
||||
|
||||
modalTemplate =
|
||||
`<div id="modal_${promptID}" class="promptModal" style="z-index:${zindex + 2}">
|
||||
<div class="promptModalInner">
|
||||
<span id="close_${promptID}" class='modalClose' data-pid="${promptID}">×</span>
|
||||
<span class='promptModalMessage'>${inputText}</span>
|
||||
<input id="input_${promptID}" data-pid="${promptID}" type="text" class="largeTextEntry" />
|
||||
<span class='promptModalLabel'><input id="private_${promptID}" data-pid="${promptID}" type="checkbox" title="Note: this won't work fully if using obfuscated links" /> Allow the guest to rejoin the transfer room on their own</span>
|
||||
<span class='promptModalLabel'><input id="broadcast_${promptID}" data-pid="${promptID}" type="checkbox" /> Guest will arrive in the new room in <i>broadcast</i> mode</span>
|
||||
<button id="submit_${promptID}" data-pid="${promptID}" style="width:120px; background-color: #fff; position: relative;border: 1px solid #999; margin: 0 0 0 55px;" data-translate='ok'>✔ OK</button>
|
||||
<button id="cancel_${promptID}" data-pid="${promptID}" style="width:120px; background-color: #fff; position: relative;border: 1px solid #999; margin: 0;" data-translate='cancel'>❌ Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="modalBackdrop_${promptID}" class="${backdropClass}" style="z-index:${zindex + 1}"></div>`;
|
||||
|
||||
|
||||
document.body.insertAdjacentHTML("beforeend", modalTemplate); // Insert modal at body end
|
||||
|
||||
document.getElementById("input_"+promptID).focus();
|
||||
|
||||
if (value!==null){
|
||||
document.getElementById("input_"+promptID).value = value;
|
||||
}
|
||||
|
||||
if (bcmode!==null){
|
||||
document.getElementById("broadcast_"+promptID).checked = bcmode;
|
||||
}
|
||||
|
||||
if (updateurl!==null){
|
||||
document.getElementById("private_"+promptID).checked = updateurl;
|
||||
}
|
||||
|
||||
document.getElementById("input_"+promptID).addEventListener("keyup", function(event) {
|
||||
if (event.key === "Enter") {
|
||||
var pid = event.target.dataset.pid;
|
||||
var room = document.getElementById("input_"+pid).value;
|
||||
var updateurl = document.getElementById("private_"+pid).checked;
|
||||
var broadcast = document.getElementById("broadcast_"+pid).checked;
|
||||
document.getElementById("modal_"+pid).remove();
|
||||
document.getElementById("modalBackdrop_"+pid).remove();
|
||||
Prompts[pid].resolve();
|
||||
result = {roomid:room, updateurl:updateurl, broadcast:broadcast};
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById("submit_"+promptID).addEventListener("click", function(event){
|
||||
var pid = event.target.dataset.pid;
|
||||
var room = document.getElementById("input_"+pid).value;
|
||||
var updateurl = document.getElementById("private_"+pid).checked;
|
||||
var broadcast = document.getElementById("broadcast_"+pid).checked;
|
||||
|
||||
document.getElementById("modal_"+pid).remove();
|
||||
document.getElementById("modalBackdrop_"+pid).remove();
|
||||
Prompts[pid].resolve();
|
||||
result = {roomid:room, updateurl:updateurl, broadcast:broadcast};
|
||||
});
|
||||
|
||||
document.getElementById("cancel_"+promptID).addEventListener("click", function(event){
|
||||
var pid = event.target.dataset.pid;
|
||||
document.getElementById("modal_"+pid).remove();
|
||||
document.getElementById("modalBackdrop_"+pid).remove();
|
||||
Prompts[pid].resolve();
|
||||
});
|
||||
|
||||
document.getElementById("close_"+promptID).addEventListener("click", function(event){
|
||||
var pid = event.target.dataset.pid;
|
||||
document.getElementById("modal_"+pid).remove();
|
||||
document.getElementById("modalBackdrop_"+pid).remove();
|
||||
Prompts[pid].resolve();
|
||||
});
|
||||
|
||||
getById("modal_"+promptID).addEventListener("click", function(e) {
|
||||
e.stopPropagation();
|
||||
return false;
|
||||
});
|
||||
return;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
async function confirmAlt(inputText, block=false){
|
||||
var result = null;
|
||||
if (session.beepToNotify){
|
||||
@ -1788,7 +1892,7 @@ function updateMixerRun(e=false){ // this is the main auto-mixing code. It's a
|
||||
}
|
||||
}
|
||||
|
||||
if (session.broadcast!==false){
|
||||
if (session.broadcast !==false){
|
||||
if (roomQuality>0){
|
||||
if (session.nopreview!==false){
|
||||
mediaPool = []; // we don't want to show our self-preview if in broadcast mode and there is a director.
|
||||
@ -3217,7 +3321,7 @@ function pokeIframeAPI(action, value = null, UUID = null, SID=null) {
|
||||
|
||||
|
||||
|
||||
function jumptoroom(event = null) {
|
||||
async function jumptoroom(event = null) {
|
||||
|
||||
if (event) {
|
||||
if (event.which !== 13) {
|
||||
@ -3232,7 +3336,7 @@ function jumptoroom(event = null) {
|
||||
|
||||
var passStr = "";
|
||||
window.focus();
|
||||
var pass = prompt("Enter a password if provided, otherwise just click cancel"); //sanitizePassword(session.password);
|
||||
var pass = await promptAlt("Enter a password if provided, otherwise just click cancel", false); //sanitizePassword(session.password);
|
||||
if (pass && pass.length) {
|
||||
session.password = sanitizePassword(pass);
|
||||
passStr = "&password=" + session.password;
|
||||
@ -5347,8 +5451,9 @@ var previousRoom = "";
|
||||
var stillNeedRoom = true;
|
||||
var transferCancelled = false;
|
||||
var armedTransfer = false;
|
||||
var transferSettings = false;
|
||||
|
||||
function directMigrate(ele, event, room=false) { // 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.
|
||||
async function directMigrate(ele, event, room=false) { // 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 (room){
|
||||
var migrateRoom = room;
|
||||
@ -5382,8 +5487,25 @@ function directMigrate(ele, event, room=false) { // everyone in the room will ha
|
||||
if (armedTransfer!==false && previousRoom!==""){
|
||||
var migrateRoom = sanitizeRoomName(previousRoom);
|
||||
} else {
|
||||
var broadcastMode = null;
|
||||
if (transferSettings && ("broadcast" in transferSettings)){
|
||||
broadcastMode = transferSettings.broadcast;
|
||||
} else if (session.rpcs[ele.dataset.UUID] && session.rpcs[ele.dataset.UUID].stats.info && ("broadcast_mode" in session.rpcs[ele.dataset.UUID].stats.info)){
|
||||
broadcastMode = session.rpcs[ele.dataset.UUID].stats.info.broadcast_mode;
|
||||
}
|
||||
|
||||
var updateurl = null;
|
||||
if (transferSettings && ("updateurl" in transferSettings)){
|
||||
updateurl = transferSettings.updateurl;
|
||||
}
|
||||
window.focus();
|
||||
var migrateRoom = prompt(miscTranslations["transfer-guest-to-room"], previousRoom);
|
||||
|
||||
|
||||
var response = await promptTransfer(previousRoom, broadcastMode, updateurl);
|
||||
var migrateRoom = response.roomid;
|
||||
if (migrateRoom !== null){
|
||||
transferSettings = response;
|
||||
}
|
||||
}
|
||||
stillNeedRoom = true;
|
||||
if (migrateRoom === null) { // user cancelled
|
||||
@ -5405,40 +5527,11 @@ function directMigrate(ele, event, room=false) { // everyone in the room will ha
|
||||
|
||||
if (migrateRoom) {
|
||||
previousRoom = migrateRoom;
|
||||
var msg = {};
|
||||
msg.request = "migrate";
|
||||
if (session.password) {
|
||||
return generateHash(migrateRoom + session.password + session.salt, 16).then(function(rid) {
|
||||
var msg = {};
|
||||
if (session.director && session.directorUUID && (session.directorUUID !==true)){
|
||||
msg.migrate = ele.dataset.UUID;
|
||||
msg.roomid = rid;
|
||||
session.sendRequest(msg, session.directorUUID);
|
||||
log(msg);
|
||||
} else {
|
||||
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.
|
||||
}
|
||||
}).catch(errorlog);
|
||||
} else {
|
||||
var msg = {};
|
||||
if (session.director && session.directorUUID && (session.directorUUID !==true)){
|
||||
msg.migrate = ele.dataset.UUID;
|
||||
msg.roomid = migrateRoom;
|
||||
session.sendRequest(msg, session.directorUUID);
|
||||
log(msg);
|
||||
} else {
|
||||
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.
|
||||
}
|
||||
}
|
||||
session.directMigrateIssue(migrateRoom, transferSettings, ele.dataset.UUID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var stillNeedHangupTarget = 1;
|
||||
function directHangup(ele, event) { // everyone in the room will hangup this guest? I like that idea.
|
||||
if (event == false) {
|
||||
@ -5573,7 +5666,7 @@ var stillNeedURL = true;
|
||||
var reloadCancelled = false;
|
||||
var armedReload = false;
|
||||
|
||||
function directPageReload(ele, event) {
|
||||
async function directPageReload(ele, event) {
|
||||
log("URL Page reload");
|
||||
if (event === false) {
|
||||
if (previousURL === null) { // user cancelled in previous callback
|
||||
@ -5603,7 +5696,7 @@ function directPageReload(ele, event) {
|
||||
reloadURL = previousURL;
|
||||
} else {
|
||||
window.focus();
|
||||
var reloadURL = prompt(miscTranslations["transfer-guest-to-url"], previousURL);
|
||||
var reloadURL = await promptAlt(miscTranslations["transfer-guest-to-url"], false, value=previousURL);
|
||||
stillNeedURL = true;
|
||||
if (reloadURL === null) { // user cancelled
|
||||
ele.innerHTML = '<i class="las la-sync"></i> <span data-translate="change-url">change URL</span>';
|
||||
@ -5634,13 +5727,13 @@ function directPageReload(ele, event) {
|
||||
|
||||
|
||||
|
||||
function directTimer(ele, event=false) { // A directing room only is controlled by the Director, with the exception of MUTE.
|
||||
async function directTimer(ele, event=false) { // A directing room only is controlled by the Director, with the exception of MUTE.
|
||||
log("directTimer");
|
||||
if (!ele.dataset.UUID){return;}
|
||||
var msg = {};
|
||||
if (!event || (!((event.ctrlKey) || (event.metaKey)))) {
|
||||
if (ele.dataset.value == 0 || ele.dataset.value == 2) {
|
||||
var getTime = prompt("Time in seconds to count down", parseInt(getById("overlayClockContainer").dataset.initial));
|
||||
var getTime = await promptAlt("Time in seconds to count down", false, value=parseInt(getById("overlayClockContainer").dataset.initial));
|
||||
if (!getTime){return;}
|
||||
getById("overlayClockContainer").dataset.initial = parseInt(getTime) || 600;
|
||||
ele.dataset.value = 1;
|
||||
@ -6644,6 +6737,7 @@ function outboundAudioPipeline(stream) {
|
||||
webAudio.analyser = false;
|
||||
webAudio.gainNode = false;
|
||||
webAudio.splitter = false;
|
||||
webAudio.subGainNodes = false;
|
||||
|
||||
webAudio.lowEQ = false;
|
||||
webAudio.midEQ = false;
|
||||
@ -6666,6 +6760,7 @@ function outboundAudioPipeline(stream) {
|
||||
webAudio.audioContext = audioContext;
|
||||
webAudio.destination = audioContext.createMediaStreamDestination();
|
||||
|
||||
|
||||
if (tracks.length>1){ // tries to
|
||||
try {
|
||||
webAudio.mediaStreamSource = createMediaStream();
|
||||
@ -6673,26 +6768,37 @@ function outboundAudioPipeline(stream) {
|
||||
if (session.stereo===false){
|
||||
maxChannelCount = 1;
|
||||
}
|
||||
|
||||
webAudio.subGainNodes = {};//
|
||||
|
||||
var merger = audioContext.createChannelMerger(maxChannelCount);
|
||||
for (var i=0;i<tracks.length;i++){
|
||||
var tempStream = createMediaStream();
|
||||
tempStream.addTrack(tracks[i]);
|
||||
trackStream = audioContext.createMediaStreamSource(tempStream);
|
||||
if (maxChannelCount==2){
|
||||
var splitter = audioContext.createChannelSplitter(2);
|
||||
trackStream.connect(splitter);
|
||||
splitter.connect(merger, 0, 0);
|
||||
try{
|
||||
trackStream.connect(merger, 1, 1);
|
||||
} catch(e){
|
||||
try {
|
||||
trackStream.connect(merger, 0, 1); // hack.
|
||||
} catch(e){errorlog(e);}
|
||||
try {
|
||||
var tempStream = createMediaStream();
|
||||
tempStream.addTrack(tracks[i]);
|
||||
trackStream = audioContext.createMediaStreamSource(tempStream);
|
||||
|
||||
webAudio.subGainNodes[tracks[i].id] = audioContext.createGain();
|
||||
trackStream.connect(webAudio.subGainNodes[tracks[i].id]);
|
||||
|
||||
if (maxChannelCount==2){
|
||||
var splitter = audioContext.createChannelSplitter(2);
|
||||
webAudio.subGainNodes[tracks[i].id].connect(splitter);
|
||||
splitter.connect(merger, 0, 0);
|
||||
try{
|
||||
splitter.connect(merger, 1, 1);
|
||||
} catch(e){
|
||||
errorlog(e);
|
||||
try {
|
||||
splitter.connect(merger, 0, 1); // hack.
|
||||
} catch(e){errorlog(e);}
|
||||
}
|
||||
} else {
|
||||
webAudio.subGainNodes[tracks[i].id].connect(merger, 0, 0);
|
||||
}
|
||||
} else {
|
||||
trackStream.connect(merger, 0, 0);
|
||||
}
|
||||
} catch(e){errorlog(e);}
|
||||
}
|
||||
|
||||
webAudio.gainNode = audioGainNode(merger, audioContext);
|
||||
} catch(e){
|
||||
webAudio.mediaStreamSource = audioContext.createMediaStreamSource(stream);
|
||||
@ -6894,6 +7000,43 @@ function changeHighEQ(highEQ, deviceid=null) {
|
||||
|
||||
}
|
||||
|
||||
function changeSubGain(gain, deviceid=null) {
|
||||
if (gain !== false) {
|
||||
gain = parseFloat(gain / 100.0) || 0;
|
||||
} else {
|
||||
gain = 1.0;
|
||||
}
|
||||
for (var webAudio in session.webAudios) {
|
||||
try{
|
||||
if (!session.webAudios[webAudio].subGainNodes) {
|
||||
errorlog("EQ not setup");
|
||||
return;
|
||||
}
|
||||
if (deviceid in session.webAudios[webAudio].subGainNodes){
|
||||
session.webAudios[webAudio].subGainNodes[deviceid].gain.setValueAtTime(gain, session.webAudios[webAudio].audioContext.currentTime);
|
||||
} else {
|
||||
errorlog("NOT FOUND:" + deviceid);
|
||||
}
|
||||
break;
|
||||
} catch(e){errorlog(e);}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function changeMainGain(gain, deviceid=null) {
|
||||
for (var webAudio in session.webAudios) {
|
||||
if (!session.webAudios[webAudio].gainNode){
|
||||
return;
|
||||
}
|
||||
if (gain !== false) {
|
||||
gain = parseFloat(gain / 100.0) || 0;
|
||||
} else {
|
||||
gain = 1.0;
|
||||
}
|
||||
session.webAudios[webAudio].gainNode.gain.setValueAtTime(gain, session.webAudios[webAudio].audioContext.currentTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function micDelayNode(mediaStreamSource, audioContext) {
|
||||
var delayNode = audioContext.createDelay();
|
||||
@ -7401,6 +7544,59 @@ function hideDirectorinvites(ele, skip=true) {
|
||||
}
|
||||
}
|
||||
|
||||
function toggleCoDirector_changeurl(ele){
|
||||
session.codirector_changeURL = ele.checked; // doesn't do anything yet though.
|
||||
}
|
||||
|
||||
function toggleCoDirector_transfer(ele){
|
||||
session.codirector_transfer = ele.checked;
|
||||
}
|
||||
|
||||
async function toggleCoDirector(ele){
|
||||
//session.coDirectorAllowed = ele.checked;
|
||||
if (!ele.checked){
|
||||
getById("codirectorSettings").style.display = "none";
|
||||
return;
|
||||
}
|
||||
if (!session.directorPassword){
|
||||
session.directorPassword = await promptAlt(miscTranslations["enter-new-codirector-password"], false);
|
||||
if (!session.directorPassword){
|
||||
session.directorPassword=false;
|
||||
ele.checked=false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
updateURL("codirector="+session.directorPassword, true, false);
|
||||
getById("coDirectorEnableSpan").style.display = "none";
|
||||
|
||||
await generateHash(session.directorPassword + session.salt + "abc123", 12).then(function(hash) { // million to one error.
|
||||
log("dir room hash is " + hash);
|
||||
session.directorHash = hash;
|
||||
return;
|
||||
}).catch(errorlog);
|
||||
|
||||
if (session.codirector_transfer){
|
||||
getById("codirectorSettings_transfer").checked = true;
|
||||
} else {
|
||||
getById("codirectorSettings_transfer").checked = false;
|
||||
}
|
||||
if (session.codirector_changeURL){
|
||||
getById("codirectorSettings_changeurl").checked = true;
|
||||
} else {
|
||||
getById(codirectorSettings_changeurl).checked = false;
|
||||
}
|
||||
|
||||
getById("codirectorSettings_invite").value = "https://"+location.host+location.pathname+"?dir="+session.roomid+"&codirector="+session.directorPassword;
|
||||
if (session.password!==session.sitePassword){
|
||||
if (session.password===false){
|
||||
getById("codirectorSettings_invite").value += "&password=false";
|
||||
} else{
|
||||
getById("codirectorSettings_invite").value += "&password";
|
||||
}
|
||||
}
|
||||
|
||||
getById("codirectorSettings").style.display = "block";
|
||||
}
|
||||
function createRoomCallback(passAdd, passAdd2) {
|
||||
|
||||
var gridlayout = getById("gridlayout");
|
||||
@ -7500,7 +7696,34 @@ function createRoomCallback(passAdd, passAdd2) {
|
||||
|
||||
session.director = true;
|
||||
screensharesupport = false;
|
||||
|
||||
|
||||
if (session.directorPassword){
|
||||
getById("coDirectorEnable").checked = true;
|
||||
getById("coDirectorEnableSpan").style.display = "none";
|
||||
|
||||
getById("codirectorSettings_invite").value = "https://"+location.host+location.pathname+"?dir="+session.roomid+"&codirector="+session.directorPassword;
|
||||
if (session.password!==session.sitePassword){
|
||||
if (session.password==false){
|
||||
getById("codirectorSettings_invite").value += "&password=false";
|
||||
} else{
|
||||
getById("codirectorSettings_invite").value += "&password";
|
||||
}
|
||||
}
|
||||
|
||||
if (session.codirector_transfer){
|
||||
getById("codirectorSettings_transfer").checked = true;
|
||||
} else {
|
||||
getById("codirectorSettings_transfer").checked = false;
|
||||
}
|
||||
if (session.codirector_changeURL){
|
||||
getById("codirectorSettings_changeurl").checked = true;
|
||||
} else {
|
||||
getById("codirectorSettings_changeurl").checked = false;
|
||||
}
|
||||
getById("codirectorSettings").style.display = "block";
|
||||
}
|
||||
|
||||
|
||||
window.onresize = updateMixer;
|
||||
window.onorientationchange = function(){setTimeout(updateMixer, 200);};
|
||||
getById("reshare").parentNode.removeChild(getById("reshare"));
|
||||
@ -7768,7 +7991,7 @@ function requestVideoSettings(ele) {
|
||||
}
|
||||
|
||||
|
||||
function createDirectorOnlyBox() {
|
||||
async function createDirectorOnlyBox() {
|
||||
|
||||
var codecGroupFlag="";
|
||||
|
||||
@ -7840,13 +8063,13 @@ function createDirectorOnlyBox() {
|
||||
|
||||
var labelID = document.getElementById("label_director");
|
||||
|
||||
labelID.onclick = function(ee){
|
||||
labelID.onclick = async function(ee){
|
||||
var oldlabel = ee.target.innerText;
|
||||
if (session.label===false){
|
||||
oldlabel = "";
|
||||
}
|
||||
window.focus();
|
||||
var newlabel = prompt(miscTranslations["enter-new-display-name"], oldlabel);
|
||||
var newlabel = await promptAlt(miscTranslations["enter-new-display-name"], false, value=oldlabel);
|
||||
if (newlabel!==null){
|
||||
if (newlabel == ""){
|
||||
newlabel = false;
|
||||
@ -13552,6 +13775,16 @@ function listAudioSettingsPrep() {
|
||||
} else {
|
||||
trackSet.lowcut = false;
|
||||
}
|
||||
|
||||
trackSet.subGain = false;
|
||||
for (var waid in session.webAudios) { // TODO: EXCLUDE CURRENT TRACK IF ALREADY EXISTS ... if (track.id === wa.id){..
|
||||
try{
|
||||
if (session.webAudios[waid].subGainNodes && (track0.id in session.webAudios[waid].subGainNodes)){
|
||||
trackSet.subGain = session.webAudios[waid].subGainNodes[track0.id].gain.value;
|
||||
}
|
||||
break;
|
||||
} catch(e){}
|
||||
}
|
||||
|
||||
data.push(trackSet);
|
||||
}
|
||||
@ -13699,7 +13932,7 @@ function setupClosedCaptions() {
|
||||
}
|
||||
|
||||
|
||||
function requestVideoRecord(ele) {
|
||||
async function requestVideoRecord(ele) {
|
||||
var UUID = ele.dataset.UUID
|
||||
if (ele.classList.contains("pressed")) {
|
||||
var msg = {};
|
||||
@ -13712,7 +13945,7 @@ function requestVideoRecord(ele) {
|
||||
msg.requestVideoRecord = true;
|
||||
msg.UUID = UUID;
|
||||
window.focus();
|
||||
var bitrate = prompt(miscTranslations["what-bitrate"], 6000);
|
||||
var bitrate = await promptAlt(miscTranslations["what-bitrate"], false, value=6000);
|
||||
if (bitrate) {
|
||||
msg.value = bitrate;
|
||||
session.sendRequest(msg, msg.UUID);
|
||||
@ -13777,6 +14010,16 @@ function requestChangeEQ(keyname, value, UUID, track = 0) { // updateCameraConst
|
||||
session.sendRequest(msg, msg.UUID);
|
||||
}
|
||||
|
||||
function requestChangeSubGain(value, UUID, deviceID) { // updateCameraConstraints
|
||||
var msg = {};
|
||||
msg.requestChangeSubGain = true;
|
||||
msg.value = value;
|
||||
msg.UUID = UUID;
|
||||
msg.deviceID = deviceID; // pointless atm
|
||||
log(msg);
|
||||
session.sendRequest(msg, msg.UUID);
|
||||
}
|
||||
|
||||
function requestChangeLowcut(value, UUID, track = 0) { // updateCameraConstraints
|
||||
var msg = {};
|
||||
msg.requestChangeLowcut = true;
|
||||
@ -13968,6 +14211,7 @@ function updateDirectorsAudio(dataN, UUID) {
|
||||
audioEle.appendChild(input);
|
||||
}
|
||||
|
||||
|
||||
if (dataN.length>1){
|
||||
if (data.trackLabel) {
|
||||
var label = document.createElement("span");
|
||||
@ -14139,6 +14383,41 @@ function updateDirectorsAudio(dataN, UUID) {
|
||||
errorlog(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (data.subGain!==false) {
|
||||
var label = document.createElement("label");
|
||||
var i = "Gain";
|
||||
label.id = "label_" + i + "_" + n;
|
||||
label.htmlFor = "constraints_" + i + "_" + n;
|
||||
|
||||
var input = document.createElement("input");
|
||||
input.min = 0;
|
||||
input.max = 200;
|
||||
input.value = data.subGain*100;
|
||||
input.title = "Previously was: "+parseInt(input.value);
|
||||
input.type = "range";
|
||||
input.dataset.keyname = i + "_" + n;
|
||||
input.dataset.labelname = "Gain:"
|
||||
label.innerText = input.dataset.labelname+" "+parseInt(input.value);
|
||||
input.dataset.track = data.deviceID;
|
||||
input.dataset.UUID = UUID;
|
||||
input.id = "constraints_" + i + "_" + n;
|
||||
input.style = "display:block; width:100%;";
|
||||
input.name = "constraints_" + i + "_" + n;
|
||||
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);
|
||||
//e.target.title = e.target.value;
|
||||
requestChangeSubGain(parseInt(e.target.value), e.target.dataset.UUID, e.target.dataset.track);
|
||||
};
|
||||
|
||||
audioEle.appendChild(label);
|
||||
audioEle.appendChild(input);
|
||||
}
|
||||
|
||||
getById("advanced_audio_director_" + UUID).appendChild(audioEle);
|
||||
}
|
||||
}
|
||||
@ -14532,10 +14811,12 @@ function listAudioSettings() {
|
||||
}
|
||||
////////
|
||||
if (tracks.length>1){
|
||||
|
||||
var label = document.createElement("h4");
|
||||
label.innerHTML = track0.label;
|
||||
label.style = "text-shadow: 0 0 10px #fff3;"
|
||||
getById("popupSelector_constraints_audio").appendChild(label);
|
||||
|
||||
}
|
||||
|
||||
for (var i in session.audioConstraints) {
|
||||
@ -14710,6 +14991,91 @@ function listAudioSettings() {
|
||||
errorlog(e);
|
||||
}
|
||||
}
|
||||
if (tracks.length>1){
|
||||
for (var webAudio in session.webAudios) {
|
||||
if (session.webAudios[webAudio].subGainNodes && (track0.id in session.webAudios[webAudio].subGainNodes)) {
|
||||
|
||||
if (getById("popupSelector_constraints_audio").style.display == "none") {
|
||||
getById("advancedOptionsAudio").style.display = "inline-block";
|
||||
}
|
||||
|
||||
var label = document.createElement("label");
|
||||
var i = "Gain";
|
||||
label.id = "label_" + i + "_" + track0.id;
|
||||
label.htmlFor = "constraints_" + i + "_" + track0.id;
|
||||
label.innerText = "Gain:";
|
||||
|
||||
var input = document.createElement("input");
|
||||
input.min = 0;
|
||||
input.max = 200;
|
||||
|
||||
input.dataset.deviceid = track0.id; // pointless
|
||||
|
||||
input.type = "range";
|
||||
input.dataset.keyname = i;
|
||||
input.dataset.labelname = label.innerHTML;
|
||||
input.id = "constraints_" + i+ "_" + track0.id;
|
||||
input.style = "display:block; width:100%;";
|
||||
input.name = "constraints_" + i + "_" + track0.id;
|
||||
|
||||
input.value = session.webAudios[webAudio].subGainNodes[track0.id].gain.value * 100;
|
||||
label.innerHTML += " " + parseInt(session.webAudios[webAudio].subGainNodes[track0.id].gain.value * 100);
|
||||
input.title = parseInt(input.value);
|
||||
|
||||
input.onchange = function(e) {
|
||||
getById("label_" + e.target.dataset.keyname).innerHTML = e.target.dataset.labelname + " " + e.target.value;
|
||||
changeSubGain(e.target.value, e.target.dataset.deviceid);
|
||||
e.target.title = e.target.value;
|
||||
};
|
||||
|
||||
getById("popupSelector_constraints_audio").appendChild(label);
|
||||
getById("popupSelector_constraints_audio").appendChild(input);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (var webAudio in session.webAudios) {
|
||||
if (session.webAudios[webAudio].gainNode) {
|
||||
|
||||
if (getById("popupSelector_constraints_audio").style.display == "none") {
|
||||
getById("advancedOptionsAudio").style.display = "inline-block";
|
||||
}
|
||||
|
||||
var label = document.createElement("label");
|
||||
var i = "Gain";
|
||||
label.id = "label_" + i;
|
||||
label.htmlFor = "constraints_" + i;
|
||||
label.innerText = "Gain:";
|
||||
|
||||
var input = document.createElement("input");
|
||||
input.min = 0;
|
||||
input.max = 200;
|
||||
|
||||
input.dataset.deviceid = track0.id; // pointless
|
||||
|
||||
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;
|
||||
|
||||
input.value = session.webAudios[webAudio].gainNode.gain.value * 100;
|
||||
label.innerHTML += " " + parseInt(session.webAudios[webAudio].gainNode.gain.value * 100);
|
||||
input.title = parseInt(input.value);
|
||||
|
||||
input.onchange = function(e) {
|
||||
getById("label_" + e.target.dataset.keyname).innerHTML = e.target.dataset.labelname + " " + e.target.value;
|
||||
changeMainGain(e.target.value, e.target.dataset.deviceid);
|
||||
e.target.title = e.target.value;
|
||||
};
|
||||
|
||||
getById("popupSelector_constraints_audio").appendChild(label);
|
||||
getById("popupSelector_constraints_audio").appendChild(input);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -15498,7 +15864,7 @@ Promise.prototype.timeout = function(ms) {
|
||||
};
|
||||
|
||||
|
||||
function shareWebsite(autostart=false, evt=false){
|
||||
async function shareWebsite(autostart=false, evt=false){
|
||||
if (session.iframeSrc){
|
||||
if (evt && (evt.ctrlKey || evt.metaKey)){
|
||||
if (getById("websitesharebutton").classList.contains("green")){
|
||||
@ -15545,7 +15911,7 @@ function shareWebsite(autostart=false, evt=false){
|
||||
getById("websitesharebutton").title = "Hold CTRL (or CMD) and click to spotlight this video";
|
||||
if (autostart===false){
|
||||
window.focus();
|
||||
var iframeURL = prompt(miscTranslations["enter-website"], session.defaultIframeSrc);
|
||||
var iframeURL = await promptAlt(miscTranslations["enter-website"], false, value=session.defaultIframeSrc);
|
||||
} else {
|
||||
var iframeURL = autostart;
|
||||
}
|
||||
@ -16410,7 +16776,7 @@ var vis = (function() {
|
||||
}
|
||||
}
|
||||
|
||||
function menuItemListener(link) {
|
||||
async function menuItemListener(link) {
|
||||
if (link.getAttribute("data-action") === "Open") {
|
||||
window.open(taskItemInContext.href);
|
||||
} else if (link.getAttribute("data-action") === "Copy") {
|
||||
@ -16423,7 +16789,7 @@ var vis = (function() {
|
||||
//copyFunction(taskItemInContext.href);
|
||||
} else if (link.getAttribute("data-action") === "Edit") {
|
||||
//copyFunction(taskItemInContext.href);
|
||||
var response = prompt("Please note, manual edits to the URL may conflict with the toggles", taskItemInContext.href);
|
||||
var response = await promptAlt("Please note, manual edits to the URL may conflict with the toggles", false, false, taskItemInContext.href);
|
||||
if (response){
|
||||
taskItemInContext.href = response;
|
||||
taskItemInContext.dataset.raw = response;
|
||||
@ -17045,7 +17411,7 @@ function showCustomizer(arg, ele) {
|
||||
|
||||
var defaultRecordingBitrate = false;
|
||||
|
||||
function recordVideo(target, event, videoKbps = false) { // event.currentTarget,this.parentNode.parentNode.dataset.UUID
|
||||
async function recordVideo(target, event, videoKbps = false) { // event.currentTarget,this.parentNode.parentNode.dataset.UUID
|
||||
|
||||
var UUID = target.dataset.UUID;
|
||||
var video = session.rpcs[UUID].videoElement;
|
||||
@ -17108,7 +17474,7 @@ function recordVideo(target, event, videoKbps = false) { // event.currentTarget,
|
||||
if (defaultRecordingBitrate == false) {
|
||||
videoKbps = 4000; // 4mbps recording bitrate
|
||||
window.focus();
|
||||
videoKbps = prompt(miscTranslations["press-ok-to-record"], videoKbps);
|
||||
videoKbps = await promptAlt(miscTranslations["press-ok-to-record"], false, value=videoKbps);
|
||||
if (videoKbps === null) {
|
||||
//target.style.backgroundColor = null;
|
||||
//target.innerHTML = '<i class="las la-circle"></i><span data-translate="record"> record local</span>';
|
||||
|
||||
12
main.css
12
main.css
@ -46,6 +46,14 @@ table {
|
||||
background-color: #FFF;
|
||||
}
|
||||
|
||||
.promptModalLabel{
|
||||
cursor: pointer;
|
||||
font-weight: normal;
|
||||
font-size: 1.0em;
|
||||
display:block;
|
||||
margin: 17px 20px 15px 20px;
|
||||
}
|
||||
|
||||
#bigPlayButton {
|
||||
margin:0 auto;
|
||||
background-color: #0000;
|
||||
@ -2979,7 +2987,7 @@ input:checked + .slider:before {
|
||||
border-radius: 10px;
|
||||
font-weight: bold;
|
||||
z-index:31;
|
||||
min-width:400px;
|
||||
min-width:500px;
|
||||
max-width:90%;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
@ -2995,7 +3003,7 @@ input:checked + .slider:before {
|
||||
.promptModalInner {
|
||||
position: relative;
|
||||
padding: 1em;
|
||||
max-width: 400px;
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
.promptModalMessage {
|
||||
|
||||
24
main.js
24
main.js
@ -229,6 +229,17 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
if (urlParams.has('broadcast') || urlParams.has('bc')) {
|
||||
log("Broadcast flag set");
|
||||
session.broadcast = urlParams.get('broadcast') || urlParams.get('bc') || null;
|
||||
|
||||
if (session.broadcast === "false") {
|
||||
session.broadcast = false;
|
||||
} else if (session.broadcast=== "0") {
|
||||
session.broadcast = false;
|
||||
} else if (session.broadcast === "no") {
|
||||
session.broadcast = false;
|
||||
} else if (session.broadcast === "off") {
|
||||
session.broadcast = false;
|
||||
}
|
||||
|
||||
//if ((iOS) || (iPad)) {
|
||||
// session.nopreview = false;
|
||||
//} else {
|
||||
@ -626,6 +637,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
document.querySelector("head").appendChild(cssStyleSheet);
|
||||
};
|
||||
|
||||
session.sitePassword = session.defaultPassword;
|
||||
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) {
|
||||
@ -1993,6 +2005,8 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
} else if ((parseInt(session.style) == 3) || (session.style == "volume")) { // photo is taken? upload option? canvas?
|
||||
session.style = 3;
|
||||
session.audioEffects = true;
|
||||
} else if (parseInt(session.style) == 4) { // photo is taken? upload option? canvas?
|
||||
session.style = 4;
|
||||
} else {
|
||||
session.style = 1;
|
||||
}
|
||||
@ -2261,10 +2275,10 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
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')) {
|
||||
if (urlParams.has('room')) { // needs to be first; takes priority
|
||||
roomid = urlParams.get('room');
|
||||
} else if (filename) {
|
||||
roomid = filename;
|
||||
} else if (urlParams.has('roomid')) {
|
||||
roomid = urlParams.get('roomid');
|
||||
} else if (urlParams.has('r')) {
|
||||
@ -3186,7 +3200,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
log(e);
|
||||
var note = e.note.name + e.note.octave;
|
||||
var velocity = e.velocity || false;
|
||||
midiHotkeysNote(node,velocity);
|
||||
midiHotkeysNote(note,velocity);
|
||||
});
|
||||
input.addListener('controlchange', "all", function(e) {
|
||||
|
||||
@ -3207,7 +3221,7 @@ async function main(){ // main asyncronous thread; mostly initializes the user s
|
||||
var command = e.controller.number;
|
||||
var value = e.value;
|
||||
|
||||
midiHotkeys(command, value)
|
||||
midiHotkeysCommand(command, value)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
593
mixer.html
Normal file
593
mixer.html
Normal file
@ -0,0 +1,593 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>IFRAME Example</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type" />
|
||||
<style>
|
||||
body{
|
||||
padding:0;
|
||||
margin:0;
|
||||
background-color: #0000;
|
||||
}
|
||||
iframe {
|
||||
border:0;
|
||||
padding:0;
|
||||
display:block;
|
||||
width:1280px;
|
||||
height:720px;
|
||||
background-color: #111;
|
||||
}
|
||||
#viewlink {
|
||||
width:400px;
|
||||
}
|
||||
#container {
|
||||
display:block;
|
||||
padding:0px;
|
||||
}
|
||||
input{
|
||||
padding:5px;
|
||||
margin:5px;
|
||||
}
|
||||
button{
|
||||
padding:5px;
|
||||
margin:5px;
|
||||
}
|
||||
canvas{
|
||||
padding:10px;
|
||||
cursor:pointer;
|
||||
}
|
||||
.thing {
|
||||
width: 100px;
|
||||
height: 2em;
|
||||
padding: 10px 0.5em 0 0.5em;
|
||||
margin: 0.5em;
|
||||
background: rgba(0,0,0,0.8);
|
||||
color: white;
|
||||
font-family: sans-serif;
|
||||
cursor: grab;
|
||||
text-align: center;
|
||||
}
|
||||
.empty {
|
||||
width: 100px;
|
||||
height: 2em;
|
||||
padding: 10px 0.5em 0 0.5em;
|
||||
margin: 0.5em;
|
||||
background: rgba(0,0,0,0.8);
|
||||
color: white;
|
||||
font-family: sans-serif;
|
||||
user-select: none;
|
||||
text-align: center;
|
||||
}
|
||||
.col {
|
||||
width: 130px;
|
||||
height: 450px;
|
||||
padding: 1em;
|
||||
border: 1px solid;
|
||||
border-radius: 5px;
|
||||
position: relative;
|
||||
float: left;
|
||||
}
|
||||
.pressed{
|
||||
border: solid 2px black;
|
||||
}
|
||||
a{
|
||||
display:block;
|
||||
margin:5px;
|
||||
}
|
||||
#delete {
|
||||
background-color: rgb(191 191 191);
|
||||
margin: 3px 0 10px 0;
|
||||
text-align: center;
|
||||
padding: 10px 15px 0 15px;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
|
||||
function allowDrop(ev) {
|
||||
ev.preventDefault();
|
||||
}
|
||||
|
||||
function swapNodes(n1, n2) {
|
||||
var p1 = n1.parentNode;
|
||||
var p2 = n2.parentNode;
|
||||
var i1, i2;
|
||||
|
||||
if ( !p1 || !p2 || p1.isEqualNode(n2) || p2.isEqualNode(n1) ) return;
|
||||
|
||||
for (var i = 0; i < p1.children.length; i++) {
|
||||
if (p1.children[i].isEqualNode(n1)) {
|
||||
i1 = i;
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < p2.children.length; i++) {
|
||||
if (p2.children[i].isEqualNode(n2)) {
|
||||
i2 = i;
|
||||
}
|
||||
}
|
||||
|
||||
if ( p1.isEqualNode(p2) && i1 < i2 ) {
|
||||
i2++;
|
||||
}
|
||||
p1.insertBefore(n2, p1.children[i1]);
|
||||
p2.insertBefore(n1, p2.children[i2]);
|
||||
}
|
||||
|
||||
function drag(ev) {
|
||||
ev.dataTransfer.setData("text", ev.target.id);
|
||||
}
|
||||
|
||||
function drop(ev) {
|
||||
ev.preventDefault();
|
||||
var data = ev.dataTransfer.getData("text");
|
||||
var origThing = document.getElementById(data);
|
||||
console.log(origThing);
|
||||
console.log(data);
|
||||
console.log(ev);
|
||||
ev.target.style.border = "";
|
||||
origThing.style.border = "";
|
||||
//var newThing = origThing.cloneNode(true);
|
||||
if (ev.target.classList.contains("thing")){
|
||||
//ev.target.parentNode.insertBefore(origThing, ev.target.nextSibling);
|
||||
//elem.parentNode.insertBefore(elem, elem.parentNode.firstChild);
|
||||
swapNodes( ev.target, origThing);
|
||||
var slot = origThing.dataset.slot;
|
||||
origThing.dataset.slot = ev.target.dataset.slot;
|
||||
ev.target.dataset.slot = slot;
|
||||
origThing.style.backgroundColor = ev.target.style.backgroundColor;
|
||||
} else if (ev.target.classList.contains("empty")){
|
||||
ev.target.parentNode.insertBefore(origThing, ev.target.nextSibling);
|
||||
|
||||
console.warn(origThing);
|
||||
|
||||
if (origThing.dataset.slot){
|
||||
document.querySelector(".empty[data-slot='"+origThing.dataset.slot+"']").style.display = "block";
|
||||
}
|
||||
origThing.dataset.slot = ev.target.dataset.slot;
|
||||
ev.target.style.display = "none";
|
||||
origThing.style.backgroundColor = ev.target.style.backgroundColor;
|
||||
}
|
||||
}
|
||||
|
||||
function dragenter(event) {
|
||||
event.preventDefault();
|
||||
if ( event.target.classList.contains("thing") ) {
|
||||
event.target.style.border = "3px dotted black";
|
||||
} else if (event.target.classList.contains("empty")){
|
||||
event.target.style.border = "3px dotted black";
|
||||
}
|
||||
}
|
||||
|
||||
function dragleave(event) {
|
||||
event.preventDefault();
|
||||
if (event.target.classList.contains("thing")){
|
||||
event.target.style.border = "";
|
||||
} else if (event.target.classList.contains("empty")){
|
||||
event.target.style.border = "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function dropRemove(ev) {
|
||||
ev.preventDefault();
|
||||
var data = ev.dataTransfer.getData("text");
|
||||
var origThing = document.getElementById(data);
|
||||
|
||||
ev.target.style.border = "";
|
||||
origThing.style.border = "";
|
||||
|
||||
|
||||
if (origThing.dataset.slot){
|
||||
document.querySelector(".empty[data-slot='"+origThing.dataset.slot+"']").style.display = "block";
|
||||
delete origThing.dataset.slot;
|
||||
}
|
||||
origThing.style.backgroundColor = "#000";
|
||||
if (ev.target.classList.contains("thing")){
|
||||
ev.target.parentNode.insertBefore(origThing, ev.target.nextSibling);
|
||||
} else {
|
||||
ev.target.appendChild(origThing);
|
||||
}
|
||||
document.getElementById("col2").appendChild(document.getElementById("delete"));
|
||||
}
|
||||
|
||||
var streamIDs = [];
|
||||
var slotsNeeded = 1;
|
||||
|
||||
function updateList(){
|
||||
//<div id="col2" ondrop="dropRemove(event)" ondragover="allowDrop(event)">
|
||||
// <div class="thing" draggable="true" ondragstart="drag(event)" id="thing4">THING 4</div>
|
||||
// <div class="thing" draggable="true" ondragstart="drag(event)" id="thing1">THING 1</div>
|
||||
//</div>
|
||||
for (var i=0;i<streamIDs.length;i++){
|
||||
if (!document.getElementById("sid_"+streamIDs[i])){
|
||||
var thing = document.createElement("div");
|
||||
thing.draggable = true;
|
||||
thing.classList.add("thing");
|
||||
thing.addEventListener("dragstart", drag);
|
||||
|
||||
thing.dataset.sid = streamIDs[i];
|
||||
thing.id = "sid_"+streamIDs[i];
|
||||
thing.innerText = streamIDs[i];
|
||||
document.getElementById("col2").appendChild(thing);
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("col2").appendChild(document.getElementById("delete"));
|
||||
}
|
||||
|
||||
function loadIframe(){
|
||||
|
||||
document.getElementById("container").innerHTML = "";
|
||||
|
||||
var iframe = document.createElement("iframe");
|
||||
var iframeContainer = document.createElement("div");
|
||||
iframe.allow = "autoplay;camera;microphone;fullscreen;picture-in-picture;display-capture;";
|
||||
|
||||
var promptRoom = prompt("Enter a room name to use");
|
||||
if (promptRoom){
|
||||
var iframesrc = "./?transparent&cleanoutput&director="+promptRoom;
|
||||
} else {
|
||||
promptRoom = "testroom123312";
|
||||
var iframesrc = "./?transparent&cleanoutput&director="+promptRoom;
|
||||
}
|
||||
|
||||
function remoteActivate(){
|
||||
if (this.dataset.layout){
|
||||
var layout = JSON.parse(this.dataset.layout);
|
||||
var combined = {};
|
||||
for (var i=0;i<layout.length;i++){
|
||||
//layout[i].z = i;
|
||||
if (!layout[i]){continue;}
|
||||
|
||||
var stream = document.querySelector(".thing[data-slot='"+(i+1)+"'");
|
||||
if (!stream){continue;}
|
||||
combined[stream.dataset.sid] = layout[i];
|
||||
}
|
||||
} else {
|
||||
var layout = null;
|
||||
combined = false;
|
||||
}
|
||||
|
||||
iframe.contentWindow.postMessage({"scene":"0", "layout":combined}, '*');
|
||||
var layoutButtons = document.querySelectorAll("canvas[data-layout]");
|
||||
|
||||
for (var i = 0;i<layoutButtons.length;i++){
|
||||
layoutButtons[i].classList.remove("pressed");
|
||||
}
|
||||
this.classList.add("pressed");
|
||||
}
|
||||
|
||||
function activate(){
|
||||
console.log(this.dataset.layout);
|
||||
var layout = JSON.parse(this.dataset.layout);
|
||||
|
||||
iframe.contentWindow.postMessage({"target":"*", "remove":true}, '*');
|
||||
|
||||
|
||||
|
||||
for (var i=0;i<layout.length;i++){
|
||||
|
||||
var stream = document.querySelector(".thing[data-slot='"+(i+1)+"'");
|
||||
if (!stream){continue;}
|
||||
|
||||
var x = layout[i].x|| 0;
|
||||
var y = layout[i].y || 0;
|
||||
var w = layout[i].w || 0;
|
||||
var h = layout[i].h || 0;
|
||||
var cover = layout[i].c || false;
|
||||
|
||||
if (!(w && h)){continue;}
|
||||
|
||||
x = x + "%";
|
||||
y = y + "%";
|
||||
w = w + "%";
|
||||
h = h + "%";
|
||||
|
||||
if (cover){
|
||||
cover = "object-fit:cover;";
|
||||
} else {
|
||||
cover = "";
|
||||
}
|
||||
|
||||
iframe.contentWindow.postMessage({"target":stream.dataset.sid, "add":true, "settings":{"style": "width:"+w+";height:"+h+";position:absolute;left:"+x+";top:"+y+";display:block;"+cover}}, '*');
|
||||
}
|
||||
}
|
||||
|
||||
var button = document.createElement("button");
|
||||
button.innerHTML = "Refresh list";
|
||||
button.onclick = function(){iframe.contentWindow.postMessage({"getStreamIDs":true}, '*');};
|
||||
button.style.display = "block";
|
||||
document.getElementById("sources").appendChild(button);
|
||||
|
||||
var a = document.createElement("a");
|
||||
a.innerHTML = "Invite Guest Link";
|
||||
a.href = "./?room="+promptRoom+"&broadcast";
|
||||
a.target = "_blank";
|
||||
document.getElementById("sources").appendChild(a);
|
||||
|
||||
var a = document.createElement("a");
|
||||
a.innerHTML = "Scene View Link";
|
||||
a.href = "./?scene=0&room="+promptRoom;
|
||||
a.target = "_blank";
|
||||
document.getElementById("sources").appendChild(a);
|
||||
|
||||
|
||||
|
||||
var colors = [
|
||||
"#00AAAA",
|
||||
"#FF0000",
|
||||
"#0000FF",
|
||||
"#AA00AA",
|
||||
"#00FF00",
|
||||
"#AAAA00",
|
||||
"#AACC44",
|
||||
"#CCAA44",
|
||||
"#CC44AA",
|
||||
"#44AACC"
|
||||
];
|
||||
|
||||
|
||||
var slots = document.getElementById("col1").children;
|
||||
for (var i=0;i<slots.length;i++){
|
||||
slots[i].style.backgroundColor = colors[i];
|
||||
slots[i].style.opacity = "0.4";
|
||||
}
|
||||
|
||||
function drawLayout(layoutOriginal){
|
||||
|
||||
var layout = [];
|
||||
for (var i=0;i<layoutOriginal.length;i++){
|
||||
if (!layoutOriginal[i]){
|
||||
continue;
|
||||
}
|
||||
layoutOriginal[i].i = i; // slot index (0 == slot 1)
|
||||
layout.push(layoutOriginal[i]);
|
||||
}
|
||||
|
||||
function compare( a, b ) { // sorts layout based on z-index.
|
||||
var aa = a.z || 0;
|
||||
var bb = b.z || 0;
|
||||
if ( aa > bb ){
|
||||
return 1;
|
||||
}
|
||||
if ( aa < bb ){
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
layout.sort(compare);
|
||||
|
||||
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width="80";
|
||||
canvas.height="45";
|
||||
var ctx = canvas.getContext('2d');
|
||||
document.getElementById("container").appendChild(canvas);
|
||||
ctx.beginPath();
|
||||
ctx.rect(0, 0, 80, 45);
|
||||
ctx.fillStyle = "#000";
|
||||
ctx.fill();
|
||||
|
||||
for (var i=0;i<layout.length;i++){
|
||||
|
||||
ctx.fillStyle = colors[layout[i].i];
|
||||
ctx.lineWidth = 3;
|
||||
var x = layout[i].x*0.8 || 0;
|
||||
var y = layout[i].y*0.45 || 0;
|
||||
var w = layout[i].w*0.8 || 0;
|
||||
var h = layout[i].h*0.45 || 0;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.rect(x, y, w, h);
|
||||
ctx.fill();
|
||||
}
|
||||
|
||||
canvas.dataset.layout = JSON.stringify(layout);
|
||||
//canvas.onclick = activate;
|
||||
canvas.onclick = remoteActivate;
|
||||
|
||||
if (slotsNeeded<layout.length){
|
||||
slotsNeeded = layout.length;
|
||||
for (var i=0;i<slotsNeeded;i++){
|
||||
if (!document.querySelector("div[data-slot='"+(i+1)+"']")){
|
||||
var emptySlot = document.createElement("div");
|
||||
emptySlot.innerHTML = "SLOT "+(i+1);
|
||||
emptySlot.classList.add("empty");
|
||||
emptySlot.dataset.slot = (i+1)+"";
|
||||
emptySlot.style.backgroundColor = colors[i];
|
||||
document.getElementById("col1").appendChild(emptySlot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function drawAutoLayout(){
|
||||
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width="80";
|
||||
canvas.height="45";
|
||||
var ctx = canvas.getContext('2d');
|
||||
document.getElementById("container").appendChild(canvas);
|
||||
ctx.beginPath();
|
||||
ctx.rect(0, 0, 80, 45);
|
||||
ctx.fillStyle = "#000";
|
||||
ctx.fill();
|
||||
|
||||
ctx.fillStyle = "#FFF";
|
||||
ctx.font = "15px Arial";
|
||||
ctx.fillText(" clear ", 4, 25);
|
||||
|
||||
canvas.dataset.layout = false;
|
||||
//canvas.onclick = activate;
|
||||
canvas.onclick = remoteActivate;
|
||||
|
||||
|
||||
}
|
||||
|
||||
drawAutoLayout();
|
||||
|
||||
|
||||
var data = [
|
||||
{x:0, y:0, w:100, h:100}
|
||||
];
|
||||
drawLayout(data);
|
||||
|
||||
|
||||
var data = [
|
||||
null,
|
||||
{x:0, y:0, w:100, h:100, c:true}
|
||||
];
|
||||
drawLayout(data);
|
||||
|
||||
|
||||
var data = [
|
||||
{x:0, y:25, w:50, h:50, c:true},
|
||||
{x:50, y:25, w:50, h:50, c:true}
|
||||
];
|
||||
drawLayout(data);
|
||||
|
||||
|
||||
|
||||
var data = [
|
||||
{x:70, y:70, w:30, h:30, z:1, c:false},
|
||||
{x:0, y:0, w:100, h:100,z:0, c:true}
|
||||
];
|
||||
drawLayout(data);
|
||||
|
||||
|
||||
var data = [
|
||||
{x:0, y:0, w:100, h:100,z:0, c:true},
|
||||
{x:70, y:70, w:30, h:30, z:1, c:false}
|
||||
];
|
||||
drawLayout(data);
|
||||
|
||||
|
||||
var data = [
|
||||
{x:0, y:0, w:20, h:20, z:1, c:false},
|
||||
{x:0, y:0, w:100, h:100,z:0, c:true}
|
||||
];
|
||||
drawLayout(data);
|
||||
|
||||
|
||||
var data = [
|
||||
{x:0, y:0, w:50, h:50},
|
||||
{x:50, y:0, w:50, h:50},
|
||||
{x:0, y:50, w:50, h:50},
|
||||
{x:50, y:50, w:50, h:50}
|
||||
];
|
||||
drawLayout(data);
|
||||
|
||||
|
||||
var data = [
|
||||
{x:0, y:16.667, w:66.667, h:66.667},
|
||||
{x:66.667, y:0, w:33.333, h:33.333},
|
||||
{x:66.667, y:33.333, w:33.333, h:33.333},
|
||||
{x:66.667, y:66.667, w:33.333, h:33.333}
|
||||
];
|
||||
drawLayout(data);
|
||||
|
||||
|
||||
var data = [
|
||||
{x:66.667, y:0, w:33.333, h:33.333},
|
||||
{x:0, y:16.667, w:66.667, h:66.667},
|
||||
{x:66.667, y:33.333, w:33.333, h:33.333},
|
||||
{x:66.667, y:66.667, w:33.333, h:33.333}
|
||||
];
|
||||
drawLayout(data);
|
||||
|
||||
|
||||
var data = [
|
||||
null,
|
||||
null,
|
||||
{x:0, y:0, w:100, h:100}
|
||||
];
|
||||
drawLayout(data);
|
||||
|
||||
|
||||
var data = [
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
{x:0, y:0, w:100, h:100}
|
||||
];
|
||||
drawLayout(data);
|
||||
|
||||
|
||||
var data = [
|
||||
null,
|
||||
null,
|
||||
{x:70, y:70, w:30, h:30, z:1, c:false},
|
||||
{x:0, y:0, w:100, h:100,z:0, c:true}
|
||||
];
|
||||
drawLayout(data);
|
||||
|
||||
|
||||
var data = [
|
||||
null,
|
||||
null,
|
||||
{x:0, y:25, w:50, h:50, c:true},
|
||||
{x:50, y:25, w:50, h:50, c:true}
|
||||
];
|
||||
drawLayout(data);
|
||||
|
||||
|
||||
|
||||
iframe.src = iframesrc;
|
||||
iframeContainer.appendChild(iframe);
|
||||
document.getElementById("container").appendChild(iframeContainer);
|
||||
|
||||
|
||||
//////////// LISTEN FOR EVENTS
|
||||
|
||||
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
|
||||
var eventer = window[eventMethod];
|
||||
var messageEvent = eventMethod === "attachEvent" ? "onmessage" : "message";
|
||||
|
||||
|
||||
/// If you have a routing system setup, you could have just one global listener for all iframes instead.
|
||||
|
||||
eventer(messageEvent, function (e) {
|
||||
if (e.source != iframe.contentWindow){return} // reject messages send from other iframes
|
||||
|
||||
|
||||
if ("action" in e.data){
|
||||
var outputWindow = document.createElement("div");
|
||||
outputWindow.innerHTML = "event: "+e.data.action+"<br />";
|
||||
outputWindow.style.border="1px dotted black";
|
||||
iframeContainer.appendChild(outputWindow);
|
||||
|
||||
if (e.data.action === "new-view-connection"){
|
||||
iframe.contentWindow.postMessage({"getStreamIDs":true}, '*');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ("streamIDs" in e.data){
|
||||
streamIDs = [];
|
||||
for (var key in e.data.streamIDs){
|
||||
streamIDs.push(key);
|
||||
}
|
||||
updateList();
|
||||
console.log(streamIDs);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="loadIframe();">
|
||||
<div class="col" id="sources">
|
||||
<div id="col2" ondrop="dropRemove(event)" ondragover="allowDrop(event)" ondragenter="dragenter(event)" ondragleave="dragleave(event)">
|
||||
<div class="thing" draggable="false" id="delete">Remove</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col" id="col1" ondrop="drop(event)" ondragover="allowDrop(event)" ondragenter="dragenter(event)" ondragleave="dragleave(event)">
|
||||
<div class="empty" data-slot="1">SLOT 1</div>
|
||||
<div class="empty" data-slot="2">SLOT 2</div>
|
||||
<div class="empty" data-slot="3">SLOT 3</div>
|
||||
<div class="empty" data-slot="4">SLOT 4</div>
|
||||
</div>
|
||||
<div id="container">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
x
Reference in New Issue
Block a user