Commit 20569c21 authored by Dele Olajide's avatar Dele Olajide Committed by dele

Rayo plugin - Added support for SIP handsets

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@13776 b35dd754-fafc-0310-a699-88a17e54d16e
parent 51e60be8
......@@ -23,6 +23,7 @@
var username = null;
var password = null;
var jid = window.location.hostname;
var sipHandset = null;
window.dialer = new Dialpad({
onPress: function (key) {
......@@ -74,6 +75,7 @@
if (urlParam("domain")) domain = urlParam("domain");
if (urlParam("username")) username = urlParam("username");
if (urlParam("password")) password = urlParam("password");
if (urlParam("handset")) sipHandset = urlParam("handset");
if (domain == "81.201.82.25" && prefix == "sip:") prefix = "sip:883510";
if (prefix == "tel:") domain = "";
......@@ -132,6 +134,7 @@
{
codec_name: "PCMU",
stereo_pan: "0",
sip_handset: sipHandset,
offHook: function() {
$("#status").html("Off Hook");
......@@ -261,7 +264,6 @@
if (!username) groupname = null;
window.connection.rayo.dial("xmpp:" + window.connection.jid, sipUri, {
codec_name: "PCMU",
group_name: groupname
});
......
......@@ -178,7 +178,7 @@ Strophe.addConnectionPlugin('rayo',
//console.log(iq.toString());
that._connection.sendIQ(iq, function(response) {
$('ref', response).each(function()
{
callId = $(this).attr('id');
......@@ -200,6 +200,8 @@ Strophe.addConnectionPlugin('rayo',
});
}, function(error){
//console.log(error);
$('error', error).each(function()
{
......@@ -225,16 +227,47 @@ Strophe.addConnectionPlugin('rayo',
//console.log(headers);
var that = this;
var sipuri = (headers && headers.sip_handset) ? headers.sip_handset : (that.callbacks.sip_handset ? that.callbacks.sip_handset : null);
navigator.webkitGetUserMedia({audio:true, video:false}, function(stream)
if (sipuri)
{
that.localStream = stream;
that._offhook1(mixer, headers, action);
}, function(error) {
var group = (headers && headers.group_name) ? headers.group_name : "";
var codec = (headers && headers.codec_name) ? headers.codec_name : (that.callbacks.codec_name ? that.callbacks.codec_name : "OPUS");
if (that.callbacks && that.callbacks.onError) that.callbacks.onError(error);
});
var iq = $iq({to: "rayo." + that._connection.domain, from: that._connection.jid, type: "get"}).c("offhook", {xmlns: Strophe.NS.RAYO_HANDSET, sipuri: sipuri, mixer: mixer, group: group, codec: codec});
//console.log(iq.toString())
that._connection.sendIQ(iq, function(response)
{
//console.log(response)
$('ref', response).each(function()
{
that.handsetId = $(this).attr('id');
that.handsetUri = $(this).attr('uri');
if (action) action();
});
}, function (error) {
if (that.callbacks && that.callbacks.onError) that.callbacks.onError("offhook failure");
});
} else {
navigator.webkitGetUserMedia({audio:true, video:false}, function(stream)
{
that.localStream = stream;
that._offhook1(mixer, headers, action);
}, function(error) {
if (that.callbacks && that.callbacks.onError) that.callbacks.onError(error);
});
}
},
_offhook1: function(mixer, headers, action)
......
......@@ -24,32 +24,14 @@ import org.apache.commons.lang.builder.ToStringStyle;
public class Handset extends BaseVerb {
public static final String MISSING_CRYPTO_SUITE = "Missing Crypto Suite";
public static final String MISSING_LOCAL_CRYPTO = "Missing Local Crypto";
public static final String MISSING_REMOTE_CRYPTO = "Missing Remote Crypto";
public static final String MISSING_MIXER = "Missing Mixer";
public static final String MISSING_CODEC = "Missing Codec";
public static final String MISSING_STEREO = "Missing Stereo";
@NotNull(message=Handset.MISSING_CRYPTO_SUITE)
public String cryptoSuite;
@NotNull(message=Handset.MISSING_LOCAL_CRYPTO)
public String localCrypto;
@NotNull(message=Handset.MISSING_REMOTE_CRYPTO)
public String remoteCrypto;
@NotNull(message=Handset.MISSING_CODEC)
public String codec;
@NotNull(message=Handset.MISSING_STEREO)
public String stereo;
@NotNull(message=Handset.MISSING_MIXER)
public String mixer;
public String group;
public String cryptoSuite = null;
public String localCrypto = null;
public String remoteCrypto = null;
public String codec = null;
public String stereo = null;
public String mixer = null;
public String group = null;
public String sipuri = null;
public Handset(String cryptoSuite, String localCrypto, String remoteCrypto, String codec, String stereo, String mixer)
{
......@@ -61,6 +43,13 @@ public class Handset extends BaseVerb {
this.mixer = mixer;
}
public Handset(String sipuri, String mixer, String codec)
{
this.sipuri = sipuri;
this.mixer = mixer;
this.codec = codec;
}
@Override
public String toString() {
......@@ -72,7 +61,8 @@ public class Handset extends BaseVerb {
.append("remoteCrypto",remoteCrypto)
.append("codec",codec)
.append("stereo",stereo)
.append("stereo",mixer)
.append("mixer",mixer)
.append("sipuri",sipuri)
.toString();
}
}
......@@ -69,12 +69,22 @@ public class HandsetProvider extends BaseProvider {
private Object buildOffHookCommand(Element element) throws URISyntaxException {
Handset handset = new Handset( element.attributeValue("cryptosuite"),
element.attributeValue("localcrypto"),
element.attributeValue("remotecrypto"),
element.attributeValue("codec"),
element.attributeValue("stereo"),
element.attributeValue("mixer"));
Handset handset;
String sipuri = element.attributeValue("sipuri");
if (sipuri != null && "".equals(sipuri) == false)
{
handset = new Handset( element.attributeValue("sipuri"), element.attributeValue("mixer"), element.attributeValue("codec"));
} else {
handset = new Handset( element.attributeValue("cryptosuite"),
element.attributeValue("localcrypto"),
element.attributeValue("remotecrypto"),
element.attributeValue("codec"),
element.attributeValue("stereo"),
element.attributeValue("mixer"));
}
handset.group = element.attributeValue("group");
......
......@@ -26,9 +26,14 @@ public final class SIPAlertInfo extends ParametersHeader
return stringbuffer.toString();
}
protected StringBuilder encodeBody(StringBuilder builder)
protected StringBuilder encodeBody(StringBuilder builder)
{
return null;
builder.append(namePair);
if(!parameters.isEmpty())
builder.append(";").append(parameters.encode());
return builder;
}
public void setNamePair(String namePair)
......
......@@ -124,10 +124,12 @@ public class RayoComponent extends AbstractComponent
Object object = handsetProvider.fromXML(element);
if (object instanceof OnHookCommand) {
reply = handleOnOffHookCommand((OnHookCommand) object, iq);
OnHookCommand command = (OnHookCommand) object;
reply = handleOnOffHookCommand(command, iq);
} else if (object instanceof OffHookCommand) {
reply = handleOnOffHookCommand((OffHookCommand) object, iq);
OffHookCommand command = (OffHookCommand) object;
reply = handleOnOffHookCommand(command, iq);
}
return reply;
}
......@@ -214,14 +216,15 @@ public class RayoComponent extends AbstractComponent
Log.info("RayoComponent handleOnOffHookCommand");
IQ reply = IQ.createResultIQ(iq);
String callId = JID.escapeNode(iq.getFrom().toString());
if (object instanceof OnHookCommand)
{
RelayChannel channel = plugin.getRelayChannel(JID.escapeNode(iq.getFrom().toString()));
CallHandler handler = CallHandler.findCall(callId);
if (channel != null)
if (handler != null)
{
handleOnOffHook(object, channel);
handleOnOffHook(callId, object, plugin.getRelayChannel(callId));
} else {
reply.setError(PacketError.Condition.item_not_found);
......@@ -230,24 +233,39 @@ public class RayoComponent extends AbstractComponent
} else {
final Handset handset = ((OffHookCommand) object).getHandset();
final RelayChannel channel = plugin.createRelayChannel(iq.getFrom(), handset);
if (channel != null) // rayo handset component can have only one call
if (handset.sipuri == null) // webrtc handset
{
final Element childElement = reply.setChildElement("ref", "urn:xmpp:rayo:1");
final RelayChannel channel = plugin.createRelayChannel(iq.getFrom(), handset);
childElement.addAttribute(HOST, LocalIPResolver.getLocalIP());
childElement.addAttribute(LOCAL_PORT, Integer.toString(channel.getPortA()));
childElement.addAttribute(REMOTE_PORT, Integer.toString(channel.getPortB()));
childElement.addAttribute(ID, channel.getAttachment());
childElement.addAttribute(URI, "handset:" + channel.getAttachment() + "@rayo." + getDomain() + "/" + iq.getFrom().getNode());
if (channel != null)
{
final Element childElement = reply.setChildElement("ref", "urn:xmpp:rayo:1");
Log.debug("Created handset channel {}:{}, {}:{}, {}:{}", new Object[]{HOST, LocalIPResolver.getLocalIP(), LOCAL_PORT, Integer.toString(channel.getPortA()), REMOTE_PORT, Integer.toString(channel.getPortB())});
childElement.addAttribute(HOST, LocalIPResolver.getLocalIP());
childElement.addAttribute(LOCAL_PORT, Integer.toString(channel.getPortA()));
childElement.addAttribute(REMOTE_PORT, Integer.toString(channel.getPortB()));
childElement.addAttribute(ID, channel.getAttachment());
childElement.addAttribute(URI, "handset:" + channel.getAttachment() + "@rayo." + getDomain() + "/" + iq.getFrom().getNode());
handleOnOffHook(object, channel);
Log.debug("Created WebRTC handset channel {}:{}, {}:{}, {}:{}", new Object[]{HOST, LocalIPResolver.getLocalIP(), LOCAL_PORT, Integer.toString(channel.getPortA()), REMOTE_PORT, Integer.toString(channel.getPortB())});
} else {
reply.setError(PacketError.Condition.internal_server_error);
handleOnOffHook(callId, object, channel);
} else {
reply.setError(PacketError.Condition.internal_server_error);
}
} else { // SIP handset
final Element childElement = reply.setChildElement("ref", "urn:xmpp:rayo:1");
childElement.addAttribute(ID, callId);
childElement.addAttribute(URI, "handset:" + callId + "@rayo." + getDomain() + "/" + iq.getFrom().getNode());
Log.info("Created SIP handset channel " + handset.sipuri);
handleOnOffHook(callId, object, null);
}
}
......@@ -255,19 +273,19 @@ public class RayoComponent extends AbstractComponent
}
private void handleOnOffHook(Object object, RelayChannel channel)
private void handleOnOffHook(String callId, Object object, RelayChannel channel)
{
final boolean flag = object instanceof OnHookCommand;
Log.info("RayoComponent handleOnOffHook " + flag);
try {
OutgoingCallHandler callHandler = channel.getCallHandler();
CallHandler handler = CallHandler.findCall(callId);
if (callHandler != null)
if (handler != null)
{
callHandler.cancelRequest("Reseting handset to " + (flag ? "on" : "off") + "hook");
callHandler = null;
handler.cancelRequest("Reseting handset to " + (flag ? "on" : "off") + "hook");
handler = null;
}
if (!flag) // offhook
......@@ -280,27 +298,41 @@ public class RayoComponent extends AbstractComponent
mediaPreference = "PCM/48000/2";
CallParticipant cp = new CallParticipant();
cp.setCallId(channel.getAttachment());
cp.setProtocol("WebRtc");
cp.setCallId(callId);
cp.setConferenceId(handset.mixer);
cp.setMediaPreference(mediaPreference);
cp.setRelayChannel(channel);
cp.setDisplayName(channel.getAttachment());
cp.setDisplayName("rayo-handset-" + System.currentTimeMillis());
cp.setName(cp.getDisplayName());
cp.setVoiceDetection(true);
cp.setCallOwner(channel.getFrom().toString());
cp.setCallOwner(JID.unescapeNode(callId));
if (handset.group != null && ! "".equals(handset.group))
{
// set for new or existing conference
ConferenceManager.getConference(handset.mixer, channel.getMediaPreference(), handset.group, false);
ConferenceManager.getConference(handset.mixer, mediaPreference, handset.group, false);
ConferenceManager.setDisplayName(handset.mixer, handset.group);
}
callHandler = new OutgoingCallHandler(this, cp);
if (channel == null)
{
cp.setMediaPreference("PCMU/8000/1");
cp.setPhoneNumber(handset.sipuri);
cp.setAutoAnswer(true);
cp.setProtocol("SIP");
} else {
cp.setMediaPreference(mediaPreference);
cp.setRelayChannel(channel);
cp.setProtocol("WebRtc");
}
OutgoingCallHandler callHandler = new OutgoingCallHandler(this, cp);
callHandler.start();
channel.setCallHandler(callHandler);
if (channel != null)
{
channel.setCallHandler(callHandler);
}
}
} catch (Exception e) {
......@@ -923,16 +955,15 @@ public class RayoComponent extends AbstractComponent
{
Log.info("RayoComponent doPhoneAndPcCall " + handsetId);
RelayChannel channel = plugin.getRelayChannel(handsetId);
CallHandler handsetHandler = CallHandler.findCall(handsetId);
if (channel != null)
if (handsetHandler != null)
{
try {
setMixer(channel, reply, cp);
setMixer(handsetHandler, reply, cp);
OutgoingCallHandler outgoingCallHandler = new OutgoingCallHandler(this, cp);
//OutgoingCallHandler handsetHandler = channel.getCallHandler();
//outgoingCallHandler.setOtherCall(handsetHandler);
//handsetHandler.setOtherCall(outgoingCallHandler);
......@@ -953,15 +984,16 @@ public class RayoComponent extends AbstractComponent
return reply;
}
private void setMixer(RelayChannel channel, IQ reply, CallParticipant cp)
private void setMixer(CallHandler handsetHandler, IQ reply, CallParticipant cp)
{
String username = channel.getFrom().getNode();
String mixer = channel.getHandset().mixer;
CallParticipant hp = handsetHandler.getCallParticipant();
ConferenceManager conferenceManager = ConferenceManager.getConference( mixer,
channel.getMediaPreference(),
username, false);
try {
String mixer = hp.getConferenceId();
ConferenceManager conferenceManager = ConferenceManager.getConference( mixer,
hp.getMediaPreference(),
cp.getName(), false);
cp.setConferenceId(mixer);
cp.setCallId(mixer);
conferenceManager.setCallId(mixer);
......@@ -1026,8 +1058,12 @@ public class RayoComponent extends AbstractComponent
if ("001 STATE CHANGED".equals(myEvent))
{
if ("100 INVITED".equals(callState)) {
presence.getElement().add(rayoProvider.toXML(new RingingEvent(null, headers)));
sendPacket(presence);
if (cp.isAutoAnswer() == false) // SIP handset, no ringing event
{
presence.getElement().add(rayoProvider.toXML(new RingingEvent(null, headers)));
sendPacket(presence);
}
} else if ("200 ESTABLISHED".equals(callState)) {
......
......@@ -294,9 +294,11 @@ public class RayoPlugin implements Plugin, SessionEventListener {
private void checkRecordingFolder(File pluginDirectory)
{
String rayoHome = JiveGlobals.getHomeDirectory() + File.separator + "resources" + File.separator + "spank" + File.separator + "rayo";
try
{
File rayoFolderPath = new File(JiveGlobals.getHomeDirectory() + File.separator + "rayo");
File rayoFolderPath = new File(rayoHome);
if(!rayoFolderPath.exists())
{
......@@ -304,7 +306,7 @@ public class RayoPlugin implements Plugin, SessionEventListener {
}
File recordingFolderPath = new File(JiveGlobals.getHomeDirectory() + File.separator + "rayo" + File.separator + "recordings");
File recordingFolderPath = new File(rayoHome + File.separator + "recordings");
if(!recordingFolderPath.exists())
{
......@@ -312,7 +314,7 @@ public class RayoPlugin implements Plugin, SessionEventListener {
}
File soundsFolderPath = new File(JiveGlobals.getHomeDirectory() + File.separator + "rayo" + File.separator + "sounds");
File soundsFolderPath = new File(rayoHome + File.separator + "sounds");
if(!soundsFolderPath.exists())
{
......
......@@ -46,7 +46,7 @@ public class Application implements CallEventListener {
System.setProperty("com.sun.voip.server.PUBLIC_IP_ADDRESS", config.getPublicHost());
System.setProperty("com.sun.voip.server.PROTOCOL", config.getDefaultProtocol());
System.setProperty("com.sun.voip.server.SIP_PORT", config.getDefaultSIPPort());
System.setProperty("com.sun.voip.server.Bridge.recordDirectory", pluginDirectory.getAbsolutePath() + File.separator + ".." + File.separator + ".." + File.separator + "rayo" + File.separator + "recordings");
System.setProperty("com.sun.voip.server.Bridge.recordDirectory", pluginDirectory.getAbsolutePath() + File.separator + ".." + File.separator + ".." + File.separator + "resources" + File.separator + "spank" + File.separator + "rayo" + File.separator + "recordings");
System.setProperty("freetts.voices", "com.sun.speech.freetts.en.us.cmu_us_kal.KevinVoiceDirectory");
Properties properties = new Properties();
......
......@@ -178,7 +178,7 @@ Strophe.addConnectionPlugin('rayo',
//console.log(iq.toString());
that._connection.sendIQ(iq, function(response) {
$('ref', response).each(function()
{
callId = $(this).attr('id');
......@@ -200,6 +200,8 @@ Strophe.addConnectionPlugin('rayo',
});
}, function(error){
//console.log(error);
$('error', error).each(function()
{
......@@ -225,16 +227,47 @@ Strophe.addConnectionPlugin('rayo',
//console.log(headers);
var that = this;
var sipuri = (headers && headers.sip_handset) ? headers.sip_handset : (that.callbacks.sip_handset ? that.callbacks.sip_handset : null);
navigator.webkitGetUserMedia({audio:true, video:false}, function(stream)
if (sipuri)
{
that.localStream = stream;
that._offhook1(mixer, headers, action);
}, function(error) {
var group = (headers && headers.group_name) ? headers.group_name : "";
var codec = (headers && headers.codec_name) ? headers.codec_name : (that.callbacks.codec_name ? that.callbacks.codec_name : "OPUS");
if (that.callbacks && that.callbacks.onError) that.callbacks.onError(error);
});
var iq = $iq({to: "rayo." + that._connection.domain, from: that._connection.jid, type: "get"}).c("offhook", {xmlns: Strophe.NS.RAYO_HANDSET, sipuri: sipuri, mixer: mixer, group: group, codec: codec});
//console.log(iq.toString())
that._connection.sendIQ(iq, function(response)
{
//console.log(response)
$('ref', response).each(function()
{
that.handsetId = $(this).attr('id');
that.handsetUri = $(this).attr('uri');
if (action) action();
});
}, function (error) {
if (that.callbacks && that.callbacks.onError) that.callbacks.onError("offhook failure");
});
} else {
navigator.webkitGetUserMedia({audio:true, video:false}, function(stream)
{
that.localStream = stream;
that._offhook1(mixer, headers, action);
}, function(error) {
if (that.callbacks && that.callbacks.onError) that.callbacks.onError(error);
});
}
},
_offhook1: function(mixer, headers, action)
......
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