Commit 1a6c79e9 authored by Dele Olajide's avatar Dele Olajide Committed by dele

Rayo plugin work-in-progress

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@13756 b35dd754-fafc-0310-a699-88a17e54d16e
parent dc855d85
...@@ -17,10 +17,8 @@ ...@@ -17,10 +17,8 @@
<script> <script>
var avatar = 'unknown.jpg'; var avatar = 'unknown.jpg';
var callerId = "unknown";
var domain = "81.201.82.25"; var domain = "81.201.82.25";
var prefix = "sip:"; var prefix = "sip:";
var handsetOffhook = false;
var ringtone; var ringtone;
window.dialer = new Dialpad({ window.dialer = new Dialpad({
...@@ -65,6 +63,7 @@ ...@@ -65,6 +63,7 @@
if (domain == "81.201.82.25" && prefix == "sip:") prefix = "sip:883510"; if (domain == "81.201.82.25" && prefix == "sip:") prefix = "sip:883510";
if (prefix == "tel:") domain = ""; if (prefix == "tel:") domain = "";
if (prefix == "xmpp:") domain = window.location.hostname;
var iNum = urlParam("inum"); var iNum = urlParam("inum");
...@@ -74,7 +73,6 @@ ...@@ -74,7 +73,6 @@
} }
window.connection = new Openfire.Connection(window.location.protocol + '//' + window.location.host + '/http-bind/'); window.connection = new Openfire.Connection(window.location.protocol + '//' + window.location.host + '/http-bind/');
window.connection.resource = iNum; window.connection.resource = iNum;
window.connection.addHandler(handlePresence, null,"presence", null, null, null);
window.connection.connect(window.location.hostname, null, function (status) window.connection.connect(window.location.hostname, null, function (status)
{ {
...@@ -84,16 +82,13 @@ ...@@ -84,16 +82,13 @@
if (status === Strophe.Status.CONNECTED) if (status === Strophe.Status.CONNECTED)
{ {
$("#status").html("Ready"); $("#status").html("Ready");
setPresence(); window.connection.send($pres());
$(window).unload( function() { $(window).unload( function() {
onhook();
window.connection.disconnect(); window.connection.disconnect();
}); });
setPresence(); setPhone();
getContacts();
offhook();
} }
}); });
...@@ -105,184 +100,109 @@ ...@@ -105,184 +100,109 @@
} }
}) })
function setPresence(chat)
{
//console.log("setPresence");
if (window.connection)
{
var presence = $pres();
if (chat) presence.c('show').t(chat).up();
window.connection.send(presence);
}
}
function offhook() function setPhone()
{ {
console.log("offhook()"); console.log("setPhone()");
if (window.connection) if (window.connection)
{ {
window.connection.rayo.offhook( window.connection.rayo.phone(
{ {
codec: "OPUS",
stereo: "0",
onReady: function() { onReady: function() {
console.log('Handset is off hook'); console.log('Handset is off hook');
$("#status").html("Off Hook"); $("#status").html("Off Hook");
handsetOffhook = true;
}, },
onUnready: function() { onUnready: function() {
console.log('Handset is on hook'); console.log('Handset is on hook');
$("#status").html("On Hook"); $("#status").html("On Hook");
handsetOffhook = false;
}, },
onEnd: function() { onOffer: function(call, headers) {
console.log('Handset is disconnected'); console.log('onOffer ' + call.from);
$("#status").html("On Hook"); console.log(headers);
handsetOffhook = false;
},
onError: function(e) {
console.error(e);
}
});
}
}
function toggleHook()
{
console.log("onhook()");
if (window.connection) if (window.candybar.call == null) // ignore when user has active call
{
if (handsetOffhook)
window.connection.rayo.onhook();
else
offhook()
}
}
function handlePresence(presence)
{
//console.log("handlePresence");
//console.log(presence);
var from = $(presence).attr('from');
var iNum = Strophe.getResourceFromJid(from);
var xquery = presence.getElementsByTagName("x");
if (xquery.length == 0)
{
var type = $(presence).attr('type');
if (type == "unavailable")
{ {
window.candybar.setUser({
name: call.from,
number: call.to,
picUrl: 'unknown.jpg'
});
window.candybar.call = call;
} else { window.candybar.setState('incoming');
//var status = $(presence).find('status').text(); window.dialer.setCallLabel('Answer');
}
} }
},
return true; onEnd: function(callId, headers) {
}; console.log('onEnd ' + callId);
console.log(headers);
function getContacts ()
{
//console.log("getContacts ");
};
function makeCall(destination)
{
console.log("makeCall " + destination);
var sipUri = prefix + destination + "@" + domain
if (prefix == "tel:") sipUri = prefix + destination
window.candybar.call = window.connection.rayo.dial(
{
from: 'unknown',
to: sipUri,
onEnd: function() {
//console.log('ended...............');
window.candybar.endGently(); window.candybar.endGently();
window.candybar.call = null; window.candybar.call = null;
window.dialer.setCallLabel('Call'); window.dialer.setCallLabel('Call');
}, },
onAnswer: function() { onAnswer: function(callId, headers) {
//console.log('answered...............'); console.log('onAnswer ' + callId);
console.log(headers);
window.candybar.setState('active'); window.candybar.setState('active');
window.dialer.setCallLabel('Hangup'); window.dialer.setCallLabel('Hangup');
stopTone(); stopTone();
}, },
onRing: function() { onRing: function(callId, headers) {
//console.log('ringing...............'); console.log('onRing ' + callId);
console.log(headers);
window.candybar.setState('calling'); window.candybar.setState('calling');
startTone("ringback-uk"); startTone("ringback-uk");
}, },
onError: function(e) { onError: function(e) {
//console.log('dial error ' + e); console.error(e);
window.candybar.endGently();
window.candybar.call = null;
} }
}); });
}
}
function makeCall(destination)
{
console.log("makeCall " + destination);
var sipUri = prefix + destination + "@" + domain
if (prefix == "tel:") sipUri = prefix + destination
window.candybar.call = window.connection.rayo.dial("xmpp:" + window.connection.jid, sipUri);
window.candybar.setUser({ window.candybar.setUser({
name: callerId, name: sipUri,
number: destination, number: destination,
picUrl: 'unknown.jpg' picUrl: 'unknown.jpg'
}); });
} }
function onIncomingCall(event) function onIncomingCall(call)
{ {
console.log(' call from ' + event.call.initiator); console.log(' call from ' + call.from);
if (window.candybar.call == null) // ignore when user has active call if (window.candybar.call == null) // ignore when user has active call
{ {
var destination = Strophe.getNodeFromJid(event.call.initiator);
window.candybar.setUser({ window.candybar.setUser({
name: destination, name: call.from,
number: destination, number: call.to,
picUrl: 'http://placekitten.com/100/100' picUrl: 'unknown.jpg'
}); });
window.candybar.call = event.call; window.candybar.call = call;
window.candybar.setState('incoming'); window.candybar.setState('incoming');
window.dialer.setCallLabel('Answer'); window.dialer.setCallLabel('Answer');
/*
window.candybar.call.bind(
{
onHangup: function(event)
{
window.candybar.endGently();
//window.candybar.call = null;
window.dialer.setCallLabel('Call');
},
onAnswer: function(event)
{
window.candybar.setState('active');
window.dialer.setCallLabel('Hangup');
},
onError: function(event)
{
console.log('call error ' + event.reason);
}
});
*/
} }
} }
...@@ -303,15 +223,18 @@ ...@@ -303,15 +223,18 @@
} }
function stopTone() function stopTone()
{
if (ringtone)
{ {
ringtone.pause(); ringtone.pause();
ringtone = null; ringtone = null;
} }
}
</script> </script>
</head> </head>
<body> <body>
<div id="dialpadDiv" style="position: absolute; width: 500px: height: 300px;"/> <div id="dialpadDiv" style="position: absolute; width: 500px: height: 300px;"/>
<span id="status" onClick="toggleHook()">Loading...</span> <span id="status">Loading...</span>
</body> </body>
</html> </html>
\ No newline at end of file
...@@ -21,7 +21,6 @@ Strophe.addConnectionPlugin('rayo', ...@@ -21,7 +21,6 @@ Strophe.addConnectionPlugin('rayo',
init: function(conn) init: function(conn)
{ {
this._connection = conn; this._connection = conn;
this.calls = {};
Strophe.addNamespace('RAYO_CORE', "urn:xmpp:rayo:1"); Strophe.addNamespace('RAYO_CORE', "urn:xmpp:rayo:1");
Strophe.addNamespace('RAYO_CALL', "urn:xmpp:rayo:call:1"); Strophe.addNamespace('RAYO_CALL', "urn:xmpp:rayo:call:1");
...@@ -40,39 +39,171 @@ Strophe.addConnectionPlugin('rayo', ...@@ -40,39 +39,171 @@ Strophe.addConnectionPlugin('rayo',
Strophe.addNamespace('RAYO_HANDSET', "urn:xmpp:rayo:handset:1"); Strophe.addNamespace('RAYO_HANDSET', "urn:xmpp:rayo:handset:1");
Strophe.addNamespace('RAYO_HANDSET_COMPLETE', "urn:xmpp:rayo:handset:complete:1"); Strophe.addNamespace('RAYO_HANDSET_COMPLETE', "urn:xmpp:rayo:handset:complete:1");
this._connection.addHandler(this.handlePresence.bind(this), null,"presence", null, null, null); this._connection.addHandler(this._handlePresence.bind(this), null,"presence", null, null, null);
console.log('Rayo plugin initialised'); console.log('Rayo plugin initialised');
}, },
offhook: function(handset) phone: function(callbacks)
{ {
//console.log('Rayo plugin offhook'); this.callbacks = callbacks;
},
if (this.handset && this.handset.mixer) // reuse mixer hangup: function(callId)
{ {
handset.mixer = this.handset.mixer; console.log("hangup " + callId);
var that = this;
var iq = $iq({to: callId + "@rayo." + this._connection.domain, from: this._connection.jid, type: "get"}).c("hangup", {xmlns: Strophe.NS.RAYO_CORE});
console.log(iq.toString());
that._connection.sendIQ(iq, function(response)
{
console.log(response);
if ($(response).attr('type') != "result")
{
if (that.callbacks && that.callbacks.onError) that.callbacks.onError("hangup failure");
} }
});
if (!handset.mixer) handset.mixer = "rayo-mixer-" + Math.random().toString(36).substr(2,9); this._onhook();
},
digit: function(callId, key)
{
//console.log("digit " + callId + " " + key);
var that = this;
var iq = $iq({to: callId + "@rayo." + this._connection.domain, from: this._connection.jid, type: "get"}).c("dtmf", {xmlns: Strophe.NS.RAYO_CORE, tones: key});
that._connection.sendIQ(iq, function(response)
{
if ($(response).attr('type') != "result")
{
if (that.callbacks && that.callbacks.onError) that.callbacks.onError("dtmf failure");
}
});
},
answer: function(callId, headers)
{
//console.log('Rayo plugin accept ' + callId);
//console.log(headers)
var that = this;
if (this._isOffhook()) this._onhook();
this._offhook(callId, headers, function()
{
var iq = $iq({to: "rayo." + that._connection.domain, from: that._connection.jid, type: "get"}).c("answer", {xmlns: Strophe.NS.RAYO_CORE});
if (headers)
{
var hdrs = Object.getOwnPropertyNames(headers)
for (var i=0; i< hdrs.length; i++)
{
var name = hdrs[i];
var value = headers[name];
iq.c("header", {name: name, value: value}).up();
}
}
console.log(iq.toString());
that._connection.sendIQ(iq, function(response)
{
if ($(response).attr('type') != "result")
{
if (that.callbacks && that.callbacks.onError) that.callbacks.onError("answer failure");
}
});
});
},
dial: function(from, to, headers)
{
//console.log('Rayo plugin dial ' + from + " " + to);
//console.log(headers)
var that = this;
var callId = "rayo-call-" + Math.random().toString(36).substr(2,9);
if (this._isOffhook()) this._onhook();
this._offhook(callId, headers, function()
{
var iq = $iq({to: "rayo." + that._connection.domain, from: that._connection.jid, type: "get"}).c("dial", {xmlns: Strophe.NS.RAYO_CORE, to: to, from: from});
iq.c("header", {name: "call-id", value: callId}).up();
if (headers)
{
var hdrs = Object.getOwnPropertyNames(headers)
for (var i=0; i< hdrs.length; i++)
{
var name = hdrs[i];
var value = headers[name];
iq.c("header", {name: name, value: value}).up();
}
}
console.log(iq.toString());
that._connection.sendIQ(iq, function(response)
{
if ($(response).attr('type') != "result")
{
if (that.callbacks && that.callbacks.onError) that.callbacks.onError("dial failure");
}
});
});
return {
digit: function(tone) {that.digit(callId, tone);},
hangup: function() {that.hangup(callId);},
from: from,
to: to,
id: callId
}
},
_isOffhook: function()
{
return this.localStream != null;
},
_offhook: function(mixer, headers, action)
{
//console.log('Rayo plugin offhook ' + mixer);
//console.log(headers);
this.handset = handset;
var that = this; var that = this;
navigator.webkitGetUserMedia({audio:true, video:false}, function(stream) navigator.webkitGetUserMedia({audio:true, video:false}, function(stream)
{ {
that.localStream = stream; that.localStream = stream;
that._offhook1(); that._offhook1(mixer, headers, action);
}, function(error) { }, function(error) {
if (that.handset && that.handset.onError) that.handset.onError(error); if (that.callbacks && that.callbacks.onError) that.callbacks.onError(error);
}); });
}, },
_offhook1: function() _offhook1: function(mixer, headers, action)
{ {
//console.log('Rayo plugin _offhook1 '); //console.log('Rayo plugin _offhook1 ' + mixer);
var that = this; var that = this;
that.pc1 = new webkitRTCPeerConnection(null); that.pc1 = new webkitRTCPeerConnection(null);
...@@ -100,7 +231,7 @@ Strophe.addConnectionPlugin('rayo', ...@@ -100,7 +231,7 @@ Strophe.addConnectionPlugin('rayo',
var sdp = WebrtcSDP.buildSDP(sdpObj2); var sdp = WebrtcSDP.buildSDP(sdpObj2);
//console.log(sdp); //console.log(sdp);
that.pc1.setRemoteDescription(new RTCSessionDescription({type: "answer", sdp : sdp})); that.pc1.setRemoteDescription(new RTCSessionDescription({type: "answer", sdp : sdp}));
that._offhook2(); that._offhook2(mixer, headers, action);
}); });
}); });
...@@ -115,12 +246,15 @@ Strophe.addConnectionPlugin('rayo', ...@@ -115,12 +246,15 @@ Strophe.addConnectionPlugin('rayo',
}; };
}, },
_offhook2: function() _offhook2: function(mixer, headers, action)
{ {
//console.log('Rayo plugin _offhook2 ' + this.cryptoSuite + " " + this.localCrypto + " " + this.remoteCrypto); //console.log('Rayo plugin _offhook2 ' + this.cryptoSuite + " " + this.localCrypto + " " + this.remoteCrypto + " " + mixer);
var that = this; var that = this;
var iq = $iq({to: "rayo." + that._connection.domain, from: that._connection.jid, type: "get"}).c("offhook", {xmlns: Strophe.NS.RAYO_HANDSET, cryptoSuite: that.cryptoSuite, localCrypto: that.localCrypto, remoteCrypto: that.remoteCrypto, codec: that.handset.codec, stereo: that.handset.stereo, mixer: that.handset.mixer}); var stereo = (headers && headers.stereo) ? headers.stereo : "0";
var codec = (headers && headers.codec) ? headers.codec : "OPUS";
var iq = $iq({to: "rayo." + that._connection.domain, from: that._connection.jid, type: "get"}).c("offhook", {xmlns: Strophe.NS.RAYO_HANDSET, cryptoSuite: that.cryptoSuite, localCrypto: that.localCrypto, remoteCrypto: that.remoteCrypto, codec: codec, stereo: stereo, mixer: mixer});
//console.log(iq.toString()) //console.log(iq.toString())
...@@ -139,15 +273,16 @@ Strophe.addConnectionPlugin('rayo', ...@@ -139,15 +273,16 @@ Strophe.addConnectionPlugin('rayo',
that.pc2.addIceCandidate(new RTCIceCandidate({sdpMLineIndex: "0", candidate: "a=candidate:3707591233 1 udp 2113937151 " + that.relayHost + " " + that.relayRemotePort + " typ host generation 0"})); that.pc2.addIceCandidate(new RTCIceCandidate({sdpMLineIndex: "0", candidate: "a=candidate:3707591233 1 udp 2113937151 " + that.relayHost + " " + that.relayRemotePort + " typ host generation 0"}));
that.pc1.addIceCandidate(new RTCIceCandidate({sdpMLineIndex: "0", candidate: "a=candidate:3707591233 1 udp 2113937151 " + that.relayHost + " " + that.relayLocalPort + " typ host generation 0"})); that.pc1.addIceCandidate(new RTCIceCandidate({sdpMLineIndex: "0", candidate: "a=candidate:3707591233 1 udp 2113937151 " + that.relayHost + " " + that.relayLocalPort + " typ host generation 0"}));
action();
}); });
} else { } else {
if (handset.onError) handset.onError("offhook failure"); if (that.callbacks && that.callbacks.onError) that.callbacks.onError("offhook failure");
} }
}); });
}, },
onhook: function() _onhook: function()
{ {
//console.log('Rayo plugin onhook ' + this.handsetId); //console.log('Rayo plugin onhook ' + this.handsetId);
...@@ -167,76 +302,66 @@ Strophe.addConnectionPlugin('rayo', ...@@ -167,76 +302,66 @@ Strophe.addConnectionPlugin('rayo',
}, },
dial: function(config)
{
//console.log('Rayo plugin dial');
//console.log(config)
var callId = "rayo-call-" + Math.random().toString(36).substr(2,9); _handlePresence: function(presence)
{
//console.log('Rayo plugin handlePresence');
//console.log(presence);
var that = this; var that = this;
var from = $(presence).attr('from');
var headers = {}
var iq = $iq({to: "rayo." + this._connection.domain, from: this._connection.jid, type: "get"}).c("dial", {xmlns: Strophe.NS.RAYO_CORE, to: config.to, from: config.from}); $(presence).find('header').each(function()
iq.c("join", {xmlns: Strophe.NS.RAYO_CORE, 'mixer-name': this.handset.mixer}).up();
iq.c("header", {name: "call-id", value: callId}).up();
iq.c("header", {name: "handset", value: that.handsetId}).up();
if (config.headers)
{
for (var i=0; i<headers.length; i++)
{ {
iq.c("header", {name: config.headers[i].name, value: config.headers[i].value}).up(); var name = $(this).attr('name');
} var value = $(this).attr('value');
}
//console.log(iq.toString()); headers[name] = value;
});
this._connection.sendIQ(iq, function(response) $(presence).find('complete').each(function()
{ {
if ($(response).attr('type') != "result") $(this).find('success').each(function()
{
if ($(this).attr('xmlns') == Strophe.NS.RAYO_HANDSET_COMPLETE)
{ {
if (config.onError) config.onError("dial failure"); that._onhook();
} }
}); });
});
this.calls[callId] = $(presence).find('offer').each(function()
{ {
callId: callId, if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE)
onRing: config.onRing,
onAnswer: config.onAnswer,
onError: config.onError,
onEnd: config.onEnd,
from: config.from,
to: config.to,
hangup: function()
{ {
//console.log("hangup " + this.callId); var callFrom = $(this).attr('from');
var callTo = $(this).attr('value');
var callId = Strophe.getNodeFromJid(from);
var iq = $iq({to: this.callId + "@rayo." + that._connection.domain, from: that._connection.jid, type: "get"}).c("hangup", {xmlns: Strophe.NS.RAYO_CORE}); var call = {
digit: function(tone) {that.digit(callId, tone);},
hangup: function() {that.hangup(callId);},
answer: function(callId, headers) {that.answer(callId, headers);},
that._connection.sendIQ(iq, function(response) from: callFrom,
{ to: callTo,
if ($(response).attr('type') != "result") id: callId
{
if (config.onError) config.onError("hangup failure");
} }
});
},
answer: function() if (that.callbacks && that.callbacks.onOffer) that.callbacks.onOffer(call, headers);
{
}, var iq = $iq({to: from, from: that._connection.jid, type: "get"}).c("accept", {xmlns: Strophe.NS.RAYO_CORE});
digit: function(key) var hdrs = Object.getOwnPropertyNames(headers)
for (var i=0; i< hdrs.length; i++)
{ {
//console.log("digit " + this.callId + " " + key); var name = hdrs[i];
var value = headers[name];
var iq = $iq({to: this.callId + "@rayo." + that._connection.domain, from: that._connection.jid, type: "get"}).c("dtmf", {xmlns: Strophe.NS.RAYO_CORE, tones: key}); iq.c("header", {name: name, value: value}).up();
}
//console.log(iq.toString()); //console.log(iq.toString());
...@@ -244,44 +369,17 @@ Strophe.addConnectionPlugin('rayo', ...@@ -244,44 +369,17 @@ Strophe.addConnectionPlugin('rayo',
{ {
if ($(response).attr('type') != "result") if ($(response).attr('type') != "result")
{ {
if (config.onError) config.onError("dtmf failure"); if (that.callbacks && that.callbacks.onError) that.callbacks.onError("accept failure");
} }
}); });
} }
}; })
return this.calls[callId];
},
handlePresence: function(presence)
{
//console.log('Rayo plugin handlePresence');
//console.log(presence);
var that = this;
var from = $(presence).attr('from');
$(presence).find('complete').each(function()
{
$(this).find('success').each(function()
{
if ($(this).attr('xmlns') == Strophe.NS.RAYO_HANDSET_COMPLETE)
{
that.onhook();
if (that.handset && that.handset.onEnd) that.handset.onEnd();
}
});
});
$(presence).find('joined').each(function() $(presence).find('joined').each(function()
{ {
if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE) if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE)
{ {
if (that.handsetId == Strophe.getNodeFromJid(from))
{
if (that.handset && that.handset.onReady) that.handset.onReady();
}
} }
}); });
...@@ -289,41 +387,50 @@ Strophe.addConnectionPlugin('rayo', ...@@ -289,41 +387,50 @@ Strophe.addConnectionPlugin('rayo',
{ {
if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE) if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE)
{ {
if (that.handsetId == Strophe.getNodeFromJid(from))
{
if (that.handset && that.handset.onUnready) that.handset.onUnready();
}
} }
}); });
$(presence).find('ringing').each(function() $(presence).find('ringing').each(function()
{ {
if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE) if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE)
{
if (that.handsetId != Strophe.getNodeFromJid(from))
{ {
var callId = Strophe.getNodeFromJid(from); var callId = Strophe.getNodeFromJid(from);
var call = that.calls[callId]; if (that.callbacks && that.callbacks.onRing) that.callbacks.onRing(callId, headers);
if (call && call.onRing) call.onRing(call); }
} }
}); });
$(presence).find('answered').each(function() $(presence).find('answered').each(function()
{ {
if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE) if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE)
{
if (that.handsetId != Strophe.getNodeFromJid(from))
{ {
var callId = Strophe.getNodeFromJid(from); var callId = Strophe.getNodeFromJid(from);
var call = that.calls[callId]; if (that.callbacks && that.callbacks.onAnswer) that.callbacks.onAnswer(callId, headers);
if (call && call.onAnswer) call.onAnswer(call);
} else {
if (that.callbacks && that.callbacks.onReady) that.callbacks.onReady();
}
} }
}); });
$(presence).find('end').each(function() $(presence).find('end').each(function()
{ {
if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE) if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE)
{
if (that.handsetId != Strophe.getNodeFromJid(from))
{ {
var callId = Strophe.getNodeFromJid(from); var callId = Strophe.getNodeFromJid(from);
var call = that.calls[callId]; if (that.callbacks && that.callbacks.onEnd) that.callbacks.onEnd(callId, headers);
if (call && call.onEnd) call.onEnd(call);
that.calls[callId] = null; } else {
if (that.callbacks && that.callbacks.onUnready) that.callbacks.onUnready();
}
} }
}); });
......
...@@ -27,6 +27,7 @@ import java.net.InetSocketAddress; ...@@ -27,6 +27,7 @@ import java.net.InetSocketAddress;
import org.voicebridge.*; import org.voicebridge.*;
import org.xmpp.jnodes.RelayChannel; import org.xmpp.jnodes.RelayChannel;
import java.util.*;
/** /**
* A Class to represent a call participant - a party in a call. * A Class to represent a call participant - a party in a call.
...@@ -90,6 +91,9 @@ public class CallParticipant { ...@@ -90,6 +91,9 @@ public class CallParticipant {
private ProxyCredentials proxyCredentials = null; private ProxyCredentials proxyCredentials = null;
private RelayChannel relayChannel = null; private RelayChannel relayChannel = null;
private boolean autoAnswer = true; private boolean autoAnswer = true;
private long startTimestamp = 0;
private long endTimestamp = 0;
private Map<String, String> headers = new HashMap<String, String>();
/* /*
* Second party in a two party call or target of migration * Second party in a two party call or target of migration
...@@ -123,9 +127,7 @@ public class CallParticipant { ...@@ -123,9 +127,7 @@ public class CallParticipant {
this.proxyCredentials = proxyCredentials; this.proxyCredentials = proxyCredentials;
} }
/**
* Get/Set proxy credentials
*/
public RelayChannel getRelayChannel() public RelayChannel getRelayChannel()
{ {
return relayChannel; return relayChannel;
...@@ -136,6 +138,35 @@ public class CallParticipant { ...@@ -136,6 +138,35 @@ public class CallParticipant {
this.relayChannel = relayChannel; this.relayChannel = relayChannel;
} }
public long getStartTimestamp()
{
return startTimestamp;
}
public void setStartTimestamp(long startTimestamp)
{
this.startTimestamp = startTimestamp;
}
public long getEndTimestamp()
{
return endTimestamp;
}
public void setEndTimestamp(long endTimestamp)
{
this.endTimestamp = endTimestamp;
}
public Map<String, String> getHeaders()
{
return headers;
}
public void setHeaders(Map<String, String> headers)
{
this.headers = headers;
}
/** /**
* Get call answer timeout * Get call answer timeout
......
...@@ -30,6 +30,8 @@ import org.xmpp.packet.*; ...@@ -30,6 +30,8 @@ import org.xmpp.packet.*;
import java.util.*; import java.util.*;
import java.text.ParseException; import java.text.ParseException;
import java.net.URI;
import java.net.URISyntaxException;
import com.rayo.core.*; import com.rayo.core.*;
import com.rayo.core.verb.*; import com.rayo.core.verb.*;
...@@ -39,6 +41,11 @@ import com.rayo.core.xml.providers.*; ...@@ -39,6 +41,11 @@ import com.rayo.core.xml.providers.*;
import com.sun.voip.server.*; import com.sun.voip.server.*;
import com.sun.voip.*; import com.sun.voip.*;
import org.voicebridge.*;
public class RayoComponent extends AbstractComponent public class RayoComponent extends AbstractComponent
implements TreatmentDoneListener, implements TreatmentDoneListener,
CallEventListener, CallEventListener,
...@@ -139,8 +146,6 @@ public class RayoComponent extends AbstractComponent ...@@ -139,8 +146,6 @@ public class RayoComponent extends AbstractComponent
if (object instanceof ConnectCommand) { if (object instanceof ConnectCommand) {
} else if (object instanceof AcceptCommand) {
} else if (object instanceof HoldCommand) { } else if (object instanceof HoldCommand) {
} else if (object instanceof UnholdCommand) { } else if (object instanceof UnholdCommand) {
...@@ -155,8 +160,11 @@ public class RayoComponent extends AbstractComponent ...@@ -155,8 +160,11 @@ public class RayoComponent extends AbstractComponent
} else if (object instanceof UnjoinCommand) { } else if (object instanceof UnjoinCommand) {
reply = handleUnjoinCommand((UnjoinCommand) object, iq); reply = handleUnjoinCommand((UnjoinCommand) object, iq);
} else if (object instanceof AcceptCommand) {
reply = handleAcceptCommand((AcceptCommand) object, iq);
} else if (object instanceof AnswerCommand) { } else if (object instanceof AnswerCommand) {
reply = handleAnswerCommand((AnswerCommand) object, iq);
} else if (object instanceof HangupCommand) { } else if (object instanceof HangupCommand) {
reply = handleHangupCommand(iq); reply = handleHangupCommand(iq);
...@@ -199,11 +207,7 @@ public class RayoComponent extends AbstractComponent ...@@ -199,11 +207,7 @@ public class RayoComponent extends AbstractComponent
if (object instanceof OnHookCommand) if (object instanceof OnHookCommand)
{ {
String key = iq.getTo().getNode(); RelayChannel channel = plugin.getRelayChannel(JID.escapeNode(iq.getFrom().toString()));
if (key != null)
{
RelayChannel channel = plugin.getRelayChannel(iq.getTo().getNode());
if (channel != null) if (channel != null)
{ {
...@@ -213,11 +217,6 @@ public class RayoComponent extends AbstractComponent ...@@ -213,11 +217,6 @@ public class RayoComponent extends AbstractComponent
reply.setError(PacketError.Condition.item_not_found); reply.setError(PacketError.Condition.item_not_found);
} }
} else {
reply.setError(PacketError.Condition.item_not_found);
}
} else { } else {
final Handset handset = ((OffHookCommand) object).getHandset(); final Handset handset = ((OffHookCommand) object).getHandset();
...@@ -371,6 +370,88 @@ public class RayoComponent extends AbstractComponent ...@@ -371,6 +370,88 @@ public class RayoComponent extends AbstractComponent
} }
private IQ handleAcceptCommand(AcceptCommand command, IQ iq)
{
Log.info("RayoComponent handleAcceptCommand " + iq.getFrom() + " " + iq.getTo().getNode());
IQ reply = IQ.createResultIQ(iq);
Map<String, String> headers = command.getHeaders();
try {
Presence presence = new Presence();
presence.setFrom(iq.getTo());
presence.setTo(JID.unescapeNode(iq.getTo().getNode()));
presence.getElement().add(rayoProvider.toXML(new RingingEvent(null, headers)));
sendPacket(presence);
} catch (Exception e) {
reply.setError(PacketError.Condition.item_not_found);
}
return reply;
}
private IQ handleAnswerCommand(AnswerCommand command, IQ iq)
{
Log.info("RayoComponent AnswerCommand " + iq.getFrom() + " " + iq.getTo().getNode());
IQ reply = IQ.createResultIQ(iq);
Map<String, String> headers = command.getHeaders();
try {
String handsetId = JID.escapeNode(iq.getFrom().toString());
Presence presence = new Presence();
presence.setFrom(iq.getTo());
presence.setTo(JID.unescapeNode(iq.getTo().getNode()));
presence.getElement().add(rayoProvider.toXML(new AnsweredEvent(null, headers)));
sendPacket(presence);
RelayChannel channel = plugin.getRelayChannel(handsetId);
if (channel != null)
{
Handset handset = channel.getHandset();
CallHandler callHandler = channel.getCallHandler();
if (callHandler != null)
{
Log.info("RayoComponent handleAnswerCommand found call handler " + callHandler);
CallParticipant cp = callHandler.getCallParticipant();
if (cp != null)
{
String username = iq.getFrom().getNode();
ConferenceManager conferenceManager = ConferenceManager.getConference( handset.mixer,
channel.getMediaPreference(),
username, false);
try {
cp.setStartTimestamp(System.currentTimeMillis());
cp.setHeaders(headers);
String recording = handset.mixer + "-" + cp.getStartTimestamp() + ".au";
conferenceManager.recordConference(true, recording, "au");
Config.createCallRecord(username, recording, "xmpp:" + iq.getFrom().toString(), cp.getStartTimestamp(), 0, "dialed") ;
} catch (ParseException e1) {
reply.setError(PacketError.Condition.internal_server_error);
}
}
}
}
} catch (Exception e) {
reply.setError(PacketError.Condition.item_not_found);
e.printStackTrace();
}
return reply;
}
private IQ handleHangupCommand(IQ iq) private IQ handleHangupCommand(IQ iq)
{ {
Log.info("RayoComponent handleHangupCommand " + iq.getFrom()); Log.info("RayoComponent handleHangupCommand " + iq.getFrom());
...@@ -478,55 +559,90 @@ public class RayoComponent extends AbstractComponent ...@@ -478,55 +559,90 @@ public class RayoComponent extends AbstractComponent
boolean toPhone = to.indexOf("sip:") == 0 || to.indexOf("tel:") == 0; boolean toPhone = to.indexOf("sip:") == 0 || to.indexOf("tel:") == 0;
boolean toXmpp = to.indexOf("xmpp:") == 0; boolean toXmpp = to.indexOf("xmpp:") == 0;
String codec = headers.get("caller-id");
String handsetId = headers.get("handset");
String mixer = null;
String callId = headers.get("call-id"); String callId = headers.get("call-id");
String callerName = headers.get("caller-name"); String callerName = headers.get("caller-name");
String calledName = headers.get("called-name"); String calledName = headers.get("called-name");
String handsetId = iq.getFrom().toString();
JoinCommand join = command.getJoin(); JoinCommand join = command.getJoin();
if (join != null && join.getTo() != null) if (join != null)
{ {
if (join.getType() == JoinDestinationType.CALL) { if (join.getType() == JoinDestinationType.CALL) {
// TODO join.getTo() // TODO join.getTo()
} else { } else {
mixer = join.getTo();
} }
reply.setError(PacketError.Condition.feature_not_implemented);
} else {
if (callId == null)
{
callId = "rayo-call-" + System.currentTimeMillis();
headers.put("call-id", callId);
} }
if (mixer != null) if (callerName == null)
{ {
if (callId == null) callId = "rayo-call-" + System.currentTimeMillis(); callerName = iq.getFrom().getNode();
if (callerName == null) callerName = iq.getFrom().toString(); headers.put("caller-name", callerName);
}
CallParticipant cp = new CallParticipant(); if (calledName == null)
cp.setVoiceDetection(true); {
cp.setCallOwner(iq.getFrom().toString()); calledName = to;
headers.put("called-name", calledName);
}
if (toPhone) if (toPhone)
{ {
CallParticipant cp = new CallParticipant();
cp.setVoiceDetection(true);
cp.setCallOwner(handsetId);
cp.setMediaPreference("PCMU/8000/1"); cp.setMediaPreference("PCMU/8000/1");
cp.setProtocol("SIP"); cp.setProtocol("SIP");
cp.setCallId(callId); cp.setCallId(callId);
cp.setDisplayName(callerName); cp.setDisplayName(callerName);
cp.setPhoneNumber(to); cp.setPhoneNumber(to);
cp.setName(calledName == null ? cp.getPhoneNumber() : calledName); cp.setName(calledName);
cp.setConferenceId(mixer); cp.setHeaders(headers);
reply = doPhoneAndPcCall(handsetId, cp, reply); reply = doPhoneAndPcCall(JID.escapeNode(handsetId), cp, reply);
} else if (toXmpp){ } else if (toXmpp){
} else { String destination = to.substring(5);
String mixer = JID.escapeNode(destination);
Presence presence = new Presence();
presence.setFrom(mixer + "@rayo." + getDomain());
presence.setTo(new JID(destination));
headers.put("mixer-name", mixer);
OfferEvent offer = new OfferEvent(callId);
try {
offer.setFrom(new URI("xmpp:" + iq.getFrom().toString()));
offer.setTo(new URI(to));
} catch (URISyntaxException e) {
reply.setError(PacketError.Condition.feature_not_implemented); reply.setError(PacketError.Condition.feature_not_implemented);
return reply;
} }
offer.setHeaders(headers);
presence.getElement().add(rayoProvider.toXML(offer));
sendPacket(presence);
} else { } else {
reply.setError(PacketError.Condition.feature_not_implemented); reply.setError(PacketError.Condition.feature_not_implemented);
} }
}
return reply; return reply;
} }
...@@ -662,16 +778,14 @@ public class RayoComponent extends AbstractComponent ...@@ -662,16 +778,14 @@ public class RayoComponent extends AbstractComponent
private IQ doPhoneAndPcCall(String handsetId, CallParticipant cp, IQ reply) private IQ doPhoneAndPcCall(String handsetId, CallParticipant cp, IQ reply)
{ {
String mixer = cp.getConferenceId(); Log.info("RayoComponent doPhoneAndPcCall " + handsetId);
Log.info("RayoComponent doPhoneAndPcCall " + handsetId + " " + mixer);
RelayChannel channel = plugin.getRelayChannel(handsetId); RelayChannel channel = plugin.getRelayChannel(handsetId);
if (channel != null) if (channel != null)
{ {
try { try {
setMixer(mixer, channel, reply); setMixer(channel, reply, cp);
OutgoingCallHandler outgoingCallHandler = new OutgoingCallHandler(this, cp); OutgoingCallHandler outgoingCallHandler = new OutgoingCallHandler(this, cp);
...@@ -696,15 +810,20 @@ public class RayoComponent extends AbstractComponent ...@@ -696,15 +810,20 @@ public class RayoComponent extends AbstractComponent
return reply; return reply;
} }
private void setMixer(String mixer, RelayChannel channel, IQ reply) private void setMixer(RelayChannel channel, IQ reply, CallParticipant cp)
{ {
String username = channel.getFrom().getNode();
String mixer = channel.getHandset().mixer;
ConferenceManager conferenceManager = ConferenceManager.getConference( mixer, ConferenceManager conferenceManager = ConferenceManager.getConference( mixer,
channel.getMediaPreference(), channel.getMediaPreference(),
channel.getFrom().getNode(), false); username, false);
try { try {
if (conferenceManager.getMemberList().size() == 0) { cp.setConferenceId(mixer);
conferenceManager.recordConference(true, mixer + "-" + System.currentTimeMillis() + ".au", "au"); cp.setStartTimestamp(System.currentTimeMillis());
} String recording = mixer + "-" + cp.getStartTimestamp() + ".au";
conferenceManager.recordConference(true, recording, "au");
Config.createCallRecord(cp.getDisplayName(), recording, cp.getPhoneNumber(), cp.getStartTimestamp(), 0, "dialed") ;
} catch (ParseException e1) { } catch (ParseException e1) {
reply.setError(PacketError.Condition.internal_server_error); reply.setError(PacketError.Condition.internal_server_error);
...@@ -737,18 +856,30 @@ public class RayoComponent extends AbstractComponent ...@@ -737,18 +856,30 @@ public class RayoComponent extends AbstractComponent
String myEvent = com.sun.voip.CallEvent.getEventString(callEvent.getEvent()); String myEvent = com.sun.voip.CallEvent.getEventString(callEvent.getEvent());
String callState = callEvent.getCallState().toString(); String callState = callEvent.getCallState().toString();
Map<String, String> headers = new HashMap<String, String>(); try {
headers.put("callId", callEvent.getCallId()); CallHandler callHandler = CallHandler.findCall(callEvent.getCallId());
headers.put("info", callEvent.getCallInfo() == null ? "" : callEvent.getCallInfo());
headers.put("mixer", callEvent.getConferenceId() == null ? "" : callEvent.getConferenceId()); if (callHandler != null)
headers.put("callInfo", callEvent.getCallInfo() == null ? "" : callEvent.getCallInfo()); {
Log.info("RayoComponent callEventNotification found call handler " + callHandler);
CallParticipant cp = callHandler.getCallParticipant();
if (cp != null)
{
Log.info("RayoComponent callEventNotification found call paticipant " + cp);
Map<String, String> headers = cp.getHeaders();
headers.put("call-id", callEvent.getCallId());
headers.put("mixer-name", callEvent.getConferenceId());
Presence presence = new Presence(); Presence presence = new Presence();
presence.setFrom(callEvent.getCallId() + "@rayo." + getDomain()); presence.setFrom(callEvent.getCallId() + "@rayo." + getDomain());
presence.setTo(from); presence.setTo(from);
if ("001 STATE CHANGED".equals(myEvent)) { if ("001 STATE CHANGED".equals(myEvent))
{
if ("110 ANSWERED".equals(callState)) { if ("110 ANSWERED".equals(callState)) {
presence.getElement().add(rayoProvider.toXML(new RingingEvent(null, headers))); presence.getElement().add(rayoProvider.toXML(new RingingEvent(null, headers)));
sendPacket(presence); sendPacket(presence);
...@@ -760,16 +891,28 @@ public class RayoComponent extends AbstractComponent ...@@ -760,16 +891,28 @@ public class RayoComponent extends AbstractComponent
} else if ("299 ENDED".equals(callState)) { } else if ("299 ENDED".equals(callState)) {
presence.getElement().add(rayoProvider.toXML(new EndEvent(null, EndEvent.Reason.valueOf("HANGUP"), headers))); presence.getElement().add(rayoProvider.toXML(new EndEvent(null, EndEvent.Reason.valueOf("HANGUP"), headers)));
sendPacket(presence); sendPacket(presence);
if (cp.getStartTimestamp() > 0)
{
cp.setEndTimestamp(System.currentTimeMillis());
Config.updateCallRecord(cp.getStartTimestamp(), (int)((cp.getEndTimestamp() - cp.getStartTimestamp()) / 1000));
ConferenceManager conferenceManager = ConferenceManager.findConferenceManager(callEvent.getConferenceId());
conferenceManager.recordConference(false, null, null);
cp.setStartTimestamp(0);
} }
}
} else if ("250 STARTED SPEAKING".equals(myEvent)) { } else if ("250 STARTED SPEAKING".equals(myEvent)) {
StartedSpeakingEvent speaker = new StartedSpeakingEvent(); StartedSpeakingEvent speaker = new StartedSpeakingEvent();
speaker.setSpeakerId(headers.get("callId")); speaker.setSpeakerId(callEvent.getCallId());
presence.getElement().add(rayoProvider.toXML(speaker)); presence.getElement().add(rayoProvider.toXML(speaker));
sendPacket(presence); sendPacket(presence);
} else if ("259 STOPPED SPEAKING".equals(myEvent)) { } else if ("259 STOPPED SPEAKING".equals(myEvent)) {
StoppedSpeakingEvent speaker = new StoppedSpeakingEvent(); StoppedSpeakingEvent speaker = new StoppedSpeakingEvent();
speaker.setSpeakerId(headers.get("callId")); speaker.setSpeakerId(callEvent.getCallId());
presence.getElement().add(rayoProvider.toXML(speaker)); presence.getElement().add(rayoProvider.toXML(speaker));
sendPacket(presence); sendPacket(presence);
...@@ -785,6 +928,12 @@ public class RayoComponent extends AbstractComponent ...@@ -785,6 +928,12 @@ public class RayoComponent extends AbstractComponent
} }
} }
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void initiated(String name, String callId) public void initiated(String name, String callId)
{ {
Log.info( "RayoComponent initiated " + name + " " + callId); Log.info( "RayoComponent initiated " + name + " " + callId);
......
...@@ -159,7 +159,7 @@ public class RayoPlugin implements Plugin, SessionEventListener { ...@@ -159,7 +159,7 @@ public class RayoPlugin implements Plugin, SessionEventListener {
try { try {
rc = RelayChannel.createLocalRelayChannel(bindAllInterfaces ? "0.0.0.0" : LocalIPResolver.getLocalIP(), 30000, 50000); rc = RelayChannel.createLocalRelayChannel(bindAllInterfaces ? "0.0.0.0" : LocalIPResolver.getLocalIP(), 30000, 50000);
final int id = ids.incrementAndGet(); final int id = ids.incrementAndGet();
final String sId = "rayo-handset-" + String.valueOf(id); final String sId = JID.escapeNode(jid.toString());
rc.setAttachment(sId); rc.setAttachment(sId);
rc.setFrom(jid, component); rc.setFrom(jid, component);
rc.setCrypto(handset); rc.setCrypto(handset);
......
...@@ -4,6 +4,9 @@ import java.util.*; ...@@ -4,6 +4,9 @@ import java.util.*;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
...@@ -20,6 +23,8 @@ import org.xmpp.packet.*; ...@@ -20,6 +23,8 @@ import org.xmpp.packet.*;
public class Config implements MUCEventListener { public class Config implements MUCEventListener {
private static final Logger Log = LoggerFactory.getLogger(Config.class);
private MultiUserChatManager mucManager; private MultiUserChatManager mucManager;
private HashMap<String, Conference> conferences; private HashMap<String, Conference> conferences;
private HashMap<String, Conference> confExtensions; private HashMap<String, Conference> confExtensions;
...@@ -59,7 +64,7 @@ public class Config implements MUCEventListener { ...@@ -59,7 +64,7 @@ public class Config implements MUCEventListener {
MUCEventDispatcher.addListener(this); MUCEventDispatcher.addListener(this);
try { try {
System.out.println(String.format("VoiceBridge read site configuration")); Log.info(String.format("VoiceBridge read site configuration"));
mucManager = XMPPServer.getInstance().getMultiUserChatManager(); mucManager = XMPPServer.getInstance().getMultiUserChatManager();
...@@ -87,14 +92,15 @@ public class Config implements MUCEventListener { ...@@ -87,14 +92,15 @@ public class Config implements MUCEventListener {
processDefaultRegistration(username); processDefaultRegistration(username);
} }
Log.info(String.format("VoiceBridge sip plugin assumed available"));
sipPlugin = true;
} else { } else {
registerWithDefaultProxy(); registerWithDefaultProxy();
} }
} }
} catch (Throwable t) { } catch (Throwable t) {
t.printStackTrace(); t.printStackTrace();
} }
...@@ -147,10 +153,10 @@ public class Config implements MUCEventListener { ...@@ -147,10 +153,10 @@ public class Config implements MUCEventListener {
registrars.add(sipAccount.getHost()); registrars.add(sipAccount.getHost());
registrations.add(sipAccount); registrations.add(sipAccount);
System.out.println(String.format("VoiceBridge adding SIP registration: %s with user %s host %s", sipAccount.getXmppUserName(), sipAccount.getUserName(), sipAccount.getHost())); Log.info(String.format("VoiceBridge adding SIP registration: %s with user %s host %s", sipAccount.getXmppUserName(), sipAccount.getUserName(), sipAccount.getHost()));
} catch (Exception e) { } catch (Exception e) {
System.out.println("registerWithDefaultProxy " + e); Log.info("registerWithDefaultProxy " + e);
} }
} }
...@@ -176,20 +182,18 @@ public class Config implements MUCEventListener { ...@@ -176,20 +182,18 @@ public class Config implements MUCEventListener {
registrars.add(credentials.getHost()); registrars.add(credentials.getHost());
registrations.add(credentials); registrations.add(credentials);
System.out.println(String.format("VoiceBridge adding SIP registration: %s with user %s host %s", credentials.getXmppUserName(), credentials.getUserName(), credentials.getHost())); Log.info(String.format("VoiceBridge adding SIP registration: %s with user %s host %s", credentials.getXmppUserName(), credentials.getUserName(), credentials.getHost()));
} catch (Exception e) { } catch (Exception e) {
System.out.println(String.format("processDefaultRegistration Bad Address %s ", credentials.getHost())); Log.info(String.format("processDefaultRegistration Bad Address %s ", credentials.getHost()));
} }
} }
rs.close(); rs.close();
pstmt.close(); pstmt.close();
con.close(); con.close();
sipPlugin = true;
} catch (SQLException e) { } catch (SQLException e) {
System.out.println("processDefaultRegistration " + e); Log.info("processDefaultRegistration " + e);
} }
} }
...@@ -214,21 +218,19 @@ public class Config implements MUCEventListener { ...@@ -214,21 +218,19 @@ public class Config implements MUCEventListener {
registrars.add(credentials.getHost()); registrars.add(credentials.getHost());
registrations.add(credentials); registrations.add(credentials);
System.out.println(String.format("VoiceBridge adding SIP registration: %s with user %s host %s", credentials.getXmppUserName(), credentials.getUserName(), credentials.getHost())); Log.info(String.format("VoiceBridge adding SIP registration: %s with user %s host %s", credentials.getXmppUserName(), credentials.getUserName(), credentials.getHost()));
} catch (Exception e) { } catch (Exception e) {
System.out.println(String.format("processRegistrations Bad Address %s ", credentials.getHost())); Log.info(String.format("processRegistrations Bad Address %s ", credentials.getHost()));
} }
} }
rs.close(); rs.close();
pstmt.close(); pstmt.close();
con.close(); con.close();
sipPlugin = true;
} catch (SQLException e) { } catch (SQLException e) {
System.out.println("processRegistrations " + e); Log.info("processRegistrations " + e);
} }
} }
...@@ -261,7 +263,7 @@ public class Config implements MUCEventListener { ...@@ -261,7 +263,7 @@ public class Config implements MUCEventListener {
sipExtensions.put(username, sipAccount); sipExtensions.put(username, sipAccount);
} catch (SQLException e) { } catch (SQLException e) {
System.out.println("ProxyCredentials " + e); Log.info("ProxyCredentials " + e);
} }
return sipAccount; return sipAccount;
...@@ -289,7 +291,7 @@ public class Config implements MUCEventListener { ...@@ -289,7 +291,7 @@ public class Config implements MUCEventListener {
} catch (SQLException e) { } catch (SQLException e) {
System.out.println("updateStatus " + e); Log.info("updateStatus " + e);
} finally { } finally {
DbConnectionManager.closeConnection(psmt, con); DbConnectionManager.closeConnection(psmt, con);
...@@ -297,7 +299,11 @@ public class Config implements MUCEventListener { ...@@ -297,7 +299,11 @@ public class Config implements MUCEventListener {
} }
} }
public static void recordCall(String username, String addressFrom, String addressTo, long datetime, int duration, String calltype) { public static void createCallRecord(String username, String addressFrom, String addressTo, long datetime, int duration, String calltype) {
if (sipPlugin)
{
Log.info("createCallRecord " + username + " " + addressFrom + " " + addressTo + " " + datetime);
String sql = "INSERT INTO ofSipPhoneLog (username, addressFrom, addressTo, datetime, duration, calltype) values (?, ?, ?, ?, ?, ?)"; String sql = "INSERT INTO ofSipPhoneLog (username, addressFrom, addressTo, datetime, duration, calltype) values (?, ?, ?, ?, ?, ?)";
...@@ -318,11 +324,41 @@ public class Config implements MUCEventListener { ...@@ -318,11 +324,41 @@ public class Config implements MUCEventListener {
psmt.executeUpdate(); psmt.executeUpdate();
} catch (SQLException e) { } catch (SQLException e) {
Log.debug(e.getMessage(), e); Log.error(e.getMessage(), e);
} finally { } finally {
DbConnectionManager.closeConnection(rs, psmt, con); DbConnectionManager.closeConnection(rs, psmt, con);
} }
}
}
public static void updateCallRecord(long datetime, int duration) {
if (sipPlugin)
{
Log.info("updateCallRecord " + datetime + " " + duration);
String sql = "UPDATE ofSipPhoneLog SET duration = ? WHERE datetime = ?";
Connection con = null;
PreparedStatement psmt = null;
try {
con = DbConnectionManager.getConnection();
psmt = con.prepareStatement(sql);
psmt.setInt(1, duration);
psmt.setLong(2, datetime);
psmt.executeUpdate();
} catch (SQLException e) {
Log.error(e.getMessage(), e);
} finally {
DbConnectionManager.closeConnection(psmt, con);
}
}
} }
public ProxyCredentials getProxyCredentialsByUser(String username) public ProxyCredentials getProxyCredentialsByUser(String username)
...@@ -370,7 +406,7 @@ public class Config implements MUCEventListener { ...@@ -370,7 +406,7 @@ public class Config implements MUCEventListener {
conferences.put(conference.id, conference); conferences.put(conference.id, conference);
System.out.println(String.format("VoiceBridge create conference: %s with pin %s extension %s", conference.id, conference.pin, conference.exten)); Log.info(String.format("VoiceBridge create conference: %s with pin %s extension %s", conference.id, conference.pin, conference.exten));
} }
private void destroyConference(MUCRoom room) private void destroyConference(MUCRoom room)
...@@ -383,7 +419,7 @@ public class Config implements MUCEventListener { ...@@ -383,7 +419,7 @@ public class Config implements MUCEventListener {
Conference conference2 = confExtensions.remove(room.getName()); Conference conference2 = confExtensions.remove(room.getName());
conference2 = null; conference2 = null;
System.out.println(String.format("VoiceBridge destroy conference: %s", room.getName())); Log.info(String.format("VoiceBridge destroy conference: %s", room.getName()));
} }
} }
......
...@@ -21,7 +21,6 @@ Strophe.addConnectionPlugin('rayo', ...@@ -21,7 +21,6 @@ Strophe.addConnectionPlugin('rayo',
init: function(conn) init: function(conn)
{ {
this._connection = conn; this._connection = conn;
this.calls = {};
Strophe.addNamespace('RAYO_CORE', "urn:xmpp:rayo:1"); Strophe.addNamespace('RAYO_CORE', "urn:xmpp:rayo:1");
Strophe.addNamespace('RAYO_CALL', "urn:xmpp:rayo:call:1"); Strophe.addNamespace('RAYO_CALL', "urn:xmpp:rayo:call:1");
...@@ -40,39 +39,171 @@ Strophe.addConnectionPlugin('rayo', ...@@ -40,39 +39,171 @@ Strophe.addConnectionPlugin('rayo',
Strophe.addNamespace('RAYO_HANDSET', "urn:xmpp:rayo:handset:1"); Strophe.addNamespace('RAYO_HANDSET', "urn:xmpp:rayo:handset:1");
Strophe.addNamespace('RAYO_HANDSET_COMPLETE', "urn:xmpp:rayo:handset:complete:1"); Strophe.addNamespace('RAYO_HANDSET_COMPLETE', "urn:xmpp:rayo:handset:complete:1");
this._connection.addHandler(this.handlePresence.bind(this), null,"presence", null, null, null); this._connection.addHandler(this._handlePresence.bind(this), null,"presence", null, null, null);
console.log('Rayo plugin initialised'); console.log('Rayo plugin initialised');
}, },
offhook: function(handset) phone: function(callbacks)
{ {
//console.log('Rayo plugin offhook'); this.callbacks = callbacks;
},
if (this.handset && this.handset.mixer) // reuse mixer hangup: function(callId)
{ {
handset.mixer = this.handset.mixer; console.log("hangup " + callId);
var that = this;
var iq = $iq({to: callId + "@rayo." + this._connection.domain, from: this._connection.jid, type: "get"}).c("hangup", {xmlns: Strophe.NS.RAYO_CORE});
console.log(iq.toString());
that._connection.sendIQ(iq, function(response)
{
console.log(response);
if ($(response).attr('type') != "result")
{
if (that.callbacks && that.callbacks.onError) that.callbacks.onError("hangup failure");
} }
});
if (!handset.mixer) handset.mixer = "rayo-mixer-" + Math.random().toString(36).substr(2,9); this._onhook();
},
digit: function(callId, key)
{
//console.log("digit " + callId + " " + key);
var that = this;
var iq = $iq({to: callId + "@rayo." + this._connection.domain, from: this._connection.jid, type: "get"}).c("dtmf", {xmlns: Strophe.NS.RAYO_CORE, tones: key});
that._connection.sendIQ(iq, function(response)
{
if ($(response).attr('type') != "result")
{
if (that.callbacks && that.callbacks.onError) that.callbacks.onError("dtmf failure");
}
});
},
answer: function(callId, headers)
{
//console.log('Rayo plugin accept ' + callId);
//console.log(headers)
var that = this;
if (this._isOffhook()) this._onhook();
this._offhook(callId, headers, function()
{
var iq = $iq({to: "rayo." + that._connection.domain, from: that._connection.jid, type: "get"}).c("answer", {xmlns: Strophe.NS.RAYO_CORE});
if (headers)
{
var hdrs = Object.getOwnPropertyNames(headers)
for (var i=0; i< hdrs.length; i++)
{
var name = hdrs[i];
var value = headers[name];
iq.c("header", {name: name, value: value}).up();
}
}
console.log(iq.toString());
that._connection.sendIQ(iq, function(response)
{
if ($(response).attr('type') != "result")
{
if (that.callbacks && that.callbacks.onError) that.callbacks.onError("answer failure");
}
});
});
},
dial: function(from, to, headers)
{
//console.log('Rayo plugin dial ' + from + " " + to);
//console.log(headers)
var that = this;
var callId = "rayo-call-" + Math.random().toString(36).substr(2,9);
if (this._isOffhook()) this._onhook();
this._offhook(callId, headers, function()
{
var iq = $iq({to: "rayo." + that._connection.domain, from: that._connection.jid, type: "get"}).c("dial", {xmlns: Strophe.NS.RAYO_CORE, to: to, from: from});
iq.c("header", {name: "call-id", value: callId}).up();
if (headers)
{
var hdrs = Object.getOwnPropertyNames(headers)
for (var i=0; i< hdrs.length; i++)
{
var name = hdrs[i];
var value = headers[name];
iq.c("header", {name: name, value: value}).up();
}
}
console.log(iq.toString());
that._connection.sendIQ(iq, function(response)
{
if ($(response).attr('type') != "result")
{
if (that.callbacks && that.callbacks.onError) that.callbacks.onError("dial failure");
}
});
});
return {
digit: function(tone) {that.digit(callId, tone);},
hangup: function() {that.hangup(callId);},
from: from,
to: to,
id: callId
}
},
_isOffhook: function()
{
return this.localStream != null;
},
_offhook: function(mixer, headers, action)
{
//console.log('Rayo plugin offhook ' + mixer);
//console.log(headers);
this.handset = handset;
var that = this; var that = this;
navigator.webkitGetUserMedia({audio:true, video:false}, function(stream) navigator.webkitGetUserMedia({audio:true, video:false}, function(stream)
{ {
that.localStream = stream; that.localStream = stream;
that._offhook1(); that._offhook1(mixer, headers, action);
}, function(error) { }, function(error) {
if (that.handset && that.handset.onError) that.handset.onError(error); if (that.callbacks && that.callbacks.onError) that.callbacks.onError(error);
}); });
}, },
_offhook1: function() _offhook1: function(mixer, headers, action)
{ {
//console.log('Rayo plugin _offhook1 '); //console.log('Rayo plugin _offhook1 ' + mixer);
var that = this; var that = this;
that.pc1 = new webkitRTCPeerConnection(null); that.pc1 = new webkitRTCPeerConnection(null);
...@@ -100,7 +231,7 @@ Strophe.addConnectionPlugin('rayo', ...@@ -100,7 +231,7 @@ Strophe.addConnectionPlugin('rayo',
var sdp = WebrtcSDP.buildSDP(sdpObj2); var sdp = WebrtcSDP.buildSDP(sdpObj2);
//console.log(sdp); //console.log(sdp);
that.pc1.setRemoteDescription(new RTCSessionDescription({type: "answer", sdp : sdp})); that.pc1.setRemoteDescription(new RTCSessionDescription({type: "answer", sdp : sdp}));
that._offhook2(); that._offhook2(mixer, headers, action);
}); });
}); });
...@@ -115,12 +246,15 @@ Strophe.addConnectionPlugin('rayo', ...@@ -115,12 +246,15 @@ Strophe.addConnectionPlugin('rayo',
}; };
}, },
_offhook2: function() _offhook2: function(mixer, headers, action)
{ {
//console.log('Rayo plugin _offhook2 ' + this.cryptoSuite + " " + this.localCrypto + " " + this.remoteCrypto); //console.log('Rayo plugin _offhook2 ' + this.cryptoSuite + " " + this.localCrypto + " " + this.remoteCrypto + " " + mixer);
var that = this; var that = this;
var iq = $iq({to: "rayo." + that._connection.domain, from: that._connection.jid, type: "get"}).c("offhook", {xmlns: Strophe.NS.RAYO_HANDSET, cryptoSuite: that.cryptoSuite, localCrypto: that.localCrypto, remoteCrypto: that.remoteCrypto, codec: that.handset.codec, stereo: that.handset.stereo, mixer: that.handset.mixer}); var stereo = (headers && headers.stereo) ? headers.stereo : "0";
var codec = (headers && headers.codec) ? headers.codec : "OPUS";
var iq = $iq({to: "rayo." + that._connection.domain, from: that._connection.jid, type: "get"}).c("offhook", {xmlns: Strophe.NS.RAYO_HANDSET, cryptoSuite: that.cryptoSuite, localCrypto: that.localCrypto, remoteCrypto: that.remoteCrypto, codec: codec, stereo: stereo, mixer: mixer});
//console.log(iq.toString()) //console.log(iq.toString())
...@@ -139,15 +273,16 @@ Strophe.addConnectionPlugin('rayo', ...@@ -139,15 +273,16 @@ Strophe.addConnectionPlugin('rayo',
that.pc2.addIceCandidate(new RTCIceCandidate({sdpMLineIndex: "0", candidate: "a=candidate:3707591233 1 udp 2113937151 " + that.relayHost + " " + that.relayRemotePort + " typ host generation 0"})); that.pc2.addIceCandidate(new RTCIceCandidate({sdpMLineIndex: "0", candidate: "a=candidate:3707591233 1 udp 2113937151 " + that.relayHost + " " + that.relayRemotePort + " typ host generation 0"}));
that.pc1.addIceCandidate(new RTCIceCandidate({sdpMLineIndex: "0", candidate: "a=candidate:3707591233 1 udp 2113937151 " + that.relayHost + " " + that.relayLocalPort + " typ host generation 0"})); that.pc1.addIceCandidate(new RTCIceCandidate({sdpMLineIndex: "0", candidate: "a=candidate:3707591233 1 udp 2113937151 " + that.relayHost + " " + that.relayLocalPort + " typ host generation 0"}));
action();
}); });
} else { } else {
if (handset.onError) handset.onError("offhook failure"); if (that.callbacks && that.callbacks.onError) that.callbacks.onError("offhook failure");
} }
}); });
}, },
onhook: function() _onhook: function()
{ {
//console.log('Rayo plugin onhook ' + this.handsetId); //console.log('Rayo plugin onhook ' + this.handsetId);
...@@ -167,76 +302,66 @@ Strophe.addConnectionPlugin('rayo', ...@@ -167,76 +302,66 @@ Strophe.addConnectionPlugin('rayo',
}, },
dial: function(config)
{
//console.log('Rayo plugin dial');
//console.log(config)
var callId = "rayo-call-" + Math.random().toString(36).substr(2,9); _handlePresence: function(presence)
{
//console.log('Rayo plugin handlePresence');
//console.log(presence);
var that = this; var that = this;
var from = $(presence).attr('from');
var headers = {}
var iq = $iq({to: "rayo." + this._connection.domain, from: this._connection.jid, type: "get"}).c("dial", {xmlns: Strophe.NS.RAYO_CORE, to: config.to, from: config.from}); $(presence).find('header').each(function()
iq.c("join", {xmlns: Strophe.NS.RAYO_CORE, 'mixer-name': this.handset.mixer}).up();
iq.c("header", {name: "call-id", value: callId}).up();
iq.c("header", {name: "handset", value: that.handsetId}).up();
if (config.headers)
{
for (var i=0; i<headers.length; i++)
{ {
iq.c("header", {name: config.headers[i].name, value: config.headers[i].value}).up(); var name = $(this).attr('name');
} var value = $(this).attr('value');
}
//console.log(iq.toString()); headers[name] = value;
});
this._connection.sendIQ(iq, function(response) $(presence).find('complete').each(function()
{ {
if ($(response).attr('type') != "result") $(this).find('success').each(function()
{
if ($(this).attr('xmlns') == Strophe.NS.RAYO_HANDSET_COMPLETE)
{ {
if (config.onError) config.onError("dial failure"); that._onhook();
} }
}); });
});
this.calls[callId] = $(presence).find('offer').each(function()
{ {
callId: callId, if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE)
onRing: config.onRing,
onAnswer: config.onAnswer,
onError: config.onError,
onEnd: config.onEnd,
from: config.from,
to: config.to,
hangup: function()
{ {
//console.log("hangup " + this.callId); var callFrom = $(this).attr('from');
var callTo = $(this).attr('value');
var callId = Strophe.getNodeFromJid(from);
var iq = $iq({to: this.callId + "@rayo." + that._connection.domain, from: that._connection.jid, type: "get"}).c("hangup", {xmlns: Strophe.NS.RAYO_CORE}); var call = {
digit: function(tone) {that.digit(callId, tone);},
hangup: function() {that.hangup(callId);},
answer: function(callId, headers) {that.answer(callId, headers);},
that._connection.sendIQ(iq, function(response) from: callFrom,
{ to: callTo,
if ($(response).attr('type') != "result") id: callId
{
if (config.onError) config.onError("hangup failure");
} }
});
},
answer: function() if (that.callbacks && that.callbacks.onOffer) that.callbacks.onOffer(call, headers);
{
}, var iq = $iq({to: from, from: that._connection.jid, type: "get"}).c("accept", {xmlns: Strophe.NS.RAYO_CORE});
digit: function(key) var hdrs = Object.getOwnPropertyNames(headers)
for (var i=0; i< hdrs.length; i++)
{ {
//console.log("digit " + this.callId + " " + key); var name = hdrs[i];
var value = headers[name];
var iq = $iq({to: this.callId + "@rayo." + that._connection.domain, from: that._connection.jid, type: "get"}).c("dtmf", {xmlns: Strophe.NS.RAYO_CORE, tones: key}); iq.c("header", {name: name, value: value}).up();
}
//console.log(iq.toString()); //console.log(iq.toString());
...@@ -244,44 +369,17 @@ Strophe.addConnectionPlugin('rayo', ...@@ -244,44 +369,17 @@ Strophe.addConnectionPlugin('rayo',
{ {
if ($(response).attr('type') != "result") if ($(response).attr('type') != "result")
{ {
if (config.onError) config.onError("dtmf failure"); if (that.callbacks && that.callbacks.onError) that.callbacks.onError("accept failure");
} }
}); });
} }
}; })
return this.calls[callId];
},
handlePresence: function(presence)
{
//console.log('Rayo plugin handlePresence');
//console.log(presence);
var that = this;
var from = $(presence).attr('from');
$(presence).find('complete').each(function()
{
$(this).find('success').each(function()
{
if ($(this).attr('xmlns') == Strophe.NS.RAYO_HANDSET_COMPLETE)
{
that.onhook();
if (that.handset && that.handset.onEnd) that.handset.onEnd();
}
});
});
$(presence).find('joined').each(function() $(presence).find('joined').each(function()
{ {
if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE) if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE)
{ {
if (that.handsetId == Strophe.getNodeFromJid(from))
{
if (that.handset && that.handset.onReady) that.handset.onReady();
}
} }
}); });
...@@ -289,41 +387,50 @@ Strophe.addConnectionPlugin('rayo', ...@@ -289,41 +387,50 @@ Strophe.addConnectionPlugin('rayo',
{ {
if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE) if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE)
{ {
if (that.handsetId == Strophe.getNodeFromJid(from))
{
if (that.handset && that.handset.onUnready) that.handset.onUnready();
}
} }
}); });
$(presence).find('ringing').each(function() $(presence).find('ringing').each(function()
{ {
if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE) if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE)
{
if (that.handsetId != Strophe.getNodeFromJid(from))
{ {
var callId = Strophe.getNodeFromJid(from); var callId = Strophe.getNodeFromJid(from);
var call = that.calls[callId]; if (that.callbacks && that.callbacks.onRing) that.callbacks.onRing(callId, headers);
if (call && call.onRing) call.onRing(call); }
} }
}); });
$(presence).find('answered').each(function() $(presence).find('answered').each(function()
{ {
if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE) if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE)
{
if (that.handsetId != Strophe.getNodeFromJid(from))
{ {
var callId = Strophe.getNodeFromJid(from); var callId = Strophe.getNodeFromJid(from);
var call = that.calls[callId]; if (that.callbacks && that.callbacks.onAnswer) that.callbacks.onAnswer(callId, headers);
if (call && call.onAnswer) call.onAnswer(call);
} else {
if (that.callbacks && that.callbacks.onReady) that.callbacks.onReady();
}
} }
}); });
$(presence).find('end').each(function() $(presence).find('end').each(function()
{ {
if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE) if ($(this).attr('xmlns') == Strophe.NS.RAYO_CORE)
{
if (that.handsetId != Strophe.getNodeFromJid(from))
{ {
var callId = Strophe.getNodeFromJid(from); var callId = Strophe.getNodeFromJid(from);
var call = that.calls[callId]; if (that.callbacks && that.callbacks.onEnd) that.callbacks.onEnd(callId, headers);
if (call && call.onEnd) call.onEnd(call);
that.calls[callId] = null; } else {
if (that.callbacks && that.callbacks.onUnready) that.callbacks.onUnready();
}
} }
}); });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment