<dialog class = "ready-dialog mdl-dialog"> html code works only on chrome browser
Opened this issue · 0 comments
burakguder commented
The session cannot be attended because other browsers do not support the dialog feature.
I replaced this with $('#modalinfo').modal
www/index.html
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700" type="text/css">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://code.getmdl.io/1.3.0/material.indigo-pink.min.css">
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link href="css/getmdl-select.min.css" rel="stylesheet" type="text/css"/>
<link href="css/flag-icon.min.css" rel="stylesheet" type="text/css"/>
<link href="css/bootstrap.min.css" rel="stylesheet">
<script src="js/jquery-2.2.4.min.js"></script>
<script src="js/common_scripts.js"></script>
<script src="js/jquery-ui-1.8.22.min.js"></script>
<script defer src="https://code.getmdl.io/1.3.0/material.min.js"></script>
<script src="js/transaction-manager.js" type="text/javascript"></script>
<script src="js/getmdl-select.js" type="text/javascript"></script>
<script src="js/soundmeter.js" type="text/javascript"></script>
<script src="js/sfu.js" type="text/javascript"></script>
<style>
body {
background: #e2e1e0;
text-align: center;
margin: 0px;
padding: 0px;
}
.scroll {
overflow: auto;
overflow: overlay;
z-index: 9;
scroll-snap-type: proximity;
}
.scroll::-webkit-scrollbar {
position: absolute;
width: 12px;
height: 12px;
}
.scroll::-webkit-scrollbar-button {
width: 0px;
height: 0px;
}
.scroll::-webkit-scrollbar-corner {
background-color: transparent;
}
.scroll::-webkit-scrollbar-track {
border: 4px solid transparent;
border-radius: 50px;
background-clip: content-box;
background-color: transparent;
}
.scroll::-webkit-scrollbar-thumb {
border: 4px solid transparent;
border-radius: 50px;
background-clip: content-box;
background-color: rgba(0, 0, 0, 0.2);
min-height: 40px;
}
.scroll.dark::-webkit-scrollbar-thumb {
background-color: rgba(255, 255, 255, 0.4);
min-height: 40px;
}
.scroll:hover::-webkit-scrollbar-track {
background-color: rgba(0, 0, 0, 0.1);
}
.scroll.dark:hover::-webkit-scrollbar-track {
background-color: rgba(255, 255, 255, 0.2);
}
.scroll:hover::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, 0.3);
}
.scroll.dark:hover::-webkit-scrollbar-thumb {
background-color: rgba(255, 255, 255, 0.6);
}
.scroll:hover::-webkit-scrollbar-track:hover {
background-color: rgba(0, 0, 0, 0.2);
}
.scroll.dark:hover::-webkit-scrollbar-track:hover {
background-color: rgba(255, 255, 255, 0.3);
}
.scroll:hover::-webkit-scrollbar-thumb:hover {
background-color: rgba(0, 0, 0, 0.5);
}
.scroll.dark:hover::-webkit-scrollbar-thumb:hover {
background-color: rgba(255, 255, 255, 0.8);
}
.scroll:hover::-webkit-scrollbar-thumb:active {
background-color: rgba(0, 0, 0, 0.8);
}
.scroll.dark:hover::-webkit-scrollbar-thumb:active {
background-color: rgba(255, 255, 255, 0.8);
}
.scroll.scroll-big::-webkit-scrollbar {
width: 24px;
height: 24px;
}
.scroll.scroll-big::-webkit-scrollbar-button {
width: 0px;
height: 0px;
}
.scroll.scroll-big::-webkit-scrollbar-corner {
background-color: transparent;
}
.scroll.scroll-big::-webkit-scrollbar-track {
border: 9px solid transparent;
border-radius: 50px;
background-clip: content-box;
background-color: transparent;
}
.scroll.scroll-big::-webkit-scrollbar-thumb {
border: 9px solid transparent;
border-radius: 50px;
background-clip: content-box;
background-color: rgba(0, 0, 0, 0.2);
min-height: 40px;
}
.scroll.scroll-big.dark::-webkit-scrollbar-thumb {
background-color: rgba(255, 255, 255, 0.4);
min-height: 40px;
}
.scroll.scroll-big:hover::-webkit-scrollbar-track {
background-color: rgba(0, 0, 0, 0.1);
}
.scroll.scroll-big.dark:hover::-webkit-scrollbar-track {
background-color: rgba(255, 255, 255, 0.2);
}
.scroll.scroll-big:hover::-webkit-scrollbar-thumb {
background-color: rgba(0, 0, 0, 0.3);
}
.scroll.scroll-big.dark:hover::-webkit-scrollbar-thumb {
background-color: rgba(255, 255, 255, 0.6);
}
.scroll.scroll-big:hover::-webkit-scrollbar-track:hover {
background-color: rgba(0, 0, 0, 0.2);
}
.scroll.scroll-big.dark:hover::-webkit-scrollbar-track:hover {
background-color: rgba(255, 255, 255, 0.3);
}
.scroll.scroll-big:hover::-webkit-scrollbar-thumb:hover {
background-color: rgba(0, 0, 0, 0.5);
}
.scroll.scroll-big.dark:hover::-webkit-scrollbar-thumb:hover {
background-color: rgba(255, 255, 255, 0.8);
}
.scroll.scroll-big:hover::-webkit-scrollbar-thumb:active {
background-color: rgba(0, 0, 0, 0.8);
}
.scroll.scroll-big.dark:hover::-webkit-scrollbar-thumb:active {
background-color: rgba(255, 255, 255, 0.8);
}
video {
object-fit: cover;
float: left;
background: #fff;
border-radius: 2px;
display: inline-block;
margin: 1rem;
position: relative;
height: 150px;
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
transition: all 0.5s cubic-bezier(.25,.8,.25,1);
padding:1px;
bottom: 0px;
max-width: 200px;
opacity: 1;
}
.disabled {
height: 0px;
opacity: 0;
}
video:hover {
box-shadow: 0 14px 28px rgba(0,0,0,0.25), 0 10px 10px rgba(0,0,0,0.22);
bottom: 125px;
height: 300px;
max-width: 400px;
}
video::before {
content: "hola";
}
video::after {
content: "hola";
}
#outher-container {
margin: 0px;
padding: 0px;
width: 100%;
position: fixed;
bottom: 5px;
height: 100%;
display: flex;
overflow-x: auto;
overflow-y: hidden;
}
#container {
position: absolute;
bottom: 60px;
margin: 0px;
padding: 0px;
height: 150px;
display: flex;
}
.ready-dialog
{
width: 640px;
text-align: left;
}
.ready-dialog p
{
color: black;
font-size: 12pt;
}
.ready-dialog code
{
font-size: 12pt;
}
/***********************************/
.bar-audio{
display: block;
margin: 0 auto;
padding-left: 40px;
padding-bottom: 5px;
}
bar-audio p.text-1{
font-size: 8px;
margin: 5px;
}
bar-audio p.text-1 span{
font-size: 8px;
padding-left: 155px;
}
.bg-bar-outher {
width: 300px;
text-align: left;
}
.bg-bar{
margin: 0 auto;
display:block;
height:20px;
width:202px;
background: url("images/bar_audio.png");
}
.bar-inside{
display:block;
height:20px;
width:0%;
background: url("images/bar_audio_on.png");
}
#random {
top: -8px;
left: 15px;
}
.room-header {
position: relative;
top: 10px;
margin: 0 auto;
}
.room-info {
background: #111;
border-radius: 2px;
width: 200px;
height: 40px;
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
transition: all 0.5s cubic-bezier(.25,.8,.25,1);
opacity: 0;
padding-top: 15px;
font-size: 14pt;
color: white;
}
a {
text-decoration: none !important;
}
</style>
</head>
<body>
<div id="outher-container" class="scroll">
<div class="room-header">
<div class="room-info"> Room: <a href="" id="room-id"></a></div>
</div>
<div id="container">
</div>
</div>
<div aria-hidden="true" aria-labelledby="myModalLabel" role="dialog"
tabindex="-1" id="modalinfo" class="modal fade"
style="z-index: 1200; top: 95px;">
<div class="modal-dialog">
<div class="modal-content">
<form action="#" id="ready-form">
<div class="modal-header">
<h4 class="modal-title">SFU Test154 Konfium</h4>
</div>
<div class="modal-body">
<div class="alert alert-warning">Lütfen Tüm alanları Doldurunuz!</div>
<div class="form-group">
<label for="roomId">Room Id</label>
<input class="form-control" type="text" id="roomId" name="roomId" required>
</div>
<div class="form-group">
<label for="name">Adınız</label>
<input class="form-control" type="text" id="name" name="name" required>
</div>
<div class="form-group">
<label for="name">Anahtar Şifreniz</label>
<input class="form-control" type="text" id="key" name="key" required>
</div>
<div class="mdl-selectfield">
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label getmdl-select getmdl-select__fix-height">
<input class="mdl-textfield__input" type="text" id="audio_devices" readonly tabIndex="-1" value="Default">
<label for="audio_devices">
<i class="mdl-icon-toggle__label material-icons">keyboard_arrow_down</i>
</label>
<label for="audio_devices" class="mdl-textfield__label">Audio Device</label>
<ul id="audio_devices_menu" for="audio_devices" class="mdl-menu mdl-menu--bottom-left mdl-js-menu" style="width:300px">
</ul>
</div>
</div>
<div class="bg-bar-outher">
<div class="bg-bar">
<div class="voometer bar-inside" style="width: 5%;"></div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" id="random">Rastgele Ata</button>
<button type="submit" class="btn btn-danger" id="connect" >Katıl</button>
</div>
</form>
</div>
</div>
</div>
<script>
$( function() {
$('#modalinfo').modal({backdrop: 'static', keyboard: false});
$('#modalinfo').modal('show');
} );
</script>
</body>
</html>
Change
www/js/sfu.js
let participants;
let audioDeviceId;
let videoResolution = true;
//Get our url
const href = new URL(window.location.href);
//Get id
const roomId = href.searchParams.get("roomId");
//Get name
const name = href.searchParams.get("name");
//Get key
const key = href.searchParams.get("key");
//Get video
const nopublish = href.searchParams.has("nopublish");
//Get ws url from navigaro url
const url = "wss://"+href.host;
//Check support for insertabe media streams
const supportsInsertableStreams = !!RTCRtpSender.prototype.createEncodedVideoStreams;
if (href.searchParams.has ("video"))
switch (href.searchParams.get ("video").toLowerCase ())
{
case "1080p":
videoResolution = {
width: {min: 1920, max: 1920},
height: {min: 1080, max: 1080},
};
break;
case "720p":
videoResolution = {
width: {min: 1280, max: 1280},
height: {min: 720, max: 720},
};
break;
case "576p":
videoResolution = {
width: {min: 720, max: 720},
height: {min: 576, max: 576},
};
break;
case "480p":
videoResolution = {
width: {min: 640, max: 640},
height: {min: 480, max: 480},
};
break;
case "320p":
videoResolution = {
width: {min: 320, max: 320},
height: {min: 240, max: 240},
};
break;
case "no":
videoResolution = false;
break;
}
function addRemoteTrack(event)
{
console.log(event);
const track = event.track;
const stream = event.streams[0];
if (!stream)
return console.log("addRemoteTrack() no stream")
//Check if video is already present
let video = container.querySelector("video[id='"+stream.id+"']");
//Check if already present
if (video)
//Ignore
return console.log("addRemoteTrack() video already present for "+stream.id);
//Listen for end event
track.onended=(event)=>{
console.log(event);
//Check if video is already present
let video = container.querySelector("video[id='"+stream.id+"']");
//Check if already present
if (!video)
//Ignore
return console.log("removeRemoteTrack() video not present for "+stream.id);
container.removeChild(video);
}
//Create new video element
video = document.createElement("video");
//Set same id
video.id = stream.id;
//Set src stream
video.srcObject = stream;
//Set other properties
video.autoplay = true;
video.play();
//Append it
container.appendChild(video);
}
function addLocalVideoForStream(stream,muted)
{
//Create new video element
const video = document.createElement("video");
//Set same id
video.id = stream.id;
//Set src stream
video.srcObject = stream;
//Set other properties
video.autoplay = true;
video.muted = muted;
video.play();
//Append it
container.appendChild(video);
}
/*
Get some key material to use as input to the deriveKey method.
The key material is a secret key supplied by the user.
*/
async function getRoomKey(roomId,secret)
{
const enc = new TextEncoder();
const keyMaterial = await window.crypto.subtle.importKey(
"raw",
enc.encode(secret),
{name: "PBKDF2"},
false,
["deriveBits", "deriveKey"]
);
return window.crypto.subtle.deriveKey(
{
name: "PBKDF2",
salt: enc.encode(roomId),
iterations: 100000,
hash: "SHA-256"
},
keyMaterial,
{"name": "AES-GCM", "length": 256},
true,
["encrypt", "decrypt"]
);
}
/*
*
*/
async function connect(url,roomId,name,secret)
{
let counter = 0;
const roomKey = await getRoomKey(roomId,secret);
async function encrypt(chunk, controller) {
try {
//Get iv
const iv = new ArrayBuffer(4);
//Create view, inc counter and set it
new DataView(iv).setUint32(0,counter <65535 ? counter++ : counter=0);
//Encrypt
const ciphertext = await window.crypto.subtle.encrypt(
{
name: "AES-GCM",
iv: iv
},
roomKey,
chunk.data
);
//Set chunk data
chunk.data = new ArrayBuffer(ciphertext.byteLength + 4);
//Crate new encoded data and allocate size for iv
const data = new Uint8Array(chunk.data);
//Copy iv
data.set(new Uint8Array(iv),0);
//Copy cipher
data.set(new Uint8Array(ciphertext),4);
//Write
controller.enqueue(chunk);
} catch(e) {
}
}
async function decrypt(chunk, controller) {
try {
//decrypt
chunk.data = await window.crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: new Uint8Array(chunk.data,0,4)
},
roomKey,
new Uint8Array(chunk.data,4,chunk.data.byteLength - 4)
);
//Write
controller.enqueue(chunk);
} catch(e) {
}
}
const isCryptoEnabled = !!secret && supportsInsertableStreams;
var pc = new RTCPeerConnection({
bundlePolicy : "max-bundle",
rtcpMuxPolicy : "require",
forceEncodedVideoInsertableStreams : isCryptoEnabled
});
//Create room url
const roomUrl = url +"?id="+roomId;
var ws = new WebSocket(roomUrl);
var tm = new TransactionManager(ws);
pc.ontrack = (event) => {
//If encrypting/decrypting
if (isCryptoEnabled)
{
//Create transfor strem fro decrypting
const transform = new TransformStream({
start() {},
flush() {},
transform: decrypt
});
//Get the receiver streams for track
let receiverStreams = event.receiver.createEncodedVideoStreams();
//Decrytp
receiverStreams.readableStream
.pipeThrough(transform)
.pipeTo(receiverStreams.writableStream);
}
addRemoteTrack(event);
};
ws.onopen = async function()
{
console.log("ws:opened");
try
{
if (!nopublish)
{
const stream = await navigator.mediaDevices.getUserMedia({
audio: {
deviceId: audioDeviceId
},
video: videoResolution
});
console.debug("md::getUserMedia sucess",stream);
//Play it
addLocalVideoForStream(stream,true);
//Add stream to peer connection
for (const track of stream.getTracks())
{
//Add track
const sender = pc.addTrack(track,stream);
//If encrypting/decrypting
if (isCryptoEnabled)
{
//Get insertable streams
const senderStreams = sender.createEncodedVideoStreams();
//Create transform stream for encryption
let senderTransformStream = new TransformStream({
start() {},
flush() {},
transform: encrypt
});
//Encrypt
senderStreams.readableStream
.pipeThrough(senderTransformStream)
.pipeTo(senderStreams.writableStream);
}
}
}
//Create new offer
const offer = await pc.createOffer({
offerToReceiveAudio: true,
offerToReceiveVideo: true
});
console.debug("pc::createOffer sucess",offer);
//Set it
pc.setLocalDescription(offer);
console.log("pc::setLocalDescription succes",offer.sdp);
//Join room
const joined = await tm.cmd("join",{
name : name,
sdp : offer.sdp
});
console.log("cmd::join success",joined);
//Create answer
const answer = new RTCSessionDescription({
type :'answer',
sdp : joined.sdp
});
//Set it
await pc.setRemoteDescription(answer);
console.log("pc::setRemoteDescription succes",answer.sdp);
console.log("JOINED");
} catch (error) {
console.error("Error",error);
ws.close();
}
};
tm.on("cmd",async function(cmd) {
console.log("ts::cmd",cmd);
switch (cmd.name)
{
case "update" :
try
{
console.log(cmd.data.sdp);
//Create new offer
const offer = new RTCSessionDescription({
type : 'offer',
sdp : cmd.data.sdp
});
//Set offer
await pc.setRemoteDescription(offer);
console.log("pc::setRemoteDescription succes",offer.sdp);
//Create answer
const answer = await pc.createAnswer();
console.log("pc::createAnswer succes",answer.sdp);
//Only set it locally
await pc.setLocalDescription(answer);
console.log("pc::setLocalDescription succes",answer.sdp);
//accept
cmd.accept({sdp:answer.sdp});
} catch (error) {
console.error("Error",error);
ws.close();
}
break;
}
});
tm.on("event",async function(event) {
console.log("ts::event",event);
switch (event.name)
{
case "participants" :
//update participant list
participants = event.participants;
break;
}
});
}
navigator.mediaDevices.getUserMedia({
audio: true,
video: false
})
.then(function(stream){
//Set the input value
audio_devices.value = stream.getAudioTracks()[0].label;
//Get the select
var menu = document.getElementById("audio_devices_menu");
//Populate the device lists
navigator.mediaDevices.enumerateDevices()
.then(function(devices) {
//For each one
devices.forEach(function(device)
{
//It is a mic?
if (device.kind==="audioinput")
{
//Create menu item
var li = document.createElement("li");
//Populate
li.dataset["val"] = device.deviceId;
li.innerText = device.label;
li.className = "mdl-menu__item";
//Add listener
li.addEventListener('click', function() {
console.log(device.deviceId);
//Close previous
stream.getAudioTracks()[0].stop();
//Store device id
audioDeviceId = device.deviceId
//Get stream for the device
navigator.mediaDevices.getUserMedia({
audio: {
deviceId: device.deviceId
},
video: false
})
.then(function(stream){
//Store it
soundMeter.connectToSource(stream).then(draw);
});
});
//Append
menu.appendChild (li);
}
});
//Upgrade
getmdlSelect.init('.getmdl-select');
componentHandler.upgradeDom();
})
.catch(function(error){
console.log(error);
});
var fps = 20;
var now;
var then = Date.now();
var interval = 1000/fps;
var delta;
var drawTimer;
var soundMeter = new SoundMeter(window);
//Stop
cancelAnimationFrame(drawTimer);
function draw() {
drawTimer = requestAnimationFrame(draw);
now = Date.now();
delta = now - then;
if (delta > interval) {
then = now ;
var tot = Math.min(100,(soundMeter.instant*200));
//Get all
const voometers = document.querySelectorAll (".voometer");
//Set new size
for (let i=0;i<voometers.length;++i)
voometers[i].style.width = (Math.floor(tot/5)*5) + "%";
}
}
soundMeter.connectToSource(stream).then(draw);
var dialog = document.querySelector('dialog');
//dialog.showModal();
if (!supportsInsertableStreams)
$('#key').html("<red>Your browser does not support insertable streams<red>");
if (roomId)
{
$('#roomId').val(roomId);
supportsInsertableStreams && $('#key').val(key);
//$('#name').focus();
}
$( "#random" ).click(function() {
$('#roomId').val(Math.random().toString(36).substring(7));
$('#name').val(Math.random().toString(36).substring(7));
$('#key').val(Math.random().toString(36).substring(7));
});
$( "form" ).submit(function( event ) {
$('#modalinfo').modal('hide');
var a = document.querySelector(".room-info a");
a.target = "_blank";
a.href = "?roomId="+this.roomId.value;
if (this.key.value)
a.href += "&key="+encodeURI(this.key.value);
a.innerText = this.roomId.value;
a.parentElement.style.opacity = 1;
connect(url, this.roomId.value, this.name.value,this.key.value);
event.preventDefault();
});
});