OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 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/net/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/net/cast_transport_defines.h" |
| 15 #include "media/cast/net/pacing/paced_sender.h" |
| 16 #include "media/cast/net/rtcp/rtcp_defines.h" |
| 17 #include "media/cast/net/rtcp/rtcp_utility.h" |
| 18 |
| 19 namespace media { |
| 20 namespace cast { |
| 21 namespace { |
| 22 |
| 23 // Max delta is 4095 milliseconds because we need to be able to encode it in |
| 24 // 12 bits. |
| 25 const int64 kMaxWireFormatTimeDeltaMs = INT64_C(0xfff); |
| 26 |
| 27 uint16 MergeEventTypeAndTimestampForWireFormat( |
| 28 const CastLoggingEvent& event, |
| 29 const base::TimeDelta& time_delta) { |
| 30 int64 time_delta_ms = time_delta.InMilliseconds(); |
| 31 |
| 32 DCHECK_GE(time_delta_ms, 0); |
| 33 DCHECK_LE(time_delta_ms, kMaxWireFormatTimeDeltaMs); |
| 34 |
| 35 uint16 time_delta_12_bits = |
| 36 static_cast<uint16>(time_delta_ms & kMaxWireFormatTimeDeltaMs); |
| 37 |
| 38 uint16 event_type_4_bits = ConvertEventTypeToWireFormat(event); |
| 39 DCHECK(event_type_4_bits); |
| 40 DCHECK(~(event_type_4_bits & 0xfff0)); |
| 41 return (event_type_4_bits << 12) | time_delta_12_bits; |
| 42 } |
| 43 |
| 44 bool EventTimestampLessThan(const RtcpReceiverEventLogMessage& lhs, |
| 45 const RtcpReceiverEventLogMessage& rhs) { |
| 46 return lhs.event_timestamp < rhs.event_timestamp; |
| 47 } |
| 48 |
| 49 void AddReceiverLog( |
| 50 const RtcpReceiverLogMessage& redundancy_receiver_log_message, |
| 51 RtcpReceiverLogMessage* receiver_log_message, |
| 52 size_t* remaining_space, |
| 53 size_t* number_of_frames, |
| 54 size_t* total_number_of_messages_to_send) { |
| 55 RtcpReceiverLogMessage::const_iterator it = |
| 56 redundancy_receiver_log_message.begin(); |
| 57 while (it != redundancy_receiver_log_message.end() && |
| 58 *remaining_space >= |
| 59 kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize) { |
| 60 receiver_log_message->push_front(*it); |
| 61 size_t num_event_logs = (*remaining_space - kRtcpReceiverFrameLogSize) / |
| 62 kRtcpReceiverEventLogSize; |
| 63 RtcpReceiverEventLogMessages& event_log_messages = |
| 64 receiver_log_message->front().event_log_messages_; |
| 65 if (num_event_logs < event_log_messages.size()) |
| 66 event_log_messages.resize(num_event_logs); |
| 67 |
| 68 *remaining_space -= kRtcpReceiverFrameLogSize + |
| 69 event_log_messages.size() * kRtcpReceiverEventLogSize; |
| 70 ++*number_of_frames; |
| 71 *total_number_of_messages_to_send += event_log_messages.size(); |
| 72 ++it; |
| 73 } |
| 74 } |
| 75 |
| 76 // A class to build a string representing the NACK list in Cast message. |
| 77 // |
| 78 // The string will look like "23:3-6 25:1,5-6", meaning packets 3 to 6 in frame |
| 79 // 23 are being NACK'ed (i.e. they are missing from the receiver's point of |
| 80 // view) and packets 1, 5 and 6 are missing in frame 25. A frame that is |
| 81 // completely missing will show as "26:65535". |
| 82 class NackStringBuilder { |
| 83 public: |
| 84 NackStringBuilder() |
| 85 : frame_count_(0), |
| 86 packet_count_(0), |
| 87 last_frame_id_(-1), |
| 88 last_packet_id_(-1), |
| 89 contiguous_sequence_(false) {} |
| 90 ~NackStringBuilder() {} |
| 91 |
| 92 bool Empty() const { return frame_count_ == 0; } |
| 93 |
| 94 void PushFrame(int frame_id) { |
| 95 DCHECK_GE(frame_id, 0); |
| 96 if (frame_count_ > 0) { |
| 97 if (frame_id == last_frame_id_) { |
| 98 return; |
| 99 } |
| 100 if (contiguous_sequence_) { |
| 101 stream_ << "-" << last_packet_id_; |
| 102 } |
| 103 stream_ << ", "; |
| 104 } |
| 105 stream_ << frame_id; |
| 106 last_frame_id_ = frame_id; |
| 107 packet_count_ = 0; |
| 108 contiguous_sequence_ = false; |
| 109 ++frame_count_; |
| 110 } |
| 111 |
| 112 void PushPacket(int packet_id) { |
| 113 DCHECK_GE(last_frame_id_, 0); |
| 114 DCHECK_GE(packet_id, 0); |
| 115 if (packet_count_ == 0) { |
| 116 stream_ << ":" << packet_id; |
| 117 } else if (packet_id == last_packet_id_ + 1) { |
| 118 contiguous_sequence_ = true; |
| 119 } else { |
| 120 if (contiguous_sequence_) { |
| 121 stream_ << "-" << last_packet_id_; |
| 122 contiguous_sequence_ = false; |
| 123 } |
| 124 stream_ << "," << packet_id; |
| 125 } |
| 126 ++packet_count_; |
| 127 last_packet_id_ = packet_id; |
| 128 } |
| 129 |
| 130 std::string GetString() { |
| 131 if (contiguous_sequence_) { |
| 132 stream_ << "-" << last_packet_id_; |
| 133 contiguous_sequence_ = false; |
| 134 } |
| 135 return stream_.str(); |
| 136 } |
| 137 |
| 138 private: |
| 139 std::ostringstream stream_; |
| 140 int frame_count_; |
| 141 int packet_count_; |
| 142 int last_frame_id_; |
| 143 int last_packet_id_; |
| 144 bool contiguous_sequence_; |
| 145 }; |
| 146 } // namespace |
| 147 |
| 148 RtcpSender::RtcpSender(PacedPacketSender* outgoing_transport, |
| 149 uint32 sending_ssrc) |
| 150 : ssrc_(sending_ssrc), |
| 151 transport_(outgoing_transport) { |
| 152 } |
| 153 |
| 154 RtcpSender::~RtcpSender() {} |
| 155 |
| 156 void RtcpSender::SendRtcpFromRtpReceiver( |
| 157 const RtcpReportBlock* report_block, |
| 158 const RtcpReceiverReferenceTimeReport* rrtr, |
| 159 const RtcpCastMessage* cast_message, |
| 160 const ReceiverRtcpEventSubscriber::RtcpEventMultiMap* rtcp_events, |
| 161 base::TimeDelta target_delay) { |
| 162 PacketRef packet(new base::RefCountedData<Packet>); |
| 163 packet->data.reserve(kMaxIpPacketSize); |
| 164 if (report_block) |
| 165 BuildRR(report_block, &packet->data); |
| 166 if (rrtr) |
| 167 BuildRrtr(rrtr, &packet->data); |
| 168 if (cast_message) |
| 169 BuildCast(cast_message, target_delay, &packet->data); |
| 170 if (rtcp_events) |
| 171 BuildReceiverLog(*rtcp_events, &packet->data); |
| 172 |
| 173 if (packet->data.empty()) { |
| 174 NOTREACHED() << "Empty packet."; |
| 175 return; // Sanity don't send empty packets. |
| 176 } |
| 177 |
| 178 transport_->SendRtcpPacket(ssrc_, packet); |
| 179 } |
| 180 |
| 181 void RtcpSender::SendRtcpFromRtpSender( |
| 182 const RtcpSenderInfo& sender_info) { |
| 183 PacketRef packet(new base::RefCountedData<Packet>); |
| 184 packet->data.reserve(kMaxIpPacketSize); |
| 185 BuildSR(sender_info, &packet->data); |
| 186 |
| 187 if (packet->data.empty()) { |
| 188 NOTREACHED() << "Empty packet."; |
| 189 return; // Sanity - don't send empty packets. |
| 190 } |
| 191 |
| 192 transport_->SendRtcpPacket(ssrc_, packet); |
| 193 } |
| 194 |
| 195 void RtcpSender::BuildRR(const RtcpReportBlock* report_block, |
| 196 Packet* packet) const { |
| 197 size_t start_size = packet->size(); |
| 198 DCHECK_LT(start_size + 32, kMaxIpPacketSize) << "Not enough buffer space"; |
| 199 if (start_size + 32 > kMaxIpPacketSize) |
| 200 return; |
| 201 |
| 202 uint16 number_of_rows = (report_block) ? 7 : 1; |
| 203 packet->resize(start_size + 8); |
| 204 |
| 205 base::BigEndianWriter big_endian_writer( |
| 206 reinterpret_cast<char*>(&((*packet)[start_size])), 8); |
| 207 big_endian_writer.WriteU8(0x80 + (report_block ? 1 : 0)); |
| 208 big_endian_writer.WriteU8(kPacketTypeReceiverReport); |
| 209 big_endian_writer.WriteU16(number_of_rows); |
| 210 big_endian_writer.WriteU32(ssrc_); |
| 211 |
| 212 if (report_block) { |
| 213 AddReportBlocks(*report_block, packet); // Adds 24 bytes. |
| 214 } |
| 215 } |
| 216 |
| 217 void RtcpSender::AddReportBlocks(const RtcpReportBlock& report_block, |
| 218 Packet* packet) const { |
| 219 size_t start_size = packet->size(); |
| 220 DCHECK_LT(start_size + 24, kMaxIpPacketSize) << "Not enough buffer space"; |
| 221 if (start_size + 24 > kMaxIpPacketSize) |
| 222 return; |
| 223 |
| 224 packet->resize(start_size + 24); |
| 225 |
| 226 base::BigEndianWriter big_endian_writer( |
| 227 reinterpret_cast<char*>(&((*packet)[start_size])), 24); |
| 228 big_endian_writer.WriteU32(report_block.media_ssrc); |
| 229 big_endian_writer.WriteU8(report_block.fraction_lost); |
| 230 big_endian_writer.WriteU8(report_block.cumulative_lost >> 16); |
| 231 big_endian_writer.WriteU8(report_block.cumulative_lost >> 8); |
| 232 big_endian_writer.WriteU8(report_block.cumulative_lost); |
| 233 |
| 234 // Extended highest seq_no, contain the highest sequence number received. |
| 235 big_endian_writer.WriteU32(report_block.extended_high_sequence_number); |
| 236 big_endian_writer.WriteU32(report_block.jitter); |
| 237 |
| 238 // Last SR timestamp; our NTP time when we received the last report. |
| 239 // This is the value that we read from the send report packet not when we |
| 240 // received it. |
| 241 big_endian_writer.WriteU32(report_block.last_sr); |
| 242 |
| 243 // Delay since last received report, time since we received the report. |
| 244 big_endian_writer.WriteU32(report_block.delay_since_last_sr); |
| 245 } |
| 246 |
| 247 void RtcpSender::BuildRrtr(const RtcpReceiverReferenceTimeReport* rrtr, |
| 248 Packet* packet) const { |
| 249 size_t start_size = packet->size(); |
| 250 DCHECK_LT(start_size + 20, kMaxIpPacketSize) << "Not enough buffer space"; |
| 251 if (start_size + 20 > kMaxIpPacketSize) |
| 252 return; |
| 253 |
| 254 packet->resize(start_size + 20); |
| 255 |
| 256 base::BigEndianWriter big_endian_writer( |
| 257 reinterpret_cast<char*>(&((*packet)[start_size])), 20); |
| 258 |
| 259 big_endian_writer.WriteU8(0x80); |
| 260 big_endian_writer.WriteU8(kPacketTypeXr); |
| 261 big_endian_writer.WriteU16(4); // Length. |
| 262 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. |
| 263 big_endian_writer.WriteU8(4); // Add block type. |
| 264 big_endian_writer.WriteU8(0); // Add reserved. |
| 265 big_endian_writer.WriteU16(2); // Block length. |
| 266 |
| 267 // Add the media (received RTP) SSRC. |
| 268 big_endian_writer.WriteU32(rrtr->ntp_seconds); |
| 269 big_endian_writer.WriteU32(rrtr->ntp_fraction); |
| 270 } |
| 271 |
| 272 void RtcpSender::BuildCast(const RtcpCastMessage* cast, |
| 273 base::TimeDelta target_delay, |
| 274 Packet* packet) const { |
| 275 size_t start_size = packet->size(); |
| 276 DCHECK_LT(start_size + 20, kMaxIpPacketSize) << "Not enough buffer space"; |
| 277 if (start_size + 20 > kMaxIpPacketSize) |
| 278 return; |
| 279 |
| 280 packet->resize(start_size + 20); |
| 281 |
| 282 base::BigEndianWriter big_endian_writer( |
| 283 reinterpret_cast<char*>(&((*packet)[start_size])), 20); |
| 284 uint8 FMT = 15; // Application layer feedback. |
| 285 big_endian_writer.WriteU8(0x80 + FMT); |
| 286 big_endian_writer.WriteU8(kPacketTypePayloadSpecific); |
| 287 big_endian_writer.WriteU8(0); |
| 288 size_t cast_size_pos = start_size + 3; // Save length position. |
| 289 big_endian_writer.WriteU8(4); |
| 290 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. |
| 291 big_endian_writer.WriteU32(cast->media_ssrc); // Remote SSRC. |
| 292 big_endian_writer.WriteU32(kCast); |
| 293 big_endian_writer.WriteU8(static_cast<uint8>(cast->ack_frame_id)); |
| 294 size_t cast_loss_field_pos = start_size + 17; // Save loss field position. |
| 295 big_endian_writer.WriteU8(0); // Overwritten with number_of_loss_fields. |
| 296 DCHECK_LE(target_delay.InMilliseconds(), |
| 297 std::numeric_limits<uint16_t>::max()); |
| 298 big_endian_writer.WriteU16(target_delay.InMilliseconds()); |
| 299 |
| 300 size_t number_of_loss_fields = 0; |
| 301 size_t max_number_of_loss_fields = std::min<size_t>( |
| 302 kRtcpMaxCastLossFields, (kMaxIpPacketSize - packet->size()) / 4); |
| 303 |
| 304 MissingFramesAndPacketsMap::const_iterator frame_it = |
| 305 cast->missing_frames_and_packets.begin(); |
| 306 |
| 307 NackStringBuilder nack_string_builder; |
| 308 for (; frame_it != cast->missing_frames_and_packets.end() && |
| 309 number_of_loss_fields < max_number_of_loss_fields; |
| 310 ++frame_it) { |
| 311 nack_string_builder.PushFrame(frame_it->first); |
| 312 // Iterate through all frames with missing packets. |
| 313 if (frame_it->second.empty()) { |
| 314 // Special case all packets in a frame is missing. |
| 315 start_size = packet->size(); |
| 316 packet->resize(start_size + 4); |
| 317 base::BigEndianWriter big_endian_nack_writer( |
| 318 reinterpret_cast<char*>(&((*packet)[start_size])), 4); |
| 319 big_endian_nack_writer.WriteU8(static_cast<uint8>(frame_it->first)); |
| 320 big_endian_nack_writer.WriteU16(kRtcpCastAllPacketsLost); |
| 321 big_endian_nack_writer.WriteU8(0); |
| 322 nack_string_builder.PushPacket(kRtcpCastAllPacketsLost); |
| 323 ++number_of_loss_fields; |
| 324 } else { |
| 325 PacketIdSet::const_iterator packet_it = frame_it->second.begin(); |
| 326 while (packet_it != frame_it->second.end()) { |
| 327 uint16 packet_id = *packet_it; |
| 328 |
| 329 start_size = packet->size(); |
| 330 packet->resize(start_size + 4); |
| 331 base::BigEndianWriter big_endian_nack_writer( |
| 332 reinterpret_cast<char*>(&((*packet)[start_size])), 4); |
| 333 |
| 334 // Write frame and packet id to buffer before calculating bitmask. |
| 335 big_endian_nack_writer.WriteU8(static_cast<uint8>(frame_it->first)); |
| 336 big_endian_nack_writer.WriteU16(packet_id); |
| 337 nack_string_builder.PushPacket(packet_id); |
| 338 |
| 339 uint8 bitmask = 0; |
| 340 ++packet_it; |
| 341 while (packet_it != frame_it->second.end()) { |
| 342 int shift = static_cast<uint8>(*packet_it - packet_id) - 1; |
| 343 if (shift >= 0 && shift <= 7) { |
| 344 nack_string_builder.PushPacket(*packet_it); |
| 345 bitmask |= (1 << shift); |
| 346 ++packet_it; |
| 347 } else { |
| 348 break; |
| 349 } |
| 350 } |
| 351 big_endian_nack_writer.WriteU8(bitmask); |
| 352 ++number_of_loss_fields; |
| 353 } |
| 354 } |
| 355 } |
| 356 VLOG_IF(1, !nack_string_builder.Empty()) |
| 357 << "SSRC: " << cast->media_ssrc |
| 358 << ", ACK: " << cast->ack_frame_id |
| 359 << ", NACK: " << nack_string_builder.GetString(); |
| 360 DCHECK_LE(number_of_loss_fields, kRtcpMaxCastLossFields); |
| 361 (*packet)[cast_size_pos] = static_cast<uint8>(4 + number_of_loss_fields); |
| 362 (*packet)[cast_loss_field_pos] = static_cast<uint8>(number_of_loss_fields); |
| 363 } |
| 364 |
| 365 void RtcpSender::BuildSR(const RtcpSenderInfo& sender_info, |
| 366 Packet* packet) const { |
| 367 // Sender report. |
| 368 size_t start_size = packet->size(); |
| 369 if (start_size + 52 > kMaxIpPacketSize) { |
| 370 DLOG(FATAL) << "Not enough buffer space"; |
| 371 return; |
| 372 } |
| 373 |
| 374 uint16 number_of_rows = 6; |
| 375 packet->resize(start_size + 28); |
| 376 |
| 377 base::BigEndianWriter big_endian_writer( |
| 378 reinterpret_cast<char*>(&((*packet)[start_size])), 28); |
| 379 big_endian_writer.WriteU8(0x80); |
| 380 big_endian_writer.WriteU8(kPacketTypeSenderReport); |
| 381 big_endian_writer.WriteU16(number_of_rows); |
| 382 big_endian_writer.WriteU32(ssrc_); |
| 383 big_endian_writer.WriteU32(sender_info.ntp_seconds); |
| 384 big_endian_writer.WriteU32(sender_info.ntp_fraction); |
| 385 big_endian_writer.WriteU32(sender_info.rtp_timestamp); |
| 386 big_endian_writer.WriteU32(sender_info.send_packet_count); |
| 387 big_endian_writer.WriteU32(static_cast<uint32>(sender_info.send_octet_count)); |
| 388 return; |
| 389 } |
| 390 |
| 391 /* |
| 392 0 1 2 3 |
| 393 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 |
| 394 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 395 |V=2|P|reserved | PT=XR=207 | length | |
| 396 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 397 | SSRC | |
| 398 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 399 | BT=5 | reserved | block length | |
| 400 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| 401 | SSRC1 (SSRC of first receiver) | sub- |
| 402 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ block |
| 403 | last RR (LRR) | 1 |
| 404 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 405 | delay since last RR (DLRR) | |
| 406 +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
| 407 */ |
| 408 void RtcpSender::BuildDlrrRb(const RtcpDlrrReportBlock& dlrr, |
| 409 Packet* packet) const { |
| 410 size_t start_size = packet->size(); |
| 411 if (start_size + 24 > kMaxIpPacketSize) { |
| 412 DLOG(FATAL) << "Not enough buffer space"; |
| 413 return; |
| 414 } |
| 415 |
| 416 packet->resize(start_size + 24); |
| 417 |
| 418 base::BigEndianWriter big_endian_writer( |
| 419 reinterpret_cast<char*>(&((*packet)[start_size])), 24); |
| 420 big_endian_writer.WriteU8(0x80); |
| 421 big_endian_writer.WriteU8(kPacketTypeXr); |
| 422 big_endian_writer.WriteU16(5); // Length. |
| 423 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. |
| 424 big_endian_writer.WriteU8(5); // Add block type. |
| 425 big_endian_writer.WriteU8(0); // Add reserved. |
| 426 big_endian_writer.WriteU16(3); // Block length. |
| 427 big_endian_writer.WriteU32(ssrc_); // Add the media (received RTP) SSRC. |
| 428 big_endian_writer.WriteU32(dlrr.last_rr); |
| 429 big_endian_writer.WriteU32(dlrr.delay_since_last_rr); |
| 430 return; |
| 431 } |
| 432 |
| 433 void RtcpSender::BuildReceiverLog( |
| 434 const ReceiverRtcpEventSubscriber::RtcpEventMultiMap& rtcp_events, |
| 435 Packet* packet) { |
| 436 const size_t packet_start_size = packet->size(); |
| 437 size_t number_of_frames = 0; |
| 438 size_t total_number_of_messages_to_send = 0; |
| 439 size_t rtcp_log_size = 0; |
| 440 RtcpReceiverLogMessage receiver_log_message; |
| 441 |
| 442 if (!BuildRtcpReceiverLogMessage(rtcp_events, |
| 443 packet_start_size, |
| 444 &receiver_log_message, |
| 445 &number_of_frames, |
| 446 &total_number_of_messages_to_send, |
| 447 &rtcp_log_size)) { |
| 448 return; |
| 449 } |
| 450 packet->resize(packet_start_size + rtcp_log_size); |
| 451 |
| 452 base::BigEndianWriter big_endian_writer( |
| 453 reinterpret_cast<char*>(&((*packet)[packet_start_size])), rtcp_log_size); |
| 454 big_endian_writer.WriteU8(0x80 + kReceiverLogSubtype); |
| 455 big_endian_writer.WriteU8(kPacketTypeApplicationDefined); |
| 456 big_endian_writer.WriteU16(static_cast<uint16>( |
| 457 2 + 2 * number_of_frames + total_number_of_messages_to_send)); |
| 458 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. |
| 459 big_endian_writer.WriteU32(kCast); |
| 460 |
| 461 while (!receiver_log_message.empty() && |
| 462 total_number_of_messages_to_send > 0) { |
| 463 RtcpReceiverFrameLogMessage& frame_log_messages( |
| 464 receiver_log_message.front()); |
| 465 |
| 466 // Add our frame header. |
| 467 big_endian_writer.WriteU32(frame_log_messages.rtp_timestamp_); |
| 468 size_t messages_in_frame = frame_log_messages.event_log_messages_.size(); |
| 469 if (messages_in_frame > total_number_of_messages_to_send) { |
| 470 // We are running out of space. |
| 471 messages_in_frame = total_number_of_messages_to_send; |
| 472 } |
| 473 // Keep track of how many messages we have left to send. |
| 474 total_number_of_messages_to_send -= messages_in_frame; |
| 475 |
| 476 // On the wire format is number of messages - 1. |
| 477 big_endian_writer.WriteU8(static_cast<uint8>(messages_in_frame - 1)); |
| 478 |
| 479 base::TimeTicks event_timestamp_base = |
| 480 frame_log_messages.event_log_messages_.front().event_timestamp; |
| 481 uint32 base_timestamp_ms = |
| 482 (event_timestamp_base - base::TimeTicks()).InMilliseconds(); |
| 483 big_endian_writer.WriteU8(static_cast<uint8>(base_timestamp_ms >> 16)); |
| 484 big_endian_writer.WriteU8(static_cast<uint8>(base_timestamp_ms >> 8)); |
| 485 big_endian_writer.WriteU8(static_cast<uint8>(base_timestamp_ms)); |
| 486 |
| 487 while (!frame_log_messages.event_log_messages_.empty() && |
| 488 messages_in_frame > 0) { |
| 489 const RtcpReceiverEventLogMessage& event_message = |
| 490 frame_log_messages.event_log_messages_.front(); |
| 491 uint16 event_type_and_timestamp_delta = |
| 492 MergeEventTypeAndTimestampForWireFormat( |
| 493 event_message.type, |
| 494 event_message.event_timestamp - event_timestamp_base); |
| 495 switch (event_message.type) { |
| 496 case FRAME_ACK_SENT: |
| 497 case FRAME_PLAYOUT: |
| 498 case FRAME_DECODED: |
| 499 big_endian_writer.WriteU16( |
| 500 static_cast<uint16>(event_message.delay_delta.InMilliseconds())); |
| 501 big_endian_writer.WriteU16(event_type_and_timestamp_delta); |
| 502 break; |
| 503 case PACKET_RECEIVED: |
| 504 big_endian_writer.WriteU16(event_message.packet_id); |
| 505 big_endian_writer.WriteU16(event_type_and_timestamp_delta); |
| 506 break; |
| 507 default: |
| 508 NOTREACHED(); |
| 509 } |
| 510 messages_in_frame--; |
| 511 frame_log_messages.event_log_messages_.pop_front(); |
| 512 } |
| 513 if (frame_log_messages.event_log_messages_.empty()) { |
| 514 // We sent all messages on this frame; pop the frame header. |
| 515 receiver_log_message.pop_front(); |
| 516 } |
| 517 } |
| 518 DCHECK_EQ(total_number_of_messages_to_send, 0u); |
| 519 } |
| 520 |
| 521 bool RtcpSender::BuildRtcpReceiverLogMessage( |
| 522 const ReceiverRtcpEventSubscriber::RtcpEventMultiMap& rtcp_events, |
| 523 size_t start_size, |
| 524 RtcpReceiverLogMessage* receiver_log_message, |
| 525 size_t* number_of_frames, |
| 526 size_t* total_number_of_messages_to_send, |
| 527 size_t* rtcp_log_size) { |
| 528 size_t remaining_space = |
| 529 std::min(kMaxReceiverLogBytes, kMaxIpPacketSize - start_size); |
| 530 if (remaining_space < kRtcpCastLogHeaderSize + kRtcpReceiverFrameLogSize + |
| 531 kRtcpReceiverEventLogSize) { |
| 532 return false; |
| 533 } |
| 534 |
| 535 // We use this to do event timestamp sorting and truncating for events of |
| 536 // a single frame. |
| 537 std::vector<RtcpReceiverEventLogMessage> sorted_log_messages; |
| 538 |
| 539 // Account for the RTCP header for an application-defined packet. |
| 540 remaining_space -= kRtcpCastLogHeaderSize; |
| 541 |
| 542 ReceiverRtcpEventSubscriber::RtcpEventMultiMap::const_reverse_iterator rit = |
| 543 rtcp_events.rbegin(); |
| 544 |
| 545 while (rit != rtcp_events.rend() && |
| 546 remaining_space >= |
| 547 kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize) { |
| 548 const RtpTimestamp rtp_timestamp = rit->first; |
| 549 RtcpReceiverFrameLogMessage frame_log(rtp_timestamp); |
| 550 remaining_space -= kRtcpReceiverFrameLogSize; |
| 551 ++*number_of_frames; |
| 552 |
| 553 // Get all events of a single frame. |
| 554 sorted_log_messages.clear(); |
| 555 do { |
| 556 RtcpReceiverEventLogMessage event_log_message; |
| 557 event_log_message.type = rit->second.type; |
| 558 event_log_message.event_timestamp = rit->second.timestamp; |
| 559 event_log_message.delay_delta = rit->second.delay_delta; |
| 560 event_log_message.packet_id = rit->second.packet_id; |
| 561 sorted_log_messages.push_back(event_log_message); |
| 562 ++rit; |
| 563 } while (rit != rtcp_events.rend() && rit->first == rtp_timestamp); |
| 564 |
| 565 std::sort(sorted_log_messages.begin(), |
| 566 sorted_log_messages.end(), |
| 567 &EventTimestampLessThan); |
| 568 |
| 569 // From |sorted_log_messages|, only take events that are no greater than |
| 570 // |kMaxWireFormatTimeDeltaMs| seconds away from the latest event. Events |
| 571 // older than that cannot be encoded over the wire. |
| 572 std::vector<RtcpReceiverEventLogMessage>::reverse_iterator sorted_rit = |
| 573 sorted_log_messages.rbegin(); |
| 574 base::TimeTicks first_event_timestamp = sorted_rit->event_timestamp; |
| 575 size_t events_in_frame = 0; |
| 576 while (sorted_rit != sorted_log_messages.rend() && |
| 577 events_in_frame < kRtcpMaxReceiverLogMessages && |
| 578 remaining_space >= kRtcpReceiverEventLogSize) { |
| 579 base::TimeDelta delta(first_event_timestamp - |
| 580 sorted_rit->event_timestamp); |
| 581 if (delta.InMilliseconds() > kMaxWireFormatTimeDeltaMs) |
| 582 break; |
| 583 frame_log.event_log_messages_.push_front(*sorted_rit); |
| 584 ++events_in_frame; |
| 585 ++*total_number_of_messages_to_send; |
| 586 remaining_space -= kRtcpReceiverEventLogSize; |
| 587 ++sorted_rit; |
| 588 } |
| 589 |
| 590 receiver_log_message->push_front(frame_log); |
| 591 } |
| 592 |
| 593 rtcp_events_history_.push_front(*receiver_log_message); |
| 594 |
| 595 // We don't try to match RTP timestamps of redundancy frame logs with those |
| 596 // from the newest set (which would save the space of an extra RTP timestamp |
| 597 // over the wire). Unless the redundancy frame logs are very recent, it's |
| 598 // unlikely there will be a match anyway. |
| 599 if (rtcp_events_history_.size() > kFirstRedundancyOffset) { |
| 600 // Add first redundnacy messages, if enough space remaining |
| 601 AddReceiverLog(rtcp_events_history_[kFirstRedundancyOffset], |
| 602 receiver_log_message, |
| 603 &remaining_space, |
| 604 number_of_frames, |
| 605 total_number_of_messages_to_send); |
| 606 } |
| 607 |
| 608 if (rtcp_events_history_.size() > kSecondRedundancyOffset) { |
| 609 // Add second redundancy messages, if enough space remaining |
| 610 AddReceiverLog(rtcp_events_history_[kSecondRedundancyOffset], |
| 611 receiver_log_message, |
| 612 &remaining_space, |
| 613 number_of_frames, |
| 614 total_number_of_messages_to_send); |
| 615 } |
| 616 |
| 617 if (rtcp_events_history_.size() > kReceiveLogMessageHistorySize) { |
| 618 rtcp_events_history_.pop_back(); |
| 619 } |
| 620 |
| 621 DCHECK_LE(rtcp_events_history_.size(), kReceiveLogMessageHistorySize); |
| 622 |
| 623 *rtcp_log_size = |
| 624 kRtcpCastLogHeaderSize + *number_of_frames * kRtcpReceiverFrameLogSize + |
| 625 *total_number_of_messages_to_send * kRtcpReceiverEventLogSize; |
| 626 DCHECK_GE(kMaxIpPacketSize, start_size + *rtcp_log_size) |
| 627 << "Not enough buffer space."; |
| 628 |
| 629 VLOG(3) << "number of frames: " << *number_of_frames; |
| 630 VLOG(3) << "total messages to send: " << *total_number_of_messages_to_send; |
| 631 VLOG(3) << "rtcp log size: " << *rtcp_log_size; |
| 632 return *number_of_frames > 0; |
| 633 } |
| 634 |
| 635 } // namespace cast |
| 636 } // namespace media |
OLD | NEW |