UNPKG

rtcmulticonnection

Version:

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

386 lines (320 loc) 12.1 kB
<!-- Demo version: 2018.09.22 --> <!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title>Video + Screen Sharing using RTCMultiConnection</title> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0"> <link rel="shortcut icon" href="/demos/logo.png"> <link rel="stylesheet" href="/demos/stylesheet.css"> <script src="/demos/menu.js"></script> </head> <body> <header> <a class="logo" href="/demos/"><img src="/demos/logo.png" alt="RTCMultiConnection"></a> <a href="/demos/" class="menu-explorer">Menu<img src="/demos/menu-icon.png" alt="Menu"></a> <nav> <li> <a href="/demos/">Home</a> </li> <li> <a href="https://www.rtcmulticonnection.org/docs/getting-started/">Getting Started</a> </li> <li> <a href="https://www.rtcmulticonnection.org/FAQ/">FAQ</a> </li> <li> <a href="https://www.youtube.com/playlist?list=PLPRQUXAnRydKdyun-vjKPMrySoow2N4tl">YouTube</a> </li> <li> <a href="https://rtcmulticonnection.herokuapp.com/demos/">Demos</a> </li> <li> <a href="https://github.com/muaz-khan/RTCMultiConnection/wiki">Wiki</a> </li> <li> <a href="https://github.com/muaz-khan/RTCMultiConnection">Github</a> </li> </nav> </header> <h1> Video + Screen Sharing using RTCMultiConnection <p class="no-mobile"> Multi-user (many-to-many) video chat using mesh networking model. </p> <p> Add and remove screen anytime and multiple times! </p> </h1> <section class="make-center"> <p style="margin: 0; padding: 0; padding-bottom: 20px;"> <input type="text" id="room-id" value="abcdef" autocorrect=off autocapitalize=off size=20> <button id="open-room">Open Room</button> <button id="join-room">Join Room</button> <button id="share-screen" disabled>Share Your Screen</button> </p> <div id="videos-container" style="margin: 20px 0;"></div> </section> <script src="/dist/RTCMultiConnection.min.js"></script> <script src="/dev/adapter.js"></script> <script src="/socket.io/socket.io.js"></script> <!-- custom layout for HTML5 audio/video elements --> <link rel="stylesheet" href="/dev/getHTMLMediaElement.css"> <script src="/dev/getHTMLMediaElement.js"></script> <script src="/dev/getScreenId.js"></script> <script> // ...................................................... // .......................UI Code........................ // ...................................................... document.getElementById('open-room').onclick = function() { disableInputButtons(); var roomid = document.getElementById('room-id').value; beforeOpenOrJoin(roomid, function() { connection.open(roomid, function() { afterOpenOrJoin(); }); }); }; document.getElementById('join-room').onclick = function() { disableInputButtons(); var roomid = document.getElementById('room-id').value; beforeOpenOrJoin(roomid, function() { connection.join(roomid, function() { // join callback afterOpenOrJoin(); }); }); }; // ...................................................... // ..................RTCMultiConnection Code............. // ...................................................... var connection = new RTCMultiConnection(); // by default, socket.io server is assumed to be deployed on your own URL connection.socketURL = '/'; // comment-out below line if you do not have your own socket.io server // connection.socketURL = 'https://rtcmulticonnection.herokuapp.com:443/'; connection.socketMessageEvent = 'video-screen-demo'; connection.session = { audio: true, video: true }; connection.sdpConstraints.mandatory = { OfferToReceiveAudio: true, OfferToReceiveVideo: true }; connection.videosContainer = document.getElementById('videos-container'); connection.onstream = function(event) { var existing = document.getElementById(event.streamid); if(existing && existing.parentNode) { existing.parentNode.removeChild(existing); } if(event.type === 'local') { RMCMediaTrack.camera = event.stream.getVideoTracks()[0]; RMCMediaTrack.cameraStream = event.stream; } event.mediaElement.removeAttribute('src'); event.mediaElement.removeAttribute('srcObject'); event.mediaElement.muted = true; event.mediaElement.volume = 0; var video = document.createElement('video'); try { video.setAttributeNode(document.createAttribute('autoplay')); video.setAttributeNode(document.createAttribute('playsinline')); } catch (e) { video.setAttribute('autoplay', true); video.setAttribute('playsinline', true); } if(event.type === 'local') { video.volume = 0; try { video.setAttributeNode(document.createAttribute('muted')); } catch (e) { video.setAttribute('muted', true); } } video.srcObject = event.stream; var width = parseInt(connection.videosContainer.clientWidth / 3) - 20; var mediaElement = getHTMLMediaElement(video, { title: event.userid, buttons: ['full-screen'], width: width, showOnMouseEnter: false }); connection.videosContainer.appendChild(mediaElement); setTimeout(function() { mediaElement.media.play(); }, 5000); mediaElement.id = event.streamid; if(event.type === 'local') { RMCMediaTrack.selfVideo = mediaElement.media; } // to keep room-id in cache localStorage.setItem(connection.socketMessageEvent, connection.sessionid); }; connection.onstreamended = function(event) { var mediaElement = document.getElementById(event.streamid); if (mediaElement) { mediaElement.parentNode.removeChild(mediaElement); } }; connection.onMediaError = function(e) { if (e.message === 'Concurrent mic process limit.') { if (DetectRTC.audioInputDevices.length <= 1) { alert('Please select external microphone. Check github issue number 483.'); return; } var secondaryMic = DetectRTC.audioInputDevices[1].deviceId; connection.mediaConstraints.audio = { deviceId: secondaryMic }; connection.join(connection.sessionid); } }; // .................................. // ALL below scripts are redundant!!! // .................................. function disableInputButtons() { document.getElementById('room-id').onkeyup(); document.getElementById('open-room').disabled = true; document.getElementById('join-room').disabled = true; document.getElementById('room-id').disabled = true; } // ...................................................... // ......................Handling Room-ID................ // ...................................................... var roomid = ''; if (localStorage.getItem(connection.socketMessageEvent)) { roomid = localStorage.getItem(connection.socketMessageEvent); } else { roomid = connection.token(); } var txtRoomId = document.getElementById('room-id'); txtRoomId.value = roomid; txtRoomId.onkeyup = txtRoomId.oninput = txtRoomId.onpaste = function() { localStorage.setItem(connection.socketMessageEvent, document.getElementById('room-id').value); }; // detect 2G if(navigator.connection && navigator.connection.type === 'cellular' && navigator.connection.downlinkMax <= 0.115) { alert('2G is not supported. Please use a better internet service.'); } </script> <script type="text/javascript"> // screen sharing codes goes here var RMCMediaTrack = { camera: null, screen: null }; function beforeOpenOrJoin(roomid, callback) { connection.socketCustomEvent = roomid; callback(); } function afterOpenOrJoin() { connection.socket.on(connection.socketCustomEvent, function(message) { if(message.userid === connection.userid) return; // ignore self messages if(message.justSharedMyScreen === true) { var video = document.getElementById(message.userid); if(video) { // video.querySelector('video').srcObject = null; } } if(message.justStoppedMyScreen === true) { var video = document.getElementById(message.userid); if(video) { video.querySelector('video').srcObject = null; } } }); } var btnShareScreen = document.getElementById('share-screen'); connection.onUserStatusChanged = function() { btnShareScreen.disabled = connection.getAllParticipants().length <= 0; }; btnShareScreen.onclick = function() { this.disabled = true; getScreenStream(function(screen) { RMCMediaTrack.screen = screen.getVideoTracks()[0]; var isLiveSession = connection.getAllParticipants().length > 0; if(isLiveSession) { replaceTrack(RMCMediaTrack.screen); } }); }; function addStreamStopListener(stream, callback) { var streamEndedEvent = 'ended'; if ('oninactive' in stream) { streamEndedEvent = 'inactive'; } stream.addEventListener(streamEndedEvent, function() { callback(); callback = function() {}; }, false); stream.getAudioTracks().forEach(function(track) { track.addEventListener(streamEndedEvent, function() { callback(); callback = function() {}; }, false); }); stream.getVideoTracks().forEach(function(track) { track.addEventListener(streamEndedEvent, function() { callback(); callback = function() {}; }, false); }); } function getScreenStream(callback) { getScreenId(function (error, sourceId, screen_constraints) { navigator.mediaDevices.getUserMedia(screen_constraints).then(function(screen) { RMCMediaTrack.selfVideo.srcObject = screen; callback(screen); addStreamStopListener(screen, function() { RMCMediaTrack.selfVideo.srcObject = RMCMediaTrack.cameraStream; connection.socket && connection.socket.emit(connection.socketCustomEvent, { justStoppedMyScreen: true, userid: connection.userid }); // share camera again replaceTrack(RMCMediaTrack.camera); // so that user can share again btnShareScreen.disabled = false; }); connection.socket && connection.socket.emit(connection.socketCustomEvent, { justSharedMyScreen: true, userid: connection.userid }); }); }); } function replaceTrack(videoTrack) { connection.getAllParticipants().forEach(function(pid) { var peer = connection.peers[pid].peer; if (!peer.getSenders) return; var trackToReplace = videoTrack; peer.getSenders().forEach(function(sender) { if (!sender || !sender.track) return; if (sender.track.kind === 'video' && trackToReplace) { sender.replaceTrack(trackToReplace); trackToReplace = null; } }); }); } </script> <section> <p> You can write cordova/ionic/phonegap based <a href="https://www.rtcmulticonnection.org/docs/Write-iOS-Apps/" target="_blank">iOS</a> or <a href="https://www.rtcmulticonnection.org/docs/Write-Android-Apps/" target="_blank">Android</a> apps for this demo as well. </p> <p> You can run same demo on Safari-11 as well. (both on MacOSX & iOS) </p> <p> Microsoft Edge is also supported. </p> </section> <footer> <small id="send-message"></small> </footer> <script src="https://cdn.webrtc-experiment.com/common.js"></script> </body> </html>