Skip to content

Instantly share code, notes, and snippets.

@zyxar
Last active September 11, 2018 05:40
Show Gist options
  • Save zyxar/9827049 to your computer and use it in GitHub Desktop.
Save zyxar/9827049 to your computer and use it in GitHub Desktop.
WebRTC <-> SIP <-> WebRTC
var express = require('express');
var app = express();
app.configure(function () {
"use strict";
app.use(express.logger('dev'));
app.use(express.static(__dirname + '/public'));
});
app.use(function (req, res, next) {
"use strict";
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS, DELETE');
res.header('Access-Control-Allow-Headers', 'origin, content-type');
if (req.method == 'OPTIONS') {
res.send(200);
}
else {
next();
}
});
var port = process.env.PORT || 4321;
app.listen(port);
<!DOCTYPE html><html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>WebRTC over SIP POC</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="js/jquery-latest.js"></script>
<link rel="stylesheet" href="css/bootstrap.min.css">
<script src="js/bootstrap.min.js"></script>
<script src="js/jssip.js"></script>
<script type="text/javascript" src="poc.js"></script>
</head>
<body>
<div class="container">
<div class="row clearfix">
<div class="col-md-12 column">
<div class="jumbotron">
<span>WebRTC over SIP</span>
</div>
</div>
</div>
<div class="row clearfix">
<div class="col-md-8 column">
<div class="row">
<h2>Call</h2>
<div style="white-space:nowrap;">
<input type="text" style="width: 100%; height:100%" id="sipURI" value="" placeholder="Enter sip uri" />
</div><br />
<div style="white-space:nowrap;">
<input type="text" style="width: 100%; height:100%" id="sipText" value="" placeholder="Enter text message to send" />
</div><br />
<div class="btn-toolbar" >
<div class="btn-group pull-left">
<button id="btnConnect" class="btn btn-success" data-toggle="dropdown">Connect</button>
</div>
<div class="btn-group pull-right">
<button id="btnCall" class="btn btn-primary" data-toggle="dropdown" disabled="disabled">Call</button>
</div>
<div class="btn-group pull-right">
<button id="btnHangup" class="btn btn-warning" data-toggle="dropdown" disabled="disabled">Hangup</button>
</div>
<div class="btn-group pull-right">
<button id="btnSend" class="btn btn-info" data-toggle="dropdown" disabled="disabled">Send</button>
</div>
</div>
</div>
<div class="row"><br /></div>
<div class="row">
<div class="col-md-4 column">
<video id="my-video"></video>
</div>
<div class="col-md-4 column">
<video id="peer-video"></video>
</div>
</div>
</div>
<div class="col-md-4 column">
<div id="mysipuri">
</div>
<div id="messageBoard">
</div>
</div>
</div>
</div>
<script>
$(document).ready(function(){
var self = {};
var dismiss_button_str = '<button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>';
function enableButtons () {
for (var i = arguments.length - 1; i >= 0; i--) {
$(arguments[i]).removeAttr('disabled');
};
}
function disableButtons () {
for (var i = arguments.length - 1; i >= 0; i--) {
$(arguments[i]).attr('disabled', 'disabled');
};
}
var sip_handlers = {
newRTCSession: function (e) {
var domElement = $('#messageBoard');
domElement.append('<div class="alert alert-info alert-dismissable">'+ dismiss_button_str+'newRTCSession!' +'</div>');
$('#messageBoard .alert-info:last').delay(2000).addClass("in").fadeOut(4000);
},
connected: function (e) {
var domElement = $('#messageBoard');
domElement.append('<div class="alert alert-info alert-dismissable">'+ dismiss_button_str+'connected!' +'</div>');
$('#messageBoard .alert-info:last').delay(2000).addClass("in").fadeOut(4000);
},
disconnected: function (e) {
var domElement = $('#messageBoard');
domElement.append('<div class="alert alert-info alert-dismissable">'+ dismiss_button_str+'disconnected!' +'</div>');
$('#messageBoard .alert-info:last').delay(2000).addClass("in").fadeOut(4000);
$('#mysipuri').children().remove();
},
newMessage: function (e) {
if (e.data.originator !== 'local' && e.data.message) {
var message = {
from: e.data.message.request.from.uri.user,
body: e.data.message.request.body,
data: e.data.message.request.data
};
$('input#sipURI').val(e.data.message.request.from.uri);
var domElement = $('#messageBoard');
domElement.append('<div class="alert alert-info alert-dismissable">'+ dismiss_button_str+'<strong>'+message.from+'</strong>: '+message.body +'</div>');
$('#messageBoard .alert-info:last').delay(2000).addClass("in").fadeOut(4000);
} else {
console.log(e.data);
}
},
registered: function (e) {
$('#mysipuri').append('<h4>My SIP URI:<br /><span></span></h4>');
var domElement = $('#mysipuri span')
domElement.removeClass();
domElement.addClass("label label-info");
domElement.text(self.siprtc.uri());
console.log(e.data.response);
$('#messageBoard').append('<div class="alert alert-success alert-dismissable">'+ dismiss_button_str+e.data.response.data +'</div>');
$('#messageBoard .alert-success:last').delay(5000).addClass("in").fadeOut(1000);
enableButtons('button#btnSend', 'button#btnCall');
},
unregistered: function (e) {
var domElement = $('#messageBoard');
domElement.append('<div class="alert alert-info alert-dismissable">'+ dismiss_button_str+'unregistered!' +'</div>');
$('#messageBoard .alert-info:last').delay(2000).addClass("in").fadeOut(4000);
$('#mysipuri').children().remove();
},
registrationFailed: function (e) {
var domElement = $('#messageBoard');
domElement.append('<div class="alert alert-info alert-dismissable">'+ dismiss_button_str+'registrationFailed!' +'</div>');
$('#messageBoard .alert-info:last').delay(2000).addClass("in").fadeOut(4000);
}
};
$('button#btnConnect').click(function (event) {
event.preventDefault();
var siprtc = self.siprtc = new SipRTC({
eventHandlers: sip_handlers
});
$(event.currentTarget).attr('disabled','disabled');
});
$('button#btnCall').click(function (event) {
event.preventDefault();
if (self.siprtc) {
var target = $('input#sipURI').val();
var options = {
'mediaConstraints': {'audio': true, 'video': true}
};
self.siprtc.call(target, options);
}
})
$('button#btnSend').click(function (event) {
event.preventDefault();
if (self.siprtc) {
var target = $('input#sipURI').val();
var message = $('input#sipText').val();
self.siprtc.sendMessage(target, message, {
eventHandlers: {
succeeded: function(e){
var domElement = $('#messageBoard');
domElement.append('<div class="alert alert-success alert-dismissable">'+ dismiss_button_str+'message sent!' +'</div>');
$('#messageBoard .alert-success:last').delay(2000).addClass("in").fadeOut(4000);
},
failed: function(e){
var domElement = $('#messageBoard');
domElement.append('<div class="alert alert-danger alert-dismissable">'+ dismiss_button_str+'message not sent!' +'</div>');
$('#messageBoard .alert-danger:last').delay(2000).addClass("in").fadeOut(4000);
}
}
});
}
})
});
</script>
</body></html>
SipRTC = function (config) {
config = config || {};
var sip_config = config.sip_config || {};
this.sip_config = {
ws_servers: [ "ws://WS_SIP_SERVER:10080" ],
// register: true,
// register_expires: 300,
trace_sip: true,
stun_servers: [ "stun:74.125.132.127:19302" ],
use_preloaded_route: false,
log: 'warn' // works only on 'jssip-devel.js'i
};
if (typeof sip_config.uri === 'string' && sip_config.uri !== '') {
this.sip_config.uri = sip_config.uri;
this.sip_config.display_name = sip_config.display_name || "SipRTC_User";
this.sip_config.password = sip_config.password || '';
} else {
var uid = sip_config.uid || 'woogeen00'+(Math.floor(Math.random() * 10) % 9 + 1);
this.sip_config.uri = 'sip:'+uid+"@SIP_SERVER";
this.sip_config.display_name = sip_config.display_name || 'SipRTC_'+uid;
this.sip_config.password = sip_config.password || uid;
}
try {
this.sip = new JsSIP.UA(this.sip_config);
} catch (e) {
console.log(e);
throw(e);
return this;
}
var eventHandlers = config.eventHandlers || {};
eventHandlers.newRTCSession = eventHandlers.newRTCSession || function(e){console.log(e.data);};
eventHandlers.connected = eventHandlers.connected || function(e){console.log(e.data);};
eventHandlers.disconnected = eventHandlers.disconnected || function(e){console.log(e.data);};
eventHandlers.newMessage = eventHandlers.newMessage || function(e){console.log(e.data);};
eventHandlers.registered = eventHandlers.registered || function(e){console.log(e.data);};
eventHandlers.unregistered = eventHandlers.unregistered || function(e){console.log(e.data);};
eventHandlers.registrationFailed = eventHandlers.registrationFailed || function(e){console.log(e.data);};
this.sip.on('newRTCSession', (function(e) {
eventHandlers.newRTCSession(e);
this.onCall(e);
}).bind(this));
this.sip.on('connected', eventHandlers.connected);
this.sip.on('disconnected', eventHandlers.disconnected);
this.sip.on('newMessage', eventHandlers.newMessage);
this.sip.on('registered', eventHandlers.registered);
this.sip.on('unregistered', eventHandlers.unregistered);
this.sip.on('registrationFailed', eventHandlers.registrationFailed);
this.sip.start();
function VideoView (eid) {
var self = this;
this.view = document.getElementById(eid);
this.on = false;
this.start = function (session) {
if (!self.on && session.getLocalStreams().length > 0) {
self.view.src = window.URL.createObjectURL(session.getLocalStreams()[0]);
self.view.play();
self.on = true;
}
};
this.stop = function () {
if (self.on) {
self.view.src = "";
self.view.pause();
self.on = false;
}
};
}
this.localVideo = new VideoView('my-video');
this.remoteVideo = new VideoView('peer-video');
};
SipRTC.prototype.uri = function() {
return this.sip_config.uri;
};
SipRTC.prototype.onCall = function(evt) { // TODO;
// var request = evt.data.request;
var session = evt.data.session;
this.currentSession = session;
if (session.direction === 'incoming') {
console.log("incoming call from " + session.remote_identity.uri.user);
session.answer({
mediaConstraints: { audio: true, video: true }
});
this.localVideo.start(session);
}
session.on('progress', (function (e) {
console.log("call " + e.type + ":");
console.log(e.data);
this.localVideo.start(session);
}).bind(this));
session.on('started', (function (e) {
console.log("call " + e.type + ":");
console.log(e.data);
this.localVideo.start(session);
this.remoteVideo.start(session);
}).bind(this));
session.on('failed', function (e) {
console.log("call " + e.type + ":");
console.log(e.data);
});
session.on('ended', (function (e) {
console.log("call " + e.type + ":");
console.log(e.data);
this.remoteVideo.stop();
}).bind(this));
};
SipRTC.prototype.sendMessage = function() {
this.sip.sendMessage.apply(this.sip, arguments);
};
SipRTC.prototype.call = function() {
this.sip.call.apply(this.sip, arguments);
};
// SipRTC.onXXX%
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment