Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
293 lines (257 sloc) 10.4 KB
<!DOCTYPE HTML>
<!--
(c) 2016, Kundan Singh. All Rights Reserved.
The web page displays two video elements, and uses WebRTC to show a user interface
of the a video call. It uses WebSocket connection to notify.py to exchange signaling
data.
To start as the first user, offerer, just launch it without any query parameter.
Once launched, it will show a URL with a query parameter, to be used for the answerer.
Click on the URL to open the answerer in a new tab, or copy and send the URL in
another browser on another machine. The term, offerer and answerer, are in the context
of which side sends the session offer and which sends sends the session answer when
establishing a peer connection.
To test this, first install rtclite and start the websocket server as follows.
$ python -m rtclite.app.web.rtc.notify -l tcp:0.0.0.0:8080 -d
Then put this file under a web server, such as python's SimpleHTTPServer as follows:
$ python -m SimpleHTTPServer 8000
Then open a WebRTC capable browser such as Google Chrome and visit:
http://localhost:8000/rtclite/app/web/rtc/webrtc.html
Once connected, it will show local video and another link. Click on the other link
or send it to another machine to open. Now you should be in a two-party video call.
-->
<html>
<head>
<title>webrtc test</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<meta name="author" content="Kundan Singh"/>
<style type="text/css">
body { margin: 0; padding: 0; position: absolute; width: 100%; height: 100%; }
video#local { position: absolute; width: 320px; height: 240px; left: 2px; top: 2px; background: black; }
video#remote { position: absolute; width: 320px; height: 240px; left: 324px; top: 2px; background: black; }
div { position: absolute; top: 244px; left: 2px; right: 2px; }
input#url { width: 150px; }
input#session { width: 50px; }
input[type="button"] { border: solid 1px #808080; background: #efefef; cursor: pointer; }
input[type="button"]:hover { border-color: #00ff00; }
</style>
</head>
<body>
<video id="local" autoplay controls muted></video>
<video id="remote" autoplay controls></video>
<div>
<a id="url"></a>
</div>
<script type="text/javascript">
var sid = "", mode = "";
var ws = null, peerconnection = null, local_stream = null, pending = [];
if (typeof console == "undefined" || typeof console.log == "undefined") {
console = { log: function(msg) { alert(msg); } };
}
function $(index) {
if (index.charAt(0) == "#") {
return document.getElementById(index.substr(1));
}
return null;
}
function onopen() {
console.log("onopen");
do_peerconnection1();
}
function onclose() {
console.log("onclose");
if (window.history) {
window.history.pushState("without url", "webrtc test", window.location.href.split('?')[0]);
}
$("#url").href = window.location.href.split('?')[0];
$("#url").removeAttribute("target")
$("#url").innerHTML = "call closed, refresh the page for new call"
ws = null;
pending.splice(0, pending.length);
if (peerconnection) {
peerconnection.close();
peerconnection = null;
}
if (local_stream) {
var audio = local_stream.getAudioTracks();
var video = local_stream.getVideoTracks();
for (var i=0; i<audio.length; ++i) {
audio[0].ended = true;
}
for (var i=0; i<video.length; ++i) {
video[0].ended = true;
}
local_stream = null;
}
}
function onmessage(event) {
console.log("< " + event.data);
var request = JSON.parse(event.data);
if (request.msg_id == 1) {
do_peerconnection2(request.result);
}
else if (request.method == "NOTIFY") {
if (peerconnection) {
onnotify(request.data);
}
else {
pending.push(request.data);
}
}
}
function send(message) {
console.log("> " + message);
ws.send(message);
}
function do_local() {
navigator.mediaDevices.getUserMedia({audio: true, video: true})
.then(function(stream) {
local_stream = stream;
$("#local").srcObject = stream;
do_connect();
})
.catch(function(error) {
console.log("failed to get user media");
console.log(error);
});
}
function do_connect() {
var ws_url = "ws://localhost:8080/call/" + sid;
console.log("connecting to " + ws_url);
ws = new WebSocket(ws_url);
ws.onopen = onopen;
ws.onclose = onclose;
ws.onmessage = onmessage;
}
function do_peerconnection1() {
var request = {msg_id: 1, method: "GET", resource: "/peerconnection"};
send(JSON.stringify(request));
}
function do_peerconnection2(data) {
console.log('creating peer connection for mode=' + mode)
peerconnection = new RTCPeerConnection(data.configuration);
peerconnection.onicecandidate = onicecandidate;
peerconnection.ontrack = onaddtrack;
peerconnection.onremovetrack = onremovetrack;
if (mode == "caller") {
console.log("addStream " + local_stream);
peerconnection.addStream(local_stream);
// var tracks = local_stream.getTracks();
// for (var i=0; i<tracks.length; ++i) {
// console.log("addTrack " + i + " " + tracks[i]);
// peerconnection.addTrack(tracks[i]);
// }
onnegotiationneeded(null);
}
else if (pending.length > 0) {
var todo = pending.slice(0);
pending.splice(pending.length);
for (var i=0; i<todo.length; ++i) {
onnotify(todo[i]);
}
}
}
function onnotify(data) {
if (data == null || data.candidate) {
onrecvcandidate(data);
}
else if (data.type == "offer") {
onrecvoffer(data);
}
else if (data.type == "answer") {
onrecvanswer(data);
}
}
function onrecvoffer(data) {
peerconnection.setRemoteDescription(new RTCSessionDescription(data))
.then(function() {
peerconnection.addStream(local_stream);
// var tracks = local_stream.getTracks();
// for (var i=0; i<tracks.length; ++i) {
// console.log("addTrack " + i + " " + tracks[i]);
// peerconnection.addTrack(tracks[i]);
// }
})
.then(function() {
return peerconnection.createAnswer();
})
.then(function(answer) {
return peerconnection.setLocalDescription(answer);
})
.then(function() {
send(JSON.stringify({method: "NOTIFY", data: peerconnection.localDescription}));
})
.catch(function(error) {
console.log("failed to createAnswer: " + error);
});
}
function onrecvanswer(data) {
peerconnection.setRemoteDescription(new RTCSessionDescription(data))
.catch(function(error) {
console.log("failed to setRemoteDescription: " + error);
});
}
function onrecvcandidate(data) {
if (data) {
peerconnection.addIceCandidate(new RTCIceCandidate(data))
.catch(function(error) {
console.log("failed to addIceCandidate: " + error);
});
}
}
function onnegotiationneeded(event) {
console.log("onnegotiationneeded")
peerconnection.createOffer()
.then(function(offer) {
return peerconnection.setLocalDescription(offer);
})
.then(function() {
send(JSON.stringify({method: "NOTIFY", data: peerconnection.localDescription}));
})
.catch(function(error) {
console.log("failed to createOffer");
});
}
function onicecandidate(event) {
console.log("onicecandidate");
send(JSON.stringify({method: "NOTIFY", data: event.candidate}));
}
function onaddtrack(event) {
console.log(event);
console.log("onaddtrack: " + event.streams[0]);
if ($("#remote").srcObject != event.streams[0]) {
$("#remote").srcObject = event.streams[0];
}
}
function onremovetrack(event) {
console.log("onremovetrack");
var stream = $("#remote").srcObject;
var tracks = stream.getTracks();
if (tracks.length == 0) {
$("#remote").srcObject = null;
}
}
function initialize() {
var url = window.location.href
if (window.location.search) {
sid = window.location.search.substr(1);
mode = "callee";
}
else {
sid = ("" + Math.random()).substr(2, 10);
url += "?" + sid;
mode = "caller";
if (window.history) {
window.history.pushState("with url", "webrtc test", url);
}
}
$("#url").href = url;
$("#url").setAttribute("target", "_blank");
$("#url").innerHTML = url;
setTimeout(do_local, 500);
//do_local(); // causes invalidStateError on getUserMedia
}
initialize();
</script>
</body>
</html>
You can’t perform that action at this time.