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/sender/frame_sender.h" | 5 #include "media/cast/sender/frame_sender.h" |
6 | 6 |
7 #include <limits> | 7 #include <limits> |
8 | 8 |
9 #include "base/trace_event/trace_event.h" | 9 #include "base/trace_event/trace_event.h" |
10 #include "media/cast/cast_defines.h" | 10 #include "media/cast/cast_defines.h" |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
51 duplicate_ack_counter_(0), | 51 duplicate_ack_counter_(0), |
52 congestion_control_(congestion_control), | 52 congestion_control_(congestion_control), |
53 rtp_timebase_(rtp_timebase), | 53 rtp_timebase_(rtp_timebase), |
54 is_audio_(is_audio), | 54 is_audio_(is_audio), |
55 weak_factory_(this) { | 55 weak_factory_(this) { |
56 DCHECK(transport_sender_); | 56 DCHECK(transport_sender_); |
57 DCHECK_GT(rtp_timebase_, 0); | 57 DCHECK_GT(rtp_timebase_, 0); |
58 DCHECK(congestion_control_); | 58 DCHECK(congestion_control_); |
59 SetTargetPlayoutDelay(min_playout_delay_); | 59 SetTargetPlayoutDelay(min_playout_delay_); |
60 send_target_playout_delay_ = false; | 60 send_target_playout_delay_ = false; |
61 memset(frame_rtp_timestamps_, 0, sizeof(frame_rtp_timestamps_)); | |
62 } | 61 } |
63 | 62 |
64 FrameSender::~FrameSender() { | 63 FrameSender::~FrameSender() { |
65 } | 64 } |
66 | 65 |
67 void FrameSender::ScheduleNextRtcpReport() { | 66 void FrameSender::ScheduleNextRtcpReport() { |
68 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 67 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
69 | 68 |
70 cast_environment_->PostDelayedTask( | 69 cast_environment_->PostDelayedTask( |
71 CastEnvironment::MAIN, FROM_HERE, | 70 CastEnvironment::MAIN, FROM_HERE, |
(...skipping 10 matching lines...) Expand all Loading... |
82 | 81 |
83 // Create lip-sync info for the sender report. The last sent frame's | 82 // Create lip-sync info for the sender report. The last sent frame's |
84 // reference time and RTP timestamp are used to estimate an RTP timestamp in | 83 // reference time and RTP timestamp are used to estimate an RTP timestamp in |
85 // terms of "now." Note that |now| is never likely to be precise to an exact | 84 // terms of "now." Note that |now| is never likely to be precise to an exact |
86 // frame boundary; and so the computation here will result in a | 85 // frame boundary; and so the computation here will result in a |
87 // |now_as_rtp_timestamp| value that is rarely equal to any one emitted by the | 86 // |now_as_rtp_timestamp| value that is rarely equal to any one emitted by the |
88 // encoder. | 87 // encoder. |
89 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | 88 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); |
90 const base::TimeDelta time_delta = | 89 const base::TimeDelta time_delta = |
91 now - GetRecordedReferenceTime(last_sent_frame_id_); | 90 now - GetRecordedReferenceTime(last_sent_frame_id_); |
92 const int64_t rtp_delta = TimeDeltaToRtpDelta(time_delta, rtp_timebase_); | 91 const RtpTimeDelta rtp_delta = |
93 const uint32_t now_as_rtp_timestamp = | 92 RtpTimeDelta::FromTimeDelta(time_delta, rtp_timebase_); |
94 GetRecordedRtpTimestamp(last_sent_frame_id_) + | 93 const RtpTimeTicks now_as_rtp_timestamp = |
95 static_cast<uint32_t>(rtp_delta); | 94 GetRecordedRtpTimestamp(last_sent_frame_id_) + rtp_delta; |
96 transport_sender_->SendSenderReport(ssrc_, now, now_as_rtp_timestamp); | 95 transport_sender_->SendSenderReport(ssrc_, now, now_as_rtp_timestamp); |
97 | 96 |
98 if (schedule_future_reports) | 97 if (schedule_future_reports) |
99 ScheduleNextRtcpReport(); | 98 ScheduleNextRtcpReport(); |
100 } | 99 } |
101 | 100 |
102 void FrameSender::OnMeasuredRoundTripTime(base::TimeDelta rtt) { | 101 void FrameSender::OnMeasuredRoundTripTime(base::TimeDelta rtt) { |
103 DCHECK(rtt > base::TimeDelta()); | 102 DCHECK(rtt > base::TimeDelta()); |
104 current_round_trip_time_ = rtt; | 103 current_round_trip_time_ = rtt; |
105 } | 104 } |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
158 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 157 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
159 DCHECK(!last_send_time_.is_null()); | 158 DCHECK(!last_send_time_.is_null()); |
160 VLOG(1) << SENDER_SSRC << "Resending last packet of frame " | 159 VLOG(1) << SENDER_SSRC << "Resending last packet of frame " |
161 << last_sent_frame_id_ << " to kick-start."; | 160 << last_sent_frame_id_ << " to kick-start."; |
162 last_send_time_ = cast_environment_->Clock()->NowTicks(); | 161 last_send_time_ = cast_environment_->Clock()->NowTicks(); |
163 transport_sender_->ResendFrameForKickstart(ssrc_, last_sent_frame_id_); | 162 transport_sender_->ResendFrameForKickstart(ssrc_, last_sent_frame_id_); |
164 } | 163 } |
165 | 164 |
166 void FrameSender::RecordLatestFrameTimestamps(uint32_t frame_id, | 165 void FrameSender::RecordLatestFrameTimestamps(uint32_t frame_id, |
167 base::TimeTicks reference_time, | 166 base::TimeTicks reference_time, |
168 RtpTimestamp rtp_timestamp) { | 167 RtpTimeTicks rtp_timestamp) { |
169 DCHECK(!reference_time.is_null()); | 168 DCHECK(!reference_time.is_null()); |
170 frame_reference_times_[frame_id % arraysize(frame_reference_times_)] = | 169 frame_reference_times_[frame_id % arraysize(frame_reference_times_)] = |
171 reference_time; | 170 reference_time; |
172 frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)] = | 171 frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)] = |
173 rtp_timestamp; | 172 rtp_timestamp; |
174 } | 173 } |
175 | 174 |
176 base::TimeTicks FrameSender::GetRecordedReferenceTime(uint32_t frame_id) const { | 175 base::TimeTicks FrameSender::GetRecordedReferenceTime(uint32_t frame_id) const { |
177 return frame_reference_times_[frame_id % arraysize(frame_reference_times_)]; | 176 return frame_reference_times_[frame_id % arraysize(frame_reference_times_)]; |
178 } | 177 } |
179 | 178 |
180 RtpTimestamp FrameSender::GetRecordedRtpTimestamp(uint32_t frame_id) const { | 179 RtpTimeTicks FrameSender::GetRecordedRtpTimestamp(uint32_t frame_id) const { |
181 return frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)]; | 180 return frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)]; |
182 } | 181 } |
183 | 182 |
184 int FrameSender::GetUnacknowledgedFrameCount() const { | 183 int FrameSender::GetUnacknowledgedFrameCount() const { |
185 const int count = | 184 const int count = |
186 static_cast<int32_t>(last_sent_frame_id_ - latest_acked_frame_id_); | 185 static_cast<int32_t>(last_sent_frame_id_ - latest_acked_frame_id_); |
187 DCHECK_GE(count, 0); | 186 DCHECK_GE(count, 0); |
188 return count; | 187 return count; |
189 } | 188 } |
190 | 189 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 | 235 |
237 RecordLatestFrameTimestamps(frame_id, | 236 RecordLatestFrameTimestamps(frame_id, |
238 encoded_frame->reference_time, | 237 encoded_frame->reference_time, |
239 encoded_frame->rtp_timestamp); | 238 encoded_frame->rtp_timestamp); |
240 | 239 |
241 if (!is_audio_) { | 240 if (!is_audio_) { |
242 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc | 241 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc |
243 TRACE_EVENT_INSTANT1( | 242 TRACE_EVENT_INSTANT1( |
244 "cast_perf_test", "VideoFrameEncoded", | 243 "cast_perf_test", "VideoFrameEncoded", |
245 TRACE_EVENT_SCOPE_THREAD, | 244 TRACE_EVENT_SCOPE_THREAD, |
246 "rtp_timestamp", encoded_frame->rtp_timestamp); | 245 "rtp_timestamp", encoded_frame->rtp_timestamp.lower_32_bits()); |
247 } | 246 } |
248 | 247 |
249 // At the start of the session, it's important to send reports before each | 248 // At the start of the session, it's important to send reports before each |
250 // frame so that the receiver can properly compute playout times. The reason | 249 // frame so that the receiver can properly compute playout times. The reason |
251 // more than one report is sent is because transmission is not guaranteed, | 250 // more than one report is sent is because transmission is not guaranteed, |
252 // only best effort, so send enough that one should almost certainly get | 251 // only best effort, so send enough that one should almost certainly get |
253 // through. | 252 // through. |
254 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) { | 253 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) { |
255 // SendRtcpReport() will schedule future reports to be made if this is the | 254 // SendRtcpReport() will schedule future reports to be made if this is the |
256 // last "aggressive report." | 255 // last "aggressive report." |
257 ++num_aggressive_rtcp_reports_sent_; | 256 ++num_aggressive_rtcp_reports_sent_; |
258 const bool is_last_aggressive_report = | 257 const bool is_last_aggressive_report = |
259 (num_aggressive_rtcp_reports_sent_ == kNumAggressiveReportsSentAtStart); | 258 (num_aggressive_rtcp_reports_sent_ == kNumAggressiveReportsSentAtStart); |
260 VLOG_IF(1, is_last_aggressive_report) | 259 VLOG_IF(1, is_last_aggressive_report) |
261 << SENDER_SSRC << "Sending last aggressive report."; | 260 << SENDER_SSRC << "Sending last aggressive report."; |
262 SendRtcpReport(is_last_aggressive_report); | 261 SendRtcpReport(is_last_aggressive_report); |
263 } | 262 } |
264 | 263 |
265 congestion_control_->SendFrameToTransport( | 264 congestion_control_->SendFrameToTransport( |
266 frame_id, encoded_frame->data.size() * 8, last_send_time_); | 265 frame_id, encoded_frame->data.size() * 8, last_send_time_); |
267 | 266 |
268 if (send_target_playout_delay_) { | 267 if (send_target_playout_delay_) { |
269 encoded_frame->new_playout_delay_ms = | 268 encoded_frame->new_playout_delay_ms = |
270 target_playout_delay_.InMilliseconds(); | 269 target_playout_delay_.InMilliseconds(); |
271 } | 270 } |
272 | 271 |
273 TRACE_EVENT_ASYNC_BEGIN1("cast.stream", | 272 TRACE_EVENT_ASYNC_BEGIN1("cast.stream", |
274 is_audio_ ? "Audio Transport" : "Video Transport", | 273 is_audio_ ? "Audio Transport" : "Video Transport", |
275 frame_id, | 274 frame_id, |
276 "rtp_timestamp", encoded_frame->rtp_timestamp); | 275 "rtp_timestamp", encoded_frame->rtp_timestamp.lower_32_bits()); |
277 transport_sender_->InsertFrame(ssrc_, *encoded_frame); | 276 transport_sender_->InsertFrame(ssrc_, *encoded_frame); |
278 } | 277 } |
279 | 278 |
280 void FrameSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) { | 279 void FrameSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) { |
281 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 280 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
282 | 281 |
283 const bool have_valid_rtt = current_round_trip_time_ > base::TimeDelta(); | 282 const bool have_valid_rtt = current_round_trip_time_ > base::TimeDelta(); |
284 if (have_valid_rtt) { | 283 if (have_valid_rtt) { |
285 congestion_control_->UpdateRtt(current_round_trip_time_); | 284 congestion_control_->UpdateRtt(current_round_trip_time_); |
286 | 285 |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
407 VLOG(1) << SENDER_SSRC << "Dropping: In-flight duration would be too high."; | 406 VLOG(1) << SENDER_SSRC << "Dropping: In-flight duration would be too high."; |
408 return true; | 407 return true; |
409 } | 408 } |
410 | 409 |
411 // Next frame is accepted. | 410 // Next frame is accepted. |
412 return false; | 411 return false; |
413 } | 412 } |
414 | 413 |
415 } // namespace cast | 414 } // namespace cast |
416 } // namespace media | 415 } // namespace media |
OLD | NEW |