| OLD | NEW |
| (Empty) |
| 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/rtcp/rtcp_sender.h" | |
| 6 | |
| 7 #include <stdint.h> | |
| 8 | |
| 9 #include <algorithm> | |
| 10 #include <vector> | |
| 11 | |
| 12 #include "base/big_endian.h" | |
| 13 #include "base/logging.h" | |
| 14 #include "media/cast/cast_environment.h" | |
| 15 #include "media/cast/rtcp/rtcp_defines.h" | |
| 16 #include "media/cast/rtcp/rtcp_utility.h" | |
| 17 #include "media/cast/transport/cast_transport_defines.h" | |
| 18 #include "media/cast/transport/pacing/paced_sender.h" | |
| 19 | |
| 20 namespace media { | |
| 21 namespace cast { | |
| 22 namespace { | |
| 23 | |
| 24 // Max delta is 4095 milliseconds because we need to be able to encode it in | |
| 25 // 12 bits. | |
| 26 const int64 kMaxWireFormatTimeDeltaMs = INT64_C(0xfff); | |
| 27 | |
| 28 uint16 MergeEventTypeAndTimestampForWireFormat( | |
| 29 const CastLoggingEvent& event, | |
| 30 const base::TimeDelta& time_delta) { | |
| 31 int64 time_delta_ms = time_delta.InMilliseconds(); | |
| 32 | |
| 33 DCHECK_GE(time_delta_ms, 0); | |
| 34 DCHECK_LE(time_delta_ms, kMaxWireFormatTimeDeltaMs); | |
| 35 | |
| 36 uint16 time_delta_12_bits = | |
| 37 static_cast<uint16>(time_delta_ms & kMaxWireFormatTimeDeltaMs); | |
| 38 | |
| 39 uint16 event_type_4_bits = ConvertEventTypeToWireFormat(event); | |
| 40 DCHECK(event_type_4_bits); | |
| 41 DCHECK(~(event_type_4_bits & 0xfff0)); | |
| 42 return (event_type_4_bits << 12) | time_delta_12_bits; | |
| 43 } | |
| 44 | |
| 45 bool EventTimestampLessThan(const RtcpReceiverEventLogMessage& lhs, | |
| 46 const RtcpReceiverEventLogMessage& rhs) { | |
| 47 return lhs.event_timestamp < rhs.event_timestamp; | |
| 48 } | |
| 49 | |
| 50 void AddReceiverLog( | |
| 51 const RtcpReceiverLogMessage& redundancy_receiver_log_message, | |
| 52 RtcpReceiverLogMessage* receiver_log_message, | |
| 53 size_t* remaining_space, | |
| 54 size_t* number_of_frames, | |
| 55 size_t* total_number_of_messages_to_send) { | |
| 56 RtcpReceiverLogMessage::const_iterator it = | |
| 57 redundancy_receiver_log_message.begin(); | |
| 58 while (it != redundancy_receiver_log_message.end() && | |
| 59 *remaining_space >= | |
| 60 kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize) { | |
| 61 receiver_log_message->push_front(*it); | |
| 62 size_t num_event_logs = (*remaining_space - kRtcpReceiverFrameLogSize) / | |
| 63 kRtcpReceiverEventLogSize; | |
| 64 RtcpReceiverEventLogMessages& event_log_messages = | |
| 65 receiver_log_message->front().event_log_messages_; | |
| 66 if (num_event_logs < event_log_messages.size()) | |
| 67 event_log_messages.resize(num_event_logs); | |
| 68 | |
| 69 *remaining_space -= kRtcpReceiverFrameLogSize + | |
| 70 event_log_messages.size() * kRtcpReceiverEventLogSize; | |
| 71 ++*number_of_frames; | |
| 72 *total_number_of_messages_to_send += event_log_messages.size(); | |
| 73 ++it; | |
| 74 } | |
| 75 } | |
| 76 | |
| 77 // A class to build a string representing the NACK list in Cast message. | |
| 78 // | |
| 79 // The string will look like "23:3-6 25:1,5-6", meaning packets 3 to 6 in frame | |
| 80 // 23 are being NACK'ed (i.e. they are missing from the receiver's point of | |
| 81 // view) and packets 1, 5 and 6 are missing in frame 25. A frame that is | |
| 82 // completely missing will show as "26:65535". | |
| 83 class NackStringBuilder { | |
| 84 public: | |
| 85 NackStringBuilder() | |
| 86 : frame_count_(0), | |
| 87 packet_count_(0), | |
| 88 last_frame_id_(-1), | |
| 89 last_packet_id_(-1), | |
| 90 contiguous_sequence_(false) {} | |
| 91 ~NackStringBuilder() {} | |
| 92 | |
| 93 bool Empty() const { return frame_count_ == 0; } | |
| 94 | |
| 95 void PushFrame(int frame_id) { | |
| 96 DCHECK_GE(frame_id, 0); | |
| 97 if (frame_count_ > 0) { | |
| 98 if (frame_id == last_frame_id_) { | |
| 99 return; | |
| 100 } | |
| 101 if (contiguous_sequence_) { | |
| 102 stream_ << "-" << last_packet_id_; | |
| 103 } | |
| 104 stream_ << ", "; | |
| 105 } | |
| 106 stream_ << frame_id; | |
| 107 last_frame_id_ = frame_id; | |
| 108 packet_count_ = 0; | |
| 109 contiguous_sequence_ = false; | |
| 110 ++frame_count_; | |
| 111 } | |
| 112 | |
| 113 void PushPacket(int packet_id) { | |
| 114 DCHECK_GE(last_frame_id_, 0); | |
| 115 DCHECK_GE(packet_id, 0); | |
| 116 if (packet_count_ == 0) { | |
| 117 stream_ << ":" << packet_id; | |
| 118 } else if (packet_id == last_packet_id_ + 1) { | |
| 119 contiguous_sequence_ = true; | |
| 120 } else { | |
| 121 if (contiguous_sequence_) { | |
| 122 stream_ << "-" << last_packet_id_; | |
| 123 contiguous_sequence_ = false; | |
| 124 } | |
| 125 stream_ << "," << packet_id; | |
| 126 } | |
| 127 ++packet_count_; | |
| 128 last_packet_id_ = packet_id; | |
| 129 } | |
| 130 | |
| 131 std::string GetString() { | |
| 132 if (contiguous_sequence_) { | |
| 133 stream_ << "-" << last_packet_id_; | |
| 134 contiguous_sequence_ = false; | |
| 135 } | |
| 136 return stream_.str(); | |
| 137 } | |
| 138 | |
| 139 private: | |
| 140 std::ostringstream stream_; | |
| 141 int frame_count_; | |
| 142 int packet_count_; | |
| 143 int last_frame_id_; | |
| 144 int last_packet_id_; | |
| 145 bool contiguous_sequence_; | |
| 146 }; | |
| 147 } // namespace | |
| 148 | |
| 149 // TODO(mikhal): This is only used by the receiver. Consider renaming. | |
| 150 RtcpSender::RtcpSender(scoped_refptr<CastEnvironment> cast_environment, | |
| 151 transport::PacedPacketSender* outgoing_transport, | |
| 152 uint32 sending_ssrc, | |
| 153 const std::string& c_name) | |
| 154 : ssrc_(sending_ssrc), | |
| 155 c_name_(c_name), | |
| 156 transport_(outgoing_transport), | |
| 157 cast_environment_(cast_environment) { | |
| 158 DCHECK_LT(c_name_.length(), kRtcpCnameSize) << "Invalid config"; | |
| 159 } | |
| 160 | |
| 161 RtcpSender::~RtcpSender() {} | |
| 162 | |
| 163 void RtcpSender::SendRtcpFromRtpReceiver( | |
| 164 uint32 packet_type_flags, | |
| 165 const transport::RtcpReportBlock* report_block, | |
| 166 const RtcpReceiverReferenceTimeReport* rrtr, | |
| 167 const RtcpCastMessage* cast_message, | |
| 168 const ReceiverRtcpEventSubscriber::RtcpEventMultiMap* rtcp_events, | |
| 169 base::TimeDelta target_delay) { | |
| 170 if (packet_type_flags & transport::kRtcpSr || | |
| 171 packet_type_flags & transport::kRtcpDlrr || | |
| 172 packet_type_flags & transport::kRtcpSenderLog) { | |
| 173 NOTREACHED() << "Invalid argument"; | |
| 174 } | |
| 175 if (packet_type_flags & transport::kRtcpPli || | |
| 176 packet_type_flags & transport::kRtcpRpsi || | |
| 177 packet_type_flags & transport::kRtcpRemb || | |
| 178 packet_type_flags & transport::kRtcpNack) { | |
| 179 // Implement these for webrtc interop. | |
| 180 NOTIMPLEMENTED(); | |
| 181 } | |
| 182 transport::PacketRef packet(new base::RefCountedData<Packet>); | |
| 183 packet->data.reserve(kMaxIpPacketSize); | |
| 184 | |
| 185 if (packet_type_flags & transport::kRtcpRr) { | |
| 186 BuildRR(report_block, &packet->data); | |
| 187 if (!c_name_.empty()) { | |
| 188 BuildSdec(&packet->data); | |
| 189 } | |
| 190 } | |
| 191 if (packet_type_flags & transport::kRtcpBye) { | |
| 192 BuildBye(&packet->data); | |
| 193 } | |
| 194 if (packet_type_flags & transport::kRtcpRrtr) { | |
| 195 DCHECK(rrtr) << "Invalid argument"; | |
| 196 BuildRrtr(rrtr, &packet->data); | |
| 197 } | |
| 198 if (packet_type_flags & transport::kRtcpCast) { | |
| 199 DCHECK(cast_message) << "Invalid argument"; | |
| 200 BuildCast(cast_message, target_delay, &packet->data); | |
| 201 } | |
| 202 if (packet_type_flags & transport::kRtcpReceiverLog) { | |
| 203 DCHECK(rtcp_events) << "Invalid argument"; | |
| 204 BuildReceiverLog(*rtcp_events, &packet->data); | |
| 205 } | |
| 206 | |
| 207 if (packet->data.empty()) | |
| 208 return; // Sanity don't send empty packets. | |
| 209 | |
| 210 transport_->SendRtcpPacket(ssrc_, packet); | |
| 211 } | |
| 212 | |
| 213 void RtcpSender::BuildRR(const transport::RtcpReportBlock* report_block, | |
| 214 Packet* packet) const { | |
| 215 size_t start_size = packet->size(); | |
| 216 DCHECK_LT(start_size + 32, kMaxIpPacketSize) << "Not enough buffer space"; | |
| 217 if (start_size + 32 > kMaxIpPacketSize) | |
| 218 return; | |
| 219 | |
| 220 uint16 number_of_rows = (report_block) ? 7 : 1; | |
| 221 packet->resize(start_size + 8); | |
| 222 | |
| 223 base::BigEndianWriter big_endian_writer( | |
| 224 reinterpret_cast<char*>(&((*packet)[start_size])), 8); | |
| 225 big_endian_writer.WriteU8(0x80 + (report_block ? 1 : 0)); | |
| 226 big_endian_writer.WriteU8(transport::kPacketTypeReceiverReport); | |
| 227 big_endian_writer.WriteU16(number_of_rows); | |
| 228 big_endian_writer.WriteU32(ssrc_); | |
| 229 | |
| 230 if (report_block) { | |
| 231 AddReportBlocks(*report_block, packet); // Adds 24 bytes. | |
| 232 } | |
| 233 } | |
| 234 | |
| 235 void RtcpSender::AddReportBlocks(const transport::RtcpReportBlock& report_block, | |
| 236 Packet* packet) const { | |
| 237 size_t start_size = packet->size(); | |
| 238 DCHECK_LT(start_size + 24, kMaxIpPacketSize) << "Not enough buffer space"; | |
| 239 if (start_size + 24 > kMaxIpPacketSize) | |
| 240 return; | |
| 241 | |
| 242 packet->resize(start_size + 24); | |
| 243 | |
| 244 base::BigEndianWriter big_endian_writer( | |
| 245 reinterpret_cast<char*>(&((*packet)[start_size])), 24); | |
| 246 big_endian_writer.WriteU32(report_block.media_ssrc); | |
| 247 big_endian_writer.WriteU8(report_block.fraction_lost); | |
| 248 big_endian_writer.WriteU8(report_block.cumulative_lost >> 16); | |
| 249 big_endian_writer.WriteU8(report_block.cumulative_lost >> 8); | |
| 250 big_endian_writer.WriteU8(report_block.cumulative_lost); | |
| 251 | |
| 252 // Extended highest seq_no, contain the highest sequence number received. | |
| 253 big_endian_writer.WriteU32(report_block.extended_high_sequence_number); | |
| 254 big_endian_writer.WriteU32(report_block.jitter); | |
| 255 | |
| 256 // Last SR timestamp; our NTP time when we received the last report. | |
| 257 // This is the value that we read from the send report packet not when we | |
| 258 // received it. | |
| 259 big_endian_writer.WriteU32(report_block.last_sr); | |
| 260 | |
| 261 // Delay since last received report, time since we received the report. | |
| 262 big_endian_writer.WriteU32(report_block.delay_since_last_sr); | |
| 263 } | |
| 264 | |
| 265 void RtcpSender::BuildSdec(Packet* packet) const { | |
| 266 size_t start_size = packet->size(); | |
| 267 DCHECK_LT(start_size + 12 + c_name_.length(), kMaxIpPacketSize) | |
| 268 << "Not enough buffer space"; | |
| 269 if (start_size + 12 > kMaxIpPacketSize) | |
| 270 return; | |
| 271 | |
| 272 // SDES Source Description. | |
| 273 packet->resize(start_size + 10); | |
| 274 | |
| 275 base::BigEndianWriter big_endian_writer( | |
| 276 reinterpret_cast<char*>(&((*packet)[start_size])), 10); | |
| 277 // We always need to add one SDES CNAME. | |
| 278 big_endian_writer.WriteU8(0x80 + 1); | |
| 279 big_endian_writer.WriteU8(transport::kPacketTypeSdes); | |
| 280 | |
| 281 // Handle SDES length later on. | |
| 282 uint32 sdes_length_position = static_cast<uint32>(start_size) + 3; | |
| 283 big_endian_writer.WriteU16(0); | |
| 284 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. | |
| 285 big_endian_writer.WriteU8(1); // CNAME = 1 | |
| 286 big_endian_writer.WriteU8(static_cast<uint8>(c_name_.length())); | |
| 287 | |
| 288 size_t sdes_length = 10 + c_name_.length(); | |
| 289 packet->insert( | |
| 290 packet->end(), c_name_.c_str(), c_name_.c_str() + c_name_.length()); | |
| 291 | |
| 292 size_t padding = 0; | |
| 293 | |
| 294 // We must have a zero field even if we have an even multiple of 4 bytes. | |
| 295 if ((packet->size() % 4) == 0) { | |
| 296 padding++; | |
| 297 packet->push_back(0); | |
| 298 } | |
| 299 while ((packet->size() % 4) != 0) { | |
| 300 padding++; | |
| 301 packet->push_back(0); | |
| 302 } | |
| 303 sdes_length += padding; | |
| 304 | |
| 305 // In 32-bit words minus one and we don't count the header. | |
| 306 uint8 buffer_length = static_cast<uint8>((sdes_length / 4) - 1); | |
| 307 (*packet)[sdes_length_position] = buffer_length; | |
| 308 } | |
| 309 | |
| 310 void RtcpSender::BuildPli(uint32 remote_ssrc, Packet* packet) const { | |
| 311 size_t start_size = packet->size(); | |
| 312 DCHECK_LT(start_size + 12, kMaxIpPacketSize) << "Not enough buffer space"; | |
| 313 if (start_size + 12 > kMaxIpPacketSize) | |
| 314 return; | |
| 315 | |
| 316 packet->resize(start_size + 12); | |
| 317 | |
| 318 base::BigEndianWriter big_endian_writer( | |
| 319 reinterpret_cast<char*>(&((*packet)[start_size])), 12); | |
| 320 uint8 FMT = 1; // Picture loss indicator. | |
| 321 big_endian_writer.WriteU8(0x80 + FMT); | |
| 322 big_endian_writer.WriteU8(transport::kPacketTypePayloadSpecific); | |
| 323 big_endian_writer.WriteU16(2); // Used fixed length of 2. | |
| 324 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. | |
| 325 big_endian_writer.WriteU32(remote_ssrc); // Add the remote SSRC. | |
| 326 } | |
| 327 | |
| 328 /* | |
| 329 0 1 2 3 | |
| 330 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 | |
| 331 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 332 | PB |0| Payload Type| Native Rpsi bit string | | |
| 333 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 334 | defined per codec ... | Padding (0) | | |
| 335 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
| 336 */ | |
| 337 void RtcpSender::BuildRpsi(const RtcpRpsiMessage* rpsi, Packet* packet) const { | |
| 338 size_t start_size = packet->size(); | |
| 339 DCHECK_LT(start_size + 24, kMaxIpPacketSize) << "Not enough buffer space"; | |
| 340 if (start_size + 24 > kMaxIpPacketSize) | |
| 341 return; | |
| 342 | |
| 343 packet->resize(start_size + 24); | |
| 344 | |
| 345 base::BigEndianWriter big_endian_writer( | |
| 346 reinterpret_cast<char*>(&((*packet)[start_size])), 24); | |
| 347 uint8 FMT = 3; // Reference Picture Selection Indication. | |
| 348 big_endian_writer.WriteU8(0x80 + FMT); | |
| 349 big_endian_writer.WriteU8(transport::kPacketTypePayloadSpecific); | |
| 350 | |
| 351 // Calculate length. | |
| 352 uint32 bits_required = 7; | |
| 353 uint8 bytes_required = 1; | |
| 354 while ((rpsi->picture_id >> bits_required) > 0) { | |
| 355 bits_required += 7; | |
| 356 bytes_required++; | |
| 357 } | |
| 358 uint8 size = 3; | |
| 359 if (bytes_required > 6) { | |
| 360 size = 5; | |
| 361 } else if (bytes_required > 2) { | |
| 362 size = 4; | |
| 363 } | |
| 364 big_endian_writer.WriteU8(0); | |
| 365 big_endian_writer.WriteU8(size); | |
| 366 big_endian_writer.WriteU32(ssrc_); | |
| 367 big_endian_writer.WriteU32(rpsi->remote_ssrc); | |
| 368 | |
| 369 uint8 padding_bytes = 4 - ((2 + bytes_required) % 4); | |
| 370 if (padding_bytes == 4) { | |
| 371 padding_bytes = 0; | |
| 372 } | |
| 373 // Add padding length in bits, padding can be 0, 8, 16 or 24. | |
| 374 big_endian_writer.WriteU8(padding_bytes * 8); | |
| 375 big_endian_writer.WriteU8(rpsi->payload_type); | |
| 376 | |
| 377 // Add picture ID. | |
| 378 for (int i = bytes_required - 1; i > 0; i--) { | |
| 379 big_endian_writer.WriteU8(0x80 | | |
| 380 static_cast<uint8>(rpsi->picture_id >> (i * 7))); | |
| 381 } | |
| 382 // Add last byte of picture ID. | |
| 383 big_endian_writer.WriteU8(static_cast<uint8>(rpsi->picture_id & 0x7f)); | |
| 384 | |
| 385 // Add padding. | |
| 386 for (int j = 0; j < padding_bytes; ++j) { | |
| 387 big_endian_writer.WriteU8(0); | |
| 388 } | |
| 389 } | |
| 390 | |
| 391 void RtcpSender::BuildRemb(const RtcpRembMessage* remb, Packet* packet) const { | |
| 392 size_t start_size = packet->size(); | |
| 393 size_t remb_size = 20 + 4 * remb->remb_ssrcs.size(); | |
| 394 DCHECK_LT(start_size + remb_size, kMaxIpPacketSize) | |
| 395 << "Not enough buffer space"; | |
| 396 if (start_size + remb_size > kMaxIpPacketSize) | |
| 397 return; | |
| 398 | |
| 399 packet->resize(start_size + remb_size); | |
| 400 | |
| 401 base::BigEndianWriter big_endian_writer( | |
| 402 reinterpret_cast<char*>(&((*packet)[start_size])), remb_size); | |
| 403 | |
| 404 // Add application layer feedback. | |
| 405 uint8 FMT = 15; | |
| 406 big_endian_writer.WriteU8(0x80 + FMT); | |
| 407 big_endian_writer.WriteU8(transport::kPacketTypePayloadSpecific); | |
| 408 big_endian_writer.WriteU8(0); | |
| 409 big_endian_writer.WriteU8(static_cast<uint8>(remb->remb_ssrcs.size() + 4)); | |
| 410 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. | |
| 411 big_endian_writer.WriteU32(0); // Remote SSRC must be 0. | |
| 412 big_endian_writer.WriteU32(kRemb); | |
| 413 big_endian_writer.WriteU8(static_cast<uint8>(remb->remb_ssrcs.size())); | |
| 414 | |
| 415 // 6 bit exponent and a 18 bit mantissa. | |
| 416 uint8 bitrate_exponent; | |
| 417 uint32 bitrate_mantissa; | |
| 418 BitrateToRembExponentBitrate( | |
| 419 remb->remb_bitrate, &bitrate_exponent, &bitrate_mantissa); | |
| 420 | |
| 421 big_endian_writer.WriteU8(static_cast<uint8>( | |
| 422 (bitrate_exponent << 2) + ((bitrate_mantissa >> 16) & 0x03))); | |
| 423 big_endian_writer.WriteU8(static_cast<uint8>(bitrate_mantissa >> 8)); | |
| 424 big_endian_writer.WriteU8(static_cast<uint8>(bitrate_mantissa)); | |
| 425 | |
| 426 std::list<uint32>::const_iterator it = remb->remb_ssrcs.begin(); | |
| 427 for (; it != remb->remb_ssrcs.end(); ++it) { | |
| 428 big_endian_writer.WriteU32(*it); | |
| 429 } | |
| 430 } | |
| 431 | |
| 432 void RtcpSender::BuildNack(const RtcpNackMessage* nack, Packet* packet) const { | |
| 433 size_t start_size = packet->size(); | |
| 434 DCHECK_LT(start_size + 16, kMaxIpPacketSize) << "Not enough buffer space"; | |
| 435 if (start_size + 16 > kMaxIpPacketSize) | |
| 436 return; | |
| 437 | |
| 438 packet->resize(start_size + 16); | |
| 439 | |
| 440 base::BigEndianWriter big_endian_writer( | |
| 441 reinterpret_cast<char*>(&((*packet)[start_size])), 16); | |
| 442 | |
| 443 uint8 FMT = 1; | |
| 444 big_endian_writer.WriteU8(0x80 + FMT); | |
| 445 big_endian_writer.WriteU8(transport::kPacketTypeGenericRtpFeedback); | |
| 446 big_endian_writer.WriteU8(0); | |
| 447 size_t nack_size_pos = start_size + 3; | |
| 448 big_endian_writer.WriteU8(3); | |
| 449 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. | |
| 450 big_endian_writer.WriteU32(nack->remote_ssrc); // Add the remote SSRC. | |
| 451 | |
| 452 // Build NACK bitmasks and write them to the Rtcp message. | |
| 453 // The nack list should be sorted and not contain duplicates. | |
| 454 size_t number_of_nack_fields = 0; | |
| 455 size_t max_number_of_nack_fields = std::min<size_t>( | |
| 456 kRtcpMaxNackFields, (kMaxIpPacketSize - packet->size()) / 4); | |
| 457 | |
| 458 std::list<uint16>::const_iterator it = nack->nack_list.begin(); | |
| 459 while (it != nack->nack_list.end() && | |
| 460 number_of_nack_fields < max_number_of_nack_fields) { | |
| 461 uint16 nack_sequence_number = *it; | |
| 462 uint16 bitmask = 0; | |
| 463 ++it; | |
| 464 while (it != nack->nack_list.end()) { | |
| 465 int shift = static_cast<uint16>(*it - nack_sequence_number) - 1; | |
| 466 if (shift >= 0 && shift <= 15) { | |
| 467 bitmask |= (1 << shift); | |
| 468 ++it; | |
| 469 } else { | |
| 470 break; | |
| 471 } | |
| 472 } | |
| 473 // Write the sequence number and the bitmask to the packet. | |
| 474 start_size = packet->size(); | |
| 475 DCHECK_LT(start_size + 4, kMaxIpPacketSize) << "Not enough buffer space"; | |
| 476 if (start_size + 4 > kMaxIpPacketSize) | |
| 477 return; | |
| 478 | |
| 479 packet->resize(start_size + 4); | |
| 480 base::BigEndianWriter big_endian_nack_writer( | |
| 481 reinterpret_cast<char*>(&((*packet)[start_size])), 4); | |
| 482 big_endian_nack_writer.WriteU16(nack_sequence_number); | |
| 483 big_endian_nack_writer.WriteU16(bitmask); | |
| 484 number_of_nack_fields++; | |
| 485 } | |
| 486 DCHECK_GE(kRtcpMaxNackFields, number_of_nack_fields); | |
| 487 (*packet)[nack_size_pos] = static_cast<uint8>(2 + number_of_nack_fields); | |
| 488 } | |
| 489 | |
| 490 void RtcpSender::BuildBye(Packet* packet) const { | |
| 491 size_t start_size = packet->size(); | |
| 492 DCHECK_LT(start_size + 8, kMaxIpPacketSize) << "Not enough buffer space"; | |
| 493 if (start_size + 8 > kMaxIpPacketSize) | |
| 494 return; | |
| 495 | |
| 496 packet->resize(start_size + 8); | |
| 497 | |
| 498 base::BigEndianWriter big_endian_writer( | |
| 499 reinterpret_cast<char*>(&((*packet)[start_size])), 8); | |
| 500 big_endian_writer.WriteU8(0x80 + 1); | |
| 501 big_endian_writer.WriteU8(transport::kPacketTypeBye); | |
| 502 big_endian_writer.WriteU16(1); // Length. | |
| 503 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. | |
| 504 } | |
| 505 | |
| 506 void RtcpSender::BuildRrtr(const RtcpReceiverReferenceTimeReport* rrtr, | |
| 507 Packet* packet) const { | |
| 508 size_t start_size = packet->size(); | |
| 509 DCHECK_LT(start_size + 20, kMaxIpPacketSize) << "Not enough buffer space"; | |
| 510 if (start_size + 20 > kMaxIpPacketSize) | |
| 511 return; | |
| 512 | |
| 513 packet->resize(start_size + 20); | |
| 514 | |
| 515 base::BigEndianWriter big_endian_writer( | |
| 516 reinterpret_cast<char*>(&((*packet)[start_size])), 20); | |
| 517 | |
| 518 big_endian_writer.WriteU8(0x80); | |
| 519 big_endian_writer.WriteU8(transport::kPacketTypeXr); | |
| 520 big_endian_writer.WriteU16(4); // Length. | |
| 521 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. | |
| 522 big_endian_writer.WriteU8(4); // Add block type. | |
| 523 big_endian_writer.WriteU8(0); // Add reserved. | |
| 524 big_endian_writer.WriteU16(2); // Block length. | |
| 525 | |
| 526 // Add the media (received RTP) SSRC. | |
| 527 big_endian_writer.WriteU32(rrtr->ntp_seconds); | |
| 528 big_endian_writer.WriteU32(rrtr->ntp_fraction); | |
| 529 } | |
| 530 | |
| 531 void RtcpSender::BuildCast(const RtcpCastMessage* cast, | |
| 532 base::TimeDelta target_delay, | |
| 533 Packet* packet) const { | |
| 534 size_t start_size = packet->size(); | |
| 535 DCHECK_LT(start_size + 20, kMaxIpPacketSize) << "Not enough buffer space"; | |
| 536 if (start_size + 20 > kMaxIpPacketSize) | |
| 537 return; | |
| 538 | |
| 539 packet->resize(start_size + 20); | |
| 540 | |
| 541 base::BigEndianWriter big_endian_writer( | |
| 542 reinterpret_cast<char*>(&((*packet)[start_size])), 20); | |
| 543 uint8 FMT = 15; // Application layer feedback. | |
| 544 big_endian_writer.WriteU8(0x80 + FMT); | |
| 545 big_endian_writer.WriteU8(transport::kPacketTypePayloadSpecific); | |
| 546 big_endian_writer.WriteU8(0); | |
| 547 size_t cast_size_pos = start_size + 3; // Save length position. | |
| 548 big_endian_writer.WriteU8(4); | |
| 549 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. | |
| 550 big_endian_writer.WriteU32(cast->media_ssrc_); // Remote SSRC. | |
| 551 big_endian_writer.WriteU32(kCast); | |
| 552 big_endian_writer.WriteU8(static_cast<uint8>(cast->ack_frame_id_)); | |
| 553 size_t cast_loss_field_pos = start_size + 17; // Save loss field position. | |
| 554 big_endian_writer.WriteU8(0); // Overwritten with number_of_loss_fields. | |
| 555 DCHECK_LE(target_delay.InMilliseconds(), | |
| 556 std::numeric_limits<uint16_t>::max()); | |
| 557 big_endian_writer.WriteU16(target_delay.InMilliseconds()); | |
| 558 | |
| 559 size_t number_of_loss_fields = 0; | |
| 560 size_t max_number_of_loss_fields = std::min<size_t>( | |
| 561 kRtcpMaxCastLossFields, (kMaxIpPacketSize - packet->size()) / 4); | |
| 562 | |
| 563 MissingFramesAndPacketsMap::const_iterator frame_it = | |
| 564 cast->missing_frames_and_packets_.begin(); | |
| 565 | |
| 566 NackStringBuilder nack_string_builder; | |
| 567 for (; frame_it != cast->missing_frames_and_packets_.end() && | |
| 568 number_of_loss_fields < max_number_of_loss_fields; | |
| 569 ++frame_it) { | |
| 570 nack_string_builder.PushFrame(frame_it->first); | |
| 571 // Iterate through all frames with missing packets. | |
| 572 if (frame_it->second.empty()) { | |
| 573 // Special case all packets in a frame is missing. | |
| 574 start_size = packet->size(); | |
| 575 packet->resize(start_size + 4); | |
| 576 base::BigEndianWriter big_endian_nack_writer( | |
| 577 reinterpret_cast<char*>(&((*packet)[start_size])), 4); | |
| 578 big_endian_nack_writer.WriteU8(static_cast<uint8>(frame_it->first)); | |
| 579 big_endian_nack_writer.WriteU16(kRtcpCastAllPacketsLost); | |
| 580 big_endian_nack_writer.WriteU8(0); | |
| 581 nack_string_builder.PushPacket(kRtcpCastAllPacketsLost); | |
| 582 ++number_of_loss_fields; | |
| 583 } else { | |
| 584 PacketIdSet::const_iterator packet_it = frame_it->second.begin(); | |
| 585 while (packet_it != frame_it->second.end()) { | |
| 586 uint16 packet_id = *packet_it; | |
| 587 | |
| 588 start_size = packet->size(); | |
| 589 packet->resize(start_size + 4); | |
| 590 base::BigEndianWriter big_endian_nack_writer( | |
| 591 reinterpret_cast<char*>(&((*packet)[start_size])), 4); | |
| 592 | |
| 593 // Write frame and packet id to buffer before calculating bitmask. | |
| 594 big_endian_nack_writer.WriteU8(static_cast<uint8>(frame_it->first)); | |
| 595 big_endian_nack_writer.WriteU16(packet_id); | |
| 596 nack_string_builder.PushPacket(packet_id); | |
| 597 | |
| 598 uint8 bitmask = 0; | |
| 599 ++packet_it; | |
| 600 while (packet_it != frame_it->second.end()) { | |
| 601 int shift = static_cast<uint8>(*packet_it - packet_id) - 1; | |
| 602 if (shift >= 0 && shift <= 7) { | |
| 603 nack_string_builder.PushPacket(*packet_it); | |
| 604 bitmask |= (1 << shift); | |
| 605 ++packet_it; | |
| 606 } else { | |
| 607 break; | |
| 608 } | |
| 609 } | |
| 610 big_endian_nack_writer.WriteU8(bitmask); | |
| 611 ++number_of_loss_fields; | |
| 612 } | |
| 613 } | |
| 614 } | |
| 615 VLOG_IF(1, !nack_string_builder.Empty()) | |
| 616 << "SSRC: " << cast->media_ssrc_ | |
| 617 << ", ACK: " << cast->ack_frame_id_ | |
| 618 << ", NACK: " << nack_string_builder.GetString(); | |
| 619 DCHECK_LE(number_of_loss_fields, kRtcpMaxCastLossFields); | |
| 620 (*packet)[cast_size_pos] = static_cast<uint8>(4 + number_of_loss_fields); | |
| 621 (*packet)[cast_loss_field_pos] = static_cast<uint8>(number_of_loss_fields); | |
| 622 } | |
| 623 | |
| 624 void RtcpSender::BuildReceiverLog( | |
| 625 const ReceiverRtcpEventSubscriber::RtcpEventMultiMap& rtcp_events, | |
| 626 Packet* packet) { | |
| 627 const size_t packet_start_size = packet->size(); | |
| 628 size_t number_of_frames = 0; | |
| 629 size_t total_number_of_messages_to_send = 0; | |
| 630 size_t rtcp_log_size = 0; | |
| 631 RtcpReceiverLogMessage receiver_log_message; | |
| 632 | |
| 633 if (!BuildRtcpReceiverLogMessage(rtcp_events, | |
| 634 packet_start_size, | |
| 635 &receiver_log_message, | |
| 636 &number_of_frames, | |
| 637 &total_number_of_messages_to_send, | |
| 638 &rtcp_log_size)) { | |
| 639 return; | |
| 640 } | |
| 641 packet->resize(packet_start_size + rtcp_log_size); | |
| 642 | |
| 643 base::BigEndianWriter big_endian_writer( | |
| 644 reinterpret_cast<char*>(&((*packet)[packet_start_size])), rtcp_log_size); | |
| 645 big_endian_writer.WriteU8(0x80 + kReceiverLogSubtype); | |
| 646 big_endian_writer.WriteU8(transport::kPacketTypeApplicationDefined); | |
| 647 big_endian_writer.WriteU16(static_cast<uint16>( | |
| 648 2 + 2 * number_of_frames + total_number_of_messages_to_send)); | |
| 649 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. | |
| 650 big_endian_writer.WriteU32(kCast); | |
| 651 | |
| 652 while (!receiver_log_message.empty() && | |
| 653 total_number_of_messages_to_send > 0) { | |
| 654 RtcpReceiverFrameLogMessage& frame_log_messages( | |
| 655 receiver_log_message.front()); | |
| 656 | |
| 657 // Add our frame header. | |
| 658 big_endian_writer.WriteU32(frame_log_messages.rtp_timestamp_); | |
| 659 size_t messages_in_frame = frame_log_messages.event_log_messages_.size(); | |
| 660 if (messages_in_frame > total_number_of_messages_to_send) { | |
| 661 // We are running out of space. | |
| 662 messages_in_frame = total_number_of_messages_to_send; | |
| 663 } | |
| 664 // Keep track of how many messages we have left to send. | |
| 665 total_number_of_messages_to_send -= messages_in_frame; | |
| 666 | |
| 667 // On the wire format is number of messages - 1. | |
| 668 big_endian_writer.WriteU8(static_cast<uint8>(messages_in_frame - 1)); | |
| 669 | |
| 670 base::TimeTicks event_timestamp_base = | |
| 671 frame_log_messages.event_log_messages_.front().event_timestamp; | |
| 672 uint32 base_timestamp_ms = | |
| 673 (event_timestamp_base - base::TimeTicks()).InMilliseconds(); | |
| 674 big_endian_writer.WriteU8(static_cast<uint8>(base_timestamp_ms >> 16)); | |
| 675 big_endian_writer.WriteU8(static_cast<uint8>(base_timestamp_ms >> 8)); | |
| 676 big_endian_writer.WriteU8(static_cast<uint8>(base_timestamp_ms)); | |
| 677 | |
| 678 while (!frame_log_messages.event_log_messages_.empty() && | |
| 679 messages_in_frame > 0) { | |
| 680 const RtcpReceiverEventLogMessage& event_message = | |
| 681 frame_log_messages.event_log_messages_.front(); | |
| 682 uint16 event_type_and_timestamp_delta = | |
| 683 MergeEventTypeAndTimestampForWireFormat( | |
| 684 event_message.type, | |
| 685 event_message.event_timestamp - event_timestamp_base); | |
| 686 switch (event_message.type) { | |
| 687 case FRAME_ACK_SENT: | |
| 688 case FRAME_PLAYOUT: | |
| 689 case FRAME_DECODED: | |
| 690 big_endian_writer.WriteU16( | |
| 691 static_cast<uint16>(event_message.delay_delta.InMilliseconds())); | |
| 692 big_endian_writer.WriteU16(event_type_and_timestamp_delta); | |
| 693 break; | |
| 694 case PACKET_RECEIVED: | |
| 695 big_endian_writer.WriteU16(event_message.packet_id); | |
| 696 big_endian_writer.WriteU16(event_type_and_timestamp_delta); | |
| 697 break; | |
| 698 default: | |
| 699 NOTREACHED(); | |
| 700 } | |
| 701 messages_in_frame--; | |
| 702 frame_log_messages.event_log_messages_.pop_front(); | |
| 703 } | |
| 704 if (frame_log_messages.event_log_messages_.empty()) { | |
| 705 // We sent all messages on this frame; pop the frame header. | |
| 706 receiver_log_message.pop_front(); | |
| 707 } | |
| 708 } | |
| 709 DCHECK_EQ(total_number_of_messages_to_send, 0u); | |
| 710 } | |
| 711 | |
| 712 bool RtcpSender::BuildRtcpReceiverLogMessage( | |
| 713 const ReceiverRtcpEventSubscriber::RtcpEventMultiMap& rtcp_events, | |
| 714 size_t start_size, | |
| 715 RtcpReceiverLogMessage* receiver_log_message, | |
| 716 size_t* number_of_frames, | |
| 717 size_t* total_number_of_messages_to_send, | |
| 718 size_t* rtcp_log_size) { | |
| 719 size_t remaining_space = | |
| 720 std::min(kMaxReceiverLogBytes, kMaxIpPacketSize - start_size); | |
| 721 if (remaining_space < kRtcpCastLogHeaderSize + kRtcpReceiverFrameLogSize + | |
| 722 kRtcpReceiverEventLogSize) { | |
| 723 return false; | |
| 724 } | |
| 725 | |
| 726 // We use this to do event timestamp sorting and truncating for events of | |
| 727 // a single frame. | |
| 728 std::vector<RtcpReceiverEventLogMessage> sorted_log_messages; | |
| 729 | |
| 730 // Account for the RTCP header for an application-defined packet. | |
| 731 remaining_space -= kRtcpCastLogHeaderSize; | |
| 732 | |
| 733 ReceiverRtcpEventSubscriber::RtcpEventMultiMap::const_reverse_iterator rit = | |
| 734 rtcp_events.rbegin(); | |
| 735 | |
| 736 while (rit != rtcp_events.rend() && | |
| 737 remaining_space >= | |
| 738 kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize) { | |
| 739 const RtpTimestamp rtp_timestamp = rit->first; | |
| 740 RtcpReceiverFrameLogMessage frame_log(rtp_timestamp); | |
| 741 remaining_space -= kRtcpReceiverFrameLogSize; | |
| 742 ++*number_of_frames; | |
| 743 | |
| 744 // Get all events of a single frame. | |
| 745 sorted_log_messages.clear(); | |
| 746 do { | |
| 747 RtcpReceiverEventLogMessage event_log_message; | |
| 748 event_log_message.type = rit->second.type; | |
| 749 event_log_message.event_timestamp = rit->second.timestamp; | |
| 750 event_log_message.delay_delta = rit->second.delay_delta; | |
| 751 event_log_message.packet_id = rit->second.packet_id; | |
| 752 sorted_log_messages.push_back(event_log_message); | |
| 753 ++rit; | |
| 754 } while (rit != rtcp_events.rend() && rit->first == rtp_timestamp); | |
| 755 | |
| 756 std::sort(sorted_log_messages.begin(), | |
| 757 sorted_log_messages.end(), | |
| 758 &EventTimestampLessThan); | |
| 759 | |
| 760 // From |sorted_log_messages|, only take events that are no greater than | |
| 761 // |kMaxWireFormatTimeDeltaMs| seconds away from the latest event. Events | |
| 762 // older than that cannot be encoded over the wire. | |
| 763 std::vector<RtcpReceiverEventLogMessage>::reverse_iterator sorted_rit = | |
| 764 sorted_log_messages.rbegin(); | |
| 765 base::TimeTicks first_event_timestamp = sorted_rit->event_timestamp; | |
| 766 size_t events_in_frame = 0; | |
| 767 while (sorted_rit != sorted_log_messages.rend() && | |
| 768 events_in_frame < kRtcpMaxReceiverLogMessages && | |
| 769 remaining_space >= kRtcpReceiverEventLogSize) { | |
| 770 base::TimeDelta delta(first_event_timestamp - | |
| 771 sorted_rit->event_timestamp); | |
| 772 if (delta.InMilliseconds() > kMaxWireFormatTimeDeltaMs) | |
| 773 break; | |
| 774 frame_log.event_log_messages_.push_front(*sorted_rit); | |
| 775 ++events_in_frame; | |
| 776 ++*total_number_of_messages_to_send; | |
| 777 remaining_space -= kRtcpReceiverEventLogSize; | |
| 778 ++sorted_rit; | |
| 779 } | |
| 780 | |
| 781 receiver_log_message->push_front(frame_log); | |
| 782 } | |
| 783 | |
| 784 rtcp_events_history_.push_front(*receiver_log_message); | |
| 785 | |
| 786 // We don't try to match RTP timestamps of redundancy frame logs with those | |
| 787 // from the newest set (which would save the space of an extra RTP timestamp | |
| 788 // over the wire). Unless the redundancy frame logs are very recent, it's | |
| 789 // unlikely there will be a match anyway. | |
| 790 if (rtcp_events_history_.size() > kFirstRedundancyOffset) { | |
| 791 // Add first redundnacy messages, if enough space remaining | |
| 792 AddReceiverLog(rtcp_events_history_[kFirstRedundancyOffset], | |
| 793 receiver_log_message, | |
| 794 &remaining_space, | |
| 795 number_of_frames, | |
| 796 total_number_of_messages_to_send); | |
| 797 } | |
| 798 | |
| 799 if (rtcp_events_history_.size() > kSecondRedundancyOffset) { | |
| 800 // Add second redundancy messages, if enough space remaining | |
| 801 AddReceiverLog(rtcp_events_history_[kSecondRedundancyOffset], | |
| 802 receiver_log_message, | |
| 803 &remaining_space, | |
| 804 number_of_frames, | |
| 805 total_number_of_messages_to_send); | |
| 806 } | |
| 807 | |
| 808 if (rtcp_events_history_.size() > kReceiveLogMessageHistorySize) { | |
| 809 rtcp_events_history_.pop_back(); | |
| 810 } | |
| 811 | |
| 812 DCHECK_LE(rtcp_events_history_.size(), kReceiveLogMessageHistorySize); | |
| 813 | |
| 814 *rtcp_log_size = | |
| 815 kRtcpCastLogHeaderSize + *number_of_frames * kRtcpReceiverFrameLogSize + | |
| 816 *total_number_of_messages_to_send * kRtcpReceiverEventLogSize; | |
| 817 DCHECK_GE(kMaxIpPacketSize, start_size + *rtcp_log_size) | |
| 818 << "Not enough buffer space."; | |
| 819 | |
| 820 VLOG(3) << "number of frames: " << *number_of_frames; | |
| 821 VLOG(3) << "total messages to send: " << *total_number_of_messages_to_send; | |
| 822 VLOG(3) << "rtcp log size: " << *rtcp_log_size; | |
| 823 return *number_of_frames > 0; | |
| 824 } | |
| 825 | |
| 826 } // namespace cast | |
| 827 } // namespace media | |
| OLD | NEW |