blob: 3ed1fbdb803e6434a1f25585babbe4a59e6aecf1 [file] [log] [blame]
Danil Chapovalova5eba6c2016-01-15 12:40:15 +01001/*
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/rtcp_packet/remb.h"
Danil Chapovalova5eba6c2016-01-15 12:40:15 +010012
Yves Gerey988cc082018-10-23 12:03:01 +020013#include <cstdint>
danilchap822a16f2016-09-27 09:27:47 -070014#include <utility>
15
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "modules/rtp_rtcp/source/byte_io.h"
17#include "modules/rtp_rtcp/source/rtcp_packet/common_header.h"
18#include "rtc_base/checks.h"
19#include "rtc_base/logging.h"
Danil Chapovalova5eba6c2016-01-15 12:40:15 +010020
21namespace webrtc {
22namespace rtcp {
Danil Chapovalovd215ade2016-05-12 15:25:39 +020023constexpr uint8_t Remb::kFeedbackMessageType;
Danil Chapovalova5eba6c2016-01-15 12:40:15 +010024// Receiver Estimated Max Bitrate (REMB) (draft-alvestrand-rmcat-remb).
25//
danilchapd8dccd52016-01-20 12:08:51 -080026// 0 1 2 3
27// 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
28// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
29// |V=2|P| FMT=15 | PT=206 | length |
30// +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
31// 0 | SSRC of packet sender |
32// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33// 4 | Unused = 0 |
34// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35// 8 | Unique identifier 'R' 'E' 'M' 'B' |
36// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37// 12 | Num SSRC | BR Exp | BR Mantissa |
38// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39// 16 | SSRC feedback |
40// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
41// : ... :
eladalon8fa21c42017-06-16 07:07:47 -070042
43Remb::Remb() : bitrate_bps_(0) {}
44
Mirko Bonadei55d5ef02018-09-03 09:47:38 +020045Remb::Remb(const Remb& rhs) = default;
46
eladalon8fa21c42017-06-16 07:07:47 -070047Remb::~Remb() = default;
48
Danil Chapovalovd215ade2016-05-12 15:25:39 +020049bool Remb::Parse(const CommonHeader& packet) {
50 RTC_DCHECK(packet.type() == kPacketType);
51 RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType);
Danil Chapovalova5eba6c2016-01-15 12:40:15 +010052
Danil Chapovalovd215ade2016-05-12 15:25:39 +020053 if (packet.payload_size_bytes() < 16) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010054 RTC_LOG(LS_WARNING) << "Payload length " << packet.payload_size_bytes()
55 << " is too small for Remb packet.";
danilchapd8dccd52016-01-20 12:08:51 -080056 return false;
Danil Chapovalova5eba6c2016-01-15 12:40:15 +010057 }
Danil Chapovalovd215ade2016-05-12 15:25:39 +020058 const uint8_t* const payload = packet.payload();
danilchapd8dccd52016-01-20 12:08:51 -080059 if (kUniqueIdentifier != ByteReader<uint32_t>::ReadBigEndian(&payload[8])) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010060 RTC_LOG(LS_WARNING) << "REMB identifier not found, not a REMB packet.";
danilchapd8dccd52016-01-20 12:08:51 -080061 return false;
62 }
63 uint8_t number_of_ssrcs = payload[12];
Danil Chapovalovd215ade2016-05-12 15:25:39 +020064 if (packet.payload_size_bytes() !=
danilchapd8dccd52016-01-20 12:08:51 -080065 kCommonFeedbackLength + (2 + number_of_ssrcs) * 4) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010066 RTC_LOG(LS_WARNING) << "Payload size " << packet.payload_size_bytes()
67 << " does not match " << number_of_ssrcs << " ssrcs.";
danilchapd8dccd52016-01-20 12:08:51 -080068 return false;
69 }
70
71 ParseCommonFeedback(payload);
72 uint8_t exponenta = payload[13] >> 2;
Danil Chapovalovd215ade2016-05-12 15:25:39 +020073 uint64_t mantissa = (static_cast<uint32_t>(payload[13] & 0x03) << 16) |
danilchapd8dccd52016-01-20 12:08:51 -080074 ByteReader<uint16_t>::ReadBigEndian(&payload[14]);
75 bitrate_bps_ = (mantissa << exponenta);
Danil Chapovalovd215ade2016-05-12 15:25:39 +020076 bool shift_overflow = (bitrate_bps_ >> exponenta) != mantissa;
77 if (shift_overflow) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010078 RTC_LOG(LS_ERROR) << "Invalid remb bitrate value : " << mantissa << "*2^"
79 << static_cast<int>(exponenta);
Danil Chapovalovd215ade2016-05-12 15:25:39 +020080 return false;
81 }
danilchapd8dccd52016-01-20 12:08:51 -080082
83 const uint8_t* next_ssrc = payload + 16;
84 ssrcs_.clear();
85 ssrcs_.reserve(number_of_ssrcs);
86 for (uint8_t i = 0; i < number_of_ssrcs; ++i) {
87 ssrcs_.push_back(ByteReader<uint32_t>::ReadBigEndian(next_ssrc));
88 next_ssrc += sizeof(uint32_t);
89 }
90
91 return true;
Danil Chapovalova5eba6c2016-01-15 12:40:15 +010092}
danilchapd8dccd52016-01-20 12:08:51 -080093
danilchap822a16f2016-09-27 09:27:47 -070094bool Remb::SetSsrcs(std::vector<uint32_t> ssrcs) {
95 if (ssrcs.size() > kMaxNumberOfSsrcs) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010096 RTC_LOG(LS_WARNING) << "Not enough space for all given SSRCs.";
danilchapd8dccd52016-01-20 12:08:51 -080097 return false;
98 }
danilchap822a16f2016-09-27 09:27:47 -070099 ssrcs_ = std::move(ssrcs);
danilchapd8dccd52016-01-20 12:08:51 -0800100 return true;
101}
Danil Chapovalova5eba6c2016-01-15 12:40:15 +0100102
eladalon8fa21c42017-06-16 07:07:47 -0700103size_t Remb::BlockLength() const {
104 return kHeaderLength + kCommonFeedbackLength + (2 + ssrcs_.size()) * 4;
105}
106
Danil Chapovalova5eba6c2016-01-15 12:40:15 +0100107bool Remb::Create(uint8_t* packet,
108 size_t* index,
109 size_t max_length,
Danil Chapovalov5c3cc412017-12-07 10:15:53 +0100110 PacketReadyCallback callback) const {
Danil Chapovalova5eba6c2016-01-15 12:40:15 +0100111 while (*index + BlockLength() > max_length) {
112 if (!OnBufferFull(packet, index, callback))
113 return false;
114 }
danilchapd8dccd52016-01-20 12:08:51 -0800115 size_t index_end = *index + BlockLength();
116 CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet,
117 index);
kwibergaf476c72016-11-28 15:21:39 -0800118 RTC_DCHECK_EQ(0, Psfb::media_ssrc());
danilchapd8dccd52016-01-20 12:08:51 -0800119 CreateCommonFeedback(packet + *index);
120 *index += kCommonFeedbackLength;
121
122 ByteWriter<uint32_t>::WriteBigEndian(packet + *index, kUniqueIdentifier);
123 *index += sizeof(uint32_t);
124 const uint32_t kMaxMantissa = 0x3ffff; // 18 bits.
Danil Chapovalovd215ade2016-05-12 15:25:39 +0200125 uint64_t mantissa = bitrate_bps_;
danilchapd8dccd52016-01-20 12:08:51 -0800126 uint8_t exponenta = 0;
127 while (mantissa > kMaxMantissa) {
128 mantissa >>= 1;
129 ++exponenta;
130 }
Danil Chapovalov6c170572017-09-15 16:48:14 +0200131 packet[(*index)++] = static_cast<uint8_t>(ssrcs_.size());
danilchapd8dccd52016-01-20 12:08:51 -0800132 packet[(*index)++] = (exponenta << 2) | (mantissa >> 16);
133 ByteWriter<uint16_t>::WriteBigEndian(packet + *index, mantissa & 0xffff);
134 *index += sizeof(uint16_t);
135
136 for (uint32_t ssrc : ssrcs_) {
137 ByteWriter<uint32_t>::WriteBigEndian(packet + *index, ssrc);
138 *index += sizeof(uint32_t);
139 }
140 RTC_DCHECK_EQ(index_end, *index);
Danil Chapovalova5eba6c2016-01-15 12:40:15 +0100141 return true;
142}
Danil Chapovalova5eba6c2016-01-15 12:40:15 +0100143} // namespace rtcp
144} // namespace webrtc