net.sf.fmj.media.rtp.BasicJitterBufferBehaviour Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fmj Show documentation
Show all versions of fmj Show documentation
Freedom for Media in Java
The newest version!
package net.sf.fmj.media.rtp;
import javax.media.*;
import javax.media.control.*;
import net.sf.fmj.media.*;
/**
* Implements a basic JitterBufferBehaviour which is not adaptive, does
* not perform buffering beyond the one performed by the associated
* JitterBuffer and is agnostic of the Format of the received
* media data. The implementation may be used by extenders to facilitate the
* implementation of the JitterBufferBehaviour interface.
*
* @author Lyubomir Marinov
*/
class BasicJitterBufferBehaviour
implements JitterBufferBehaviour
{
/**
* The RTP packet queue/jitter buffer which implements the storage of the
* RTP packets added to and read from {@link #stream}.
*/
protected final JitterBuffer q;
/**
* The value which has been applied by this instance with an invocation of
* {@link RTPRawReceiver#setRecvBufSize(int)}.
*/
private int recvBufSize;
/**
* The statistics related to the RTP packet queue/jitter buffer associated
* with {@link #stream}.
*/
protected final JitterBufferStats stats;
/**
* The RTPSourceStream which has initialized this instance.
*/
protected final RTPSourceStream stream;
/**
* Initializes a new BasicJitterBufferBehaviour instance for the
* purposes of a specific RTPSourceStream.
*
* @param stream the RTPSourceStream which has requested the
* initialization of the new instance
*/
protected BasicJitterBufferBehaviour(RTPSourceStream stream)
{
this.stream = stream;
this.q = this.stream.q;
this.stats = this.stream.stats;
}
/**
* Removes the first element (the one with the least sequence number)
* from fill and releases it to be reused (adds it to
* free)
*/
protected void dropFirstPkt()
{
q.dropFirstFill();
}
/**
* Removes an element from the queue and releases it to be reused.
*/
public void dropPkt()
{
dropFirstPkt();
}
/**
* {@inheritDoc}
*
* BasicJitterBufferBehaviour implements a fixed jitter buffer and,
* consequently, returns {@link #getMaximumDelay()}.
*/
@Override
public int getAbsoluteMaximumDelay()
{
return getMaximumDelay();
}
/**
* Gets the BufferControl implementation set on the associated
* RTPSourceStream. Provided as a convenience which delegates to
* {@link RTPSourceStream#getBufferControl()}.
*
* @return the BufferControl implementation set on the associated
* RTPSourceStream
*/
protected BufferControl getBufferControl()
{
return stream.getBufferControl();
}
/**
* {@inheritDoc}
*
* BasicJitterBufferBehaviour does not have a notion of RTP packet
* duration and, consequently, returns 65535.
*/
@Override
public int getMaximumDelay()
{
return 65535;
}
/**
* {@inheritDoc}
*
* BasicJitterBufferBehaviour does not have a notion of RTP packet
* duration and, consequently, returns 0.
*/
@Override
public int getNominalDelay()
{
return 0;
}
/**
* Grows {@link #q} to a specific capacity.
*
* @param capacity the capacity to set on q
* @throws IllegalArgumentException if the specified capacity is
* less than the capacity of q
*/
protected void grow(int capacity)
{
if (capacity < 1)
throw new IllegalArgumentException("capacity");
int qCapacity = q.getCapacity();
if (capacity == qCapacity)
return;
if (capacity < qCapacity)
throw new IllegalArgumentException("capacity");
Log.info("Growing packet queue to " + capacity);
stats.incrementNbGrow();
q.setCapacity(capacity);
}
/**
* {@inheritDoc}
*
* BasicJitterBufferBehaviour always returns false to
* indicate that it implements a fixed jitter buffer/RTP packet queue.
*/
public boolean isAdaptive()
{
return false;
}
/**
* Allows extenders to adapt the size/capacity of the associated RTP packet
* queue/JitterBuffer after a specific Buffer is received
* and before it is added to the JitterBuffer.
*
* @param buffer the Buffer which has been received and is to be
* added (after the method returns)
* @return the approximate length in packets of the buffering performed by
* this JitterBufferBehaviour and the associated
* JitterBuffer. BasicJitterBufferBehaviour always returns
* 0.
*/
protected int monitorQSize(Buffer buffer)
{
return 0;
}
/**
* {@inheritDoc}
*
* Maintains an average approximation of the size in bytes of an RTP packet
* in the JitterBufferStats of the associated
* RTPSourceStream and updates the recvBufSize of the
* specified rtprawreceiver.
*/
public boolean preAdd(Buffer buffer, RTPRawReceiver rtprawreceiver)
{
stats.updateSizePerPacket(buffer);
int aprxBufferLengthInPkts = monitorQSize(buffer);
if (aprxBufferLengthInPkts > 0)
setRecvBufSize(rtprawreceiver, aprxBufferLengthInPkts);
return true;
}
/**
* {@inheritDoc}
*/
public void read(Buffer buffer)
{
if (q.getFillCount() == 0)
{
buffer.setDiscard(true);
}
else
{
Buffer bufferFromQueue = q.getFill();
// Whatever follows, it sounds safer to return the bufferFromQueue
// into the free pool eventually.
try
{
// Copy the bufferFromQueue into the specified (output) buffer.
Object bufferData = buffer.getData();
Object bufferHeader = buffer.getHeader();
buffer.copy(bufferFromQueue);
bufferFromQueue.setData(bufferData);
bufferFromQueue.setHeader(bufferHeader);
}
finally
{
q.returnFree(bufferFromQueue);
}
}
}
/**
* {@inheritDoc}
*/
public void reset()
{
}
protected void setRecvBufSize(
RTPRawReceiver rtprawreceiver,
int aprxBufferLengthInPkts)
{
int sizePerPkt = stats.getSizePerPacket();
// There was no comment and the variables did not use meaningful names
// at the time the following code was initially written. Consequently,
// it is not immediately obvious why it is necessary at all and it may
// be hard to understand. A possible explanation may be that, since the
// threshold value will force a delay with a specific duration/byte
// size, we should better be able to hold on to that much in the socket
// so that it does not throw the delayed data away.
int aprxThresholdInBytes
= (aprxBufferLengthInPkts * sizePerPkt) / 2;
if ((rtprawreceiver != null)
&& (aprxThresholdInBytes > this.recvBufSize))
{
rtprawreceiver.setRecvBufSize(aprxThresholdInBytes);
int recvBufSize = rtprawreceiver.getRecvBufSize();
this.recvBufSize
= (recvBufSize < aprxThresholdInBytes)
? 0x7fffffff /* BufferControlImpl.NOT_SPECIFIED? */
: aprxThresholdInBytes;
Log.comment(
"RTP socket receive buffer size: " + recvBufSize
+ " bytes.\n");
}
}
/**
* {@inheritDoc}
*
* BasicJitterBufferBehaviour returns true if the
* associated RTP packet queue/jitter buffer is empty; otherwise,
* false
*/
public boolean willReadBlock()
{
return q.noMoreFill();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy