You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@openmeetings.apache.org by co...@google.com on 2013/02/06 18:33:33 UTC

[red5phone] r71 committed - red5sip:...

Revision: 71
Author:   timur.tleukenov@gmail.com
Date:     Wed Feb  6 09:31:44 2013
Log:      red5sip:
1) Switch red5sip to RTPStreamMultiplexingSender.
2) Added per-stream jitter buffers.
http://code.google.com/p/red5phone/source/detail?r=71

Added:
  /branches/red5sip/src/java/org/red5/sip/app/IMediaStream.java
  /branches/red5sip/src/java/org/red5/sip/app/RTPStream.java
  /branches/red5sip/src/java/org/red5/sip/app/RTPStreamForMultiplex.java
Modified:
  /branches/red5sip/lib/red5sip.jar
  /branches/red5sip/red5sip.iml
  /branches/red5sip/src/java/org/red5/sip/app/IMediaSender.java
  /branches/red5sip/src/java/org/red5/sip/app/PlayNetStream.java
  /branches/red5sip/src/java/org/red5/sip/app/RTMPRoomClient.java
   
/branches/red5sip/src/java/org/red5/sip/app/RTPStreamMultiplexingSender.java
  /branches/red5sip/src/java/org/red5/sip/app/RTPStreamSender.java
  /branches/red5sip/src/java/org/red5/sip/app/SIPAudioLauncher.java

=======================================
--- /dev/null
+++ /branches/red5sip/src/java/org/red5/sip/app/IMediaStream.java	Wed Feb   
6 09:31:44 2013
@@ -0,0 +1,7 @@
+package org.red5.sip.app;
+
+public interface IMediaStream {
+
+    void send(long timestamp, byte[] asaoBuffer, int offset, int num);
+
+}
=======================================
--- /dev/null
+++ /branches/red5sip/src/java/org/red5/sip/app/RTPStream.java	Wed Feb  6  
09:31:44 2013
@@ -0,0 +1,171 @@
+package org.red5.sip.app;
+
+import local.net.RtpPacket;
+import org.red5.codecs.asao.ByteStream;
+import org.red5.logging.Red5LoggerFactory;
+import org.slf4j.Logger;
+
+public class RTPStream implements IMediaStream {
+
+    protected static Logger log =  
Red5LoggerFactory.getLogger(RTPStream.class, "sip");
+
+    private int streamId;
+    private RTPStreamSender sender;
+    private long syncSource;
+    private long timestamp;
+
+    /** Sip codec to be used on audio session */
+    private byte[] packetBuffer;
+    private RtpPacket rtpPacket;
+
+    // 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;
+
+    public RTPStream(int streamId, long syncSource, RTPStreamSender  
sender) {
+        this.streamId = streamId;
+        this.syncSource = syncSource;
+        this.sender = sender;
+        this.packetBuffer = new byte[  
sender.sipCodec.getOutgoingEncodedFrameSize() +  
RTPStreamSender.RTP_HEADER_SIZE ];
+        this.rtpPacket = new RtpPacket( this.packetBuffer, 0 );
+        this.rtpPacket.setPayloadType( sender.sipCodec.getCodecId() );
+        this.tempBuffer = new float[  
RTPStreamSender.NELLYMOSER_DECODED_PACKET_SIZE ];
+        this.encodingBuffer = new float[  
sender.sipCodec.getOutgoingDecodedFrameSize() ];
+    }
+
+    public void send(long timestamp, byte[] asaoBuffer, int offset, int  
num) {
+        if(RTPStreamSender.useASAO) {
+            sendASAO(asaoBuffer, offset, num);
+        } else {
+            sendRaw(asaoBuffer, offset, num);
+        }
+    }
+
+    public void sendRaw(byte[] asaoInput, int offset, int num ) {
+        System.arraycopy(asaoInput, offset, packetBuffer,  
RTPStreamSender.RTP_HEADER_SIZE, num);
+        rtpPacket.setSscr(syncSource);
+        rtpPacket.setTimestamp( timestamp );
+        rtpPacket.setPayloadLength(  
sender.sipCodec.getOutgoingEncodedFrameSize() );
+        sender.send(rtpPacket);
+    }
+
+    public void sendASAO(byte[] asaoBuffer, int offset, int num) {
+        asao_buffer_processed = false;
+
+        if ( num > 0 ) {
+            do {
+                int encodedBytes = fillRtpPacketBuffer( asaoBuffer );
+                if ( encodedBytes == 0 ) {
+                    break;
+                }
+                if ( encodingOffset ==  
sender.sipCodec.getOutgoingDecodedFrameSize() ) {
+                    try {
+                        rtpPacket.setSscr(syncSource);
+                        rtpPacket.setTimestamp(timestamp);
+                         
rtpPacket.setPayloadLength(sender.sipCodec.getOutgoingEncodedFrameSize());
+                        sender.send(rtpPacket);
+                        timestamp +=  
sender.sipCodec.getOutgoingPacketization();
+                    }
+                    catch ( Exception e ) {
+                        log.error( "sendASAO: " +  
sender.sipCodec.getCodecName() + " encoder error.", e );
+                    }
+                    encodingOffset = 0;
+                }
+            }
+            while ( !asao_buffer_processed );
+        }
+    }
+
+    /** Fill the buffer of RtpPacket with necessary data. */
+    private int fillRtpPacketBuffer(byte[] asaoBuffer) {
+
+        boolean isBufferFilled = false;
+        int copyingSize = 0;
+        int finalCopySize = 0;
+        byte[] codedBuffer = new byte[  
sender.sipCodec.getOutgoingEncodedFrameSize() ];
+
+        try {
+            if ( ( tempBufferRemaining + encodingOffset ) >=  
sender.sipCodec.getOutgoingDecodedFrameSize() ) {
+
+                copyingSize = encodingBuffer.length - encodingOffset;
+
+                BufferUtils.floatBufferIndexedCopy(
+                        encodingBuffer,
+                        encodingOffset,
+                        tempBuffer,
+                        tempBuffer.length - tempBufferRemaining,
+                        copyingSize );
+
+                encodingOffset =  
sender.sipCodec.getOutgoingDecodedFrameSize();
+                tempBufferRemaining -= copyingSize;
+                finalCopySize =  
sender.sipCodec.getOutgoingDecodedFrameSize();
+
+                //println( "fillRtpPacketBuffer", "Simple copy of " +  
copyingSize + " bytes." );
+            }
+            else {
+                if ( tempBufferRemaining > 0 ) {
+                    BufferUtils.floatBufferIndexedCopy(
+                            encodingBuffer,
+                            encodingOffset,
+                            tempBuffer,
+                            tempBuffer.length - tempBufferRemaining,
+                            tempBufferRemaining );
+
+                    encodingOffset += tempBufferRemaining;
+                    finalCopySize += tempBufferRemaining;
+                    tempBufferRemaining = 0;
+                }
+
+                // Decode new asao packet.
+
+                asao_buffer_processed = true;
+
+                ByteStream audioStream = new ByteStream( asaoBuffer, 1,  
RTPStreamSender.NELLYMOSER_ENCODED_PACKET_SIZE );
+
+                sender.decoderMap = sender.decoder.decode(  
sender.decoderMap, audioStream.bytes, 1, tempBuffer, 0 );
+
+                tempBufferRemaining = tempBuffer.length;
+
+                if ( ( encodingOffset + tempBufferRemaining ) >  
sender.sipCodec.getOutgoingDecodedFrameSize() ) {
+                    copyingSize = encodingBuffer.length - encodingOffset;
+                }
+                else {
+                    copyingSize = tempBufferRemaining;
+                }
+
+                BufferUtils.floatBufferIndexedCopy(
+                        encodingBuffer,
+                        encodingOffset,
+                        tempBuffer,
+                        0,
+                        copyingSize );
+
+                encodingOffset += copyingSize;
+                tempBufferRemaining -= copyingSize;
+                finalCopySize += copyingSize;
+            }
+
+            if (encodingOffset == encodingBuffer.length)
+            {
+                isBufferFilled = true;
+                int encodedBytes = sender.sipCodec.pcmToCodec(  
encodingBuffer, codedBuffer );
+                if ( encodedBytes ==  
sender.sipCodec.getOutgoingEncodedFrameSize() ) {
+                    BufferUtils.byteBufferIndexedCopy( packetBuffer,
+                            RTPStreamSender.RTP_HEADER_SIZE, codedBuffer,  
0, codedBuffer.length );
+                }
+            }
+        }
+        catch ( Exception e ) {
+            e.printStackTrace();
+        }
+
+        return finalCopySize;
+    }
+}
=======================================
--- /dev/null
+++ /branches/red5sip/src/java/org/red5/sip/app/RTPStreamForMultiplex.java	 
Wed Feb  6 09:31:44 2013
@@ -0,0 +1,73 @@
+package org.red5.sip.app;
+
+import org.red5.logging.Red5LoggerFactory;
+import org.slf4j.Logger;
+
+public class RTPStreamForMultiplex implements IMediaStream {
+    protected static Logger log =  
Red5LoggerFactory.getLogger(RTPStreamForMultiplex.class, "sip");
+
+    private int streamId;
+    private RTPStreamMultiplexingSender sender;
+    private long syncSource;
+    private static int BUFFERS_COUNT = 1024;
+    private byte[][] buffer = new byte[BUFFERS_COUNT][65];
+    private int[] bufLen = new int[BUFFERS_COUNT];
+    private int start, end;
+    private boolean ready = false;
+
+    protected RTPStreamForMultiplex(int streamId, long syncSource,  
RTPStreamMultiplexingSender sender) {
+        this.streamId = streamId;
+        this.sender = sender;
+        this.syncSource = syncSource;
+        end = 0;
+        start = -1;
+    }
+
+    public int getStreamId() {
+        return streamId;
+    }
+
+    public synchronized void send(long timestamp, byte[] asaoBuffer, int  
offset, int num) {
+        if(end == start) {
+            log.error("Stream buffer overflow: streamId: " + streamId + ",  
start: " + start + ", end: " + end);
+            return;
+        }
+        System.arraycopy(asaoBuffer, 0, buffer[end], 0, asaoBuffer.length);
+        bufLen[end++] = num;
+        if(end == BUFFERS_COUNT) {
+            end = 0;
+        }
+        if(start == -1) {
+            start = 0;
+        }
+
+        if(!ready && available() > 10) {
+            ready = true;
+        }
+    }
+
+    protected synchronized int available() {
+        return (end > start) ? (end - start) : (BUFFERS_COUNT - start +  
end);
+    }
+
+    protected synchronized boolean ready() {
+        return ready;
+    }
+
+    protected synchronized int read(byte[] dst, int offset) {
+        int res = -1;
+        if(start >= 0) {
+            System.arraycopy(buffer[start], 0, dst, offset, dst.length);
+            res = start++;
+            if(start == BUFFERS_COUNT) {
+                start = 0;
+            }
+            if(start == end) {
+                start = -1;
+                end = 0;
+                ready = false;
+            }
+        }
+        return res;
+    }
+}
=======================================
--- /branches/red5sip/lib/red5sip.jar	Tue Jan 29 03:52:07 2013
+++ /branches/red5sip/lib/red5sip.jar	Wed Feb  6 09:31:44 2013
Binary file, no diff available.
=======================================
--- /branches/red5sip/red5sip.iml	Mon Feb  4 23:34:05 2013
+++ /branches/red5sip/red5sip.iml	Wed Feb  6 09:31:44 2013
@@ -512,6 +512,7 @@
        </library>
      </orderEntry>
      <orderEntry type="library" name="lib" level="project" />
+    <orderEntry type="library" name="Unnamed" level="project" />
    </component>
  </module>

=======================================
--- /branches/red5sip/src/java/org/red5/sip/app/IMediaSender.java	Fri Feb  
10 07:37:46 2012
+++ /branches/red5sip/src/java/org/red5/sip/app/IMediaSender.java	Wed Feb   
6 09:31:44 2013
@@ -2,7 +2,9 @@

  public interface IMediaSender {

-    void send(int streamId, byte[] asaoBuffer, int offset, int num);
+    IMediaStream createStream(int streamId);
+
+    void deleteStream(int streamId);

      void start();

=======================================
--- /branches/red5sip/src/java/org/red5/sip/app/PlayNetStream.java	Fri Feb  
10 07:37:46 2012
+++ /branches/red5sip/src/java/org/red5/sip/app/PlayNetStream.java	Wed Feb   
6 09:31:44 2013
@@ -11,6 +11,9 @@
  import org.red5.server.stream.AbstractClientStream;
  import org.red5.server.stream.IStreamData;
  import org.slf4j.Logger;
+import org.zoolu.tools.Random;
+
+import java.util.concurrent.atomic.AtomicLong;

  public class PlayNetStream extends AbstractClientStream implements  
IEventDispatcher {

@@ -18,32 +21,30 @@

      private int audioTs = 0;

-    private int kt = 0;
+    private IMediaSender mediaSender;

-    private int kt2 = 0;
-
-    private IMediaSender mediaSender;
+    private IMediaStream mediaStream;

      public PlayNetStream(IMediaSender mediaSender) {
          this.mediaSender = mediaSender;
-        if(mediaSender instanceof RTPStreamMultiplexingSender) {
-            ((RTPStreamMultiplexingSender) mediaSender).streamAdded();
-        }
      }
-
-

      public void close() {
-
+        if(mediaSender != null) {
+            mediaSender.deleteStream(getStreamId());
+        }
      }
-

      public void start() {
-
+        if(mediaSender != null) {
+            mediaStream = mediaSender.createStream(getStreamId());
+        }
      }

      public void stop() {
-
+        if(mediaSender != null) {
+            mediaSender.deleteStream(getStreamId());
+        }
      }

      public void dispatchEvent(IEvent event) {
@@ -55,11 +56,6 @@

          IRTMPEvent rtmpEvent = (IRTMPEvent) event;

-        if (logger.isDebugEnabled()) {
-            // logger.debug("rtmp event: " + rtmpEvent.getHeader() + ", " +
-            // rtmpEvent.getClass().getSimpleName());
-        }
-
          if (!(rtmpEvent instanceof IStreamData)) {
              logger.debug("skipping non stream data");
              return;
@@ -75,28 +71,18 @@
              // tag.setTimestamp(videoTs);

          } else if (rtmpEvent instanceof AudioData) {
-            audioTs += rtmpEvent.getTimestamp();
+            audioTs = rtmpEvent.getTimestamp();

              IoBuffer audioData = ((IStreamData)  
rtmpEvent).getData().asReadOnlyBuffer();
              byte[] data = SerializeUtils.ByteBufferToByteArray(audioData);
-
-            //System.out.println( "RTMPUser.dispatchEvent() - AudioData ->  
length = " + data.length + ".");
-
-            kt2++;
-
-            if (kt2 < 10) {
-                logger.debug("*** " + data.length);
-                System.out.println("*** " + data.length);
-            }

              try {
-                if (mediaSender != null) {
-                    mediaSender.send(getStreamId(), data, 1, data.length -  
1);
+                if(mediaStream != null) {
+                    mediaStream.send(audioTs, data, 1, data.length - 1);
                  }
              } catch (Exception e) {
                  System.out.println("PlayNetStream dispatchEvent  
exception " + e);
              }
-
          }
      }
  }
=======================================
--- /branches/red5sip/src/java/org/red5/sip/app/RTMPRoomClient.java	Tue Jan  
29 03:52:07 2013
+++ /branches/red5sip/src/java/org/red5/sip/app/RTMPRoomClient.java	Wed  
Feb  6 09:31:44 2013
@@ -2,7 +2,7 @@

  import org.apache.mina.core.RuntimeIoException;
  import org.apache.mina.core.buffer.IoBuffer;
-import org.apache.openmeetings.persistence.beans.rooms.Client;
+import org.apache.openmeetings.persistence.beans.room.Client;
  import org.red5.io.utils.ObjectMap;
  import org.red5.server.api.IScope;
  import org.red5.server.api.event.IEvent;
@@ -31,7 +31,7 @@
      private static final int MAX_RETRY_NUMBER = 100;
      private static final int UPDATE_MS = 10000;

-    private List<Integer> broadcastIds = new ArrayList<Integer>();
+    private Set<Integer> broadcastIds = new HashSet<Integer>();
      private Map<Long,Integer> clientStreamMap = new HashMap<Long,  
Integer>();
      private String publicSID = null;
      private long broadCastId = -1;
@@ -170,6 +170,7 @@
                  stream.setStreamId(streamIdInt.intValue());
                  conn.addClientStream(stream);
                  play(streamIdInt, "" + broadCastId, -2000, -1000);
+                stream.start();
              }
          }

@@ -193,7 +194,6 @@

      protected void startStreaming() {
          //red5 -> SIP
-        //createPlayStream(56);
          for(long broadCastId: broadcastIds) {
              if(broadCastId != this.broadCastId) {
                  createPlayStream(broadCastId);
@@ -306,14 +306,6 @@
          this.micMuted = !client.getPublicSID().equals(this.publicSID);
          log.info("Mic switched: " + this.micMuted);
      }
-
-    public void receiveMicMuteSwitched(Client client) {
-        log.debug("receiveMicMuteSwitched:" + client.getPublicSID());
-        if(client.getPublicSID().equals(this.publicSID)) {
-            log.info("Mic switched: " + client.getMicMuted());
-            this.micMuted = client.getMicMuted();
-        }
-    }

      public void sendVarsToMessageWithClient(Object message) {
          if(message instanceof Map) {
@@ -337,11 +329,10 @@
          log.debug("closeStream:" + client.getBroadCastID());
          Integer streamId = clientStreamMap.get(client.getBroadCastID());
          if(streamId != null) {
-            if(sender instanceof RTPStreamMultiplexingSender) {
-                ((RTPStreamMultiplexingSender) sender).streamRemoved();
-            }
              clientStreamMap.remove(client.getBroadCastID());
+            conn.getStreamById(streamId).stop();
              conn.removeClientStream(streamId);
+            conn.deleteStreamById(streamId);
          }
      }

=======================================
---  
/branches/red5sip/src/java/org/red5/sip/app/RTPStreamMultiplexingSender.java	 
Tue Jan 29 03:52:07 2013
+++  
/branches/red5sip/src/java/org/red5/sip/app/RTPStreamMultiplexingSender.java	 
Wed Feb  6 09:31:44 2013
@@ -2,6 +2,7 @@

  import local.net.RtpPacket;
  import local.net.RtpSocket;
+import org.apache.mina.util.ConcurrentHashSet;
  import org.red5.codecs.SIPCodec;
  import org.red5.codecs.asao.ByteStream;
  import org.red5.codecs.asao.Decoder;
@@ -9,8 +10,10 @@
  import org.red5.logging.Red5LoggerFactory;
  import org.slf4j.Logger;

+import java.lang.ref.WeakReference;
  import java.net.DatagramSocket;
  import java.net.InetAddress;
+import java.util.*;

  public class RTPStreamMultiplexingSender implements IMediaSender, Runnable  
{
      protected static Logger log =  
Red5LoggerFactory.getLogger(RTPStreamMultiplexingSender.class, "sip");
@@ -23,7 +26,9 @@

      RtpSocket rtpSocket = null;

-    /** Sip codec to be used on audio session */
+    /**
+     * Sip codec to be used on audio session
+     */
      protected SIPCodec sipCodec = null;

      boolean socketIsLocal = false;
@@ -41,20 +46,25 @@
      private int seqn = 0;

      private long time = 0;
+    private long syncSource = 0;

      // Temporary buffer with received PCM audio from FlashPlayer.
      float[] tempBuffer;

-    int[] multiplexedStreams;
      float[] decodedBuffer1;
      float[] decodedBuffer2;
-    long sendInterval = 0;

      volatile int multiplexingCount = 0;

-    int streamsCount = 0;
+    private Thread sendThread = new Thread(this);

-    private Thread sendThread;
+    ConcurrentHashSet<WeakReference<RTPStreamForMultiplex>> streamSet =  
new ConcurrentHashSet<WeakReference<RTPStreamForMultiplex>>();
+    //Set<RTPStreamForMultiplex> streamSet =  
Collections.synchronizedSet(new WeakHashSet<RTPStreamForMultiplex>());
+
+    private static int SEND_BUFFER_MAX = 100;
+    private byte[][] sendBuffer = new byte[SEND_BUFFER_MAX][];
+    private int[] sendBufferLength = new int[SEND_BUFFER_MAX];
+    private int sendBufferPos = 0;

      // Floats remaining on temporary buffer.
      int tempBufferRemaining = 0;
@@ -72,32 +82,26 @@
      // been initialized.
      boolean hasInitilializedBuffers = false;

-
      /**
       * Constructs a RtpStreamSender.
       *
-     * @param mediaReceiver
-     *            the RTMP stream source
-     * @param do_sync
-     *            whether time synchronization must be performed by the
-     *            RtpStreamSender, or it is performed by the InputStream  
(e.g.
-     *            the system audio input)
-     * @param sipCodec
-     *            codec to be used on audio session
-     * @param dest_addr
-     *            the destination address
-     * @param dest_port
-     *            the destination port
+     * @param mediaReceiver the RTMP stream source
+     * @param do_sync       whether time synchronization must be performed  
by the
+     *                      RtpStreamSender, or it is performed by the  
InputStream (e.g.
+     *                      the system audio input)
+     * @param sipCodec      codec to be used on audio session
+     * @param dest_addr     the destination address
+     * @param dest_port     the destination port
       */

      public RTPStreamMultiplexingSender(
-        IMediaReceiver mediaReceiver,
-        boolean do_sync,
-        SIPCodec sipCodec,
-        String dest_addr,
-        int dest_port ) {
+            IMediaReceiver mediaReceiver,
+            boolean do_sync,
+            SIPCodec sipCodec,
+            String dest_addr,
+            int dest_port) {

-        init( mediaReceiver, do_sync, sipCodec, null, dest_addr, dest_port  
);
+        init(mediaReceiver, do_sync, sipCodec, null, dest_addr, dest_port);
      }


@@ -125,136 +129,188 @@
      // {
      // init( mediaReceiver, do_sync, payloadType, frame_rate, frame_size,  
null, src_port, dest_addr, dest_port);
      // }
+
      /**
       * Constructs a RtpStreamSender.
       *
-     * @param mediaReceiver
-     *            the RTMP stream source
-     * @param do_sync
-     *            whether time synchronization must be performed by the
-     *            RtpStreamSender, or it is performed by the InputStream  
(e.g.
-     *            the system audio input)
-     * @param sipCodec
-     *            codec to be used on audio session
-     * @param src_socket
-     *            the socket used to send the RTP packet
-     * @param dest_addr
-     *            the destination address
-     * @param dest_port
-     *            the thestination port
+     * @param mediaReceiver the RTMP stream source
+     * @param do_sync       whether time synchronization must be performed  
by the
+     *                      RtpStreamSender, or it is performed by the  
InputStream (e.g.
+     *                      the system audio input)
+     * @param sipCodec      codec to be used on audio session
+     * @param src_socket    the socket used to send the RTP packet
+     * @param dest_addr     the destination address
+     * @param dest_port     the thestination port
       */
      public RTPStreamMultiplexingSender(
-        IMediaReceiver mediaReceiver,
-        boolean do_sync,
-        SIPCodec sipCodec,
-        DatagramSocket src_socket,
-        String dest_addr,
-        int dest_port ) {
+            IMediaReceiver mediaReceiver,
+            boolean do_sync,
+            SIPCodec sipCodec,
+            DatagramSocket src_socket,
+            String dest_addr,
+            int dest_port) {

-        init( mediaReceiver, do_sync, sipCodec, src_socket, dest_addr,  
dest_port );
+        init(mediaReceiver, do_sync, sipCodec, src_socket, dest_addr,  
dest_port);
      }


-    /** Inits the RtpStreamSender */
+    /**
+     * Inits the RtpStreamSender
+     */
      private void init(
-        IMediaReceiver mediaReceiver,
-        boolean do_sync,
-        SIPCodec sipCodec,
-        DatagramSocket src_socket,
-        String dest_addr,
-        int dest_port ) {
+            IMediaReceiver mediaReceiver,
+            boolean do_sync,
+            SIPCodec sipCodec,
+            DatagramSocket src_socket,
+            String dest_addr,
+            int dest_port) {

          mediaReceiver.setSender(this);
          this.sipCodec = sipCodec;
          this.doSync = do_sync;
+        this.sendBufferPos = 0;
+
+        for(int i=0; i<SEND_BUFFER_MAX; i++) {
+            sendBuffer[i] = new  
byte[sipCodec.getOutgoingEncodedFrameSize() + RTP_HEADER_SIZE];
+        }

          try {
-            if ( src_socket == null ) {
+            if (src_socket == null) {

                  src_socket = new DatagramSocket();
                  socketIsLocal = true;
              }

-            rtpSocket = new RtpSocket( src_socket,  
InetAddress.getByName(dest_addr), dest_port );
-        }
-        catch ( Exception e ) {
+            rtpSocket = new RtpSocket(src_socket,  
InetAddress.getByName(dest_addr), dest_port);
+        } catch (Exception e) {
              e.printStackTrace();
          }
      }
-
-    public void streamAdded() {
-        this.streamsCount++;
-    }
-
-    public void streamRemoved() {
-        this.streamsCount--;
-    }

      public void start() {
-
-        packetBuffer = new byte[ sipCodec.getOutgoingEncodedFrameSize() +  
RTP_HEADER_SIZE ];
-        rtpPacket = new RtpPacket( packetBuffer, 0 );
-        rtpPacket.setPayloadType( sipCodec.getCodecId() );
+        packetBuffer = new byte[sipCodec.getOutgoingEncodedFrameSize() +  
RTP_HEADER_SIZE];
+        rtpPacket = new RtpPacket(packetBuffer, 0);
+        rtpPacket.setPayloadType(sipCodec.getCodecId());

          seqn = 0;
          time = 0;
+        syncSource = 0;

-        println( "start()", "using blocks of " + ( packetBuffer.length -  
RTP_HEADER_SIZE ) + " bytes." );
+        println("start()", "using blocks of " + (packetBuffer.length -  
RTP_HEADER_SIZE) + " bytes.");

          decoder = new Decoder();
          decoderMap = null;

-        sendThread = new Thread(this);
-        sendInterval = System.currentTimeMillis();
          sendThread.start();
      }

      private void fillDecodedBuffer(byte[] asaoBuffer, float[] tempBuffer) {
-        ByteStream audioStream = new ByteStream( asaoBuffer, 1,  
NELLYMOSER_ENCODED_PACKET_SIZE );
-        decoderMap = decoder.decode( decoderMap, audioStream.bytes, 1,  
tempBuffer, 0 );
+        ByteStream audioStream = new ByteStream(asaoBuffer, 1,  
NELLYMOSER_ENCODED_PACKET_SIZE);
+        decoderMap = decoder.decode(decoderMap, audioStream.bytes, 1,  
tempBuffer, 0);
+        //ResampleUtils.normalize(tempBuffer, tempBuffer.length);
      }

-    public void send(int streamId, byte[] asaoBuffer, int offset, int num)  
{
-        boolean bufferAvailable = false;
-        do {
-            synchronized (this) {
-                bufferAvailable = multiplexingCount < streamsCount;
-                for(int i=0; i<multiplexingCount; i++) {
-                    bufferAvailable = bufferAvailable && streamId !=  
multiplexedStreams[i];
-                }
+    public synchronized IMediaStream createStream(int streamId) {
+        RTPStreamForMultiplex stream = new RTPStreamForMultiplex(streamId,  
syncSource, this);
+        streamSet.add(new WeakReference<RTPStreamForMultiplex>(stream));
+        return stream;
+    }
+
+    public void deleteStream(int streamId) {
+        for (Iterator<WeakReference<RTPStreamForMultiplex>> iterator =  
streamSet.iterator(); iterator.hasNext(); ) {
+            WeakReference<RTPStreamForMultiplex> ref = iterator.next();
+            if (ref.get() != null && ref.get().getStreamId() == streamId )  
{
+                iterator.remove();
              }
-            try {
-                if(bufferAvailable) {
-                    fillDecodedBuffer(asaoBuffer, decodedBuffer1);
-                    synchronized (this) {
-                        if(multiplexingCount != 0) {
-                            ResampleUtils.multiplex(decodedBuffer2,  
decodedBuffer1);
+        }
+    }
+
+    private void doRtpDelay() {
+        try {
+            Thread.sleep( sipCodec.getOutgoingPacketization() - 2);
+        }
+        catch ( Exception e ) {
+        }
+    }
+
+    public void run() {
+        if (!hasInitilializedBuffers) {
+            tempBuffer = new float[NELLYMOSER_DECODED_PACKET_SIZE];
+            decodedBuffer1 = new float[NELLYMOSER_DECODED_PACKET_SIZE];
+            decodedBuffer2 = new float[NELLYMOSER_DECODED_PACKET_SIZE];
+            encodingBuffer = new  
float[sipCodec.getOutgoingDecodedFrameSize()];
+            multiplexingCount = 0;
+            hasInitilializedBuffers = true;
+        }
+        byte[] asaoBuffer = new byte[65];
+        while(rtpSocket != null) {
+            multiplexingCount = 0;
+            for(Iterator<WeakReference<RTPStreamForMultiplex>> i =  
streamSet.iterator(); i.hasNext();) {
+                int len = -1;
+                WeakReference<RTPStreamForMultiplex> ref = i.next();
+                RTPStreamForMultiplex stream = ref.get();
+                if(stream != null) {
+                    synchronized (stream) {
+                        System.out.println(String.format("Stream id %d,  
avail %d", stream.getStreamId(), stream.available()));
+                        if(stream != null && stream.ready()) {
+                            len = stream.read(asaoBuffer, 0);
                          } else {
-                             
BufferUtils.floatBufferIndexedCopy(decodedBuffer2, 0, decodedBuffer1, 0,  
decodedBuffer1.length);
+                            break;
                          }
-                        multiplexedStreams[multiplexingCount++] = streamId;
                      }
-                    //System.out.println("Multiplex: " + multiplexingCount  
+ "("+streamId+")");
                  } else {
-                    Thread.yield();
+                    i.remove();
+                    break;
+                }
+                if(len != -1) {
+                    fillDecodedBuffer(asaoBuffer, decodedBuffer1);
+                    if (multiplexingCount > 0) {
+                        ResampleUtils.multiplex(decodedBuffer2,  
decodedBuffer1);
+                    } else {
+                        BufferUtils.floatBufferIndexedCopy(decodedBuffer2,  
0, decodedBuffer1, 0, decodedBuffer1.length);
+                    }
+                    multiplexingCount++;
+                    //System.out.println("Multiplex stream: " + streamId);
+                }
+                Thread.yield();
+            }
+            if(multiplexingCount > 0) {
+                //System.out.println("Send: multiplexed: " +  
multiplexingCount + ", total streams: " + streamSet.size());
+                ResampleUtils.normalize(decodedBuffer2,  
decodedBuffer2.length);
+                try {
+                    asao_buffer_processed = false;
+                    do {
+                        int encodedBytes = fillRtpPacketBuffer();
+                        if (encodedBytes == 0) {
+                            break;
+                        }
+                        if (encodingOffset ==  
sipCodec.getOutgoingDecodedFrameSize()) {
+                            rtpSocketSend(rtpPacket);
+                            doRtpDelay();
+                            encodingOffset = 0;
+                        }
+                    }
+                    while (!asao_buffer_processed);
+                } catch (Exception e) {
+                    log.error("Error preparing RTP packet", e);
                  }
-            } catch (Exception e) {
-                log.debug("Send error : ", e);
              }

-        } while (!bufferAvailable);
+        }
      }

-    /** Fill the buffer of RtpPacket with necessary data. */
+    /**
+     * Fill the buffer of RtpPacket with necessary data.
+     */
      private int fillRtpPacketBuffer() {

          int copyingSize = 0;
          int finalCopySize = 0;
-        byte[] codedBuffer = new byte[  
sipCodec.getOutgoingEncodedFrameSize() ];
+        byte[] codedBuffer = new  
byte[sipCodec.getOutgoingEncodedFrameSize()];

          try {

-            if ( ( tempBufferRemaining + encodingOffset ) >=  
sipCodec.getOutgoingDecodedFrameSize() ) {
+            if ((tempBufferRemaining + encodingOffset) >=  
sipCodec.getOutgoingDecodedFrameSize()) {

                  copyingSize = encodingBuffer.length - encodingOffset;

@@ -263,22 +319,19 @@
                          encodingOffset,
                          tempBuffer,
                          tempBuffer.length - tempBufferRemaining,
-                        copyingSize );
+                        copyingSize);

                  encodingOffset = sipCodec.getOutgoingDecodedFrameSize();
                  tempBufferRemaining -= copyingSize;
                  finalCopySize = sipCodec.getOutgoingDecodedFrameSize();
-
-                //println( "fillRtpPacketBuffer", "Simple copy of " +  
copyingSize + " bytes." );
-            }
-            else {
-                if ( tempBufferRemaining > 0 ) {
+            } else {
+                if (tempBufferRemaining > 0) {
                      BufferUtils.floatBufferIndexedCopy(
                              encodingBuffer,
                              encodingOffset,
                              tempBuffer,
                              tempBuffer.length - tempBufferRemaining,
-                            tempBufferRemaining );
+                            tempBufferRemaining);

                      encodingOffset += tempBufferRemaining;
                      finalCopySize += tempBufferRemaining;
@@ -289,46 +342,21 @@
                  // Decode new asao packet.

                  asao_buffer_processed = true;
-
-                boolean bufferAvailable = false;
-                int waitCount = 0;
-                do {
-                    if(multiplexingCount != 0) {
-                        synchronized (this) {
-                            bufferAvailable = multiplexingCount ==  
streamsCount || waitCount++ > streamsCount;
-                            if(bufferAvailable) {
-//                                System.out.println("waitCount:" +  
waitCount);
-                                multiplexingCount = 0;
-                                waitCount = 0;
-                                 
BufferUtils.floatBufferIndexedCopy(tempBuffer, 0, decodedBuffer2, 0,  
decodedBuffer2.length);
-                            }
-                        }
-                    }
-                    if(!bufferAvailable) {
-                        Thread.sleep(5);
-                    }
-                } while (!bufferAvailable);
-                long tmp = System.currentTimeMillis() - sendInterval;
-                if(tmp > 50) {
-                    System.out.println("Send: " + tmp);
-                }
-                sendInterval = System.currentTimeMillis();
-
+                BufferUtils.floatBufferIndexedCopy(tempBuffer, 0,  
decodedBuffer2, 0, decodedBuffer2.length);
  //                tempBuffer = ResampleUtils.normalize(tempBuffer, 256); 	 
// normalise volume

                  tempBufferRemaining = tempBuffer.length;

-                if ( tempBuffer.length <= 0 ) {
+                if (tempBuffer.length <= 0) {

-                    println( "fillRtpPacketBuffer", "Asao decoder Error."  
);
+                    println("fillRtpPacketBuffer", "Asao decoder Error.");
                  }

                  // Try to complete the encodingBuffer with necessary data.

-                if ( ( encodingOffset + tempBufferRemaining ) >  
sipCodec.getOutgoingDecodedFrameSize() ) {
+                if ((encodingOffset + tempBufferRemaining) >  
sipCodec.getOutgoingDecodedFrameSize()) {
                      copyingSize = encodingBuffer.length - encodingOffset;
-                }
-                else {
+                } else {
                      copyingSize = tempBufferRemaining;
                  }

@@ -337,93 +365,29 @@
                          encodingOffset,
                          tempBuffer,
                          0,
-                        copyingSize );
+                        copyingSize);

                  encodingOffset += copyingSize;
                  tempBufferRemaining -= copyingSize;
                  finalCopySize += copyingSize;
              }

-            if (encodingOffset == encodingBuffer.length)
-            {
-                int encodedBytes = sipCodec.pcmToCodec( encodingBuffer,  
codedBuffer );
+            if (encodingOffset == encodingBuffer.length) {
+                int encodedBytes = sipCodec.pcmToCodec(encodingBuffer,  
codedBuffer);

-                if ( encodedBytes ==  
sipCodec.getOutgoingEncodedFrameSize() ) {
+                if (encodedBytes ==  
sipCodec.getOutgoingEncodedFrameSize()) {

-                    BufferUtils.byteBufferIndexedCopy( packetBuffer,
-                            RTP_HEADER_SIZE, codedBuffer, 0,  
codedBuffer.length );
+                    BufferUtils.byteBufferIndexedCopy(packetBuffer,
+                            RTP_HEADER_SIZE, codedBuffer, 0,  
codedBuffer.length);
                  }
              }

-        }
-        catch ( Exception e ) {
+        } catch (Exception e) {
              e.printStackTrace();
          }

          return finalCopySize;
      }
-
-
-    public void run() {
-
-        if ( rtpSocket == null ) {
-            return;
-        }
-
-        asao_buffer_processed = false;
-
-        if ( !hasInitilializedBuffers ) {
-
-            tempBuffer = new float[ NELLYMOSER_DECODED_PACKET_SIZE ];
-            multiplexedStreams = new int[100];
-            decodedBuffer1 = new float[ NELLYMOSER_DECODED_PACKET_SIZE ];
-            decodedBuffer2 = new float[ NELLYMOSER_DECODED_PACKET_SIZE ];
-            encodingBuffer = new float[  
sipCodec.getOutgoingDecodedFrameSize() ];
-
-            hasInitilializedBuffers = true;
-        }
-
-        //println( "send",
-        //        "asaoBuffer.length = [" + asaoBuffer.length + "], offset  
= ["
-        //        + offset + "], num = [" + num + "]." );
-        do {
-
-            do {
-
-                int encodedBytes = fillRtpPacketBuffer();
-
-                //println( "send", sipCodec.getCodecName() + " encoded " +  
encodedBytes + " bytes." );
-
-                if ( encodedBytes == 0 ) {
-
-                    break;
-                }
-
-                if ( encodingOffset ==  
sipCodec.getOutgoingDecodedFrameSize() ) {
-
-                    //println( "send", "Seding packet with " +  
encodedBytes + " bytes." );
-
-                    try {
-
-                        rtpPacket.setSequenceNumber(seqn++);
-                        rtpPacket.setTimestamp(time);
-                         
rtpPacket.setPayloadLength(sipCodec.getOutgoingEncodedFrameSize());
-                        rtpSocketSend( rtpPacket );
-                    }
-                    catch ( Exception e ) {
-                        println( "send", sipCodec.getCodecName() + "  
encoder error." );
-                    }
-
-                    encodingOffset = 0;
-                }
-
-                //println( "send", "asao_buffer_processed = ["
-                //        + asao_buffer_processed + "] ." );
-            }
-            while ( !asao_buffer_processed );
-
-        } while (rtpSocket != null);
-    }

      public void halt() {

@@ -431,29 +395,34 @@

          rtpSocket.close();

-        if ( socketIsLocal && socket != null ) {
+        if (socketIsLocal && socket != null) {
              socket.close();
          }

          rtpSocket = null;
          sendThread = null;

-        println( "halt", "Terminated" );
+        println("halt", "Terminated");
      }

-    private synchronized void rtpSocketSend(RtpPacket rtpPacket) {
+    private long lastMS = System.currentTimeMillis();

+    private void rtpSocketSend(RtpPacket rtpPacket) {
          try {
-         	rtpSocket.send( rtpPacket );
-            time += sipCodec.getOutgoingDecodedFrameSize();
-        }
-        catch ( Exception e ) {
+            rtpPacket.setTimestamp(time);
+            rtpPacket.setSequenceNumber(seqn++);
+             
rtpPacket.setPayloadLength(sipCodec.getOutgoingEncodedFrameSize());
+            rtpPacket.setPayloadType(sipCodec.getCodecId());
+            rtpSocket.send(rtpPacket);
+            time += sipCodec.getOutgoingPacketization();
+            //System.out.println(String.format("Send RTP: interval %d,  
ts %d", System.currentTimeMillis() - lastMS, time));
+        } catch (Exception e) {
+            log.error("Error sending RTP packet", e);
          }
      }

-    private static void println( String method, String message ) {
-
-        log.debug( "RTPStreamSender - " + method + " -> " + message );
-        System.out.println( "RTPStreamSender - " + method + " -> " +  
message );
+    private static void println(String method, String message) {
+        log.debug("RTPStreamSender - " + method + " -> " + message);
+        System.out.println("RTPStreamSender - " + method + " -> " +  
message);
      }
  }
=======================================
--- /branches/red5sip/src/java/org/red5/sip/app/RTPStreamSender.java	Tue  
Jan 29 03:52:07 2013
+++ /branches/red5sip/src/java/org/red5/sip/app/RTPStreamSender.java	Wed  
Feb  6 09:31:44 2013
@@ -12,6 +12,8 @@

  import java.net.DatagramSocket;
  import java.net.InetAddress;
+import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicLong;


  public class RTPStreamSender implements IMediaSender {
@@ -35,37 +37,13 @@

      boolean doSync = true;

-    private Decoder decoder;
+    protected Decoder decoder;

-    private DecoderMap decoderMap;
-
-    private byte[] packetBuffer;
-
-    private RtpPacket rtpPacket;
+    protected DecoderMap decoderMap;

      private int seqn = 0;

-    private long time = 0;
-
-    // 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 AtomicLong syncSourceBase = new AtomicLong(Random.nextLong());

      /**
       * Constructs a RtpStreamSender.
@@ -176,248 +154,26 @@
          }
      }

-    public void start() {
+    public IMediaStream createStream(int streamId) {
+        return new RTPStream(streamId, syncSourceBase.getAndIncrement(),  
this);
+    }

-        packetBuffer = new byte[ sipCodec.getOutgoingEncodedFrameSize() +  
RTP_HEADER_SIZE ];
-        rtpPacket = new RtpPacket( packetBuffer, 0 );
-        rtpPacket.setPayloadType( sipCodec.getCodecId() );
+    public void deleteStream(int streamId) {
+        //nothing to do
+    }

+    public void start() {
          seqn = 0;
-        time = 0;
-
-        println( "start()", "using blocks of " + ( packetBuffer.length -  
RTP_HEADER_SIZE ) + " bytes." );
-
          decoder = new Decoder();
          decoderMap = null;
      }

-    /** Fill the buffer of RtpPacket with necessary data. */
-    private int fillRtpPacketBuffer(byte[] asaoBuffer) {
-
-        boolean isBufferFilled = false;
-        int copyingSize = 0;
-        int finalCopySize = 0;
-        byte[] codedBuffer = new byte[  
sipCodec.getOutgoingEncodedFrameSize() ];
-
-        try {
-            //println( "fillRtpPacketBuffer",
-            //        "packetBuffer.length = " + packetBuffer.length
-            //        + ", asaoBuffer.length = " + asaoBuffer.length
-            //        + ", tempBuffer.length = " + tempBuffer.length
-            //        + ", encodingOffset = " + encodingOffset
-            //        + ", tempBufferRemaining = " + tempBufferRemaining  
+ "." );
-
-            if ( ( tempBufferRemaining + encodingOffset ) >=  
sipCodec.getOutgoingDecodedFrameSize() ) {
-
-                copyingSize = encodingBuffer.length - encodingOffset;
-
-                BufferUtils.floatBufferIndexedCopy(
-                        encodingBuffer,
-                        encodingOffset,
-                        tempBuffer,
-                        tempBuffer.length - tempBufferRemaining,
-                        copyingSize );
-
-                encodingOffset = sipCodec.getOutgoingDecodedFrameSize();
-                tempBufferRemaining -= copyingSize;
-                finalCopySize = sipCodec.getOutgoingDecodedFrameSize();
-
-                //println( "fillRtpPacketBuffer", "Simple copy of " +  
copyingSize + " bytes." );
-            }
-            else {
-                if ( tempBufferRemaining > 0 ) {
-                    BufferUtils.floatBufferIndexedCopy(
-                            encodingBuffer,
-                            encodingOffset,
-                            tempBuffer,
-                            tempBuffer.length - tempBufferRemaining,
-                            tempBufferRemaining );
-
-                    encodingOffset += tempBufferRemaining;
-                    finalCopySize += tempBufferRemaining;
-                    tempBufferRemaining = 0;
-
-                    //println( "fillRtpPacketBuffer",
-                    //        "tempBufferRemaining copied -> "
-                    //        + "encodingOffset = " + encodingOffset
-                    //        + ", tempBufferRemaining = " +  
tempBufferRemaining + "." );
-                }
-
-                // Decode new asao packet.
-
-                asao_buffer_processed = true;
-
-                ByteStream audioStream = new ByteStream( asaoBuffer, 1,  
NELLYMOSER_ENCODED_PACKET_SIZE );
-
-                decoderMap = decoder.decode( decoderMap,  
audioStream.bytes, 1, tempBuffer, 0 );
-
-//                tempBuffer = ResampleUtils.normalize(tempBuffer, 256); 	 
// normalise volume
-
-                tempBufferRemaining = tempBuffer.length;
-
-                //println( "fillRtpPacketBuffer",
-                //        "Decoded pcm " + tempBuffer.length + " floats."  
);
-
-                if ( tempBuffer.length <= 0 ) {
-
-                    println( "fillRtpPacketBuffer", "Asao decoder Error."  
);
-                }
-
-                // Try to complete the encodingBuffer with necessary data.
-
-                //println( "fillRtpPacketBuffer",
-                //        "New buffer processed -> "
-                //        + "finalCopySize = " + finalCopySize
-                //        + ", encodingOffset = " + encodingOffset
-                //        + ", tempBufferRemaining = " +  
tempBufferRemaining + "." );
-
-                if ( ( encodingOffset + tempBufferRemaining ) >  
sipCodec.getOutgoingDecodedFrameSize() ) {
-                    copyingSize = encodingBuffer.length - encodingOffset;
-                }
-                else {
-                    copyingSize = tempBufferRemaining;
-                }
-
-                //println( "fillRtpPacketBuffer", "CopyingSize = " +  
copyingSize + "." );
-
-                BufferUtils.floatBufferIndexedCopy(
-                        encodingBuffer,
-                        encodingOffset,
-                        tempBuffer,
-                        0,
-                        copyingSize );
-
-                encodingOffset += copyingSize;
-                tempBufferRemaining -= copyingSize;
-                finalCopySize += copyingSize;
-            }
-
-            if (encodingOffset == encodingBuffer.length)
-            {
-                isBufferFilled = true;
-
-                int encodedBytes = sipCodec.pcmToCodec( encodingBuffer,  
codedBuffer );
-
-                //println( "fillRtpPacketBuffer",
-                //        "encodedBytes = " + encodedBytes +
-                //        ", outgoingEncodedFrameSize = " +  
sipCodec.getOutgoingEncodedFrameSize() + "." );
-
-                if ( encodedBytes ==  
sipCodec.getOutgoingEncodedFrameSize() ) {
-
-                    BufferUtils.byteBufferIndexedCopy( packetBuffer,
-                            RTP_HEADER_SIZE, codedBuffer, 0,  
codedBuffer.length );
-                }
-                else {
-                    //println( "fillRtpPacketBuffer", "Failure encoding  
buffer." );
-                }
-            }
-
-            //println( "fillRtpPacketBuffer",
-            //        "finalCopySize = " + finalCopySize
-            //        + ", isBufferFilled = " + isBufferFilled
-            //        + ", encodingOffset = " + encodingOffset
-            //        + ", tempBufferRemaining = " + tempBufferRemaining  
+ "." );
-        }
-        catch ( Exception e ) {
-            e.printStackTrace();
-        }
-
-        return finalCopySize;
-    }
-
-    public void send( int streamId, byte[] asaoInput, int offset, int num  
) {
-        if(this.useASAO) {
-            sendASAO(streamId, asaoInput, offset, num);
-        } else {
-            sendRaw(streamId, asaoInput, offset, num);
-        }
-    }
-
-    public void sendRaw( int streamId, byte[] asaoInput, int offset, int  
num ) {
-
-        if ( rtpSocket == null ) {
-            return;
-        }
-
-        if ( num > 0 ) {
-
-            byte [] asaoBuffer = new byte[num];
-            System.arraycopy(asaoInput, offset, packetBuffer,  
RTP_HEADER_SIZE, num);
-
-            Random.setSeed(streamId);
-            rtpPacket.setSscr(Random.nextLong());
-            rtpPacket.setSequenceNumber( seqn++);
-            rtpPacket.setTimestamp( time );
-            rtpPacket.setPayloadLength(  
sipCodec.getOutgoingEncodedFrameSize() );
-            rtpSocketSend( rtpPacket );
-
-        } else if ( num < 0 ) {
-
-            println( "send", "Closing" );
-        }
-    }
-
-
-    public void sendASAO(int streamId, byte[] asaoBuffer, int offset, int  
num) {
-
+    protected void send(RtpPacket rtpPacket) {
          if ( rtpSocket == null ) {
              return;
          }
-
-        asao_buffer_processed = false;
-
-        if ( !hasInitilializedBuffers ) {
-
-            tempBuffer = new float[ NELLYMOSER_DECODED_PACKET_SIZE ];
-            encodingBuffer = new float[  
sipCodec.getOutgoingDecodedFrameSize() ];
-
-            hasInitilializedBuffers = true;
-        }
-
-        //println( "send",
-        //        "asaoBuffer.length = [" + asaoBuffer.length + "], offset  
= ["
-        //        + offset + "], num = [" + num + "]." );
-
-        if ( num > 0 ) {
-
-            do {
-
-                int encodedBytes = fillRtpPacketBuffer( asaoBuffer );
-
-                //println( "send", sipCodec.getCodecName() + " encoded " +  
encodedBytes + " bytes." );
-
-                if ( encodedBytes == 0 ) {
-
-                    break;
-                }
-
-                if ( encodingOffset ==  
sipCodec.getOutgoingDecodedFrameSize() ) {
-
-                    //println( "send", "Seding packet with " +  
encodedBytes + " bytes." );
-
-                    try {
-                        Random.setSeed(streamId);
-                        rtpPacket.setSscr(Random.nextLong());
-                        rtpPacket.setSequenceNumber(seqn++);
-                        rtpPacket.setTimestamp(time);
-                         
rtpPacket.setPayloadLength(sipCodec.getOutgoingEncodedFrameSize());
-                        rtpSocketSend( rtpPacket );
-                    }
-                    catch ( Exception e ) {
-                        println( "send", sipCodec.getCodecName() + "  
encoder error." );
-                    }
-
-                    encodingOffset = 0;
-                }
-
-                //println( "send", "asao_buffer_processed = ["
-                //        + asao_buffer_processed + "] ." );
-            }
-            while ( !asao_buffer_processed );
-        }
-        else if ( num < 0 ) {
-            println( "send", "Closing" );
-        }
+        rtpPacket.setSequenceNumber(seqn++);
+        rtpSocketSend( rtpPacket );
      }


@@ -438,7 +194,6 @@


      private void doRtpDelay() {
-
          try {
              Thread.sleep( sipCodec.getOutgoingPacketization() - 2 );
          }
@@ -448,17 +203,15 @@


      private synchronized void rtpSocketSend(RtpPacket rtpPacket) {
-
          try {
           	rtpSocket.send( rtpPacket );
-            time += sipCodec.getOutgoingDecodedFrameSize();
+            System.out.println(rtpPacket.getSscr() + " : " +  
rtpPacket.getTimestamp());
          }
          catch ( Exception e ) {
          }
      }

      private static void println( String method, String message ) {
-
          log.debug( "RTPStreamSender - " + method + " -> " + message );
          System.out.println( "RTPStreamSender - " + method + " -> " +  
message );
      }
=======================================
--- /branches/red5sip/src/java/org/red5/sip/app/SIPAudioLauncher.java	Tue  
Jan 29 03:52:07 2013
+++ /branches/red5sip/src/java/org/red5/sip/app/SIPAudioLauncher.java	Wed  
Feb  6 09:31:44 2013
@@ -36,10 +36,10 @@
                      "sender configs: payloadType = [" +  
sipCodec.getCodecId() +
                      "], payloadName = [" + sipCodec.getCodecName() + "].");

-            sender = new RTPStreamSender( mediaReceiver, false,
-                    sipCodec, socket, remoteAddr, remotePort );
-//            sender = new RTPStreamMultiplexingSender( mediaReceiver,  
false,
+//            sender = new RTPStreamSender( mediaReceiver, false,
  //                    sipCodec, socket, remoteAddr, remotePort );
+            sender = new RTPStreamMultiplexingSender( mediaReceiver, false,
+                    sipCodec, socket, remoteAddr, remotePort );

              printLog( "SIPAudioLauncher", "New audio receiver on " +  
localPort + "." );