Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(46)

Side by Side Diff: chrome/browser/media/cast_remoting_sender.cc

Issue 2307653002: Adding CastRemotingSender for media remoting. (Closed)
Patch Set: Addressed miu's comments. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
40 : public media::cast::RtcpObserver {
41 public:
42 RemotingRtcpClient(base::WeakPtr<CastRemotingSender> remoting_sender)
dcheng 2016/09/10 02:31:36 Nit: explicit
xjz 2016/09/12 18:22:05 Done.
43 : remoting_sender_(remoting_sender) {}
44
45 ~RemotingRtcpClient() final {}
dcheng 2016/09/10 02:31:36 Optional: you could just mark the class final (cla
xjz 2016/09/12 18:22:05 Done.
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* const transport,
74 const media::cast::CastTransportRtpConfig& config)
75 : remoting_stream_id_(config.rtp_stream_id),
76 cast_environment_(cast_environment),
dcheng 2016/09/10 02:31:36 std::move(), since we're moving ownership here.
xjz 2016/09/12 18:22:05 Done.
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),
dcheng 2016/09/10 02:31:35 Seems like it'd be better to have media::Cast::Fra
xjz 2016/09/12 18:22:05 |last_sent_frame_id_| is initialized to this value
dcheng 2016/09/13 01:22:20 It doesn't have to be done in this CL, but since i
xjz 2016/09/13 17:06:10 Maybe something like media::Cast::FrameId::id_befo
83 duplicate_ack_counter_(0),
84 last_frame_was_canceled_(false),
85 weak_factory_(this) {
86 DCHECK(cast_environment_->CurrentlyOn(media::cast::CastEnvironment::MAIN));
87
88 CastRemotingSender*& pointer_in_map = g_sender_map.Get()[remoting_stream_id_];
89 DCHECK(!pointer_in_map);
90 pointer_in_map = this;
91 transport_->InitializeStream(
92 config, base::MakeUnique<RemotingRtcpClient>(weak_factory_.GetWeakPtr()));
93 }
94
95 CastRemotingSender::~CastRemotingSender() {
96 DCHECK(cast_environment_->CurrentlyOn(media::cast::CastEnvironment::MAIN));
97
98 g_sender_map.Pointer()->erase(remoting_stream_id_);
99 }
100
101 void CastRemotingSender::OnReceivedRtt(base::TimeDelta round_trip_time) {
102 DCHECK(round_trip_time > base::TimeDelta());
dcheng 2016/09/10 02:31:35 Nit: DCHECK_GT. Also,is |round_trip_time| ultimate
xjz 2016/09/12 18:22:05 Done. The |round_trip_time| here comes from the re
103 current_round_trip_time_ = round_trip_time;
104 max_ack_delay_ = 2 * current_round_trip_time_ + kReceiverProcessTime;
105 max_ack_delay_ =
106 std::max(std::min(max_ack_delay_, kMaxAckDelay), kMinAckDelay);
107 }
108
109 void CastRemotingSender::ResendCheck() {
110 DCHECK(cast_environment_->CurrentlyOn(media::cast::CastEnvironment::MAIN));
111
112 DCHECK(!last_send_time_.is_null());
113 const base::TimeDelta time_since_last_send =
114 cast_environment_->Clock()->NowTicks() - last_send_time_;
115 if (time_since_last_send > max_ack_delay_) {
116 if (latest_acked_frame_id_ == last_sent_frame_id_) {
117 // Last frame acked, no point in doing anything.
118 } else {
119 VLOG(1) << SENDER_SSRC
120 << "ACK timeout; last acked frame: " << latest_acked_frame_id_;
121 ResendForKickstart();
122 }
123 }
124 ScheduleNextResendCheck();
125 }
126
127 void CastRemotingSender::ScheduleNextResendCheck() {
128 DCHECK(cast_environment_->CurrentlyOn(media::cast::CastEnvironment::MAIN));
129
130 DCHECK(!last_send_time_.is_null());
131 base::TimeDelta time_to_next =
132 last_send_time_ - cast_environment_->Clock()->NowTicks() + max_ack_delay_;
133 time_to_next = std::max(time_to_next, kMinSchedulingDelay);
134 cast_environment_->PostDelayedTask(
135 media::cast::CastEnvironment::MAIN, FROM_HERE,
136 base::Bind(&CastRemotingSender::ResendCheck, weak_factory_.GetWeakPtr()),
137 time_to_next);
138 }
139
140 void CastRemotingSender::ResendForKickstart() {
141 DCHECK(cast_environment_->CurrentlyOn(media::cast::CastEnvironment::MAIN));
142
143 DCHECK(!last_send_time_.is_null());
144 VLOG(1) << SENDER_SSRC << "Resending last packet of frame "
145 << last_sent_frame_id_ << " to kick-start.";
146 last_send_time_ = cast_environment_->Clock()->NowTicks();
147 transport_->ResendFrameForKickstart(ssrc_, last_sent_frame_id_);
148 }
149
150 // TODO(xjz): We may need to count in the frames acknowledged in
151 // RtcpCastMessage::received_later_frames for more accurate calculation on
152 // available bandwidth. Same logic should apply on
153 // media::cast::FrameSender::GetUnacknowledgedFrameCount().
154 int CastRemotingSender::NumberOfFramesInFlight() const {
155 if (last_send_time_.is_null())
156 return 0;
157 const int count = last_sent_frame_id_ - latest_acked_frame_id_;
158 DCHECK_GE(count, 0);
159 return count;
160 }
161
162 void CastRemotingSender::RecordLatestFrameTimestamps(
163 media::cast::FrameId frame_id,
164 media::cast::RtpTimeTicks rtp_timestamp) {
165 frame_rtp_timestamps_[frame_id.lower_8_bits()] = rtp_timestamp;
166 }
167
168 media::cast::RtpTimeTicks CastRemotingSender::GetRecordedRtpTimestamp(
169 media::cast::FrameId frame_id) const {
170 return frame_rtp_timestamps_[frame_id.lower_8_bits()];
171 }
172
173 void CastRemotingSender::OnReceivedCastMessage(
174 const media::cast::RtcpCastMessage& cast_feedback) {
175 DCHECK(cast_environment_->CurrentlyOn(media::cast::CastEnvironment::MAIN));
176
177 if (last_send_time_.is_null())
178 return; // Cannot get an ACK without having first sent a frame.
179
180 if (cast_feedback.missing_frames_and_packets.empty() &&
181 cast_feedback.received_later_frames.empty()) {
182 if (latest_acked_frame_id_ == cast_feedback.ack_frame_id) {
183 VLOG(1) << SENDER_SSRC << "Received duplicate ACK for frame "
184 << latest_acked_frame_id_;
185 TRACE_EVENT_INSTANT2(
186 "cast.stream", "Duplicate ACK", TRACE_EVENT_SCOPE_THREAD,
187 "ack_frame_id", cast_feedback.ack_frame_id.lower_32_bits(),
188 "last_sent_frame_id", last_sent_frame_id_.lower_32_bits());
189 }
190 // We only count duplicate ACKs when we have sent newer frames.
191 if (latest_acked_frame_id_ == cast_feedback.ack_frame_id &&
192 latest_acked_frame_id_ != last_sent_frame_id_) {
193 duplicate_ack_counter_++;
194 } else {
195 duplicate_ack_counter_ = 0;
196 }
197 // TODO(miu): The values "2" and "3" should be derived from configuration.
198 if (duplicate_ack_counter_ >= 2 && duplicate_ack_counter_ % 3 == 2) {
199 ResendForKickstart();
200 }
201 } else {
202 // Only count duplicated ACKs if there is no NACK request in between.
203 // This is to avoid aggresive resend.
dcheng 2016/09/10 02:31:36 aggresive => aggressive
xjz 2016/09/12 18:22:05 Done.
204 duplicate_ack_counter_ = 0;
205 }
206
207 base::TimeTicks now = cast_environment_->Clock()->NowTicks();
208 std::unique_ptr<media::cast::FrameEvent> ack_event(
dcheng 2016/09/10 02:31:36 Optional: consider writing auto ack_event = base::
xjz 2016/09/12 18:22:05 Done.
209 new 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 latest_acked_frame_id_ = frame_id - 1;
dcheng 2016/09/10 02:31:36 This always starts at media::cast::FrameId::first(
xjz 2016/09/12 18:22:05 Done.
273 ScheduleNextResendCheck();
274 }
275
276 DVLOG(3) << "Sending remoting frame, id = " << frame_id;
277
278 media::cast::EncodedFrame remoting_frame;
279 remoting_frame.frame_id = frame_id;
280 remoting_frame.dependency =
281 (is_first_frame_to_be_sent || last_frame_was_canceled_)
282 ? media::cast::EncodedFrame::KEY
283 : media::cast::EncodedFrame::DEPENDENT;
284 remoting_frame.referenced_frame_id =
285 remoting_frame.dependency == media::cast::EncodedFrame::KEY
286 ? frame_id
287 : frame_id - 1;
288 remoting_frame.reference_time = last_send_time_;
289 media::cast::RtpTimeTicks last_frame_rtp_timestamp;
290 if (is_first_frame_to_be_sent) {
291 last_frame_reference_time = remoting_frame.reference_time;
292 last_frame_rtp_timestamp =
293 media::cast::RtpTimeTicks() - media::cast::RtpTimeDelta::FromTicks(1);
294 } else {
295 last_frame_rtp_timestamp = GetRecordedRtpTimestamp(frame_id - 1);
296 }
297 // Ensure each successive frame's RTP timestamp is unique, but otherwise just
298 // base it on the reference time.
299 remoting_frame.rtp_timestamp =
300 last_frame_rtp_timestamp +
301 std::max(media::cast::RtpTimeDelta::FromTicks(1),
302 media::cast::RtpTimeDelta::FromTimeDelta(
303 remoting_frame.reference_time - last_frame_reference_time,
304 media::cast::kRemotingRtpTimebase));
305 remoting_frame.data.swap(next_frame_data_);
306
307 std::unique_ptr<media::cast::FrameEvent> remoting_event(
308 new media::cast::FrameEvent());
309 remoting_event->timestamp = remoting_frame.reference_time;
310 // TODO(xjz): Use a new event type for remoting.
311 remoting_event->type = media::cast::FRAME_ENCODED;
312 remoting_event->media_type =
313 is_audio_ ? media::cast::AUDIO_EVENT : media::cast::VIDEO_EVENT;
314 remoting_event->rtp_timestamp = remoting_frame.rtp_timestamp;
315 remoting_event->frame_id = frame_id;
316 remoting_event->size = remoting_frame.data.length();
317 remoting_event->key_frame =
318 remoting_frame.dependency == media::cast::EncodedFrame::KEY;
319 remoting_event->target_bitrate = 0; // Not used for remoting.
dcheng 2016/09/10 02:31:36 If they're not used, would it make sense to just l
xjz 2016/09/12 18:22:05 Done.
320 remoting_event->encoder_cpu_utilization = 0; // Not used for remoting.
321 remoting_event->idealized_bitrate_utilization = 0; // Not used for remoting.
322 cast_environment_->logger()->DispatchFrameEvent(std::move(remoting_event));
323
324 RecordLatestFrameTimestamps(frame_id, remoting_frame.rtp_timestamp);
325 last_frame_was_canceled_ = false;
326
327 transport_->InsertFrame(ssrc_, remoting_frame);
328 }
329
330 void CastRemotingSender::CancelFramesInFlight() {
331 DCHECK(cast_environment_->CurrentlyOn(media::cast::CastEnvironment::MAIN));
332
333 // Note: Not calling clear(), in order to force a significant amount of memory
334 // to be freed.
335 std::string().swap(next_frame_data_);
dcheng 2016/09/10 02:31:35 Let's use STLClearObject() from base/stl_util.h he
xjz 2016/09/12 18:22:05 Done.
336
337 if (latest_acked_frame_id_ < last_sent_frame_id_) {
338 std::vector<media::cast::FrameId> frames_to_cancel;
339 do {
340 ++latest_acked_frame_id_;
341 frames_to_cancel.push_back(latest_acked_frame_id_);
342 } while (latest_acked_frame_id_ < last_sent_frame_id_);
343 transport_->CancelSendingFrames(ssrc_, frames_to_cancel);
344 }
345
346 last_frame_was_canceled_ = true;
347 }
348
349 } // namespace cast
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698