Line data Source code
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 "webrtc/modules/rtp_rtcp/source/rtcp_packet/remb.h"
12 :
13 : #include <utility>
14 :
15 : #include "webrtc/base/checks.h"
16 : #include "webrtc/base/logging.h"
17 : #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
18 : #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/common_header.h"
19 :
20 : namespace webrtc {
21 : namespace rtcp {
22 : constexpr uint8_t Remb::kFeedbackMessageType;
23 : // Receiver Estimated Max Bitrate (REMB) (draft-alvestrand-rmcat-remb).
24 : //
25 : // 0 1 2 3
26 : // 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
27 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
28 : // |V=2|P| FMT=15 | PT=206 | length |
29 : // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
30 : // 0 | SSRC of packet sender |
31 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
32 : // 4 | Unused = 0 |
33 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
34 : // 8 | Unique identifier 'R' 'E' 'M' 'B' |
35 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
36 : // 12 | Num SSRC | BR Exp | BR Mantissa |
37 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
38 : // 16 | SSRC feedback |
39 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 : // : ... :
41 0 : bool Remb::Parse(const CommonHeader& packet) {
42 0 : RTC_DCHECK(packet.type() == kPacketType);
43 0 : RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType);
44 :
45 0 : if (packet.payload_size_bytes() < 16) {
46 0 : LOG(LS_WARNING) << "Payload length " << packet.payload_size_bytes()
47 0 : << " is too small for Remb packet.";
48 0 : return false;
49 : }
50 0 : const uint8_t* const payload = packet.payload();
51 0 : if (kUniqueIdentifier != ByteReader<uint32_t>::ReadBigEndian(&payload[8])) {
52 0 : LOG(LS_WARNING) << "REMB identifier not found, not a REMB packet.";
53 0 : return false;
54 : }
55 0 : uint8_t number_of_ssrcs = payload[12];
56 0 : if (packet.payload_size_bytes() !=
57 0 : kCommonFeedbackLength + (2 + number_of_ssrcs) * 4) {
58 0 : LOG(LS_WARNING) << "Payload size " << packet.payload_size_bytes()
59 0 : << " does not match " << number_of_ssrcs << " ssrcs.";
60 0 : return false;
61 : }
62 :
63 0 : ParseCommonFeedback(payload);
64 0 : uint8_t exponenta = payload[13] >> 2;
65 0 : uint64_t mantissa = (static_cast<uint32_t>(payload[13] & 0x03) << 16) |
66 0 : ByteReader<uint16_t>::ReadBigEndian(&payload[14]);
67 0 : bitrate_bps_ = (mantissa << exponenta);
68 0 : bool shift_overflow = (bitrate_bps_ >> exponenta) != mantissa;
69 0 : if (shift_overflow) {
70 0 : LOG(LS_ERROR) << "Invalid remb bitrate value : " << mantissa
71 0 : << "*2^" << static_cast<int>(exponenta);
72 0 : return false;
73 : }
74 :
75 0 : const uint8_t* next_ssrc = payload + 16;
76 0 : ssrcs_.clear();
77 0 : ssrcs_.reserve(number_of_ssrcs);
78 0 : for (uint8_t i = 0; i < number_of_ssrcs; ++i) {
79 0 : ssrcs_.push_back(ByteReader<uint32_t>::ReadBigEndian(next_ssrc));
80 0 : next_ssrc += sizeof(uint32_t);
81 : }
82 :
83 0 : return true;
84 : }
85 :
86 0 : bool Remb::SetSsrcs(std::vector<uint32_t> ssrcs) {
87 0 : if (ssrcs.size() > kMaxNumberOfSsrcs) {
88 0 : LOG(LS_WARNING) << "Not enough space for all given SSRCs.";
89 0 : return false;
90 : }
91 0 : ssrcs_ = std::move(ssrcs);
92 0 : return true;
93 : }
94 :
95 0 : bool Remb::Create(uint8_t* packet,
96 : size_t* index,
97 : size_t max_length,
98 : RtcpPacket::PacketReadyCallback* callback) const {
99 0 : while (*index + BlockLength() > max_length) {
100 0 : if (!OnBufferFull(packet, index, callback))
101 0 : return false;
102 : }
103 0 : size_t index_end = *index + BlockLength();
104 0 : CreateHeader(kFeedbackMessageType, kPacketType, HeaderLength(), packet,
105 0 : index);
106 0 : RTC_DCHECK_EQ(0, Psfb::media_ssrc());
107 0 : CreateCommonFeedback(packet + *index);
108 0 : *index += kCommonFeedbackLength;
109 :
110 0 : ByteWriter<uint32_t>::WriteBigEndian(packet + *index, kUniqueIdentifier);
111 0 : *index += sizeof(uint32_t);
112 0 : const uint32_t kMaxMantissa = 0x3ffff; // 18 bits.
113 0 : uint64_t mantissa = bitrate_bps_;
114 0 : uint8_t exponenta = 0;
115 0 : while (mantissa > kMaxMantissa) {
116 0 : mantissa >>= 1;
117 0 : ++exponenta;
118 : }
119 0 : packet[(*index)++] = ssrcs_.size();
120 0 : packet[(*index)++] = (exponenta << 2) | (mantissa >> 16);
121 0 : ByteWriter<uint16_t>::WriteBigEndian(packet + *index, mantissa & 0xffff);
122 0 : *index += sizeof(uint16_t);
123 :
124 0 : for (uint32_t ssrc : ssrcs_) {
125 0 : ByteWriter<uint32_t>::WriteBigEndian(packet + *index, ssrc);
126 0 : *index += sizeof(uint32_t);
127 : }
128 0 : RTC_DCHECK_EQ(index_end, *index);
129 0 : return true;
130 : }
131 : } // namespace rtcp
132 : } // namespace webrtc
|