// data in the buffer, the stream should not allocate it.
// See http://java.sun.com/products/java-media/jmf/2.1.1/apidocs/javax/media/protocol/PushBufferStream.html
// The original implementation here assumed this. But in JMF there are some badly behaving PushBufferStreams,
// namely those in RTPSyncBufferMux, which give us a new buffer. So we'll check for that below, and
// copy it back to buffer. kenlars99 7/13/07.
Buffer recvBuffer = new Buffer();
try {
// Make sure that buffer is big enough. kenlars99 6/3/07.
if (buffer.length < MAX_PUSHBUFFER_DATA_SIZE + RTPHeader.SIZE) {
buffer = new byte[MAX_PUSHBUFFER_DATA_SIZE + RTPHeader.SIZE];
}
// According to the API, if the caller sets the
// data in the buffer, the stream should not allocate it.
// See http://java.sun.com/products/java-media/jmf/2.1.1/apidocs/javax/media/protocol/PushBufferStream.html
// The original implementation here assumed this. But in JMF there are some badly behaving PushBufferStreams,
// namely those in RTPSyncBufferMux, which give us a new buffer. So we'll check for that below, and
// copy it back to buffer. kenlars99 7/13/07.
recvBuffer.setData(buffer);
recvBuffer.setOffset(RTPHeader.SIZE);
recvBuffer.setLength(buffer.length - RTPHeader.SIZE);
stream.read(recvBuffer);
if (recvBuffer.getLength() > 0)
{
// copy the data back into buffer, if the stream put it in a different byte array. kenlars99 7/13/07.
if (recvBuffer.getData() != buffer)
System.arraycopy(recvBuffer.getData(), recvBuffer.getOffset(), buffer, RTPHeader.SIZE, recvBuffer.getLength());
/* We set the marker flag if we're at the end of a video frame */
boolean marker = (recvBuffer.getFlags() & Buffer.FLAG_RTP_MARKER) != 0;
//printFlags(recvBuffer);
//System.out.println("MARKER : "+recvBuffer.getFlags()+" / "+ recvBuffer.FLAG_RTP_MARKER +" => "+marker);
//System.out.println("TIME "+recvBuffer.getTimeStamp());
long rtpTimestamp = 0;
// mgodehardt: the timestamp value in the rtp packet is dependent on the payload type, for ulaw
// its easy 160 bytes in a packet means, add 160 to the timestamp, see below
// TODO: add other formats, at the moment only ULAW works
if ( (stream.getFormat().getEncoding() == AudioFormat.ULAW_RTP) || (stream.getFormat().getEncoding() == AudioFormat.GSM_RTP) )
{
rtpTimestamp = lastTimestamp;
}
else if ( stream.getFormat().getEncoding() == VideoFormat.JPEG_RTP )
{
rtpTimestamp = lastTimestamp;
if ( 0 == lastBufferTimestamp )
{
lastBufferTimestamp = System.nanoTime() / 1000000L;
}
}
// RFC 3550 Page 13, The timestamp reflects the sampling instant of the first octet in the buffer
writeHeaderToBuffer(marker, rtpTimestamp);
// copy the data back into buffer, if the stream put it in a different byte array. kenlars99 7/13/07.
if (recvBuffer.getData() != buffer)
{
System.arraycopy(recvBuffer.getData(), recvBuffer.getOffset(), buffer, RTPHeader.SIZE, recvBuffer.getLength());
}
///long encodeTime = (System.nanoTime() - recvBuffer.getTimeStamp()) / 1000000L;
///System.out.println("### " + (recvBuffer.getLength() + RTPHeader.SIZE) + " " + marker + " rtpTimestamp=" + rtpTimestamp + " encodeTime=" + encodeTime);
rtpDataStream.write(buffer, 0, recvBuffer.getLength() + RTPHeader.SIZE);
// TODO: add other formats
if ( stream.getFormat().getEncoding() == AudioFormat.ULAW_RTP )
{
// RFC 3550 Page 13, fixed rate audio should increment timestamp by one for each sampling period
// we use 8000Hz for ULAW/PCMU
lastTimestamp += recvBuffer.getLength();
}
else if ( stream.getFormat().getEncoding() == AudioFormat.GSM_RTP )
{
// RFC 3550 Page 13, fixed rate audio should increment timestamp by one for each sampling period
// we use 8000Hz for GSM 6.10
lastTimestamp += (recvBuffer.getLength() * 8000) / 1650;
}
else if ( stream.getFormat().getEncoding() == VideoFormat.JPEG_RTP )
{
if ( (recvBuffer.getFlags() & Buffer.FLAG_RTP_MARKER) > 0 )
{
long currentTime = (System.nanoTime() / 1000000L);
// we use 90000Hz for JPEG ( see RFC 3551 )
long diffTime = currentTime - lastBufferTimestamp;
lastTimestamp += (diffTime * 90);
lastBufferTimestamp = currentTime;
}
}
// must be done here, lastTimestamp and lastSendTime must have a relationship
lastSendTime = System.currentTimeMillis() - RTCPSenderInfo.MSB_1_BASE_TIME;
if ( initialSendTime == -1 )
{
initialSendTime = lastSendTime;
}
}
} catch (IOException e) {
logger.log(Level.WARNING, "" + e, e);
}
stats.addPDUTransmitted();
RTPHeader header=null;
try
{
header = new RTPHeader(buffer, 0, RTPHeader.SIZE);
//System.out.println("PADDING for "+header.getSsrc()+" : "+header.getPadding()+" ["+(int)buffer[buffer.length-1]+"]");
int len = recvBuffer.getLength() - (header.getPadding() > 0 ? (int)buffer[buffer.length-1]:0);
//System.out.println("ADDING LEN "+len);
stats.addBytesTransmitted(len);
} catch (IOException ex)
{
//ex.printStackTrace();
// TODO: why don't we log this?
}
rtpMgr.RTPPacketSent(lastSendTime, recvBuffer.getLength()+RTPHeader.SIZE);
}
}