blob: 6ab5944b5aa734a31b05fc5e8fcf72d52d18a335 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11/*
12 * RTP related functions.
13 */
14
15#include "rtp.h"
16
17#include "typedefs.h" /* to define endianness */
18
19#include "neteq_error_codes.h"
20
pbos@webrtc.org0946a562013-04-09 00:28:06 +000021int WebRtcNetEQ_RTPPayloadInfo(int16_t* pw16_Datagram, int i_DatagramLen,
niklase@google.com470e71d2011-07-07 08:21:25 +000022 RTPPacket_t* RTPheader)
23{
24 int i_P, i_X, i_CC, i_startPosition;
25 int i_IPver;
26 int i_extlength = -1; /* Default value is there is no extension */
27 int i_padlength = 0; /* Default value if there is no padding */
28
29 if (i_DatagramLen < 12)
30 {
31 return RTP_TOO_SHORT_PACKET;
32 }
33
andrew@webrtc.org621df672013-10-22 10:27:23 +000034#ifdef WEBRTC_ARCH_BIG_ENDIAN
pbos@webrtc.org0946a562013-04-09 00:28:06 +000035 i_IPver = (((uint16_t) (pw16_Datagram[0] & 0xC000)) >> 14); /* Extract the version */
36 i_P = (((uint16_t) (pw16_Datagram[0] & 0x2000)) >> 13); /* Extract the P bit */
37 i_X = (((uint16_t) (pw16_Datagram[0] & 0x1000)) >> 12); /* Extract the X bit */
38 i_CC = ((uint16_t) (pw16_Datagram[0] >> 8) & 0xF); /* Get the CC number */
niklase@google.com470e71d2011-07-07 08:21:25 +000039 RTPheader->payloadType = pw16_Datagram[0] & 0x7F; /* Get the coder type */
40 RTPheader->seqNumber = pw16_Datagram[1]; /* Get the sequence number */
pbos@webrtc.org0946a562013-04-09 00:28:06 +000041 RTPheader->timeStamp = ((((uint32_t) ((uint16_t) pw16_Datagram[2])) << 16)
42 | (uint16_t) (pw16_Datagram[3])); /* Get timestamp */
43 RTPheader->ssrc = (((uint32_t) pw16_Datagram[4]) << 16)
44 + (((uint32_t) pw16_Datagram[5])); /* Get the SSRC */
niklase@google.com470e71d2011-07-07 08:21:25 +000045
46 if (i_X == 1)
47 {
pbos@webrtc.org0946a562013-04-09 00:28:06 +000048 /* Extension header exists. Find out how many int32_t it consists of. */
niklase@google.com470e71d2011-07-07 08:21:25 +000049 i_extlength = pw16_Datagram[7 + 2 * i_CC];
50 }
51 if (i_P == 1)
52 {
53 /* Padding exists. Find out how many bytes the padding consists of. */
54 if (i_DatagramLen & 0x1)
55 {
56 /* odd number of bytes => last byte in higher byte */
pbos@webrtc.org0946a562013-04-09 00:28:06 +000057 i_padlength = (((uint16_t) pw16_Datagram[i_DatagramLen >> 1]) >> 8);
niklase@google.com470e71d2011-07-07 08:21:25 +000058 }
59 else
60 {
61 /* even number of bytes => last byte in lower byte */
62 i_padlength = ((pw16_Datagram[(i_DatagramLen >> 1) - 1]) & 0xFF);
63 }
64 }
andrew@webrtc.org621df672013-10-22 10:27:23 +000065#else /* WEBRTC_ARCH_LITTLE_ENDIAN */
pbos@webrtc.org0946a562013-04-09 00:28:06 +000066 i_IPver = (((uint16_t) (pw16_Datagram[0] & 0xC0)) >> 6); /* Extract the IP version */
67 i_P = (((uint16_t) (pw16_Datagram[0] & 0x20)) >> 5); /* Extract the P bit */
68 i_X = (((uint16_t) (pw16_Datagram[0] & 0x10)) >> 4); /* Extract the X bit */
69 i_CC = (uint16_t) (pw16_Datagram[0] & 0xF); /* Get the CC number */
niklase@google.com470e71d2011-07-07 08:21:25 +000070 RTPheader->payloadType = (pw16_Datagram[0] >> 8) & 0x7F; /* Get the coder type */
pbos@webrtc.org0946a562013-04-09 00:28:06 +000071 RTPheader->seqNumber = (((((uint16_t) pw16_Datagram[1]) >> 8) & 0xFF)
72 | (((uint16_t) (pw16_Datagram[1] & 0xFF)) << 8)); /* Get the packet number */
73 RTPheader->timeStamp = ((((uint16_t) pw16_Datagram[2]) & 0xFF) << 24)
74 | ((((uint16_t) pw16_Datagram[2]) & 0xFF00) << 8)
75 | ((((uint16_t) pw16_Datagram[3]) >> 8) & 0xFF)
76 | ((((uint16_t) pw16_Datagram[3]) & 0xFF) << 8); /* Get timestamp */
77 RTPheader->ssrc = ((((uint16_t) pw16_Datagram[4]) & 0xFF) << 24)
78 | ((((uint16_t) pw16_Datagram[4]) & 0xFF00) << 8)
79 | ((((uint16_t) pw16_Datagram[5]) >> 8) & 0xFF)
80 | ((((uint16_t) pw16_Datagram[5]) & 0xFF) << 8); /* Get the SSRC */
niklase@google.com470e71d2011-07-07 08:21:25 +000081
82 if (i_X == 1)
83 {
pbos@webrtc.org0946a562013-04-09 00:28:06 +000084 /* Extension header exists. Find out how many int32_t it consists of. */
85 i_extlength = (((((uint16_t) pw16_Datagram[7 + 2 * i_CC]) >> 8) & 0xFF)
86 | (((uint16_t) (pw16_Datagram[7 + 2 * i_CC] & 0xFF)) << 8));
niklase@google.com470e71d2011-07-07 08:21:25 +000087 }
88 if (i_P == 1)
89 {
90 /* Padding exists. Find out how many bytes the padding consists of. */
91 if (i_DatagramLen & 0x1)
92 {
93 /* odd number of bytes => last byte in higher byte */
94 i_padlength = (pw16_Datagram[i_DatagramLen >> 1] & 0xFF);
95 }
96 else
97 {
98 /* even number of bytes => last byte in lower byte */
pbos@webrtc.org0946a562013-04-09 00:28:06 +000099 i_padlength = (((uint16_t) pw16_Datagram[(i_DatagramLen >> 1) - 1]) >> 8);
niklase@google.com470e71d2011-07-07 08:21:25 +0000100 }
101 }
102#endif
103
104 i_startPosition = 12 + 4 * (i_extlength + 1) + 4 * i_CC;
105 RTPheader->payload = &pw16_Datagram[i_startPosition >> 1];
106 RTPheader->payloadLen = i_DatagramLen - i_startPosition - i_padlength;
107 RTPheader->starts_byte1 = 0;
108
109 if ((i_IPver != 2) || (RTPheader->payloadLen <= 0) || (RTPheader->payloadLen >= 16000)
110 || (i_startPosition < 12) || (i_startPosition > i_DatagramLen))
111 {
112 return RTP_CORRUPT_PACKET;
113 }
114
115 return 0;
116}
117
118#ifdef NETEQ_RED_CODEC
119
120int WebRtcNetEQ_RedundancySplit(RTPPacket_t* RTPheader[], int i_MaximumPayloads,
121 int *i_No_Of_Payloads)
122{
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000123 const int16_t *pw16_data = RTPheader[0]->payload; /* Pointer to the data */
124 uint16_t uw16_offsetTimeStamp = 65535, uw16_secondPayload = 65535;
niklase@google.com470e71d2011-07-07 08:21:25 +0000125 int i_blockLength, i_k;
126 int i_discardedBlockLength = 0;
127 int singlePayload = 0;
128
andrew@webrtc.org621df672013-10-22 10:27:23 +0000129#ifdef WEBRTC_ARCH_BIG_ENDIAN
niklase@google.com470e71d2011-07-07 08:21:25 +0000130 if ((pw16_data[0] & 0x8000) == 0)
131 {
132 /* Only one payload in this packet*/
133 singlePayload = 1;
134 /* set the blocklength to -4 to deduce the non-existent 4-byte RED header */
135 i_blockLength = -4;
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000136 RTPheader[0]->payloadType = ((((uint16_t)pw16_data[0]) & 0x7F00) >> 8);
niklase@google.com470e71d2011-07-07 08:21:25 +0000137 }
138 else
139 {
140 /* Discard all but the two last payloads. */
henrik.lundin@webrtc.orgf0effa12012-09-11 12:44:06 +0000141 while (((pw16_data[2] & 0x8000) != 0) &&
niklase@google.com470e71d2011-07-07 08:21:25 +0000142 (pw16_data<((RTPheader[0]->payload)+((RTPheader[0]->payloadLen+1)>>1))))
143 {
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000144 i_discardedBlockLength += (4+(((uint16_t)pw16_data[1]) & 0x3FF));
niklase@google.com470e71d2011-07-07 08:21:25 +0000145 pw16_data+=2;
146 }
147 if (pw16_data>=(RTPheader[0]->payload+((RTPheader[0]->payloadLen+1)>>1)))
148 {
149 return RED_SPLIT_ERROR2; /* Error, we are outside the packet */
150 }
151 singlePayload = 0; /* the packet contains more than one payload */
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000152 uw16_secondPayload = ((((uint16_t)pw16_data[0]) & 0x7F00) >> 8);
153 RTPheader[0]->payloadType = ((((uint16_t)pw16_data[2]) & 0x7F00) >> 8);
154 uw16_offsetTimeStamp = ((((uint16_t)pw16_data[0]) & 0xFF) << 6) +
155 ((((uint16_t)pw16_data[1]) & 0xFC00) >> 10);
156 i_blockLength = (((uint16_t)pw16_data[1]) & 0x3FF);
niklase@google.com470e71d2011-07-07 08:21:25 +0000157 }
andrew@webrtc.org621df672013-10-22 10:27:23 +0000158#else /* WEBRTC_ARCH_LITTLE_ENDIAN */
niklase@google.com470e71d2011-07-07 08:21:25 +0000159 if ((pw16_data[0] & 0x80) == 0)
160 {
161 /* Only one payload in this packet */
162 singlePayload = 1;
163 /* set the blocklength to -4 to deduce the non-existent 4-byte RED header */
164 i_blockLength = -4;
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000165 RTPheader[0]->payloadType = (((uint16_t) pw16_data[0]) & 0x7F);
niklase@google.com470e71d2011-07-07 08:21:25 +0000166 }
167 else
168 {
169 /* Discard all but the two last payloads. */
henrik.lundin@webrtc.orgf0effa12012-09-11 12:44:06 +0000170 while (((pw16_data[2] & 0x80) != 0) && (pw16_data < ((RTPheader[0]->payload)
niklase@google.com470e71d2011-07-07 08:21:25 +0000171 + ((RTPheader[0]->payloadLen + 1) >> 1))))
172 {
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000173 i_discardedBlockLength += (4 + ((((uint16_t) pw16_data[1]) & 0x3) << 8)
174 + ((((uint16_t) pw16_data[1]) & 0xFF00) >> 8));
niklase@google.com470e71d2011-07-07 08:21:25 +0000175 pw16_data += 2;
176 }
177 if (pw16_data >= (RTPheader[0]->payload + ((RTPheader[0]->payloadLen + 1) >> 1)))
178 {
179 return RED_SPLIT_ERROR2; /* Error, we are outside the packet */;
180 }
181 singlePayload = 0; /* the packet contains more than one payload */
pbos@webrtc.org0946a562013-04-09 00:28:06 +0000182 uw16_secondPayload = (((uint16_t) pw16_data[0]) & 0x7F);
183 RTPheader[0]->payloadType = (((uint16_t) pw16_data[2]) & 0x7F);
184 uw16_offsetTimeStamp = ((((uint16_t) pw16_data[0]) & 0xFF00) >> 2)
185 + ((((uint16_t) pw16_data[1]) & 0xFC) >> 2);
186 i_blockLength = ((((uint16_t) pw16_data[1]) & 0x3) << 8)
187 + ((((uint16_t) pw16_data[1]) & 0xFF00) >> 8);
niklase@google.com470e71d2011-07-07 08:21:25 +0000188 }
189#endif
190
191 if (i_MaximumPayloads < 2 || singlePayload == 1)
192 {
193 /* Reject the redundancy; or no redundant payload present. */
194 for (i_k = 1; i_k < i_MaximumPayloads; i_k++)
195 {
196 RTPheader[i_k]->payloadType = -1;
197 RTPheader[i_k]->payloadLen = 0;
198 }
199
200 /* update the pointer for the main data */
201 pw16_data = &pw16_data[(5 + i_blockLength) >> 1];
202 RTPheader[0]->starts_byte1 = (5 + i_blockLength) & 0x1;
203 RTPheader[0]->payloadLen = RTPheader[0]->payloadLen - (i_blockLength + 5)
204 - i_discardedBlockLength;
205 RTPheader[0]->payload = pw16_data;
206
207 *i_No_Of_Payloads = 1;
208
209 }
210 else
211 {
212 /* Redundancy accepted, put the redundancy in second RTPheader. */
213 RTPheader[1]->payloadType = uw16_secondPayload;
214 RTPheader[1]->payload = &pw16_data[5 >> 1];
215 RTPheader[1]->starts_byte1 = 5 & 0x1;
216 RTPheader[1]->seqNumber = RTPheader[0]->seqNumber;
217 RTPheader[1]->timeStamp = RTPheader[0]->timeStamp - uw16_offsetTimeStamp;
218 RTPheader[1]->ssrc = RTPheader[0]->ssrc;
219 RTPheader[1]->payloadLen = i_blockLength;
220
221 /* Modify first RTP packet, so that it contains the main data. */
222 RTPheader[0]->payload = &pw16_data[(5 + i_blockLength) >> 1];
223 RTPheader[0]->starts_byte1 = (5 + i_blockLength) & 0x1;
224 RTPheader[0]->payloadLen = RTPheader[0]->payloadLen - (i_blockLength + 5)
225 - i_discardedBlockLength;
226
227 /* Clear the following payloads. */
228 for (i_k = 2; i_k < i_MaximumPayloads; i_k++)
229 {
230 RTPheader[i_k]->payloadType = -1;
231 RTPheader[i_k]->payloadLen = 0;
232 }
233
234 *i_No_Of_Payloads = 2;
235 }
236 return 0;
237}
238
239#endif
240