Commit 2f20b26c authored by Dele Olajide's avatar Dele Olajide Committed by dele

Rayo plugin - Implemented OPUS decoding/encoding for SIP calls

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@13802 b35dd754-fafc-0310-a699-88a17e54d16e
parent de9cab2e
...@@ -124,17 +124,15 @@ if (false) { ...@@ -124,17 +124,15 @@ if (false) {
(byte)125, RtpPacket.SPEEX_ENCODING, 32000, 2, false)); (byte)125, RtpPacket.SPEEX_ENCODING, 32000, 2, false));
} }
public MediaInfo(byte payload , int encoding, int sampleRate, public MediaInfo(byte payload , int encoding, int sampleRate, int channels, boolean isTelephoneEventPayload)
int channels, boolean isTelephoneEventPayload) { {
this.payload = payload;
this.payload = payload; this.encoding = encoding;
this.encoding = encoding; this.sampleRate = sampleRate;
this.sampleRate = sampleRate; this.channels = channels;
this.channels = channels; this.isTelephoneEventPayload = isTelephoneEventPayload;
this.isTelephoneEventPayload = isTelephoneEventPayload;
samplesPerPacket = sampleRate * channels / (1000 / RtpPacket.PACKET_PERIOD);
samplesPerPacket =
sampleRate * channels / (1000 / RtpPacket.PACKET_PERIOD);
} }
public static MediaInfo findMediaInfo(int encoding, int sampleRate, public static MediaInfo findMediaInfo(int encoding, int sampleRate,
......
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
* *
* This file is part of jVoiceBridge. * This file is part of jVoiceBridge.
* *
* jVoiceBridge is free software: you can redistribute it and/or modify * jVoiceBridge is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation and distributed hereunder * published by the Free Software Foundation and distributed hereunder
* to you. * to you.
* *
* jVoiceBridge is distributed in the hope that it will be useful, * jVoiceBridge is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
...@@ -17,8 +17,8 @@ ...@@ -17,8 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* Sun designates this particular file as subject to the "Classpath" * Sun designates this particular file as subject to the "Classpath"
* exception as provided by Sun in the License file that accompanied this * exception as provided by Sun in the License file that accompanied this
* code. * code.
*/ */
package com.sun.voip; package com.sun.voip;
...@@ -49,7 +49,7 @@ public class SdpInfo { ...@@ -49,7 +49,7 @@ public class SdpInfo {
private MediaInfo transmitMediaInfo; private MediaInfo transmitMediaInfo;
private boolean transmitMediaInfoOk; private boolean transmitMediaInfoOk;
public SdpInfo(String remoteHost, int remotePort, public SdpInfo(String remoteHost, int remotePort,
byte telephoneEventPayload, Vector supportedMedia, byte telephoneEventPayload, Vector supportedMedia,
MediaInfo mediaInfo, boolean preferredMediaSpecified) { MediaInfo mediaInfo, boolean preferredMediaSpecified) {
...@@ -136,7 +136,7 @@ public class SdpInfo { ...@@ -136,7 +136,7 @@ public class SdpInfo {
public MediaInfo getMediaInfo() { public MediaInfo getMediaInfo() {
return mediaInfo; return mediaInfo;
} }
public void setTransmitMediaInfoOk(boolean transmitMediaInfoOk) { public void setTransmitMediaInfoOk(boolean transmitMediaInfoOk) {
this.transmitMediaInfoOk = transmitMediaInfoOk; this.transmitMediaInfoOk = transmitMediaInfoOk;
} }
...@@ -150,7 +150,7 @@ public class SdpInfo { ...@@ -150,7 +150,7 @@ public class SdpInfo {
} }
public MediaInfo getTransmitMediaInfo() { public MediaInfo getTransmitMediaInfo() {
if (transmitMediaInfo == null || mediaInfo.getPayload() == if (transmitMediaInfo == null || mediaInfo.getPayload() ==
RtpPacket.PCMU_PAYLOAD) { RtpPacket.PCMU_PAYLOAD) {
return mediaInfo; return mediaInfo;
...@@ -176,7 +176,7 @@ public class SdpInfo { ...@@ -176,7 +176,7 @@ public class SdpInfo {
Logger.println(e.getMessage()); Logger.println(e.getMessage());
Logger.println("Using transmit media info " + transmitMediaInfo); Logger.println("Using transmit media info " + transmitMediaInfo);
} }
return transmitMediaInfo; return transmitMediaInfo;
} }
...@@ -204,7 +204,7 @@ public class SdpInfo { ...@@ -204,7 +204,7 @@ public class SdpInfo {
return true; return true;
} }
public MediaInfo getMediaInfo(int sampleRate, int channels, int encoding) public MediaInfo getMediaInfo(int sampleRate, int channels, int encoding)
throws IOException { throws IOException {
if (supportedMedia != null) { if (supportedMedia != null) {
...@@ -224,8 +224,7 @@ public class SdpInfo { ...@@ -224,8 +224,7 @@ public class SdpInfo {
+ encoding + "/" + sampleRate + "/" + channels); + encoding + "/" + sampleRate + "/" + channels);
} }
public MediaInfo findBestMediaInfo(Vector otherSupportedMedia, public MediaInfo findBestMediaInfo(Vector otherSupportedMedia, MediaInfo otherMediaPreference) throws IOException {
MediaInfo otherMediaPreference) throws IOException {
MediaInfo best = null; MediaInfo best = null;
...@@ -239,7 +238,7 @@ public class SdpInfo { ...@@ -239,7 +238,7 @@ public class SdpInfo {
if (otherMediaPreference != null) { if (otherMediaPreference != null) {
if (m.getSampleRate() > otherMediaPreference.getSampleRate() || if (m.getSampleRate() > otherMediaPreference.getSampleRate() ||
m.getChannels() > otherMediaPreference.getChannels()) { m.getChannels() > otherMediaPreference.getChannels()) {
continue; continue;
} }
} }
...@@ -257,7 +256,7 @@ public class SdpInfo { ...@@ -257,7 +256,7 @@ public class SdpInfo {
} }
private boolean isBetter(MediaInfo m1, MediaInfo m2) { private boolean isBetter(MediaInfo m1, MediaInfo m2) {
if (m1.getSampleRate() > m2.getSampleRate() && if (m1.getSampleRate() > m2.getSampleRate() &&
m1.getChannels() >= m2.getChannels()) { m1.getChannels() >= m2.getChannels()) {
return true; return true;
......
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
* *
* This file is part of jVoiceBridge. * This file is part of jVoiceBridge.
* *
* jVoiceBridge is free software: you can redistribute it and/or modify * jVoiceBridge is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation and distributed hereunder * published by the Free Software Foundation and distributed hereunder
* to you. * to you.
* *
* jVoiceBridge is distributed in the hope that it will be useful, * jVoiceBridge is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
...@@ -17,8 +17,8 @@ ...@@ -17,8 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* Sun designates this particular file as subject to the "Classpath" * Sun designates this particular file as subject to the "Classpath"
* exception as provided by Sun in the License file that accompanied this * exception as provided by Sun in the License file that accompanied this
* code. * code.
*/ */
package com.sun.voip; package com.sun.voip;
...@@ -74,7 +74,7 @@ public class SdpManager { ...@@ -74,7 +74,7 @@ public class SdpManager {
SdpManager.supportedMedia = supportedMedia; SdpManager.supportedMedia = supportedMedia;
} }
public void setPreferredMedia(int encoding, int sampleRate, int channels) public void setPreferredMedia(int encoding, int sampleRate, int channels)
throws ParseException { throws ParseException {
if (sampleRate == 8000 && channels == 1) { if (sampleRate == 8000 && channels == 1) {
...@@ -95,7 +95,7 @@ public class SdpManager { ...@@ -95,7 +95,7 @@ public class SdpManager {
return localMediaPreference; return localMediaPreference;
} }
public void setTransmitMediaInfo(int encoding, int sampleRate, public void setTransmitMediaInfo(int encoding, int sampleRate,
int channels) throws ParseException { int channels) throws ParseException {
transmitMediaInfo = findMediaInfo(encoding, sampleRate, channels); transmitMediaInfo = findMediaInfo(encoding, sampleRate, channels);
...@@ -124,16 +124,13 @@ public class SdpManager { ...@@ -124,16 +124,13 @@ public class SdpManager {
for (int i = 0; i < supportedMedia.size(); i++) { for (int i = 0; i < supportedMedia.size(); i++) {
MediaInfo mediaInfo = (MediaInfo) supportedMedia.elementAt(i); MediaInfo mediaInfo = (MediaInfo) supportedMedia.elementAt(i);
if (mediaInfo.getSampleRate() > maxSampleRate || if (mediaInfo.getSampleRate() > maxSampleRate || mediaInfo.getChannels() > maxChannels) {
mediaInfo.getChannels() > maxChannels) { continue;
continue;
} }
if (useTelephoneEvent == false && if (useTelephoneEvent == false && mediaInfo.isTelephoneEventPayload())
mediaInfo.isTelephoneEventPayload()) { {
continue;
continue;
} }
if (n > 0) { if (n > 0) {
...@@ -153,14 +150,13 @@ public class SdpManager { ...@@ -153,14 +150,13 @@ public class SdpManager {
private String getRtpmaps() { private String getRtpmaps() {
String rtpmaps = ""; String rtpmaps = "";
for (int i = 0; i < supportedMedia.size(); i++) { for (int i = 0; i < supportedMedia.size(); i++)
MediaInfo mediaInfo = (MediaInfo) {
supportedMedia.elementAt(i); MediaInfo mediaInfo = (MediaInfo) supportedMedia.elementAt(i);
if (mediaInfo.getSampleRate() > maxSampleRate ||
mediaInfo.getChannels() > maxChannels) {
continue; if (mediaInfo.getSampleRate() > maxSampleRate || mediaInfo.getChannels() > maxChannels)
{
continue;
} }
rtpmaps += generateRtpmap(mediaInfo) + "\r\n"; rtpmaps += generateRtpmap(mediaInfo) + "\r\n";
...@@ -181,7 +177,7 @@ public class SdpManager { ...@@ -181,7 +177,7 @@ public class SdpManager {
*/ */
private String generateRtpmap(MediaInfo mediaInfo) { private String generateRtpmap(MediaInfo mediaInfo) {
if (mediaInfo.isTelephoneEventPayload()) { if (mediaInfo.isTelephoneEventPayload()) {
// if (useTelephoneEvent == false) { // if (useTelephoneEvent == false) {
// return ""; // return "";
// } // }
...@@ -189,7 +185,7 @@ public class SdpManager { ...@@ -189,7 +185,7 @@ public class SdpManager {
+ " telephone-event/8000"; + " telephone-event/8000";
} }
return "a=rtpmap:" + mediaInfo.getPayload() + " " return "a=rtpmap:" + mediaInfo.getPayload() + " "
+ mediaInfo.getEncodingString() + "/" + mediaInfo.getEncodingString() + "/"
+ mediaInfo.getSampleRate() + "/" + mediaInfo.getSampleRate() + "/"
+ mediaInfo.getChannels(); + mediaInfo.getChannels();
...@@ -198,7 +194,7 @@ public class SdpManager { ...@@ -198,7 +194,7 @@ public class SdpManager {
/* /*
* Find the MediaInfo for a specified payload * Find the MediaInfo for a specified payload
*/ */
public static MediaInfo findMediaInfo(byte payload) public static MediaInfo findMediaInfo(byte payload)
throws ParseException { throws ParseException {
for (int i = 0; i < supportedMedia.size(); i++) { for (int i = 0; i < supportedMedia.size(); i++) {
...@@ -235,8 +231,8 @@ public class SdpManager { ...@@ -235,8 +231,8 @@ public class SdpManager {
} }
} }
throw new ParseException("Unsupported media " + throw new ParseException("Unsupported media " +
"encoding " + encoding + " sample rate " + sampleRate "encoding " + encoding + " sample rate " + sampleRate
+ " channels " + channels, 0); + " channels " + channels, 0);
} }
...@@ -246,7 +242,7 @@ public class SdpManager { ...@@ -246,7 +242,7 @@ public class SdpManager {
+ "o=" + name + " 1 1 IN IP4 " + "o=" + name + " 1 1 IN IP4 "
+ isa.getAddress().getHostAddress() + "\r\n" + isa.getAddress().getHostAddress() + "\r\n"
+ "s=SIP Call\r\n" + "s=SIP Call\r\n"
+ "c=IN IP4 " + "c=IN IP4 "
+ isa.getAddress().getHostAddress() + "\r\n" + isa.getAddress().getHostAddress() + "\r\n"
+ "t=0 0 \r\n" + "t=0 0 \r\n"
+ "m=audio " + isa.getPort() + "m=audio " + isa.getPort()
...@@ -255,112 +251,105 @@ public class SdpManager { ...@@ -255,112 +251,105 @@ public class SdpManager {
+ getRtpmaps(); + getRtpmaps();
if (localMediaPreference != null) { if (localMediaPreference != null) {
sdp += "a=PreferredPayload:" sdp += "a=PreferredPayload:"
+ localMediaPreference.getPayload() + "\r\n"; + localMediaPreference.getPayload() + "\r\n";
} }
if (transmitMediaInfo != null) { if (transmitMediaInfo != null) {
sdp += "a=transmitPayload:" sdp += "a=transmitPayload:"
+ transmitMediaInfo.getPayload() + "\r\n"; + transmitMediaInfo.getPayload() + "\r\n";
} }
return sdp; return sdp;
} }
public String generateSdp(String name, InetSocketAddress isa, public String generateSdp(String name, InetSocketAddress isa, SdpInfo remoteSdpInfo) throws IOException
SdpInfo remoteSdpInfo) throws IOException { {
MediaInfo mediaInfo = null;
MediaInfo mediaInfo = null; if (localMediaPreference != null)
{
if (localMediaPreference != null) { if (remoteSdpInfo.isSupported(localMediaPreference)) {
if (remoteSdpInfo.isSupported(localMediaPreference)) { mediaInfo = localMediaPreference;
mediaInfo = localMediaPreference; Logger.println("Using local media preference: " + mediaInfo);
}
if (Logger.logLevel >= Logger.LOG_INFO) {
Logger.println("Using local media preference: " + mediaInfo);
} }
}
} /*
* Try remote media preference
/* */
* Try remote media preference if (remoteSdpInfo.preferredMediaSpecified())
*/ {
if (mediaInfo == null && remoteSdpInfo.preferredMediaSpecified()) { MediaInfo remoteMediaPreference = remoteSdpInfo.getMediaInfo();
MediaInfo remoteMediaPreference = remoteSdpInfo.getMediaInfo();
if (remoteMediaPreference.getSampleRate() <= maxSampleRate &&
if (remoteMediaPreference.getSampleRate() <= maxSampleRate && remoteMediaPreference.getChannels() <= maxChannels) {
remoteMediaPreference.getChannels() <= maxChannels) {
/*
/* * See if remote media preference is supported
* See if remote media preference is supported */
*/ try {
try { mediaInfo = findMediaInfo(remoteMediaPreference.getPayload());
mediaInfo = Logger.println("Using remote media preference: " + mediaInfo);
findMediaInfo(remoteMediaPreference.getPayload()); } catch (ParseException e) {
}
Logger.println("Using remote media preference: " }
+ mediaInfo);
} catch (ParseException e) {
}
}
} }
if (mediaInfo == null) { if (mediaInfo == null) {
/* /*
* default to 8000/1 ulaw * default to 8000/1 ulaw
*/ */
mediaInfo = remoteSdpInfo.findBestMediaInfo(supportedMedia, mediaInfo = remoteSdpInfo.findBestMediaInfo(supportedMedia, localMediaPreference);
localMediaPreference);
Logger.println("Using best media " + mediaInfo); Logger.println("Using best media " + mediaInfo);
} }
remoteSdpInfo.setMediaInfo(mediaInfo); remoteSdpInfo.setMediaInfo(mediaInfo);
String payloads = "13 " + mediaInfo.getPayload(); String payloads = "13 " + mediaInfo.getPayload();
byte telephoneEventPayload = remoteSdpInfo.getTelephoneEventPayload(); byte telephoneEventPayload = remoteSdpInfo.getTelephoneEventPayload();
String telephoneEvent = ""; String telephoneEvent = "";
if (useTelephoneEvent == true && telephoneEventPayload != 0) { if (useTelephoneEvent == true && telephoneEventPayload != 0) {
try { try {
MediaInfo m = findMediaInfo(telephoneEventPayload); MediaInfo m = findMediaInfo(telephoneEventPayload);
payloads += " " + telephoneEventPayload; payloads += " " + telephoneEventPayload;
telephoneEvent += generateRtpmap(m) + "\r\n"; telephoneEvent += generateRtpmap(m) + "\r\n";
} catch (ParseException e) { } catch (ParseException e) {
Logger.println("Failed to add rtpmap for telephone event " Logger.println("Failed to add rtpmap for telephone event " + telephoneEventPayload);
+ telephoneEventPayload); }
} }
}
String transmitMap = ""; String transmitMap = "";
if (transmitMediaInfo != null) { if (transmitMediaInfo != null) {
transmitMap = generateRtpmap(transmitMediaInfo) + "\r\n"; transmitMap = generateRtpmap(transmitMediaInfo) + "\r\n";
} }
String sdp = String sdp =
"v=0\r\n" "v=0\r\n"
+ "o=" + name + " 1 1 IN IP4 " + "o=" + name + " 1 1 IN IP4 "
+ isa.getAddress().getHostAddress() + "\r\n" + isa.getAddress().getHostAddress() + "\r\n"
+ "s=SIP Call\r\n" + "s=SIP Call\r\n"
+ "c=IN IP4 " + "c=IN IP4 "
+ isa.getAddress().getHostAddress() + "\r\n" + isa.getAddress().getHostAddress() + "\r\n"
+ "t=0 0 \r\n" + "t=0 0 \r\n"
+ "m=audio " + isa.getPort() + "m=audio " + isa.getPort()
+ " RTP/AVP " + payloads + "\r\n" + " RTP/AVP " + payloads + "\r\n"
+ "a=rtpmap:13 CN/8000" + "\r\n" + "a=rtpmap:13 CN/8000" + "\r\n"
+ generateRtpmap(mediaInfo) + "\r\n" + generateRtpmap(mediaInfo) + "\r\n"
+ transmitMap + transmitMap
+ telephoneEvent; + telephoneEvent;
if (transmitMediaInfo != null) { if (transmitMediaInfo != null) {
sdp += "a=transmitPayload:" sdp += "a=transmitPayload:"
+ transmitMediaInfo.getPayload() + "\r\n"; + transmitMediaInfo.getPayload() + "\r\n";
} }
return sdp; return sdp;
} }
} }
...@@ -172,7 +172,7 @@ public class SdpParser { ...@@ -172,7 +172,7 @@ public class SdpParser {
+ payloads[i], 0); + payloads[i], 0);
} }
if (payload != 0 && payload < 96 || payload > 127) { if (payload != 0 && (payload < 96 || payload > 127)) {
/* /*
* Not one we can deal with * Not one we can deal with
*/ */
......
...@@ -323,10 +323,9 @@ public abstract class CallHandler extends Thread { ...@@ -323,10 +323,9 @@ public abstract class CallHandler extends Thread {
* Send indication when a dtmf key is pressed * Send indication when a dtmf key is pressed
*/ */
public void dtmfKeys(String dtmfKeys) { public void dtmfKeys(String dtmfKeys) {
if (Logger.logLevel >= Logger.LOG_MOREINFO) { //if (Logger.logLevel >= Logger.LOG_MOREINFO) {
Logger.println(cp + " got dtmf keys " + dtmfKeys + " " Logger.println(cp + " got dtmf keys " + dtmfKeys + " " + cp.dtmfDetection());
+ cp.dtmfDetection()); //}
}
if (isCallEstablished()) { if (isCallEstablished()) {
if (cp.dtmfDetection()) { if (cp.dtmfDetection()) {
......
...@@ -97,46 +97,49 @@ public class IncomingCallHandler extends CallHandler ...@@ -97,46 +97,49 @@ public class IncomingCallHandler extends CallHandler
addCallEventListener(this); addCallEventListener(this);
if (cp.getConferenceId() == null || cp.getConferenceId().length() == 0) if (directConferencing)
{ {
if (directConferencing) if (cp.getConferenceId() == null || cp.getConferenceId().length() == 0)
{ {
System.out.println("Don't have conf, using default...."); System.out.println("Don't have conf, using default....");
cp.setConferenceId(defaultIncomingConferenceId); // wait in lobby cp.setConferenceId(defaultIncomingConferenceId); // wait in lobby
} else { } else {
System.out.println("Incoming SIP, call " + cp); Logger.println("Have conf " + cp.getConferenceId());
haveIncomingConferenceId = true; // goto your conference
}
if (RayoComponent.self.routeIncomingSIP(cp)) start();
{
haveIncomingConferenceId = true;
} else { } else {
// conf bridge
if (Config.getInstance().getConferenceExten().equals(cp.getToPhoneNumber())) System.out.println("Incoming SIP, call " + cp);
{
incomingConferenceHandler = new IncomingConferenceHandler(this, cp.getToPhoneNumber());
} else if (Config.getInstance().getConferenceByPhone(cp.getToPhoneNumber()) != null) { if (RayoComponent.self.routeIncomingSIP(cp))
{
haveIncomingConferenceId = true;
start();
incomingConferenceHandler = new IncomingConferenceHandler(this, cp.getToPhoneNumber()); } else {
// conf bridge
} else { if (Config.getInstance().getConferenceExten().equals(cp.getToPhoneNumber()))
cancelRequest(cp.getToPhoneNumber() + " is not a valid endpoint"); // reject call {
} incomingConferenceHandler = new IncomingConferenceHandler(this, cp.getToPhoneNumber());
} start();
} } else if (Config.getInstance().getConferenceByPhone(cp.getToPhoneNumber()) != null) {
} else { incomingConferenceHandler = new IncomingConferenceHandler(this, cp.getToPhoneNumber());
start();
Logger.println("Have conf " + cp.getConferenceId()); } else {
haveIncomingConferenceId = true; // goto your conference cancelRequest(cp.getToPhoneNumber() + " is not a valid endpoint"); // reject call
} }
}
start(); }
} }
public static void setDirectConferencing(boolean directConferencing) { public static void setDirectConferencing(boolean directConferencing) {
...@@ -350,6 +353,9 @@ public class IncomingCallHandler extends CallHandler ...@@ -350,6 +353,9 @@ public class IncomingCallHandler extends CallHandler
public void callEventNotification(CallEvent callEvent) { public void callEventNotification(CallEvent callEvent) {
Logger.println("IncomingCallHandler " + callEvent.toString());
if (callEvent.equals(callEvent.STATE_CHANGED) && if (callEvent.equals(callEvent.STATE_CHANGED) &&
callEvent.getCallState().equals(CallState.ESTABLISHED)) { callEvent.getCallState().equals(CallState.ESTABLISHED)) {
...@@ -461,6 +467,8 @@ public class IncomingCallHandler extends CallHandler ...@@ -461,6 +467,8 @@ public class IncomingCallHandler extends CallHandler
public ConferenceManager transferCall(String conferenceId) public ConferenceManager transferCall(String conferenceId)
throws IOException { throws IOException {
System.out.println("transferCall " + conferenceId);
ConferenceManager conferenceManager = transferCall(this, conferenceId); ConferenceManager conferenceManager = transferCall(this, conferenceId);
String s = getNumberOfCallsAsTreatment(conferenceManager.getNumberOfMembers()); String s = getNumberOfCallsAsTreatment(conferenceManager.getNumberOfMembers());
......
...@@ -80,10 +80,12 @@ public class IncomingConferenceHandler extends Thread ...@@ -80,10 +80,12 @@ public class IncomingConferenceHandler extends Thread
* Constructor. * Constructor.
*/ */
public IncomingConferenceHandler(IncomingCallHandler incomingCallHandler, String phoneNo) { public IncomingConferenceHandler(IncomingCallHandler incomingCallHandler, String phoneNo) {
this.incomingCallHandler = incomingCallHandler; this.incomingCallHandler = incomingCallHandler;
this.phoneNo = phoneNo; this.phoneNo = phoneNo;
incomingCallHandler.addCallEventListener(this); incomingCallHandler.addCallEventListener(this);
Logger.println("IncomingConferenceHandler: " + phoneNo);
} }
private String lastMessagePlayed; private String lastMessagePlayed;
...@@ -121,9 +123,9 @@ public class IncomingConferenceHandler extends Thread ...@@ -121,9 +123,9 @@ public class IncomingConferenceHandler extends Thread
* Called when status for an incoming call changes. * Called when status for an incoming call changes.
*/ */
public void callEventNotification(CallEvent callEvent) { public void callEventNotification(CallEvent callEvent) {
if (Logger.logLevel >= Logger.LOG_INFO) { //if (Logger.logLevel >= Logger.LOG_INFO) {
Logger.println(callEvent.toString()); Logger.println("IncomingConferenceHandler " + callEvent.toString());
} //}
if (callEvent.equals(CallEvent.STATE_CHANGED) && if (callEvent.equals(CallEvent.STATE_CHANGED) &&
callEvent.getCallState().equals(CallState.ESTABLISHED)) { callEvent.getCallState().equals(CallState.ESTABLISHED)) {
...@@ -132,18 +134,19 @@ public class IncomingConferenceHandler extends Thread ...@@ -132,18 +134,19 @@ public class IncomingConferenceHandler extends Thread
* New incoming call * New incoming call
*/ */
if (callEvent.getInfo() != null) { if (callEvent.getInfo() != null) {
Logger.println("IncomingConferenceHandler: " Logger.println("IncomingConferenceHandler: " + callEvent.getInfo());
+ callEvent.getInfo());
} }
if (Config.getInstance().getMeetingCode(phoneNo) != null) if (Config.getInstance().getMeetingCode(phoneNo) != null)
{ {
meetingCode = Config.getInstance().getMeetingCode(phoneNo); meetingCode = Config.getInstance().getMeetingCode(phoneNo);
Logger.println("IncomingConferenceHandler: meeting code " + meetingCode);
if (Config.getInstance().getPassCode(meetingCode, phoneNo) == null) if (Config.getInstance().getPassCode(meetingCode, phoneNo) == null)
{ {
try { try {
incomingCallHandler.transferCall(Config.getInstance().getMeetingCode(phoneNo)); incomingCallHandler.transferCall(meetingCode);
state = IN_MEETING; state = IN_MEETING;
} catch (IOException e) { } catch (IOException e) {
......
...@@ -71,6 +71,7 @@ import java.awt.Point; ...@@ -71,6 +71,7 @@ import java.awt.Point;
import org.ifsoft.*; import org.ifsoft.*;
import org.ifsoft.rtp.*; import org.ifsoft.rtp.*;
import org.jitsi.impl.neomedia.codec.audio.opus.Opus;
/** /**
* Receive RTP data for this ConferenceMember, add it to the mix * Receive RTP data for this ConferenceMember, add it to the mix
...@@ -116,6 +117,15 @@ public class MemberReceiver implements MixDataSource, TreatmentDoneListener { ...@@ -116,6 +117,15 @@ public class MemberReceiver implements MixDataSource, TreatmentDoneListener {
private SpeexDecoder speexDecoder; private SpeexDecoder speexDecoder;
private long opusDecoder = 0;
private final int opusSampleRate = 48000;
private final int frameSizeInMillis = 20;
private final int outputFrameSize = 2;
private final int opusChannels = 2;
private int frameSizeInSamplesPerChannel = (opusSampleRate * frameSizeInMillis) / 1000;
private int frameSizeInBytes = outputFrameSize * opusChannels * frameSizeInSamplesPerChannel;
private int dropPackets; private int dropPackets;
private boolean done = false; private boolean done = false;
...@@ -448,11 +458,28 @@ public class MemberReceiver implements MixDataSource, TreatmentDoneListener { ...@@ -448,11 +458,28 @@ public class MemberReceiver implements MixDataSource, TreatmentDoneListener {
Logger.println("Call " + cp + " created SpeexDecoder"); Logger.println("Call " + cp + " created SpeexDecoder");
} catch (SpeexException e) { } catch (SpeexException e) {
Logger.println("Call " + cp + e.getMessage()); Logger.println("Call " + cp + e.getMessage());
callHandler.cancelRequest(e.getMessage()); callHandler.cancelRequest(e.getMessage());
return; return;
} }
} else if (myMediaInfo.getEncoding() == RtpPacket.PCM_ENCODING) {
try {
opusDecoder = Opus.decoder_create(opusSampleRate, opusChannels);
if (opusDecoder == 0)
{
Logger.println("Call " + cp + " OPUS decoder creation error ");
callHandler.cancelRequest("OPUS decoder creation error ");
return;
}
} catch (Exception e) {
e.printStackTrace();
} }
}
if (cp.getJoinConfirmationTimeout() == 0) { if (cp.getJoinConfirmationTimeout() == 0) {
joinConfirmationReceived = true; joinConfirmationReceived = true;
readyToReceiveData = true; readyToReceiveData = true;
...@@ -1170,9 +1197,7 @@ public class MemberReceiver implements MixDataSource, TreatmentDoneListener { ...@@ -1170,9 +1197,7 @@ public class MemberReceiver implements MixDataSource, TreatmentDoneListener {
callHandler.getMember().adjustVolume(data, inputVolume); callHandler.getMember().adjustVolume(data, inputVolume);
} }
//Logger.println("Call " + cp //Logger.println("Call " + cp + " receiveMedia length " + length + " decoded int length " + data.length);
// + " receiveMedia length " + length + " decoded int length "
// + data.length);
int numberOfSamples = data.length; int numberOfSamples = data.length;
...@@ -1246,60 +1271,77 @@ public class MemberReceiver implements MixDataSource, TreatmentDoneListener { ...@@ -1246,60 +1271,77 @@ public class MemberReceiver implements MixDataSource, TreatmentDoneListener {
return numberOfSamples; return numberOfSamples;
} }
private int[] decodeToLinear(byte[] receivedData, int length) private int[] decodeToLinear(byte[] receivedData, int length) throws SpeexException
throws SpeexException { {
/*
* receivedData has the 12 byte RTP header.
*/
/* int[] data = new int[myMediaInfo.getSamplesPerPacket()];
* receivedData has the 12 byte RTP header.
*/
int[] data = new int[myMediaInfo.getSamplesPerPacket()];
long start = 0; long start = 0;
if (myMediaInfo.getEncoding() == RtpPacket.PCMU_ENCODING) { if (myMediaInfo.getEncoding() == RtpPacket.PCMU_ENCODING)
if (traceCall || Logger.logLevel == -1) { {
start = System.nanoTime(); if (traceCall || Logger.logLevel == -1)
} {
start = System.nanoTime();
}
/* /*
* Convert ulaw data to linear. length is the ulaw * Convert ulaw data to linear. length is the ulaw
* data length plus the RTP header length. * data length plus the RTP header length.
* *
* If the incoming packet is shorter, than we expect, * If the incoming packet is shorter, than we expect,
* the rest of <data> will be filled with 0 * which is PCM_SILENCE. * the rest of <data> will be filled with 0 * which is PCM_SILENCE.
*/ */
AudioConversion.ulawToLinear(receivedData, RtpPacket.HEADER_SIZE,
length - RtpPacket.HEADER_SIZE, data);
if (length < 172 && Logger.logLevel >= Logger.LOG_DETAIL) { AudioConversion.ulawToLinear(receivedData, RtpPacket.HEADER_SIZE, length - RtpPacket.HEADER_SIZE, data);
Logger.println("Call " + cp + " received short packet "
+ length); if (length < 172 && Logger.logLevel >= Logger.LOG_DETAIL) {
} Logger.println("Call " + cp + " received short packet " + length);
}
if (traceCall || Logger.logLevel == -1) { if (traceCall || Logger.logLevel == -1) {
Logger.println("Call " + cp + " ulawToLinear time " Logger.println("Call " + cp + " ulawToLinear time " + ((System.nanoTime() - start) / 1000000000.) + " seconds");
+ ((System.nanoTime() - start) / 1000000000.)
+ " seconds");
} }
} else if (myMediaInfo.getEncoding() == RtpPacket.PCM_ENCODING) {
int inputOffset = RtpPacket.HEADER_SIZE;
int inputLength = length - RtpPacket.HEADER_SIZE;
int frameSizeInSamplesPerChannel = Opus.decoder_get_nb_samples(opusDecoder, receivedData, inputOffset, inputLength);
if (frameSizeInSamplesPerChannel > 1)
{
int frameSizeInBytes = outputFrameSize * opusChannels * frameSizeInSamplesPerChannel;
byte[] output = new byte[frameSizeInBytes];
frameSizeInSamplesPerChannel = Opus.decode(opusDecoder, receivedData, inputOffset, inputLength, output, 0, frameSizeInSamplesPerChannel, 0);
data = AudioConversion.bytesToLittleEndianInts(output);
}
} else if (myMediaInfo.getEncoding() == RtpPacket.SPEEX_ENCODING) { } else if (myMediaInfo.getEncoding() == RtpPacket.SPEEX_ENCODING) {
if (traceCall || Logger.logLevel == -1) { if (traceCall || Logger.logLevel == -1) {
start = System.nanoTime(); start = System.nanoTime();
} }
data = speexDecoder.decodeToIntArray(receivedData, data = speexDecoder.decodeToIntArray(receivedData, RtpPacket.HEADER_SIZE, length - RtpPacket.HEADER_SIZE);
RtpPacket.HEADER_SIZE, length - RtpPacket.HEADER_SIZE);
if (traceCall || Logger.logLevel == -1) { if (traceCall || Logger.logLevel == -1)
Logger.println("Call " + cp + " speex decode time " {
+ ((System.nanoTime() - start) / 1000000000.) Logger.println("Call " + cp + " speex decode time " + ((System.nanoTime() - start) / 1000000000.) + " seconds");
+ " seconds"); }
}
} else {
AudioConversion.bytesToInts(receivedData, RtpPacket.HEADER_SIZE,
length - RtpPacket.HEADER_SIZE, data);
}
return data; } else {
AudioConversion.bytesToInts(receivedData, RtpPacket.HEADER_SIZE,
length - RtpPacket.HEADER_SIZE, data);
}
return data;
} }
public synchronized void handleVP8Video(RTPPacket videoPacket) public synchronized void handleVP8Video(RTPPacket videoPacket)
...@@ -1827,56 +1869,62 @@ public class MemberReceiver implements MixDataSource, TreatmentDoneListener { ...@@ -1827,56 +1869,62 @@ public class MemberReceiver implements MixDataSource, TreatmentDoneListener {
public void end() { public void end() {
if (done) { if (done) {
return; return;
} }
done = true; done = true;
if (speechDetector != null && speechDetector.isSpeaking()) { if (speechDetector != null && speechDetector.isSpeaking()) {
callHandler.speakingChanged(false); callHandler.speakingChanged(false);
} }
synchronized (recordingLock) { synchronized (recordingLock) {
if (recorder != null) { if (recorder != null) {
recorder.done(); recorder.done();
recorder = null; recorder = null;
} }
} }
readyToReceiveData = false; readyToReceiveData = false;
if (datagramChannelRegistered && datagramChannel != null) { if (datagramChannelRegistered && datagramChannel != null) {
try { try {
datagramChannel.close(); datagramChannel.close();
if (Logger.logLevel >= Logger.LOG_DETAIL) { if (Logger.logLevel >= Logger.LOG_DETAIL) {
Logger.println("Call " + cp + " closed datagramChannel " Logger.println("Call " + cp + " closed datagramChannel "
+ datagramChannel); + datagramChannel);
}
datagramChannel = null;
} catch (IOException e) {
Logger.println("Call " + cp
+ " exception closing datagram channel " + e.getMessage());
}
} else {
Logger.println("Call " + cp + " not closing datagramChannel");
} }
datagramChannel = null;
} catch (IOException e) {
Logger.println("Call " + cp
+ " exception closing datagram channel " + e.getMessage());
}
} else {
Logger.println("Call " + cp + " not closing datagramChannel");
}
if (joinConfirmationReceived == true) { if (joinConfirmationReceived == true) {
String leaveTreatment; String leaveTreatment;
/** /**
* Play audio treatment to all conference members indicating that * Play audio treatment to all conference members indicating that
* a member has left the conference. * a member has left the conference.
*/ */
if ((leaveTreatment = cp.getConferenceLeaveTreatment()) != null) { if ((leaveTreatment = cp.getConferenceLeaveTreatment()) != null) {
try { try {
conferenceManager.addTreatment(leaveTreatment); conferenceManager.addTreatment(leaveTreatment);
} catch (IOException e) { } catch (IOException e) {
Logger.println("Call " + cp Logger.println("Call " + cp
+ " failed to start leave treatment " + leaveTreatment); + " failed to start leave treatment " + leaveTreatment);
}
}
} }
}
} if (opusDecoder != 0)
{
Opus.decoder_destroy(opusDecoder);
opusDecoder = 0;
}
} }
public void printStatistics() { public void printStatistics() {
......
...@@ -55,6 +55,8 @@ import org.xmpp.jnodes.RelayChannel; ...@@ -55,6 +55,8 @@ import org.xmpp.jnodes.RelayChannel;
import org.ifsoft.*; import org.ifsoft.*;
import org.ifsoft.rtp.*; import org.ifsoft.rtp.*;
import org.jitsi.impl.neomedia.codec.audio.opus.Opus;
/** /**
* Send RTP data to this ConferenceMember, * Send RTP data to this ConferenceMember,
*/ */
...@@ -73,6 +75,14 @@ public class MemberSender { ...@@ -73,6 +75,14 @@ public class MemberSender {
private RtpSenderPacket senderPacket; private RtpSenderPacket senderPacket;
private SpeexEncoder speexEncoder; private SpeexEncoder speexEncoder;
private long opusEncoder = 0;
private final int opusSampleRate = 48000;
private final int frameSizeInMillis = 20;
private final int outputFrameSize = 2;
private final int opusChannels = 2;
private int frameSizeInSamplesPerChannel = (opusSampleRate * frameSizeInMillis) / 1000;
private int frameSizeInBytes = outputFrameSize * opusChannels * frameSizeInSamplesPerChannel;
private InetSocketAddress memberAddress; private InetSocketAddress memberAddress;
private boolean done = false; private boolean done = false;
...@@ -265,6 +275,23 @@ public class MemberSender { ...@@ -265,6 +275,23 @@ public class MemberSender {
} }
} }
if (myMediaInfo.getEncoding() == RtpPacket.PCM_ENCODING) {
try {
opusEncoder = Opus.encoder_create(opusSampleRate, opusChannels);
if (opusEncoder == 0)
{
Logger.println("Call " + cp + " OPUS encoder creation error ");
callHandler.cancelRequest("OPUS encoder creation error ");
return;
}
} catch (Exception e) {
e.printStackTrace();
}
}
initializationDone = true; initializationDone = true;
...@@ -411,6 +438,8 @@ public class MemberSender { ...@@ -411,6 +438,8 @@ public class MemberSender {
//Logger.println("Call " + cp + " Sending data..."); //Logger.println("Call " + cp + " Sending data...");
byte[] opusBytes = null;
if (myMediaInfo.getEncoding() == RtpPacket.PCMU_ENCODING) { if (myMediaInfo.getEncoding() == RtpPacket.PCMU_ENCODING) {
/* /*
* Convert to ulaw * Convert to ulaw
...@@ -433,13 +462,27 @@ public class MemberSender { ...@@ -433,13 +462,27 @@ public class MemberSender {
Logger.println("Call " + this + ": " + e.getMessage()); Logger.println("Call " + this + ": " + e.getMessage());
return false; return false;
} }
} else if (myMediaInfo.getEncoding() == RtpPacket.PCM_ENCODING) {
byte[] input = AudioConversion.littleEndianIntsToBytes(dataToSend);
byte[] output = new byte[Opus.MAX_PACKET];
int outLength = Opus.encode(opusEncoder, input, 0, frameSizeInSamplesPerChannel, output, 0, output.length);
opusBytes = new byte[outLength];
System.arraycopy(output, 0, opusBytes, 0, outLength);
System.arraycopy(output, 0, rtpData, RtpPacket.HEADER_SIZE, outLength);
senderPacket.setLength(outLength + RtpPacket.HEADER_SIZE);
//Logger.println("RtpPacket.PCM_ENCODING " + outLength);
} else { } else {
AudioConversion.intsToBytes(dataToSend, rtpData, RtpPacket.HEADER_SIZE); AudioConversion.intsToBytes(dataToSend, rtpData, RtpPacket.HEADER_SIZE);
} }
recordPacket(rtpData, senderPacket.getLength()); recordPacket(rtpData, senderPacket.getLength());
recordAudio(rtpData, RtpPacket.HEADER_SIZE, recordAudio(rtpData, RtpPacket.HEADER_SIZE, senderPacket.getLength() - RtpPacket.HEADER_SIZE);
senderPacket.getLength() - RtpPacket.HEADER_SIZE);
/* /*
* Encrypt data if required * Encrypt data if required
...@@ -469,14 +512,12 @@ public class MemberSender { ...@@ -469,14 +512,12 @@ public class MemberSender {
try { try {
senderPacket.setSocketAddress(memberAddress); senderPacket.setSocketAddress(memberAddress);
datagramChannel.send( datagramChannel.send(ByteBuffer.wrap(senderPacket.getData(), 0, senderPacket.getLength()), memberAddress);
ByteBuffer.wrap(senderPacket.getData(), 0,
senderPacket.getLength()), memberAddress);
if (Logger.logLevel >= Logger.LOG_MOREDETAIL) { if (Logger.logLevel >= Logger.LOG_MOREDETAIL) {
Logger.writeFile("Call " + cp + " back from sending data"); Logger.writeFile("Call " + cp + " back from sending data");
} }
} catch (IOException e) { } catch (Exception e) {
if (!done) { if (!done) {
Logger.error("Call " + cp + " sendData " + e.getMessage()); Logger.error("Call " + cp + " sendData " + e.getMessage());
e.printStackTrace(); e.printStackTrace();
...@@ -488,7 +529,8 @@ public class MemberSender { ...@@ -488,7 +529,8 @@ public class MemberSender {
} else { } else {
try { try {
getWebRTCParticipant().pushAudio(rtpData, dataToSend);
getWebRTCParticipant().pushAudio(senderPacket.getData(), opusBytes);
} catch (Exception e) { } catch (Exception e) {
...@@ -758,8 +800,7 @@ public class MemberSender { ...@@ -758,8 +800,7 @@ public class MemberSender {
senderPacket.setSocketAddress(memberAddress); senderPacket.setSocketAddress(memberAddress);
try { try {
datagramChannel.send( datagramChannel.send(ByteBuffer.wrap(senderPacket.getData()), memberAddress);
ByteBuffer.wrap(senderPacket.getData()), memberAddress);
} catch (IOException e) { } catch (IOException e) {
if (!done) { if (!done) {
Logger.println("Call " + cp + " sendComfortNoisePayload " Logger.println("Call " + cp + " sendComfortNoisePayload "
...@@ -854,16 +895,22 @@ public class MemberSender { ...@@ -854,16 +895,22 @@ public class MemberSender {
public void end() { public void end() {
if (done) { if (done) {
return; return;
} }
done = true; done = true;
synchronized (recordingLock) { synchronized (recordingLock) {
if (recorder != null) { if (recorder != null) {
recorder.done(); recorder.done();
recorder = null; recorder = null;
} }
} }
if (opusEncoder != 0)
{
Opus.encoder_destroy(opusEncoder);
opusEncoder = 0;
}
} }
public void printStatistics() { public void printStatistics() {
......
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
* *
* This file is part of jVoiceBridge. * This file is part of jVoiceBridge.
* *
* jVoiceBridge is free software: you can redistribute it and/or modify * jVoiceBridge is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation and distributed hereunder * published by the Free Software Foundation and distributed hereunder
* to you. * to you.
* *
* jVoiceBridge is distributed in the hope that it will be useful, * jVoiceBridge is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
...@@ -17,8 +17,8 @@ ...@@ -17,8 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* Sun designates this particular file as subject to the "Classpath" * Sun designates this particular file as subject to the "Classpath"
* exception as provided by Sun in the License file that accompanied this * exception as provided by Sun in the License file that accompanied this
* code. * code.
*/ */
package com.sun.voip.server; package com.sun.voip.server;
...@@ -46,7 +46,7 @@ public class MixManager { ...@@ -46,7 +46,7 @@ public class MixManager {
private SpatialAudio sa; private SpatialAudio sa;
public MixManager(ConferenceMember member, public MixManager(ConferenceMember member,
int conferenceSamplesPerPacket, int channels) { int conferenceSamplesPerPacket, int channels) {
this.member = member; this.member = member;
...@@ -66,7 +66,7 @@ public class MixManager { ...@@ -66,7 +66,7 @@ public class MixManager {
} }
sa.initialize(member.getConferenceManager().getId(), sa.initialize(member.getConferenceManager().getId(),
member.getCallParticipant().getCallId(), sampleRate, member.getCallParticipant().getCallId(), sampleRate,
channels, conferenceSamplesPerPacket / channels); channels, conferenceSamplesPerPacket / channels);
} }
...@@ -119,7 +119,7 @@ public class MixManager { ...@@ -119,7 +119,7 @@ public class MixManager {
mixDescriptors.add(mixDescriptor); mixDescriptors.add(mixDescriptor);
setUseFastMix(); setUseFastMix();
} }
public void addMix(MixDataSource mixDataSource, double attenuation) { public void addMix(MixDataSource mixDataSource, double attenuation) {
MixDescriptor mixDescriptor = findMixDescriptor(mixDataSource); MixDescriptor mixDescriptor = findMixDescriptor(mixDataSource);
...@@ -127,7 +127,7 @@ public class MixManager { ...@@ -127,7 +127,7 @@ public class MixManager {
if (mixDescriptor != null) { if (mixDescriptor != null) {
if (Logger.logLevel >= Logger.LOG_MOREINFO) { if (Logger.logLevel >= Logger.LOG_MOREINFO) {
Logger.println("Call " + member Logger.println("Call " + member
+ " Remove mix, volume 0 " + " mixDataSource " + " Remove mix, volume 0 " + " mixDataSource "
+ mixDataSource); + mixDataSource);
} }
removeMix(mixDescriptor); removeMix(mixDescriptor);
...@@ -147,7 +147,7 @@ public class MixManager { ...@@ -147,7 +147,7 @@ public class MixManager {
mixDescriptors.add(mixDescriptor); mixDescriptors.add(mixDescriptor);
if (Logger.logLevel >= Logger.LOG_MOREINFO) { if (Logger.logLevel >= Logger.LOG_MOREINFO) {
Logger.println("created new mix for " + mixDataSource Logger.println("created new mix for " + mixDataSource
+ " " + attenuation); + " " + attenuation);
} }
...@@ -158,7 +158,7 @@ public class MixManager { ...@@ -158,7 +158,7 @@ public class MixManager {
mixDescriptor.setAttenuation(attenuation); mixDescriptor.setAttenuation(attenuation);
setUseFastMix(); setUseFastMix();
} }
public void removeMix(MixDataSource mixDataSource) { public void removeMix(MixDataSource mixDataSource) {
MixDescriptor mixDescriptor = findMixDescriptor(mixDataSource); MixDescriptor mixDescriptor = findMixDescriptor(mixDataSource);
...@@ -227,7 +227,7 @@ public class MixManager { ...@@ -227,7 +227,7 @@ public class MixManager {
} }
return; return;
} }
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
MixDescriptor mixDescriptor = (MixDescriptor) MixDescriptor mixDescriptor = (MixDescriptor)
mixDescriptors.get(i); mixDescriptors.get(i);
...@@ -322,7 +322,7 @@ public class MixManager { ...@@ -322,7 +322,7 @@ public class MixManager {
return forcePrivateMix; return forcePrivateMix;
} }
public MixDescriptor setPrivateMix(MixDataSource mixDataSource, public MixDescriptor setPrivateMix(MixDataSource mixDataSource,
double[] spatialValues) { double[] spatialValues) {
MixDescriptor mixDescriptor; MixDescriptor mixDescriptor;
...@@ -334,7 +334,7 @@ public class MixManager { ...@@ -334,7 +334,7 @@ public class MixManager {
} }
if (mixDescriptor == null) { if (mixDescriptor == null) {
mixDescriptor = new MixDescriptor(mixDataSource, 1.0, mixDescriptor = new MixDescriptor(mixDataSource, 1.0,
spatialValues); spatialValues);
mixDescriptors.add(mixDescriptor); mixDescriptors.add(mixDescriptor);
...@@ -351,7 +351,7 @@ public class MixManager { ...@@ -351,7 +351,7 @@ public class MixManager {
} }
if (Logger.logLevel >= Logger.LOG_MOREINFO) { if (Logger.logLevel >= Logger.LOG_MOREINFO) {
Logger.println("MixManager: Setting private mix " Logger.println("MixManager: Setting private mix "
+ mixDescriptor); + mixDescriptor);
} }
...@@ -389,7 +389,7 @@ public class MixManager { ...@@ -389,7 +389,7 @@ public class MixManager {
outData = new int[conferenceSamplesPerPacket]; outData = new int[conferenceSamplesPerPacket];
//Logger.println("Call " + member + " MixManager mixing " //Logger.println("Call " + member + " MixManager mixing "
// + mixDescriptors.size()); // + mixDescriptors.size());
boolean needToSend = false; boolean needToSend = false;
...@@ -428,7 +428,7 @@ public class MixManager { ...@@ -428,7 +428,7 @@ public class MixManager {
spatialValues = sv; spatialValues = sv;
if (Logger.logLevel == -69) { if (Logger.logLevel == -69) {
Logger.println("Call " + member + " pm for " Logger.println("Call " + member + " pm for "
+ mixDataSource.toAbbreviatedString() + mixDataSource.toAbbreviatedString()
+ " s3 " + spatialValues[3]); + " s3 " + spatialValues[3]);
} }
...@@ -437,7 +437,7 @@ public class MixManager { ...@@ -437,7 +437,7 @@ public class MixManager {
/* /*
* Subtract the current contribution from the mix * Subtract the current contribution from the mix
*/ */
if (contribution != null && if (contribution != null &&
mixDataSource.contributionIsInCommonMix()) { mixDataSource.contributionIsInCommonMix()) {
WhisperGroup.mixData(contribution, outData, false); WhisperGroup.mixData(contribution, outData, false);
...@@ -453,7 +453,7 @@ public class MixManager { ...@@ -453,7 +453,7 @@ public class MixManager {
} }
contribution = sa.generateSpatialAudio( contribution = sa.generateSpatialAudio(
mixDataSource.getSourceId(), mixDataSource.getSourceId(),
mixDataSource.getPreviousContribution(), mixDataSource.getPreviousContribution(),
contribution, spatialValues); contribution, spatialValues);
} }
...@@ -484,8 +484,8 @@ public class MixManager { ...@@ -484,8 +484,8 @@ public class MixManager {
} }
/* /*
* We know there are two MixDescriptors and the first one is * We know there are two MixDescriptors and the first one is
* the conference Mix and the second one is for subtracting * the conference Mix and the second one is for subtracting
* out the member's own data. * out the member's own data.
*/ */
private int[] fastMix() { private int[] fastMix() {
...@@ -508,26 +508,28 @@ public class MixManager { ...@@ -508,26 +508,28 @@ public class MixManager {
memberMixDescriptor.getMixDataSource().getCurrentContribution(); memberMixDescriptor.getMixDataSource().getCurrentContribution();
if (memberContribution == null) { if (memberContribution == null) {
System.arraycopy(conferenceMixContribution, 0, outData, 0,
conferenceMixContribution.length); if (outData.length <= conferenceMixContribution.length)
System.arraycopy(conferenceMixContribution, 0, outData, 0, outData.length);
if (Logger.logLevel == -39) { else
System.arraycopy(conferenceMixContribution, 0, outData, 0, conferenceMixContribution.length);
if (Logger.logLevel == -39) {
checkData(outData, useFastMix); checkData(outData, useFastMix);
} }
AudioConversion.clip(outData); AudioConversion.clip(outData);
return outData; return outData;
} }
WhisperGroup.mixData(conferenceMixContribution, memberContribution, WhisperGroup.mixData(conferenceMixContribution, memberContribution, outData);
outData);
if (Logger.logLevel == -39) { if (Logger.logLevel == -39) {
checkData(outData, useFastMix); checkData(outData, useFastMix);
} }
AudioConversion.clip(outData); AudioConversion.clip(outData);
return outData; return outData;
} }
private void checkData(int[] data, boolean useFastMix) { private void checkData(int[] data, boolean useFastMix) {
...@@ -536,7 +538,7 @@ public class MixManager { ...@@ -536,7 +538,7 @@ public class MixManager {
Logger.println("Call " + member + " Non-zero data at " + i); Logger.println("Call " + member + " Non-zero data at " + i);
Logger.println("Call " + member Logger.println("Call " + member
+ " useFastMix " + useFastMix); + " useFastMix " + useFastMix);
Logger.println("Call " + member + " " Logger.println("Call " + member + " "
+ toAbbreviatedString()); + toAbbreviatedString());
if (mixDescriptors.size() != 2 && useFastMix == true) { if (mixDescriptors.size() != 2 && useFastMix == true) {
Logger.println("useFastMix should be false!!!"); Logger.println("useFastMix should be false!!!");
...@@ -559,7 +561,7 @@ public class MixManager { ...@@ -559,7 +561,7 @@ public class MixManager {
for (int i = 0; i < data.length; i++) { for (int i = 0; i < data.length; i++) {
data[i] = 0; // optimize when volume is 0 data[i] = 0; // optimize when volume is 0
} }
return; return;
} }
for (int i = 0; i < data.length; i++) { for (int i = 0; i < data.length; i++) {
...@@ -593,9 +595,9 @@ public class MixManager { ...@@ -593,9 +595,9 @@ public class MixManager {
s += " " + mixDescriptor.toAbbreviatedString(); s += " " + mixDescriptor.toAbbreviatedString();
if (member.getWhisperGroup() == if (member.getWhisperGroup() ==
mixDescriptor.getMixDataSource()) { mixDescriptor.getMixDataSource()) {
s += " + "; s += " + ";
} }
......
...@@ -74,12 +74,11 @@ public class SipIncomingCallAgent extends CallSetupAgent implements SipListener ...@@ -74,12 +74,11 @@ public class SipIncomingCallAgent extends CallSetupAgent implements SipListener
sipServerCallback = SipServer.getSipServerCallback(); sipServerCallback = SipServer.getSipServerCallback();
MediaInfo mixerMediaPreference = MediaInfo mixerMediaPreference = callHandler.getConferenceManager().getMediaInfo();
callHandler.getConferenceManager().getMediaInfo();
sipUtil = new SipUtil(mixerMediaPreference); sipUtil = new SipUtil(mixerMediaPreference);
handleInvite((RequestEvent)o); handleInvite((RequestEvent)o);
} }
/** /**
......
...@@ -87,8 +87,7 @@ public class SipTPCCallAgent extends CallSetupAgent implements SipListener { ...@@ -87,8 +87,7 @@ public class SipTPCCallAgent extends CallSetupAgent implements SipListener {
public SipTPCCallAgent(CallHandler callHandler) { public SipTPCCallAgent(CallHandler callHandler) {
super(callHandler); super(callHandler);
MediaInfo mixerMediaPreference = MediaInfo mixerMediaPreference = callHandler.getConferenceManager().getMediaInfo();
callHandler.getConferenceManager().getMediaInfo();
sipUtil = new SipUtil(mixerMediaPreference); sipUtil = new SipUtil(mixerMediaPreference);
} }
......
...@@ -71,28 +71,30 @@ public class SipUtil { ...@@ -71,28 +71,30 @@ public class SipUtil {
private SdpManager sdpManager; private SdpManager sdpManager;
public SipUtil() { public SipUtil() {
this(null); this(null);
} }
public SipUtil(MediaInfo mediaInfo) { public SipUtil(MediaInfo mediaInfo)
if (!initialized) { {
initialize(); if (!initialized) {
} initialize();
}
sdpManager = new SdpManager(); sdpManager = new SdpManager();
if (mediaInfo == null) { if (mediaInfo == null)
try { {
mediaInfo = sdpManager.findMediaInfo(RtpPacket.PCMU_ENCODING, try {
8000, 1); mediaInfo = sdpManager.findMediaInfo(RtpPacket.PCMU_ENCODING, 8000, 1);
} catch (ParseException e) {
Logger.println( Logger.println("SipUtil: Preference default media " + mediaInfo);
"SipUtil: Invalid media info, can't set preference"
+ e.getMessage()); } catch (ParseException e) {
} Logger.println("SipUtil: Invalid media info, can't set preference" + e.getMessage());
} }
}
sdpManager.setPreferredMediaInfo(mediaInfo); sdpManager.setPreferredMediaInfo(mediaInfo);
} }
/** /**
...@@ -1042,9 +1044,8 @@ if (false) { ...@@ -1042,9 +1044,8 @@ if (false) {
return getSdpInfo(sdpBody, true); return getSdpInfo(sdpBody, true);
} }
public SdpInfo getSdpInfo(String sdpBody, boolean isRequest) public SdpInfo getSdpInfo(String sdpBody, boolean isRequest) throws ParseException
throws ParseException { {
SdpInfo remoteSdpInfo = sdpManager.parseSdp(sdpBody); SdpInfo remoteSdpInfo = sdpManager.parseSdp(sdpBody);
MediaInfo myPreferredMediaInfo = sdpManager.getPreferredMediaInfo(); MediaInfo myPreferredMediaInfo = sdpManager.getPreferredMediaInfo();
...@@ -1065,18 +1066,16 @@ if (false) { ...@@ -1065,18 +1066,16 @@ if (false) {
Logger.println("My preferred payload being used " + payload); Logger.println("My preferred payload being used " + payload);
} else { } else {
if (isRequest) { if (isRequest) {
Logger.writeFile("My preferred media " Logger.writeFile("My preferred media " + myPreferredMediaInfo + " not supported...");
+ myPreferredMediaInfo + " not supported...");
} }
try { try {
payload = remoteSdpInfo.getMediaInfo().getPayload(); payload = remoteSdpInfo.getMediaInfo().getPayload();
remoteSdpInfo.setMediaInfo(sdpManager.findMediaInfo(payload)); remoteSdpInfo.setMediaInfo(sdpManager.findMediaInfo(payload));
Logger.writeFile("media setting is " Logger.writeFile("media setting is " + remoteSdpInfo.getMediaInfo());
+ remoteSdpInfo.getMediaInfo());
} catch (ParseException e) { } catch (ParseException e) {
throw new ParseException("Unsupported media " remoteSdpInfo.setMediaInfo(new MediaInfo((byte)0, RtpPacket.PCMU_ENCODING, 8000, 1, false));
+ remoteSdpInfo.getMediaInfo(), 0);
} }
} }
return remoteSdpInfo; return remoteSdpInfo;
......
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
* *
* This file is part of jVoiceBridge. * This file is part of jVoiceBridge.
* *
* jVoiceBridge is free software: you can redistribute it and/or modify * jVoiceBridge is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation and distributed hereunder * published by the Free Software Foundation and distributed hereunder
* to you. * to you.
* *
* jVoiceBridge is distributed in the hope that it will be useful, * jVoiceBridge is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
...@@ -17,8 +17,8 @@ ...@@ -17,8 +17,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
* *
* Sun designates this particular file as subject to the "Classpath" * Sun designates this particular file as subject to the "Classpath"
* exception as provided by Sun in the License file that accompanied this * exception as provided by Sun in the License file that accompanied this
* code. * code.
*/ */
package com.sun.voip.server; package com.sun.voip.server;
...@@ -143,7 +143,7 @@ public class WhisperGroup implements MixDataSource, TreatmentDoneListener { ...@@ -143,7 +143,7 @@ public class WhisperGroup implements MixDataSource, TreatmentDoneListener {
} }
members.add(member); members.add(member);
} }
public void removeCall(ConferenceMember member) { public void removeCall(ConferenceMember member) {
if (members.contains(member) == false) { if (members.contains(member) == false) {
...@@ -171,11 +171,11 @@ public class WhisperGroup implements MixDataSource, TreatmentDoneListener { ...@@ -171,11 +171,11 @@ public class WhisperGroup implements MixDataSource, TreatmentDoneListener {
whisperers.add(member); whisperers.add(member);
if (Logger.logLevel >= Logger.LOG_INFO) { if (Logger.logLevel >= Logger.LOG_INFO) {
Logger.println("Call " + member + " started whispering to " Logger.println("Call " + member + " started whispering to "
+ id); + id);
} }
return; return;
} }
if (whisperers.contains(member) == false) { if (whisperers.contains(member) == false) {
Logger.println("Call " + member + " is not in whisperers!"); Logger.println("Call " + member + " is not in whisperers!");
...@@ -233,21 +233,22 @@ public class WhisperGroup implements MixDataSource, TreatmentDoneListener { ...@@ -233,21 +233,22 @@ public class WhisperGroup implements MixDataSource, TreatmentDoneListener {
* This is called when data is received from a conference member * This is called when data is received from a conference member
* The member has already converted its contribution to linear. * The member has already converted its contribution to linear.
*/ */
public void addToLinearDataMix(int[] contribution, boolean doNotRecord) { public void addToLinearDataMix(int[] contribution, boolean doNotRecord)
if (doNotRecord) { {
if (doNotRecordMix == null) { if (doNotRecord) {
doNotRecordMix = new int[contribution.length]; if (doNotRecordMix == null) {
doNotRecordMix = new int[contribution.length];
System.arraycopy(contribution, 0, doNotRecordMix, 0,
contribution.length); System.arraycopy(contribution, 0, doNotRecordMix, 0,
return; contribution.length);
} return;
}
mixData(contribution, doNotRecordMix, true);
return; mixData(contribution, doNotRecordMix, true);
} return;
}
if (linearMixBuffer == null) { if (linearMixBuffer == null) {
linearMixBuffer = new int[contribution.length]; linearMixBuffer = new int[contribution.length];
System.arraycopy(contribution, 0, linearMixBuffer, 0, System.arraycopy(contribution, 0, linearMixBuffer, 0,
...@@ -258,39 +259,70 @@ public class WhisperGroup implements MixDataSource, TreatmentDoneListener { ...@@ -258,39 +259,70 @@ public class WhisperGroup implements MixDataSource, TreatmentDoneListener {
mixData(contribution, linearMixBuffer, true); mixData(contribution, linearMixBuffer, true);
} }
public static void mixData(int[] inData, int[] mixData, boolean add) { public static void mixData(int[] inData, int[] mixData, boolean add)
try { {
if (add) { //Logger.println("mixData - inData length " + inData.length + " mixData length " + mixData.length + " add " + add);
for (int i = 0; i < inData.length; i++) {
mixData[i] = mixData[i] + inData[i];
}
} else {
for (int i = 0; i < inData.length; i++) {
mixData[i] = mixData[i] - inData[i];
}
}
} catch (IndexOutOfBoundsException e) {
Logger.println("Exception! inData length " + inData.length
+ " mixData length " + mixData.length + " add " + add);
e.printStackTrace(); try {
} if (add) {
if (inData.length <= mixData.length)
{
for (int i = 0; i < inData.length; i++) {
mixData[i] = mixData[i] + inData[i];
}
} else {
for (int i = 0; i < mixData.length; i++) {
mixData[i] = mixData[i] + inData[i];
}
}
} else {
if (inData.length <= mixData.length)
{
for (int i = 0; i < inData.length; i++) {
mixData[i] = mixData[i] - inData[i];
}
} else {
for (int i = 0; i < mixData.length; i++) {
mixData[i] = mixData[i] - inData[i];
}
}
}
} catch (IndexOutOfBoundsException e) {
Logger.println("Exception! inData length " + inData.length
+ " mixData length " + mixData.length + " add " + add);
e.printStackTrace();
}
} }
public static void mixData(int[] conferenceData, int[] memberData, public static void mixData(int[] conferenceData, int[] memberData, int[] outData)
int[] outData) { {
//Logger.println("mixData - conferenceData length " + conferenceData.length +" memberData.length " + memberData.length + " outData length " + outData.length);
try { try {
for (int i = 0; i < outData.length; i ++) { if (outData.length <= memberData.length)
outData[i] = conferenceData[i] - memberData[i]; {
} for (int i = 0; i < outData.length; i ++) {
} catch (IndexOutOfBoundsException e) { outData[i] = conferenceData[i] - memberData[i];
Logger.println("Exception! conferenceData length " }
+ conferenceData.length +" memberData.length "
+ memberData.length + " outData length " + outData.length);
e.printStackTrace(); } else {
} for (int i = 0; i < memberData.length; i ++) {
outData[i] = conferenceData[i] - memberData[i];
}
}
} catch (IndexOutOfBoundsException e) {
Logger.println("mixData Exception! conferenceData length " + conferenceData.length +" memberData.length " + memberData.length + " outData length " + outData.length);
e.printStackTrace();
}
} }
private int[] previousContribution; private int[] previousContribution;
...@@ -321,8 +353,8 @@ public class WhisperGroup implements MixDataSource, TreatmentDoneListener { ...@@ -321,8 +353,8 @@ public class WhisperGroup implements MixDataSource, TreatmentDoneListener {
synchronized (conferenceTreatments) { synchronized (conferenceTreatments) {
currentTreatment.saveCurrentContribution(); currentTreatment.saveCurrentContribution();
int[] treatmentData = currentTreatment.getCurrentContribution(); int[] treatmentData = currentTreatment.getCurrentContribution();
if (treatmentDone) { if (treatmentDone) {
conferenceTreatments.remove(currentTreatment); conferenceTreatments.remove(currentTreatment);
...@@ -442,7 +474,7 @@ public class WhisperGroup implements MixDataSource, TreatmentDoneListener { ...@@ -442,7 +474,7 @@ public class WhisperGroup implements MixDataSource, TreatmentDoneListener {
if (audioRecorder == null) { if (audioRecorder == null) {
synchronized (recordingLock) { synchronized (recordingLock) {
audioRecorder = new Recorder(recordingFile, "au", audioRecorder = new Recorder(recordingFile, "au",
mediaInfo); mediaInfo);
Logger.println("starting conference recorder for " Logger.println("starting conference recorder for "
...@@ -553,7 +585,7 @@ public class WhisperGroup implements MixDataSource, TreatmentDoneListener { ...@@ -553,7 +585,7 @@ public class WhisperGroup implements MixDataSource, TreatmentDoneListener {
s += " "; s += " ";
for (int i = 0; i < members.size(); i++) { for (int i = 0; i < members.size(); i++) {
ConferenceMember member = ConferenceMember member =
(ConferenceMember)members.get(i); (ConferenceMember)members.get(i);
CallParticipant cp = member.getCallParticipant(); CallParticipant cp = member.getCallParticipant();
...@@ -564,7 +596,7 @@ public class WhisperGroup implements MixDataSource, TreatmentDoneListener { ...@@ -564,7 +596,7 @@ public class WhisperGroup implements MixDataSource, TreatmentDoneListener {
} }
s += " "; s += " ";
} }
return s; return s;
} }
......
...@@ -558,7 +558,6 @@ public class RayoComponent extends AbstractComponent ...@@ -558,7 +558,6 @@ public class RayoComponent extends AbstractComponent
{ {
if (channel == null) if (channel == null)
{ {
cp.setMediaPreference("PCMU/8000/1");
cp.setPhoneNumber(handset.sipuri); cp.setPhoneNumber(handset.sipuri);
cp.setAutoAnswer(true); cp.setAutoAnswer(true);
cp.setProtocol("SIP"); cp.setProtocol("SIP");
...@@ -1037,7 +1036,6 @@ public class RayoComponent extends AbstractComponent ...@@ -1037,7 +1036,6 @@ public class RayoComponent extends AbstractComponent
CallParticipant cp = new CallParticipant(); CallParticipant cp = new CallParticipant();
cp.setVoiceDetection(true); cp.setVoiceDetection(true);
cp.setCallOwner(handsetId); cp.setCallOwner(handsetId);
cp.setMediaPreference("PCMU/8000/1");
cp.setProtocol("SIP"); cp.setProtocol("SIP");
cp.setDisplayName(callerName); cp.setDisplayName(callerName);
cp.setPhoneNumber(to); cp.setPhoneNumber(to);
...@@ -1063,6 +1061,7 @@ public class RayoComponent extends AbstractComponent ...@@ -1063,6 +1061,7 @@ public class RayoComponent extends AbstractComponent
CallParticipant hp = handsetHandler.getCallParticipant(); CallParticipant hp = handsetHandler.getCallParticipant();
headers.put("mixer_name", hp.getConferenceId()); headers.put("mixer_name", hp.getConferenceId());
headers.put("codec_name", "PCM/48000/2".equals(hp.getMediaPreference()) ? "OPUS" : "PCMU");
try { try {
ConferenceManager conferenceManager = ConferenceManager.findConferenceManager(hp.getConferenceId()); ConferenceManager conferenceManager = ConferenceManager.findConferenceManager(hp.getConferenceId());
...@@ -1225,6 +1224,7 @@ public class RayoComponent extends AbstractComponent ...@@ -1225,6 +1224,7 @@ public class RayoComponent extends AbstractComponent
ConferenceManager conferenceManager = ConferenceManager.findConferenceManager(mixer); ConferenceManager conferenceManager = ConferenceManager.findConferenceManager(mixer);
cp.setConferenceId(mixer); cp.setConferenceId(mixer);
cp.setCallId(mixer); cp.setCallId(mixer);
cp.setMediaPreference(hp.getMediaPreference());
conferenceManager.setCallId(mixer); conferenceManager.setCallId(mixer);
conferenceManager.setTransferCall(transferCall); conferenceManager.setTransferCall(transferCall);
...@@ -1761,68 +1761,65 @@ public class RayoComponent extends AbstractComponent ...@@ -1761,68 +1761,65 @@ public class RayoComponent extends AbstractComponent
public boolean routeIncomingSIP(CallParticipant cp) public boolean routeIncomingSIP(CallParticipant cp)
{ {
Log.info("Incoming SIP, call route to user " + cp.getToPhoneNumber()); boolean canRoute = false;
Group group = null;
JID foundUser = findUser(cp.getToPhoneNumber()); JID foundUser = findUser(cp.getToPhoneNumber());
String callId = "rayo-incoming-" + System.currentTimeMillis(); if (foundUser != null)
cp.setCallId(callId); canRoute = true;
cp.setMediaPreference("PCMU/8000/1");
cp.setConferenceId(callId);
else {
try {
group = GroupManager.getInstance().getGroup(cp.getToPhoneNumber());
canRoute = true;
ConferenceManager conferenceManager = ConferenceManager.getConference(callId, cp.getMediaPreference(), cp.getToPhoneNumber(), false); } catch (GroupNotFoundException e) {
conferenceManager.setCallId(callId);
Map<String, String> headers = cp.getHeaders(); }
headers.put("mixer_name", callId);
headers.put("call_protocol", "SIP");
headers.put("group_name", cp.getToPhoneNumber());
if (foundUser != null) // send this call to specific user
{
cp.setCallOwner(foundUser.toString());
routeSIPCall(foundUser, cp, callId, headers);
return true;
} }
try { Log.info("Incoming SIP, call route to entity " + cp.getToPhoneNumber() + " " + canRoute);
Group group = GroupManager.getInstance().getGroup(cp.getToPhoneNumber());
conferenceManager.setGroupName(cp.getToPhoneNumber()); if (canRoute)
{
String callId = "rayo-incoming-" + System.currentTimeMillis();
cp.setCallId(callId);
cp.setConferenceId(callId);
for (JID memberJID : group.getMembers()) if (cp.getMediaPreference() == null) cp.setMediaPreference("PCMU/8000/1"); // regular phone
{
Collection<ClientSession> sessions = SessionManager.getInstance().getSessions(memberJID.getNode());
for (ClientSession session : sessions) ConferenceManager conferenceManager = ConferenceManager.getConference(callId, cp.getMediaPreference(), cp.getToPhoneNumber(), false);
{ conferenceManager.setCallId(callId);
routeSIPCall(session.getAddress(), cp, callId, headers);
}
}
return true; Map<String, String> headers = cp.getHeaders();
headers.put("mixer_name", callId);
headers.put("call_protocol", "SIP");
headers.put("codec_name", "PCM/48000/2".equals(cp.getMediaPreference()) ? "OPUS" : "PCMU");
headers.put("group_name", cp.getToPhoneNumber());
} catch (GroupNotFoundException e) { if (foundUser != null) // send this call to specific user
// Group not found {
cp.setCallOwner(foundUser.toString());
routeSIPCall(foundUser, cp, callId, headers);
if (XMPPServer.getInstance().getMultiUserChatManager().getMultiUserChatService("conference").hasChatRoom(cp.getToPhoneNumber())) { } else {
MUCRoom room = XMPPServer.getInstance().getMultiUserChatManager().getMultiUserChatService("conference").getChatRoom(cp.getToPhoneNumber()); conferenceManager.setGroupName(cp.getToPhoneNumber());
if (room != null) for (JID memberJID : group.getMembers())
{ {
for (MUCRole role : room.getOccupants()) Collection<ClientSession> sessions = SessionManager.getInstance().getSessions(memberJID.getNode());
for (ClientSession session : sessions)
{ {
routeSIPCall(role.getUserAddress(), cp, callId, headers); routeSIPCall(session.getAddress(), cp, callId, headers);
} }
} }
return true;
} else {
return false;
} }
} }
return canRoute;
} }
public void routeSIPCall(JID callee, CallParticipant cp, String callId, Map<String, String> headers) public void routeSIPCall(JID callee, CallParticipant cp, String callId, Map<String, String> headers)
......
...@@ -91,7 +91,6 @@ public class RelayChannel { ...@@ -91,7 +91,6 @@ public class RelayChannel {
private Integer lastAudioTimestamp = new Integer((int)0); private Integer lastAudioTimestamp = new Integer((int)0);
private long decoder = 0; private long decoder = 0;
private long encoder = 0;
private final int sampleRate = 48000; private final int sampleRate = 48000;
private final int frameSizeInMillis = 20; private final int frameSizeInMillis = 20;
private final int outputFrameSize = 2; private final int outputFrameSize = 2;
...@@ -297,22 +296,13 @@ public class RelayChannel { ...@@ -297,22 +296,13 @@ public class RelayChannel {
encryptor2 = new Encryptor(SDPCryptoSuite.getEncryptionMode(handset.cryptoSuite), remoteCryptoKey, remoteCryptoSalt, localCryptoKey, localCryptoSalt); encryptor2 = new Encryptor(SDPCryptoSuite.getEncryptionMode(handset.cryptoSuite), remoteCryptoKey, remoteCryptoSalt, localCryptoKey, localCryptoSalt);
decoder = Opus.decoder_create(sampleRate, channels); decoder = Opus.decoder_create(sampleRate, channels);
encoder = Opus.encoder_create(sampleRate, channels);
//Opus.encoder_set_bandwidth(encoder, Opus.OPUS_AUTO);
//Opus.encoder_set_bitrate(encoder, 32000);
//Opus.encoder_set_complexity(encoder, 10);
//Opus.encoder_set_inband_fec(encoder, 1);
//Opus.encoder_set_packet_loss_perc(encoder, 1);
//Opus.encoder_set_dtx(encoder, 1);
if (decoder == 0) Log.error( "Opus decoder creation error "); if (decoder == 0) Log.error( "Opus decoder creation error ");
if (encoder == 0) Log.error( "Opus encoder creation error ");
if (decoder == 0 || encoder == 0) if (decoder == 0)
{ {
handset.codec = "PCMU"; handset.codec = "PCMU";
Log.warn( "Opus encoder/decoder creation failure, PCMU will be used in default"); Log.warn( "Opus decoder creation failure, PCMU will be used in default");
} }
} catch (Exception e) { } catch (Exception e) {
...@@ -361,12 +351,6 @@ public class RelayChannel { ...@@ -361,12 +351,6 @@ public class RelayChannel {
decoder = 0; decoder = 0;
} }
if (encoder != 0)
{
Opus.encoder_destroy(encoder);
encoder = 0;
}
SayCompleteEvent complete = new SayCompleteEvent(); SayCompleteEvent complete = new SayCompleteEvent();
complete.setReason(SayCompleteEvent.Reason.valueOf("SUCCESS")); complete.setReason(SayCompleteEvent.Reason.valueOf("SUCCESS"));
...@@ -445,7 +429,7 @@ public class RelayChannel { ...@@ -445,7 +429,7 @@ public class RelayChannel {
return new Long((new Integer(timestamp.intValue())).longValue()); return new Long((new Integer(timestamp.intValue())).longValue());
} }
public synchronized void pushAudio(byte[] rtpData, int[] in) public synchronized void pushAudio(byte[] rtpData, byte[] opus)
{ {
try { try {
...@@ -454,15 +438,9 @@ public class RelayChannel { ...@@ -454,15 +438,9 @@ public class RelayChannel {
RTPPacket newPacket = RTPPacket.parseBytes(BitAssistant.bytesToArray(rtpData)); RTPPacket newPacket = RTPPacket.parseBytes(BitAssistant.bytesToArray(rtpData));
RTPPacket packet = RTPPacket.parseBytes(lastAudioPacket.getBytes()); RTPPacket packet = RTPPacket.parseBytes(lastAudioPacket.getBytes());
if (handset.codec == null || "OPUS".equals(handset.codec)) if (opus != null)
{ {
byte[] input = AudioConversion.littleEndianIntsToBytes(in); packet.setPayload(BitAssistant.bytesToArray(opus));
byte[] output = new byte[Opus.MAX_PACKET];
int outLength = Opus.encode(encoder, input, 0, frameSizeInSamplesPerChannel, output, 0, output.length);
byte[] compressedBytes = new byte[outLength];
System.arraycopy(output, 0, compressedBytes, 0, outLength);
packet.setPayload(BitAssistant.bytesToArray(compressedBytes));
packet.setTimestamp(getNextAudioTimestamp(Long.valueOf(48000))); packet.setTimestamp(getNextAudioTimestamp(Long.valueOf(48000)));
} else { // ULAW } else { // ULAW
...@@ -484,8 +462,8 @@ public class RelayChannel { ...@@ -484,8 +462,8 @@ public class RelayChannel {
kt++; kt++;
if ( kt < 10 ) { if ( kt < 20 ) {
Log.info( "+++ " + in ); Log.info( "+++ " + packet.getPayload().length );
} }
} }
......
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