1 /*
2  *  Copyright (c) 2015 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/dlrr.h"
12 
13 #include "webrtc/base/checks.h"
14 #include "webrtc/base/logging.h"
15 #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
16 
17 namespace webrtc {
18 namespace rtcp {
19 // DLRR Report Block (RFC 3611).
20 //
21 //   0                   1                   2                   3
22 //   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
23 //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
24 //  |     BT=5      |   reserved    |         block length          |
25 //  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
26 //  |                 SSRC_1 (SSRC of first receiver)               | sub-
27 //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
28 //  |                         last RR (LRR)                         |   1
29 //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
30 //  |                   delay since last RR (DLRR)                  |
31 //  +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
32 //  |                 SSRC_2 (SSRC of second receiver)              | sub-
33 //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
34 //  :                               ...                             :   2
Parse(const uint8_t * buffer,uint16_t block_length_32bits)35 bool Dlrr::Parse(const uint8_t* buffer, uint16_t block_length_32bits) {
36   RTC_DCHECK(buffer[0] == kBlockType);
37   // kReserved = buffer[1];
38   RTC_DCHECK_EQ(block_length_32bits,
39                 ByteReader<uint16_t>::ReadBigEndian(&buffer[2]));
40   if (block_length_32bits % 3 != 0) {
41     LOG(LS_WARNING) << "Invalid size for dlrr block.";
42     return false;
43   }
44 
45   size_t blocks_count = block_length_32bits / 3;
46   const uint8_t* read_at = buffer + kBlockHeaderLength;
47   sub_blocks_.resize(blocks_count);
48   for (SubBlock& sub_block : sub_blocks_) {
49     sub_block.ssrc = ByteReader<uint32_t>::ReadBigEndian(&read_at[0]);
50     sub_block.last_rr = ByteReader<uint32_t>::ReadBigEndian(&read_at[4]);
51     sub_block.delay_since_last_rr =
52         ByteReader<uint32_t>::ReadBigEndian(&read_at[8]);
53     read_at += kSubBlockLength;
54   }
55   return true;
56 }
57 
BlockLength() const58 size_t Dlrr::BlockLength() const {
59   if (sub_blocks_.empty())
60     return 0;
61   return kBlockHeaderLength + kSubBlockLength * sub_blocks_.size();
62 }
63 
Create(uint8_t * buffer) const64 void Dlrr::Create(uint8_t* buffer) const {
65   if (sub_blocks_.empty())  // No subblocks, no need to write header either.
66     return;
67   // Create block header.
68   const uint8_t kReserved = 0;
69   buffer[0] = kBlockType;
70   buffer[1] = kReserved;
71   ByteWriter<uint16_t>::WriteBigEndian(&buffer[2], 3 * sub_blocks_.size());
72   // Create sub blocks.
73   uint8_t* write_at = buffer + kBlockHeaderLength;
74   for (const SubBlock& sub_block : sub_blocks_) {
75     ByteWriter<uint32_t>::WriteBigEndian(&write_at[0], sub_block.ssrc);
76     ByteWriter<uint32_t>::WriteBigEndian(&write_at[4], sub_block.last_rr);
77     ByteWriter<uint32_t>::WriteBigEndian(&write_at[8],
78                                          sub_block.delay_since_last_rr);
79     write_at += kSubBlockLength;
80   }
81   RTC_DCHECK_EQ(buffer + BlockLength(), write_at);
82 }
83 
WithDlrrItem(uint32_t ssrc,uint32_t last_rr,uint32_t delay_last_rr)84 bool Dlrr::WithDlrrItem(uint32_t ssrc,
85                         uint32_t last_rr,
86                         uint32_t delay_last_rr) {
87   if (sub_blocks_.size() >= kMaxNumberOfDlrrItems) {
88     LOG(LS_WARNING) << "Max DLRR items reached.";
89     return false;
90   }
91   SubBlock block;
92   block.ssrc = ssrc;
93   block.last_rr = last_rr;
94   block.delay_since_last_rr = delay_last_rr;
95   sub_blocks_.push_back(block);
96   return true;
97 }
98 
99 }  // namespace rtcp
100 }  // namespace webrtc
101