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

Side by Side Diff: media/cast/sender/frame_sender.cc

Issue 542883004: Cast: Merge common functionality from audio/video sender into frame_sender. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: merge Created 6 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
« no previous file with comments | « media/cast/sender/frame_sender.h ('k') | media/cast/sender/video_sender.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/sender/frame_sender.h" 5 #include "media/cast/sender/frame_sender.h"
6 6
7 #include "base/debug/trace_event.h"
8
7 namespace media { 9 namespace media {
8 namespace cast { 10 namespace cast {
9 namespace { 11 namespace {
12
10 const int kMinSchedulingDelayMs = 1; 13 const int kMinSchedulingDelayMs = 1;
14 const int kNumAggressiveReportsSentAtStart = 100;
15
11 } // namespace 16 } // namespace
12 17
13 FrameSender::FrameSender(scoped_refptr<CastEnvironment> cast_environment, 18 FrameSender::FrameSender(scoped_refptr<CastEnvironment> cast_environment,
19 bool is_audio,
14 CastTransportSender* const transport_sender, 20 CastTransportSender* const transport_sender,
15 base::TimeDelta rtcp_interval, 21 base::TimeDelta rtcp_interval,
16 int rtp_timebase, 22 int rtp_timebase,
17 uint32 ssrc, 23 uint32 ssrc,
18 double max_frame_rate, 24 double max_frame_rate,
19 base::TimeDelta playout_delay) 25 base::TimeDelta playout_delay,
26 CongestionControl* congestion_control)
20 : cast_environment_(cast_environment), 27 : cast_environment_(cast_environment),
21 transport_sender_(transport_sender), 28 transport_sender_(transport_sender),
22 ssrc_(ssrc), 29 ssrc_(ssrc),
23 rtt_available_(false), 30 rtt_available_(false),
24 rtcp_interval_(rtcp_interval), 31 rtcp_interval_(rtcp_interval),
25 max_frame_rate_(max_frame_rate), 32 max_frame_rate_(max_frame_rate),
33 frames_in_encoder_(0),
26 num_aggressive_rtcp_reports_sent_(0), 34 num_aggressive_rtcp_reports_sent_(0),
27 last_sent_frame_id_(0), 35 last_sent_frame_id_(0),
28 latest_acked_frame_id_(0), 36 latest_acked_frame_id_(0),
29 duplicate_ack_counter_(0), 37 duplicate_ack_counter_(0),
30 rtp_timebase_(rtp_timebase), 38 rtp_timebase_(rtp_timebase),
39 congestion_control_(congestion_control),
40 is_audio_(is_audio),
31 weak_factory_(this) { 41 weak_factory_(this) {
32 DCHECK_GT(rtp_timebase_, 0); 42 DCHECK_GT(rtp_timebase_, 0);
33 SetTargetPlayoutDelay(playout_delay); 43 SetTargetPlayoutDelay(playout_delay);
34 send_target_playout_delay_ = false; 44 send_target_playout_delay_ = false;
35 memset(frame_rtp_timestamps_, 0, sizeof(frame_rtp_timestamps_)); 45 memset(frame_rtp_timestamps_, 0, sizeof(frame_rtp_timestamps_));
36 } 46 }
37 47
38 FrameSender::~FrameSender() { 48 FrameSender::~FrameSender() {
39 } 49 }
40 50
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 } 161 }
152 162
153 base::TimeTicks FrameSender::GetRecordedReferenceTime(uint32 frame_id) const { 163 base::TimeTicks FrameSender::GetRecordedReferenceTime(uint32 frame_id) const {
154 return frame_reference_times_[frame_id % arraysize(frame_reference_times_)]; 164 return frame_reference_times_[frame_id % arraysize(frame_reference_times_)];
155 } 165 }
156 166
157 RtpTimestamp FrameSender::GetRecordedRtpTimestamp(uint32 frame_id) const { 167 RtpTimestamp FrameSender::GetRecordedRtpTimestamp(uint32 frame_id) const {
158 return frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)]; 168 return frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)];
159 } 169 }
160 170
171
172 void FrameSender::SendEncodedFrame(
173 int requested_bitrate_before_encode,
174 scoped_ptr<EncodedFrame> encoded_frame) {
175 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
176
177 DCHECK_GT(frames_in_encoder_, 0) << " is_audio: " << is_audio_;
178 frames_in_encoder_--;
179
180 const uint32 frame_id = encoded_frame->frame_id;
181
182 const bool is_first_frame_to_be_sent = last_send_time_.is_null();
183 last_send_time_ = cast_environment_->Clock()->NowTicks();
184 last_sent_frame_id_ = frame_id;
185 // If this is the first frame about to be sent, fake the value of
186 // |latest_acked_frame_id_| to indicate the receiver starts out all caught up.
187 // Also, schedule the periodic frame re-send checks.
188 if (is_first_frame_to_be_sent) {
189 latest_acked_frame_id_ = frame_id - 1;
190 ScheduleNextResendCheck();
191 }
192
193 VLOG_IF(1, encoded_frame->dependency == EncodedFrame::KEY)
194 << "Send encoded key frame; frame_id: " << frame_id;
195
196 cast_environment_->Logging()->InsertEncodedFrameEvent(
197 last_send_time_, FRAME_ENCODED,
198 is_audio_ ? AUDIO_EVENT : VIDEO_EVENT,
199 encoded_frame->rtp_timestamp,
200 frame_id, static_cast<int>(encoded_frame->data.size()),
201 encoded_frame->dependency == EncodedFrame::KEY,
202 requested_bitrate_before_encode);
203
204 RecordLatestFrameTimestamps(frame_id,
205 encoded_frame->reference_time,
206 encoded_frame->rtp_timestamp);
207
208 if (!is_audio_) {
209 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc
210 TRACE_EVENT_INSTANT1(
211 "cast_perf_test", "VideoFrameEncoded",
212 TRACE_EVENT_SCOPE_THREAD,
213 "rtp_timestamp", encoded_frame->rtp_timestamp);
214 }
215
216 // At the start of the session, it's important to send reports before each
217 // frame so that the receiver can properly compute playout times. The reason
218 // more than one report is sent is because transmission is not guaranteed,
219 // only best effort, so send enough that one should almost certainly get
220 // through.
221 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) {
222 // SendRtcpReport() will schedule future reports to be made if this is the
223 // last "aggressive report."
224 ++num_aggressive_rtcp_reports_sent_;
225 const bool is_last_aggressive_report =
226 (num_aggressive_rtcp_reports_sent_ == kNumAggressiveReportsSentAtStart);
227 VLOG_IF(1, is_last_aggressive_report) << "Sending last aggressive report.";
228 SendRtcpReport(is_last_aggressive_report);
229 }
230
231 congestion_control_->SendFrameToTransport(
232 frame_id, encoded_frame->data.size() * 8, last_send_time_);
233
234 if (send_target_playout_delay_) {
235 encoded_frame->new_playout_delay_ms =
236 target_playout_delay_.InMilliseconds();
237 }
238 transport_sender_->InsertFrame(ssrc_, *encoded_frame);
239 }
240
241 void FrameSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) {
242 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
243
244 base::TimeDelta rtt;
245 base::TimeDelta avg_rtt;
246 base::TimeDelta min_rtt;
247 base::TimeDelta max_rtt;
248 if (is_rtt_available()) {
249 rtt = rtt_;
250 avg_rtt = avg_rtt_;
251 min_rtt = min_rtt_;
252 max_rtt = max_rtt_;
253
254 congestion_control_->UpdateRtt(rtt);
255
256 // Don't use a RTT lower than our average.
257 rtt = std::max(rtt, avg_rtt);
258
259 // Having the RTT values implies the receiver sent back a receiver report
260 // based on it having received a report from here. Therefore, ensure this
261 // sender stops aggressively sending reports.
262 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) {
263 VLOG(1) << "No longer a need to send reports aggressively (sent "
264 << num_aggressive_rtcp_reports_sent_ << ").";
265 num_aggressive_rtcp_reports_sent_ = kNumAggressiveReportsSentAtStart;
266 ScheduleNextRtcpReport();
267 }
268 } else {
269 // We have no measured value use default.
270 rtt = base::TimeDelta::FromMilliseconds(kStartRttMs);
271 }
272
273 if (last_send_time_.is_null())
274 return; // Cannot get an ACK without having first sent a frame.
275
276 if (cast_feedback.missing_frames_and_packets.empty()) {
277 OnAck(cast_feedback.ack_frame_id);
278
279 // We only count duplicate ACKs when we have sent newer frames.
280 if (latest_acked_frame_id_ == cast_feedback.ack_frame_id &&
281 latest_acked_frame_id_ != last_sent_frame_id_) {
282 duplicate_ack_counter_++;
283 } else {
284 duplicate_ack_counter_ = 0;
285 }
286 // TODO(miu): The values "2" and "3" should be derived from configuration.
287 if (duplicate_ack_counter_ >= 2 && duplicate_ack_counter_ % 3 == 2) {
288 VLOG(1) << "Received duplicate ACK for frame " << latest_acked_frame_id_;
289 ResendForKickstart();
290 }
291 } else {
292 // Only count duplicated ACKs if there is no NACK request in between.
293 // This is to avoid aggresive resend.
294 duplicate_ack_counter_ = 0;
295 }
296
297 base::TimeTicks now = cast_environment_->Clock()->NowTicks();
298 congestion_control_->AckFrame(cast_feedback.ack_frame_id, now);
299
300 cast_environment_->Logging()->InsertFrameEvent(
301 now,
302 FRAME_ACK_RECEIVED,
303 is_audio_ ? AUDIO_EVENT : VIDEO_EVENT,
304 GetRecordedRtpTimestamp(cast_feedback.ack_frame_id),
305 cast_feedback.ack_frame_id);
306
307 const bool is_acked_out_of_order =
308 static_cast<int32>(cast_feedback.ack_frame_id -
309 latest_acked_frame_id_) < 0;
310 VLOG(2) << "Received ACK" << (is_acked_out_of_order ? " out-of-order" : "")
311 << " for frame " << cast_feedback.ack_frame_id;
312 if (!is_acked_out_of_order) {
313 // Cancel resends of acked frames.
314 std::vector<uint32> cancel_sending_frames;
315 while (latest_acked_frame_id_ != cast_feedback.ack_frame_id) {
316 latest_acked_frame_id_++;
317 cancel_sending_frames.push_back(latest_acked_frame_id_);
318 }
319 transport_sender_->CancelSendingFrames(ssrc_, cancel_sending_frames);
320 latest_acked_frame_id_ = cast_feedback.ack_frame_id;
321 }
322 }
323
324 bool FrameSender::ShouldDropNextFrame(base::TimeTicks capture_time) const {
325 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
326 int frames_in_flight = 0;
327 base::TimeDelta duration_in_flight;
328 if (!last_send_time_.is_null()) {
329 frames_in_flight =
330 static_cast<int32>(last_sent_frame_id_ - latest_acked_frame_id_);
331 if (frames_in_flight > 0) {
332 const uint32 oldest_unacked_frame_id = latest_acked_frame_id_ + 1;
333 duration_in_flight =
334 capture_time - GetRecordedReferenceTime(oldest_unacked_frame_id);
335 }
336 }
337 frames_in_flight += frames_in_encoder_;
338 VLOG(2) << frames_in_flight
339 << " frames in flight; last sent: " << last_sent_frame_id_
340 << "; latest acked: " << latest_acked_frame_id_
341 << "; frames in encoder: " << frames_in_encoder_
342 << "; duration in flight: "
343 << duration_in_flight.InMicroseconds() << " usec ("
344 << (target_playout_delay_ > base::TimeDelta() ?
345 100 * duration_in_flight / target_playout_delay_ :
346 kint64max) << "%)";
347 return frames_in_flight >= max_unacked_frames_ ||
348 duration_in_flight >= target_playout_delay_;
349 }
350
161 } // namespace cast 351 } // namespace cast
162 } // namespace media 352 } // namespace media
OLDNEW
« no previous file with comments | « media/cast/sender/frame_sender.h ('k') | media/cast/sender/video_sender.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698