OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 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 "chrome/browser/media/cast_remoting_sender.h" | |
6 | |
7 #include <map> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/bind_helpers.h" | |
11 #include "base/callback.h" | |
12 #include "base/lazy_instance.h" | |
13 #include "base/memory/ptr_util.h" | |
14 #include "base/numerics/safe_conversions.h" | |
15 #include "base/trace_event/trace_event.h" | |
16 #include "content/public/browser/browser_thread.h" | |
17 #include "media/base/bind_to_current_loop.h" | |
18 #include "media/cast/constants.h" | |
19 | |
20 namespace { | |
21 | |
22 // Global map for looking-up CastRemotingSender instances by their | |
23 // |remoting_stream_id_|. | |
24 using CastRemotingSenderMap = std::map<int32_t, cast::CastRemotingSender*>; | |
25 base::LazyInstance<CastRemotingSenderMap>::Leaky g_sender_map = | |
26 LAZY_INSTANCE_INITIALIZER; | |
27 | |
28 constexpr base::TimeDelta kMinSchedulingDelay = | |
29 base::TimeDelta::FromMilliseconds(1); | |
30 constexpr base::TimeDelta kMaxAckDelay = base::TimeDelta::FromMilliseconds(800); | |
31 constexpr base::TimeDelta kMinAckDelay = base::TimeDelta::FromMilliseconds(400); | |
32 constexpr base::TimeDelta kReceiverProcessTime = | |
33 base::TimeDelta::FromMilliseconds(250); | |
34 | |
35 } // namespace | |
36 | |
37 namespace cast { | |
38 | |
39 class CastRemotingSender::RemotingRtcpClient final | |
40 : public media::cast::RtcpObserver { | |
41 public: | |
42 explicit RemotingRtcpClient(base::WeakPtr<CastRemotingSender> remoting_sender) | |
43 : remoting_sender_(remoting_sender) {} | |
44 | |
45 ~RemotingRtcpClient() final {} | |
46 | |
47 void OnReceivedCastMessage( | |
48 const media::cast::RtcpCastMessage& cast_message) final { | |
49 if (remoting_sender_) | |
50 remoting_sender_->OnReceivedCastMessage(cast_message); | |
51 } | |
52 | |
53 void OnReceivedRtt(base::TimeDelta round_trip_time) final { | |
54 if (remoting_sender_) | |
55 remoting_sender_->OnReceivedRtt(round_trip_time); | |
56 } | |
57 | |
58 void OnReceivedPli() final { | |
59 // Receiving PLI messages on remoting streams is ignored. | |
60 } | |
61 | |
62 private: | |
63 const base::WeakPtr<CastRemotingSender> remoting_sender_; | |
64 | |
65 DISALLOW_COPY_AND_ASSIGN(RemotingRtcpClient); | |
66 }; | |
67 | |
68 // Convenience macro used in logging statements throughout this file. | |
69 #define SENDER_SSRC (is_audio_ ? "AUDIO[" : "VIDEO[") << ssrc_ << "] " | |
70 | |
71 CastRemotingSender::CastRemotingSender( | |
72 scoped_refptr<media::cast::CastEnvironment> cast_environment, | |
73 media::cast::CastTransport* transport, | |
74 const media::cast::CastTransportRtpConfig& config) | |
75 : remoting_stream_id_(config.rtp_stream_id), | |
76 cast_environment_(std::move(cast_environment)), | |
77 transport_(transport), | |
78 ssrc_(config.ssrc), | |
79 is_audio_(config.rtp_payload_type == | |
80 media::cast::RtpPayloadType::REMOTE_AUDIO), | |
81 max_ack_delay_(kMaxAckDelay), | |
82 last_sent_frame_id_(media::cast::FrameId::first() - 1), | |
83 latest_acked_frame_id_(media::cast::FrameId::first() - 1), | |
84 duplicate_ack_counter_(0), | |
85 last_frame_was_canceled_(false), | |
86 weak_factory_(this) { | |
87 DCHECK(cast_environment_->CurrentlyOn(media::cast::CastEnvironment::MAIN)); | |
88 | |
89 CastRemotingSender*& pointer_in_map = g_sender_map.Get()[remoting_stream_id_]; | |
90 DCHECK(!pointer_in_map); | |
91 pointer_in_map = this; | |
92 transport_->InitializeStream( | |
93 config, base::MakeUnique<RemotingRtcpClient>(weak_factory_.GetWeakPtr())); | |
94 } | |
95 | |
96 CastRemotingSender::~CastRemotingSender() { | |
97 DCHECK(cast_environment_->CurrentlyOn(media::cast::CastEnvironment::MAIN)); | |
98 | |
99 g_sender_map.Pointer()->erase(remoting_stream_id_); | |
100 } | |
101 | |
102 void CastRemotingSender::OnReceivedRtt(base::TimeDelta round_trip_time) { | |
103 DCHECK_GT(round_trip_time, base::TimeDelta()); | |
104 current_round_trip_time_ = round_trip_time; | |
105 max_ack_delay_ = 2 * current_round_trip_time_ + kReceiverProcessTime; | |
106 max_ack_delay_ = | |
107 std::max(std::min(max_ack_delay_, kMaxAckDelay), kMinAckDelay); | |
108 } | |
109 | |
110 void CastRemotingSender::ResendCheck() { | |
111 DCHECK(cast_environment_->CurrentlyOn(media::cast::CastEnvironment::MAIN)); | |
112 | |
113 DCHECK(!last_send_time_.is_null()); | |
114 const base::TimeDelta time_since_last_send = | |
115 cast_environment_->Clock()->NowTicks() - last_send_time_; | |
116 if (time_since_last_send > max_ack_delay_) { | |
117 if (latest_acked_frame_id_ == last_sent_frame_id_) { | |
118 // Last frame acked, no point in doing anything. | |
119 } else { | |
120 VLOG(1) << SENDER_SSRC | |
121 << "ACK timeout; last acked frame: " << latest_acked_frame_id_; | |
122 ResendForKickstart(); | |
123 } | |
124 } | |
125 ScheduleNextResendCheck(); | |
126 } | |
127 | |
128 void CastRemotingSender::ScheduleNextResendCheck() { | |
129 DCHECK(cast_environment_->CurrentlyOn(media::cast::CastEnvironment::MAIN)); | |
130 | |
131 DCHECK(!last_send_time_.is_null()); | |
132 base::TimeDelta time_to_next = | |
133 last_send_time_ - cast_environment_->Clock()->NowTicks() + max_ack_delay_; | |
134 time_to_next = std::max(time_to_next, kMinSchedulingDelay); | |
135 cast_environment_->PostDelayedTask( | |
136 media::cast::CastEnvironment::MAIN, FROM_HERE, | |
137 base::Bind(&CastRemotingSender::ResendCheck, weak_factory_.GetWeakPtr()), | |
138 time_to_next); | |
139 } | |
140 | |
141 void CastRemotingSender::ResendForKickstart() { | |
142 DCHECK(cast_environment_->CurrentlyOn(media::cast::CastEnvironment::MAIN)); | |
143 | |
144 DCHECK(!last_send_time_.is_null()); | |
145 VLOG(1) << SENDER_SSRC << "Resending last packet of frame " | |
146 << last_sent_frame_id_ << " to kick-start."; | |
147 last_send_time_ = cast_environment_->Clock()->NowTicks(); | |
148 transport_->ResendFrameForKickstart(ssrc_, last_sent_frame_id_); | |
149 } | |
150 | |
151 // TODO(xjz): We may need to count in the frames acknowledged in | |
152 // RtcpCastMessage::received_later_frames for more accurate calculation on | |
153 // available bandwidth. Same logic should apply on | |
154 // media::cast::FrameSender::GetUnacknowledgedFrameCount(). | |
155 int CastRemotingSender::NumberOfFramesInFlight() const { | |
156 if (last_send_time_.is_null()) | |
157 return 0; | |
158 const int count = last_sent_frame_id_ - latest_acked_frame_id_; | |
159 DCHECK_GE(count, 0); | |
160 return count; | |
161 } | |
162 | |
163 void CastRemotingSender::RecordLatestFrameTimestamps( | |
164 media::cast::FrameId frame_id, | |
165 media::cast::RtpTimeTicks rtp_timestamp) { | |
166 frame_rtp_timestamps_[frame_id.lower_8_bits()] = rtp_timestamp; | |
167 } | |
168 | |
169 media::cast::RtpTimeTicks CastRemotingSender::GetRecordedRtpTimestamp( | |
170 media::cast::FrameId frame_id) const { | |
171 return frame_rtp_timestamps_[frame_id.lower_8_bits()]; | |
172 } | |
173 | |
174 void CastRemotingSender::OnReceivedCastMessage( | |
175 const media::cast::RtcpCastMessage& cast_feedback) { | |
176 DCHECK(cast_environment_->CurrentlyOn(media::cast::CastEnvironment::MAIN)); | |
177 | |
178 if (last_send_time_.is_null()) | |
179 return; // Cannot get an ACK without having first sent a frame. | |
180 | |
181 if (cast_feedback.missing_frames_and_packets.empty() && | |
182 cast_feedback.received_later_frames.empty()) { | |
183 if (latest_acked_frame_id_ == cast_feedback.ack_frame_id) { | |
184 VLOG(1) << SENDER_SSRC << "Received duplicate ACK for frame " | |
185 << latest_acked_frame_id_; | |
186 TRACE_EVENT_INSTANT2( | |
187 "cast.stream", "Duplicate ACK", TRACE_EVENT_SCOPE_THREAD, | |
188 "ack_frame_id", cast_feedback.ack_frame_id.lower_32_bits(), | |
189 "last_sent_frame_id", last_sent_frame_id_.lower_32_bits()); | |
190 } | |
191 // We only count duplicate ACKs when we have sent newer frames. | |
192 if (latest_acked_frame_id_ == cast_feedback.ack_frame_id && | |
193 latest_acked_frame_id_ != last_sent_frame_id_) { | |
194 duplicate_ack_counter_++; | |
195 } else { | |
196 duplicate_ack_counter_ = 0; | |
197 } | |
198 // TODO(miu): The values "2" and "3" should be derived from configuration. | |
199 if (duplicate_ack_counter_ >= 2 && duplicate_ack_counter_ % 3 == 2) { | |
200 ResendForKickstart(); | |
201 } | |
202 } else { | |
203 // Only count duplicated ACKs if there is no NACK request in between. | |
204 // This is to avoid aggressive resend. | |
205 duplicate_ack_counter_ = 0; | |
206 } | |
207 | |
208 base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | |
209 auto ack_event = base::MakeUnique<media::cast::FrameEvent>(); | |
210 ack_event->timestamp = now; | |
211 ack_event->type = media::cast::FRAME_ACK_RECEIVED; | |
212 ack_event->media_type = | |
213 is_audio_ ? media::cast::AUDIO_EVENT : media::cast::VIDEO_EVENT; | |
214 ack_event->rtp_timestamp = | |
215 GetRecordedRtpTimestamp(cast_feedback.ack_frame_id); | |
216 ack_event->frame_id = cast_feedback.ack_frame_id; | |
217 cast_environment_->logger()->DispatchFrameEvent(std::move(ack_event)); | |
218 | |
219 const bool is_acked_out_of_order = | |
220 cast_feedback.ack_frame_id < latest_acked_frame_id_; | |
221 VLOG(2) << SENDER_SSRC << "Received ACK" | |
222 << (is_acked_out_of_order ? " out-of-order" : "") << " for frame " | |
223 << cast_feedback.ack_frame_id; | |
224 if (is_acked_out_of_order) { | |
225 TRACE_EVENT_INSTANT2( | |
226 "cast.stream", "ACK out of order", TRACE_EVENT_SCOPE_THREAD, | |
227 "ack_frame_id", cast_feedback.ack_frame_id.lower_32_bits(), | |
228 "latest_acked_frame_id", latest_acked_frame_id_.lower_32_bits()); | |
229 } else if (latest_acked_frame_id_ < cast_feedback.ack_frame_id) { | |
230 // Cancel resends of acked frames. | |
231 std::vector<media::cast::FrameId> frames_to_cancel; | |
232 frames_to_cancel.reserve(cast_feedback.ack_frame_id - | |
233 latest_acked_frame_id_); | |
234 do { | |
235 ++latest_acked_frame_id_; | |
236 frames_to_cancel.push_back(latest_acked_frame_id_); | |
237 // This is a good place to match the trace for frame ids | |
238 // since this ensures we not only track frame ids that are | |
239 // implicitly ACKed, but also handles duplicate ACKs | |
240 TRACE_EVENT_ASYNC_END1( | |
241 "cast.stream", is_audio_ ? "Audio Transport" : "Video Transport", | |
242 latest_acked_frame_id_.lower_32_bits(), "RTT_usecs", | |
243 current_round_trip_time_.InMicroseconds()); | |
244 } while (latest_acked_frame_id_ < cast_feedback.ack_frame_id); | |
245 transport_->CancelSendingFrames(ssrc_, frames_to_cancel); | |
246 } | |
247 } | |
248 | |
249 void CastRemotingSender::SendFrame() { | |
250 DCHECK(cast_environment_->CurrentlyOn(media::cast::CastEnvironment::MAIN)); | |
251 | |
252 if (NumberOfFramesInFlight() >= media::cast::kMaxUnackedFrames) { | |
253 // TODO(xjz): Delay the sending of this frame and stop reading the next | |
254 // frame data. | |
255 return; | |
256 } | |
257 | |
258 VLOG(2) << SENDER_SSRC | |
259 << "About to send another frame: last_sent=" << last_sent_frame_id_ | |
260 << ", latest_acked=" << latest_acked_frame_id_; | |
261 | |
262 const media::cast::FrameId frame_id = last_sent_frame_id_ + 1; | |
263 const bool is_first_frame_to_be_sent = last_send_time_.is_null(); | |
264 | |
265 base::TimeTicks last_frame_reference_time = last_send_time_; | |
266 last_send_time_ = cast_environment_->Clock()->NowTicks(); | |
267 last_sent_frame_id_ = frame_id; | |
268 // If this is the first frame about to be sent, fake the value of | |
269 // |latest_acked_frame_id_| to indicate the receiver starts out all caught up. | |
270 // Also, schedule the periodic frame re-send checks. | |
271 if (is_first_frame_to_be_sent) | |
272 ScheduleNextResendCheck(); | |
273 | |
274 DVLOG(3) << "Sending remoting frame, id = " << frame_id; | |
275 | |
276 media::cast::EncodedFrame remoting_frame; | |
277 remoting_frame.frame_id = frame_id; | |
278 remoting_frame.dependency = | |
279 (is_first_frame_to_be_sent || last_frame_was_canceled_) | |
280 ? media::cast::EncodedFrame::KEY | |
281 : media::cast::EncodedFrame::DEPENDENT; | |
282 remoting_frame.referenced_frame_id = | |
283 remoting_frame.dependency == media::cast::EncodedFrame::KEY | |
284 ? frame_id | |
285 : frame_id - 1; | |
286 remoting_frame.reference_time = last_send_time_; | |
287 media::cast::RtpTimeTicks last_frame_rtp_timestamp; | |
288 if (is_first_frame_to_be_sent) { | |
289 last_frame_reference_time = remoting_frame.reference_time; | |
290 last_frame_rtp_timestamp = | |
291 media::cast::RtpTimeTicks() - media::cast::RtpTimeDelta::FromTicks(1); | |
292 } else { | |
293 last_frame_rtp_timestamp = GetRecordedRtpTimestamp(frame_id - 1); | |
294 } | |
295 // Ensure each successive frame's RTP timestamp is unique, but otherwise just | |
296 // base it on the reference time. | |
297 remoting_frame.rtp_timestamp = | |
298 last_frame_rtp_timestamp + | |
299 std::max(media::cast::RtpTimeDelta::FromTicks(1), | |
300 media::cast::RtpTimeDelta::FromTimeDelta( | |
301 remoting_frame.reference_time - last_frame_reference_time, | |
302 media::cast::kRemotingRtpTimebase)); | |
303 remoting_frame.data.swap(next_frame_data_); | |
304 | |
305 std::unique_ptr<media::cast::FrameEvent> remoting_event( | |
306 new media::cast::FrameEvent()); | |
307 remoting_event->timestamp = remoting_frame.reference_time; | |
308 // TODO(xjz): Use a new event type for remoting. | |
309 remoting_event->type = media::cast::FRAME_ENCODED; | |
310 remoting_event->media_type = | |
311 is_audio_ ? media::cast::AUDIO_EVENT : media::cast::VIDEO_EVENT; | |
312 remoting_event->rtp_timestamp = remoting_frame.rtp_timestamp; | |
313 remoting_event->frame_id = frame_id; | |
314 remoting_event->size = remoting_frame.data.length(); | |
315 remoting_event->key_frame = | |
316 remoting_frame.dependency == media::cast::EncodedFrame::KEY; | |
317 cast_environment_->logger()->DispatchFrameEvent(std::move(remoting_event)); | |
318 | |
319 RecordLatestFrameTimestamps(frame_id, remoting_frame.rtp_timestamp); | |
320 last_frame_was_canceled_ = false; | |
321 | |
322 transport_->InsertFrame(ssrc_, remoting_frame); | |
323 } | |
324 | |
325 void CastRemotingSender::CancelFramesInFlight() { | |
326 DCHECK(cast_environment_->CurrentlyOn(media::cast::CastEnvironment::MAIN)); | |
327 | |
328 // Force to clear internal memory. | |
dcheng
2016/09/13 01:22:20
Nit: remove this comment, since I think STLClearOb
xjz
2016/09/13 17:06:10
Done.
| |
329 base::STLClearObject(&next_frame_data_); | |
330 | |
331 if (latest_acked_frame_id_ < last_sent_frame_id_) { | |
332 std::vector<media::cast::FrameId> frames_to_cancel; | |
333 do { | |
334 ++latest_acked_frame_id_; | |
335 frames_to_cancel.push_back(latest_acked_frame_id_); | |
336 } while (latest_acked_frame_id_ < last_sent_frame_id_); | |
337 transport_->CancelSendingFrames(ssrc_, frames_to_cancel); | |
338 } | |
339 | |
340 last_frame_was_canceled_ = true; | |
341 } | |
342 | |
343 } // namespace cast | |
OLD | NEW |