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/tmmbn.h" 12 13 #include "webrtc/base/logging.h" 14 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" 15 16 using webrtc::RTCPUtility::PT_RTPFB; 17 using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBN; 18 using webrtc::RTCPUtility::RTCPPacketRTPFBTMMBRItem; 19 20 namespace webrtc { 21 namespace rtcp { 22 namespace { 23 const uint32_t kUnusedMediaSourceSsrc0 = 0; 24 void AssignUWord8(uint8_t* buffer, size_t* offset, uint8_t value) { 25 buffer[(*offset)++] = value; 26 } 27 void AssignUWord32(uint8_t* buffer, size_t* offset, uint32_t value) { 28 ByteWriter<uint32_t>::WriteBigEndian(buffer + *offset, value); 29 *offset += 4; 30 } 31 32 void ComputeMantissaAnd6bitBase2Exponent(uint32_t input_base10, 33 uint8_t bits_mantissa, 34 uint32_t* mantissa, 35 uint8_t* exp) { 36 // input_base10 = mantissa * 2^exp 37 assert(bits_mantissa <= 32); 38 uint32_t mantissa_max = (1 << bits_mantissa) - 1; 39 uint8_t exponent = 0; 40 for (uint32_t i = 0; i < 64; ++i) { 41 if (input_base10 <= (mantissa_max << i)) { 42 exponent = i; 43 break; 44 } 45 } 46 *exp = exponent; 47 *mantissa = (input_base10 >> exponent); 48 } 49 50 void CreateTmmbrItem(const RTCPPacketRTPFBTMMBRItem& tmmbr_item, 51 uint8_t* buffer, 52 size_t* pos) { 53 uint32_t bitrate_bps = tmmbr_item.MaxTotalMediaBitRate * 1000; 54 uint32_t mantissa = 0; 55 uint8_t exp = 0; 56 ComputeMantissaAnd6bitBase2Exponent(bitrate_bps, 17, &mantissa, &exp); 57 58 AssignUWord32(buffer, pos, tmmbr_item.SSRC); 59 AssignUWord8(buffer, pos, (exp << 2) + ((mantissa >> 15) & 0x03)); 60 AssignUWord8(buffer, pos, mantissa >> 7); 61 AssignUWord8(buffer, pos, (mantissa << 1) + 62 ((tmmbr_item.MeasuredOverhead >> 8) & 0x01)); 63 AssignUWord8(buffer, pos, tmmbr_item.MeasuredOverhead); 64 } 65 66 // Temporary Maximum Media Stream Bit Rate Notification (TMMBN) (RFC 5104). 67 // 68 // FCI: 69 // 70 // 0 1 2 3 71 // 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 72 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 73 // | SSRC | 74 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 75 // | MxTBR Exp | MxTBR Mantissa |Measured Overhead| 76 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 77 78 void CreateTmmbn(const RTCPPacketRTPFBTMMBN& tmmbn, 79 const std::vector<RTCPPacketRTPFBTMMBRItem>& tmmbn_items, 80 uint8_t* buffer, 81 size_t* pos) { 82 AssignUWord32(buffer, pos, tmmbn.SenderSSRC); 83 AssignUWord32(buffer, pos, kUnusedMediaSourceSsrc0); 84 for (uint8_t i = 0; i < tmmbn_items.size(); ++i) { 85 CreateTmmbrItem(tmmbn_items[i], buffer, pos); 86 } 87 } 88 } // namespace 89 90 bool Tmmbn::WithTmmbr(uint32_t ssrc, uint32_t bitrate_kbps, uint16_t overhead) { 91 assert(overhead <= 0x1ff); 92 if (tmmbn_items_.size() >= kMaxNumberOfTmmbrs) { 93 LOG(LS_WARNING) << "Max TMMBN size reached."; 94 return false; 95 } 96 RTCPPacketRTPFBTMMBRItem tmmbn_item; 97 tmmbn_item.SSRC = ssrc; 98 tmmbn_item.MaxTotalMediaBitRate = bitrate_kbps; 99 tmmbn_item.MeasuredOverhead = overhead; 100 tmmbn_items_.push_back(tmmbn_item); 101 return true; 102 } 103 104 bool Tmmbn::Create(uint8_t* packet, 105 size_t* index, 106 size_t max_length, 107 RtcpPacket::PacketReadyCallback* callback) const { 108 while (*index + BlockLength() > max_length) { 109 if (!OnBufferFull(packet, index, callback)) 110 return false; 111 } 112 const uint8_t kFmt = 4; 113 CreateHeader(kFmt, PT_RTPFB, HeaderLength(), packet, index); 114 CreateTmmbn(tmmbn_, tmmbn_items_, packet, index); 115 return true; 116 } 117 118 } // namespace rtcp 119 } // namespace webrtc 120