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
17namespace webrtc {
18namespace 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
35bool 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
58size_t Dlrr::BlockLength() const {
59  if (sub_blocks_.empty())
60    return 0;
61  return kBlockHeaderLength + kSubBlockLength * sub_blocks_.size();
62}
63
64void 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
84bool 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