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/receiver_rtcp_event_subscriber.h"
13 #include "media/cast/rtcp/rtcp_defines.h"
14 #include "media/cast/rtcp/rtcp_utility.h"
15 #include "media/cast/transport/cast_transport_defines.h"
16 #include "media/cast/transport/pacing/paced_sender.h"
17 #include "net/base/big_endian.h"
21 using media::cast::kRtcpCastLogHeaderSize
;
22 using media::cast::kRtcpSenderFrameLogSize
;
23 using media::cast::kRtcpReceiverFrameLogSize
;
24 using media::cast::kRtcpReceiverEventLogSize
;
26 // Converts a log event type to an integer value.
27 int ConvertEventTypeToWireFormat(const media::cast::CastLoggingEvent
& event
) {
29 case media::cast::kAudioAckSent
:
31 case media::cast::kAudioPlayoutDelay
:
33 case media::cast::kAudioFrameDecoded
:
35 case media::cast::kAudioPacketReceived
:
37 case media::cast::kVideoAckSent
:
39 case media::cast::kVideoFrameDecoded
:
41 case media::cast::kVideoRenderDelay
:
43 case media::cast::kVideoPacketReceived
:
45 case media::cast::kDuplicateAudioPacketReceived
:
47 case media::cast::kDuplicateVideoPacketReceived
:
50 return 0; // Not an interesting event.
54 uint16
MergeEventTypeAndTimestampForWireFormat(
55 const media::cast::CastLoggingEvent
& event
,
56 const base::TimeDelta
& time_delta
) {
57 int64 time_delta_ms
= time_delta
.InMilliseconds();
58 // Max delta is 4096 milliseconds.
59 DCHECK_GE(GG_INT64_C(0xfff), time_delta_ms
);
61 uint16 event_type_and_timestamp_delta
=
62 static_cast<uint16
>(time_delta_ms
& 0xfff);
64 uint16 event_type
= ConvertEventTypeToWireFormat(event
);
66 DCHECK(!(event_type
& 0xfff0));
67 return (event_type
<< 12) + event_type_and_timestamp_delta
;
70 bool ScanRtcpReceiverLogMessage(
71 const media::cast::RtcpReceiverLogMessage
& receiver_log_message
,
72 size_t start_size
, size_t* number_of_frames
,
73 size_t* total_number_of_messages_to_send
, size_t* rtcp_log_size
) {
74 if (receiver_log_message
.empty()) return false;
76 size_t remaining_space
= media::cast::kMaxIpPacketSize
- start_size
;
78 // We must have space for at least one message
79 DCHECK_GE(remaining_space
, kRtcpCastLogHeaderSize
+
80 kRtcpReceiverFrameLogSize
+
81 kRtcpReceiverEventLogSize
)
82 << "Not enough buffer space";
84 if (remaining_space
< kRtcpCastLogHeaderSize
+ kRtcpReceiverFrameLogSize
+
85 kRtcpReceiverEventLogSize
) {
88 // Account for the RTCP header for an application-defined packet.
89 remaining_space
-= kRtcpCastLogHeaderSize
;
91 media::cast::RtcpReceiverLogMessage::const_iterator frame_it
=
92 receiver_log_message
.begin();
93 for (; frame_it
!= receiver_log_message
.end(); ++frame_it
) {
94 (*number_of_frames
)++;
96 remaining_space
-= kRtcpReceiverFrameLogSize
;
98 size_t messages_in_frame
= frame_it
->event_log_messages_
.size();
99 size_t remaining_space_in_messages
=
100 remaining_space
/ kRtcpReceiverEventLogSize
;
101 size_t messages_to_send
=
102 std::min(messages_in_frame
, remaining_space_in_messages
);
103 if (messages_to_send
> media::cast::kRtcpMaxReceiverLogMessages
) {
104 // We can't send more than 256 messages.
106 media::cast::kRtcpMaxReceiverLogMessages
* kRtcpReceiverEventLogSize
;
107 *total_number_of_messages_to_send
+=
108 media::cast::kRtcpMaxReceiverLogMessages
;
111 remaining_space
-= messages_to_send
* kRtcpReceiverEventLogSize
;
112 *total_number_of_messages_to_send
+= messages_to_send
;
114 if (remaining_space
<
115 kRtcpReceiverFrameLogSize
+ kRtcpReceiverEventLogSize
) {
116 // Make sure that we have room for at least one more message.
121 kRtcpCastLogHeaderSize
+ *number_of_frames
* kRtcpReceiverFrameLogSize
+
122 *total_number_of_messages_to_send
* kRtcpReceiverEventLogSize
;
123 DCHECK_GE(media::cast::kMaxIpPacketSize
, start_size
+ *rtcp_log_size
)
124 << "Not enough buffer space";
126 VLOG(1) << "number of frames " << *number_of_frames
;
127 VLOG(1) << "total messages to send " << *total_number_of_messages_to_send
;
128 VLOG(1) << "rtcp log size " << *rtcp_log_size
;
136 // TODO(mikhal): This is only used by the receiver. Consider renaming.
137 RtcpSender::RtcpSender(scoped_refptr
<CastEnvironment
> cast_environment
,
138 transport::PacedPacketSender
* outgoing_transport
,
139 uint32 sending_ssrc
, const std::string
& c_name
)
140 : ssrc_(sending_ssrc
),
142 transport_(outgoing_transport
),
143 cast_environment_(cast_environment
) {
144 DCHECK_LT(c_name_
.length(), kRtcpCnameSize
) << "Invalid config";
147 RtcpSender::~RtcpSender() {}
150 bool RtcpSender::IsReceiverEvent(const media::cast::CastLoggingEvent
& event
) {
151 return ConvertEventTypeToWireFormat(event
) != 0;
154 void RtcpSender::SendRtcpFromRtpReceiver(
155 uint32 packet_type_flags
,
156 const transport::RtcpReportBlock
* report_block
,
157 const RtcpReceiverReferenceTimeReport
* rrtr
,
158 const RtcpCastMessage
* cast_message
,
159 ReceiverRtcpEventSubscriber
* event_subscriber
) {
160 if (packet_type_flags
& kRtcpSr
|| packet_type_flags
& kRtcpDlrr
||
161 packet_type_flags
& kRtcpSenderLog
) {
162 NOTREACHED() << "Invalid argument";
164 if (packet_type_flags
& kRtcpPli
|| packet_type_flags
& kRtcpRpsi
||
165 packet_type_flags
& kRtcpRemb
|| packet_type_flags
& kRtcpNack
) {
166 // Implement these for webrtc interop.
170 packet
.reserve(kMaxIpPacketSize
);
172 if (packet_type_flags
& kRtcpRr
) {
173 BuildRR(report_block
, &packet
);
174 if (!c_name_
.empty()) {
178 if (packet_type_flags
& kRtcpBye
) {
181 if (packet_type_flags
& kRtcpRrtr
) {
182 DCHECK(rrtr
) << "Invalid argument";
183 BuildRrtr(rrtr
, &packet
);
185 if (packet_type_flags
& kRtcpCast
) {
186 DCHECK(cast_message
) << "Invalid argument";
187 BuildCast(cast_message
, &packet
);
189 if (packet_type_flags
& kRtcpReceiverLog
) {
190 DCHECK(event_subscriber
) << "Invalid argument";
191 RtcpReceiverLogMessage receiver_log
;
192 event_subscriber
->GetReceiverLogMessageAndReset(&receiver_log
);
193 BuildReceiverLog(&receiver_log
, &packet
);
195 if (packet
.empty()) return; // Sanity don't send empty packets.
197 transport_
->SendRtcpPacket(packet
);
200 void RtcpSender::BuildRR(const transport::RtcpReportBlock
* report_block
,
201 Packet
* packet
) const {
202 size_t start_size
= packet
->size();
203 DCHECK_LT(start_size
+ 32, kMaxIpPacketSize
) << "Not enough buffer space";
204 if (start_size
+ 32 > kMaxIpPacketSize
) return;
206 uint16 number_of_rows
= (report_block
) ? 7 : 1;
207 packet
->resize(start_size
+ 8);
209 net::BigEndianWriter
big_endian_writer(&((*packet
)[start_size
]), 8);
210 big_endian_writer
.WriteU8(0x80 + (report_block
? 1 : 0));
211 big_endian_writer
.WriteU8(transport::kPacketTypeReceiverReport
);
212 big_endian_writer
.WriteU16(number_of_rows
);
213 big_endian_writer
.WriteU32(ssrc_
);
216 AddReportBlocks(*report_block
, packet
); // Adds 24 bytes.
220 void RtcpSender::AddReportBlocks(const transport::RtcpReportBlock
& report_block
,
221 Packet
* packet
) const {
222 size_t start_size
= packet
->size();
223 DCHECK_LT(start_size
+ 24, kMaxIpPacketSize
) << "Not enough buffer space";
224 if (start_size
+ 24 > kMaxIpPacketSize
) return;
226 packet
->resize(start_size
+ 24);
228 net::BigEndianWriter
big_endian_writer(&((*packet
)[start_size
]), 24);
229 big_endian_writer
.WriteU32(report_block
.media_ssrc
);
230 big_endian_writer
.WriteU8(report_block
.fraction_lost
);
231 big_endian_writer
.WriteU8(report_block
.cumulative_lost
>> 16);
232 big_endian_writer
.WriteU8(report_block
.cumulative_lost
>> 8);
233 big_endian_writer
.WriteU8(report_block
.cumulative_lost
);
235 // Extended highest seq_no, contain the highest sequence number received.
236 big_endian_writer
.WriteU32(report_block
.extended_high_sequence_number
);
237 big_endian_writer
.WriteU32(report_block
.jitter
);
239 // Last SR timestamp; our NTP time when we received the last report.
240 // This is the value that we read from the send report packet not when we
242 big_endian_writer
.WriteU32(report_block
.last_sr
);
244 // Delay since last received report, time since we received the report.
245 big_endian_writer
.WriteU32(report_block
.delay_since_last_sr
);
248 void RtcpSender::BuildSdec(Packet
* packet
) const {
249 size_t start_size
= packet
->size();
250 DCHECK_LT(start_size
+ 12 + c_name_
.length(), kMaxIpPacketSize
)
251 << "Not enough buffer space";
252 if (start_size
+ 12 > kMaxIpPacketSize
) return;
254 // SDES Source Description.
255 packet
->resize(start_size
+ 10);
257 net::BigEndianWriter
big_endian_writer(&((*packet
)[start_size
]), 10);
258 // We always need to add one SDES CNAME.
259 big_endian_writer
.WriteU8(0x80 + 1);
260 big_endian_writer
.WriteU8(transport::kPacketTypeSdes
);
262 // Handle SDES length later on.
263 uint32 sdes_length_position
= static_cast<uint32
>(start_size
) + 3;
264 big_endian_writer
.WriteU16(0);
265 big_endian_writer
.WriteU32(ssrc_
); // Add our own SSRC.
266 big_endian_writer
.WriteU8(1); // CNAME = 1
267 big_endian_writer
.WriteU8(static_cast<uint8
>(c_name_
.length()));
269 size_t sdes_length
= 10 + c_name_
.length();
270 packet
->insert(packet
->end(), c_name_
.c_str(),
271 c_name_
.c_str() + c_name_
.length());
275 // We must have a zero field even if we have an even multiple of 4 bytes.
276 if ((packet
->size() % 4) == 0) {
278 packet
->push_back(0);
280 while ((packet
->size() % 4) != 0) {
282 packet
->push_back(0);
284 sdes_length
+= padding
;
286 // In 32-bit words minus one and we don't count the header.
287 uint8 buffer_length
= static_cast<uint8
>((sdes_length
/ 4) - 1);
288 (*packet
)[sdes_length_position
] = buffer_length
;
291 void RtcpSender::BuildPli(uint32 remote_ssrc
, 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
, Packet
* packet
) const {
317 size_t start_size
= packet
->size();
318 DCHECK_LT(start_size
+ 24, kMaxIpPacketSize
) << "Not enough buffer space";
319 if (start_size
+ 24 > kMaxIpPacketSize
) return;
321 packet
->resize(start_size
+ 24);
323 net::BigEndianWriter
big_endian_writer(&((*packet
)[start_size
]), 24);
324 uint8 FMT
= 3; // Reference Picture Selection Indication.
325 big_endian_writer
.WriteU8(0x80 + FMT
);
326 big_endian_writer
.WriteU8(transport::kPacketTypePayloadSpecific
);
329 uint32 bits_required
= 7;
330 uint8 bytes_required
= 1;
331 while ((rpsi
->picture_id
>> bits_required
) > 0) {
336 if (bytes_required
> 6) {
338 } else if (bytes_required
> 2) {
341 big_endian_writer
.WriteU8(0);
342 big_endian_writer
.WriteU8(size
);
343 big_endian_writer
.WriteU32(ssrc_
);
344 big_endian_writer
.WriteU32(rpsi
->remote_ssrc
);
346 uint8 padding_bytes
= 4 - ((2 + bytes_required
) % 4);
347 if (padding_bytes
== 4) {
350 // Add padding length in bits, padding can be 0, 8, 16 or 24.
351 big_endian_writer
.WriteU8(padding_bytes
* 8);
352 big_endian_writer
.WriteU8(rpsi
->payload_type
);
355 for (int i
= bytes_required
- 1; i
> 0; i
--) {
356 big_endian_writer
.WriteU8(0x80 |
357 static_cast<uint8
>(rpsi
->picture_id
>> (i
* 7)));
359 // Add last byte of picture ID.
360 big_endian_writer
.WriteU8(static_cast<uint8
>(rpsi
->picture_id
& 0x7f));
363 for (int j
= 0; j
< padding_bytes
; ++j
) {
364 big_endian_writer
.WriteU8(0);
368 void RtcpSender::BuildRemb(const RtcpRembMessage
* remb
, Packet
* packet
) const {
369 size_t start_size
= packet
->size();
370 size_t remb_size
= 20 + 4 * remb
->remb_ssrcs
.size();
371 DCHECK_LT(start_size
+ remb_size
, kMaxIpPacketSize
)
372 << "Not enough buffer space";
373 if (start_size
+ remb_size
> kMaxIpPacketSize
) return;
375 packet
->resize(start_size
+ remb_size
);
377 net::BigEndianWriter
big_endian_writer(&((*packet
)[start_size
]), remb_size
);
379 // Add application layer feedback.
381 big_endian_writer
.WriteU8(0x80 + FMT
);
382 big_endian_writer
.WriteU8(transport::kPacketTypePayloadSpecific
);
383 big_endian_writer
.WriteU8(0);
384 big_endian_writer
.WriteU8(static_cast<uint8
>(remb
->remb_ssrcs
.size() + 4));
385 big_endian_writer
.WriteU32(ssrc_
); // Add our own SSRC.
386 big_endian_writer
.WriteU32(0); // Remote SSRC must be 0.
387 big_endian_writer
.WriteU32(kRemb
);
388 big_endian_writer
.WriteU8(static_cast<uint8
>(remb
->remb_ssrcs
.size()));
390 // 6 bit exponent and a 18 bit mantissa.
391 uint8 bitrate_exponent
;
392 uint32 bitrate_mantissa
;
393 BitrateToRembExponentBitrate(remb
->remb_bitrate
, &bitrate_exponent
,
396 big_endian_writer
.WriteU8(static_cast<uint8
>(
397 (bitrate_exponent
<< 2) + ((bitrate_mantissa
>> 16) & 0x03)));
398 big_endian_writer
.WriteU8(static_cast<uint8
>(bitrate_mantissa
>> 8));
399 big_endian_writer
.WriteU8(static_cast<uint8
>(bitrate_mantissa
));
401 std::list
<uint32
>::const_iterator it
= remb
->remb_ssrcs
.begin();
402 for (; it
!= remb
->remb_ssrcs
.end(); ++it
) {
403 big_endian_writer
.WriteU32(*it
);
405 base::TimeTicks now
= cast_environment_
->Clock()->NowTicks();
406 cast_environment_
->Logging()->InsertGenericEvent(now
, kRembBitrate
,
410 void RtcpSender::BuildNack(const RtcpNackMessage
* nack
, Packet
* packet
) const {
411 size_t start_size
= packet
->size();
412 DCHECK_LT(start_size
+ 16, kMaxIpPacketSize
) << "Not enough buffer space";
413 if (start_size
+ 16 > kMaxIpPacketSize
) return;
415 packet
->resize(start_size
+ 16);
417 net::BigEndianWriter
big_endian_writer(&((*packet
)[start_size
]), 16);
420 big_endian_writer
.WriteU8(0x80 + FMT
);
421 big_endian_writer
.WriteU8(transport::kPacketTypeGenericRtpFeedback
);
422 big_endian_writer
.WriteU8(0);
423 size_t nack_size_pos
= start_size
+ 3;
424 big_endian_writer
.WriteU8(3);
425 big_endian_writer
.WriteU32(ssrc_
); // Add our own SSRC.
426 big_endian_writer
.WriteU32(nack
->remote_ssrc
); // Add the remote SSRC.
428 // Build NACK bitmasks and write them to the Rtcp message.
429 // The nack list should be sorted and not contain duplicates.
430 size_t number_of_nack_fields
= 0;
431 size_t max_number_of_nack_fields
= std::min
<size_t>(
432 kRtcpMaxNackFields
, (kMaxIpPacketSize
- packet
->size()) / 4);
434 std::list
<uint16
>::const_iterator it
= nack
->nack_list
.begin();
435 while (it
!= nack
->nack_list
.end() &&
436 number_of_nack_fields
< max_number_of_nack_fields
) {
437 uint16 nack_sequence_number
= *it
;
440 while (it
!= nack
->nack_list
.end()) {
441 int shift
= static_cast<uint16
>(*it
- nack_sequence_number
) - 1;
442 if (shift
>= 0 && shift
<= 15) {
443 bitmask
|= (1 << shift
);
449 // Write the sequence number and the bitmask to the packet.
450 start_size
= packet
->size();
451 DCHECK_LT(start_size
+ 4, kMaxIpPacketSize
) << "Not enough buffer space";
452 if (start_size
+ 4 > kMaxIpPacketSize
) return;
454 packet
->resize(start_size
+ 4);
455 net::BigEndianWriter
big_endian_nack_writer(&((*packet
)[start_size
]), 4);
456 big_endian_nack_writer
.WriteU16(nack_sequence_number
);
457 big_endian_nack_writer
.WriteU16(bitmask
);
458 number_of_nack_fields
++;
460 DCHECK_GE(kRtcpMaxNackFields
, number_of_nack_fields
);
461 (*packet
)[nack_size_pos
] = static_cast<uint8
>(2 + number_of_nack_fields
);
464 void RtcpSender::BuildBye(Packet
* packet
) const {
465 size_t start_size
= packet
->size();
466 DCHECK_LT(start_size
+ 8, kMaxIpPacketSize
) << "Not enough buffer space";
467 if (start_size
+ 8 > kMaxIpPacketSize
) return;
469 packet
->resize(start_size
+ 8);
471 net::BigEndianWriter
big_endian_writer(&((*packet
)[start_size
]), 8);
472 big_endian_writer
.WriteU8(0x80 + 1);
473 big_endian_writer
.WriteU8(transport::kPacketTypeBye
);
474 big_endian_writer
.WriteU16(1); // Length.
475 big_endian_writer
.WriteU32(ssrc_
); // Add our own SSRC.
478 void RtcpSender::BuildRrtr(const RtcpReceiverReferenceTimeReport
* rrtr
,
479 Packet
* packet
) const {
480 size_t start_size
= packet
->size();
481 DCHECK_LT(start_size
+ 20, kMaxIpPacketSize
) << "Not enough buffer space";
482 if (start_size
+ 20 > kMaxIpPacketSize
) return;
484 packet
->resize(start_size
+ 20);
486 net::BigEndianWriter
big_endian_writer(&((*packet
)[start_size
]), 20);
488 big_endian_writer
.WriteU8(0x80);
489 big_endian_writer
.WriteU8(transport::kPacketTypeXr
);
490 big_endian_writer
.WriteU16(4); // Length.
491 big_endian_writer
.WriteU32(ssrc_
); // Add our own SSRC.
492 big_endian_writer
.WriteU8(4); // Add block type.
493 big_endian_writer
.WriteU8(0); // Add reserved.
494 big_endian_writer
.WriteU16(2); // Block length.
496 // Add the media (received RTP) SSRC.
497 big_endian_writer
.WriteU32(rrtr
->ntp_seconds
);
498 big_endian_writer
.WriteU32(rrtr
->ntp_fraction
);
501 void RtcpSender::BuildCast(const RtcpCastMessage
* cast
, Packet
* packet
) const {
502 size_t start_size
= packet
->size();
503 DCHECK_LT(start_size
+ 20, kMaxIpPacketSize
) << "Not enough buffer space";
504 if (start_size
+ 20 > kMaxIpPacketSize
) return;
506 packet
->resize(start_size
+ 20);
508 net::BigEndianWriter
big_endian_writer(&((*packet
)[start_size
]), 20);
509 uint8 FMT
= 15; // Application layer feedback.
510 big_endian_writer
.WriteU8(0x80 + FMT
);
511 big_endian_writer
.WriteU8(transport::kPacketTypePayloadSpecific
);
512 big_endian_writer
.WriteU8(0);
513 size_t cast_size_pos
= start_size
+ 3; // Save length position.
514 big_endian_writer
.WriteU8(4);
515 big_endian_writer
.WriteU32(ssrc_
); // Add our own SSRC.
516 big_endian_writer
.WriteU32(cast
->media_ssrc_
); // Remote SSRC.
517 big_endian_writer
.WriteU32(kCast
);
518 big_endian_writer
.WriteU8(static_cast<uint8
>(cast
->ack_frame_id_
));
519 size_t cast_loss_field_pos
= start_size
+ 17; // Save loss field position.
520 big_endian_writer
.WriteU8(0); // Overwritten with number_of_loss_fields.
521 big_endian_writer
.WriteU8(0); // Reserved.
522 big_endian_writer
.WriteU8(0); // Reserved.
524 size_t number_of_loss_fields
= 0;
525 size_t max_number_of_loss_fields
= std::min
<size_t>(
526 kRtcpMaxCastLossFields
, (kMaxIpPacketSize
- packet
->size()) / 4);
528 MissingFramesAndPacketsMap::const_iterator frame_it
=
529 cast
->missing_frames_and_packets_
.begin();
531 for (; frame_it
!= cast
->missing_frames_and_packets_
.end() &&
532 number_of_loss_fields
< max_number_of_loss_fields
;
534 // Iterate through all frames with missing packets.
535 if (frame_it
->second
.empty()) {
536 // Special case all packets in a frame is missing.
537 start_size
= packet
->size();
538 packet
->resize(start_size
+ 4);
539 net::BigEndianWriter
big_endian_nack_writer(&((*packet
)[start_size
]), 4);
540 big_endian_nack_writer
.WriteU8(static_cast<uint8
>(frame_it
->first
));
541 big_endian_nack_writer
.WriteU16(kRtcpCastAllPacketsLost
);
542 big_endian_nack_writer
.WriteU8(0);
543 ++number_of_loss_fields
;
545 PacketIdSet::const_iterator packet_it
= frame_it
->second
.begin();
546 while (packet_it
!= frame_it
->second
.end()) {
547 uint16 packet_id
= *packet_it
;
549 start_size
= packet
->size();
550 packet
->resize(start_size
+ 4);
551 net::BigEndianWriter
big_endian_nack_writer(&((*packet
)[start_size
]),
554 // Write frame and packet id to buffer before calculating bitmask.
555 big_endian_nack_writer
.WriteU8(static_cast<uint8
>(frame_it
->first
));
556 big_endian_nack_writer
.WriteU16(packet_id
);
560 while (packet_it
!= frame_it
->second
.end()) {
561 int shift
= static_cast<uint8
>(*packet_it
- packet_id
) - 1;
562 if (shift
>= 0 && shift
<= 7) {
563 bitmask
|= (1 << shift
);
569 big_endian_nack_writer
.WriteU8(bitmask
);
570 ++number_of_loss_fields
;
574 DCHECK_LE(number_of_loss_fields
, kRtcpMaxCastLossFields
);
575 (*packet
)[cast_size_pos
] = static_cast<uint8
>(4 + number_of_loss_fields
);
576 (*packet
)[cast_loss_field_pos
] = static_cast<uint8
>(number_of_loss_fields
);
579 void RtcpSender::BuildReceiverLog(RtcpReceiverLogMessage
* receiver_log_message
,
580 Packet
* packet
) const {
581 DCHECK(receiver_log_message
);
582 const size_t packet_start_size
= packet
->size();
583 size_t number_of_frames
= 0;
584 size_t total_number_of_messages_to_send
= 0;
585 size_t rtcp_log_size
= 0;
587 if (!ScanRtcpReceiverLogMessage(
588 *receiver_log_message
, packet_start_size
, &number_of_frames
,
589 &total_number_of_messages_to_send
, &rtcp_log_size
)) {
592 packet
->resize(packet_start_size
+ rtcp_log_size
);
594 net::BigEndianWriter
big_endian_writer(&((*packet
)[packet_start_size
]),
596 big_endian_writer
.WriteU8(0x80 + kReceiverLogSubtype
);
597 big_endian_writer
.WriteU8(transport::kPacketTypeApplicationDefined
);
598 big_endian_writer
.WriteU16(static_cast<uint16
>(
599 2 + 2 * number_of_frames
+ total_number_of_messages_to_send
));
600 big_endian_writer
.WriteU32(ssrc_
); // Add our own SSRC.
601 big_endian_writer
.WriteU32(kCast
);
603 while (!receiver_log_message
->empty() &&
604 total_number_of_messages_to_send
> 0) {
605 RtcpReceiverFrameLogMessage
& frame_log_messages(
606 receiver_log_message
->front());
608 // Add our frame header.
609 big_endian_writer
.WriteU32(frame_log_messages
.rtp_timestamp_
);
610 size_t messages_in_frame
= frame_log_messages
.event_log_messages_
.size();
611 if (messages_in_frame
> total_number_of_messages_to_send
) {
612 // We are running out of space.
613 messages_in_frame
= total_number_of_messages_to_send
;
615 // Keep track of how many messages we have left to send.
616 total_number_of_messages_to_send
-= messages_in_frame
;
618 // On the wire format is number of messages - 1.
619 big_endian_writer
.WriteU8(static_cast<uint8
>(messages_in_frame
- 1));
621 base::TimeTicks event_timestamp_base
=
622 frame_log_messages
.event_log_messages_
.front().event_timestamp
;
623 uint32 base_timestamp_ms
=
624 (event_timestamp_base
- base::TimeTicks()).InMilliseconds();
625 big_endian_writer
.WriteU8(static_cast<uint8
>(base_timestamp_ms
>> 16));
626 big_endian_writer
.WriteU8(static_cast<uint8
>(base_timestamp_ms
>> 8));
627 big_endian_writer
.WriteU8(static_cast<uint8
>(base_timestamp_ms
));
629 while (!frame_log_messages
.event_log_messages_
.empty() &&
630 messages_in_frame
> 0) {
631 const RtcpReceiverEventLogMessage
& event_message
=
632 frame_log_messages
.event_log_messages_
.front();
633 uint16 event_type_and_timestamp_delta
=
634 MergeEventTypeAndTimestampForWireFormat(
636 event_message
.event_timestamp
- event_timestamp_base
);
637 switch (event_message
.type
) {
640 case kAudioPlayoutDelay
:
641 case kAudioFrameDecoded
:
642 case kVideoFrameDecoded
:
643 case kVideoRenderDelay
:
644 big_endian_writer
.WriteU16(
645 static_cast<uint16
>(event_message
.delay_delta
.InMilliseconds()));
646 big_endian_writer
.WriteU16(event_type_and_timestamp_delta
);
648 case kAudioPacketReceived
:
649 case kVideoPacketReceived
:
650 case kDuplicateAudioPacketReceived
:
651 case kDuplicateVideoPacketReceived
:
652 big_endian_writer
.WriteU16(event_message
.packet_id
);
653 big_endian_writer
.WriteU16(event_type_and_timestamp_delta
);
659 frame_log_messages
.event_log_messages_
.pop_front();
661 if (frame_log_messages
.event_log_messages_
.empty()) {
662 // We sent all messages on this frame; pop the frame header.
663 receiver_log_message
->pop_front();
666 DCHECK_EQ(total_number_of_messages_to_send
, 0);