UNPKG

rtcmulticonnection

Version:

RTCMultiConnection is a WebRTC JavaScript wrapper library runs top over RTCPeerConnection API to support all possible peer-to-peer features.

539 lines (453 loc) 16.5 kB
<!DOCTYPE html> <html itemscope itemtype="http://schema.org/WebPage"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0, user-scalable=no"> <title>Dashboard + Video Conferencing + Chat + File Sharing | RTCMultiConnection</title> <meta name="description" content="WebRTC Dashboard including support for canvas drawing, canvas data syncing, video conferencing, screen sharing and video conferencing. Including chat and file sharing."> <meta name="author" content="Muaz Khan"> <link rel="author" type="text/html" href="https://plus.google.com/+MuazKhan"> </head> <body> <script src="https://cdn.webrtc-experiment.com/Canvas-Designer/canvas-designer-widget.js"></script> <style> * { -webkit-user-select: none; -moz-user-select: none; -o-user-select: none; -ms-user-select: none; user-select: none; } input[type=text] { -webkit-user-select: initial; -moz-user-select: initial; -o-user-select: initial; -ms-user-select: initial; user-select: initial; } button, input { font-family: Myriad, Arial, Verdana; font-weight: normal; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; padding: 4px 12px; text-decoration: none; color: rgb(27, 26, 26); display: inline-block; box-shadow: rgb(255, 255, 255) 1px 1px 0px 0px inset; text-shadow: none; background: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(0.05, rgb(241, 241, 241)), to(rgb(230, 230, 230))); font-size: 20px; border: 1px solid red; outline:none; } button:hover, button:hover, input:focus { background: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(5%, rgb(221, 221, 221)), to(rgb(250, 250, 250))); border: 1px solid rgb(142, 142, 142); } button[disabled], input[disabled], textarea[disabled] { background: rgb(249, 249, 249); border: 1px solid rgb(218, 207, 207); color: rgb(197, 189, 189); } input { background: white; } .extra-controls { position: absolute; right: 21%; } #btn-comments { color: red; margin-top: 5px; font-size: 24px; text-shadow: 1px 1px white; } #other-videos { margin-top: 5px; } #other-videos video { width: 45%; margin: 5px; border: 1px solid black; padding: 1px; border-radius: 3px; } #txt-chat-message { width: 100%; resize: vertical; margin: 5px; margin-right: 0; min-height: 30px; } #btn-chat-message { margin: 5px; } #conversation-panel { margin-bottom: 20px; text-align: left; max-height: 200px; overflow: auto; border-top: 1px solid #E5E5E5; width: 106%; } #conversation-panel .message { border-bottom: 1px solid #E5E5E5; padding: 5px 10px; } #conversation-panel .message img, #conversation-panel .message video, #conversation-panel .message iframe { max-width: 100%; } #main-video { width: 100%; margin-top: -9px; border-bottom: 1px solid #121010; display: none; padding-bottom: 1px; } hr { height: 1px; border: 0; background: #E5E5E5; } #btn-attach-file { width: 25px; vertical-align: middle; cursor: pointer; display: none; } .checkmark { display:none; width: 15px; vertical-align: middle; } </style> <div id="widget-container" style="position: fixed;bottom: 0;right: 0;left: 20%;height: 100%;border: 1px solid black; border-top:0; border-bottom: 0;"></div> <div style="width: 20%; height: 100%; position: absolute;left:0;"> <video id="main-video" controls></video> <div id="other-videos"></div> <hr> <div style="padding: 5px 10px;"> <div id="onUserStatusChanged"> <label for="user-full-name">Name:</label> <input type="text" id="user-full-name" placeholder="Name" disabled style="margin: 5px; margin-right: 0;width: 55%;margin-right: 2px;"> <br> <label for="room-name">Room:</label> <input type="text" id="room-name" placeholder="room-name" disabled style="margin: 5px; margin-right: 0;width: 55%;margin-right: 2px;"> <br> <button id="open-room" disabled style="margin: 5px; margin-left: 52px;">Join</button> </div> </div> <div style="margin-top: 20px;position: absolute;bottom: 0;background: white; padding-bottom: 20px; width: 94%"> <div id="conversation-panel"></div> <textarea id="txt-chat-message" disabled></textarea> <button id="btn-chat-message" disabled>Send</button> <img id="btn-attach-file" src="https://webrtcweb.com/attach-file.png" title="Attach a File"> </div> </div> <script> document.getElementById('open-room').onclick = function() { var roomid = roomName.value; if (!roomid.length) return alert('Please enter roomid.'); this.disabled = true; connection.openOrJoin(roomid, function(isRoomAlreadyCreatedBySomeoneElse) { // Remove "true" from below line, if you want only presenter/moderator to share dashboard screen if(true || isRoomAlreadyCreatedBySomeoneElse === false) { onOpenRoom(); } else { document.getElementById('open-room').parentNode.innerHTML = ''; } }); }; var designer = new CanvasDesigner(); // you can place widget.html anywhere designer.widgetHtmlURL = 'https://cdn.webrtc-experiment.com/Canvas-Designer/widget.html'; designer.widgetJsURL = 'https://cdn.webrtc-experiment.com/Canvas-Designer/widget.min.js' designer.addSyncListener(function(data) { connection.send(data); }); designer.setSelected('pencil'); designer.setTools({ pencil: true, text: true, image: true, pdf: true, eraser: true, line: true, arrow: true, dragSingle: true, dragMultiple: true, arc: true, rectangle: true, quadratic: false, bezier: true, marker: true, zoom: false, lineWidth: false, colorsPicker: false, extraOptions: false, code: false, undo: true }); designer.appendTo(document.getElementById('widget-container')); </script> <script src="/dev/adapter.js"></script> <script src="/dist/RTCMultiConnection.min.js"></script> <script src="/socket.io/socket.io.js"></script> <script src="/dev/FileBufferReader.js"></script> <script> var connection = new RTCMultiConnection(); connection.socketURL = '/'; // connection.socketURL = 'https://rtcmulticonnection.herokuapp.com:443/'; connection.socketMessageEvent = 'canvas-designer'; connection.chunkSize = 16000; connection.enableFileSharing = true; connection.session = { audio: true, video: true, data: true }; connection.sdpConstraints.mandatory = { OfferToReceiveAudio: true, OfferToReceiveVideo: true }; connection.onUserStatusChanged = function(event) { var infoBar = document.getElementById('onUserStatusChanged'); var names = []; connection.getAllParticipants().forEach(function(pid) { names.push(getFullName(pid)); }); if(!names.length) { names = ['Only You']; } else { names = [connection.extra.userFullName || 'You'].concat(names); } infoBar.innerHTML = '<b>Active users:</b> ' + names.join(', '); }; connection.onopen = function(event) { connection.onUserStatusChanged(event); if (designer.pointsLength <= 0) { // make sure that remote user gets all drawings synced. setTimeout(function() { connection.send('plz-sync-points'); }, 1000); } document.getElementById('btn-chat-message').disabled = false; document.getElementById('txt-chat-message').disabled = false; document.getElementById('btn-attach-file').style.display = 'inline-block'; }; connection.onclose = connection.onerror = connection.onleave = function(event) { connection.onUserStatusChanged(event); }; connection.onmessage = function(event) { if(event.data.chatMessage) { appendChatMessage(event); return; } if(event.data.checkmark === 'received') { var checkmarkElement = document.getElementById(event.data.checkmark_id); if(checkmarkElement) { checkmarkElement.style.display = 'inline'; } return; } if (event.data === 'plz-sync-points') { designer.sync(); return; } designer.syncData(event.data); }; </script> <script src="https://cdn.webrtc-experiment.com/Canvas-Designer/dev/webrtc-handler.js"></script> <script> function onOpenRoom() { // capture canvas-2d stream // and share in realtime using RTCPeerConnection.addStream // requires: dev/webrtc-handler.js designer.captureStream(function(stream) { stream.isScreen = true; stream.streamid = stream.id; stream.type = 'local'; /* var video = document.createElement('video'); video.muted = true; video.srcObject = stream; video.play(); */ connection.attachStreams.push(stream); connection.onstream({ stream: stream, type: 'local', streamid: stream.id, // mediaElement: video }); }); } connection.onstream = function(event) { if(event.stream.isScreen) { var video = document.getElementById('main-video'); video.setAttribute('data-streamid', event.streamid); video.style.display = 'block'; video.srcObject = event.stream; video.play(); } else { event.mediaElement.controls = false; var otherVideos = document.querySelector('#other-videos'); otherVideos.appendChild(event.mediaElement); } }; connection.onstreamended = function(event) { var video = document.querySelector('video[data-streamid="' + event.streamid + '"]'); if(!video) { video = document.getElementById(event.streamid); if(video) { video.parentNode.removeChild(video); return; } } if(video) { video.srcObject = null; video.style.display = 'none'; } }; var conversationPanel = document.getElementById('conversation-panel'); function appendChatMessage(event, checkmark_id) { var div = document.createElement('div'); div.className = 'message'; if(event.data) { div.innerHTML = '<b>' + (event.extra.userFullName || event.userid) + ':</b><br>' + event.data.chatMessage; if(event.data.checkmark_id) { connection.send({ checkmark: 'received', checkmark_id: event.data.checkmark_id }); } } else { div.innerHTML = '<b>You:</b> <img class="checkmark" id="' + checkmark_id + '" title="Received" src="https://webrtcweb.com/checkmark.png"><br>' + event; div.style.background = '#cbffcb'; } conversationPanel.appendChild(div); conversationPanel.scrollTop = conversationPanel.clientHeight; conversationPanel.scrollTop = conversationPanel.scrollHeight - conversationPanel.scrollTop; } document.getElementById('btn-chat-message').onclick = function() { var chatMessage = document.getElementById('txt-chat-message').value; document.getElementById('txt-chat-message').value = ''; if(!chatMessage || !chatMessage.replace(/ /g, '').length) return; var checkmark_id = connection.userid + connection.token(); appendChatMessage(chatMessage, checkmark_id); connection.send({ chatMessage: chatMessage, checkmark_id: checkmark_id }); }; document.getElementById('txt-chat-message').onkeyup = function(e) { var code = e.keyCode || e.which; if (code == 13) { document.getElementById('btn-chat-message').click(); // you can even call "onclick" } }; document.getElementById('btn-attach-file').onclick = function() { var file = new FileSelector(); file.selectSingleFile(function(file) { connection.send(file); }); }; function getFileHTML(file) { var url = file.url || URL.createObjectURL(file); var attachment = '<a href="' + url + '" target="_blank" download="' + file.name + '">Download: <b>' + file.name + '</b></a>'; if (file.name.match(/\.jpg|\.png|\.jpeg|\.gif/gi)) { attachment += '<br><img crossOrigin="anonymous" src="' + url + '">'; } else if (file.name.match(/\.wav|\.mp3/gi)) { attachment += '<br><audio src="' + url + '" controls></audio>'; } else if (file.name.match(/\.pdf|\.js|\.txt|\.sh/gi)) { attachment += '<iframe class="inline-iframe" src="' + url + '"></iframe></a>'; } return attachment; } function getFullName(userid) { var _userFullName = userid; if(connection.peers[userid] && connection.peers[userid].extra.userFullName) { _userFullName = connection.peers[userid].extra.userFullName; } return _userFullName; } connection.onFileEnd = function (file) { var html = getFileHTML(file); var div = progressHelper[file.uuid].div; if(file.userid === connection.userid) { div.innerHTML = '<b>You:</b><br>' + html; div.style.background = '#cbffcb'; } else { div.innerHTML = '<b>' + getFullName(file.userid) + ':</b><br>' + html; } }; // to make sure file-saver dialog is not invoked. connection.autoSaveToDisk = false; var progressHelper = {}; connection.onFileProgress = function (chunk, uuid) { var helper = progressHelper[chunk.uuid]; helper.progress.value = chunk.currentPosition || chunk.maxChunks || helper.progress.max; updateLabel(helper.progress, helper.label); }; connection.onFileStart = function (file) { var div = document.createElement('div'); div.className = 'message'; if(file.userid === connection.userid) { div.innerHTML = '<b>You:</b><br><label>0%</label> <progress></progress>'; div.style.background = '#cbffcb'; } else { div.innerHTML = '<b>' + getFullName(file.userid) + ':</b><br><label>0%</label> <progress></progress>'; } div.title = file.name; conversationPanel.appendChild(div); progressHelper[file.uuid] = { div: div, progress: div.querySelector('progress'), label: div.querySelector('label') }; progressHelper[file.uuid].progress.max = file.maxChunks; conversationPanel.scrollTop = conversationPanel.clientHeight; conversationPanel.scrollTop = conversationPanel.scrollHeight - conversationPanel.scrollTop; }; function updateLabel(progress, label) { if (progress.position == -1) return; var position = +progress.position.toFixed(2).split('.')[1] || 100; label.innerHTML = position + '%'; } var roomName = document.getElementById('room-name'); var userFullName = document.getElementById('user-full-name'); document.getElementById('open-room').disabled = false; roomName.disabled = false; userFullName.disabled = false; roomName.onkeyup = roomName.onblur = roomName.oninput = roomName.onpaste = function() { localStorage.setItem('canvas-designer-roomid', this.value); }; if (localStorage.getItem('canvas-designer-roomid')) { roomName.value = localStorage.getItem('canvas-designer-roomid'); } userFullName.onkeyup = userFullName.onblur = userFullName.oninput = userFullName.onpaste = function() { localStorage.setItem('canvas-designer-user-full-name', userFullName.value); connection.extra.userFullName = userFullName.value; if(connection.getAllParticipants().length) { connection.updateExtraData(); } }; if (localStorage.getItem('canvas-designer-user-full-name')) { userFullName.value = localStorage.getItem('canvas-designer-user-full-name'); } if(userFullName.value.length && userFullName.value.replace(/ /g, '').length) { connection.extra.userFullName = userFullName.value; } </script> </body> </html>