Skip to content

Instantly share code, notes, and snippets.

@stryju
Last active September 13, 2016 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stryju/5a59a7e466a485071c43b9bfc985ec0f to your computer and use it in GitHub Desktop.
Save stryju/5a59a7e466a485071c43b9bfc985ec0f to your computer and use it in GitHub Desktop.
esnextbin sketch
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>ESNextbin Sketch</title>
<!-- put additional styles and scripts here -->
</head>
<body>
<!-- put markup and other contents here -->
</body>
</html>
(function(RTCSessionDescription, RTCPeerConnection, RTCIceCandidate) {
function genID() {
return Math.random().toString(32);
}
class Client {
constructor(PCConfig, signalingChannel) {
const pc = new RTCPeerConnection(PCConfig);
pc.onicecandidate = ({candidate}) => {
if (!candidate) {
return;
}
this._sendData({candidate});
};
pc.onnegotiationneeded = () => pc.createOffer()
.then((desc) => this._localDescCreated(desc))
.catch((err) => error('failed to create offer', err));
this.id = genID();
this._pc = pc;
this._signalingChannel = signalingChannel;
this._requests = {};
}
_sendData(data) {
this._signalingChannel.send(this.id, this.remoteId, JSON.stringify(data));
}
_localDescCreated(desc) {
const pc = this._pc;
pc.setLocalDescription(desc)
.then(() => this._sendData({sdp: pc.localDescription}))
.catch((err) => error('failed to set local description', err));
}
connect({id}) {
this.remoteId = id;
this._setupChannel(this._pc.createDataChannel(genID()));
}
_setupChannel(channel) {
let count = 0;
this._channel = channel;
channel.onopen = () => {
log('Data chanel opened', channel.readyState);
this._sendRequest('ping');
};
channel.onmessage = (e) => {
log('Message received', this.id, e);
setTimeout(() => this._sendRequest(`pong #${count}`), 100);
if (++count === 5) {
log('Disconnecting client', this.id);
this._destroy();
}
};
}
_sendRequest(request) {
if (this._channel.readyState === 'open') {
this._channel.send(JSON.stringify(request));
}
}
_destroy() {
if (this._channel) {
this._channel.close();
}
this._pc.close();
this._pc = null;
this._signalingChannel.removeClient(this);
}
onsignalingmessage(remoteId, json) {
const pc = this._pc;
if (!this.remoteId) {
this.remoteId = remoteId;
pc.ondatachannel = ({channel}) => this._setupChannel(channel);
}
const {sdp, candidate} = JSON.parse(json);
if (sdp) {
pc.setRemoteDescription(new RTCSessionDescription(sdp))
.then(() => {
if (pc.remoteDescription.type !== 'offer') {
return;
}
pc.createAnswer()
.then((desc) => this._localDescCreated(desc))
.catch((err) => error('failed to create answer', err));
})
.catch((err) => error('failed to set remote desc', err));
} else {
pc.addIceCandidate(new RTCIceCandidate(candidate))
.catch((err) => error('failed to add ice candidate', err));
}
}
}
class SignalingChannel {
constructor() {
this._clients = new Map();
}
addClient(client) {
this._clients.set(client.id, client);
}
getClient(id) {
return this._clients.get(id);
}
removeClient(client) {
this._clients.delete(client.id);
}
send(from, to, message) {
this._clients.get(to).onsignalingmessage(from, message);
}
}
setInterval(() => {
// console.groupEnd();
// console.group();
log('creating signalling channel');
const channel = new SignalingChannel();
const PCConfig = {'iceServers': [{'url': 'stun:stun.l.google.com:19302'}]};
log('creating client #1');
const client1 = new Client(PCConfig, channel);
channel.addClient(client1);
log('creating client #2');
const client2 = new Client(PCConfig, channel);
channel.addClient(client2);
log('connecting clients');
client1.connect(client2);
}, 1000);
function log(...args) {
// console.log(...args);
}
function error(...args) {
// console.error(...args);
}
})(
window.RTCSessionDescription || window.mozRTCSessionDescription,
window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection,
window.RTCIceCandidate || window.mozRTCIceCandidate
);
{
"name": "esnextbin-sketch",
"version": "0.0.0",
"dependencies": {
"babel-runtime": "6.11.6"
}
}
'use strict';
var _map = require('babel-runtime/core-js/map');
var _map2 = _interopRequireDefault(_map);
var _stringify = require('babel-runtime/core-js/json/stringify');
var _stringify2 = _interopRequireDefault(_stringify);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
(function (RTCSessionDescription, RTCPeerConnection, RTCIceCandidate) {
function genID() {
return Math.random().toString(32);
}
var Client = function () {
function Client(PCConfig, signalingChannel) {
var _this = this;
(0, _classCallCheck3.default)(this, Client);
var pc = new RTCPeerConnection(PCConfig);
pc.onicecandidate = function (_ref) {
var candidate = _ref.candidate;
if (!candidate) {
return;
}
_this._sendData({ candidate: candidate });
};
pc.onnegotiationneeded = function () {
return pc.createOffer().then(function (desc) {
return _this._localDescCreated(desc);
}).catch(function (err) {
return error('failed to create offer', err);
});
};
this.id = genID();
this._pc = pc;
this._signalingChannel = signalingChannel;
this._requests = {};
}
(0, _createClass3.default)(Client, [{
key: '_sendData',
value: function _sendData(data) {
this._signalingChannel.send(this.id, this.remoteId, (0, _stringify2.default)(data));
}
}, {
key: '_localDescCreated',
value: function _localDescCreated(desc) {
var _this2 = this;
var pc = this._pc;
pc.setLocalDescription(desc).then(function () {
return _this2._sendData({ sdp: pc.localDescription });
}).catch(function (err) {
return error('failed to set local description', err);
});
}
}, {
key: 'connect',
value: function connect(_ref2) {
var id = _ref2.id;
this.remoteId = id;
this._setupChannel(this._pc.createDataChannel(genID()));
}
}, {
key: '_setupChannel',
value: function _setupChannel(channel) {
var _this3 = this;
var count = 0;
this._channel = channel;
channel.onopen = function () {
log('Data chanel opened', channel.readyState);
_this3._sendRequest('ping');
};
channel.onmessage = function (e) {
log('Message received', _this3.id, e);
setTimeout(function () {
return _this3._sendRequest('pong #' + count);
}, 100);
if (++count === 5) {
log('Disconnecting client', _this3.id);
_this3._destroy();
}
};
}
}, {
key: '_sendRequest',
value: function _sendRequest(request) {
if (this._channel.readyState === 'open') {
this._channel.send((0, _stringify2.default)(request));
}
}
}, {
key: '_destroy',
value: function _destroy() {
if (this._channel) {
this._channel.close();
}
this._pc.close();
this._pc = null;
this._signalingChannel.removeClient(this);
}
}, {
key: 'onsignalingmessage',
value: function onsignalingmessage(remoteId, json) {
var _this4 = this;
var pc = this._pc;
if (!this.remoteId) {
this.remoteId = remoteId;
pc.ondatachannel = function (_ref3) {
var channel = _ref3.channel;
return _this4._setupChannel(channel);
};
}
var _JSON$parse = JSON.parse(json);
var sdp = _JSON$parse.sdp;
var candidate = _JSON$parse.candidate;
if (sdp) {
pc.setRemoteDescription(new RTCSessionDescription(sdp)).then(function () {
if (pc.remoteDescription.type !== 'offer') {
return;
}
pc.createAnswer().then(function (desc) {
return _this4._localDescCreated(desc);
}).catch(function (err) {
return error('failed to create answer', err);
});
}).catch(function (err) {
return error('failed to set remote desc', err);
});
} else {
pc.addIceCandidate(new RTCIceCandidate(candidate)).catch(function (err) {
return error('failed to add ice candidate', err);
});
}
}
}]);
return Client;
}();
var SignalingChannel = function () {
function SignalingChannel() {
(0, _classCallCheck3.default)(this, SignalingChannel);
this._clients = new _map2.default();
}
(0, _createClass3.default)(SignalingChannel, [{
key: 'addClient',
value: function addClient(client) {
this._clients.set(client.id, client);
}
}, {
key: 'getClient',
value: function getClient(id) {
return this._clients.get(id);
}
}, {
key: 'removeClient',
value: function removeClient(client) {
this._clients.delete(client.id);
}
}, {
key: 'send',
value: function send(from, to, message) {
this._clients.get(to).onsignalingmessage(from, message);
}
}]);
return SignalingChannel;
}();
setInterval(function () {
// console.groupEnd();
// console.group();
log('creating signalling channel');
var channel = new SignalingChannel();
var PCConfig = { 'iceServers': [{ 'url': 'stun:stun.l.google.com:19302' }] };
log('creating client #1');
var client1 = new Client(PCConfig, channel);
channel.addClient(client1);
log('creating client #2');
var client2 = new Client(PCConfig, channel);
channel.addClient(client2);
log('connecting clients');
client1.connect(client2);
}, 1000);
function log() {
// console.log(...args);
}
function error() {
// console.error(...args);
}
})(window.RTCSessionDescription || window.mozRTCSessionDescription, window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection, window.RTCIceCandidate || window.mozRTCIceCandidate);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment