|  | /* | 
|  | *  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) != 0) && | 
|  | (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) != 0) && (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 | 
|  |  |