1/*
2 *  Copyright (c) 2012 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#include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
12
13#include <string.h>
14
15#include "webrtc/base/logging.h"
16#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
17
18namespace webrtc {
19
20RtpData* NullObjectRtpData() {
21  static NullRtpData null_rtp_data;
22  return &null_rtp_data;
23}
24
25RtpFeedback* NullObjectRtpFeedback() {
26  static NullRtpFeedback null_rtp_feedback;
27  return &null_rtp_feedback;
28}
29
30RtpAudioFeedback* NullObjectRtpAudioFeedback() {
31  static NullRtpAudioFeedback null_rtp_audio_feedback;
32  return &null_rtp_audio_feedback;
33}
34
35ReceiveStatistics* NullObjectReceiveStatistics() {
36  static NullReceiveStatistics null_receive_statistics;
37  return &null_receive_statistics;
38}
39
40namespace RtpUtility {
41
42enum {
43  kRtcpExpectedVersion = 2,
44  kRtcpMinHeaderLength = 4,
45  kRtcpMinParseLength = 8,
46
47  kRtpExpectedVersion = 2,
48  kRtpMinParseLength = 12
49};
50
51/*
52 * Misc utility routines
53 */
54
55#if defined(_WIN32)
56bool StringCompare(const char* str1, const char* str2,
57                   const uint32_t length) {
58  return _strnicmp(str1, str2, length) == 0;
59}
60#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
61bool StringCompare(const char* str1, const char* str2,
62                   const uint32_t length) {
63  return strncasecmp(str1, str2, length) == 0;
64}
65#endif
66
67size_t Word32Align(size_t size) {
68  uint32_t remainder = size % 4;
69  if (remainder != 0)
70    return size + 4 - remainder;
71  return size;
72}
73
74RtpHeaderParser::RtpHeaderParser(const uint8_t* rtpData,
75                                 const size_t rtpDataLength)
76    : _ptrRTPDataBegin(rtpData),
77      _ptrRTPDataEnd(rtpData ? (rtpData + rtpDataLength) : NULL) {
78}
79
80RtpHeaderParser::~RtpHeaderParser() {
81}
82
83bool RtpHeaderParser::RTCP() const {
84  // 72 to 76 is reserved for RTP
85  // 77 to 79 is not reserver but  they are not assigned we will block them
86  // for RTCP 200 SR  == marker bit + 72
87  // for RTCP 204 APP == marker bit + 76
88  /*
89  *       RTCP
90  *
91  * FIR      full INTRA-frame request             192     [RFC2032]   supported
92  * NACK     negative acknowledgement             193     [RFC2032]
93  * IJ       Extended inter-arrival jitter report 195     [RFC-ietf-avt-rtp-toff
94  * set-07.txt] http://tools.ietf.org/html/draft-ietf-avt-rtp-toffset-07
95  * SR       sender report                        200     [RFC3551]   supported
96  * RR       receiver report                      201     [RFC3551]   supported
97  * SDES     source description                   202     [RFC3551]   supported
98  * BYE      goodbye                              203     [RFC3551]   supported
99  * APP      application-defined                  204     [RFC3551]   ignored
100  * RTPFB    Transport layer FB message           205     [RFC4585]   supported
101  * PSFB     Payload-specific FB message          206     [RFC4585]   supported
102  * XR       extended report                      207     [RFC3611]   supported
103  */
104
105  /* 205       RFC 5104
106   * FMT 1      NACK       supported
107   * FMT 2      reserved
108   * FMT 3      TMMBR      supported
109   * FMT 4      TMMBN      supported
110   */
111
112  /* 206      RFC 5104
113  * FMT 1:     Picture Loss Indication (PLI)                      supported
114  * FMT 2:     Slice Lost Indication (SLI)
115  * FMT 3:     Reference Picture Selection Indication (RPSI)
116  * FMT 4:     Full Intra Request (FIR) Command                   supported
117  * FMT 5:     Temporal-Spatial Trade-off Request (TSTR)
118  * FMT 6:     Temporal-Spatial Trade-off Notification (TSTN)
119  * FMT 7:     Video Back Channel Message (VBCM)
120  * FMT 15:    Application layer FB message
121  */
122
123  const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
124  if (length < kRtcpMinHeaderLength) {
125    return false;
126  }
127
128  const uint8_t V = _ptrRTPDataBegin[0] >> 6;
129  if (V != kRtcpExpectedVersion) {
130    return false;
131  }
132
133  const uint8_t payloadType = _ptrRTPDataBegin[1];
134  switch (payloadType) {
135    case 192:
136      return true;
137    case 193:
138      // not supported
139      // pass through and check for a potential RTP packet
140      return false;
141    case 195:
142    case 200:
143    case 201:
144    case 202:
145    case 203:
146    case 204:
147    case 205:
148    case 206:
149    case 207:
150      return true;
151    default:
152      return false;
153  }
154}
155
156bool RtpHeaderParser::ParseRtcp(RTPHeader* header) const {
157  assert(header != NULL);
158
159  const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
160  if (length < kRtcpMinParseLength) {
161    return false;
162  }
163
164  const uint8_t V = _ptrRTPDataBegin[0] >> 6;
165  if (V != kRtcpExpectedVersion) {
166    return false;
167  }
168
169  const uint8_t PT = _ptrRTPDataBegin[1];
170  const size_t len = (_ptrRTPDataBegin[2] << 8) + _ptrRTPDataBegin[3];
171  const uint8_t* ptr = &_ptrRTPDataBegin[4];
172
173  uint32_t SSRC = ByteReader<uint32_t>::ReadBigEndian(ptr);
174  ptr += 4;
175
176  header->payloadType  = PT;
177  header->ssrc         = SSRC;
178  header->headerLength = 4 + (len << 2);
179
180  return true;
181}
182
183bool RtpHeaderParser::Parse(RTPHeader* header,
184                            RtpHeaderExtensionMap* ptrExtensionMap) const {
185  const ptrdiff_t length = _ptrRTPDataEnd - _ptrRTPDataBegin;
186  if (length < kRtpMinParseLength) {
187    return false;
188  }
189
190  // Version
191  const uint8_t V  = _ptrRTPDataBegin[0] >> 6;
192  // Padding
193  const bool          P  = ((_ptrRTPDataBegin[0] & 0x20) == 0) ? false : true;
194  // eXtension
195  const bool          X  = ((_ptrRTPDataBegin[0] & 0x10) == 0) ? false : true;
196  const uint8_t CC = _ptrRTPDataBegin[0] & 0x0f;
197  const bool          M  = ((_ptrRTPDataBegin[1] & 0x80) == 0) ? false : true;
198
199  const uint8_t PT = _ptrRTPDataBegin[1] & 0x7f;
200
201  const uint16_t sequenceNumber = (_ptrRTPDataBegin[2] << 8) +
202      _ptrRTPDataBegin[3];
203
204  const uint8_t* ptr = &_ptrRTPDataBegin[4];
205
206  uint32_t RTPTimestamp = ByteReader<uint32_t>::ReadBigEndian(ptr);
207  ptr += 4;
208
209  uint32_t SSRC = ByteReader<uint32_t>::ReadBigEndian(ptr);
210  ptr += 4;
211
212  if (V != kRtpExpectedVersion) {
213    return false;
214  }
215
216  const size_t CSRCocts = CC * 4;
217
218  if ((ptr + CSRCocts) > _ptrRTPDataEnd) {
219    return false;
220  }
221
222  header->markerBit      = M;
223  header->payloadType    = PT;
224  header->sequenceNumber = sequenceNumber;
225  header->timestamp      = RTPTimestamp;
226  header->ssrc           = SSRC;
227  header->numCSRCs       = CC;
228  header->paddingLength  = P ? *(_ptrRTPDataEnd - 1) : 0;
229
230  for (uint8_t i = 0; i < CC; ++i) {
231    uint32_t CSRC = ByteReader<uint32_t>::ReadBigEndian(ptr);
232    ptr += 4;
233    header->arrOfCSRCs[i] = CSRC;
234  }
235
236  header->headerLength   = 12 + CSRCocts;
237
238  // If in effect, MAY be omitted for those packets for which the offset
239  // is zero.
240  header->extension.hasTransmissionTimeOffset = false;
241  header->extension.transmissionTimeOffset = 0;
242
243  // May not be present in packet.
244  header->extension.hasAbsoluteSendTime = false;
245  header->extension.absoluteSendTime = 0;
246
247  // May not be present in packet.
248  header->extension.hasAudioLevel = false;
249  header->extension.voiceActivity = false;
250  header->extension.audioLevel = 0;
251
252  // May not be present in packet.
253  header->extension.hasVideoRotation = false;
254  header->extension.videoRotation = 0;
255
256  if (X) {
257    /* RTP header extension, RFC 3550.
258     0                   1                   2                   3
259     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
260    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
261    |      defined by profile       |           length              |
262    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
263    |                        header extension                       |
264    |                             ....                              |
265    */
266    const ptrdiff_t remain = _ptrRTPDataEnd - ptr;
267    if (remain < 4) {
268      return false;
269    }
270
271    header->headerLength += 4;
272
273    uint16_t definedByProfile = ByteReader<uint16_t>::ReadBigEndian(ptr);
274    ptr += 2;
275
276    // in 32 bit words
277    size_t XLen = ByteReader<uint16_t>::ReadBigEndian(ptr);
278    ptr += 2;
279    XLen *= 4;  // in bytes
280
281    if (static_cast<size_t>(remain) < (4 + XLen)) {
282      return false;
283    }
284    if (definedByProfile == kRtpOneByteHeaderExtensionId) {
285      const uint8_t* ptrRTPDataExtensionEnd = ptr + XLen;
286      ParseOneByteExtensionHeader(header,
287                                  ptrExtensionMap,
288                                  ptrRTPDataExtensionEnd,
289                                  ptr);
290    }
291    header->headerLength += XLen;
292  }
293  if (header->headerLength + header->paddingLength >
294      static_cast<size_t>(length))
295    return false;
296  return true;
297}
298
299void RtpHeaderParser::ParseOneByteExtensionHeader(
300    RTPHeader* header,
301    const RtpHeaderExtensionMap* ptrExtensionMap,
302    const uint8_t* ptrRTPDataExtensionEnd,
303    const uint8_t* ptr) const {
304  if (!ptrExtensionMap) {
305    return;
306  }
307
308  while (ptrRTPDataExtensionEnd - ptr > 0) {
309    //  0
310    //  0 1 2 3 4 5 6 7
311    // +-+-+-+-+-+-+-+-+
312    // |  ID   |  len  |
313    // +-+-+-+-+-+-+-+-+
314
315    // Note that 'len' is the header extension element length, which is the
316    // number of bytes - 1.
317    const int id = (*ptr & 0xf0) >> 4;
318    const int len = (*ptr & 0x0f);
319    ptr++;
320
321    if (id == 15) {
322      LOG(LS_WARNING)
323          << "RTP extension header 15 encountered. Terminate parsing.";
324      return;
325    }
326
327    RTPExtensionType type;
328    if (ptrExtensionMap->GetType(id, &type) != 0) {
329      // If we encounter an unknown extension, just skip over it.
330      LOG(LS_WARNING) << "Failed to find extension id: " << id;
331    } else {
332      switch (type) {
333        case kRtpExtensionTransmissionTimeOffset: {
334          if (len != 2) {
335            LOG(LS_WARNING) << "Incorrect transmission time offset len: "
336                            << len;
337            return;
338          }
339          //  0                   1                   2                   3
340          //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
341          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
342          // |  ID   | len=2 |              transmission offset              |
343          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
344
345          header->extension.transmissionTimeOffset =
346              ByteReader<int32_t, 3>::ReadBigEndian(ptr);
347          header->extension.hasTransmissionTimeOffset = true;
348          break;
349        }
350        case kRtpExtensionAudioLevel: {
351          if (len != 0) {
352            LOG(LS_WARNING) << "Incorrect audio level len: " << len;
353            return;
354          }
355          //  0                   1
356          //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
357          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
358          // |  ID   | len=0 |V|   level     |
359          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
360          //
361          header->extension.audioLevel = ptr[0] & 0x7f;
362          header->extension.voiceActivity = (ptr[0] & 0x80) != 0;
363          header->extension.hasAudioLevel = true;
364          break;
365        }
366        case kRtpExtensionAbsoluteSendTime: {
367          if (len != 2) {
368            LOG(LS_WARNING) << "Incorrect absolute send time len: " << len;
369            return;
370          }
371          //  0                   1                   2                   3
372          //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
373          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
374          // |  ID   | len=2 |              absolute send time               |
375          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
376
377          header->extension.absoluteSendTime =
378              ByteReader<uint32_t, 3>::ReadBigEndian(ptr);
379          header->extension.hasAbsoluteSendTime = true;
380          break;
381        }
382        case kRtpExtensionVideoRotation: {
383          if (len != 0) {
384            LOG(LS_WARNING)
385                << "Incorrect coordination of video coordination len: " << len;
386            return;
387          }
388          //  0                   1
389          //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
390          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
391          // |  ID   | len=0 |0 0 0 0 C F R R|
392          // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
393          header->extension.hasVideoRotation = true;
394          header->extension.videoRotation = ptr[0];
395          break;
396        }
397        case kRtpExtensionTransportSequenceNumber: {
398          if (len != 1) {
399            LOG(LS_WARNING) << "Incorrect transport sequence number len: "
400                            << len;
401            return;
402          }
403          //   0                   1                   2
404          //   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
405          //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
406          //  |  ID   | L=1   |transport wide sequence number |
407          //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
408
409          uint16_t sequence_number = ptr[0] << 8;
410          sequence_number += ptr[1];
411          header->extension.transportSequenceNumber = sequence_number;
412          header->extension.hasTransportSequenceNumber = true;
413          break;
414        }
415        default: {
416          LOG(LS_WARNING) << "Extension type not implemented: " << type;
417          return;
418        }
419      }
420    }
421    ptr += (len + 1);
422    uint8_t num_bytes = ParsePaddingBytes(ptrRTPDataExtensionEnd, ptr);
423    ptr += num_bytes;
424  }
425}
426
427uint8_t RtpHeaderParser::ParsePaddingBytes(
428    const uint8_t* ptrRTPDataExtensionEnd,
429    const uint8_t* ptr) const {
430  uint8_t num_zero_bytes = 0;
431  while (ptrRTPDataExtensionEnd - ptr > 0) {
432    if (*ptr != 0) {
433      return num_zero_bytes;
434    }
435    ptr++;
436    num_zero_bytes++;
437  }
438  return num_zero_bytes;
439}
440}  // namespace RtpUtility
441}  // namespace webrtc
442