blob: bd4f9a2260b064bd445ccda5a6bcee849ff196a7 [file] [log] [blame]
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
/*
* RTP related functions.
*/
#include "rtp.h"
#include "typedefs.h" /* to define endianness */
#include "neteq_error_codes.h"
int WebRtcNetEQ_RTPPayloadInfo(WebRtc_Word16* pw16_Datagram, int i_DatagramLen,
RTPPacket_t* RTPheader)
{
int i_P, i_X, i_CC, i_startPosition;
int i_IPver;
int i_extlength = -1; /* Default value is there is no extension */
int i_padlength = 0; /* Default value if there is no padding */
if (i_DatagramLen < 12)
{
return RTP_TOO_SHORT_PACKET;
}
#ifdef WEBRTC_BIG_ENDIAN
i_IPver = (((WebRtc_UWord16) (pw16_Datagram[0] & 0xC000)) >> 14); /* Extract the version */
i_P = (((WebRtc_UWord16) (pw16_Datagram[0] & 0x2000)) >> 13); /* Extract the P bit */
i_X = (((WebRtc_UWord16) (pw16_Datagram[0] & 0x1000)) >> 12); /* Extract the X bit */
i_CC = ((WebRtc_UWord16) (pw16_Datagram[0] >> 8) & 0xF); /* Get the CC number */
RTPheader->payloadType = pw16_Datagram[0] & 0x7F; /* Get the coder type */
RTPheader->seqNumber = pw16_Datagram[1]; /* Get the sequence number */
RTPheader->timeStamp = ((((WebRtc_UWord32) ((WebRtc_UWord16) pw16_Datagram[2])) << 16)
| (WebRtc_UWord16) (pw16_Datagram[3])); /* Get timestamp */
RTPheader->ssrc = (((WebRtc_UWord32) pw16_Datagram[4]) << 16)
+ (((WebRtc_UWord32) pw16_Datagram[5])); /* Get the SSRC */
if (i_X == 1)
{
/* Extension header exists. Find out how many WebRtc_Word32 it consists of. */
i_extlength = pw16_Datagram[7 + 2 * i_CC];
}
if (i_P == 1)
{
/* Padding exists. Find out how many bytes the padding consists of. */
if (i_DatagramLen & 0x1)
{
/* odd number of bytes => last byte in higher byte */
i_padlength = (((WebRtc_UWord16) pw16_Datagram[i_DatagramLen >> 1]) >> 8);
}
else
{
/* even number of bytes => last byte in lower byte */
i_padlength = ((pw16_Datagram[(i_DatagramLen >> 1) - 1]) & 0xFF);
}
}
#else /* WEBRTC_LITTLE_ENDIAN */
i_IPver = (((WebRtc_UWord16) (pw16_Datagram[0] & 0xC0)) >> 6); /* Extract the IP version */
i_P = (((WebRtc_UWord16) (pw16_Datagram[0] & 0x20)) >> 5); /* Extract the P bit */
i_X = (((WebRtc_UWord16) (pw16_Datagram[0] & 0x10)) >> 4); /* Extract the X bit */
i_CC = (WebRtc_UWord16) (pw16_Datagram[0] & 0xF); /* Get the CC number */
RTPheader->payloadType = (pw16_Datagram[0] >> 8) & 0x7F; /* Get the coder type */
RTPheader->seqNumber = (((((WebRtc_UWord16) pw16_Datagram[1]) >> 8) & 0xFF)
| (((WebRtc_UWord16) (pw16_Datagram[1] & 0xFF)) << 8)); /* Get the packet number */
RTPheader->timeStamp = ((((WebRtc_UWord16) pw16_Datagram[2]) & 0xFF) << 24)
| ((((WebRtc_UWord16) pw16_Datagram[2]) & 0xFF00) << 8)
| ((((WebRtc_UWord16) pw16_Datagram[3]) >> 8) & 0xFF)
| ((((WebRtc_UWord16) pw16_Datagram[3]) & 0xFF) << 8); /* Get timestamp */
RTPheader->ssrc = ((((WebRtc_UWord16) pw16_Datagram[4]) & 0xFF) << 24)
| ((((WebRtc_UWord16) pw16_Datagram[4]) & 0xFF00) << 8)
| ((((WebRtc_UWord16) pw16_Datagram[5]) >> 8) & 0xFF)
| ((((WebRtc_UWord16) pw16_Datagram[5]) & 0xFF) << 8); /* Get the SSRC */
if (i_X == 1)
{
/* Extension header exists. Find out how many WebRtc_Word32 it consists of. */
i_extlength = (((((WebRtc_UWord16) pw16_Datagram[7 + 2 * i_CC]) >> 8) & 0xFF)
| (((WebRtc_UWord16) (pw16_Datagram[7 + 2 * i_CC] & 0xFF)) << 8));
}
if (i_P == 1)
{
/* Padding exists. Find out how many bytes the padding consists of. */
if (i_DatagramLen & 0x1)
{
/* odd number of bytes => last byte in higher byte */
i_padlength = (pw16_Datagram[i_DatagramLen >> 1] & 0xFF);
}
else
{
/* even number of bytes => last byte in lower byte */
i_padlength = (((WebRtc_UWord16) pw16_Datagram[(i_DatagramLen >> 1) - 1]) >> 8);
}
}
#endif
i_startPosition = 12 + 4 * (i_extlength + 1) + 4 * i_CC;
RTPheader->payload = &pw16_Datagram[i_startPosition >> 1];
RTPheader->payloadLen = i_DatagramLen - i_startPosition - i_padlength;
RTPheader->starts_byte1 = 0;
if ((i_IPver != 2) || (RTPheader->payloadLen <= 0) || (RTPheader->payloadLen >= 16000)
|| (i_startPosition < 12) || (i_startPosition > i_DatagramLen))
{
return RTP_CORRUPT_PACKET;
}
return 0;
}
#ifdef NETEQ_RED_CODEC
int WebRtcNetEQ_RedundancySplit(RTPPacket_t* RTPheader[], int i_MaximumPayloads,
int *i_No_Of_Payloads)
{
const WebRtc_Word16 *pw16_data = RTPheader[0]->payload; /* Pointer to the data */
WebRtc_UWord16 uw16_offsetTimeStamp = 65535, uw16_secondPayload = 65535;
int i_blockLength, i_k;
int i_discardedBlockLength = 0;
int singlePayload = 0;
#ifdef WEBRTC_BIG_ENDIAN
if ((pw16_data[0] & 0x8000) == 0)
{
/* Only one payload in this packet*/
singlePayload = 1;
/* set the blocklength to -4 to deduce the non-existent 4-byte RED header */
i_blockLength = -4;
RTPheader[0]->payloadType = ((((WebRtc_UWord16)pw16_data[0]) & 0x7F00) >> 8);
}
else
{
/* Discard all but the two last payloads. */
while (((pw16_data[2] & 0x8000) == 1)&&
(pw16_data<((RTPheader[0]->payload)+((RTPheader[0]->payloadLen+1)>>1))))
{
i_discardedBlockLength += (4+(((WebRtc_UWord16)pw16_data[1]) & 0x3FF));
pw16_data+=2;
}
if (pw16_data>=(RTPheader[0]->payload+((RTPheader[0]->payloadLen+1)>>1)))
{
return RED_SPLIT_ERROR2; /* Error, we are outside the packet */
}
singlePayload = 0; /* the packet contains more than one payload */
uw16_secondPayload = ((((WebRtc_UWord16)pw16_data[0]) & 0x7F00) >> 8);
RTPheader[0]->payloadType = ((((WebRtc_UWord16)pw16_data[2]) & 0x7F00) >> 8);
uw16_offsetTimeStamp = ((((WebRtc_UWord16)pw16_data[0]) & 0xFF) << 6) +
((((WebRtc_UWord16)pw16_data[1]) & 0xFC00) >> 10);
i_blockLength = (((WebRtc_UWord16)pw16_data[1]) & 0x3FF);
}
#else /* WEBRTC_LITTLE_ENDIAN */
if ((pw16_data[0] & 0x80) == 0)
{
/* Only one payload in this packet */
singlePayload = 1;
/* set the blocklength to -4 to deduce the non-existent 4-byte RED header */
i_blockLength = -4;
RTPheader[0]->payloadType = (((WebRtc_UWord16) pw16_data[0]) & 0x7F);
}
else
{
/* Discard all but the two last payloads. */
while (((pw16_data[2] & 0x80) == 1) && (pw16_data < ((RTPheader[0]->payload)
+ ((RTPheader[0]->payloadLen + 1) >> 1))))
{
i_discardedBlockLength += (4 + ((((WebRtc_UWord16) pw16_data[1]) & 0x3) << 8)
+ ((((WebRtc_UWord16) pw16_data[1]) & 0xFF00) >> 8));
pw16_data += 2;
}
if (pw16_data >= (RTPheader[0]->payload + ((RTPheader[0]->payloadLen + 1) >> 1)))
{
return RED_SPLIT_ERROR2; /* Error, we are outside the packet */;
}
singlePayload = 0; /* the packet contains more than one payload */
uw16_secondPayload = (((WebRtc_UWord16) pw16_data[0]) & 0x7F);
RTPheader[0]->payloadType = (((WebRtc_UWord16) pw16_data[2]) & 0x7F);
uw16_offsetTimeStamp = ((((WebRtc_UWord16) pw16_data[0]) & 0xFF00) >> 2)
+ ((((WebRtc_UWord16) pw16_data[1]) & 0xFC) >> 2);
i_blockLength = ((((WebRtc_UWord16) pw16_data[1]) & 0x3) << 8)
+ ((((WebRtc_UWord16) pw16_data[1]) & 0xFF00) >> 8);
}
#endif
if (i_MaximumPayloads < 2 || singlePayload == 1)
{
/* Reject the redundancy; or no redundant payload present. */
for (i_k = 1; i_k < i_MaximumPayloads; i_k++)
{
RTPheader[i_k]->payloadType = -1;
RTPheader[i_k]->payloadLen = 0;
}
/* update the pointer for the main data */
pw16_data = &pw16_data[(5 + i_blockLength) >> 1];
RTPheader[0]->starts_byte1 = (5 + i_blockLength) & 0x1;
RTPheader[0]->payloadLen = RTPheader[0]->payloadLen - (i_blockLength + 5)
- i_discardedBlockLength;
RTPheader[0]->payload = pw16_data;
*i_No_Of_Payloads = 1;
}
else
{
/* Redundancy accepted, put the redundancy in second RTPheader. */
RTPheader[1]->payloadType = uw16_secondPayload;
RTPheader[1]->payload = &pw16_data[5 >> 1];
RTPheader[1]->starts_byte1 = 5 & 0x1;
RTPheader[1]->seqNumber = RTPheader[0]->seqNumber;
RTPheader[1]->timeStamp = RTPheader[0]->timeStamp - uw16_offsetTimeStamp;
RTPheader[1]->ssrc = RTPheader[0]->ssrc;
RTPheader[1]->payloadLen = i_blockLength;
/* Modify first RTP packet, so that it contains the main data. */
RTPheader[0]->payload = &pw16_data[(5 + i_blockLength) >> 1];
RTPheader[0]->starts_byte1 = (5 + i_blockLength) & 0x1;
RTPheader[0]->payloadLen = RTPheader[0]->payloadLen - (i_blockLength + 5)
- i_discardedBlockLength;
/* Clear the following payloads. */
for (i_k = 2; i_k < i_MaximumPayloads; i_k++)
{
RTPheader[i_k]->payloadType = -1;
RTPheader[i_k]->payloadLen = 0;
}
*i_No_Of_Payloads = 2;
}
return 0;
}
#endif