| 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 <algorithm> | 7 #include <algorithm> |
| 8 #include <limits> | 8 #include <limits> |
| 9 #include <utility> | 9 #include <utility> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 DCHECK_GT(rtp_timebase_, 0); | 65 DCHECK_GT(rtp_timebase_, 0); |
| 66 DCHECK(congestion_control_); | 66 DCHECK(congestion_control_); |
| 67 // We assume animated content to begin with since that is the common use | 67 // We assume animated content to begin with since that is the common use |
| 68 // case today. | 68 // case today. |
| 69 VLOG(1) << SENDER_SSRC << "min latency " | 69 VLOG(1) << SENDER_SSRC << "min latency " |
| 70 << min_playout_delay_.InMilliseconds() << "max latency " | 70 << min_playout_delay_.InMilliseconds() << "max latency " |
| 71 << max_playout_delay.InMilliseconds() << "animated latency " | 71 << max_playout_delay.InMilliseconds() << "animated latency " |
| 72 << animated_playout_delay.InMilliseconds(); | 72 << animated_playout_delay.InMilliseconds(); |
| 73 SetTargetPlayoutDelay(animated_playout_delay_); | 73 SetTargetPlayoutDelay(animated_playout_delay_); |
| 74 send_target_playout_delay_ = false; | 74 send_target_playout_delay_ = false; |
| 75 memset(frame_rtp_timestamps_, 0, sizeof(frame_rtp_timestamps_)); | |
| 76 } | 75 } |
| 77 | 76 |
| 78 FrameSender::~FrameSender() { | 77 FrameSender::~FrameSender() { |
| 79 } | 78 } |
| 80 | 79 |
| 81 void FrameSender::ScheduleNextRtcpReport() { | 80 void FrameSender::ScheduleNextRtcpReport() { |
| 82 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 81 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 83 | 82 |
| 84 cast_environment_->PostDelayedTask( | 83 cast_environment_->PostDelayedTask( |
| 85 CastEnvironment::MAIN, FROM_HERE, | 84 CastEnvironment::MAIN, FROM_HERE, |
| (...skipping 10 matching lines...) Expand all Loading... |
| 96 | 95 |
| 97 // Create lip-sync info for the sender report. The last sent frame's | 96 // Create lip-sync info for the sender report. The last sent frame's |
| 98 // reference time and RTP timestamp are used to estimate an RTP timestamp in | 97 // reference time and RTP timestamp are used to estimate an RTP timestamp in |
| 99 // terms of "now." Note that |now| is never likely to be precise to an exact | 98 // terms of "now." Note that |now| is never likely to be precise to an exact |
| 100 // frame boundary; and so the computation here will result in a | 99 // frame boundary; and so the computation here will result in a |
| 101 // |now_as_rtp_timestamp| value that is rarely equal to any one emitted by the | 100 // |now_as_rtp_timestamp| value that is rarely equal to any one emitted by the |
| 102 // encoder. | 101 // encoder. |
| 103 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | 102 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); |
| 104 const base::TimeDelta time_delta = | 103 const base::TimeDelta time_delta = |
| 105 now - GetRecordedReferenceTime(last_sent_frame_id_); | 104 now - GetRecordedReferenceTime(last_sent_frame_id_); |
| 106 const int64_t rtp_delta = TimeDeltaToRtpDelta(time_delta, rtp_timebase_); | 105 const RtpTimeDelta rtp_delta = |
| 107 const uint32_t now_as_rtp_timestamp = | 106 RtpTimeDelta::FromTimeDelta(time_delta, rtp_timebase_); |
| 108 GetRecordedRtpTimestamp(last_sent_frame_id_) + | 107 const RtpTimeTicks now_as_rtp_timestamp = |
| 109 static_cast<uint32_t>(rtp_delta); | 108 GetRecordedRtpTimestamp(last_sent_frame_id_) + rtp_delta; |
| 110 transport_sender_->SendSenderReport(ssrc_, now, now_as_rtp_timestamp); | 109 transport_sender_->SendSenderReport(ssrc_, now, now_as_rtp_timestamp); |
| 111 | 110 |
| 112 if (schedule_future_reports) | 111 if (schedule_future_reports) |
| 113 ScheduleNextRtcpReport(); | 112 ScheduleNextRtcpReport(); |
| 114 } | 113 } |
| 115 | 114 |
| 116 void FrameSender::OnMeasuredRoundTripTime(base::TimeDelta rtt) { | 115 void FrameSender::OnMeasuredRoundTripTime(base::TimeDelta rtt) { |
| 117 DCHECK(rtt > base::TimeDelta()); | 116 DCHECK(rtt > base::TimeDelta()); |
| 118 current_round_trip_time_ = rtt; | 117 current_round_trip_time_ = rtt; |
| 119 } | 118 } |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 172 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 171 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 173 DCHECK(!last_send_time_.is_null()); | 172 DCHECK(!last_send_time_.is_null()); |
| 174 VLOG(1) << SENDER_SSRC << "Resending last packet of frame " | 173 VLOG(1) << SENDER_SSRC << "Resending last packet of frame " |
| 175 << last_sent_frame_id_ << " to kick-start."; | 174 << last_sent_frame_id_ << " to kick-start."; |
| 176 last_send_time_ = cast_environment_->Clock()->NowTicks(); | 175 last_send_time_ = cast_environment_->Clock()->NowTicks(); |
| 177 transport_sender_->ResendFrameForKickstart(ssrc_, last_sent_frame_id_); | 176 transport_sender_->ResendFrameForKickstart(ssrc_, last_sent_frame_id_); |
| 178 } | 177 } |
| 179 | 178 |
| 180 void FrameSender::RecordLatestFrameTimestamps(uint32_t frame_id, | 179 void FrameSender::RecordLatestFrameTimestamps(uint32_t frame_id, |
| 181 base::TimeTicks reference_time, | 180 base::TimeTicks reference_time, |
| 182 RtpTimestamp rtp_timestamp) { | 181 RtpTimeTicks rtp_timestamp) { |
| 183 DCHECK(!reference_time.is_null()); | 182 DCHECK(!reference_time.is_null()); |
| 184 frame_reference_times_[frame_id % arraysize(frame_reference_times_)] = | 183 frame_reference_times_[frame_id % arraysize(frame_reference_times_)] = |
| 185 reference_time; | 184 reference_time; |
| 186 frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)] = | 185 frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)] = |
| 187 rtp_timestamp; | 186 rtp_timestamp; |
| 188 } | 187 } |
| 189 | 188 |
| 190 base::TimeTicks FrameSender::GetRecordedReferenceTime(uint32_t frame_id) const { | 189 base::TimeTicks FrameSender::GetRecordedReferenceTime(uint32_t frame_id) const { |
| 191 return frame_reference_times_[frame_id % arraysize(frame_reference_times_)]; | 190 return frame_reference_times_[frame_id % arraysize(frame_reference_times_)]; |
| 192 } | 191 } |
| 193 | 192 |
| 194 RtpTimestamp FrameSender::GetRecordedRtpTimestamp(uint32_t frame_id) const { | 193 RtpTimeTicks FrameSender::GetRecordedRtpTimestamp(uint32_t frame_id) const { |
| 195 return frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)]; | 194 return frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)]; |
| 196 } | 195 } |
| 197 | 196 |
| 198 int FrameSender::GetUnacknowledgedFrameCount() const { | 197 int FrameSender::GetUnacknowledgedFrameCount() const { |
| 199 const int count = | 198 const int count = |
| 200 static_cast<int32_t>(last_sent_frame_id_ - latest_acked_frame_id_); | 199 static_cast<int32_t>(last_sent_frame_id_ - latest_acked_frame_id_); |
| 201 DCHECK_GE(count, 0); | 200 DCHECK_GE(count, 0); |
| 202 return count; | 201 return count; |
| 203 } | 202 } |
| 204 | 203 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 250 | 249 |
| 251 RecordLatestFrameTimestamps(frame_id, | 250 RecordLatestFrameTimestamps(frame_id, |
| 252 encoded_frame->reference_time, | 251 encoded_frame->reference_time, |
| 253 encoded_frame->rtp_timestamp); | 252 encoded_frame->rtp_timestamp); |
| 254 | 253 |
| 255 if (!is_audio_) { | 254 if (!is_audio_) { |
| 256 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc | 255 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc |
| 257 TRACE_EVENT_INSTANT1( | 256 TRACE_EVENT_INSTANT1( |
| 258 "cast_perf_test", "VideoFrameEncoded", | 257 "cast_perf_test", "VideoFrameEncoded", |
| 259 TRACE_EVENT_SCOPE_THREAD, | 258 TRACE_EVENT_SCOPE_THREAD, |
| 260 "rtp_timestamp", encoded_frame->rtp_timestamp); | 259 "rtp_timestamp", encoded_frame->rtp_timestamp.lower_32_bits()); |
| 261 } | 260 } |
| 262 | 261 |
| 263 // At the start of the session, it's important to send reports before each | 262 // At the start of the session, it's important to send reports before each |
| 264 // frame so that the receiver can properly compute playout times. The reason | 263 // frame so that the receiver can properly compute playout times. The reason |
| 265 // more than one report is sent is because transmission is not guaranteed, | 264 // more than one report is sent is because transmission is not guaranteed, |
| 266 // only best effort, so send enough that one should almost certainly get | 265 // only best effort, so send enough that one should almost certainly get |
| 267 // through. | 266 // through. |
| 268 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) { | 267 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) { |
| 269 // SendRtcpReport() will schedule future reports to be made if this is the | 268 // SendRtcpReport() will schedule future reports to be made if this is the |
| 270 // last "aggressive report." | 269 // last "aggressive report." |
| 271 ++num_aggressive_rtcp_reports_sent_; | 270 ++num_aggressive_rtcp_reports_sent_; |
| 272 const bool is_last_aggressive_report = | 271 const bool is_last_aggressive_report = |
| 273 (num_aggressive_rtcp_reports_sent_ == kNumAggressiveReportsSentAtStart); | 272 (num_aggressive_rtcp_reports_sent_ == kNumAggressiveReportsSentAtStart); |
| 274 VLOG_IF(1, is_last_aggressive_report) | 273 VLOG_IF(1, is_last_aggressive_report) |
| 275 << SENDER_SSRC << "Sending last aggressive report."; | 274 << SENDER_SSRC << "Sending last aggressive report."; |
| 276 SendRtcpReport(is_last_aggressive_report); | 275 SendRtcpReport(is_last_aggressive_report); |
| 277 } | 276 } |
| 278 | 277 |
| 279 congestion_control_->SendFrameToTransport( | 278 congestion_control_->SendFrameToTransport( |
| 280 frame_id, encoded_frame->data.size() * 8, last_send_time_); | 279 frame_id, encoded_frame->data.size() * 8, last_send_time_); |
| 281 | 280 |
| 282 if (send_target_playout_delay_) { | 281 if (send_target_playout_delay_) { |
| 283 encoded_frame->new_playout_delay_ms = | 282 encoded_frame->new_playout_delay_ms = |
| 284 target_playout_delay_.InMilliseconds(); | 283 target_playout_delay_.InMilliseconds(); |
| 285 } | 284 } |
| 286 | 285 |
| 287 TRACE_EVENT_ASYNC_BEGIN1("cast.stream", | 286 TRACE_EVENT_ASYNC_BEGIN1("cast.stream", |
| 288 is_audio_ ? "Audio Transport" : "Video Transport", | 287 is_audio_ ? "Audio Transport" : "Video Transport", |
| 289 frame_id, | 288 frame_id, |
| 290 "rtp_timestamp", encoded_frame->rtp_timestamp); | 289 "rtp_timestamp", encoded_frame->rtp_timestamp.lower_32_bits()); |
| 291 transport_sender_->InsertFrame(ssrc_, *encoded_frame); | 290 transport_sender_->InsertFrame(ssrc_, *encoded_frame); |
| 292 } | 291 } |
| 293 | 292 |
| 294 void FrameSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) { | 293 void FrameSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) { |
| 295 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 294 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 296 | 295 |
| 297 const bool have_valid_rtt = current_round_trip_time_ > base::TimeDelta(); | 296 const bool have_valid_rtt = current_round_trip_time_ > base::TimeDelta(); |
| 298 if (have_valid_rtt) { | 297 if (have_valid_rtt) { |
| 299 congestion_control_->UpdateRtt(current_round_trip_time_); | 298 congestion_control_->UpdateRtt(current_round_trip_time_); |
| 300 | 299 |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 421 VLOG(1) << SENDER_SSRC << "Dropping: In-flight duration would be too high."; | 420 VLOG(1) << SENDER_SSRC << "Dropping: In-flight duration would be too high."; |
| 422 return true; | 421 return true; |
| 423 } | 422 } |
| 424 | 423 |
| 425 // Next frame is accepted. | 424 // Next frame is accepted. |
| 426 return false; | 425 return false; |
| 427 } | 426 } |
| 428 | 427 |
| 429 } // namespace cast | 428 } // namespace cast |
| 430 } // namespace media | 429 } // namespace media |
| OLD | NEW |