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/rtcp/rtcp_sender.h"
10 #include "base/logging.h"
11 #include "media/cast/cast_environment.h"
12 #include "media/cast/rtcp/rtcp_utility.h"
13 #include "media/cast/transport/cast_transport_defines.h"
14 #include "media/cast/transport/pacing/paced_sender.h"
15 #include "net/base/big_endian.h"
17 static const size_t kRtcpCastLogHeaderSize = 12;
18 static const size_t kRtcpSenderFrameLogSize = 4;
19 static const size_t kRtcpReceiverFrameLogSize = 8;
20 static const size_t kRtcpReceiverEventLogSize = 4;
24 // Converts a log event type to an integer value.
25 int ConvertEventTypeToWireFormat(const media::cast::CastLoggingEvent& event) {
27 case media::cast::kAudioAckSent:
29 case media::cast::kAudioPlayoutDelay:
31 case media::cast::kAudioFrameDecoded:
33 case media::cast::kAudioPacketReceived:
35 case media::cast::kVideoAckSent:
37 case media::cast::kVideoFrameDecoded:
39 case media::cast::kVideoRenderDelay:
41 case media::cast::kVideoPacketReceived:
43 case media::cast::kDuplicatePacketReceived:
46 return 0; // Not an interesting event.
50 uint16 MergeEventTypeAndTimestampForWireFormat(
51 const media::cast::CastLoggingEvent& event,
52 const base::TimeDelta& time_delta) {
53 int64 time_delta_ms = time_delta.InMilliseconds();
54 // Max delta is 4096 milliseconds.
55 DCHECK_GE(GG_INT64_C(0xfff), time_delta_ms);
57 uint16 event_type_and_timestamp_delta =
58 static_cast<uint16>(time_delta_ms & 0xfff);
60 uint16 event_type = ConvertEventTypeToWireFormat(event);
62 DCHECK(!(event_type & 0xfff0));
63 return (event_type << 12) + event_type_and_timestamp_delta;
66 bool ScanRtcpReceiverLogMessage(
67 const media::cast::RtcpReceiverLogMessage& receiver_log_message,
69 size_t* number_of_frames,
70 size_t* total_number_of_messages_to_send,
71 size_t* rtcp_log_size) {
72 if (receiver_log_message.empty()) return false;
74 size_t remaining_space = media::cast::kMaxIpPacketSize - start_size;
76 // We must have space for at least one message
77 DCHECK_GE(remaining_space, kRtcpCastLogHeaderSize +
78 kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize)
79 << "Not enough buffer space";
81 if (remaining_space < kRtcpCastLogHeaderSize + kRtcpReceiverFrameLogSize +
82 kRtcpReceiverEventLogSize) {
85 // Account for the RTCP header for an application-defined packet.
86 remaining_space -= kRtcpCastLogHeaderSize;
88 media::cast::RtcpReceiverLogMessage::const_iterator frame_it =
89 receiver_log_message.begin();
90 for (; frame_it != receiver_log_message.end(); ++frame_it) {
91 (*number_of_frames)++;
93 remaining_space -= kRtcpReceiverFrameLogSize;
95 size_t messages_in_frame = frame_it->event_log_messages_.size();
96 size_t remaining_space_in_messages =
97 remaining_space / kRtcpReceiverEventLogSize;
98 size_t messages_to_send = std::min(messages_in_frame,
99 remaining_space_in_messages);
100 if (messages_to_send > media::cast::kRtcpMaxReceiverLogMessages) {
101 // We can't send more than 256 messages.
102 remaining_space -= media::cast::kRtcpMaxReceiverLogMessages *
103 kRtcpReceiverEventLogSize;
104 *total_number_of_messages_to_send +=
105 media::cast::kRtcpMaxReceiverLogMessages;
108 remaining_space -= messages_to_send * kRtcpReceiverEventLogSize;
109 *total_number_of_messages_to_send += messages_to_send;
111 if (remaining_space <
112 kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize) {
113 // Make sure that we have room for at least one more message.
117 *rtcp_log_size = kRtcpCastLogHeaderSize +
118 *number_of_frames * kRtcpReceiverFrameLogSize +
119 *total_number_of_messages_to_send * kRtcpReceiverEventLogSize;
120 DCHECK_GE(media::cast::kMaxIpPacketSize,
121 start_size + *rtcp_log_size) << "Not enough buffer space";
123 VLOG(1) << "number of frames " << *number_of_frames;
124 VLOG(1) << "total messages to send " << *total_number_of_messages_to_send;
125 VLOG(1) << "rtcp log size " << *rtcp_log_size;
133 // TODO(mikhal): This is only used by the receiver. Consider renaming.
134 RtcpSender::RtcpSender(scoped_refptr<CastEnvironment> cast_environment,
135 transport::PacedPacketSender* outgoing_transport,
137 const std::string& c_name)
138 : ssrc_(sending_ssrc),
140 transport_(outgoing_transport),
141 cast_environment_(cast_environment) {
142 DCHECK_LT(c_name_.length(), kRtcpCnameSize) << "Invalid config";
145 RtcpSender::~RtcpSender() {}
148 bool RtcpSender::IsReceiverEvent(const media::cast::CastLoggingEvent& event) {
149 return ConvertEventTypeToWireFormat(event) != 0;
152 void RtcpSender::SendRtcpFromRtpReceiver(
153 uint32 packet_type_flags,
154 const transport::RtcpReportBlock* report_block,
155 const RtcpReceiverReferenceTimeReport* rrtr,
156 const RtcpCastMessage* cast_message,
157 RtcpReceiverLogMessage* receiver_log) {
158 if (packet_type_flags & kRtcpSr ||
159 packet_type_flags & kRtcpDlrr ||
160 packet_type_flags & kRtcpSenderLog) {
161 NOTREACHED() << "Invalid argument";
163 if (packet_type_flags & kRtcpPli ||
164 packet_type_flags & kRtcpRpsi ||
165 packet_type_flags & kRtcpRemb ||
166 packet_type_flags & kRtcpNack) {
167 // Implement these for webrtc interop.
171 packet.reserve(kMaxIpPacketSize);
173 if (packet_type_flags & kRtcpRr) {
174 BuildRR(report_block, &packet);
175 if (!c_name_.empty()) {
179 if (packet_type_flags & kRtcpBye) {
182 if (packet_type_flags & kRtcpRrtr) {
183 DCHECK(rrtr) << "Invalid argument";
184 BuildRrtr(rrtr, &packet);
186 if (packet_type_flags & kRtcpCast) {
187 DCHECK(cast_message) << "Invalid argument";
188 BuildCast(cast_message, &packet);
190 if (packet_type_flags & kRtcpReceiverLog) {
191 DCHECK(receiver_log) << "Invalid argument";
192 BuildReceiverLog(receiver_log, &packet);
194 if (packet.empty()) return; // Sanity don't send empty packets.
196 transport_->SendRtcpPacket(packet);
199 void RtcpSender::BuildRR(const transport::RtcpReportBlock* report_block,
200 Packet* packet) const {
201 size_t start_size = packet->size();
202 DCHECK_LT(start_size + 32, kMaxIpPacketSize) << "Not enough buffer space";
203 if (start_size + 32 > kMaxIpPacketSize) return;
205 uint16 number_of_rows = (report_block) ? 7 : 1;
206 packet->resize(start_size + 8);
208 net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 8);
209 big_endian_writer.WriteU8(0x80 + (report_block ? 1 : 0));
210 big_endian_writer.WriteU8(transport::kPacketTypeReceiverReport);
211 big_endian_writer.WriteU16(number_of_rows);
212 big_endian_writer.WriteU32(ssrc_);
215 AddReportBlocks(*report_block, packet); // Adds 24 bytes.
219 void RtcpSender::AddReportBlocks(const transport::RtcpReportBlock& report_block,
220 Packet* packet) const {
221 size_t start_size = packet->size();
222 DCHECK_LT(start_size + 24, kMaxIpPacketSize) << "Not enough buffer space";
223 if (start_size + 24 > kMaxIpPacketSize) return;
225 packet->resize(start_size + 24);
227 net::BigEndianWriter big_endian_writer(&((*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);
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);
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
241 big_endian_writer.WriteU32(report_block.last_sr);
243 // Delay since last received report, time since we received the report.
244 big_endian_writer.WriteU32(report_block.delay_since_last_sr);
247 void RtcpSender::BuildSdec(Packet* packet) const {
248 size_t start_size = packet->size();
249 DCHECK_LT(start_size + 12 + c_name_.length(), kMaxIpPacketSize)
250 << "Not enough buffer space";
251 if (start_size + 12 > kMaxIpPacketSize) return;
253 // SDES Source Description.
254 packet->resize(start_size + 10);
256 net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 10);
257 // We always need to add one SDES CNAME.
258 big_endian_writer.WriteU8(0x80 + 1);
259 big_endian_writer.WriteU8(transport::kPacketTypeSdes);
261 // Handle SDES length later on.
262 uint32 sdes_length_position = static_cast<uint32>(start_size) + 3;
263 big_endian_writer.WriteU16(0);
264 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
265 big_endian_writer.WriteU8(1); // CNAME = 1
266 big_endian_writer.WriteU8(static_cast<uint8>(c_name_.length()));
268 size_t sdes_length = 10 + c_name_.length();
269 packet->insert(packet->end(), c_name_.c_str(),
270 c_name_.c_str() + c_name_.length());
274 // We must have a zero field even if we have an even multiple of 4 bytes.
275 if ((packet->size() % 4) == 0) {
277 packet->push_back(0);
279 while ((packet->size() % 4) != 0) {
281 packet->push_back(0);
283 sdes_length += padding;
285 // In 32-bit words minus one and we don't count the header.
286 uint8 buffer_length = static_cast<uint8>((sdes_length / 4) - 1);
287 (*packet)[sdes_length_position] = buffer_length;
290 void RtcpSender::BuildPli(uint32 remote_ssrc,
291 Packet* packet) const {
292 size_t start_size = packet->size();
293 DCHECK_LT(start_size + 12, kMaxIpPacketSize) << "Not enough buffer space";
294 if (start_size + 12 > kMaxIpPacketSize) return;
296 packet->resize(start_size + 12);
298 net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 12);
299 uint8 FMT = 1; // Picture loss indicator.
300 big_endian_writer.WriteU8(0x80 + FMT);
301 big_endian_writer.WriteU8(transport::kPacketTypePayloadSpecific);
302 big_endian_writer.WriteU16(2); // Used fixed length of 2.
303 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
304 big_endian_writer.WriteU32(remote_ssrc); // Add the remote SSRC.
309 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
310 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
311 | PB |0| Payload Type| Native Rpsi bit string |
312 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
313 | defined per codec ... | Padding (0) |
314 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
316 void RtcpSender::BuildRpsi(const RtcpRpsiMessage* rpsi,
317 Packet* packet) const {
318 size_t start_size = packet->size();
319 DCHECK_LT(start_size + 24, kMaxIpPacketSize) << "Not enough buffer space";
320 if (start_size + 24 > kMaxIpPacketSize) return;
322 packet->resize(start_size + 24);
324 net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 24);
325 uint8 FMT = 3; // Reference Picture Selection Indication.
326 big_endian_writer.WriteU8(0x80 + FMT);
327 big_endian_writer.WriteU8(transport::kPacketTypePayloadSpecific);
330 uint32 bits_required = 7;
331 uint8 bytes_required = 1;
332 while ((rpsi->picture_id >> bits_required) > 0) {
337 if (bytes_required > 6) {
339 } else if (bytes_required > 2) {
342 big_endian_writer.WriteU8(0);
343 big_endian_writer.WriteU8(size);
344 big_endian_writer.WriteU32(ssrc_);
345 big_endian_writer.WriteU32(rpsi->remote_ssrc);
347 uint8 padding_bytes = 4 - ((2 + bytes_required) % 4);
348 if (padding_bytes == 4) {
351 // Add padding length in bits, padding can be 0, 8, 16 or 24.
352 big_endian_writer.WriteU8(padding_bytes * 8);
353 big_endian_writer.WriteU8(rpsi->payload_type);
356 for (int i = bytes_required - 1; i > 0; i--) {
357 big_endian_writer.WriteU8(
358 0x80 | static_cast<uint8>(rpsi->picture_id >> (i * 7)));
360 // Add last byte of picture ID.
361 big_endian_writer.WriteU8(static_cast<uint8>(rpsi->picture_id & 0x7f));
364 for (int j = 0; j < padding_bytes; ++j) {
365 big_endian_writer.WriteU8(0);
369 void RtcpSender::BuildRemb(const RtcpRembMessage* remb,
370 Packet* packet) const {
371 size_t start_size = packet->size();
372 size_t remb_size = 20 + 4 * remb->remb_ssrcs.size();
373 DCHECK_LT(start_size + remb_size, kMaxIpPacketSize)
374 << "Not enough buffer space";
375 if (start_size + remb_size > kMaxIpPacketSize) return;
377 packet->resize(start_size + remb_size);
379 net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), remb_size);
381 // Add application layer feedback.
383 big_endian_writer.WriteU8(0x80 + FMT);
384 big_endian_writer.WriteU8(transport::kPacketTypePayloadSpecific);
385 big_endian_writer.WriteU8(0);
386 big_endian_writer.WriteU8(static_cast<uint8>(remb->remb_ssrcs.size() + 4));
387 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
388 big_endian_writer.WriteU32(0); // Remote SSRC must be 0.
389 big_endian_writer.WriteU32(kRemb);
390 big_endian_writer.WriteU8(static_cast<uint8>(remb->remb_ssrcs.size()));
392 // 6 bit exponent and a 18 bit mantissa.
393 uint8 bitrate_exponent;
394 uint32 bitrate_mantissa;
395 BitrateToRembExponentBitrate(remb->remb_bitrate,
399 big_endian_writer.WriteU8(static_cast<uint8>((bitrate_exponent << 2) +
400 ((bitrate_mantissa >> 16) & 0x03)));
401 big_endian_writer.WriteU8(static_cast<uint8>(bitrate_mantissa >> 8));
402 big_endian_writer.WriteU8(static_cast<uint8>(bitrate_mantissa));
404 std::list<uint32>::const_iterator it = remb->remb_ssrcs.begin();
405 for (; it != remb->remb_ssrcs.end(); ++it) {
406 big_endian_writer.WriteU32(*it);
408 base::TimeTicks now = cast_environment_->Clock()->NowTicks();
409 cast_environment_->Logging()->InsertGenericEvent(now, kRembBitrate,
413 void RtcpSender::BuildNack(const RtcpNackMessage* nack,
414 Packet* packet) const {
415 size_t start_size = packet->size();
416 DCHECK_LT(start_size + 16, kMaxIpPacketSize) << "Not enough buffer space";
417 if (start_size + 16 > kMaxIpPacketSize) return;
419 packet->resize(start_size + 16);
421 net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 16);
424 big_endian_writer.WriteU8(0x80 + FMT);
425 big_endian_writer.WriteU8(transport::kPacketTypeGenericRtpFeedback);
426 big_endian_writer.WriteU8(0);
427 size_t nack_size_pos = start_size + 3;
428 big_endian_writer.WriteU8(3);
429 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
430 big_endian_writer.WriteU32(nack->remote_ssrc); // Add the remote SSRC.
432 // Build NACK bitmasks and write them to the Rtcp message.
433 // The nack list should be sorted and not contain duplicates.
434 size_t number_of_nack_fields = 0;
435 size_t max_number_of_nack_fields = std::min<size_t>(kRtcpMaxNackFields,
436 (kMaxIpPacketSize - packet->size()) / 4);
438 std::list<uint16>::const_iterator it = nack->nack_list.begin();
439 while (it != nack->nack_list.end() &&
440 number_of_nack_fields < max_number_of_nack_fields) {
441 uint16 nack_sequence_number = *it;
444 while (it != nack->nack_list.end()) {
445 int shift = static_cast<uint16>(*it - nack_sequence_number) - 1;
446 if (shift >= 0 && shift <= 15) {
447 bitmask |= (1 << shift);
453 // Write the sequence number and the bitmask to the packet.
454 start_size = packet->size();
455 DCHECK_LT(start_size + 4, kMaxIpPacketSize) << "Not enough buffer space";
456 if (start_size + 4 > kMaxIpPacketSize) return;
458 packet->resize(start_size + 4);
459 net::BigEndianWriter big_endian_nack_writer(&((*packet)[start_size]), 4);
460 big_endian_nack_writer.WriteU16(nack_sequence_number);
461 big_endian_nack_writer.WriteU16(bitmask);
462 number_of_nack_fields++;
464 DCHECK_GE(kRtcpMaxNackFields, number_of_nack_fields);
465 (*packet)[nack_size_pos] = static_cast<uint8>(2 + number_of_nack_fields);
468 void RtcpSender::BuildBye(Packet* packet) const {
469 size_t start_size = packet->size();
470 DCHECK_LT(start_size + 8, kMaxIpPacketSize) << "Not enough buffer space";
471 if (start_size + 8 > kMaxIpPacketSize) return;
473 packet->resize(start_size + 8);
475 net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 8);
476 big_endian_writer.WriteU8(0x80 + 1);
477 big_endian_writer.WriteU8(transport::kPacketTypeBye);
478 big_endian_writer.WriteU16(1); // Length.
479 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
482 void RtcpSender::BuildRrtr(const RtcpReceiverReferenceTimeReport* rrtr,
483 Packet* packet) const {
484 size_t start_size = packet->size();
485 DCHECK_LT(start_size + 20, kMaxIpPacketSize) << "Not enough buffer space";
486 if (start_size + 20 > kMaxIpPacketSize) return;
488 packet->resize(start_size + 20);
490 net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 20);
492 big_endian_writer.WriteU8(0x80);
493 big_endian_writer.WriteU8(transport::kPacketTypeXr);
494 big_endian_writer.WriteU16(4); // Length.
495 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
496 big_endian_writer.WriteU8(4); // Add block type.
497 big_endian_writer.WriteU8(0); // Add reserved.
498 big_endian_writer.WriteU16(2); // Block length.
500 // Add the media (received RTP) SSRC.
501 big_endian_writer.WriteU32(rrtr->ntp_seconds);
502 big_endian_writer.WriteU32(rrtr->ntp_fraction);
505 void RtcpSender::BuildCast(const RtcpCastMessage* cast,
506 Packet* packet) const {
507 size_t start_size = packet->size();
508 DCHECK_LT(start_size + 20, kMaxIpPacketSize) << "Not enough buffer space";
509 if (start_size + 20 > kMaxIpPacketSize) return;
511 packet->resize(start_size + 20);
513 net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 20);
514 uint8 FMT = 15; // Application layer feedback.
515 big_endian_writer.WriteU8(0x80 + FMT);
516 big_endian_writer.WriteU8(transport::kPacketTypePayloadSpecific);
517 big_endian_writer.WriteU8(0);
518 size_t cast_size_pos = start_size + 3; // Save length position.
519 big_endian_writer.WriteU8(4);
520 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
521 big_endian_writer.WriteU32(cast->media_ssrc_); // Remote SSRC.
522 big_endian_writer.WriteU32(kCast);
523 big_endian_writer.WriteU8(static_cast<uint8>(cast->ack_frame_id_));
524 size_t cast_loss_field_pos = start_size + 17; // Save loss field position.
525 big_endian_writer.WriteU8(0); // Overwritten with number_of_loss_fields.
526 big_endian_writer.WriteU8(0); // Reserved.
527 big_endian_writer.WriteU8(0); // Reserved.
529 size_t number_of_loss_fields = 0;
530 size_t max_number_of_loss_fields = std::min<size_t>(kRtcpMaxCastLossFields,
531 (kMaxIpPacketSize - packet->size()) / 4);
533 MissingFramesAndPacketsMap::const_iterator frame_it =
534 cast->missing_frames_and_packets_.begin();
536 for (; frame_it != cast->missing_frames_and_packets_.end() &&
537 number_of_loss_fields < max_number_of_loss_fields; ++frame_it) {
538 // Iterate through all frames with missing packets.
539 if (frame_it->second.empty()) {
540 // Special case all packets in a frame is missing.
541 start_size = packet->size();
542 packet->resize(start_size + 4);
543 net::BigEndianWriter big_endian_nack_writer(&((*packet)[start_size]), 4);
544 big_endian_nack_writer.WriteU8(static_cast<uint8>(frame_it->first));
545 big_endian_nack_writer.WriteU16(kRtcpCastAllPacketsLost);
546 big_endian_nack_writer.WriteU8(0);
547 ++number_of_loss_fields;
549 PacketIdSet::const_iterator packet_it = frame_it->second.begin();
550 while (packet_it != frame_it->second.end()) {
551 uint16 packet_id = *packet_it;
553 start_size = packet->size();
554 packet->resize(start_size + 4);
555 net::BigEndianWriter big_endian_nack_writer(
556 &((*packet)[start_size]), 4);
558 // Write frame and packet id to buffer before calculating bitmask.
559 big_endian_nack_writer.WriteU8(static_cast<uint8>(frame_it->first));
560 big_endian_nack_writer.WriteU16(packet_id);
564 while (packet_it != frame_it->second.end()) {
565 int shift = static_cast<uint8>(*packet_it - packet_id) - 1;
566 if (shift >= 0 && shift <= 7) {
567 bitmask |= (1 << shift);
573 big_endian_nack_writer.WriteU8(bitmask);
574 ++number_of_loss_fields;
578 DCHECK_LE(number_of_loss_fields, kRtcpMaxCastLossFields);
579 (*packet)[cast_size_pos] = static_cast<uint8>(4 + number_of_loss_fields);
580 (*packet)[cast_loss_field_pos] = static_cast<uint8>(number_of_loss_fields);
583 void RtcpSender::BuildReceiverLog(RtcpReceiverLogMessage* receiver_log_message,
584 Packet* packet) const {
585 DCHECK(receiver_log_message);
586 const size_t packet_start_size = packet->size();
587 size_t number_of_frames = 0;
588 size_t total_number_of_messages_to_send = 0;
589 size_t rtcp_log_size = 0;
591 if (!ScanRtcpReceiverLogMessage(*receiver_log_message,
594 &total_number_of_messages_to_send,
598 packet->resize(packet_start_size + rtcp_log_size);
600 net::BigEndianWriter big_endian_writer(&((*packet)[packet_start_size]),
602 big_endian_writer.WriteU8(0x80 + kReceiverLogSubtype);
603 big_endian_writer.WriteU8(transport::kPacketTypeApplicationDefined);
604 big_endian_writer.WriteU16(static_cast<uint16>(2 + 2 * number_of_frames +
605 total_number_of_messages_to_send));
606 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
607 big_endian_writer.WriteU32(kCast);
609 while (!receiver_log_message->empty() &&
610 total_number_of_messages_to_send > 0) {
611 RtcpReceiverFrameLogMessage& frame_log_messages =
612 receiver_log_message->front();
613 // Add our frame header.
614 big_endian_writer.WriteU32(frame_log_messages.rtp_timestamp_);
615 size_t messages_in_frame = frame_log_messages.event_log_messages_.size();
616 if (messages_in_frame > total_number_of_messages_to_send) {
617 // We are running out of space.
618 messages_in_frame = total_number_of_messages_to_send;
620 // Keep track of how many messages we have left to send.
621 total_number_of_messages_to_send -= messages_in_frame;
623 // On the wire format is number of messages - 1.
624 big_endian_writer.WriteU8(static_cast<uint8>(messages_in_frame - 1));
626 base::TimeTicks event_timestamp_base =
627 frame_log_messages.event_log_messages_.front().event_timestamp;
628 uint32 base_timestamp_ms =
629 (event_timestamp_base - base::TimeTicks()).InMilliseconds();
630 big_endian_writer.WriteU8(static_cast<uint8>(base_timestamp_ms >> 16));
631 big_endian_writer.WriteU8(static_cast<uint8>(base_timestamp_ms >> 8));
632 big_endian_writer.WriteU8(static_cast<uint8>(base_timestamp_ms));
634 while (!frame_log_messages.event_log_messages_.empty() &&
635 messages_in_frame > 0) {
636 const RtcpReceiverEventLogMessage& event_message =
637 frame_log_messages.event_log_messages_.front();
638 uint16 event_type_and_timestamp_delta =
639 MergeEventTypeAndTimestampForWireFormat(event_message.type,
640 event_message.event_timestamp - event_timestamp_base);
641 switch (event_message.type) {
644 case kAudioPlayoutDelay:
645 case kAudioFrameDecoded:
646 case kVideoFrameDecoded:
647 case kVideoRenderDelay:
648 big_endian_writer.WriteU16(static_cast<uint16>(
649 event_message.delay_delta.InMilliseconds()));
650 big_endian_writer.WriteU16(event_type_and_timestamp_delta);
652 case kAudioPacketReceived:
653 case kVideoPacketReceived:
654 case kDuplicatePacketReceived:
655 big_endian_writer.WriteU16(event_message.packet_id);
656 big_endian_writer.WriteU16(event_type_and_timestamp_delta);
662 frame_log_messages.event_log_messages_.pop_front();
664 if (frame_log_messages.event_log_messages_.empty()) {
665 // We sent all messages on this frame; pop the frame header.
666 receiver_log_message->pop_front();
669 DCHECK_EQ(total_number_of_messages_to_send, 0);