| <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> |
| |
| <html> |
| |
| <head> |
| <title>WebRTC Autoresponder</title> |
| This page should show a stream coming from a different browser. |
| <script type="text/javascript"> |
| |
| var local_name; |
| var server; |
| var my_id = -1; |
| var other_peers = {}; |
| var request = null; |
| var hanging_get = null; |
| var pc = null; |
| var local_stream = null; |
| var call_state = 0; |
| // 0 - Not started |
| // 1 - Call ongoing |
| // 2 - We have initiated closing the call |
| // 3 - Other side has initiated closing the call |
| |
| // General |
| function toggleExtraButtons() { |
| document.getElementById("createPcBtn").hidden = |
| !document.getElementById("createPcBtn").hidden; |
| document.getElementById("addStreamBtn").hidden = |
| !document.getElementById("addStreamBtn").hidden; |
| } |
| |
| function trace(txt) { |
| var elem = document.getElementById("debug"); |
| elem.innerHTML += txt + "<br>"; |
| } |
| |
| function trace_warning(txt) { |
| var wtxt = "<b>" + txt + "</b>"; |
| trace(wtxt); |
| } |
| |
| function setCallState(state) { |
| trace("Changing call state: " + call_state + " -> " + state); |
| call_state = state; |
| } |
| |
| function checkPeerConnection() { |
| if (!pc) { |
| trace_warning("No PeerConnection object exists."); |
| return 0; |
| } |
| return 1; |
| } |
| |
| // Local stream generation |
| function gotStream(s) { |
| var url = webkitURL.createObjectURL(s); |
| document.getElementById("localView").src = url; |
| trace("User has granted access to webcam. url = " + url); |
| local_stream = s; |
| } |
| |
| function gotStreamFailed(error) { |
| alert("Failed to get access to webcam. Error code was " + error.code); |
| trace("Failed to get access to webcam. Error code was " + error.code); |
| } |
| |
| // Call control |
| function createPeerConnection() { |
| if (pc) { |
| trace_warning("PeerConnection object already exists."); |
| } |
| trace("Creating PeerConnection object."); |
| pc = new webkitPeerConnection("STUN stun.l.google.com:19302", |
| onSignalingMessage); |
| pc.onaddstream = onAddStream; |
| pc.onremovestream = onRemoveStream; |
| } |
| |
| function startCall() { |
| document.getElementById("startcall").disabled = true; |
| createPeerConnection(); |
| addStream(); |
| } |
| |
| function addStream() |
| { |
| trace("Starting call. [pc.addStream(local_stream)]"); |
| pc.addStream(local_stream); |
| document.getElementById("stopcall").disabled = false; |
| } |
| |
| function stopCall() { |
| document.getElementById("stopcall").disabled = true; |
| trace("Stopping call [pc.close()]"); |
| setCallState(2); |
| pc.close(); |
| } |
| |
| function test1() { |
| addStream(); |
| } |
| |
| function callHasStarted() { |
| setCallState(1); |
| } |
| |
| // PeerConnection callbacks |
| function onAddStream(e) { |
| var stream = pc.remoteStreams[0]; |
| var url = webkitURL.createObjectURL(stream); |
| document.getElementById("remoteView").src = url; |
| trace("Started showing remote stream. url = " + url); |
| setTimeout(callHasStarted, 5000); // TODO: Temp workaround, to be removed |
| } |
| |
| function onRemoveStream(e) { |
| // Currently if we get this callback, call has ended. |
| document.getElementById("remoteView").src = ""; |
| trace("Stopped showing remote stream."); |
| if (call_state == 2) { |
| // Finalize close call. We assume here that this |
| // callback comes after onSignalingMessage. |
| pc = null; |
| setCallState(0); |
| document.getElementById("startcall").disabled = false; |
| } |
| } |
| |
| function onSignalingMessage(msg) { |
| var peer_id = parseInt(document.getElementById("peer_id").value); |
| trace("Sending message to " + other_peers[peer_id] + |
| " (ID " + peer_id + "):\n" + msg); |
| sendToPeer(peer_id, msg); |
| } |
| |
| // Server interaction |
| |
| function handleServerNotification(data) { |
| trace("Server notification: " + data); |
| var parsed = data.split(","); |
| if (parseInt(parsed[2]) != 0) |
| other_peers[parseInt(parsed[1])] = parsed[0]; |
| } |
| |
| function handlePeerMessage(peer_id, msg) { |
| trace("Received message from " + other_peers[peer_id] + |
| " (ID " + peer_id + "):\n" + msg); |
| // Assuming we have created a PeerConnection and that we receive the message |
| // from the peer we want to communicate with |
| document.getElementById("peer_id").value = peer_id; |
| if (pc) { |
| try { |
| pc.processSignalingMessage(msg); |
| } catch (e) { |
| trace_warning("Signaling message error: " + e.description); |
| } |
| if (call_state == 1) |
| setCallState(3); |
| } else { |
| createPeerConnection(); |
| pc.processSignalingMessage(msg); |
| } |
| } |
| |
| function getIntHeader(r, name) { |
| var val = r.getResponseHeader(name); |
| trace("header value: " + val); |
| return val != null && val.length ? parseInt(val) : -1; |
| } |
| |
| function hangingGetCallback() { |
| try { |
| if (hanging_get.readyState != 4) |
| return; |
| if (hanging_get.status != 200) { |
| trace("server error, status: " + hanging_get.status + |
| ", text: " + hanging_get.statusText); |
| disconnect(); |
| } else { |
| var peer_id = getIntHeader(hanging_get, "Pragma"); |
| if (peer_id == my_id) { |
| handleServerNotification(hanging_get.responseText); |
| } else { |
| handlePeerMessage(peer_id, hanging_get.responseText); |
| } |
| } |
| |
| if (hanging_get) { |
| hanging_get.abort(); |
| hanging_get = null; |
| } |
| |
| if (my_id != -1) |
| window.setTimeout(startHangingGet, 0); |
| } catch (e) { |
| trace("Hanging get error: " + e.description); |
| } |
| } |
| |
| function onHangingGetTimeout() { |
| trace("hanging get timeout. issuing again."); |
| hanging_get.abort(); |
| hanging_get = null; |
| if (my_id != -1) |
| window.setTimeout(startHangingGet, 0); |
| } |
| |
| function startHangingGet() { |
| try { |
| hanging_get = new XMLHttpRequest(); |
| hanging_get.onreadystatechange = hangingGetCallback; |
| hanging_get.ontimeout = onHangingGetTimeout; |
| hanging_get.open("GET", server + "/wait?peer_id=" + my_id, true); |
| hanging_get.send(); |
| } catch (e) { |
| trace("error" + e.description); |
| } |
| } |
| |
| function sendToPeer(peer_id, data) { |
| if (my_id == -1) { |
| alert("Not connected"); |
| return; |
| } |
| if (peer_id == my_id) { |
| alert("Can't send a message to oneself :)"); |
| return; |
| } |
| var r = new XMLHttpRequest(); |
| r.open("POST", server + "/message?peer_id=" + my_id + "&to=" + peer_id, |
| false); |
| r.setRequestHeader("Content-Type", "text/plain"); |
| r.send(data); |
| r = null; |
| } |
| |
| function signInCallback() { |
| try { |
| if (request.readyState == 4) { |
| if (request.status == 200) { |
| var peers = request.responseText.split("\n"); |
| my_id = parseInt(peers[0].split(",")[1]); |
| trace("My id: " + my_id); |
| for (var i = 1; i < peers.length; ++i) { |
| if (peers[i].length > 0) { |
| trace("Peer " + i + ": " + peers[i]); |
| var parsed = peers[i].split(","); |
| other_peers[parseInt(parsed[1])] = parsed[0]; |
| } |
| } |
| startHangingGet(); |
| request = null; |
| } |
| } |
| } catch (e) { |
| trace("error: " + e.description); |
| } |
| } |
| |
| function signIn() { |
| try { |
| request = new XMLHttpRequest(); |
| request.onreadystatechange = signInCallback; |
| request.open("GET", server + "/sign_in?" + local_name, true); |
| request.send(); |
| } catch (e) { |
| trace("error: " + e.description); |
| } |
| } |
| |
| function connect() { |
| local_name = document.getElementById("local").value.toLowerCase(); |
| server = document.getElementById("server").value.toLowerCase(); |
| if (local_name.length == 0) { |
| alert("I need a name please."); |
| document.getElementById("local").focus(); |
| } else { |
| document.getElementById("connect").disabled = true; |
| document.getElementById("disconnect").disabled = false; |
| signIn(); |
| } |
| } |
| |
| function disconnect() { |
| if (request) { |
| request.abort(); |
| request = null; |
| } |
| |
| if (hanging_get) { |
| hanging_get.abort(); |
| hanging_get = null; |
| } |
| |
| if (my_id != -1) { |
| request = new XMLHttpRequest(); |
| request.open("GET", server + "/sign_out?peer_id=" + my_id, false); |
| request.send(); |
| request = null; |
| my_id = -1; |
| } |
| |
| document.getElementById("connect").disabled = false; |
| document.getElementById("disconnect").disabled = true; |
| } |
| |
| function toggleLog() |
| { |
| document.getElementById('debug').hidden =! |
| document.getElementById('debug').hidden; |
| } |
| |
| window.onbeforeunload = disconnect; |
| |
| </script> |
| </head> |
| |
| <body> |
| <table border="0"> |
| |
| <tr> |
| <th align="left">Local Preview</th> |
| <th align="left">Remote Video</th> |
| </tr> |
| <tr> |
| <td><video width="320" height="240" id="localView" autoplay="autoplay"> |
| </video></td> |
| <td><video width="640" height="480" id="remoteView" autoplay="autoplay"> |
| </video></td> |
| </tr> |
| <tr> |
| <td valign="top"> |
| <form> |
| Target peer ID: <input type="text" id="peer_id" size="3" value="1"/><br> |
| <button id="startcall" onclick="startCall();">(4) Start call</button><br> |
| <button id="stopcall" onclick="stopCall();" disabled="true">(5) Stop call |
| </button><br> |
| <!--<input type="button" value="Test 1" onclick="test1()"/><br>--> |
| </form> |
| </td> |
| <td valign="top"> |
| <button onclick="toggleExtraButtons();">Toggle extra buttons</button><br> |
| <button id="createPcBtn" onclick="createPeerConnection();" hidden="true"> |
| Create peer connection</button><br> |
| <button id="addStreamBtn" onclick="addStream();" hidden="true">Add stream |
| </button><br> |
| </td> |
| </tr> |
| |
| <tr><td colspan="2"> |
| (1) Server: <input type="text" id="server" value="http://localhost:8888" /> |
| <br> |
| (2) Your name: <input type="text" id="local" value="responder"/> |
| <button id="connect" onclick="connect();" disabled="true">(3) Connect</button> |
| <button id="disconnect" onclick="disconnect();" disabled="true">(6) Disconnect |
| </button> |
| <br> |
| <br> |
| <button onclick="toggleLog()">Toggle view log</button> |
| <button onclick="document.getElementById('debug').innerHTML='';">Clear log |
| </button> |
| <pre id="debug"> |
| </pre> |
| </td></tr> |
| |
| </table> |
| </body> |
| <script> |
| // On init, we connect to the server. |
| connect(); |
| </script> |
| </html> |