1 /*
2  *  Copyright (c) 2014 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 "modules/rtp_rtcp/source/rtcp_packet.h"
12 
13 #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
14 #include "rtc_base/checks.h"
15 
16 namespace webrtc {
17 namespace rtcp {
18 constexpr size_t RtcpPacket::kHeaderLength;
19 
Build() const20 rtc::Buffer RtcpPacket::Build() const {
21   rtc::Buffer packet(BlockLength());
22 
23   size_t length = 0;
24   bool created = Create(packet.data(), &length, packet.capacity(), nullptr);
25   RTC_DCHECK(created) << "Invalid packet is not supported.";
26   RTC_DCHECK_EQ(length, packet.size())
27       << "BlockLength mispredicted size used by Create";
28 
29   return packet;
30 }
31 
Build(size_t max_length,PacketReadyCallback callback) const32 bool RtcpPacket::Build(size_t max_length, PacketReadyCallback callback) const {
33   RTC_CHECK_LE(max_length, IP_PACKET_SIZE);
34   uint8_t buffer[IP_PACKET_SIZE];
35   size_t index = 0;
36   if (!Create(buffer, &index, max_length, callback))
37     return false;
38   return OnBufferFull(buffer, &index, callback);
39 }
40 
OnBufferFull(uint8_t * packet,size_t * index,PacketReadyCallback callback) const41 bool RtcpPacket::OnBufferFull(uint8_t* packet,
42                               size_t* index,
43                               PacketReadyCallback callback) const {
44   if (*index == 0)
45     return false;
46   RTC_DCHECK(callback) << "Fragmentation not supported.";
47   callback(rtc::ArrayView<const uint8_t>(packet, *index));
48   *index = 0;
49   return true;
50 }
51 
HeaderLength() const52 size_t RtcpPacket::HeaderLength() const {
53   size_t length_in_bytes = BlockLength();
54   RTC_DCHECK_GT(length_in_bytes, 0);
55   RTC_DCHECK_EQ(length_in_bytes % 4, 0)
56       << "Padding must be handled by each subclass.";
57   // Length in 32-bit words without common header.
58   return (length_in_bytes - kHeaderLength) / 4;
59 }
60 
61 // From RFC 3550, RTP: A Transport Protocol for Real-Time Applications.
62 //
63 // RTP header format.
64 //   0                   1                   2                   3
65 //   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
66 //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
67 //  |V=2|P| RC/FMT  |      PT       |             length            |
68 //  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
CreateHeader(size_t count_or_format,uint8_t packet_type,size_t length,uint8_t * buffer,size_t * pos)69 void RtcpPacket::CreateHeader(
70     size_t count_or_format,  // Depends on packet type.
71     uint8_t packet_type,
72     size_t length,
73     uint8_t* buffer,
74     size_t* pos) {
75   CreateHeader(count_or_format, packet_type, length, /*padding=*/false, buffer,
76                pos);
77 }
78 
CreateHeader(size_t count_or_format,uint8_t packet_type,size_t length,bool padding,uint8_t * buffer,size_t * pos)79 void RtcpPacket::CreateHeader(
80     size_t count_or_format,  // Depends on packet type.
81     uint8_t packet_type,
82     size_t length,
83     bool padding,
84     uint8_t* buffer,
85     size_t* pos) {
86   RTC_DCHECK_LE(length, 0xffffU);
87   RTC_DCHECK_LE(count_or_format, 0x1f);
88   constexpr uint8_t kVersionBits = 2 << 6;
89   uint8_t padding_bit = padding ? 1 << 5 : 0;
90   buffer[*pos + 0] =
91       kVersionBits | padding_bit | static_cast<uint8_t>(count_or_format);
92   buffer[*pos + 1] = packet_type;
93   buffer[*pos + 2] = (length >> 8) & 0xff;
94   buffer[*pos + 3] = length & 0xff;
95   *pos += kHeaderLength;
96 }
97 
98 }  // namespace rtcp
99 }  // namespace webrtc
100