blob: 2dba4d7cfacd1c632533aaab3aa116f892883879 [file] [log] [blame]
danilchap1edb7ab2016-04-20 05:25:10 -07001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
danilchap1edb7ab2016-04-20 05:25:10 -070012
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#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"
danilchap1edb7ab2016-04-20 05:25:10 -070017
18namespace 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// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -070034constexpr RTPExtensionType AbsoluteSendTime::kId;
35constexpr uint8_t AbsoluteSendTime::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -070036constexpr const char AbsoluteSendTime::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -070037
danilchap978504e2017-04-06 01:03:53 -070038bool 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());
danilchap1edb7ab2016-04-20 05:25:10 -070043 return true;
44}
45
Danil Chapovalov9bf31582018-06-18 13:48:20 +020046bool AbsoluteSendTime::Write(rtc::ArrayView<uint8_t> data,
47 uint32_t time_24bits) {
48 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalovf3ba6482017-06-12 15:43:55 +020049 RTC_DCHECK_LE(time_24bits, 0x00FFFFFF);
Danil Chapovalov9bf31582018-06-18 13:48:20 +020050 ByteWriter<uint32_t, 3>::WriteBigEndian(data.data(), time_24bits);
danilchap1edb7ab2016-04-20 05:25:10 -070051 return true;
52}
53
54// An RTP Header Extension for Client-to-Mixer Audio Level Indication
55//
56// https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/
57//
58// The form of the audio level extension block:
59//
60// 0 1
61// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
62// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
63// | ID | len=0 |V| level |
64// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
65//
danilchape2a01772016-10-28 07:08:58 -070066constexpr RTPExtensionType AudioLevel::kId;
67constexpr uint8_t AudioLevel::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -070068constexpr const char AudioLevel::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -070069
danilchap978504e2017-04-06 01:03:53 -070070bool AudioLevel::Parse(rtc::ArrayView<const uint8_t> data,
danilchap1edb7ab2016-04-20 05:25:10 -070071 bool* voice_activity,
72 uint8_t* audio_level) {
danilchap978504e2017-04-06 01:03:53 -070073 if (data.size() != 1)
74 return false;
danilchap1edb7ab2016-04-20 05:25:10 -070075 *voice_activity = (data[0] & 0x80) != 0;
76 *audio_level = data[0] & 0x7F;
77 return true;
78}
79
Danil Chapovalov9bf31582018-06-18 13:48:20 +020080bool AudioLevel::Write(rtc::ArrayView<uint8_t> data,
danilchap1edb7ab2016-04-20 05:25:10 -070081 bool voice_activity,
82 uint8_t audio_level) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +020083 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 05:25:10 -070084 RTC_CHECK_LE(audio_level, 0x7f);
85 data[0] = (voice_activity ? 0x80 : 0x00) | audio_level;
86 return true;
87}
88
89// From RFC 5450: Transmission Time Offsets in RTP Streams.
90//
91// The transmission time is signaled to the receiver in-band using the
92// general mechanism for RTP header extensions [RFC5285]. The payload
93// of this extension (the transmitted value) is a 24-bit signed integer.
94// When added to the RTP timestamp of the packet, it represents the
95// "effective" RTP transmission time of the packet, on the RTP
96// timescale.
97//
98// The form of the transmission offset extension block:
99//
100// 0 1 2 3
101// 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
102// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
103// | ID | len=2 | transmission offset |
104// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -0700105constexpr RTPExtensionType TransmissionOffset::kId;
106constexpr uint8_t TransmissionOffset::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700107constexpr const char TransmissionOffset::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700108
danilchap978504e2017-04-06 01:03:53 -0700109bool TransmissionOffset::Parse(rtc::ArrayView<const uint8_t> data,
110 int32_t* rtp_time) {
111 if (data.size() != 3)
112 return false;
113 *rtp_time = ByteReader<int32_t, 3>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 05:25:10 -0700114 return true;
115}
116
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200117bool TransmissionOffset::Write(rtc::ArrayView<uint8_t> data, int32_t rtp_time) {
118 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalov31e4e802016-08-03 18:27:40 +0200119 RTC_DCHECK_LE(rtp_time, 0x00ffffff);
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200120 ByteWriter<int32_t, 3>::WriteBigEndian(data.data(), rtp_time);
danilchap1edb7ab2016-04-20 05:25:10 -0700121 return true;
122}
123
124// 0 1 2
125// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3
126// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
127// | ID | L=1 |transport wide sequence number |
128// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -0700129constexpr RTPExtensionType TransportSequenceNumber::kId;
130constexpr uint8_t TransportSequenceNumber::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700131constexpr const char TransportSequenceNumber::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700132
danilchap978504e2017-04-06 01:03:53 -0700133bool TransportSequenceNumber::Parse(rtc::ArrayView<const uint8_t> data,
134 uint16_t* value) {
135 if (data.size() != 2)
136 return false;
137 *value = ByteReader<uint16_t>::ReadBigEndian(data.data());
danilchap1edb7ab2016-04-20 05:25:10 -0700138 return true;
139}
140
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200141bool TransportSequenceNumber::Write(rtc::ArrayView<uint8_t> data,
142 uint16_t value) {
143 RTC_DCHECK_EQ(data.size(), 2);
144 ByteWriter<uint16_t>::WriteBigEndian(data.data(), value);
danilchap1edb7ab2016-04-20 05:25:10 -0700145 return true;
146}
147
148// Coordination of Video Orientation in RTP streams.
149//
150// Coordination of Video Orientation consists in signaling of the current
151// orientation of the image captured on the sender side to the receiver for
152// appropriate rendering and displaying.
153//
154// 0 1
155// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
156// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
157// | ID | len=0 |0 0 0 0 C F R R|
158// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
danilchape2a01772016-10-28 07:08:58 -0700159constexpr RTPExtensionType VideoOrientation::kId;
160constexpr uint8_t VideoOrientation::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700161constexpr const char VideoOrientation::kUri[];
danilchap1edb7ab2016-04-20 05:25:10 -0700162
danilchap978504e2017-04-06 01:03:53 -0700163bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
164 VideoRotation* rotation) {
165 if (data.size() != 1)
166 return false;
magjed71eb61c2016-09-08 03:24:58 -0700167 *rotation = ConvertCVOByteToVideoRotation(data[0]);
danilchap1edb7ab2016-04-20 05:25:10 -0700168 return true;
169}
170
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200171bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data,
172 VideoRotation rotation) {
173 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 05:25:10 -0700174 data[0] = ConvertVideoRotationToCVOByte(rotation);
175 return true;
176}
177
danilchap978504e2017-04-06 01:03:53 -0700178bool VideoOrientation::Parse(rtc::ArrayView<const uint8_t> data,
179 uint8_t* value) {
180 if (data.size() != 1)
181 return false;
danilchap1edb7ab2016-04-20 05:25:10 -0700182 *value = data[0];
183 return true;
184}
185
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200186bool VideoOrientation::Write(rtc::ArrayView<uint8_t> data, uint8_t value) {
187 RTC_DCHECK_EQ(data.size(), 1);
danilchap1edb7ab2016-04-20 05:25:10 -0700188 data[0] = value;
189 return true;
190}
Danil Chapovalov08b03512016-09-07 15:08:13 +0200191
192// 0 1 2 3
193// 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
194// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
195// | ID | len=2 | MIN delay | MAX delay |
196// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
197constexpr RTPExtensionType PlayoutDelayLimits::kId;
198constexpr uint8_t PlayoutDelayLimits::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700199constexpr const char PlayoutDelayLimits::kUri[];
Danil Chapovalov08b03512016-09-07 15:08:13 +0200200
danilchap978504e2017-04-06 01:03:53 -0700201bool PlayoutDelayLimits::Parse(rtc::ArrayView<const uint8_t> data,
Danil Chapovalov08b03512016-09-07 15:08:13 +0200202 PlayoutDelay* playout_delay) {
203 RTC_DCHECK(playout_delay);
danilchap978504e2017-04-06 01:03:53 -0700204 if (data.size() != 3)
205 return false;
206 uint32_t raw = ByteReader<uint32_t, 3>::ReadBigEndian(data.data());
Danil Chapovalov08b03512016-09-07 15:08:13 +0200207 uint16_t min_raw = (raw >> 12);
208 uint16_t max_raw = (raw & 0xfff);
209 if (min_raw > max_raw)
210 return false;
211 playout_delay->min_ms = min_raw * kGranularityMs;
212 playout_delay->max_ms = max_raw * kGranularityMs;
213 return true;
214}
215
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200216bool PlayoutDelayLimits::Write(rtc::ArrayView<uint8_t> data,
Danil Chapovalov08b03512016-09-07 15:08:13 +0200217 const PlayoutDelay& playout_delay) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200218 RTC_DCHECK_EQ(data.size(), 3);
Danil Chapovalov08b03512016-09-07 15:08:13 +0200219 RTC_DCHECK_LE(0, playout_delay.min_ms);
220 RTC_DCHECK_LE(playout_delay.min_ms, playout_delay.max_ms);
221 RTC_DCHECK_LE(playout_delay.max_ms, kMaxMs);
222 // Convert MS to value to be sent on extension header.
223 uint32_t min_delay = playout_delay.min_ms / kGranularityMs;
224 uint32_t max_delay = playout_delay.max_ms / kGranularityMs;
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200225 ByteWriter<uint32_t, 3>::WriteBigEndian(data.data(),
226 (min_delay << 12) | max_delay);
Danil Chapovalov08b03512016-09-07 15:08:13 +0200227 return true;
228}
229
ilnik00d802b2017-04-11 10:34:31 -0700230// Video Content Type.
231//
232// E.g. default video or screenshare.
233//
234// 0 1
235// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
236// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
237// | ID | len=0 | Content type |
238// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
239constexpr RTPExtensionType VideoContentTypeExtension::kId;
240constexpr uint8_t VideoContentTypeExtension::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700241constexpr const char VideoContentTypeExtension::kUri[];
ilnik00d802b2017-04-11 10:34:31 -0700242
243bool VideoContentTypeExtension::Parse(rtc::ArrayView<const uint8_t> data,
244 VideoContentType* content_type) {
245 if (data.size() == 1 &&
ilnik6d5b4d62017-08-30 03:32:14 -0700246 videocontenttypehelpers::IsValidContentType(data[0])) {
ilnik00d802b2017-04-11 10:34:31 -0700247 *content_type = static_cast<VideoContentType>(data[0]);
248 return true;
249 }
250 return false;
251}
252
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200253bool VideoContentTypeExtension::Write(rtc::ArrayView<uint8_t> data,
ilnik00d802b2017-04-11 10:34:31 -0700254 VideoContentType content_type) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200255 RTC_DCHECK_EQ(data.size(), 1);
ilnik00d802b2017-04-11 10:34:31 -0700256 data[0] = static_cast<uint8_t>(content_type);
257 return true;
258}
259
ilnik04f4d122017-06-19 07:18:55 -0700260// Video Timing.
261// 6 timestamps in milliseconds counted from capture time stored in rtp header:
262// encode start/finish, packetization complete, pacer exit and reserved for
sprangba050a62017-08-18 02:51:12 -0700263// modification by the network modification. |flags| is a bitmask and has the
264// following allowed values:
265// 0 = Valid data, but no flags available (backwards compatibility)
266// 1 = Frame marked as timing frame due to cyclic timer.
267// 2 = Frame marked as timing frame due to size being outside limit.
268// 255 = Invalid. The whole timing frame extension should be ignored.
269//
ilnik04f4d122017-06-19 07:18:55 -0700270// 0 1 2 3
271// 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
272// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
sprangba050a62017-08-18 02:51:12 -0700273// | ID | len=12| flags | encode start ms delta |
ilnik04f4d122017-06-19 07:18:55 -0700274// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
sprangba050a62017-08-18 02:51:12 -0700275// | encode finish ms delta | packetizer finish ms delta |
ilnik04f4d122017-06-19 07:18:55 -0700276// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
sprangba050a62017-08-18 02:51:12 -0700277// | pacer exit ms delta | network timestamp ms delta |
ilnik04f4d122017-06-19 07:18:55 -0700278// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
sprangba050a62017-08-18 02:51:12 -0700279// | network2 timestamp ms delta |
280// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
ilnik04f4d122017-06-19 07:18:55 -0700281
282constexpr RTPExtensionType VideoTimingExtension::kId;
283constexpr uint8_t VideoTimingExtension::kValueSizeBytes;
Steve Antond14d9f72017-07-21 10:59:39 -0700284constexpr const char VideoTimingExtension::kUri[];
ilnik04f4d122017-06-19 07:18:55 -0700285
286bool VideoTimingExtension::Parse(rtc::ArrayView<const uint8_t> data,
ilnik2edc6842017-07-06 03:06:50 -0700287 VideoSendTiming* timing) {
ilnik04f4d122017-06-19 07:18:55 -0700288 RTC_DCHECK(timing);
sprangba050a62017-08-18 02:51:12 -0700289 // TODO(sprang): Deprecate support for old wire format.
290 ptrdiff_t off = 0;
291 switch (data.size()) {
292 case kValueSizeBytes - 1:
293 timing->flags = 0;
294 off = 1; // Old wire format without the flags field.
295 break;
296 case kValueSizeBytes:
297 timing->flags = ByteReader<uint8_t>::ReadBigEndian(data.data());
298 break;
299 default:
300 return false;
301 }
302
303 timing->encode_start_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
304 data.data() + VideoSendTiming::kEncodeStartDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700305 timing->encode_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700306 data.data() + VideoSendTiming::kEncodeFinishDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700307 timing->packetization_finish_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700308 data.data() + VideoSendTiming::kPacketizationFinishDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700309 timing->pacer_exit_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700310 data.data() + VideoSendTiming::kPacerExitDeltaOffset - off);
Danil Chapovalov996eb9e2017-10-30 17:14:41 +0100311 timing->network_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700312 data.data() + VideoSendTiming::kNetworkTimestampDeltaOffset - off);
Danil Chapovalov996eb9e2017-10-30 17:14:41 +0100313 timing->network2_timestamp_delta_ms = ByteReader<uint16_t>::ReadBigEndian(
sprangba050a62017-08-18 02:51:12 -0700314 data.data() + VideoSendTiming::kNetwork2TimestampDeltaOffset - off);
ilnik04f4d122017-06-19 07:18:55 -0700315 return true;
316}
317
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200318bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data,
319 const VideoSendTiming& timing) {
320 RTC_DCHECK_EQ(data.size(), 1 + 2 * 6);
321 ByteWriter<uint8_t>::WriteBigEndian(
322 data.data() + VideoSendTiming::kFlagsOffset, timing.flags);
ilnik04f4d122017-06-19 07:18:55 -0700323 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200324 data.data() + VideoSendTiming::kEncodeStartDeltaOffset,
sprangba050a62017-08-18 02:51:12 -0700325 timing.encode_start_delta_ms);
326 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200327 data.data() + VideoSendTiming::kEncodeFinishDeltaOffset,
ilnik04f4d122017-06-19 07:18:55 -0700328 timing.encode_finish_delta_ms);
329 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200330 data.data() + VideoSendTiming::kPacketizationFinishDeltaOffset,
ilnik04f4d122017-06-19 07:18:55 -0700331 timing.packetization_finish_delta_ms);
332 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200333 data.data() + VideoSendTiming::kPacerExitDeltaOffset,
ilnik2edc6842017-07-06 03:06:50 -0700334 timing.pacer_exit_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700335 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200336 data.data() + VideoSendTiming::kNetworkTimestampDeltaOffset,
Danil Chapovalovf0cc8142017-10-31 17:59:39 +0100337 timing.network_timestamp_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700338 ByteWriter<uint16_t>::WriteBigEndian(
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200339 data.data() + VideoSendTiming::kNetwork2TimestampDeltaOffset,
Danil Chapovalovf0cc8142017-10-31 17:59:39 +0100340 timing.network2_timestamp_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700341 return true;
342}
343
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200344bool VideoTimingExtension::Write(rtc::ArrayView<uint8_t> data,
ilnik04f4d122017-06-19 07:18:55 -0700345 uint16_t time_delta_ms,
sprangba050a62017-08-18 02:51:12 -0700346 uint8_t offset) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200347 RTC_DCHECK_GE(data.size(), offset + 2);
Danil Chapovalovf0cc8142017-10-31 17:59:39 +0100348 RTC_DCHECK_LE(offset, kValueSizeBytes - sizeof(uint16_t));
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200349 ByteWriter<uint16_t>::WriteBigEndian(data.data() + offset, time_delta_ms);
ilnik04f4d122017-06-19 07:18:55 -0700350 return true;
351}
352
Steve Antona3251dd2017-07-21 09:58:31 -0700353bool BaseRtpStringExtension::Parse(rtc::ArrayView<const uint8_t> data,
354 StringRtpHeaderExtension* str) {
355 if (data.empty() || data[0] == 0) // Valid string extension can't be empty.
356 return false;
357 str->Set(data);
358 RTC_DCHECK(!str->empty());
359 return true;
360}
361
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200362bool BaseRtpStringExtension::Write(rtc::ArrayView<uint8_t> data,
Steve Antona3251dd2017-07-21 09:58:31 -0700363 const StringRtpHeaderExtension& str) {
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200364 RTC_DCHECK_EQ(data.size(), str.size());
Steve Antona3251dd2017-07-21 09:58:31 -0700365 RTC_DCHECK_GE(str.size(), 1);
366 RTC_DCHECK_LE(str.size(), StringRtpHeaderExtension::kMaxSize);
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200367 memcpy(data.data(), str.data(), str.size());
Steve Antona3251dd2017-07-21 09:58:31 -0700368 return true;
369}
370
371bool BaseRtpStringExtension::Parse(rtc::ArrayView<const uint8_t> data,
372 std::string* str) {
373 if (data.empty() || data[0] == 0) // Valid string extension can't be empty.
374 return false;
375 const char* cstr = reinterpret_cast<const char*>(data.data());
376 // If there is a \0 character in the middle of the |data|, treat it as end
377 // of the string. Well-formed string extensions shouldn't contain it.
378 str->assign(cstr, strnlen(cstr, data.size()));
379 RTC_DCHECK(!str->empty());
380 return true;
381}
382
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200383bool BaseRtpStringExtension::Write(rtc::ArrayView<uint8_t> data,
384 const std::string& str) {
385 RTC_DCHECK_EQ(data.size(), str.size());
Steve Antona3251dd2017-07-21 09:58:31 -0700386 RTC_DCHECK_GE(str.size(), 1);
387 RTC_DCHECK_LE(str.size(), StringRtpHeaderExtension::kMaxSize);
Danil Chapovalov9bf31582018-06-18 13:48:20 +0200388 memcpy(data.data(), str.data(), str.size());
Steve Antona3251dd2017-07-21 09:58:31 -0700389 return true;
390}
391
392// Constant declarations for string RTP header extension types.
393
danilchapef8d7732017-04-19 02:59:48 -0700394constexpr RTPExtensionType RtpStreamId::kId;
Steve Antond14d9f72017-07-21 10:59:39 -0700395constexpr const char RtpStreamId::kUri[];
danilchapef8d7732017-04-19 02:59:48 -0700396
danilchapef8d7732017-04-19 02:59:48 -0700397constexpr RTPExtensionType RepairedRtpStreamId::kId;
Steve Antond14d9f72017-07-21 10:59:39 -0700398constexpr const char RepairedRtpStreamId::kUri[];
danilchapef8d7732017-04-19 02:59:48 -0700399
Steve Antona3251dd2017-07-21 09:58:31 -0700400constexpr RTPExtensionType RtpMid::kId;
Steve Antond14d9f72017-07-21 10:59:39 -0700401constexpr const char RtpMid::kUri[];
erikvargae6b16192017-05-11 02:36:32 -0700402
danilchap1edb7ab2016-04-20 05:25:10 -0700403} // namespace webrtc