• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
18 namespace webrtc {
19 
NullObjectRtpData()20 RtpData* NullObjectRtpData() {
21   static NullRtpData null_rtp_data;
22   return &null_rtp_data;
23 }
24 
NullObjectRtpFeedback()25 RtpFeedback* NullObjectRtpFeedback() {
26   static NullRtpFeedback null_rtp_feedback;
27   return &null_rtp_feedback;
28 }
29 
NullObjectRtpAudioFeedback()30 RtpAudioFeedback* NullObjectRtpAudioFeedback() {
31   static NullRtpAudioFeedback null_rtp_audio_feedback;
32   return &null_rtp_audio_feedback;
33 }
34 
NullObjectReceiveStatistics()35 ReceiveStatistics* NullObjectReceiveStatistics() {
36   static NullReceiveStatistics null_receive_statistics;
37   return &null_receive_statistics;
38 }
39 
40 namespace RtpUtility {
41 
42 enum {
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)
StringCompare(const char * str1,const char * str2,const uint32_t length)56 bool 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)
StringCompare(const char * str1,const char * str2,const uint32_t length)61 bool StringCompare(const char* str1, const char* str2,
62                    const uint32_t length) {
63   return strncasecmp(str1, str2, length) == 0;
64 }
65 #endif
66 
Word32Align(size_t size)67 size_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 
RtpHeaderParser(const uint8_t * rtpData,const size_t rtpDataLength)74 RtpHeaderParser::RtpHeaderParser(const uint8_t* rtpData,
75                                  const size_t rtpDataLength)
76     : _ptrRTPDataBegin(rtpData),
77       _ptrRTPDataEnd(rtpData ? (rtpData + rtpDataLength) : NULL) {
78 }
79 
~RtpHeaderParser()80 RtpHeaderParser::~RtpHeaderParser() {
81 }
82 
RTCP() const83 bool 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 
ParseRtcp(RTPHeader * header) const156 bool 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 
Parse(RTPHeader * header,RtpHeaderExtensionMap * ptrExtensionMap) const183 bool 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 
ParseOneByteExtensionHeader(RTPHeader * header,const RtpHeaderExtensionMap * ptrExtensionMap,const uint8_t * ptrRTPDataExtensionEnd,const uint8_t * ptr) const299 void 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 
ParsePaddingBytes(const uint8_t * ptrRTPDataExtensionEnd,const uint8_t * ptr) const427 uint8_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