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