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