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