Permalink
Fetching contributors…
Cannot retrieve contributors at this time
404 lines (333 sloc) 12.7 KB
<!-- Demo version: 2018.10.03 -->
<!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="/node_modules/webrtc-adapter/out/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="/node_modules/webrtc-screen-capturing/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' && event.stream.isVideo) {
RMCMediaTrack.cameraStream = event.stream;
RMCMediaTrack.cameraTrack = event.stream.getVideoTracks()[0];
}
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 = {
cameraStream: null,
cameraTrack: 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) {
var isLiveSession = connection.getAllParticipants().length > 0;
if (isLiveSession) {
replaceTrack(RMCMediaTrack.screen);
}
// now remove old video track from "attachStreams" array
// so that newcomers can see screen as well
connection.attachStreams.forEach(function(stream) {
stream.getVideoTracks().forEach(function(track) {
stream.removeTrack(track);
});
// now add screen track into that stream object
stream.addTrack(RMCMediaTrack.screen);
});
});
};
function getScreenStream(callback) {
getScreenId(function(error, sourceId, screen_constraints) {
navigator.mediaDevices.getUserMedia(screen_constraints).then(function(screen) {
RMCMediaTrack.screen = screen.getVideoTracks()[0];
RMCMediaTrack.selfVideo.srcObject = screen;
// in case if onedned event does not fire
(function looper() {
// readyState can be "live" or "ended"
if (RMCMediaTrack.screen.readyState === 'ended') {
RMCMediaTrack.screen.onended();
return;
}
setTimeout(looper, 1000);
})();
var firedOnce = false;
RMCMediaTrack.screen.onended = RMCMediaTrack.screen.onmute = RMCMediaTrack.screen.oninactive = function() {
if (firedOnce) return;
firedOnce = true;
if (RMCMediaTrack.cameraStream.getVideoTracks()[0].readyState) {
RMCMediaTrack.cameraStream.getVideoTracks().forEach(function(track) {
RMCMediaTrack.cameraStream.removeTrack(track);
});
RMCMediaTrack.cameraStream.addTrack(RMCMediaTrack.cameraTrack);
}
RMCMediaTrack.selfVideo.srcObject = RMCMediaTrack.cameraStream;
connection.socket && connection.socket.emit(connection.socketCustomEvent, {
justStoppedMyScreen: true,
userid: connection.userid
});
// share camera again
replaceTrack(RMCMediaTrack.cameraTrack);
// now remove old screen from "attachStreams" array
connection.attachStreams = [RMCMediaTrack.cameraStream];
// so that user can share again
btnShareScreen.disabled = false;
};
connection.socket && connection.socket.emit(connection.socketCustomEvent, {
justSharedMyScreen: true,
userid: connection.userid
});
callback(screen);
});
});
}
function replaceTrack(videoTrack) {
if (!videoTrack) return;
if (videoTrack.readyState === 'ended') {
alert('Can not replace an "ended" track. track.readyState: ' + videoTrack.readyState);
return;
}
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>