Package net.sf.fmj.media.rtp

Source Code of net.sf.fmj.media.rtp.RTPBuffer

package net.sf.fmj.media.rtp;

import javax.media.Buffer;

/**
* Buffer for incoming RTP packets
*
* instance variables have default values in java, so classes are gettings smaller
*
* @author mgodehardt
* @version 1-1-alpha3
*/
public class RTPBuffer
{
    static private int MIN_SEQUENTIAL = 2;
    static private int MAX_MISORDER = 100;
    static private int MAX_DROPOUT = 3000;
   
    // for the jitter buffer ( using a double linked list )
    private RTPBuffer         firstItem;
    private RTPBuffer         lastItem;
    private int               itemCount;
    private int               maxItems;
    private long              duration;
    private long              lastSequenceNumber = -1;
    private long              firstSequenceNumber = -1;
    private RTPReceptionStats receptionStats;
    private int               probation = RTPBuffer.MIN_SEQUENTIAL;
    private long              received;
    private int               cycles;
   
    // for single data buffer ( wrapping a Buffer )
    private RTPBuffer previousBuffer;
    private RTPBuffer nextBuffer;
    private Buffer    buffer;

    // default ctor
    private RTPBuffer()
    {
        // disallow
    }

    // ctor for the jitter buffer
    public RTPBuffer(int maxItems, RTPReceptionStats receptionStats)
    {
        this.maxItems = maxItems;
        this.receptionStats = receptionStats;
    }

    // ctor for single data buffers
    public RTPBuffer(Buffer buffer)
    {
        this.buffer = buffer;
    }

    // how many items are in the jitter buffer
    synchronized public void resize(int maxItems)
    {
        this.maxItems = maxItems;
    }

    // remove all items
    synchronized public void clear() throws InterruptedException
    {
        while ( null != firstItem )
        {
            remove();
        }
    }

    // how many items do fit in the jitter buffer
    synchronized public int getMaxItems()
    {
        return maxItems;
    }

    // how many items are in the jitter buffer
    synchronized public int getItemCount()
    {
        return itemCount;
    }

    // returns duration in nanoseconds of the hole jitter buffer
    synchronized public long getDuration()
    {
        return duration;
    }
   
    synchronized public long getExtendedHighestSequenceNumber()
    {
        if ( lastSequenceNumber != -1 )
        {
            return (cycles << 16) + (lastSequenceNumber & 0xffff);
        }
       
        return -1;
    }
   
    synchronized public int getCumulativePacketLoss()
    {
        long extendedHighestSequenceNumber = getExtendedHighestSequenceNumber();
        if ( (extendedHighestSequenceNumber != -1) && (firstSequenceNumber != -1) )
        {
            long packetsExpected = extendedHighestSequenceNumber - firstSequenceNumber + 1;
            long cumulativePacketLoss = (packetsExpected - received);
           
            // clamp cumulativePacketLoss RFC 3550 Page 82
            if ( cumulativePacketLoss > 0x7fffff )
            {
                cumulativePacketLoss = 0x7fffff;
            }
            else if ( cumulativePacketLoss < -0x800000 )
            {
                cumulativePacketLoss = -0x800000;
            }
           
            return (int)cumulativePacketLoss;
        }
       
        return -1;
    }
   
    // add a item to the end of the jitter buffer
    synchronized public void addWait(Buffer buffer) throws InterruptedException
    {
        if ( null != firstItem )
        {
            wait();
        }
       
        firstItem = lastItem = new RTPBuffer(buffer);
        itemCount = 1;
        duration = buffer.getDuration();
       
        long seq = (buffer.getSequenceNumber() & 0xffff);
       
        if ( lastSequenceNumber != -1 )
        {
            long udelta = ((short)seq - (short)lastSequenceNumber) & 0xffff;
           
            if ( seq < lastSequenceNumber )
            {
                cycles++;
                if ( null != receptionStats )
                {
                    receptionStats.addSequenceWrap();
                }
            }
        }
       
        if ( -1 == firstSequenceNumber )
        {
            firstSequenceNumber = seq;
        }
       
        if ( null != receptionStats )
        {
            receptionStats.addPDUProcessed();
        }
        received++;
       
        lastSequenceNumber = seq;
       
        notifyAll();
    }

    // add a item to the end of the jitter buffer
    synchronized public Buffer removeWait() throws InterruptedException
    {
        if ( null == firstItem )
        {
            wait();
        }
       
        Buffer aBuffer = null;
       
        RTPBuffer aRTPBuffer = firstItem;
       
        firstItem = lastItem = null;
        itemCount = 0;
        duration = 0;
       
        aBuffer = aRTPBuffer.buffer;
       
        notifyAll();
       
        return aBuffer;
    }

    private void addImpl(Buffer buffer)
    {
        RTPBuffer aRTPBuffer = new RTPBuffer(buffer);
       
        if ( null == firstItem )
        {
            firstItem = lastItem = aRTPBuffer;
           
            itemCount = 1;
            duration = buffer.getDuration();
        }
        else
        {
            lastItem.nextBuffer = aRTPBuffer;
            aRTPBuffer.previousBuffer = lastItem;
            lastItem = aRTPBuffer;
           
            itemCount++;
            duration += buffer.getDuration();
        }
       
        if ( null != receptionStats )
        {
            receptionStats.addPDUProcessed();
        }
    }

    // add a item to the end of the jitter buffer
    synchronized public boolean add(Buffer buffer)
    {
        boolean fBufferOverrun = false;
       
        long seq = (buffer.getSequenceNumber() & 0xffff);
       
        if ( -1 == lastSequenceNumber )
        {
            lastSequenceNumber = seq;
        }
       
        if ( probation > 0 ) // source is not valid until MIN_SEQUENTIAL packets have arrived (RFC 3550 Page 80)
        {
            if ( seq == ((lastSequenceNumber + 1) & 0xffff) )
            {
                probation--;
                if ( 0 == probation )
                {
                    firstSequenceNumber = seq;
                    addImpl(buffer);
                    received++;
                }
            }
            else
            {
                probation = RTPBuffer.MIN_SEQUENTIAL - 1;
            }
            lastSequenceNumber = seq;
        }
        else
        {
            long udelta = ((short)seq - (short)lastSequenceNumber) & 0xffff;
           
            if ( udelta < MAX_DROPOUT )
            {
                if ( seq < lastSequenceNumber )
                {
                    cycles++;
                    if ( null != receptionStats )
                    {
                        receptionStats.addSequenceWrap();
                    }
                }
                addImpl(buffer);
                received++;
                lastSequenceNumber = seq;
            }
            else
            {
                ///System.out.println("### RTPBuffer DUPLICATE OR MISORDERED PACKET seq=" + seq + " last=" + lastSequenceNumber);
               
                // TODO: handle duplicate or misordered packets
                received++;
            }
        }
       
        // buffer overrun
        while ( itemCount > maxItems )
        {
            ///System.out.println("### RTPBuffer BUFFER OVERRUN " + itemCount);
           
            try
            {
                remove();
                fBufferOverrun = true;
            }
            catch ( Exception dontcare )
            {
            }
        }
       
        notifyAll();
       
        return fBufferOverrun;
    }

    // remove first item from the jitter buffer ( may block )
    synchronized public Buffer remove() throws InterruptedException
    {
        if ( null == firstItem )
        {
            wait();
        }
       
        RTPBuffer aRTPBuffer = firstItem;
        if ( null != aRTPBuffer )
        {
            if ( lastItem == firstItem )
            {
                lastItem = null;
            }
           
            firstItem = aRTPBuffer.nextBuffer;
            if ( null != firstItem )
            {
                firstItem.previousBuffer = null;
            }
           
            Buffer aBuffer = aRTPBuffer.buffer;
           
            aRTPBuffer.nextBuffer = null;
            aRTPBuffer.previousBuffer = null;
            aRTPBuffer.buffer = null;
           
            itemCount--;
            duration -= aBuffer.getDuration();
           
            return aBuffer;
        }
       
        return null;
    }
}
TOP

Related Classes of net.sf.fmj.media.rtp.RTPBuffer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.