1 /*
2 * Copyright (c) 2016 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 "modules/rtp_rtcp/source/rtp_header_extensions.h"
12
13 #include "modules/rtp_rtcp/include/rtp_cvo.h"
14 #include "modules/rtp_rtcp/source/byte_io.h"
15 #include "rtc_base/checks.h"
16 #include "rtc_base/logging.h"
17
18 namespace webrtc {
19 // Absolute send time in RTP streams.
20 //
21 // The absolute send time is signaled to the receiver in-band using the
22 // general mechanism for RTP header extensions [RFC5285]. The payload
23 // of this extension (the transmitted value) is a 24-bit unsigned integer
24 // containing the sender's current time in seconds as a fixed point number
25 // with 18 bits fractional part.
26 //
27 // The form of the absolute send time extension block:
28 //
29 // 0 1 2 3
30 // 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
31 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32 // | ID | len=2 | absolute send time |
33 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34 constexpr RTPExtensionType AbsoluteSendTime::kId;
35 constexpr uint8_t AbsoluteSendTime::kValueSizeBytes;
36 constexpr const char AbsoluteSendTime::kUri[];
37
Parse(rtc::ArrayView<const uint8_t> data,uint32_t * time_24bits)38 bool AbsoluteSendTime::Parse(rtc::ArrayView<const uint8_t> data,
39 uint32_t* time_24bits) {
40 if (data.size() != 3)
41 return false;
42 *time_24bits = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
43 return true;
44 }
45
Write(uint8_t * data,uint32_t time_24bits)46 bool AbsoluteSendTime::Write(uint8_t* data, uint32_t time_24bits) {
47 RTC_DCHECK_LE(time_24bits, 0x00FFFFFF);
48 ByteWriter<uint32_t, 3>::WriteBigEndian(data, time_24bits);
49 return true;
50 }
51
52 // An RTP Header Extension for Client-to-Mixer Audio Level Indication
53 //
54 // https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/
55 //
56 // The form of the audio level extension block:
57 //
58 // 0 1
59 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
60 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
61 // | ID | len=0 |V| level |
62 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
63 //
64 constexpr RTPExtensionType AudioLevel::kId;
65 constexpr uint8_t AudioLevel::kValueSizeBytes;
66 constexpr const char AudioLevel::kUri[];
67
Parse(rtc::ArrayView<const uint8_t> data,bool * voice_activity,uint8_t * audio_level)68 bool AudioLevel::Parse(rtc::ArrayView<const uint8_t> data,
69 bool* voice_activity,
70 uint8_t* audio_level) {
71 if (data.size() != 1)
72 return false;
73 *voice_activity = (data[0] & 0x80) != 0;
74 *audio_level = data[0] & 0x7F;
75 return true;
76 }
77
Write(uint8_t * data,bool voice_activity,uint8_t audio_level)78 bool AudioLevel::Write(uint8_t* data,
79 bool voice_activity,
80 uint8_t audio_level) {
81 RTC_CHECK_LE(audio_level, 0x7f);
82 data[0] = (voice_activity ? 0x80 : 0x00) | audio_level;
83 return true;
84 }
85
86 // From RFC 5450: Transmission Time Offsets in RTP Streams.
87 //
88 // The transmission time is signaled to the receiver in-band using the
89 // general mechanism for RTP header extensions [RFC5285]. The payload
90 // of this extension (the transmitted value) is a 24-bit signed integer.
91 // When added to the RTP timestamp of the packet, it represents the
92 // "effective" RTP transmission time of the packet, on the RTP
93 // timescale.
94 //
95 // The form of the transmission offset extension block:
96 //
97 // 0 1 2 3
98 // 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
99 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
100 // | ID | len=2 | transmission offset |
101 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
102 constexpr RTPExtensionType TransmissionOffset::kId;
103 constexpr uint8_t TransmissionOffset::kValueSizeBytes;
104 constexpr const char TransmissionOffset::kUri[];
105
Parse(rtc::ArrayView<const uint8_t> data,int32_t * rtp_time)106 bool TransmissionOffset::Parse(rtc::ArrayView<const uint8_t> data,
107 int32_t* rtp_time) {
108 if (data.size() != 3)
109 return false;
110 *rtp_time = ByteReader<int32_t, 3>::ReadBigEndian(data.data());
111 return true;
112 }
113
Write(uint8_t * data,int32_t rtp_time)114 bool TransmissionOffset::Write(uint8_t* data, int32_t rtp_time) {
115 RTC_DCHECK_LE(rtp_time, 0x00ffffff);
116 ByteWriter<int32_t, 3>::WriteBigEndian(data, rtp_time);
117 return true;
118 }
119
120 // 0 1 2
121 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
122 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
123 // | ID | L=1 |transport wide sequence number |
124 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
125 constexpr RTPExtensionType TransportSequenceNumber::kId;
126 constexpr uint8_t TransportSequenceNumber::kValueSizeBytes;
127 constexpr const char TransportSequenceNumber::kUri[];
128
Parse(rtc::ArrayView<const uint8_t> data,uint16_t * value)129 bool TransportSequenceNumber::Parse(rtc::ArrayView<const uint8_t> data,
130 uint16_t* value) {
131 if (data.size() != 2)
132 return false;
133 *value = ByteReader<uint16_t>::ReadBigEndian(data.data());
134 return true;
135 }
136
Write(uint8_t * data,uint16_t value)137 bool TransportSequenceNumber::Write(uint8_t* data, uint16_t value) {
138 ByteWriter<uint16_t>::WriteBigEndian(data, value);
139 return true;
140 }
141
142 // Coordination of Video Orientation in RTP streams.
143 //
144 // Coordination of Video Orientation consists in signaling of the current
145 // orientation of the image captured on the sender side to the receiver for
146 // appropriate rendering and displaying.
147 //
148 // 0 1
149 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
150 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
151 // | ID | len=0 |0 0 0 0 C F R R|
152 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
153 constexpr RTPExtensionType VideoOrientation::kId;
154 constexpr uint8_t VideoOrientation::kValueSizeBytes;
155 constexpr const char VideoOrientation::kUri[];
156
Parse(rtc::ArrayView<const uint8_t> data,VideoRotation * rotation)157 bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
158 VideoRotation* rotation) {
159 if (data.size() != 1)
160 return false;
161 *rotation = ConvertCVOByteToVideoRotation(data[0]);
162 return true;
163 }
164
Write(uint8_t * data,VideoRotation rotation)165 bool VideoOrientation::Write(uint8_t* data, VideoRotation rotation) {
166 data[0] = ConvertVideoRotationToCVOByte(rotation);
167 return true;
168 }
169
Parse(rtc::ArrayView<const uint8_t> data,uint8_t * value)170 bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
171 uint8_t* value) {
172 if (data.size() != 1)
173 return false;
174 *value = data[0];
175 return true;
176 }
177
Write(uint8_t * data,uint8_t value)178 bool VideoOrientation::Write(uint8_t* data, uint8_t value) {
179 data[0] = value;
180 return true;
181 }
182
183 // 0 1 2 3
184 // 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
185 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
186 // | ID | len=2 | MIN delay | MAX delay |
187 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
188 constexpr RTPExtensionType PlayoutDelayLimits::kId;
189 constexpr uint8_t PlayoutDelayLimits::kValueSizeBytes;
190 constexpr const char PlayoutDelayLimits::kUri[];
191
Parse(rtc::ArrayView<const uint8_t> data,PlayoutDelay * playout_delay)192 bool PlayoutDelayLimits::Parse(rtc::ArrayView<const uint8_t> data,
193 PlayoutDelay* playout_delay) {
194 RTC_DCHECK(playout_delay);
195 if (data.size() != 3)
196 return false;
197 uint32_t raw = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
198 uint16_t min_raw = (raw >> 12);
199 uint16_t max_raw = (raw & 0xfff);
200 if (min_raw > max_raw)
201 return false;
202 playout_delay->min_ms = min_raw * kGranularityMs;
203 playout_delay->max_ms = max_raw * kGranularityMs;
204 return true;
205 }
206
Write(uint8_t * data,const PlayoutDelay & playout_delay)207 bool PlayoutDelayLimits::Write(uint8_t* data,
208 const PlayoutDelay& playout_delay) {
209 RTC_DCHECK_LE(0, playout_delay.min_ms);
210 RTC_DCHECK_LE(playout_delay.min_ms, playout_delay.max_ms);
211 RTC_DCHECK_LE(playout_delay.max_ms, kMaxMs);
212 // Convert MS to value to be sent on extension header.
213 uint32_t min_delay = playout_delay.min_ms / kGranularityMs;
214 uint32_t max_delay = playout_delay.max_ms / kGranularityMs;
215 ByteWriter<uint32_t, 3>::WriteBigEndian(data, (min_delay << 12) | max_delay);
216 return true;
217 }
218
219 // CSRCAudioLevel
220 // Sample Audio Level Encoding Using the One-Byte Header Format
221 // Note that the range of len is 1 to 15 which is encoded as 0 to 14
222 // 0 1 2 3
223 // 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
224 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
225 // | ID | len=2 |0| level 1 |0| level 2 |0| level 3 |
226 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
227
228
229 constexpr RTPExtensionType CsrcAudioLevel::kId;
230 constexpr const char* CsrcAudioLevel::kUri;
231
Parse(rtc::ArrayView<const uint8_t> data,CsrcAudioLevelList * csrcAudioLevels)232 bool CsrcAudioLevel::Parse(rtc::ArrayView<const uint8_t> data,
233 CsrcAudioLevelList* csrcAudioLevels) {
234 if (data.size() < 1 || data.size() > kRtpCsrcSize)
235 return false;
236 csrcAudioLevels->numAudioLevels = data.size();
237 for(uint8_t i = 0; i < csrcAudioLevels->numAudioLevels; i++) {
238 // Ensure range is 0 to 127 inclusive
239 csrcAudioLevels->arrOfAudioLevels[i] = 0x7f & data[i];
240 }
241 return true;
242 }
243
ValueSize(const CsrcAudioLevelList & csrcAudioLevels)244 size_t CsrcAudioLevel::ValueSize(const CsrcAudioLevelList& csrcAudioLevels) {
245 return csrcAudioLevels.numAudioLevels;
246 }
247
Write(uint8_t * data,const CsrcAudioLevelList & csrcAudioLevels)248 bool CsrcAudioLevel::Write(uint8_t* data,
249 const CsrcAudioLevelList& csrcAudioLevels) {
250 RTC_DCHECK_GE(csrcAudioLevels.numAudioLevels, 0);
251 for(uint8_t i = 0; i < csrcAudioLevels.numAudioLevels; i++) {
252 data[i] = csrcAudioLevels.arrOfAudioLevels[i] & 0x7f;
253 }
254 // This extension if used must have at least one audio level
255 return csrcAudioLevels.numAudioLevels;
256 }
257
258 // Video Content Type.
259 //
260 // E.g. default video or screenshare.
261 //
262 // 0 1
263 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
264 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
265 // | ID | len=0 | Content type |
266 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
267 constexpr RTPExtensionType VideoContentTypeExtension::kId;
268 constexpr uint8_t VideoContentTypeExtension::kValueSizeBytes;
269 constexpr const char VideoContentTypeExtension::kUri[];
270
Parse(rtc::ArrayView<const uint8_t> data,VideoContentType * content_type)271 bool VideoContentTypeExtension::Parse(rtc::ArrayView<const uint8_t> data,
272 VideoContentType* content_type) {
273 if (data.size() == 1 &&
274 videocontenttypehelpers::IsValidContentType(data[0])) {
275 *content_type = static_cast<VideoContentType>(data[0]);
276 return true;
277 }
278 return false;
279 }
280
Write(uint8_t * data,VideoContentType content_type)281 bool VideoContentTypeExtension::Write(uint8_t* data,
282 VideoContentType content_type) {
283 data[0] = static_cast<uint8_t>(content_type);
284 return true;
285 }
286
287 // Video Timing.
288 // 6 timestamps in milliseconds counted from capture time stored in rtp header:
289 // encode start/finish, packetization complete, pacer exit and reserved for
290 // modification by the network modification. |flags| is a bitmask and has the
291 // following allowed values:
292 // 0 = Valid data, but no flags available (backwards compatibility)
293 // 1 = Frame marked as timing frame due to cyclic timer.
294 // 2 = Frame marked as timing frame due to size being outside limit.
295 // 255 = Invalid. The whole timing frame extension should be ignored.
296 //
297 // 0 1 2 3
298 // 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 2
299 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
300 // | ID | len=12| flags | encode start ms delta |
301 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
302 // | encode finish ms delta | packetizer finish ms delta |
303 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
304 // | pacer exit ms delta | network timestamp ms delta |
305 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
306 // | network2 timestamp ms delta |
307 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
308
309 constexpr RTPExtensionType VideoTimingExtension::kId;
310 constexpr uint8_t VideoTimingExtension::kValueSizeBytes;
311 constexpr const char VideoTimingExtension::kUri[];
312
Parse(rtc::ArrayView<const uint8_t> data,VideoSendTiming * timing)313 bool VideoTimingExtension::Parse(rtc::ArrayView<const uint8_t> data,
314 VideoSendTiming* timing) {
315 RTC_DCHECK(timing);
316 // TODO(sprang): Deprecate support for old wire format.
317 ptrdiff_t off = 0;
318 switch (data.size()) {
319 case kValueSizeBytes - 1:
320 timing->flags = 0;
321 off = 1; // Old wire format without the flags field.
322 break;
323 case kValueSizeBytes:
324 timing->flags = ByteReader<uint8_t>::ReadBigEndian(data.data());
325 break;
326 default:
327 return false;
328 }
329
330 timing->encode_start_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
331 data.data() + VideoSendTiming::kEncodeStartDeltaOffset - off);
332 timing->encode_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
333 data.data() + VideoSendTiming::kEncodeFinishDeltaOffset - off);
334 timing->packetization_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
335 data.data() + VideoSendTiming::kPacketizationFinishDeltaOffset - off);
336 timing->pacer_exit_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
337 data.data() + VideoSendTiming::kPacerExitDeltaOffset - off);
338 timing->network_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
339 data.data() + VideoSendTiming::kNetworkTimestampDeltaOffset - off);
340 timing->network2_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
341 data.data() + VideoSendTiming::kNetwork2TimestampDeltaOffset - off);
342 return true;
343 }
344
Write(uint8_t * data,const VideoSendTiming & timing)345 bool VideoTimingExtension::Write(uint8_t* data, const VideoSendTiming& timing) {
346 ByteWriter<uint8_t>::WriteBigEndian(data + VideoSendTiming::kFlagsOffset,
347 timing.flags);
348 ByteWriter<uint16_t>::WriteBigEndian(
349 data + VideoSendTiming::kEncodeStartDeltaOffset,
350 timing.encode_start_delta_ms);
351 ByteWriter<uint16_t>::WriteBigEndian(
352 data + VideoSendTiming::kEncodeFinishDeltaOffset,
353 timing.encode_finish_delta_ms);
354 ByteWriter<uint16_t>::WriteBigEndian(
355 data + VideoSendTiming::kPacketizationFinishDeltaOffset,
356 timing.packetization_finish_delta_ms);
357 ByteWriter<uint16_t>::WriteBigEndian(
358 data + VideoSendTiming::kPacerExitDeltaOffset,
359 timing.pacer_exit_delta_ms);
360 ByteWriter<uint16_t>::WriteBigEndian(
361 data + VideoSendTiming::kNetworkTimestampDeltaOffset,
362 timing.network_timestamp_delta_ms);
363 ByteWriter<uint16_t>::WriteBigEndian(
364 data + VideoSendTiming::kNetwork2TimestampDeltaOffset,
365 timing.network2_timestamp_delta_ms);
366 return true;
367 }
368
Write(uint8_t * data,uint16_t time_delta_ms,uint8_t offset)369 bool VideoTimingExtension::Write(uint8_t* data,
370 uint16_t time_delta_ms,
371 uint8_t offset) {
372 RTC_DCHECK_LE(offset, kValueSizeBytes - sizeof(uint16_t));
373 ByteWriter<uint16_t>::WriteBigEndian(data + offset, time_delta_ms);
374 return true;
375 }
376
Parse(rtc::ArrayView<const uint8_t> data,StringRtpHeaderExtension * str)377 bool BaseRtpStringExtension::Parse(rtc::ArrayView<const uint8_t> data,
378 StringRtpHeaderExtension* str) {
379 if (data.empty() || data[0] == 0) // Valid string extension can't be empty.
380 return false;
381 str->Set(data);
382 RTC_DCHECK(!str->empty());
383 return true;
384 }
385
Write(uint8_t * data,const StringRtpHeaderExtension & str)386 bool BaseRtpStringExtension::Write(uint8_t* data,
387 const StringRtpHeaderExtension& str) {
388 RTC_DCHECK_GE(str.size(), 1);
389 RTC_DCHECK_LE(str.size(), StringRtpHeaderExtension::kMaxSize);
390 memcpy(data, str.data(), str.size());
391 return true;
392 }
393
Parse(rtc::ArrayView<const uint8_t> data,std::string * str)394 bool BaseRtpStringExtension::Parse(rtc::ArrayView<const uint8_t> data,
395 std::string* str) {
396 if (data.empty() || data[0] == 0) // Valid string extension can't be empty.
397 return false;
398 const char* cstr = reinterpret_cast<const char*>(data.data());
399 // If there is a \0 character in the middle of the |data|, treat it as end
400 // of the string. Well-formed string extensions shouldn't contain it.
401 str->assign(cstr, strnlen(cstr, data.size()));
402 RTC_DCHECK(!str->empty());
403 return true;
404 }
405
Write(uint8_t * data,const std::string & str)406 bool BaseRtpStringExtension::Write(uint8_t* data, const std::string& str) {
407 RTC_DCHECK_GE(str.size(), 1);
408 RTC_DCHECK_LE(str.size(), StringRtpHeaderExtension::kMaxSize);
409 memcpy(data, str.data(), str.size());
410 return true;
411 }
412
413 // Constant declarations for string RTP header extension types.
414
415 constexpr RTPExtensionType RtpStreamId::kId;
416 constexpr const char RtpStreamId::kUri[];
417
418 constexpr RTPExtensionType RepairedRtpStreamId::kId;
419 constexpr const char RepairedRtpStreamId::kUri[];
420
421 constexpr RTPExtensionType RtpMid::kId;
422 constexpr const char RtpMid::kUri[];
423
424 } // namespace webrtc
425