Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RTP stream pause/resume improvements. #181

Merged
merged 13 commits into from Aug 9, 2016
138 changes: 138 additions & 0 deletions src/org/jitsi/impl/neomedia/rtcp/RTCPHeaderUtils.java
@@ -0,0 +1,138 @@
/*
* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.impl.neomedia.rtcp;

import net.sf.fmj.media.rtp.*;

/**
* Utility class that contains static methods for RTCP header manipulation.
*
* TODO maybe merge into the RTCPHeader class.
*
* @author George Politis
*/
public class RTCPHeaderUtils
{
/**
* Gets the RTCP packet type.
*
* @param buf the byte buffer that contains the RTCP header.
* @param off the offset in the byte buffer where the RTCP header starts.
* @param len the number of bytes in buffer which constitute the actual
* data.
* @return the unsigned RTCP packet type, or -1 in case of an error.
*/
public static int getPacketType(byte[] buf, int off, int len)
{
if (buf == null || Math.min(buf.length, len) < off + 2)
{
return -1;
}

return buf[off + 1] & 0xff;
}

/**
* Gets the RTCP sender SSRC.
*
* @param buf the byte buffer that contains the RTCP header.
* @param off the offset in the byte buffer where the RTCP header starts.
* @param len the number of bytes in buffer which constitute the actual
* data.
* @return the unsigned RTCP sender SSRC, or -1 in case of an error.
*/
public static long getSenderSSRC(byte[] buf, int off, int len)
{
if (buf == null || Math.min(buf.length, len) < off + 8)
{
return -1;
}

return (((buf[off + 4] & 0xff) << 24)
| ((buf[off + 5] & 0xff) << 16)
| ((buf[off + 6] & 0xff) << 8)
| (buf[off + 7] & 0xff)) & 0xffffffffl;
}

/**
* Gets the RTCP packet length in bytes.
*
* @param buf the byte buffer that contains the RTCP header.
* @param off the offset in the byte buffer where the RTCP header starts.
* @param len the number of bytes in buffer which constitute the actual
* data.
* @return the RTCP packet length in bytes, or -1 in case of an error.
*/
public static int getLength(byte[] buf, int off, int len)
{
if (buf == null || Math.min(buf.length, len) < off + 4)
{
return -1;
}

int lengthInWords
= ((buf[off + 2] & 0xff) << 8) | (buf[off + 3] & 0xff);

return (lengthInWords + 1) * 4;
}

/**
* Gets the RTCP packet version.
*
* @param buf the byte buffer that contains the RTCP header.
* @param off the offset in the byte buffer where the RTCP header starts.
* @param len the number of bytes in buffer which constitute the actual
* data.
* @return the RTCP packet version, or -1 in case of an error.
*/
public static int getVersion(byte[] buf, int off, int len)
{
if (buf == null || Math.min(buf.length, len) < off + 1)
{
return -1;
}

return (buf[off] & 0xc0) >>> 6;
}

/**
* Checks whether the RTCP header is valid or not. It does so by checking
* the RTCP header version and makes sure the buffer is at least 8 bytes
* long.
*
* @param buf the byte buffer that contains the RTCP header.
* @param off the offset in the byte buffer where the RTCP header starts.
* @param len the number of bytes in buffer which constitute the actual
* data.
* @return true if the RTCP packet is valid, false otherwise.
*/
public static boolean isValid(byte[] buf, int off, int len)
{
int version = RTCPHeaderUtils.getVersion(buf, off, len);
if (version != RTCPHeader.VERSION)
{
return false;
}

int pktLen = RTCPHeaderUtils.getLength(buf, off, len);
if (pktLen < RTCPHeader.SIZE)
{
return false;
}

return true;
}
}
99 changes: 99 additions & 0 deletions src/org/jitsi/impl/neomedia/rtcp/RTCPSenderInfoUtils.java
@@ -0,0 +1,99 @@
/*
* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.impl.neomedia.rtcp;

import net.sf.fmj.media.rtp.*;

/**
* Utility class that contains static methods for RTCP sender info manipulation.
*
* TODO maybe merge into the RTCPSenderInfo class.
*
* @author George Politis
*/
public class RTCPSenderInfoUtils
{
/**
* Gets the RTP timestamp.
*
* @param buf the byte buffer that contains the RTCP header.
* @param off the offset in the byte buffer where the RTCP sender info
* starts.
* @param len the number of bytes in buffer which constitute the actual
* data.
* @return the RTP timestamp, or -1 in case of an error.
*/
public static long getTimestamp(byte[] buf, int off, int len)
{
if (buf == null || Math.min(buf.length, len) < off + 12)
{
return -1;
}

return (((buf[off + 8] & 0xff) << 24)
| ((buf[off + 9] & 0xff) << 16)
| ((buf[off + 10] & 0xff) << 8)
| (buf[off + 11] & 0xff)) & 0xffffffffl;
}

/**
* Sets the RTP timestamp.
*
* @param buf the byte buffer that contains the RTCP header.
* @param off the offset in the byte buffer where the RTCP sender info
* starts.
* @param len the number of bytes in buffer which constitute the actual
* data.
* @param ts the new timestamp to be set.
*
* @return the number of bytes written.
*/
public static int setTimestamp(
byte[] buf, int off, int len, long ts)
{
if (buf == null || Math.min(buf.length, len) < off + 12)
{
return -1;
}

buf[off + 8] = (byte)(ts>>24);
buf[off + 9] = (byte)(ts>>16);
buf[off + 10] = (byte)(ts>>8);
buf[off + 11] = (byte)ts;

return 12;
}

/**
*
* @param buf the byte buffer that contains the RTCP header.
* @param off the offset in the byte buffer where the RTCP sender info
* starts.
* @param len the number of bytes in buffer which constitute the actual
* data.
*
* @return true if the RTCP sender info is valid, false otherwise.
*/
public static boolean isValid(byte[] buf, int off, int len)
{
if (buf == null || Math.min(buf.length, len) < RTCPSenderInfo.SIZE)
{
return false;
}

return true;
}
}
81 changes: 76 additions & 5 deletions src/org/jitsi/impl/neomedia/rtp/ResumableStreamRewriter.java
Expand Up @@ -16,6 +16,7 @@
package org.jitsi.impl.neomedia.rtp;

import org.jitsi.impl.neomedia.*;
import org.jitsi.impl.neomedia.rtcp.*;
import org.jitsi.util.*;

/**
Expand Down Expand Up @@ -70,8 +71,11 @@ public ResumableStreamRewriter()
* @param highestSequenceNumberSent the highest sequence number that got
* accepted, mod 16.
* @param seqnumDelta the seqnumDelta between what's been accepted and
* what's been
* received, mod 16.
* what's been received, mod 16.
* @param highestTimestampSent The highest timestamp that got accepted,
* mod 32.
* @param timestampDelta The timestamp delta between what's been accepted
* and what's been received, mod 32.
*/
public ResumableStreamRewriter(
int highestSequenceNumberSent, int seqnumDelta,
Expand All @@ -91,16 +95,16 @@ public ResumableStreamRewriter(
}

/**
* Rewrites the sequence number of the RTP packet in the byte buffer, hiding
* any gaps caused by drops.
* Rewrites the sequence number of the RTP packet in the byte buffer,
* hiding any gaps caused by drops.
*
* @param accept true if the packet is accepted, false otherwise
* @param buf the byte buffer that contains the RTP packet
* @param off the offset in the byte buffer where the RTP packet starts
* @param len the length of the RTP packet in the byte buffer
* @return true if the packet was altered, false otherwise
*/
public boolean rewrite(boolean accept, byte[] buf, int off, int len)
public boolean rewriteRTP(boolean accept, byte[] buf, int off, int len)
{
if (buf == null || buf.length + off < len)
{
Expand Down Expand Up @@ -134,6 +138,73 @@ public boolean rewrite(boolean accept, byte[] buf, int off, int len)
return modified;
}

/**
* Restores the RTP timestamp and sequence number of the RTP packet in the
* buffer.
*
* @param buf the byte buffer that contains the RTP packet.
* @param off the offset in the byte buffer where the RTP packet starts.
* @param len the number of bytes in buffer which constitute the actual
* data.
* @return true if the RTP packet is modified, false otherwise.
*/
public boolean restoreRTP(byte[] buf, int off, int len)
{
boolean modified = false;

if (timestampDelta != 0)
{
long ts = RawPacket.getTimestamp(buf, off, len);
RawPacket.setTimestamp(
buf, off, len, (ts + timestampDelta) & 0xffffffff);

modified = true;
}

if (seqnumDelta != 0)
{
int sn = RawPacket.getSequenceNumber(buf, off, len);
RawPacket.setSequenceNumber(
buf, off, (sn + seqnumDelta) & 0xffff);

modified = true;
}

return modified;
}

/**
* Restores the RTP timestamp of the RTCP SR packet in the buffer.
*
* @param buf the byte buffer that contains the RTCP packet.
* @param off the offset in the byte buffer where the RTCP packet starts.
* @param len the number of bytes in buffer which constitute the actual
* data.
* @return true if the SR is modified, false otherwise.
*/
public boolean processRTCP(boolean rewrite, byte[] buf, int off, int len)
{
if (timestampDelta == 0)
{
return false;
}

long ts = RTCPSenderInfoUtils.getTimestamp(buf, off, len);
if (ts == -1)
{
return false;
}

long newTs = rewrite
? (ts - timestampDelta) & 0xffffffff
: (ts + timestampDelta) & 0xffffffff;

int ret = RTCPSenderInfoUtils.setTimestamp(buf, off, len, newTs);

return ret > 0;
}


/**
* Rewrites the sequence number passed as a parameter, hiding any gaps
* caused by drops.
Expand Down