-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
221 lines (202 loc) · 7.47 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
<html>
<body>
<title>Multi-peer WebRTC Demo</title>
<table style="width:100%; height:100%">
<tr>
<td style="text-align:center">
<video id="mainVideo" muted autoplay style="width:800px; height:600px; border:1px"></video>
</td>
<td style="width:200px; vertical-align:top; overflow:auto" >
<div id="peersList"></div>
</td>
</tr>
<tr style="height:20px">
<td colspan="2" style="text-align:center">
<div id="roomId"></div>
</td>
</tr>
</table>
<script src="//rawgithub.com/broofa/node-uuid/master/uuid.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<script src="//cdn.pubnub.com/pubnub-3.5.0.min.js"></script>
<script src="peer.js"></script>
<script src="channel.js"></script>
<script>
var room = null; // room Id
var localID = null; // unique ID for self
var localChannel = null; // unique channel ID for self
var localStream = null; // local MediaStream
var peers = {}; // peers map
var options = null; // GET parameters
// Timing values
var PING_INTERVAL = 10000;
var TIMER_INTERVAL = 30000;
var MAX_PING_DELAY = 6;
$(document).ready(function() {
if (!window.chrome) { // using Chrome specific api call for now
$("body").html("Supported only on Chrome");
return;
}
loadVideo();
});
function loadVideo() {
navigator.webkitGetUserMedia({audio : true, video : true}, successCallback, errorCallback);
function successCallback(stream) {
localStream = stream;
startCall();
}
function errorCallback(error) {
console.error('An error occurred: [CODE ' + error.code + ']');
}
}
function startCall() {
// Retrieve GET parameters
options = decodeURIComponent(window.location.search.slice(1))
.split('&')
.reduce(function(a, b) {
b = b.split('=');
a[b[0]] = b[1];
return a;
}, {});
// The "room" parameter if present will contain the unique room ID
if (!options["room"]) { // Original host
isOriginalHost = true;
localID = room = uuid.v4();
} else {
room = options["room"];
localID = uuid.v4();
}
// Each peer in the call listens on the global room channel and a unique channel local to itself
listen(room, processMessage, verboseLog);
localChannel = room + "_" + localID;
listen(localChannel, processMessage, verboseLog);
// Send ping messages periodically to each peer in the room
// This serves as first contact as well as heartbeat signals
send(room, {ping : true});
setInterval(function() {send(room, {ping : true})}, PING_INTERVAL);
$(window).on("beforeunload", hangup);
// Generate the link to be used by other peers to join the call
var link = document.URL.split("?")[0] + "?room=" + room;
if (typeof options["v"] !== "undefined") { // check if verbose
link += "&v=1";
}
var $linkElement = $("<a/>", {
href : link,
target: '_blank',
html: link
});
$("#roomId").append("Waiting for peers at ");
$("#roomId").append($linkElement);
showVideo(localID, window.webkitURL.createObjectURL(localStream), true);
}
// send a bye signal to the room on local window close
function hangup() {
send(room, {bye : true});
}
// called for rendering the video tag for each peer
function showVideo(peerID, videoURI, self) {
verboseLog(peerID + ": showVideo");
var $videoTag = $("<video/>", {
id : peerID,
src : videoURI,
autoplay: true,
style: 'width: 150px; height: 112px; border: 5px solid gray'
});
if (self) { // mute if self
$videoTag.prop('muted', true);
} else { // show controls for others for muting if required
$videoTag.prop('controls', true);
if (!$("#mainVideo").prop('src')) {
$("#mainVideo").prop('src', videoURI);
}
}
$videoTag.click(function() {
$("#mainVideo").prop('src', videoURI);
});
// display video
$("#peersList").prepend($videoTag);
}
// called when a peer disconnects
function removePeer(peerID) {
verboseLog(peerID + ": removePeer");
if (peers[peerID]) {
peers[peerID].close();
clearInterval(peers[peerID].heartbeatInterval);
if ($("#mainVideo").prop("src") === $("#"+peerID).prop("src")) {
$("#mainVideo").prop('src', "");
}
// Remove video tag
$("#"+peerID).remove();
delete peers[peerID];
}
}
// send message on a channel
function send(channel, message) {
message.peerID = localID;
message.replyChannel = localChannel;
sendOnChannel(channel, message, verboseLog);
}
// returns a watchdog timer method for a peer
function updatePeerTimer(peerID) {
return function() {
verboseLog(peerID + ": updateHeartbeat");
if (peers[peerID].lastHeartbeat === MAX_PING_DELAY) { // long time since last heartbeat, drop peer
removePeer(peerID);
} else {
peers[peerID].lastHeartbeat++;
}
}
}
// log
function verboseLog(message) {
if (typeof options["v"] !== "undefined") { // log if verbose
console.log(message);
}
}
function createPeerAndStart(peerID, peerChannel) {
if(peers[peerID]) { // possible deadlock
return -2;
}
// create a WRTCPeer object for the peer
var newPeer = new WRTCPeer(peerID, peerChannel, localStream, send, showVideo, removePeer, verboseLog);
var ret = newPeer.startConnection();
if (ret === 0) {
// set up watchdog timer for the peer
newPeer.heartbeatInterval = setInterval(updatePeerTimer(peerID), TIMER_INTERVAL);
peers[peerID] = newPeer;
}
return ret;
}
// message processing callback method
function processMessage(message) {
// if message was sent by self, discard
if (message.peerID === localID) return;
verboseLog("call processMessage" + JSON.stringify(message));
if (message.ping) {
if (!peers[message.peerID]) { // peer has just entered the room
send(message.replyChannel, {pong : true});
} else { // hearbeat signal, reset associated watchdog timer
peers[message.peerID].lastHeartbeat = 0;
}
} else if (message.pong) { // peer has responded to first contact
if (createPeerAndStart(message.peerID, message.replyChannel) == 0) {
// send confirmation to start the call
send(message.replyChannel, {okstart : true});
}
} else if (message.okstart) { // confirmation received
var ret = createPeerAndStart(message.peerID, message.replyChannel);
if (ret === 0 ||
ret === -2 && localID > message.peerID) { // if a deadlock is detected, the peer with the larger localID will act as the initiator
// create WebRTC offer
peers[message.peerID].createOffer();
}
} else if (message.bye) { // peer is leaving the call
removePeer(message.peerID);
} else if (peers[message.peerID]) { // this is a WebRTC specific message, pass on for processing by the appropriate WRTCPeer object
verboseLog("to peer");
peers[message.peerID].processMessage(message);
}
}
</script>
</body>
</html>