Skip to content

Instantly share code, notes, and snippets.

@palfrey
Created June 25, 2015 22:38
Show Gist options
  • Select an option

  • Save palfrey/947f6ec7f456182e2917 to your computer and use it in GitHub Desktop.

Select an option

Save palfrey/947f6ec7f456182e2917 to your computer and use it in GitHub Desktop.
Dalek Video files
"use strict";
var selfEasyrtcid = "";
var otherClients = [];
var state = "observer";
var calling = false;
function getClient(rtcid) {
if (!_.has(otherClients, rtcid)) {
otherClients[rtcid] = {"contacted" : null, state : null, id: rtcid, feed: null};
console.log("OtherClients (after add): " + _.keys(otherClients));
}
return otherClients[rtcid];
}
function contactClient(key) {
var client = getClient(key);
if (client.contacted == null) {
console.log(key + " is a new client");
}
if (client.contacted != state) {
console.log("Informing " + key + " of our state");
easyrtc.sendDataWS(key, 'query', state, function(ackMesg) {
if( ackMesg.msgType === 'error' ) {
console.log(ackMesg.msgData.errorText);
}
else {
client.contacted = state;
}
});
}
}
function getPilot() {
var pilots = _.filter(_.values(otherClients), function(client) {
//console.log("client: " + client);
return client.state == "pilot";
});
var count = _.size(pilots);
console.log("otherClients: " + _.keys(otherClients));
console.log(pilots);
console.log("Got " + count + " pilots");
if (count == 0) {
if (state == "pilot") {
return {}; // self
}
else {
return null;
}
}
if (count == 1 && state != "pilot") {
return pilots[0];
}
return null;
}
function setup() {
//easyrtc.enableDebug(true);
easyrtc.setOnError( function(errEvent) { console.log(errEvent.errorText);});
var localFilter = easyrtc.buildLocalSdpFilter( {
audioRecvBitrate:20, videoRecvBitrate:30
});
var remoteFilter = easyrtc.buildRemoteSdpFilter({
audioSendBitrate: 20, videoSendBitrate:30
});
easyrtc.setSdpFilters(localFilter, remoteFilter);
easyrtc.setRoomOccupantListener(otherClientsCallback);
/*easyrtc.enableAudio(false);
easyrtc.enableVideo(false);
easyrtc.setAutoInitUserMedia(false);*/
easyrtc.setStreamAcceptor( function(callerEasyrtcid, stream) {
var client = getClient(callerEasyrtcid);
console.log("Incoming stream from "+ callerEasyrtcid + " who is a " + client.state);
var video;
if (client.state == "pilot") {
video = document.getElementById('pilotView');
$("#pilotControls").hide();
$("#pilotView").show();
}
else if (client.state == "dalek")
video = document.getElementById('dalekView');
else {
return;
}
easyrtc.setVideoObjectSrc(video, stream);
});
easyrtc.setAcceptChecker( function(callerEasyrtcid, acceptor){
var client = getClient(callerEasyrtcid);
console.log("Incoming call from "+ callerEasyrtcid + " who is a " + client.state);
acceptor(true);
})
easyrtc.setOnStreamClosed( function (callerEasyrtcid) {
console.log("Closed stream from " + callerEasyrtcid);
easyrtc.setVideoObjectSrc(document.getElementById('pilotView'), "");
});
easyrtc.setPeerListener( function(sendersEasyrtcid, msgType, msgData, targeting) {
if( msgType === 'query' ) {
console.log( sendersEasyrtcid + ' is a ' + msgData);
getClient(sendersEasyrtcid).state = msgData;
contactClient(sendersEasyrtcid);
if (!calling && msgData == "pilot" && (state != "dalek")) {//|| $("#pilotView").is(":hidden"))) {
console.log("Calling " + sendersEasyrtcid);
calling = true;
easyrtc.call(
sendersEasyrtcid,
function(easyrtcid) { console.log("completed call to " + easyrtcid);},
function(errorCode, errorText) { calling = false; console.log("err:" + errorText);},
function(accepted, bywho) {
calling = false;
console.log((accepted?"accepted":"rejected")+ " by " + bywho);
$("#pilotControls").hide();
$("#pilotView").show();
}
);
}
if (!calling && msgData == "dalek") {
console.log("Calling " + sendersEasyrtcid);
calling = true;
easyrtc.call(
sendersEasyrtcid,
function(easyrtcid) { calling=false; console.log("completed call to " + easyrtcid);},
function(errorCode, errorText) { console.log("err:" + errorText);},
function(accepted, bywho) {
calling = false;
console.log((accepted?"accepted":"rejected")+ " by " + bywho);
}
);
}
}
else {
console.log("Got a " + msgType + " from " + sendersEasyrtcid);
}
});
easyrtc.setServerListener( function(msgType, msgData, targeting){
console.log("The Server sent the following message " + JSON.stringify(msgData));
});
//$(".bordered").height(240).width(320);
$("#pilotControls").hide();
$("#dalekControls").hide();
}
function connect() {
setup();
easyrtc.initMediaSource(
function(){
easyrtc.connect("Dalek", loginSuccess, loginFailure);
},loginFailure);
}
function dalek() {
setup();
state = "dalek";
easyrtc.setUsername("Dalek");
easyrtc.initMediaSource(
function(){ // success callback
easyrtc.connect("Dalek", loginSuccess, loginFailure);
},
loginFailure
);
}
function pilotMode() {
state = "pilot";
console.log("Setting state to pilot");
easyrtc.disconnect();
easyrtc.myEasyrtcid = null; // clear so we can set username again
/*easyrtc.enableAudio(true);
easyrtc.enableVideo(true);*/
easyrtc.initMediaSource(
function(){
$("#pilotControls").hide();
$("#pilotView").show();
$("#dalekControls").show();
$("#pilotView").prop('muted', true);
var selfVideo = document.getElementById("pilotView");
easyrtc.setVideoObjectSrc(selfVideo, easyrtc.getLocalStream());
easyrtc.connect("Dalek", loginSuccess, loginFailure);
/*_.each(_.keys(otherClients), function(key) {
contactClient(key);
});*/
},
loginFailure
);
}
function otherClientsCallback (roomName, data) {
var oldKeys = _.keys(otherClients);
console.log("Clients: " + _.keys(data));
console.log("Old keys: " + oldKeys);
for(var key in data) {
contactClient(key);
}
_.each(oldKeys, function(key) {
if (!_.has(data, key)) {
console.log("Can't find " + key + " any more");
delete otherClients[key];
}
});
var pilot = getPilot();
if (pilot == null) {
$("#pilotControls").show();
$("#pilotView").hide();
}
}
function loginSuccess(easyrtcid) {
selfEasyrtcid = easyrtcid;
console.log("Logged in as " + easyrtcid);
var iam = document.getElementById("iam");
if (iam != null)
iam.innerHTML = "I am " + easyrtc.cleanId(easyrtcid);
}
function loginFailure(errorCode, message) {
easyrtc.showError(errorCode, message);
}
function sparkSetup() {
$("#spark-failure").hide();
$("#spark-connecting").show();
var token = 'SPARK_TOKEN_FROM_TOKENS_PY';
var dalekRemote = "SPARK_CORE_ID";
var relays = [];
spark.on('login', function() {
console.log("Logged in to Spark")
spark.getDevice(dalekRemote, function(err, device) {
console.log(device);
$("#spark-connecting").hide();
if (!device.connected) {
$("#spark-failure").show();
}
var on = function(i) {
console.log("D" + i + ",HIGH");
device.callFunction('digitalwrite', 'D' + i +',HIGH');
};
var off = function(i) {
console.log("D" + i + ",LOW");
device.callFunction('digitalwrite', 'D' + i + ',LOW');
};
// 1 - forward left
// 0 - forward right
// 2 - backwards right
// 3 - backwards left
$('#forward').mousedown(function() {
on(0);
on(1);
}).mouseup(function() {
off(0);
off(1);
});
$('#backwards').mousedown(function() {
on(2);
on(3);
}).mouseup(function() {
off(2);
off(3);
});
$('#left').mousedown(function() {
on(1);
on(3);
}).mouseup(function() {
off(1);
off(3);
});
$('#right').mousedown(function() {
on(0);
on(2);
}).mouseup(function() {
off(0);
off(2);
});
$('#allstop').click(function() {
for (var i=0;i<4;i++) {
off(i);
}
})
});
});
spark.login({ accessToken: token });
}
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <!--skip-->
<title>Dalek Chat</title>
<!--show-->
<!-- Assumes global locations for socket.io.js and easyrtc.js -->
<script src="/socket.io/socket.io.js"></script>
<script type="text/javascript" src="/easyrtc/easyrtc.js"></script>
<script type="text/javascript" src="/easyrtc/labs/easyrtc_rates.js"></script>
<script type="text/javascript" src="dalek.js"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script type="text/javascript" src="http://underscorejs.org/underscore-min.js"></script>
<script type="text/javascript" src="screenfull.js"></script>
<script src="//cdn.jsdelivr.net/sparkjs/0.4.1/spark.min.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap-theme.min.css">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<style>
.bordered {
border:1px solid black;
display: inline-block;
}
video {
margin-top: 4px; /* weird additional padding */
}
</style>
<script type="text/javascript">
$( document ).ready(function() {
document.getElementById('button').addEventListener('click', function () {
if (screenfull.enabled) {
screenfull.request();
} else {
// Ignore or do something else
}
});
$( window ).resize(function() {
console.log("Window size: " + window.innerWidth + " x " + window.innerHeight);
$("#pilotView")
.height(window.innerHeight - 8)
.width(window.innerWidth - 8);
});
document.addEventListener(screenfull.raw.fullscreenchange, function () {
if (screenfull.isFullscreen) {
$("#button").hide();
}
else {
$("#button").show();
}
});
});
</script>
</head>
<body onload="connect();sparkSetup();">
<!--hide-->
<div class="container-fluid">
<!-- Main Content -->
<h1>Dalek Chat</h1>
<!--show-->
<a class="btn btn-default" href="#" role="button" id="button">Fullscreen</a>
<div class="row">
<div class="col-xs-12" id="connectControls">
<div id="iam">Not yet connected...</div>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<video autoplay="autoplay" id="dalekView" class="bordered" width="100%"></video>
</div>
<div class="col-xs-6">
<div id="pilotControls" class="bordered" hidden>
No Dalek pilot currently. <a class="btn btn-default" href="#" role="button" onclick="pilotMode();">Become the Dalek pilot</a>
</div>
</div>
<div class="col-xs-6">
<video autoplay="autoplay" id="pilotView" class="bordered" width="100%"></video>
</div>
</div>
<div class="row">
<div class="col-md-6 col-md-offset-6" id="dalekControls">
<div class="alert alert-danger" role="alert" id="spark-failure">Can't connect to the Dalek controls, so none of these buttons will do anything</div>
<div class="alert alert-warning" role="alert" id="spark-connecting">Connecting to Dalek controls (nothing below here will work until this is done)</div>
<button class="btn btn-default" type="submit" id="forward"><span class="glyphicon glyphicon-arrow-up" aria-hidden="true"></span></button>
<button class="btn btn-default" type="submit" id="backwards"><span class="glyphicon glyphicon-arrow-down" aria-hidden="true"></span></button>
<button class="btn btn-default" type="submit" id="left"><span class="glyphicon glyphicon-arrow-left" aria-hidden="true"></span></button>
<button class="btn btn-default" type="submit" id="right"><span class="glyphicon glyphicon-arrow-right" aria-hidden="true"></span></button>
<button class="btn btn-default" type="submit" id="allstop">All Stop</button>
</div>
</div>
</div>
<!--show-->
</body>
</html>
{
"name" : "dalek_server",
"version" : "0.1",
"author" : "Tom Parker <palfrey@lshift.net>",
"description" : "Dalek!",
"private" : true,
"scripts": {
"start" : "node server.js"
},
"dependencies" : {
"easyrtc" : "1.0.x",
"express" : "*",
"socket.io" : "0.9.x",
"ssl-root-cas": "^1.1.4"
},
"engines": {
"node" : ">=0.8"
}
}
(function () {
'use strict';
var isCommonjs = typeof module !== 'undefined' && module.exports;
var keyboardAllowed = typeof Element !== 'undefined' && 'ALLOW_KEYBOARD_INPUT' in Element;
var fn = (function () {
var val;
var valLength;
var fnMap = [
[
'requestFullscreen',
'exitFullscreen',
'fullscreenElement',
'fullscreenEnabled',
'fullscreenchange',
'fullscreenerror'
],
// new WebKit
[
'webkitRequestFullscreen',
'webkitExitFullscreen',
'webkitFullscreenElement',
'webkitFullscreenEnabled',
'webkitfullscreenchange',
'webkitfullscreenerror'
],
// old WebKit (Safari 5.1)
[
'webkitRequestFullScreen',
'webkitCancelFullScreen',
'webkitCurrentFullScreenElement',
'webkitCancelFullScreen',
'webkitfullscreenchange',
'webkitfullscreenerror'
],
[
'mozRequestFullScreen',
'mozCancelFullScreen',
'mozFullScreenElement',
'mozFullScreenEnabled',
'mozfullscreenchange',
'mozfullscreenerror'
],
[
'msRequestFullscreen',
'msExitFullscreen',
'msFullscreenElement',
'msFullscreenEnabled',
'MSFullscreenChange',
'MSFullscreenError'
]
];
var i = 0;
var l = fnMap.length;
var ret = {};
for (; i < l; i++) {
val = fnMap[i];
if (val && val[1] in document) {
for (i = 0, valLength = val.length; i < valLength; i++) {
ret[fnMap[0][i]] = val[i];
}
return ret;
}
}
return false;
})();
var screenfull = {
request: function (elem) {
var request = fn.requestFullscreen;
elem = elem || document.documentElement;
// Work around Safari 5.1 bug: reports support for
// keyboard in fullscreen even though it doesn't.
// Browser sniffing, since the alternative with
// setTimeout is even worse.
if (/5\.1[\.\d]* Safari/.test(navigator.userAgent)) {
elem[request]();
} else {
elem[request](keyboardAllowed && Element.ALLOW_KEYBOARD_INPUT);
}
},
exit: function () {
document[fn.exitFullscreen]();
},
toggle: function (elem) {
if (this.isFullscreen) {
this.exit();
} else {
this.request(elem);
}
},
raw: fn
};
if (!fn) {
if (isCommonjs) {
module.exports = false;
} else {
window.screenfull = false;
}
return;
}
Object.defineProperties(screenfull, {
isFullscreen: {
get: function () {
return !!document[fn.fullscreenElement];
}
},
element: {
enumerable: true,
get: function () {
return document[fn.fullscreenElement];
}
},
enabled: {
enumerable: true,
get: function () {
// Coerce to boolean in case of old WebKit
return !!document[fn.fullscreenEnabled];
}
}
});
if (isCommonjs) {
module.exports = screenfull;
} else {
window.screenfull = screenfull;
}
})();
// Load required modules
var http = require("http"); // http server core module
var express = require("express"); // web framework external module
var io = require("socket.io"); // web socket external module
var easyrtc = require("easyrtc"); // EasyRTC external module
var https = require('https');
var path = require('path');
var fs = require('fs');
// Setup and configure Express http server. Expect a subfolder called "static" to be the web root.
var httpsApp = express();
httpsApp.use(express.static(__dirname + "/static/"));
require('ssl-root-cas')
.inject()
.addFile(path.join(__dirname, 'my-private-root-ca.crt.pem'));
options = {
key: fs.readFileSync(path.join(__dirname, 'my-server.key.pem'))
, cert: fs.readFileSync(path.join(__dirname, 'my-server.crt.pem'))
};
// Start Express http server on port 8080
var httpsServer = https.createServer(options, httpsApp).listen(8081);
var httpApp = express();
httpApp.get(/^(.+)$/, function(req, res) {
var contents = fs.readFileSync('static/http.html').toString();
contents = contents.replace("$ADDRESS", req.hostname);
res.send(contents);
});
http.createServer(httpApp).listen(8080);
// Start Socket.io so it attaches itself to Express server
var socketServer = io.listen(httpsServer, {"log level":1});
var myIceServers = [
{"url":"stun:stun.l.google.com:19302"}
];
easyrtc.setOption("appIceServers", myIceServers);
// Start EasyRTC server
var rtc = easyrtc.listen(httpsApp, socketServer);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment