OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/cast/net/pacing/paced_sender.h" | 5 #include "media/cast/net/pacing/paced_sender.h" |
6 | 6 |
7 #include "base/big_endian.h" | 7 #include "base/big_endian.h" |
8 #include "base/bind.h" | 8 #include "base/bind.h" |
9 #include "base/debug/dump_without_crashing.h" | 9 #include "base/debug/dump_without_crashing.h" |
10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
(...skipping 28 matching lines...) Expand all Loading... | |
39 uint16_t packet_id) | 39 uint16_t packet_id) |
40 : capture_time(capture_time), | 40 : capture_time(capture_time), |
41 ssrc(ssrc), | 41 ssrc(ssrc), |
42 frame_id(frame_id), | 42 frame_id(frame_id), |
43 packet_id(packet_id) {} | 43 packet_id(packet_id) {} |
44 | 44 |
45 PacketKey::PacketKey(const PacketKey& other) = default; | 45 PacketKey::PacketKey(const PacketKey& other) = default; |
46 | 46 |
47 PacketKey::~PacketKey() {} | 47 PacketKey::~PacketKey() {} |
48 | 48 |
49 PacedSender::PacketSendRecord::PacketSendRecord() | 49 struct PacedSender::PacketSendRecord { |
50 : last_byte_sent(0), last_byte_sent_for_audio(0), cancel_count(0) {} | 50 PacketSendRecord() |
51 : last_byte_sent(0), last_byte_sent_for_audio(0), cancel_count(0) {} | |
52 | |
53 base::TimeTicks time; // Time when the packet was sent. | |
54 int64_t last_byte_sent; // Number of bytes sent to network just after this | |
55 // packet was sent. | |
56 int64_t last_byte_sent_for_audio; // Number of bytes sent to network from | |
57 // audio stream just before this packet. | |
58 int cancel_count; // Number of times the packet was canceled (debugging). | |
59 }; | |
60 | |
61 struct PacedSender::RtpSession { | |
62 explicit RtpSession(bool is_audio_stream) | |
63 : last_byte_sent(0), is_audio(is_audio_stream) {} | |
64 RtpSession() {} | |
65 | |
66 // Tracks recently-logged RTP timestamps so that it can expand the truncated | |
67 // values found in packets. | |
68 RtpTimeTicks last_logged_rtp_timestamp_; | |
69 int64_t last_byte_sent; | |
70 bool is_audio; | |
71 }; | |
51 | 72 |
52 PacedSender::PacedSender( | 73 PacedSender::PacedSender( |
53 size_t target_burst_size, | 74 size_t target_burst_size, |
54 size_t max_burst_size, | 75 size_t max_burst_size, |
55 base::TickClock* clock, | 76 base::TickClock* clock, |
56 std::vector<PacketEvent>* recent_packet_events, | 77 std::vector<PacketEvent>* recent_packet_events, |
57 PacketTransport* transport, | 78 PacketTransport* transport, |
58 const scoped_refptr<base::SingleThreadTaskRunner>& transport_task_runner) | 79 const scoped_refptr<base::SingleThreadTaskRunner>& transport_task_runner) |
59 : clock_(clock), | 80 : clock_(clock), |
60 recent_packet_events_(recent_packet_events), | 81 recent_packet_events_(recent_packet_events), |
61 transport_(transport), | 82 transport_(transport), |
62 transport_task_runner_(transport_task_runner), | 83 transport_task_runner_(transport_task_runner), |
63 audio_ssrc_(0), | 84 last_byte_sent_for_audio_(0), |
64 video_ssrc_(0), | |
65 target_burst_size_(target_burst_size), | 85 target_burst_size_(target_burst_size), |
66 max_burst_size_(max_burst_size), | 86 max_burst_size_(max_burst_size), |
67 current_max_burst_size_(target_burst_size_), | 87 current_max_burst_size_(target_burst_size_), |
68 next_max_burst_size_(target_burst_size_), | 88 next_max_burst_size_(target_burst_size_), |
69 next_next_max_burst_size_(target_burst_size_), | 89 next_next_max_burst_size_(target_burst_size_), |
70 current_burst_size_(0), | 90 current_burst_size_(0), |
71 state_(State_Unblocked), | 91 state_(State_Unblocked), |
72 has_reached_upper_bound_once_(false), | 92 has_reached_upper_bound_once_(false), |
73 weak_factory_(this) {} | 93 weak_factory_(this) {} |
74 | 94 |
75 PacedSender::~PacedSender() {} | 95 PacedSender::~PacedSender() {} |
76 | 96 |
77 void PacedSender::RegisterAudioSsrc(uint32_t audio_ssrc) { | 97 void PacedSender::RegisterSsrc(uint32_t ssrc, bool is_audio) { |
78 audio_ssrc_ = audio_ssrc; | 98 if (sessions_.find(ssrc) != sessions_.end()) |
79 } | 99 DVLOG(1) << "Re-register ssrc: " << ssrc; |
80 | 100 |
81 void PacedSender::RegisterVideoSsrc(uint32_t video_ssrc) { | 101 sessions_[ssrc] = RtpSession(is_audio); |
82 video_ssrc_ = video_ssrc; | |
83 } | 102 } |
84 | 103 |
85 void PacedSender::RegisterPrioritySsrc(uint32_t ssrc) { | 104 void PacedSender::RegisterPrioritySsrc(uint32_t ssrc) { |
86 priority_ssrcs_.push_back(ssrc); | 105 priority_ssrcs_.push_back(ssrc); |
87 } | 106 } |
88 | 107 |
89 int64_t PacedSender::GetLastByteSentForPacket(const PacketKey& packet_key) { | 108 int64_t PacedSender::GetLastByteSentForPacket(const PacketKey& packet_key) { |
90 PacketSendHistory::const_iterator it = send_history_.find(packet_key); | 109 PacketSendHistory::const_iterator it = send_history_.find(packet_key); |
91 if (it == send_history_.end()) | 110 if (it == send_history_.end()) |
92 return 0; | 111 return 0; |
93 return it->second.last_byte_sent; | 112 return it->second.last_byte_sent; |
94 } | 113 } |
95 | 114 |
96 int64_t PacedSender::GetLastByteSentForSsrc(uint32_t ssrc) { | 115 int64_t PacedSender::GetLastByteSentForSsrc(uint32_t ssrc) { |
97 std::map<uint32_t, int64_t>::const_iterator it = last_byte_sent_.find(ssrc); | 116 auto it = sessions_.find(ssrc); |
98 if (it == last_byte_sent_.end()) | 117 if (it == sessions_.end()) |
99 return 0; | 118 return 0; |
100 return it->second; | 119 return it->second.last_byte_sent; |
101 } | 120 } |
102 | 121 |
103 bool PacedSender::SendPackets(const SendPacketVector& packets) { | 122 bool PacedSender::SendPackets(const SendPacketVector& packets) { |
104 if (packets.empty()) { | 123 if (packets.empty()) { |
105 return true; | 124 return true; |
106 } | 125 } |
107 const bool high_priority = IsHighPriority(packets.begin()->first); | 126 const bool high_priority = IsHighPriority(packets.begin()->first); |
108 for (size_t i = 0; i < packets.size(); i++) { | 127 for (size_t i = 0; i < packets.size(); i++) { |
109 if (VLOG_IS_ON(2)) { | 128 if (VLOG_IS_ON(2)) { |
110 PacketSendHistory::const_iterator history_it = | 129 PacketSendHistory::const_iterator history_it = |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
143 if (it == send_history_.end()) | 162 if (it == send_history_.end()) |
144 return true; | 163 return true; |
145 | 164 |
146 // Suppose there is request to retransmit X and there is an audio | 165 // Suppose there is request to retransmit X and there is an audio |
147 // packet Y sent just before X. Reject retransmission of X if ACK for | 166 // packet Y sent just before X. Reject retransmission of X if ACK for |
148 // Y has not been received. | 167 // Y has not been received. |
149 // Only do this for video packets. | 168 // Only do this for video packets. |
150 // | 169 // |
151 // TODO(miu): This sounds wrong. Audio packets are always transmitted first | 170 // TODO(miu): This sounds wrong. Audio packets are always transmitted first |
152 // (because they are put in |priority_packet_list_|, see PopNextPacket()). | 171 // (because they are put in |priority_packet_list_|, see PopNextPacket()). |
153 if (packet_key.ssrc == video_ssrc_) { | 172 auto session_it = sessions_.find(packet_key.ssrc); |
173 DCHECK(session_it != sessions_.end()); | |
dcheng
2016/07/14 03:40:27
The inconsistent handling of ssrc here makes me ne
xjz
2016/07/14 18:29:57
Yes, whenever a session for a RTP stream (with uni
dcheng
2016/07/15 01:21:19
Is it possible to be consistent about DCHECKing()
xjz
2016/07/18 20:21:58
Done. Removed the DCHECK() since it should be guar
dcheng
2016/07/19 05:56:10
To be clear, I think it's better to have the DCHEC
xjz
2016/07/19 18:18:33
Thanks for the clarification. Yes, the sessions sh
xjz
2016/07/19 21:43:19
Changed it back to DCHECK() so that the code will
| |
174 if (!session_it->second.is_audio) { | |
154 if (dedup_info.last_byte_acked_for_audio && | 175 if (dedup_info.last_byte_acked_for_audio && |
155 it->second.last_byte_sent_for_audio && | 176 it->second.last_byte_sent_for_audio && |
156 dedup_info.last_byte_acked_for_audio < | 177 dedup_info.last_byte_acked_for_audio < |
157 it->second.last_byte_sent_for_audio) { | 178 it->second.last_byte_sent_for_audio) { |
158 return false; | 179 return false; |
159 } | 180 } |
160 } | 181 } |
161 // Retransmission interval has to be greater than |resend_interval|. | 182 // Retransmission interval has to be greater than |resend_interval|. |
162 if (now - it->second.time < dedup_info.resend_interval) | 183 if (now - it->second.time < dedup_info.resend_interval) |
163 return false; | 184 return false; |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
382 LogPacketEvent(packet->data, PACKET_SENT_TO_NETWORK); | 403 LogPacketEvent(packet->data, PACKET_SENT_TO_NETWORK); |
383 break; | 404 break; |
384 case PacketType_RTCP: | 405 case PacketType_RTCP: |
385 break; | 406 break; |
386 } | 407 } |
387 | 408 |
388 const bool socket_blocked = !transport_->SendPacket(packet, cb); | 409 const bool socket_blocked = !transport_->SendPacket(packet, cb); |
389 | 410 |
390 // Save the send record. | 411 // Save the send record. |
391 send_record->last_byte_sent = transport_->GetBytesSent(); | 412 send_record->last_byte_sent = transport_->GetBytesSent(); |
392 send_record->last_byte_sent_for_audio = GetLastByteSentForSsrc(audio_ssrc_); | 413 send_record->last_byte_sent_for_audio = last_byte_sent_for_audio_; |
393 send_history_buffer_[packet_key] = *send_record; | 414 send_history_buffer_[packet_key] = *send_record; |
394 last_byte_sent_[packet_key.ssrc] = send_record->last_byte_sent; | 415 |
416 auto it = sessions_.find(packet_key.ssrc); | |
417 DCHECK(it != sessions_.end()); | |
418 it->second.last_byte_sent = send_record->last_byte_sent; | |
419 if (it->second.is_audio) | |
420 last_byte_sent_for_audio_ = send_record->last_byte_sent; | |
395 | 421 |
396 if (socket_blocked) { | 422 if (socket_blocked) { |
397 state_ = State_TransportBlocked; | 423 state_ = State_TransportBlocked; |
398 return; | 424 return; |
399 } | 425 } |
400 current_burst_size_++; | 426 current_burst_size_++; |
401 } | 427 } |
402 | 428 |
403 // Keep ~0.5 seconds of data (1000 packets). | 429 // Keep ~0.5 seconds of data (1000 packets). |
404 // | 430 // |
(...skipping 21 matching lines...) Expand all Loading... | |
426 // TODO(miu): This parsing logic belongs in RtpParser. | 452 // TODO(miu): This parsing logic belongs in RtpParser. |
427 event.timestamp = clock_->NowTicks(); | 453 event.timestamp = clock_->NowTicks(); |
428 event.type = type; | 454 event.type = type; |
429 base::BigEndianReader reader(reinterpret_cast<const char*>(&packet[0]), | 455 base::BigEndianReader reader(reinterpret_cast<const char*>(&packet[0]), |
430 packet.size()); | 456 packet.size()); |
431 bool success = reader.Skip(4); | 457 bool success = reader.Skip(4); |
432 uint32_t truncated_rtp_timestamp; | 458 uint32_t truncated_rtp_timestamp; |
433 success &= reader.ReadU32(&truncated_rtp_timestamp); | 459 success &= reader.ReadU32(&truncated_rtp_timestamp); |
434 uint32_t ssrc; | 460 uint32_t ssrc; |
435 success &= reader.ReadU32(&ssrc); | 461 success &= reader.ReadU32(&ssrc); |
436 if (ssrc == audio_ssrc_) { | 462 |
437 event.rtp_timestamp = last_logged_audio_rtp_timestamp_ = | 463 auto it = sessions_.find(ssrc); |
438 last_logged_audio_rtp_timestamp_.Expand(truncated_rtp_timestamp); | 464 if (it == sessions_.end()) { |
439 event.media_type = AUDIO_EVENT; | |
440 } else if (ssrc == video_ssrc_) { | |
441 event.rtp_timestamp = last_logged_video_rtp_timestamp_ = | |
442 last_logged_video_rtp_timestamp_.Expand(truncated_rtp_timestamp); | |
443 event.media_type = VIDEO_EVENT; | |
444 } else { | |
445 DVLOG(3) << "Got unknown ssrc " << ssrc << " when logging packet event"; | 465 DVLOG(3) << "Got unknown ssrc " << ssrc << " when logging packet event"; |
446 return; | 466 return; |
447 } | 467 } |
468 event.rtp_timestamp = it->second.last_logged_rtp_timestamp_ = | |
469 it->second.last_logged_rtp_timestamp_.Expand(truncated_rtp_timestamp); | |
470 event.media_type = it->second.is_audio ? AUDIO_EVENT : VIDEO_EVENT; | |
448 success &= reader.Skip(2); | 471 success &= reader.Skip(2); |
449 success &= reader.ReadU16(&event.packet_id); | 472 success &= reader.ReadU16(&event.packet_id); |
450 success &= reader.ReadU16(&event.max_packet_id); | 473 success &= reader.ReadU16(&event.max_packet_id); |
451 event.size = base::checked_cast<uint32_t>(packet.size()); | 474 event.size = base::checked_cast<uint32_t>(packet.size()); |
452 DCHECK(success); | 475 DCHECK(success); |
453 } | 476 } |
454 | 477 |
455 } // namespace cast | 478 } // namespace cast |
456 } // namespace media | 479 } // namespace media |
OLD | NEW |