c56dcb9607c889ee4b9c2bc6345dcef119beb7a7
[platform/framework/web/crosswalk.git] / src / media / cast / rtcp / rtcp_sender.cc
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 <algorithm>
8 #include <vector>
9
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"
16
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;
21
22 namespace {
23
24 // Converts a log event type to an integer value.
25 int ConvertEventTypeToWireFormat(const media::cast::CastLoggingEvent& event) {
26   switch (event) {
27     case media::cast::kAudioAckSent:
28       return 1;
29     case media::cast::kAudioPlayoutDelay:
30       return 2;
31     case media::cast::kAudioFrameDecoded:
32       return 3;
33     case media::cast::kAudioPacketReceived:
34       return 4;
35     case media::cast::kVideoAckSent:
36       return 5;
37     case media::cast::kVideoFrameDecoded:
38       return 6;
39     case media::cast::kVideoRenderDelay:
40       return 7;
41     case media::cast::kVideoPacketReceived:
42       return 8;
43     case media::cast::kDuplicatePacketReceived:
44       return 9;
45     default:
46       return 0;  // Not an interesting event.
47   }
48 }
49
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);
56
57   uint16 event_type_and_timestamp_delta =
58       static_cast<uint16>(time_delta_ms & 0xfff);
59
60   uint16 event_type = ConvertEventTypeToWireFormat(event);
61   DCHECK(event_type);
62   DCHECK(!(event_type & 0xfff0));
63   return (event_type << 12) + event_type_and_timestamp_delta;
64 }
65
66 bool ScanRtcpReceiverLogMessage(
67     const media::cast::RtcpReceiverLogMessage& receiver_log_message,
68     size_t start_size,
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;
73
74   size_t remaining_space = media::cast::kMaxIpPacketSize - start_size;
75
76   // We must have space for at least one message
77   DCHECK_GE(remaining_space, kRtcpCastLogHeaderSize +
78       kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize)
79       << "Not enough buffer space";
80
81   if (remaining_space < kRtcpCastLogHeaderSize + kRtcpReceiverFrameLogSize +
82       kRtcpReceiverEventLogSize) {
83     return false;
84   }
85   // Account for the RTCP header for an application-defined packet.
86   remaining_space -= kRtcpCastLogHeaderSize;
87
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)++;
92
93     remaining_space -= kRtcpReceiverFrameLogSize;
94
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;
106       break;
107     }
108     remaining_space -= messages_to_send * kRtcpReceiverEventLogSize;
109     *total_number_of_messages_to_send += messages_to_send;
110
111     if (remaining_space <
112         kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize) {
113       // Make sure that we have room for at least one more message.
114       break;
115     }
116   }
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";
122
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;
126   return true;
127 }
128 }  // namespace
129
130 namespace media {
131 namespace cast {
132
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,
136                        uint32 sending_ssrc,
137                        const std::string& c_name)
138      : ssrc_(sending_ssrc),
139        c_name_(c_name),
140        transport_(outgoing_transport),
141        cast_environment_(cast_environment) {
142   DCHECK_LT(c_name_.length(), kRtcpCnameSize) << "Invalid config";
143 }
144
145 RtcpSender::~RtcpSender() {}
146
147 // static
148 bool RtcpSender::IsReceiverEvent(const media::cast::CastLoggingEvent& event) {
149   return ConvertEventTypeToWireFormat(event) != 0;
150 }
151
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";
162   }
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.
168     NOTIMPLEMENTED();
169   }
170   Packet packet;
171   packet.reserve(kMaxIpPacketSize);
172
173   if (packet_type_flags & kRtcpRr) {
174     BuildRR(report_block, &packet);
175     if (!c_name_.empty()) {
176       BuildSdec(&packet);
177     }
178   }
179   if (packet_type_flags & kRtcpBye) {
180     BuildBye(&packet);
181   }
182   if (packet_type_flags & kRtcpRrtr) {
183     DCHECK(rrtr) << "Invalid argument";
184     BuildRrtr(rrtr, &packet);
185   }
186   if (packet_type_flags & kRtcpCast) {
187     DCHECK(cast_message) << "Invalid argument";
188     BuildCast(cast_message, &packet);
189   }
190   if (packet_type_flags & kRtcpReceiverLog) {
191     DCHECK(receiver_log) << "Invalid argument";
192     BuildReceiverLog(receiver_log, &packet);
193   }
194   if (packet.empty()) return;  // Sanity don't send empty packets.
195
196   transport_->SendRtcpPacket(packet);
197 }
198
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;
204
205   uint16 number_of_rows = (report_block) ? 7 : 1;
206   packet->resize(start_size + 8);
207
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_);
213
214   if (report_block) {
215     AddReportBlocks(*report_block, packet);  // Adds 24 bytes.
216   }
217 }
218
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;
224
225   packet->resize(start_size + 24);
226
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);
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::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;
252
253   // SDES Source Description.
254   packet->resize(start_size + 10);
255
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);
260
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()));
267
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());
271
272   size_t padding = 0;
273
274   // We must have a zero field even if we have an even multiple of 4 bytes.
275   if ((packet->size() % 4) == 0) {
276     padding++;
277     packet->push_back(0);
278   }
279   while ((packet->size() % 4) != 0) {
280     padding++;
281     packet->push_back(0);
282   }
283   sdes_length += padding;
284
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;
288 }
289
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;
295
296   packet->resize(start_size + 12);
297
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.
305 }
306
307 /*
308     0                   1                   2                   3
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    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
315 */
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;
321
322   packet->resize(start_size + 24);
323
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);
328
329   // Calculate length.
330   uint32 bits_required = 7;
331   uint8 bytes_required = 1;
332   while ((rpsi->picture_id >> bits_required) > 0) {
333     bits_required += 7;
334     bytes_required++;
335   }
336   uint8 size = 3;
337   if (bytes_required > 6) {
338     size = 5;
339   } else if (bytes_required > 2) {
340     size = 4;
341   }
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);
346
347   uint8 padding_bytes = 4 - ((2 + bytes_required) % 4);
348   if (padding_bytes == 4) {
349     padding_bytes = 0;
350   }
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);
354
355   // Add picture ID.
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)));
359   }
360   // Add last byte of picture ID.
361   big_endian_writer.WriteU8(static_cast<uint8>(rpsi->picture_id & 0x7f));
362
363   // Add padding.
364   for (int j = 0; j < padding_bytes; ++j) {
365     big_endian_writer.WriteU8(0);
366   }
367 }
368
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;
376
377   packet->resize(start_size + remb_size);
378
379   net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), remb_size);
380
381   // Add application layer feedback.
382   uint8 FMT = 15;
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()));
391
392   // 6 bit exponent and a 18 bit mantissa.
393   uint8 bitrate_exponent;
394   uint32 bitrate_mantissa;
395   BitrateToRembExponentBitrate(remb->remb_bitrate,
396                                &bitrate_exponent,
397                                &bitrate_mantissa);
398
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));
403
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);
407   }
408   base::TimeTicks now = cast_environment_->Clock()->NowTicks();
409   cast_environment_->Logging()->InsertGenericEvent(now, kRembBitrate,
410                                                    remb->remb_bitrate);
411 }
412
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;
418
419   packet->resize(start_size + 16);
420
421   net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 16);
422
423   uint8 FMT = 1;
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.
431
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);
437
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;
442     uint16 bitmask = 0;
443     ++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);
448         ++it;
449       } else {
450         break;
451       }
452     }
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;
457
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++;
463   }
464   DCHECK_GE(kRtcpMaxNackFields, number_of_nack_fields);
465   (*packet)[nack_size_pos] = static_cast<uint8>(2 + number_of_nack_fields);
466 }
467
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;
472
473   packet->resize(start_size + 8);
474
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.
480 }
481
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;
487
488   packet->resize(start_size + 20);
489
490   net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 20);
491
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.
499
500   // Add the media (received RTP) SSRC.
501   big_endian_writer.WriteU32(rrtr->ntp_seconds);
502   big_endian_writer.WriteU32(rrtr->ntp_fraction);
503 }
504
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;
510
511   packet->resize(start_size + 20);
512
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.
528
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);
532
533   MissingFramesAndPacketsMap::const_iterator frame_it =
534       cast->missing_frames_and_packets_.begin();
535
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;
548     } else {
549       PacketIdSet::const_iterator packet_it = frame_it->second.begin();
550       while (packet_it != frame_it->second.end()) {
551         uint16 packet_id = *packet_it;
552
553         start_size = packet->size();
554         packet->resize(start_size + 4);
555         net::BigEndianWriter big_endian_nack_writer(
556             &((*packet)[start_size]), 4);
557
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);
561
562         uint8 bitmask = 0;
563         ++packet_it;
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);
568             ++packet_it;
569           } else {
570             break;
571           }
572         }
573         big_endian_nack_writer.WriteU8(bitmask);
574         ++number_of_loss_fields;
575       }
576     }
577   }
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);
581 }
582
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;
590
591   if (!ScanRtcpReceiverLogMessage(*receiver_log_message,
592                                   packet_start_size,
593                                   &number_of_frames,
594                                   &total_number_of_messages_to_send,
595                                   &rtcp_log_size)) {
596     return;
597   }
598   packet->resize(packet_start_size + rtcp_log_size);
599
600   net::BigEndianWriter big_endian_writer(&((*packet)[packet_start_size]),
601                                          rtcp_log_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);
608
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;
619     }
620     // Keep track of how many messages we have left to send.
621     total_number_of_messages_to_send -= messages_in_frame;
622
623     // On the wire format is number of messages - 1.
624     big_endian_writer.WriteU8(static_cast<uint8>(messages_in_frame - 1));
625
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));
633
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) {
642         case kAudioAckSent:
643         case kVideoAckSent:
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);
651           break;
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);
657           break;
658         default:
659           NOTREACHED();
660       }
661       messages_in_frame--;
662       frame_log_messages.event_log_messages_.pop_front();
663     }
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();
667     }
668   }
669   DCHECK_EQ(total_number_of_messages_to_send, 0);
670 }
671
672 }  // namespace cast
673 }  // namespace media