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) {
(byte)125, RtpPacket.SPEEX_ENCODING, 32000, 2, false));
}
public MediaInfo(byte payload , int encoding, int sampleRate,
int channels, boolean isTelephoneEventPayload) {
public MediaInfo(byte payload , int encoding, int sampleRate, int channels, boolean isTelephoneEventPayload)
{
this.payload = payload;
this.encoding = encoding;
this.sampleRate = sampleRate;
this.channels = channels;
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,
......
......@@ -224,8 +224,7 @@ public class SdpInfo {
+ encoding + "/" + sampleRate + "/" + channels);
}
public MediaInfo findBestMediaInfo(Vector otherSupportedMedia,
MediaInfo otherMediaPreference) throws IOException {
public MediaInfo findBestMediaInfo(Vector otherSupportedMedia, MediaInfo otherMediaPreference) throws IOException {
MediaInfo best = null;
......
......@@ -124,15 +124,12 @@ public class SdpManager {
for (int i = 0; i < supportedMedia.size(); i++) {
MediaInfo mediaInfo = (MediaInfo) supportedMedia.elementAt(i);
if (mediaInfo.getSampleRate() > maxSampleRate ||
mediaInfo.getChannels() > maxChannels) {
if (mediaInfo.getSampleRate() > maxSampleRate || mediaInfo.getChannels() > maxChannels) {
continue;
}
if (useTelephoneEvent == false &&
mediaInfo.isTelephoneEventPayload()) {
if (useTelephoneEvent == false && mediaInfo.isTelephoneEventPayload())
{
continue;
}
......@@ -153,13 +150,12 @@ public class SdpManager {
private String getRtpmaps() {
String rtpmaps = "";
for (int i = 0; i < supportedMedia.size(); i++) {
MediaInfo mediaInfo = (MediaInfo)
supportedMedia.elementAt(i);
if (mediaInfo.getSampleRate() > maxSampleRate ||
mediaInfo.getChannels() > maxChannels) {
for (int i = 0; i < supportedMedia.size(); i++)
{
MediaInfo mediaInfo = (MediaInfo) supportedMedia.elementAt(i);
if (mediaInfo.getSampleRate() > maxSampleRate || mediaInfo.getChannels() > maxChannels)
{
continue;
}
......@@ -267,25 +263,23 @@ public class SdpManager {
return sdp;
}
public String generateSdp(String name, InetSocketAddress isa,
SdpInfo remoteSdpInfo) throws IOException {
public String generateSdp(String name, InetSocketAddress isa, SdpInfo remoteSdpInfo) throws IOException
{
MediaInfo mediaInfo = null;
if (localMediaPreference != null) {
if (localMediaPreference != null)
{
if (remoteSdpInfo.isSupported(localMediaPreference)) {
mediaInfo = localMediaPreference;
if (Logger.logLevel >= Logger.LOG_INFO) {
Logger.println("Using local media preference: " + mediaInfo);
}
}
}
/*
* Try remote media preference
*/
if (mediaInfo == null && remoteSdpInfo.preferredMediaSpecified()) {
if (remoteSdpInfo.preferredMediaSpecified())
{
MediaInfo remoteMediaPreference = remoteSdpInfo.getMediaInfo();
if (remoteMediaPreference.getSampleRate() <= maxSampleRate &&
......@@ -295,11 +289,8 @@ public class SdpManager {
* See if remote media preference is supported
*/
try {
mediaInfo =
findMediaInfo(remoteMediaPreference.getPayload());
Logger.println("Using remote media preference: "
+ mediaInfo);
mediaInfo = findMediaInfo(remoteMediaPreference.getPayload());
Logger.println("Using remote media preference: " + mediaInfo);
} catch (ParseException e) {
}
}
......@@ -309,8 +300,7 @@ public class SdpManager {
/*
* default to 8000/1 ulaw
*/
mediaInfo = remoteSdpInfo.findBestMediaInfo(supportedMedia,
localMediaPreference);
mediaInfo = remoteSdpInfo.findBestMediaInfo(supportedMedia, localMediaPreference);
Logger.println("Using best media " + mediaInfo);
}
......@@ -329,8 +319,7 @@ public class SdpManager {
payloads += " " + telephoneEventPayload;
telephoneEvent += generateRtpmap(m) + "\r\n";
} catch (ParseException e) {
Logger.println("Failed to add rtpmap for telephone event "
+ telephoneEventPayload);
Logger.println("Failed to add rtpmap for telephone event " + telephoneEventPayload);
}
}
......
......@@ -172,7 +172,7 @@ public class SdpParser {
+ payloads[i], 0);
}
if (payload != 0 && payload < 96 || payload > 127) {
if (payload != 0 && (payload < 96 || payload > 127)) {
/*
* Not one we can deal with
*/
......
......@@ -323,10 +323,9 @@ public abstract class CallHandler extends Thread {
* Send indication when a dtmf key is pressed
*/
public void dtmfKeys(String dtmfKeys) {
if (Logger.logLevel >= Logger.LOG_MOREINFO) {
Logger.println(cp + " got dtmf keys " + dtmfKeys + " "
+ cp.dtmfDetection());
}
//if (Logger.logLevel >= Logger.LOG_MOREINFO) {
Logger.println(cp + " got dtmf keys " + dtmfKeys + " " + cp.dtmfDetection());
//}
if (isCallEstablished()) {
if (cp.dtmfDetection()) {
......
......@@ -97,13 +97,21 @@ public class IncomingCallHandler extends CallHandler
addCallEventListener(this);
if (cp.getConferenceId() == null || cp.getConferenceId().length() == 0)
{
if (directConferencing)
{
if (cp.getConferenceId() == null || cp.getConferenceId().length() == 0)
{
System.out.println("Don't have conf, using default....");
cp.setConferenceId(defaultIncomingConferenceId); // wait in lobby
} else {
Logger.println("Have conf " + cp.getConferenceId());
haveIncomingConferenceId = true; // goto your conference
}
start();
} else {
System.out.println("Incoming SIP, call " + cp);
......@@ -111,6 +119,7 @@ public class IncomingCallHandler extends CallHandler
if (RayoComponent.self.routeIncomingSIP(cp))
{
haveIncomingConferenceId = true;
start();
} else {
// conf bridge
......@@ -118,10 +127,12 @@ public class IncomingCallHandler extends CallHandler
if (Config.getInstance().getConferenceExten().equals(cp.getToPhoneNumber()))
{
incomingConferenceHandler = new IncomingConferenceHandler(this, cp.getToPhoneNumber());
start();
} else if (Config.getInstance().getConferenceByPhone(cp.getToPhoneNumber()) != null) {
incomingConferenceHandler = new IncomingConferenceHandler(this, cp.getToPhoneNumber());
start();
} else {
cancelRequest(cp.getToPhoneNumber() + " is not a valid endpoint"); // reject call
......@@ -129,14 +140,6 @@ public class IncomingCallHandler extends CallHandler
}
}
} else {
Logger.println("Have conf " + cp.getConferenceId());
haveIncomingConferenceId = true; // goto your conference
}
start();
}
public static void setDirectConferencing(boolean directConferencing) {
......@@ -350,6 +353,9 @@ public class IncomingCallHandler extends CallHandler
public void callEventNotification(CallEvent callEvent) {
Logger.println("IncomingCallHandler " + callEvent.toString());
if (callEvent.equals(callEvent.STATE_CHANGED) &&
callEvent.getCallState().equals(CallState.ESTABLISHED)) {
......@@ -461,6 +467,8 @@ public class IncomingCallHandler extends CallHandler
public ConferenceManager transferCall(String conferenceId)
throws IOException {
System.out.println("transferCall " + conferenceId);
ConferenceManager conferenceManager = transferCall(this, conferenceId);
String s = getNumberOfCallsAsTreatment(conferenceManager.getNumberOfMembers());
......
......@@ -84,6 +84,8 @@ public class IncomingConferenceHandler extends Thread
this.phoneNo = phoneNo;
incomingCallHandler.addCallEventListener(this);
Logger.println("IncomingConferenceHandler: " + phoneNo);
}
private String lastMessagePlayed;
......@@ -121,9 +123,9 @@ public class IncomingConferenceHandler extends Thread
* Called when status for an incoming call changes.
*/
public void callEventNotification(CallEvent callEvent) {
if (Logger.logLevel >= Logger.LOG_INFO) {
Logger.println(callEvent.toString());
}
//if (Logger.logLevel >= Logger.LOG_INFO) {
Logger.println("IncomingConferenceHandler " + callEvent.toString());
//}
if (callEvent.equals(CallEvent.STATE_CHANGED) &&
callEvent.getCallState().equals(CallState.ESTABLISHED)) {
......@@ -132,18 +134,19 @@ public class IncomingConferenceHandler extends Thread
* New incoming call
*/
if (callEvent.getInfo() != null) {
Logger.println("IncomingConferenceHandler: "
+ callEvent.getInfo());
Logger.println("IncomingConferenceHandler: " + callEvent.getInfo());
}
if (Config.getInstance().getMeetingCode(phoneNo) != null)
{
meetingCode = Config.getInstance().getMeetingCode(phoneNo);
Logger.println("IncomingConferenceHandler: meeting code " + meetingCode);
if (Config.getInstance().getPassCode(meetingCode, phoneNo) == null)
{
try {
incomingCallHandler.transferCall(Config.getInstance().getMeetingCode(phoneNo));
incomingCallHandler.transferCall(meetingCode);
state = IN_MEETING;
} catch (IOException e) {
......
......@@ -71,6 +71,7 @@ import java.awt.Point;
import org.ifsoft.*;
import org.ifsoft.rtp.*;
import org.jitsi.impl.neomedia.codec.audio.opus.Opus;
/**
* Receive RTP data for this ConferenceMember, add it to the mix
......@@ -116,6 +117,15 @@ public class MemberReceiver implements MixDataSource, TreatmentDoneListener {
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 boolean done = false;
......@@ -451,6 +461,23 @@ public class MemberReceiver implements MixDataSource, TreatmentDoneListener {
callHandler.cancelRequest(e.getMessage());
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) {
......@@ -1170,9 +1197,7 @@ public class MemberReceiver implements MixDataSource, TreatmentDoneListener {
callHandler.getMember().adjustVolume(data, inputVolume);
}
//Logger.println("Call " + cp
// + " receiveMedia length " + length + " decoded int length "
// + data.length);
//Logger.println("Call " + cp + " receiveMedia length " + length + " decoded int length " + data.length);
int numberOfSamples = data.length;
......@@ -1246,18 +1271,20 @@ public class MemberReceiver implements MixDataSource, TreatmentDoneListener {
return numberOfSamples;
}
private int[] decodeToLinear(byte[] receivedData, int length)
throws SpeexException {
private int[] decodeToLinear(byte[] receivedData, int length) throws SpeexException
{
/*
* receivedData has the 12 byte RTP header.
*/
int[] data = new int[myMediaInfo.getSamplesPerPacket()];
long start = 0;
if (myMediaInfo.getEncoding() == RtpPacket.PCMU_ENCODING) {
if (traceCall || Logger.logLevel == -1) {
if (myMediaInfo.getEncoding() == RtpPacket.PCMU_ENCODING)
{
if (traceCall || Logger.logLevel == -1)
{
start = System.nanoTime();
}
......@@ -1268,32 +1295,47 @@ public class MemberReceiver implements MixDataSource, TreatmentDoneListener {
* If the incoming packet is shorter, than we expect,
* the rest of <data> will be filled with 0 * which is PCM_SILENCE.
*/
AudioConversion.ulawToLinear(receivedData, RtpPacket.HEADER_SIZE,
length - RtpPacket.HEADER_SIZE, data);
AudioConversion.ulawToLinear(receivedData, RtpPacket.HEADER_SIZE, length - RtpPacket.HEADER_SIZE, data);
if (length < 172 && Logger.logLevel >= Logger.LOG_DETAIL) {
Logger.println("Call " + cp + " received short packet "
+ length);
Logger.println("Call " + cp + " received short packet " + length);
}
if (traceCall || Logger.logLevel == -1) {
Logger.println("Call " + cp + " ulawToLinear time "
+ ((System.nanoTime() - start) / 1000000000.)
+ " seconds");
Logger.println("Call " + cp + " ulawToLinear time " + ((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) {
if (traceCall || Logger.logLevel == -1) {
start = System.nanoTime();
}
data = speexDecoder.decodeToIntArray(receivedData,
RtpPacket.HEADER_SIZE, length - RtpPacket.HEADER_SIZE);
data = speexDecoder.decodeToIntArray(receivedData, RtpPacket.HEADER_SIZE, length - RtpPacket.HEADER_SIZE);
if (traceCall || Logger.logLevel == -1) {
Logger.println("Call " + cp + " speex decode time "
+ ((System.nanoTime() - start) / 1000000000.)
+ " seconds");
if (traceCall || Logger.logLevel == -1)
{
Logger.println("Call " + cp + " speex decode time " + ((System.nanoTime() - start) / 1000000000.) + " seconds");
}
} else {
AudioConversion.bytesToInts(receivedData, RtpPacket.HEADER_SIZE,
length - RtpPacket.HEADER_SIZE, data);
......@@ -1877,6 +1919,12 @@ public class MemberReceiver implements MixDataSource, TreatmentDoneListener {
}
}
}
if (opusDecoder != 0)
{
Opus.decoder_destroy(opusDecoder);
opusDecoder = 0;
}
}
public void printStatistics() {
......
......@@ -55,6 +55,8 @@ import org.xmpp.jnodes.RelayChannel;
import org.ifsoft.*;
import org.ifsoft.rtp.*;
import org.jitsi.impl.neomedia.codec.audio.opus.Opus;
/**
* Send RTP data to this ConferenceMember,
*/
......@@ -73,6 +75,14 @@ public class MemberSender {
private RtpSenderPacket senderPacket;
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 boolean done = false;
......@@ -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;
......@@ -411,6 +438,8 @@ public class MemberSender {
//Logger.println("Call " + cp + " Sending data...");
byte[] opusBytes = null;
if (myMediaInfo.getEncoding() == RtpPacket.PCMU_ENCODING) {
/*
* Convert to ulaw
......@@ -433,13 +462,27 @@ public class MemberSender {
Logger.println("Call " + this + ": " + e.getMessage());
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 {
AudioConversion.intsToBytes(dataToSend, rtpData, RtpPacket.HEADER_SIZE);
}
recordPacket(rtpData, senderPacket.getLength());
recordAudio(rtpData, RtpPacket.HEADER_SIZE,
senderPacket.getLength() - RtpPacket.HEADER_SIZE);
recordAudio(rtpData, RtpPacket.HEADER_SIZE, senderPacket.getLength() - RtpPacket.HEADER_SIZE);
/*
* Encrypt data if required
......@@ -469,14 +512,12 @@ public class MemberSender {
try {
senderPacket.setSocketAddress(memberAddress);
datagramChannel.send(
ByteBuffer.wrap(senderPacket.getData(), 0,
senderPacket.getLength()), memberAddress);
datagramChannel.send(ByteBuffer.wrap(senderPacket.getData(), 0, senderPacket.getLength()), memberAddress);
if (Logger.logLevel >= Logger.LOG_MOREDETAIL) {
Logger.writeFile("Call " + cp + " back from sending data");
}
} catch (IOException e) {
} catch (Exception e) {
if (!done) {
Logger.error("Call " + cp + " sendData " + e.getMessage());
e.printStackTrace();
......@@ -488,7 +529,8 @@ public class MemberSender {
} else {
try {
getWebRTCParticipant().pushAudio(rtpData, dataToSend);
getWebRTCParticipant().pushAudio(senderPacket.getData(), opusBytes);
} catch (Exception e) {
......@@ -758,8 +800,7 @@ public class MemberSender {
senderPacket.setSocketAddress(memberAddress);
try {
datagramChannel.send(
ByteBuffer.wrap(senderPacket.getData()), memberAddress);
datagramChannel.send(ByteBuffer.wrap(senderPacket.getData()), memberAddress);
} catch (IOException e) {
if (!done) {
Logger.println("Call " + cp + " sendComfortNoisePayload "
......@@ -864,6 +905,12 @@ public class MemberSender {
recorder = null;
}
}
if (opusEncoder != 0)
{
Opus.encoder_destroy(opusEncoder);
opusEncoder = 0;
}
}
public void printStatistics() {
......
......@@ -508,8 +508,11 @@ public class MixManager {
memberMixDescriptor.getMixDataSource().getCurrentContribution();
if (memberContribution == null) {
System.arraycopy(conferenceMixContribution, 0, outData, 0,
conferenceMixContribution.length);
if (outData.length <= conferenceMixContribution.length)
System.arraycopy(conferenceMixContribution, 0, outData, 0, outData.length);
else
System.arraycopy(conferenceMixContribution, 0, outData, 0, conferenceMixContribution.length);
if (Logger.logLevel == -39) {
checkData(outData, useFastMix);
......@@ -519,8 +522,7 @@ public class MixManager {
return outData;
}
WhisperGroup.mixData(conferenceMixContribution, memberContribution,
outData);
WhisperGroup.mixData(conferenceMixContribution, memberContribution, outData);
if (Logger.logLevel == -39) {
checkData(outData, useFastMix);
......
......@@ -74,8 +74,7 @@ public class SipIncomingCallAgent extends CallSetupAgent implements SipListener
sipServerCallback = SipServer.getSipServerCallback();
MediaInfo mixerMediaPreference =
callHandler.getConferenceManager().getMediaInfo();
MediaInfo mixerMediaPreference = callHandler.getConferenceManager().getMediaInfo();
sipUtil = new SipUtil(mixerMediaPreference);
......
......@@ -87,8 +87,7 @@ public class SipTPCCallAgent extends CallSetupAgent implements SipListener {
public SipTPCCallAgent(CallHandler callHandler) {
super(callHandler);
MediaInfo mixerMediaPreference =
callHandler.getConferenceManager().getMediaInfo();
MediaInfo mixerMediaPreference = callHandler.getConferenceManager().getMediaInfo();
sipUtil = new SipUtil(mixerMediaPreference);
}
......
......@@ -74,21 +74,23 @@ public class SipUtil {
this(null);
}
public SipUtil(MediaInfo mediaInfo) {
public SipUtil(MediaInfo mediaInfo)
{
if (!initialized) {
initialize();
}
sdpManager = new SdpManager();
if (mediaInfo == null) {
if (mediaInfo == null)
{
try {
mediaInfo = sdpManager.findMediaInfo(RtpPacket.PCMU_ENCODING,
8000, 1);
mediaInfo = sdpManager.findMediaInfo(RtpPacket.PCMU_ENCODING, 8000, 1);
Logger.println("SipUtil: Preference default media " + mediaInfo);
} catch (ParseException e) {
Logger.println(
"SipUtil: Invalid media info, can't set preference"
+ e.getMessage());
Logger.println("SipUtil: Invalid media info, can't set preference" + e.getMessage());
}
}
......@@ -1042,9 +1044,8 @@ if (false) {
return getSdpInfo(sdpBody, true);
}
public SdpInfo getSdpInfo(String sdpBody, boolean isRequest)
throws ParseException {
public SdpInfo getSdpInfo(String sdpBody, boolean isRequest) throws ParseException
{
SdpInfo remoteSdpInfo = sdpManager.parseSdp(sdpBody);
MediaInfo myPreferredMediaInfo = sdpManager.getPreferredMediaInfo();
......@@ -1065,18 +1066,16 @@ if (false) {
Logger.println("My preferred payload being used " + payload);
} else {
if (isRequest) {
Logger.writeFile("My preferred media "
+ myPreferredMediaInfo + " not supported...");
Logger.writeFile("My preferred media " + myPreferredMediaInfo + " not supported...");
}
try {
payload = remoteSdpInfo.getMediaInfo().getPayload();
remoteSdpInfo.setMediaInfo(sdpManager.findMediaInfo(payload));
Logger.writeFile("media setting is "
+ remoteSdpInfo.getMediaInfo());
Logger.writeFile("media setting is " + remoteSdpInfo.getMediaInfo());
} catch (ParseException e) {
throw new ParseException("Unsupported media "
+ remoteSdpInfo.getMediaInfo(), 0);
remoteSdpInfo.setMediaInfo(new MediaInfo((byte)0, RtpPacket.PCMU_ENCODING, 8000, 1, false));
}
}
return remoteSdpInfo;
......
......@@ -233,7 +233,8 @@ public class WhisperGroup implements MixDataSource, TreatmentDoneListener {
* This is called when data is received from a conference member
* 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) {
doNotRecordMix = new int[contribution.length];
......@@ -258,17 +259,40 @@ public class WhisperGroup implements MixDataSource, TreatmentDoneListener {
mixData(contribution, linearMixBuffer, true);
}
public static void mixData(int[] inData, int[] mixData, boolean add) {
public static void mixData(int[] inData, int[] mixData, boolean add)
{
//Logger.println("mixData - inData length " + inData.length + " mixData length " + mixData.length + " add " + add);
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);
......@@ -277,17 +301,25 @@ public class WhisperGroup implements MixDataSource, TreatmentDoneListener {
}
}
public static void mixData(int[] conferenceData, int[] memberData,
int[] outData) {
public static void mixData(int[] conferenceData, int[] memberData, int[] outData)
{
//Logger.println("mixData - conferenceData length " + conferenceData.length +" memberData.length " + memberData.length + " outData length " + outData.length);
try {
if (outData.length <= memberData.length)
{
for (int i = 0; i < outData.length; i ++) {
outData[i] = conferenceData[i] - memberData[i];
}
} else {
for (int i = 0; i < memberData.length; i ++) {
outData[i] = conferenceData[i] - memberData[i];
}
}
} catch (IndexOutOfBoundsException e) {
Logger.println("Exception! conferenceData length "
+ conferenceData.length +" memberData.length "
+ memberData.length + " outData length " + outData.length);
Logger.println("mixData Exception! conferenceData length " + conferenceData.length +" memberData.length " + memberData.length + " outData length " + outData.length);
e.printStackTrace();
}
......
......@@ -558,7 +558,6 @@ public class RayoComponent extends AbstractComponent
{
if (channel == null)
{
cp.setMediaPreference("PCMU/8000/1");
cp.setPhoneNumber(handset.sipuri);
cp.setAutoAnswer(true);
cp.setProtocol("SIP");
......@@ -1037,7 +1036,6 @@ public class RayoComponent extends AbstractComponent
CallParticipant cp = new CallParticipant();
cp.setVoiceDetection(true);
cp.setCallOwner(handsetId);
cp.setMediaPreference("PCMU/8000/1");
cp.setProtocol("SIP");
cp.setDisplayName(callerName);
cp.setPhoneNumber(to);
......@@ -1063,6 +1061,7 @@ public class RayoComponent extends AbstractComponent
CallParticipant hp = handsetHandler.getCallParticipant();
headers.put("mixer_name", hp.getConferenceId());
headers.put("codec_name", "PCM/48000/2".equals(hp.getMediaPreference()) ? "OPUS" : "PCMU");
try {
ConferenceManager conferenceManager = ConferenceManager.findConferenceManager(hp.getConferenceId());
......@@ -1225,6 +1224,7 @@ public class RayoComponent extends AbstractComponent
ConferenceManager conferenceManager = ConferenceManager.findConferenceManager(mixer);
cp.setConferenceId(mixer);
cp.setCallId(mixer);
cp.setMediaPreference(hp.getMediaPreference());
conferenceManager.setCallId(mixer);
conferenceManager.setTransferCall(transferCall);
......@@ -1761,15 +1761,33 @@ public class RayoComponent extends AbstractComponent
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());
if (foundUser != null)
canRoute = true;
else {
try {
group = GroupManager.getInstance().getGroup(cp.getToPhoneNumber());
canRoute = true;
} catch (GroupNotFoundException e) {
}
}
Log.info("Incoming SIP, call route to entity " + cp.getToPhoneNumber() + " " + canRoute);
if (canRoute)
{
String callId = "rayo-incoming-" + System.currentTimeMillis();
cp.setCallId(callId);
cp.setMediaPreference("PCMU/8000/1");
cp.setConferenceId(callId);
if (cp.getMediaPreference() == null) cp.setMediaPreference("PCMU/8000/1"); // regular phone
ConferenceManager conferenceManager = ConferenceManager.getConference(callId, cp.getMediaPreference(), cp.getToPhoneNumber(), false);
conferenceManager.setCallId(callId);
......@@ -1777,17 +1795,15 @@ public class RayoComponent extends AbstractComponent
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());
if (foundUser != null) // send this call to specific user
{
cp.setCallOwner(foundUser.toString());
routeSIPCall(foundUser, cp, callId, headers);
return true;
}
try {
Group group = GroupManager.getInstance().getGroup(cp.getToPhoneNumber());
} else {
conferenceManager.setGroupName(cp.getToPhoneNumber());
......@@ -1800,29 +1816,10 @@ public class RayoComponent extends AbstractComponent
routeSIPCall(session.getAddress(), cp, callId, headers);
}
}
return true;
} catch (GroupNotFoundException e) {
// Group not found
if (XMPPServer.getInstance().getMultiUserChatManager().getMultiUserChatService("conference").hasChatRoom(cp.getToPhoneNumber())) {
MUCRoom room = XMPPServer.getInstance().getMultiUserChatManager().getMultiUserChatService("conference").getChatRoom(cp.getToPhoneNumber());
if (room != null)
{
for (MUCRole role : room.getOccupants())
{
routeSIPCall(role.getUserAddress(), cp, callId, headers);
}
}
return true;
} else {
return false;
}
}
return canRoute;
}
public void routeSIPCall(JID callee, CallParticipant cp, String callId, Map<String, String> headers)
......
......@@ -91,7 +91,6 @@ public class RelayChannel {
private Integer lastAudioTimestamp = new Integer((int)0);
private long decoder = 0;
private long encoder = 0;
private final int sampleRate = 48000;
private final int frameSizeInMillis = 20;
private final int outputFrameSize = 2;
......@@ -297,22 +296,13 @@ public class RelayChannel {
encryptor2 = new Encryptor(SDPCryptoSuite.getEncryptionMode(handset.cryptoSuite), remoteCryptoKey, remoteCryptoSalt, localCryptoKey, localCryptoSalt);
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 (encoder == 0) Log.error( "Opus encoder creation error ");
if (decoder == 0 || encoder == 0)
if (decoder == 0)
{
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) {
......@@ -361,12 +351,6 @@ public class RelayChannel {
decoder = 0;
}
if (encoder != 0)
{
Opus.encoder_destroy(encoder);
encoder = 0;
}
SayCompleteEvent complete = new SayCompleteEvent();
complete.setReason(SayCompleteEvent.Reason.valueOf("SUCCESS"));
......@@ -445,7 +429,7 @@ public class RelayChannel {
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 {
......@@ -454,15 +438,9 @@ public class RelayChannel {
RTPPacket newPacket = RTPPacket.parseBytes(BitAssistant.bytesToArray(rtpData));
RTPPacket packet = RTPPacket.parseBytes(lastAudioPacket.getBytes());
if (handset.codec == null || "OPUS".equals(handset.codec))
if (opus != null)
{
byte[] input = AudioConversion.littleEndianIntsToBytes(in);
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.setPayload(BitAssistant.bytesToArray(opus));
packet.setTimestamp(getNextAudioTimestamp(Long.valueOf(48000)));
} else { // ULAW
......@@ -484,8 +462,8 @@ public class RelayChannel {
kt++;
if ( kt < 10 ) {
Log.info( "+++ " + in );
if ( kt < 20 ) {
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