diff options
Diffstat (limited to 'net/webrtc/www/webrtc.js')
-rw-r--r-- | net/webrtc/www/webrtc.js | 466 |
1 files changed, 0 insertions, 466 deletions
diff --git a/net/webrtc/www/webrtc.js b/net/webrtc/www/webrtc.js deleted file mode 100644 index eb449d90..00000000 --- a/net/webrtc/www/webrtc.js +++ /dev/null @@ -1,466 +0,0 @@ -/* vim: set sts=4 sw=4 et : - * - * Demo Javascript app for negotiating and streaming a sendrecv webrtc stream - * with a GStreamer app. Runs only in passive mode, i.e., responds to offers - * with answers, exchanges ICE candidates, and streams. - * - * Author: Nirbheek Chauhan <nirbheek@centricular.com> - */ - -// Set this to override the automatic detection in websocketServerConnect() -var ws_server; -var ws_port; -// Override with your own STUN servers if you want -var rtc_configuration = {iceServers: [{urls: "stun:stun.l.google.com:19302"}, - /* TODO: do not keep these static and in clear text in production, - * and instead use one of the mechanisms discussed in - * https://groups.google.com/forum/#!topic/discuss-webrtc/nn8b6UboqRA - */ - {'urls': 'turn:turn.homeneural.net:3478?transport=udp', - 'credential': '1qaz2wsx', - 'username': 'test' - }], - /* Uncomment the following line to ensure the turn server is used - * while testing. This should be kept commented out in production, - * as non-relay ice candidates should be preferred - */ - // iceTransportPolicy: "relay", - }; - -var sessions = {} - -/* https://stackoverflow.com/questions/105034/create-guid-uuid-in-javascript */ -function getOurId() { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); - return v.toString(16); - }); -} - -function Uint8ToString(u8a){ - var CHUNK_SZ = 0x8000; - var c = []; - for (var i=0; i < u8a.length; i+=CHUNK_SZ) { - c.push(String.fromCharCode.apply(null, u8a.subarray(i, i+CHUNK_SZ))); - } - return c.join(""); -} - -function Session(our_id, peer_id, closed_callback) { - this.id = null; - this.peer_connection = null; - this.ws_conn = null; - this.peer_id = peer_id; - this.our_id = our_id; - this.closed_callback = closed_callback; - this.data_channel = null; - this.input = null; - - this.getVideoElement = function() { - return document.getElementById("stream-" + this.our_id); - }; - - this.resetState = function() { - if (this.peer_connection) { - this.peer_connection.close(); - this.peer_connection = null; - } - var videoElement = this.getVideoElement(); - if (videoElement) { - videoElement.pause(); - videoElement.src = ""; - } - - var session_div = document.getElementById("session-" + this.our_id); - if (session_div) { - session_div.parentNode.removeChild(session_div); - } - if (this.ws_conn) { - this.ws_conn.close(); - this.ws_conn = null; - } - - this.input && this.input.detach(); - this.data_channel = null; - }; - - this.handleIncomingError = function(error) { - this.resetState(); - this.closed_callback(this.our_id); - }; - - this.setStatus = function(text) { - console.log(text); - var span = document.getElementById("status-" + this.our_id); - // Don't set the status if it already contains an error - if (!span.classList.contains('error')) - span.textContent = text; - }; - - this.setError = function(text) { - console.error(text); - var span = document.getElementById("status-" + this.our_id); - span.textContent = text; - span.classList.add('error'); - this.resetState(); - this.closed_callback(this.our_id); - }; - - // Local description was set, send it to peer - this.onLocalDescription = function(desc) { - console.log("Got local description: " + JSON.stringify(desc), this); - var thiz = this; - this.peer_connection.setLocalDescription(desc).then(() => { - this.setStatus("Sending SDP answer"); - var sdp = { - 'type': 'peer', - 'sessionId': this.id, - 'sdp': this.peer_connection.localDescription.toJSON() - }; - this.ws_conn.send(JSON.stringify(sdp)); - }).catch(function(e) { - thiz.setError(e); - }); - }; - - this.onRemoteDescriptionSet = function() { - this.setStatus("Remote SDP set"); - this.setStatus("Got SDP offer"); - this.peer_connection.createAnswer() - .then(this.onLocalDescription.bind(this)).catch(this.setError); - } - - // SDP offer received from peer, set remote description and create an answer - this.onIncomingSDP = function(sdp) { - var thiz = this; - this.peer_connection.setRemoteDescription(sdp) - .then(this.onRemoteDescriptionSet.bind(this)) - .catch(function(e) { - thiz.setError(e) - }); - }; - - // ICE candidate received from peer, add it to the peer connection - this.onIncomingICE = function(ice) { - var candidate = new RTCIceCandidate(ice); - var thiz = this; - this.peer_connection.addIceCandidate(candidate).catch(function(e) { - thiz.setError(e) - }); - }; - - this.onServerMessage = function(event) { - console.log("Received " + event.data); - try { - msg = JSON.parse(event.data); - } catch (e) { - if (e instanceof SyntaxError) { - this.handleIncomingError("Error parsing incoming JSON: " + event.data); - } else { - this.handleIncomingError("Unknown error parsing response: " + event.data); - } - return; - } - - if (msg.type == "registered") { - this.setStatus("Registered with server"); - this.connectPeer(); - } else if (msg.type == "sessionStarted") { - this.setStatus("Registered with server"); - this.id = msg.sessionId; - } else if (msg.type == "error") { - this.handleIncomingError(msg.details); - } else if (msg.type == "endSession") { - this.resetState(); - this.closed_callback(this.our_id); - } else if (msg.type == "peer") { - // Incoming peer message signals the beginning of a call - if (!this.peer_connection) - this.createCall(msg); - - if (msg.sdp != null) { - this.onIncomingSDP(msg.sdp); - } else if (msg.ice != null) { - this.onIncomingICE(msg.ice); - } else { - this.handleIncomingError("Unknown incoming JSON: " + msg); - } - } - }; - - this.streamIsPlaying = function(e) { - this.setStatus("Streaming"); - }; - - this.onServerClose = function(event) { - this.resetState(); - this.closed_callback(this.our_id); - }; - - this.onServerError = function(event) { - this.handleIncomingError('Server error'); - }; - - this.websocketServerConnect = function() { - // Clear errors in the status span - var span = document.getElementById("status-" + this.our_id); - span.classList.remove('error'); - span.textContent = ''; - console.log("Our ID:", this.our_id); - var ws_port = ws_port || '8443'; - if (window.location.protocol.startsWith ("file")) { - var ws_server = ws_server || "127.0.0.1"; - } else if (window.location.protocol.startsWith ("http")) { - var ws_server = ws_server || window.location.hostname; - } else { - throw new Error ("Don't know how to connect to the signalling server with uri" + window.location); - } - var ws_url = 'ws://' + ws_server + ':' + ws_port - this.setStatus("Connecting to server " + ws_url); - this.ws_conn = new WebSocket(ws_url); - /* When connected, immediately register with the server */ - this.ws_conn.addEventListener('open', (event) => { - this.setStatus("Connecting to the peer"); - this.connectPeer(); - }); - this.ws_conn.addEventListener('error', this.onServerError.bind(this)); - this.ws_conn.addEventListener('message', this.onServerMessage.bind(this)); - this.ws_conn.addEventListener('close', this.onServerClose.bind(this)); - }; - - this.connectPeer = function() { - this.setStatus("Connecting " + this.peer_id); - - this.ws_conn.send(JSON.stringify({ - "type": "startSession", - "peerId": this.peer_id - })); - }; - - this.onRemoteStreamAdded = function(event) { - var videoTracks = event.stream.getVideoTracks(); - var audioTracks = event.stream.getAudioTracks(); - - console.log(videoTracks); - - if (videoTracks.length > 0) { - console.log('Incoming stream: ' + videoTracks.length + ' video tracks and ' + audioTracks.length + ' audio tracks'); - this.getVideoElement().srcObject = event.stream; - this.getVideoElement().play(); - } else { - this.handleIncomingError('Stream with unknown tracks added, resetting'); - } - }; - - this.createCall = function(msg) { - console.log('Creating RTCPeerConnection'); - - this.peer_connection = new RTCPeerConnection(rtc_configuration); - this.peer_connection.onaddstream = this.onRemoteStreamAdded.bind(this); - - this.peer_connection.ondatachannel = (event) => { - console.log(`Data channel created: ${event.channel.label}`); - this.data_channel = event.channel; - - video_element = this.getVideoElement(); - if (video_element) { - this.input = new Input(video_element, (data) => { - if (this.data_channel) { - console.log(`Navigation data: ${data}`); - this.data_channel.send(JSON.stringify(data)); - } - }); - } - - this.data_channel.onopen = (event) => { - console.log("Receive channel opened, attaching input"); - this.input.attach(); - } - this.data_channel.onclose = (event) => { - console.info("Receive channel closed"); - this.input && this.input.detach(); - this.data_channel = null; - } - this.data_channel.onerror = (event) => { - this.input && this.input.detach(); - console.warn("Error on receive channel", event.data); - this.data_channel = null; - } - - let buffer = []; - this.data_channel.onmessage = (event) => { - if (typeof event.data === 'string' || event.data instanceof String) { - if (event.data == 'BEGIN_IMAGE') - buffer = []; - else if (event.data == 'END_IMAGE') { - var decoder = new TextDecoder("ascii"); - var array_buffer = new Uint8Array(buffer); - var str = decoder.decode(array_buffer); - let img = document.getElementById("image"); - img.src = 'data:image/png;base64, ' + str; - } - } else { - var i, len = buffer.length - var view = new DataView(event.data); - for (i = 0; i < view.byteLength; i++) { - buffer[len + i] = view.getUint8(i); - } - } - } - } - - this.peer_connection.onicecandidate = (event) => { - if (event.candidate == null) { - console.log("ICE Candidate was null, done"); - return; - } - this.ws_conn.send(JSON.stringify({ - "type": "peer", - "sessionId": this.id, - "ice": event.candidate.toJSON() - })); - }; - - this.setStatus("Created peer connection for call, waiting for SDP"); - }; - - document.getElementById("stream-" + this.our_id).addEventListener("playing", this.streamIsPlaying.bind(this), false); - - this.websocketServerConnect(); -} - -function startSession() { - var peer_id = document.getElementById("camera-id").value; - - if (peer_id === "") { - return; - } - - sessions[peer_id] = new Session(peer_id); -} - -function session_closed(peer_id) { - sessions[peer_id] = null; -} - -function addPeer(peer_id, meta) { - console.log("Meta: ", JSON.stringify(meta)); - - var nav_ul = document.getElementById("camera-list"); - - meta = meta ? meta : {"display-name": peer_id}; - let display_html = `${meta["display-name"] ? meta["display-name"] : peer_id}<ul>`; - for (const key in meta) { - if (key != "display-name") { - display_html += `<li>- ${key}: ${meta[key]}</li>`; - } - } - display_html += "</ul>" - - var li_str = '<li id="peer-' + peer_id + '"><button class="button button1">' + display_html + '</button></li>'; - - nav_ul.insertAdjacentHTML('beforeend', li_str); - var li = document.getElementById("peer-" + peer_id); - li.onclick = function(e) { - var sessions_div = document.getElementById('sessions'); - var our_id = getOurId(); - var session_div_str = '<div class="session" id="session-' + our_id + '"><video preload="none" class="stream" id="stream-' + our_id + '"></video><p>Status: <span id="status-' + our_id + '">unknown</span></p></div>' - sessions_div.insertAdjacentHTML('beforeend', session_div_str); - sessions[peer_id] = new Session(our_id, peer_id, session_closed); - } -} - -function clearPeers() { - var nav_ul = document.getElementById("camera-list"); - - while (nav_ul.firstChild) { - nav_ul.removeChild(nav_ul.firstChild); - } -} - -function onServerMessage(event) { - console.log("Received " + event.data); - - try { - msg = JSON.parse(event.data); - } catch (e) { - if (e instanceof SyntaxError) { - console.error("Error parsing incoming JSON: " + event.data); - } else { - console.error("Unknown error parsing response: " + event.data); - } - return; - } - - if (msg.type == "welcome") { - console.info(`Got welcomed with ID ${msg.peer_id}`); - ws_conn.send(JSON.stringify({ - "type": "list" - })); - } else if (msg.type == "list") { - clearPeers(); - for (i = 0; i < msg.producers.length; i++) { - addPeer(msg.producers[i].id, msg.producers[i].meta); - } - } else if (msg.type == "peerStatusChanged") { - var li = document.getElementById("peer-" + msg.peerId); - if (msg.roles.includes("producer")) { - if (li == null) { - console.error('Adding peer'); - addPeer(msg.peerId, msg.meta); - } - } else if (li != null) { - li.parentNode.removeChild(li); - } - } else { - console.error("Unsupported message: ", msg); - } -}; - -function clearConnection() { - ws_conn.removeEventListener('error', onServerError); - ws_conn.removeEventListener('message', onServerMessage); - ws_conn.removeEventListener('close', onServerClose); - ws_conn = null; -} - -function onServerClose(event) { - clearConnection(); - clearPeers(); - console.log("Close"); - window.setTimeout(connect, 1000); -}; - -function onServerError(event) { - clearConnection(); - clearPeers(); - console.log("Error", event); - window.setTimeout(connect, 1000); -}; - -function connect() { - var ws_port = ws_port || '8443'; - if (window.location.protocol.startsWith ("file")) { - var ws_server = ws_server || "127.0.0.1"; - } else if (window.location.protocol.startsWith ("http")) { - var ws_server = ws_server || window.location.hostname; - } else { - throw new Error ("Don't know how to connect to the signalling server with uri" + window.location); - } - var ws_url = 'ws://' + ws_server + ':' + ws_port - console.log("Connecting listener"); - ws_conn = new WebSocket(ws_url); - ws_conn.addEventListener('open', (event) => { - ws_conn.send(JSON.stringify({ - "type": "setPeerStatus", - "roles": ["listener"] - })); - }); - ws_conn.addEventListener('error', onServerError); - ws_conn.addEventListener('message', onServerMessage); - ws_conn.addEventListener('close', onServerClose); -} - -function setup() { - connect(); -} |