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. 4 5 #include "media/cast/transport/rtcp/rtcp_builder.h" 6 7 #include <algorithm> 8 #include <string> 9 #include <vector> 10 11 #include "base/big_endian.h" 12 #include "base/logging.h" 13 #include "media/cast/transport/cast_transport_defines.h" 14 #include "media/cast/transport/pacing/paced_sender.h" 15 16 namespace media { 17 namespace cast { 18 namespace transport { 19 20 RtcpBuilder::RtcpBuilder(PacedSender* const outgoing_transport) 21 : transport_(outgoing_transport), 22 ssrc_(0) { 23 } 24 25 RtcpBuilder::~RtcpBuilder() {} 26 27 void RtcpBuilder::SendRtcpFromRtpSender( 28 uint32 packet_type_flags, 29 const RtcpSenderInfo& sender_info, 30 const RtcpDlrrReportBlock& dlrr, 31 uint32 sending_ssrc, 32 const std::string& c_name) { 33 if (packet_type_flags & kRtcpRr || 34 packet_type_flags & kRtcpPli || 35 packet_type_flags & kRtcpRrtr || 36 packet_type_flags & kRtcpCast || 37 packet_type_flags & kRtcpReceiverLog || 38 packet_type_flags & kRtcpRpsi || 39 packet_type_flags & kRtcpRemb || 40 packet_type_flags & kRtcpNack) { 41 NOTREACHED() << "Invalid argument"; 42 } 43 ssrc_ = sending_ssrc; 44 c_name_ = c_name; 45 PacketRef packet(new base::RefCountedData<Packet>); 46 packet->data.reserve(kMaxIpPacketSize); 47 if (packet_type_flags & kRtcpSr) { 48 if (!BuildSR(sender_info, &packet->data)) return; 49 if (!BuildSdec(&packet->data)) return; 50 } 51 if (packet_type_flags & kRtcpBye) { 52 if (!BuildBye(&packet->data)) return; 53 } 54 if (packet_type_flags & kRtcpDlrr) { 55 if (!BuildDlrrRb(dlrr, &packet->data)) return; 56 } 57 if (packet->data.empty()) 58 return; // Sanity - don't send empty packets. 59 60 transport_->SendRtcpPacket(ssrc_, packet); 61 } 62 63 bool RtcpBuilder::BuildSR(const RtcpSenderInfo& sender_info, 64 Packet* packet) const { 65 // Sender report. 66 size_t start_size = packet->size(); 67 if (start_size + 52 > kMaxIpPacketSize) { 68 DLOG(FATAL) << "Not enough buffer space"; 69 return false; 70 } 71 72 uint16 number_of_rows = 6; 73 packet->resize(start_size + 28); 74 75 base::BigEndianWriter big_endian_writer( 76 reinterpret_cast<char*>(&((*packet)[start_size])), 28); 77 big_endian_writer.WriteU8(0x80); 78 big_endian_writer.WriteU8(kPacketTypeSenderReport); 79 big_endian_writer.WriteU16(number_of_rows); 80 big_endian_writer.WriteU32(ssrc_); 81 big_endian_writer.WriteU32(sender_info.ntp_seconds); 82 big_endian_writer.WriteU32(sender_info.ntp_fraction); 83 big_endian_writer.WriteU32(sender_info.rtp_timestamp); 84 big_endian_writer.WriteU32(sender_info.send_packet_count); 85 big_endian_writer.WriteU32(static_cast<uint32>(sender_info.send_octet_count)); 86 return true; 87 } 88 89 bool RtcpBuilder::BuildSdec(Packet* packet) const { 90 size_t start_size = packet->size(); 91 if (start_size + 12 + c_name_.length() > kMaxIpPacketSize) { 92 DLOG(FATAL) << "Not enough buffer space"; 93 return false; 94 } 95 96 // SDES Source Description. 97 packet->resize(start_size + 10); 98 99 base::BigEndianWriter big_endian_writer( 100 reinterpret_cast<char*>(&((*packet)[start_size])), 10); 101 // We always need to add one SDES CNAME. 102 big_endian_writer.WriteU8(0x80 + 1); 103 big_endian_writer.WriteU8(kPacketTypeSdes); 104 105 // Handle SDES length later on. 106 uint32 sdes_length_position = static_cast<uint32>(start_size) + 3; 107 big_endian_writer.WriteU16(0); 108 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. 109 big_endian_writer.WriteU8(1); // CNAME = 1 110 big_endian_writer.WriteU8(static_cast<uint8>(c_name_.length())); 111 112 size_t sdes_length = 10 + c_name_.length(); 113 packet->insert(packet->end(), c_name_.c_str(), 114 c_name_.c_str() + c_name_.length()); 115 116 size_t padding = 0; 117 118 // We must have a zero field even if we have an even multiple of 4 bytes. 119 if ((packet->size() % 4) == 0) { 120 padding++; 121 packet->push_back(0); 122 } 123 while ((packet->size() % 4) != 0) { 124 padding++; 125 packet->push_back(0); 126 } 127 sdes_length += padding; 128 129 // In 32-bit words minus one and we don't count the header. 130 uint8 buffer_length = static_cast<uint8>((sdes_length / 4) - 1); 131 (*packet)[sdes_length_position] = buffer_length; 132 return true; 133 } 134 135 bool RtcpBuilder::BuildBye(Packet* packet) const { 136 size_t start_size = packet->size(); 137 if (start_size + 8 > kMaxIpPacketSize) { 138 DLOG(FATAL) << "Not enough buffer space"; 139 return false; 140 } 141 142 packet->resize(start_size + 8); 143 144 base::BigEndianWriter big_endian_writer( 145 reinterpret_cast<char*>(&((*packet)[start_size])), 8); 146 big_endian_writer.WriteU8(0x80 + 1); 147 big_endian_writer.WriteU8(kPacketTypeBye); 148 big_endian_writer.WriteU16(1); // Length. 149 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. 150 return true; 151 } 152 153 /* 154 0 1 2 3 155 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 156 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 157 |V=2|P|reserved | PT=XR=207 | length | 158 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 159 | SSRC | 160 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 161 | BT=5 | reserved | block length | 162 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 163 | SSRC_1 (SSRC of first receiver) | sub- 164 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block 165 | last RR (LRR) | 1 166 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 167 | delay since last RR (DLRR) | 168 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 169 */ 170 bool RtcpBuilder::BuildDlrrRb(const RtcpDlrrReportBlock& dlrr, 171 Packet* packet) const { 172 size_t start_size = packet->size(); 173 if (start_size + 24 > kMaxIpPacketSize) { 174 DLOG(FATAL) << "Not enough buffer space"; 175 return false; 176 } 177 178 packet->resize(start_size + 24); 179 180 base::BigEndianWriter big_endian_writer( 181 reinterpret_cast<char*>(&((*packet)[start_size])), 24); 182 big_endian_writer.WriteU8(0x80); 183 big_endian_writer.WriteU8(kPacketTypeXr); 184 big_endian_writer.WriteU16(5); // Length. 185 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. 186 big_endian_writer.WriteU8(5); // Add block type. 187 big_endian_writer.WriteU8(0); // Add reserved. 188 big_endian_writer.WriteU16(3); // Block length. 189 big_endian_writer.WriteU32(ssrc_); // Add the media (received RTP) SSRC. 190 big_endian_writer.WriteU32(dlrr.last_rr); 191 big_endian_writer.WriteU32(dlrr.delay_since_last_rr); 192 return true; 193 } 194 195 } // namespace transport 196 } // namespace cast 197 } // namespace media 198