- checkpoint: works with echo test
git-svn-id: http://bigbluebutton.googlecode.com/svn/trunk@3017 af16638f-c34d-0410-8cfa-b39d5352b314
This commit is contained in:
parent
74a1bb5789
commit
ef3385374a
@ -53,8 +53,20 @@ dependencies {
|
||||
|
||||
war.doLast {
|
||||
ant.unzip(src: war.archivePath, dest: "$buildDir/sip")
|
||||
ant.copy(file: "$buildDir/sip/WEB-INF/logback-sip.xml", todir: "$buildDir/sip/WEB-INF/classes")
|
||||
}
|
||||
|
||||
|
||||
task deploy() {
|
||||
def red5AppsDir = '/usr/share/red5/webapps'
|
||||
def sipDir = new File("${red5AppsDir}/sip")
|
||||
println "Deleting $sipDir"
|
||||
ant.delete(dir: sipDir)
|
||||
ant.mkdir(dir: sipDir)
|
||||
ant.copy(todir: sipDir) {
|
||||
fileset(dir: "$buildDir/sip")
|
||||
}
|
||||
}
|
||||
/*
|
||||
task deploy(type:Copy) {
|
||||
def red5AppsDir = '/usr/share/red5/webapps'
|
||||
def sipDir = new File("${red5AppsDir}/sip")
|
||||
@ -62,4 +74,5 @@ task deploy(type:Copy) {
|
||||
ant.delete(dir: sipDir)
|
||||
into(sipDir)
|
||||
from "$buildDir/sip"
|
||||
}
|
||||
}
|
||||
*/
|
@ -30,7 +30,6 @@ import org.red5.server.api.event.IEvent;
|
||||
import org.red5.server.api.stream.IBroadcastStream;
|
||||
import org.red5.server.api.stream.IStreamCodecInfo;
|
||||
import org.red5.server.api.stream.IStreamListener;
|
||||
import org.red5.server.api.stream.IVideoStreamCodec;
|
||||
import org.red5.server.api.stream.ResourceExistException;
|
||||
import org.red5.server.api.stream.ResourceNotFoundException;
|
||||
import org.red5.server.messaging.IMessageComponent;
|
||||
|
@ -29,7 +29,7 @@ public class CallStream {
|
||||
NellyToPcmTranscoder2 pTranscoder = new NellyToPcmTranscoder2(sipCodec);
|
||||
rtpSender = new RtpSender2(pTranscoder, socket, connInfo.getRemoteAddr(), connInfo.getRemotePort());
|
||||
printLog( "SIPAudioLauncher", "New audio receiver on " + connInfo.getLocalPort() + "." );
|
||||
|
||||
rtpSender.start();
|
||||
talkStream = new TalkStream(pTranscoder, rtpSender);
|
||||
listenStream = new ListenStream(scopeProvider.getScope());
|
||||
|
||||
|
@ -12,29 +12,16 @@ public class NellyToPcmTranscoder2 {
|
||||
|
||||
private static final int NELLYMOSER_DECODED_PACKET_SIZE = 256;
|
||||
private static final int NELLYMOSER_ENCODED_PACKET_SIZE = 64;
|
||||
/** Sip codec to be used on audio session */
|
||||
private Codec sipCodec = null;
|
||||
|
||||
private Codec sipCodec = null; // Sip codec to be used on audio session
|
||||
private Decoder decoder;
|
||||
private DecoderMap decoderMap;
|
||||
|
||||
// Temporary buffer with received PCM audio from FlashPlayer.
|
||||
float[] tempBuffer;
|
||||
|
||||
// Floats remaining on temporary buffer.
|
||||
int tempBufferRemaining = 0;
|
||||
|
||||
// Encoding buffer used to encode to final codec format;
|
||||
float[] encodingBuffer;
|
||||
|
||||
// Offset of encoding buffer.
|
||||
int encodingOffset = 0;
|
||||
|
||||
// Indicates whether the current asao buffer was processed.
|
||||
boolean asao_buffer_processed = false;
|
||||
|
||||
// Indicates whether the handling buffers have already
|
||||
// been initialized.
|
||||
boolean hasInitilializedBuffers = false;
|
||||
private DecoderMap decoderMap;
|
||||
float[] tempBuffer; // Temporary buffer with received PCM audio from FlashPlayer.
|
||||
int tempBufferRemaining = 0; // Floats remaining on temporary buffer.
|
||||
float[] encodingBuffer; // Encoding buffer used to encode to final codec format;
|
||||
int encodingOffset = 0; // Offset of encoding buffer.
|
||||
boolean asao_buffer_processed = false; // Indicates whether the current asao buffer was processed.
|
||||
boolean hasInitilializedBuffers = false; // Indicates whether the handling buffers have already been initialized.
|
||||
|
||||
public NellyToPcmTranscoder2(Codec sipCodec) {
|
||||
this.sipCodec = sipCodec;
|
||||
@ -63,7 +50,8 @@ public class NellyToPcmTranscoder2 {
|
||||
if ((tempBufferRemaining + encodingOffset) >= sipCodec.getOutgoingDecodedFrameSize()) {
|
||||
copyingSize = encodingBuffer.length - encodingOffset;
|
||||
|
||||
System.arraycopy(tempBuffer, tempBuffer.length-tempBufferRemaining, encodingBuffer, encodingOffset, copyingSize);
|
||||
System.arraycopy(tempBuffer, tempBuffer.length-tempBufferRemaining,
|
||||
encodingBuffer, encodingOffset, copyingSize);
|
||||
|
||||
encodingOffset = sipCodec.getOutgoingDecodedFrameSize();
|
||||
tempBufferRemaining -= copyingSize;
|
||||
@ -71,9 +59,9 @@ public class NellyToPcmTranscoder2 {
|
||||
}
|
||||
else {
|
||||
if (tempBufferRemaining > 0) {
|
||||
BufferUtils.floatBufferIndexedCopy(encodingBuffer, encodingOffset, tempBuffer,
|
||||
tempBuffer.length - tempBufferRemaining, tempBufferRemaining );
|
||||
|
||||
System.arraycopy(tempBuffer, tempBuffer.length - tempBufferRemaining,
|
||||
encodingBuffer, encodingOffset, tempBufferRemaining);
|
||||
|
||||
encodingOffset += tempBufferRemaining;
|
||||
finalCopySize += tempBufferRemaining;
|
||||
tempBufferRemaining = 0;
|
||||
@ -87,9 +75,6 @@ public class NellyToPcmTranscoder2 {
|
||||
//tempBuffer = ResampleUtils.normalize(tempBuffer, 256); // normalise volume
|
||||
tempBufferRemaining = tempBuffer.length;
|
||||
|
||||
//println( "fillRtpPacketBuffer",
|
||||
// "Decoded pcm " + tempBuffer.length + " floats." );
|
||||
|
||||
if ( tempBuffer.length <= 0 ) {
|
||||
log.error("Asao decoder Error." );
|
||||
}
|
||||
@ -102,8 +87,7 @@ public class NellyToPcmTranscoder2 {
|
||||
copyingSize = tempBufferRemaining;
|
||||
}
|
||||
|
||||
BufferUtils.floatBufferIndexedCopy(encodingBuffer, encodingOffset, tempBuffer,
|
||||
0, copyingSize );
|
||||
System.arraycopy(tempBuffer, 0, encodingBuffer, encodingOffset, copyingSize);
|
||||
|
||||
encodingOffset += copyingSize;
|
||||
tempBufferRemaining -= copyingSize;
|
||||
@ -115,7 +99,7 @@ public class NellyToPcmTranscoder2 {
|
||||
int encodedBytes = sipCodec.pcmToCodec( encodingBuffer, codedBuffer );
|
||||
|
||||
if ( encodedBytes == sipCodec.getOutgoingEncodedFrameSize() ) {
|
||||
BufferUtils.byteBufferIndexedCopy(transcodedData, dataOffset, codedBuffer, 0, codedBuffer.length );
|
||||
System.arraycopy(codedBuffer, 0, transcodedData, dataOffset, codedBuffer.length);
|
||||
}
|
||||
else {
|
||||
//println( "fillRtpPacketBuffer", "Failure encoding buffer." );
|
||||
@ -149,6 +133,7 @@ public class NellyToPcmTranscoder2 {
|
||||
}
|
||||
|
||||
if ( encodingOffset == sipCodec.getOutgoingDecodedFrameSize() ) {
|
||||
System.out.println("Send this audio to asterisk.");
|
||||
rtpSender.sendTranscodedData();
|
||||
encodingOffset = 0;
|
||||
}
|
||||
|
15
bbb-voice/src/main/java/org/red5/app/sip/RtmpAudioData.java
Normal file
15
bbb-voice/src/main/java/org/red5/app/sip/RtmpAudioData.java
Normal file
@ -0,0 +1,15 @@
|
||||
package org.red5.app.sip;
|
||||
|
||||
class RtmpAudioData {
|
||||
|
||||
private final byte[] audioData;
|
||||
|
||||
RtmpAudioData(byte[] data) {
|
||||
this.audioData = new byte[data.length];
|
||||
System.arraycopy(data, 0, this.audioData, 0, data.length);
|
||||
}
|
||||
|
||||
byte[] getData() {
|
||||
return audioData;
|
||||
}
|
||||
}
|
@ -35,7 +35,7 @@ public class RtpReceiver2 {
|
||||
rtpSocket = new RtpSocket(socket);
|
||||
}
|
||||
|
||||
initializeSocket();
|
||||
// initializeSocket();
|
||||
}
|
||||
|
||||
private void initializeSocket() {
|
||||
@ -85,9 +85,10 @@ public class RtpReceiver2 {
|
||||
+ ", length = " + payloadLength + "." );
|
||||
|
||||
System.arraycopy(packetBuffer, headerOffset, codedBuffer, 0, payloadLength);
|
||||
transcoder.transcode(codedBuffer);
|
||||
} catch (IOException e) {
|
||||
transcoder.transcode(codedBuffer);
|
||||
} catch (IOException e) {
|
||||
log.error("IOException while receiving rtp packets.");
|
||||
receivePackets = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,6 +154,7 @@ public class RtpSender {
|
||||
rtpPacket.setSequenceNumber( seqn++ );
|
||||
rtpPacket.setTimestamp( time );
|
||||
rtpPacket.setPayloadLength( transcoder.getOutgoingEncodedFrameSize() );
|
||||
|
||||
rtpSocketSend( rtpPacket );
|
||||
}
|
||||
|
||||
|
@ -3,15 +3,26 @@ package org.red5.app.sip;
|
||||
import local.net.RtpPacket;
|
||||
import local.net.RtpSocket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.red5.logging.Red5LoggerFactory;
|
||||
|
||||
public class RtpSender2 {
|
||||
protected static Logger log = Red5LoggerFactory.getLogger( RtpSender2.class, "sip" );
|
||||
private static Logger log = Red5LoggerFactory.getLogger( RtpSender2.class, "sip" );
|
||||
|
||||
public static int RTP_HEADER_SIZE = 12;
|
||||
private BlockingQueue<RtmpAudioData> packets = new LinkedBlockingQueue<RtmpAudioData>();
|
||||
private final Executor exec = Executors.newSingleThreadExecutor();
|
||||
private Runnable audioProcessor;
|
||||
private volatile boolean processAudio = false;
|
||||
|
||||
private static final int RTP_HEADER_SIZE = 12;
|
||||
private RtpSocket rtpSocket = null;
|
||||
|
||||
private boolean socketIsLocal = false;
|
||||
@ -23,7 +34,7 @@ public class RtpSender2 {
|
||||
private long timestamp = 0;
|
||||
private NellyToPcmTranscoder2 transcoder;
|
||||
|
||||
public RtpSender2(NellyToPcmTranscoder2 transcoder, DatagramSocket srcSocket, String destAddr, int destPort) {
|
||||
public RtpSender2(NellyToPcmTranscoder2 transcoder, DatagramSocket srcSocket, String destAddr, int destPort) throws UnknownHostException {
|
||||
this.transcoder = transcoder;
|
||||
if (srcSocket == null) {
|
||||
try {
|
||||
@ -34,6 +45,8 @@ public class RtpSender2 {
|
||||
}
|
||||
socketIsLocal = true;
|
||||
}
|
||||
|
||||
rtpSocket = new RtpSocket(srcSocket, InetAddress.getByName(destAddr), destPort);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
@ -113,13 +126,17 @@ public class RtpSender2 {
|
||||
}
|
||||
|
||||
public void send(byte[] asaoBuffer, int offset, int num) {
|
||||
System.out.println("Transcoding from Nelly to PCM");
|
||||
transcoder.transcode(asaoBuffer, offset, num, packetBuffer, RTP_HEADER_SIZE, this);
|
||||
}
|
||||
|
||||
public void sendTranscodedData() {
|
||||
rtpPacket.setSequenceNumber( sequenceNum++ );
|
||||
timestamp += transcoder.getOutgoingEncodedFrameSize();
|
||||
|
||||
rtpPacket.setTimestamp( timestamp );
|
||||
rtpPacket.setPayloadLength( transcoder.getOutgoingEncodedFrameSize() );
|
||||
System.out.println("Sending rtpPacket " + timestamp);
|
||||
rtpSocketSend( rtpPacket );
|
||||
}
|
||||
|
||||
|
@ -236,7 +236,7 @@ public class SipUserAgent extends CallListenerAdapter {
|
||||
callStream.stopTalkStream(broadcastStream, scope);
|
||||
}
|
||||
|
||||
protected void closeMediaApplication() {
|
||||
private void closeMediaApplication() {
|
||||
log.debug("closeMediaApplication" );
|
||||
|
||||
if (callStream != null) {
|
||||
|
@ -22,7 +22,7 @@ public class TalkStream {
|
||||
private final RtpSender2 rtpSender;
|
||||
private final IStreamListener mInputListener;
|
||||
|
||||
private BlockingQueue<IStreamPacket> packets = new LinkedBlockingQueue<IStreamPacket>();
|
||||
private BlockingQueue<RtmpAudioData> packets = new LinkedBlockingQueue<RtmpAudioData>();
|
||||
private final Executor exec = Executors.newSingleThreadExecutor();
|
||||
private Runnable audioProcessor;
|
||||
private volatile boolean processAudio = false;
|
||||
@ -42,14 +42,16 @@ public class TalkStream {
|
||||
|
||||
if (buf == null || buf.remaining() == 0){
|
||||
log.debug("skipping empty packet with no data");
|
||||
System.out.println("skipping empty packet with no data");
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet instanceof AudioData) {
|
||||
log.debug("adding packet type: {}; ts: {}; on stream: {}",
|
||||
new Object[]{"AUDIO", packet.getTimestamp(), broadcastStream.getPublishedName()});
|
||||
try {
|
||||
packets.put(packet);
|
||||
byte[] data = SerializeUtils.ByteBufferToByteArray(buf);
|
||||
RtmpAudioData audioData = new RtmpAudioData(data);
|
||||
System.out.println("Adding data " + data.length);
|
||||
packets.put(audioData);
|
||||
} catch (InterruptedException e) {
|
||||
log.info("Interrupted exception while queieing audio packet");
|
||||
}
|
||||
@ -67,7 +69,7 @@ public class TalkStream {
|
||||
public void run() {
|
||||
while (processAudio) {
|
||||
try {
|
||||
IStreamPacket packet = packets.take();
|
||||
RtmpAudioData packet = packets.take();
|
||||
processAudioPacket(packet);
|
||||
} catch (InterruptedException e) {
|
||||
log.info("InterruptedExeption while taking audio packet.");
|
||||
@ -78,9 +80,9 @@ public class TalkStream {
|
||||
exec.execute(audioProcessor);
|
||||
}
|
||||
|
||||
private void processAudioPacket(IStreamPacket packet) {
|
||||
IoBuffer audioData = ((AudioData)packet).getData().asReadOnlyBuffer();
|
||||
byte[] data = SerializeUtils.ByteBufferToByteArray(audioData);
|
||||
private void processAudioPacket(RtmpAudioData packet) {
|
||||
byte[] data = packet.getData();
|
||||
System.out.println("Proccessing voice data");
|
||||
rtpSender.send(data, 1, data.length-1);
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,26 @@
|
||||
package org.red5.app.sip;
|
||||
|
||||
public class TranscodedPcmAudioBuffer {
|
||||
|
||||
private byte[] buffer;
|
||||
private int offset;
|
||||
private RtpSender2 sender;
|
||||
|
||||
TranscodedPcmAudioBuffer(byte[] data, int offset, RtpSender2 sender) {
|
||||
buffer = data;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
boolean copyData(byte[] data) {
|
||||
if (data.length > buffer.length - offset)
|
||||
return false;
|
||||
|
||||
System.arraycopy(data, 0, buffer, offset, data.length);
|
||||
return true;
|
||||
}
|
||||
|
||||
void sendData() {
|
||||
sender.sendTranscodedData();
|
||||
}
|
||||
|
||||
}
|
@ -5,6 +5,7 @@ import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.red5.app.sip.RtmpConnection;
|
||||
import org.red5.app.sip.SipUserManager;
|
||||
import org.red5.app.sip.User;
|
||||
import org.red5.logging.Red5LoggerFactory;
|
||||
import org.red5.server.adapter.MultiThreadedApplicationAdapter;
|
||||
import org.red5.server.api.IClient;
|
||||
@ -25,6 +26,7 @@ public class VoiceConferenceApplication extends MultiThreadedApplicationAdapter
|
||||
private int startRTPPort = 3000;
|
||||
private int stopRTPPort = 3029;
|
||||
private int rtpPort;
|
||||
private String password = "secret";
|
||||
|
||||
private MessageFormat callExtensionPattern = new MessageFormat("{0}");
|
||||
|
||||
@ -89,14 +91,18 @@ public class VoiceConferenceApplication extends MultiThreadedApplicationAdapter
|
||||
log.debug( "Red5SIP Ping" );
|
||||
}
|
||||
|
||||
public void open(String uid, String username) {
|
||||
log.debug("Red5SIP open");
|
||||
login(uid, username);
|
||||
/******************************************************************/
|
||||
public void open(String obproxy,String uid, String phone,
|
||||
String username, String password, String realm, String proxy) {
|
||||
System.out.println("Red5SIP open");
|
||||
|
||||
login(obproxy, uid, phone, username, password, realm, proxy);
|
||||
register(uid);
|
||||
}
|
||||
|
||||
public void login(String uid, String username) {
|
||||
log.debug("Red5SIP login " + uid);
|
||||
public void login(String obproxy, String uid, String phone,
|
||||
String username, String password, String realm, String proxy) {
|
||||
System.out.println("Red5SIP login " + uid);
|
||||
IConnection conn = Red5.getConnectionLocal();
|
||||
IServiceCapableConnection service = (IServiceCapableConnection) conn;
|
||||
|
||||
@ -104,15 +110,35 @@ public class VoiceConferenceApplication extends MultiThreadedApplicationAdapter
|
||||
String userid = getSipUserId();
|
||||
sipManager.createSipUser(userid, rtmpConnection, sipPort, rtpPort);
|
||||
|
||||
sipManager.login(userid, obproxy, phone, username, password, realm, proxy);
|
||||
|
||||
sipPort++;
|
||||
if (sipPort > stopSIPPort) sipPort = startSIPPort;
|
||||
|
||||
rtpPort++;
|
||||
if (rtpPort > stopRTPPort) rtpPort = startRTPPort;
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
public void open(String uid, String username) {
|
||||
log.debug("Red5SIP open");
|
||||
login(uid, username);
|
||||
register(uid);
|
||||
}
|
||||
|
||||
public void login(String userid, String username) {
|
||||
log.debug("Red5SIP login " + userid);
|
||||
|
||||
/*
|
||||
* Let's tie this users account to the RTPPort. This allows us to dynamically
|
||||
* register a user when he/she joins the conference.
|
||||
*/
|
||||
String password = "secret";
|
||||
String realm = asteriskHost;
|
||||
|
||||
String realm = asteriskHost; //asteriskHost; "192.168.0.120";
|
||||
String proxy = realm;
|
||||
//SipUser will connect to "outbound-proxy", just pass-in the proxy for it.
|
||||
sipManager.login(userid, proxy, new Integer(rtpPort).toString(),username, password, realm, proxy);
|
||||
login(proxy, userid, new Integer(rtpPort).toString(), username, password, realm, proxy);
|
||||
|
||||
sipPort++;
|
||||
if (sipPort > stopSIPPort) sipPort = startSIPPort;
|
||||
@ -128,6 +154,7 @@ public class VoiceConferenceApplication extends MultiThreadedApplicationAdapter
|
||||
}
|
||||
|
||||
public void call(String uid, String destination) {
|
||||
destination = "600";
|
||||
log.debug("Red5SIP Call " + destination);
|
||||
String userid = getSipUserId();
|
||||
String extension = callExtensionPattern.format(new String[] { destination });
|
||||
|
@ -1,13 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
|
||||
<contextName>sip</contextName>
|
||||
|
||||
<jmxConfigurator contextName="sip" />
|
||||
|
||||
<appender name="SIP" class="ch.qos.logback.core.FileAppender">
|
||||
<File>log/sip.log</File>
|
||||
<Append>true</Append>
|
||||
<Append>false</Append>
|
||||
<Encoding>UTF-8</Encoding>
|
||||
<BufferedIO>false</BufferedIO>
|
||||
<ImmediateFlush>true</ImmediateFlush>
|
||||
@ -20,8 +15,6 @@
|
||||
<root>
|
||||
<level value="DEBUG" />
|
||||
<appender-ref ref="SIP" />
|
||||
</root>
|
||||
<logger name="org.red5.server.webapp.sip">
|
||||
<level value="DEBUG" />
|
||||
</logger>
|
||||
</root>
|
||||
</configuration>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user