1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/cast/transport/rtcp/rtcp_builder.h"
11 #include "base/logging.h"
12 #include "media/cast/transport/cast_transport_defines.h"
13 #include "media/cast/transport/pacing/paced_sender.h"
14 #include "net/base/big_endian.h"
16 static const size_t kRtcpCastLogHeaderSize = 12;
17 static const size_t kRtcpSenderFrameLogSize = 4;
24 // RFC 3550 page 44, including end null.
25 static const uint32 kCast = ('C' << 24) + ('A' << 16) + ('S' << 8) + 'T';
26 static const uint8 kSenderLogSubtype = 1;
29 RtcpBuilder::RtcpBuilder(PacedSender* const outgoing_transport)
30 : transport_(outgoing_transport),
34 RtcpBuilder::~RtcpBuilder() {}
36 void RtcpBuilder::SendRtcpFromRtpSender(
37 uint32 packet_type_flags,
38 const RtcpSenderInfo& sender_info,
39 const RtcpDlrrReportBlock& dlrr,
40 const RtcpSenderLogMessage& sender_log,
42 const std::string& c_name) {
43 if (packet_type_flags & kRtcpRr ||
44 packet_type_flags & kRtcpPli ||
45 packet_type_flags & kRtcpRrtr ||
46 packet_type_flags & kRtcpCast ||
47 packet_type_flags & kRtcpReceiverLog ||
48 packet_type_flags & kRtcpRpsi ||
49 packet_type_flags & kRtcpRemb ||
50 packet_type_flags & kRtcpNack) {
51 NOTREACHED() << "Invalid argument";
56 packet.reserve(kMaxIpPacketSize);
57 if (packet_type_flags & kRtcpSr) {
58 if (!BuildSR(sender_info, &packet)) return;
59 if (!BuildSdec(&packet)) return;
61 if (packet_type_flags & kRtcpBye) {
62 if (!BuildBye(&packet)) return;
64 if (packet_type_flags & kRtcpDlrr) {
65 if (!BuildDlrrRb(dlrr, &packet)) return;
67 if (packet_type_flags & kRtcpSenderLog) {
68 if (!BuildSenderLog(sender_log, &packet)) return;
71 return; // Sanity - don't send empty packets.
73 transport_->SendRtcpPacket(packet);
76 bool RtcpBuilder::BuildSR(const RtcpSenderInfo& sender_info,
77 Packet* packet) const {
79 size_t start_size = packet->size();
80 if (start_size + 52 > kMaxIpPacketSize) {
81 DLOG(FATAL) << "Not enough buffer space";
85 uint16 number_of_rows = 6;
86 packet->resize(start_size + 28);
88 net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 28);
89 big_endian_writer.WriteU8(0x80);
90 big_endian_writer.WriteU8(kPacketTypeSenderReport);
91 big_endian_writer.WriteU16(number_of_rows);
92 big_endian_writer.WriteU32(ssrc_);
93 big_endian_writer.WriteU32(sender_info.ntp_seconds);
94 big_endian_writer.WriteU32(sender_info.ntp_fraction);
95 big_endian_writer.WriteU32(sender_info.rtp_timestamp);
96 big_endian_writer.WriteU32(sender_info.send_packet_count);
97 big_endian_writer.WriteU32(static_cast<uint32>(sender_info.send_octet_count));
101 bool RtcpBuilder::BuildSdec(Packet* packet) const {
102 size_t start_size = packet->size();
103 if (start_size + 12 + c_name_.length() > kMaxIpPacketSize) {
104 DLOG(FATAL) << "Not enough buffer space";
108 // SDES Source Description.
109 packet->resize(start_size + 10);
111 net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 10);
112 // We always need to add one SDES CNAME.
113 big_endian_writer.WriteU8(0x80 + 1);
114 big_endian_writer.WriteU8(kPacketTypeSdes);
116 // Handle SDES length later on.
117 uint32 sdes_length_position = static_cast<uint32>(start_size) + 3;
118 big_endian_writer.WriteU16(0);
119 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
120 big_endian_writer.WriteU8(1); // CNAME = 1
121 big_endian_writer.WriteU8(static_cast<uint8>(c_name_.length()));
123 size_t sdes_length = 10 + c_name_.length();
124 packet->insert(packet->end(), c_name_.c_str(),
125 c_name_.c_str() + c_name_.length());
129 // We must have a zero field even if we have an even multiple of 4 bytes.
130 if ((packet->size() % 4) == 0) {
132 packet->push_back(0);
134 while ((packet->size() % 4) != 0) {
136 packet->push_back(0);
138 sdes_length += padding;
140 // In 32-bit words minus one and we don't count the header.
141 uint8 buffer_length = static_cast<uint8>((sdes_length / 4) - 1);
142 (*packet)[sdes_length_position] = buffer_length;
146 bool RtcpBuilder::BuildBye(Packet* packet) const {
147 size_t start_size = packet->size();
148 if (start_size + 8 > kMaxIpPacketSize) {
149 DLOG(FATAL) << "Not enough buffer space";
153 packet->resize(start_size + 8);
155 net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 8);
156 big_endian_writer.WriteU8(0x80 + 1);
157 big_endian_writer.WriteU8(kPacketTypeBye);
158 big_endian_writer.WriteU16(1); // Length.
159 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
165 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
166 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
167 |V=2|P|reserved | PT=XR=207 | length |
168 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
170 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
171 | BT=5 | reserved | block length |
172 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
173 | SSRC_1 (SSRC of first receiver) | sub-
174 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block
176 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
177 | delay since last RR (DLRR) |
178 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
180 bool RtcpBuilder::BuildDlrrRb(const RtcpDlrrReportBlock& dlrr,
181 Packet* packet) const {
182 size_t start_size = packet->size();
183 if (start_size + 24 > kMaxIpPacketSize) {
184 DLOG(FATAL) << "Not enough buffer space";
188 packet->resize(start_size + 24);
190 net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 24);
191 big_endian_writer.WriteU8(0x80);
192 big_endian_writer.WriteU8(kPacketTypeXr);
193 big_endian_writer.WriteU16(5); // Length.
194 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
195 big_endian_writer.WriteU8(5); // Add block type.
196 big_endian_writer.WriteU8(0); // Add reserved.
197 big_endian_writer.WriteU16(3); // Block length.
198 big_endian_writer.WriteU32(ssrc_); // Add the media (received RTP) SSRC.
199 big_endian_writer.WriteU32(dlrr.last_rr);
200 big_endian_writer.WriteU32(dlrr.delay_since_last_rr);
204 bool RtcpBuilder::BuildSenderLog(const RtcpSenderLogMessage& sender_log_message,
205 Packet* packet) const {
207 size_t start_size = packet->size();
208 size_t remaining_space = kMaxIpPacketSize - start_size;
209 if (remaining_space < kRtcpCastLogHeaderSize + kRtcpSenderFrameLogSize) {
210 DLOG(FATAL) << "Not enough buffer space";
214 size_t space_for_x_messages =
215 (remaining_space - kRtcpCastLogHeaderSize) / kRtcpSenderFrameLogSize;
216 size_t number_of_messages = std::min(space_for_x_messages,
217 sender_log_message.size());
219 size_t log_size = kRtcpCastLogHeaderSize +
220 number_of_messages * kRtcpSenderFrameLogSize;
221 packet->resize(start_size + log_size);
223 net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), log_size);
224 big_endian_writer.WriteU8(0x80 + kSenderLogSubtype);
225 big_endian_writer.WriteU8(kPacketTypeApplicationDefined);
226 big_endian_writer.WriteU16(static_cast<uint16>(2 + number_of_messages));
227 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
228 big_endian_writer.WriteU32(kCast);
230 std::vector<RtcpSenderFrameLogMessage>::const_iterator it =
231 sender_log_message.begin();
232 for (; number_of_messages > 0; --number_of_messages) {
233 DCHECK(!sender_log_message.empty());
234 const RtcpSenderFrameLogMessage& message = *it;
235 big_endian_writer.WriteU8(static_cast<uint8>(message.frame_status));
236 // We send the 24 east significant bits of the RTP timestamp.
237 big_endian_writer.WriteU8(static_cast<uint8>(message.rtp_timestamp >> 16));
238 big_endian_writer.WriteU8(static_cast<uint8>(message.rtp_timestamp >> 8));
239 big_endian_writer.WriteU8(static_cast<uint8>(message.rtp_timestamp));
245 } // namespace transport