/* * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h" #include "webrtc/base/checks.h" #include "webrtc/base/logging.h" #include "webrtc/modules/rtp_rtcp/include/rtp_cvo.h" #include "webrtc/modules/rtp_rtcp/source/byte_io.h" namespace webrtc { // Absolute send time in RTP streams. // // The absolute send time is signaled to the receiver in-band using the // general mechanism for RTP header extensions [RFC5285]. The payload // of this extension (the transmitted value) is a 24-bit unsigned integer // containing the sender's current time in seconds as a fixed point number // with 18 bits fractional part. // // The form of the absolute send time extension block: // // 0 1 2 3 // 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 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=2 | absolute send time | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ constexpr RTPExtensionType AbsoluteSendTime::kId; constexpr uint8_t AbsoluteSendTime::kValueSizeBytes; const char* const AbsoluteSendTime::kUri = "http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time"; bool AbsoluteSendTime::Parse(const uint8_t* data, uint32_t* time_24bits) { *time_24bits = ByteReader::ReadBigEndian(data); return true; } bool AbsoluteSendTime::Write(uint8_t* data, int64_t time_ms) { ByteWriter::WriteBigEndian(data, MsTo24Bits(time_ms)); return true; } // An RTP Header Extension for Client-to-Mixer Audio Level Indication // // https://datatracker.ietf.org/doc/draft-lennox-avt-rtp-audio-level-exthdr/ // // The form of the audio level extension block: // // 0 1 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=0 |V| level | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // constexpr RTPExtensionType AudioLevel::kId; constexpr uint8_t AudioLevel::kValueSizeBytes; const char* const AudioLevel::kUri = "urn:ietf:params:rtp-hdrext:ssrc-audio-level"; bool AudioLevel::Parse(const uint8_t* data, bool* voice_activity, uint8_t* audio_level) { *voice_activity = (data[0] & 0x80) != 0; *audio_level = data[0] & 0x7F; return true; } bool AudioLevel::Write(uint8_t* data, bool voice_activity, uint8_t audio_level) { RTC_CHECK_LE(audio_level, 0x7f); data[0] = (voice_activity ? 0x80 : 0x00) | audio_level; return true; } // From RFC 5450: Transmission Time Offsets in RTP Streams. // // The transmission time is signaled to the receiver in-band using the // general mechanism for RTP header extensions [RFC5285]. The payload // of this extension (the transmitted value) is a 24-bit signed integer. // When added to the RTP timestamp of the packet, it represents the // "effective" RTP transmission time of the packet, on the RTP // timescale. // // The form of the transmission offset extension block: // // 0 1 2 3 // 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 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=2 | transmission offset | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ constexpr RTPExtensionType TransmissionOffset::kId; constexpr uint8_t TransmissionOffset::kValueSizeBytes; const char* const TransmissionOffset::kUri = "urn:ietf:params:rtp-hdrext:toffset"; bool TransmissionOffset::Parse(const uint8_t* data, int32_t* rtp_time) { *rtp_time = ByteReader::ReadBigEndian(data); return true; } bool TransmissionOffset::Write(uint8_t* data, int32_t rtp_time) { RTC_DCHECK_LE(rtp_time, 0x00ffffff); ByteWriter::WriteBigEndian(data, rtp_time); return true; } // 0 1 2 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | L=1 |transport wide sequence number | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ constexpr RTPExtensionType TransportSequenceNumber::kId; constexpr uint8_t TransportSequenceNumber::kValueSizeBytes; const char* const TransportSequenceNumber::kUri = "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions"; bool TransportSequenceNumber::Parse(const uint8_t* data, uint16_t* value) { *value = ByteReader::ReadBigEndian(data); return true; } bool TransportSequenceNumber::Write(uint8_t* data, uint16_t value) { ByteWriter::WriteBigEndian(data, value); return true; } // Coordination of Video Orientation in RTP streams. // // Coordination of Video Orientation consists in signaling of the current // orientation of the image captured on the sender side to the receiver for // appropriate rendering and displaying. // // 0 1 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=0 |0 0 0 0 C F R R| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ constexpr RTPExtensionType VideoOrientation::kId; constexpr uint8_t VideoOrientation::kValueSizeBytes; const char* const VideoOrientation::kUri = "urn:3gpp:video-orientation"; bool VideoOrientation::Parse(const uint8_t* data, VideoRotation* rotation) { *rotation = ConvertCVOByteToVideoRotation(data[0]); return true; } bool VideoOrientation::Write(uint8_t* data, VideoRotation rotation) { data[0] = ConvertVideoRotationToCVOByte(rotation); return true; } bool VideoOrientation::Parse(const uint8_t* data, uint8_t* value) { *value = data[0]; return true; } bool VideoOrientation::Write(uint8_t* data, uint8_t value) { data[0] = value; return true; } // 0 1 2 3 // 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 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=2 | MIN delay | MAX delay | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ constexpr RTPExtensionType PlayoutDelayLimits::kId; constexpr uint8_t PlayoutDelayLimits::kValueSizeBytes; const char* const PlayoutDelayLimits::kUri = "http://www.webrtc.org/experiments/rtp-hdrext/playout-delay"; bool PlayoutDelayLimits::Parse(const uint8_t* data, PlayoutDelay* playout_delay) { RTC_DCHECK(playout_delay); uint32_t raw = ByteReader::ReadBigEndian(data); uint16_t min_raw = (raw >> 12); uint16_t max_raw = (raw & 0xfff); if (min_raw > max_raw) return false; playout_delay->min_ms = min_raw * kGranularityMs; playout_delay->max_ms = max_raw * kGranularityMs; return true; } bool PlayoutDelayLimits::Write(uint8_t* data, const PlayoutDelay& playout_delay) { RTC_DCHECK_LE(0, playout_delay.min_ms); RTC_DCHECK_LE(playout_delay.min_ms, playout_delay.max_ms); RTC_DCHECK_LE(playout_delay.max_ms, kMaxMs); // Convert MS to value to be sent on extension header. uint32_t min_delay = playout_delay.min_ms / kGranularityMs; uint32_t max_delay = playout_delay.max_ms / kGranularityMs; ByteWriter::WriteBigEndian(data, (min_delay << 12) | max_delay); return true; } } // namespace webrtc