OLD | NEW |
| (Empty) |
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 <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/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" | |
19 | |
20 namespace media { | |
21 namespace cast { | |
22 namespace { | |
23 | |
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); | |
27 | |
28 uint16 MergeEventTypeAndTimestampForWireFormat( | |
29 const CastLoggingEvent& event, | |
30 const base::TimeDelta& time_delta) { | |
31 int64 time_delta_ms = time_delta.InMilliseconds(); | |
32 | |
33 DCHECK_GE(time_delta_ms, 0); | |
34 DCHECK_LE(time_delta_ms, kMaxWireFormatTimeDeltaMs); | |
35 | |
36 uint16 time_delta_12_bits = | |
37 static_cast<uint16>(time_delta_ms & kMaxWireFormatTimeDeltaMs); | |
38 | |
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; | |
43 } | |
44 | |
45 bool EventTimestampLessThan(const RtcpReceiverEventLogMessage& lhs, | |
46 const RtcpReceiverEventLogMessage& rhs) { | |
47 return lhs.event_timestamp < rhs.event_timestamp; | |
48 } | |
49 | |
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); | |
68 | |
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; | |
74 } | |
75 } | |
76 | |
77 // A class to build a string representing the NACK list in Cast message. | |
78 // | |
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() {} | |
92 | |
93 bool Empty() const { return frame_count_ == 0; } | |
94 | |
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; | |
100 } | |
101 if (contiguous_sequence_) { | |
102 stream_ << "-" << last_packet_id_; | |
103 } | |
104 stream_ << ", "; | |
105 } | |
106 stream_ << frame_id; | |
107 last_frame_id_ = frame_id; | |
108 packet_count_ = 0; | |
109 contiguous_sequence_ = false; | |
110 ++frame_count_; | |
111 } | |
112 | |
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; | |
124 } | |
125 stream_ << "," << packet_id; | |
126 } | |
127 ++packet_count_; | |
128 last_packet_id_ = packet_id; | |
129 } | |
130 | |
131 std::string GetString() { | |
132 if (contiguous_sequence_) { | |
133 stream_ << "-" << last_packet_id_; | |
134 contiguous_sequence_ = false; | |
135 } | |
136 return stream_.str(); | |
137 } | |
138 | |
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_; | |
146 }; | |
147 } // namespace | |
148 | |
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"; | |
159 } | |
160 | |
161 RtcpSender::~RtcpSender() {} | |
162 | |
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 base::TimeDelta target_delay) { | |
170 if (packet_type_flags & transport::kRtcpSr || | |
171 packet_type_flags & transport::kRtcpDlrr || | |
172 packet_type_flags & transport::kRtcpSenderLog) { | |
173 NOTREACHED() << "Invalid argument"; | |
174 } | |
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(); | |
181 } | |
182 transport::PacketRef packet(new base::RefCountedData<Packet>); | |
183 packet->data.reserve(kMaxIpPacketSize); | |
184 | |
185 if (packet_type_flags & transport::kRtcpRr) { | |
186 BuildRR(report_block, &packet->data); | |
187 if (!c_name_.empty()) { | |
188 BuildSdec(&packet->data); | |
189 } | |
190 } | |
191 if (packet_type_flags & transport::kRtcpBye) { | |
192 BuildBye(&packet->data); | |
193 } | |
194 if (packet_type_flags & transport::kRtcpRrtr) { | |
195 DCHECK(rrtr) << "Invalid argument"; | |
196 BuildRrtr(rrtr, &packet->data); | |
197 } | |
198 if (packet_type_flags & transport::kRtcpCast) { | |
199 DCHECK(cast_message) << "Invalid argument"; | |
200 BuildCast(cast_message, target_delay, &packet->data); | |
201 } | |
202 if (packet_type_flags & transport::kRtcpReceiverLog) { | |
203 DCHECK(rtcp_events) << "Invalid argument"; | |
204 BuildReceiverLog(*rtcp_events, &packet->data); | |
205 } | |
206 | |
207 if (packet->data.empty()) | |
208 return; // Sanity don't send empty packets. | |
209 | |
210 transport_->SendRtcpPacket(ssrc_, packet); | |
211 } | |
212 | |
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; | |
219 | |
220 uint16 number_of_rows = (report_block) ? 7 : 1; | |
221 packet->resize(start_size + 8); | |
222 | |
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_); | |
229 | |
230 if (report_block) { | |
231 AddReportBlocks(*report_block, packet); // Adds 24 bytes. | |
232 } | |
233 } | |
234 | |
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; | |
241 | |
242 packet->resize(start_size + 24); | |
243 | |
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); | |
251 | |
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); | |
255 | |
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); | |
260 | |
261 // Delay since last received report, time since we received the report. | |
262 big_endian_writer.WriteU32(report_block.delay_since_last_sr); | |
263 } | |
264 | |
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; | |
271 | |
272 // SDES Source Description. | |
273 packet->resize(start_size + 10); | |
274 | |
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); | |
280 | |
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())); | |
287 | |
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()); | |
291 | |
292 size_t padding = 0; | |
293 | |
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); | |
298 } | |
299 while ((packet->size() % 4) != 0) { | |
300 padding++; | |
301 packet->push_back(0); | |
302 } | |
303 sdes_length += padding; | |
304 | |
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; | |
308 } | |
309 | |
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; | |
315 | |
316 packet->resize(start_size + 12); | |
317 | |
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. | |
326 } | |
327 | |
328 /* | |
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 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
336 */ | |
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; | |
342 | |
343 packet->resize(start_size + 24); | |
344 | |
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); | |
350 | |
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++; | |
357 } | |
358 uint8 size = 3; | |
359 if (bytes_required > 6) { | |
360 size = 5; | |
361 } else if (bytes_required > 2) { | |
362 size = 4; | |
363 } | |
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); | |
368 | |
369 uint8 padding_bytes = 4 - ((2 + bytes_required) % 4); | |
370 if (padding_bytes == 4) { | |
371 padding_bytes = 0; | |
372 } | |
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); | |
376 | |
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))); | |
381 } | |
382 // Add last byte of picture ID. | |
383 big_endian_writer.WriteU8(static_cast<uint8>(rpsi->picture_id & 0x7f)); | |
384 | |
385 // Add padding. | |
386 for (int j = 0; j < padding_bytes; ++j) { | |
387 big_endian_writer.WriteU8(0); | |
388 } | |
389 } | |
390 | |
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; | |
398 | |
399 packet->resize(start_size + remb_size); | |
400 | |
401 base::BigEndianWriter big_endian_writer( | |
402 reinterpret_cast<char*>(&((*packet)[start_size])), remb_size); | |
403 | |
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())); | |
414 | |
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); | |
420 | |
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)); | |
425 | |
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); | |
429 } | |
430 } | |
431 | |
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; | |
437 | |
438 packet->resize(start_size + 16); | |
439 | |
440 base::BigEndianWriter big_endian_writer( | |
441 reinterpret_cast<char*>(&((*packet)[start_size])), 16); | |
442 | |
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. | |
451 | |
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); | |
457 | |
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; | |
471 } | |
472 } | |
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; | |
478 | |
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++; | |
485 } | |
486 DCHECK_GE(kRtcpMaxNackFields, number_of_nack_fields); | |
487 (*packet)[nack_size_pos] = static_cast<uint8>(2 + number_of_nack_fields); | |
488 } | |
489 | |
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; | |
495 | |
496 packet->resize(start_size + 8); | |
497 | |
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. | |
504 } | |
505 | |
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; | |
512 | |
513 packet->resize(start_size + 20); | |
514 | |
515 base::BigEndianWriter big_endian_writer( | |
516 reinterpret_cast<char*>(&((*packet)[start_size])), 20); | |
517 | |
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. | |
525 | |
526 // Add the media (received RTP) SSRC. | |
527 big_endian_writer.WriteU32(rrtr->ntp_seconds); | |
528 big_endian_writer.WriteU32(rrtr->ntp_fraction); | |
529 } | |
530 | |
531 void RtcpSender::BuildCast(const RtcpCastMessage* cast, | |
532 base::TimeDelta target_delay, | |
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; | |
538 | |
539 packet->resize(start_size + 20); | |
540 | |
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 DCHECK_LE(target_delay.InMilliseconds(), | |
556 std::numeric_limits<uint16_t>::max()); | |
557 big_endian_writer.WriteU16(target_delay.InMilliseconds()); | |
558 | |
559 size_t number_of_loss_fields = 0; | |
560 size_t max_number_of_loss_fields = std::min<size_t>( | |
561 kRtcpMaxCastLossFields, (kMaxIpPacketSize - packet->size()) / 4); | |
562 | |
563 MissingFramesAndPacketsMap::const_iterator frame_it = | |
564 cast->missing_frames_and_packets_.begin(); | |
565 | |
566 NackStringBuilder nack_string_builder; | |
567 for (; frame_it != cast->missing_frames_and_packets_.end() && | |
568 number_of_loss_fields < max_number_of_loss_fields; | |
569 ++frame_it) { | |
570 nack_string_builder.PushFrame(frame_it->first); | |
571 // Iterate through all frames with missing packets. | |
572 if (frame_it->second.empty()) { | |
573 // Special case all packets in a frame is missing. | |
574 start_size = packet->size(); | |
575 packet->resize(start_size + 4); | |
576 base::BigEndianWriter big_endian_nack_writer( | |
577 reinterpret_cast<char*>(&((*packet)[start_size])), 4); | |
578 big_endian_nack_writer.WriteU8(static_cast<uint8>(frame_it->first)); | |
579 big_endian_nack_writer.WriteU16(kRtcpCastAllPacketsLost); | |
580 big_endian_nack_writer.WriteU8(0); | |
581 nack_string_builder.PushPacket(kRtcpCastAllPacketsLost); | |
582 ++number_of_loss_fields; | |
583 } else { | |
584 PacketIdSet::const_iterator packet_it = frame_it->second.begin(); | |
585 while (packet_it != frame_it->second.end()) { | |
586 uint16 packet_id = *packet_it; | |
587 | |
588 start_size = packet->size(); | |
589 packet->resize(start_size + 4); | |
590 base::BigEndianWriter big_endian_nack_writer( | |
591 reinterpret_cast<char*>(&((*packet)[start_size])), 4); | |
592 | |
593 // Write frame and packet id to buffer before calculating bitmask. | |
594 big_endian_nack_writer.WriteU8(static_cast<uint8>(frame_it->first)); | |
595 big_endian_nack_writer.WriteU16(packet_id); | |
596 nack_string_builder.PushPacket(packet_id); | |
597 | |
598 uint8 bitmask = 0; | |
599 ++packet_it; | |
600 while (packet_it != frame_it->second.end()) { | |
601 int shift = static_cast<uint8>(*packet_it - packet_id) - 1; | |
602 if (shift >= 0 && shift <= 7) { | |
603 nack_string_builder.PushPacket(*packet_it); | |
604 bitmask |= (1 << shift); | |
605 ++packet_it; | |
606 } else { | |
607 break; | |
608 } | |
609 } | |
610 big_endian_nack_writer.WriteU8(bitmask); | |
611 ++number_of_loss_fields; | |
612 } | |
613 } | |
614 } | |
615 VLOG_IF(1, !nack_string_builder.Empty()) | |
616 << "SSRC: " << cast->media_ssrc_ | |
617 << ", ACK: " << cast->ack_frame_id_ | |
618 << ", NACK: " << nack_string_builder.GetString(); | |
619 DCHECK_LE(number_of_loss_fields, kRtcpMaxCastLossFields); | |
620 (*packet)[cast_size_pos] = static_cast<uint8>(4 + number_of_loss_fields); | |
621 (*packet)[cast_loss_field_pos] = static_cast<uint8>(number_of_loss_fields); | |
622 } | |
623 | |
624 void RtcpSender::BuildReceiverLog( | |
625 const ReceiverRtcpEventSubscriber::RtcpEventMultiMap& rtcp_events, | |
626 Packet* packet) { | |
627 const size_t packet_start_size = packet->size(); | |
628 size_t number_of_frames = 0; | |
629 size_t total_number_of_messages_to_send = 0; | |
630 size_t rtcp_log_size = 0; | |
631 RtcpReceiverLogMessage receiver_log_message; | |
632 | |
633 if (!BuildRtcpReceiverLogMessage(rtcp_events, | |
634 packet_start_size, | |
635 &receiver_log_message, | |
636 &number_of_frames, | |
637 &total_number_of_messages_to_send, | |
638 &rtcp_log_size)) { | |
639 return; | |
640 } | |
641 packet->resize(packet_start_size + rtcp_log_size); | |
642 | |
643 base::BigEndianWriter big_endian_writer( | |
644 reinterpret_cast<char*>(&((*packet)[packet_start_size])), rtcp_log_size); | |
645 big_endian_writer.WriteU8(0x80 + kReceiverLogSubtype); | |
646 big_endian_writer.WriteU8(transport::kPacketTypeApplicationDefined); | |
647 big_endian_writer.WriteU16(static_cast<uint16>( | |
648 2 + 2 * number_of_frames + total_number_of_messages_to_send)); | |
649 big_endian_writer.WriteU32(ssrc_); // Add our own SSRC. | |
650 big_endian_writer.WriteU32(kCast); | |
651 | |
652 while (!receiver_log_message.empty() && | |
653 total_number_of_messages_to_send > 0) { | |
654 RtcpReceiverFrameLogMessage& frame_log_messages( | |
655 receiver_log_message.front()); | |
656 | |
657 // Add our frame header. | |
658 big_endian_writer.WriteU32(frame_log_messages.rtp_timestamp_); | |
659 size_t messages_in_frame = frame_log_messages.event_log_messages_.size(); | |
660 if (messages_in_frame > total_number_of_messages_to_send) { | |
661 // We are running out of space. | |
662 messages_in_frame = total_number_of_messages_to_send; | |
663 } | |
664 // Keep track of how many messages we have left to send. | |
665 total_number_of_messages_to_send -= messages_in_frame; | |
666 | |
667 // On the wire format is number of messages - 1. | |
668 big_endian_writer.WriteU8(static_cast<uint8>(messages_in_frame - 1)); | |
669 | |
670 base::TimeTicks event_timestamp_base = | |
671 frame_log_messages.event_log_messages_.front().event_timestamp; | |
672 uint32 base_timestamp_ms = | |
673 (event_timestamp_base - base::TimeTicks()).InMilliseconds(); | |
674 big_endian_writer.WriteU8(static_cast<uint8>(base_timestamp_ms >> 16)); | |
675 big_endian_writer.WriteU8(static_cast<uint8>(base_timestamp_ms >> 8)); | |
676 big_endian_writer.WriteU8(static_cast<uint8>(base_timestamp_ms)); | |
677 | |
678 while (!frame_log_messages.event_log_messages_.empty() && | |
679 messages_in_frame > 0) { | |
680 const RtcpReceiverEventLogMessage& event_message = | |
681 frame_log_messages.event_log_messages_.front(); | |
682 uint16 event_type_and_timestamp_delta = | |
683 MergeEventTypeAndTimestampForWireFormat( | |
684 event_message.type, | |
685 event_message.event_timestamp - event_timestamp_base); | |
686 switch (event_message.type) { | |
687 case FRAME_ACK_SENT: | |
688 case FRAME_PLAYOUT: | |
689 case FRAME_DECODED: | |
690 big_endian_writer.WriteU16( | |
691 static_cast<uint16>(event_message.delay_delta.InMilliseconds())); | |
692 big_endian_writer.WriteU16(event_type_and_timestamp_delta); | |
693 break; | |
694 case PACKET_RECEIVED: | |
695 big_endian_writer.WriteU16(event_message.packet_id); | |
696 big_endian_writer.WriteU16(event_type_and_timestamp_delta); | |
697 break; | |
698 default: | |
699 NOTREACHED(); | |
700 } | |
701 messages_in_frame--; | |
702 frame_log_messages.event_log_messages_.pop_front(); | |
703 } | |
704 if (frame_log_messages.event_log_messages_.empty()) { | |
705 // We sent all messages on this frame; pop the frame header. | |
706 receiver_log_message.pop_front(); | |
707 } | |
708 } | |
709 DCHECK_EQ(total_number_of_messages_to_send, 0u); | |
710 } | |
711 | |
712 bool RtcpSender::BuildRtcpReceiverLogMessage( | |
713 const ReceiverRtcpEventSubscriber::RtcpEventMultiMap& rtcp_events, | |
714 size_t start_size, | |
715 RtcpReceiverLogMessage* receiver_log_message, | |
716 size_t* number_of_frames, | |
717 size_t* total_number_of_messages_to_send, | |
718 size_t* rtcp_log_size) { | |
719 size_t remaining_space = | |
720 std::min(kMaxReceiverLogBytes, kMaxIpPacketSize - start_size); | |
721 if (remaining_space < kRtcpCastLogHeaderSize + kRtcpReceiverFrameLogSize + | |
722 kRtcpReceiverEventLogSize) { | |
723 return false; | |
724 } | |
725 | |
726 // We use this to do event timestamp sorting and truncating for events of | |
727 // a single frame. | |
728 std::vector<RtcpReceiverEventLogMessage> sorted_log_messages; | |
729 | |
730 // Account for the RTCP header for an application-defined packet. | |
731 remaining_space -= kRtcpCastLogHeaderSize; | |
732 | |
733 ReceiverRtcpEventSubscriber::RtcpEventMultiMap::const_reverse_iterator rit = | |
734 rtcp_events.rbegin(); | |
735 | |
736 while (rit != rtcp_events.rend() && | |
737 remaining_space >= | |
738 kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize) { | |
739 const RtpTimestamp rtp_timestamp = rit->first; | |
740 RtcpReceiverFrameLogMessage frame_log(rtp_timestamp); | |
741 remaining_space -= kRtcpReceiverFrameLogSize; | |
742 ++*number_of_frames; | |
743 | |
744 // Get all events of a single frame. | |
745 sorted_log_messages.clear(); | |
746 do { | |
747 RtcpReceiverEventLogMessage event_log_message; | |
748 event_log_message.type = rit->second.type; | |
749 event_log_message.event_timestamp = rit->second.timestamp; | |
750 event_log_message.delay_delta = rit->second.delay_delta; | |
751 event_log_message.packet_id = rit->second.packet_id; | |
752 sorted_log_messages.push_back(event_log_message); | |
753 ++rit; | |
754 } while (rit != rtcp_events.rend() && rit->first == rtp_timestamp); | |
755 | |
756 std::sort(sorted_log_messages.begin(), | |
757 sorted_log_messages.end(), | |
758 &EventTimestampLessThan); | |
759 | |
760 // From |sorted_log_messages|, only take events that are no greater than | |
761 // |kMaxWireFormatTimeDeltaMs| seconds away from the latest event. Events | |
762 // older than that cannot be encoded over the wire. | |
763 std::vector<RtcpReceiverEventLogMessage>::reverse_iterator sorted_rit = | |
764 sorted_log_messages.rbegin(); | |
765 base::TimeTicks first_event_timestamp = sorted_rit->event_timestamp; | |
766 size_t events_in_frame = 0; | |
767 while (sorted_rit != sorted_log_messages.rend() && | |
768 events_in_frame < kRtcpMaxReceiverLogMessages && | |
769 remaining_space >= kRtcpReceiverEventLogSize) { | |
770 base::TimeDelta delta(first_event_timestamp - | |
771 sorted_rit->event_timestamp); | |
772 if (delta.InMilliseconds() > kMaxWireFormatTimeDeltaMs) | |
773 break; | |
774 frame_log.event_log_messages_.push_front(*sorted_rit); | |
775 ++events_in_frame; | |
776 ++*total_number_of_messages_to_send; | |
777 remaining_space -= kRtcpReceiverEventLogSize; | |
778 ++sorted_rit; | |
779 } | |
780 | |
781 receiver_log_message->push_front(frame_log); | |
782 } | |
783 | |
784 rtcp_events_history_.push_front(*receiver_log_message); | |
785 | |
786 // We don't try to match RTP timestamps of redundancy frame logs with those | |
787 // from the newest set (which would save the space of an extra RTP timestamp | |
788 // over the wire). Unless the redundancy frame logs are very recent, it's | |
789 // unlikely there will be a match anyway. | |
790 if (rtcp_events_history_.size() > kFirstRedundancyOffset) { | |
791 // Add first redundnacy messages, if enough space remaining | |
792 AddReceiverLog(rtcp_events_history_[kFirstRedundancyOffset], | |
793 receiver_log_message, | |
794 &remaining_space, | |
795 number_of_frames, | |
796 total_number_of_messages_to_send); | |
797 } | |
798 | |
799 if (rtcp_events_history_.size() > kSecondRedundancyOffset) { | |
800 // Add second redundancy messages, if enough space remaining | |
801 AddReceiverLog(rtcp_events_history_[kSecondRedundancyOffset], | |
802 receiver_log_message, | |
803 &remaining_space, | |
804 number_of_frames, | |
805 total_number_of_messages_to_send); | |
806 } | |
807 | |
808 if (rtcp_events_history_.size() > kReceiveLogMessageHistorySize) { | |
809 rtcp_events_history_.pop_back(); | |
810 } | |
811 | |
812 DCHECK_LE(rtcp_events_history_.size(), kReceiveLogMessageHistorySize); | |
813 | |
814 *rtcp_log_size = | |
815 kRtcpCastLogHeaderSize + *number_of_frames * kRtcpReceiverFrameLogSize + | |
816 *total_number_of_messages_to_send * kRtcpReceiverEventLogSize; | |
817 DCHECK_GE(kMaxIpPacketSize, start_size + *rtcp_log_size) | |
818 << "Not enough buffer space."; | |
819 | |
820 VLOG(3) << "number of frames: " << *number_of_frames; | |
821 VLOG(3) << "total messages to send: " << *total_number_of_messages_to_send; | |
822 VLOG(3) << "rtcp log size: " << *rtcp_log_size; | |
823 return *number_of_frames > 0; | |
824 } | |
825 | |
826 } // namespace cast | |
827 } // namespace media | |
OLD | NEW |