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 namespace media { | 7 namespace media { |
8 namespace cast { | 8 namespace cast { |
9 namespace { | 9 namespace { |
10 const int kMinSchedulingDelayMs = 1; | 10 const int kMinSchedulingDelayMs = 1; |
11 } // namespace | 11 } // namespace |
12 | 12 |
13 FrameSender::FrameSender(scoped_refptr<CastEnvironment> cast_environment, | 13 FrameSender::FrameSender(scoped_refptr<CastEnvironment> cast_environment, |
14 CastTransportSender* const transport_sender, | 14 CastTransportSender* const transport_sender, |
15 base::TimeDelta rtcp_interval, | 15 base::TimeDelta rtcp_interval, |
16 int frequency, | 16 int rtp_timebase, |
17 uint32 ssrc, | 17 uint32 ssrc, |
18 double max_frame_rate, | 18 double max_frame_rate, |
19 base::TimeDelta playout_delay) | 19 base::TimeDelta playout_delay) |
20 : cast_environment_(cast_environment), | 20 : cast_environment_(cast_environment), |
21 transport_sender_(transport_sender), | 21 transport_sender_(transport_sender), |
22 ssrc_(ssrc), | 22 ssrc_(ssrc), |
23 rtp_timestamp_helper_(frequency), | |
24 rtt_available_(false), | 23 rtt_available_(false), |
25 rtcp_interval_(rtcp_interval), | 24 rtcp_interval_(rtcp_interval), |
26 max_frame_rate_(max_frame_rate), | 25 max_frame_rate_(max_frame_rate), |
27 num_aggressive_rtcp_reports_sent_(0), | 26 num_aggressive_rtcp_reports_sent_(0), |
28 last_sent_frame_id_(0), | 27 last_sent_frame_id_(0), |
29 latest_acked_frame_id_(0), | 28 latest_acked_frame_id_(0), |
30 duplicate_ack_counter_(0), | 29 duplicate_ack_counter_(0), |
| 30 rtp_timebase_(rtp_timebase), |
31 weak_factory_(this) { | 31 weak_factory_(this) { |
| 32 DCHECK_GT(rtp_timebase_, 0); |
32 SetTargetPlayoutDelay(playout_delay); | 33 SetTargetPlayoutDelay(playout_delay); |
33 send_target_playout_delay_ = false; | 34 send_target_playout_delay_ = false; |
34 memset(frame_id_to_rtp_timestamp_, 0, sizeof(frame_id_to_rtp_timestamp_)); | 35 memset(frame_rtp_timestamps_, 0, sizeof(frame_rtp_timestamps_)); |
35 } | 36 } |
36 | 37 |
37 FrameSender::~FrameSender() { | 38 FrameSender::~FrameSender() { |
38 } | 39 } |
39 | 40 |
40 void FrameSender::ScheduleNextRtcpReport() { | 41 void FrameSender::ScheduleNextRtcpReport() { |
41 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 42 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
42 base::TimeDelta time_to_next = rtcp_interval_; | 43 base::TimeDelta time_to_next = rtcp_interval_; |
43 | 44 |
44 time_to_next = std::max( | 45 time_to_next = std::max( |
45 time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); | 46 time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); |
46 | 47 |
47 cast_environment_->PostDelayedTask( | 48 cast_environment_->PostDelayedTask( |
48 CastEnvironment::MAIN, | 49 CastEnvironment::MAIN, |
49 FROM_HERE, | 50 FROM_HERE, |
50 base::Bind(&FrameSender::SendRtcpReport, weak_factory_.GetWeakPtr(), | 51 base::Bind(&FrameSender::SendRtcpReport, weak_factory_.GetWeakPtr(), |
51 true), | 52 true), |
52 time_to_next); | 53 time_to_next); |
53 } | 54 } |
54 | 55 |
55 void FrameSender::SendRtcpReport(bool schedule_future_reports) { | 56 void FrameSender::SendRtcpReport(bool schedule_future_reports) { |
56 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 57 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| 58 |
| 59 // Sanity-check: We should have sent at least the first frame by this point. |
| 60 DCHECK(!last_send_time_.is_null()); |
| 61 |
| 62 // Create lip-sync info for the sender report. The last sent frame's |
| 63 // reference time and RTP timestamp are used to estimate an RTP timestamp in |
| 64 // terms of "now." Note that |now| is never likely to be precise to an exact |
| 65 // frame boundary; and so the computation here will result in a |
| 66 // |now_as_rtp_timestamp| value that is rarely equal to any one emitted by the |
| 67 // encoder. |
57 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | 68 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); |
58 uint32 now_as_rtp_timestamp = 0; | 69 const base::TimeDelta time_delta = |
59 if (rtp_timestamp_helper_.GetCurrentTimeAsRtpTimestamp( | 70 now - GetRecordedReferenceTime(last_sent_frame_id_); |
60 now, &now_as_rtp_timestamp)) { | 71 const int64 rtp_delta = TimeDeltaToRtpDelta(time_delta, rtp_timebase_); |
61 transport_sender_->SendSenderReport(ssrc_, now, now_as_rtp_timestamp); | 72 const uint32 now_as_rtp_timestamp = |
62 } else { | 73 GetRecordedRtpTimestamp(last_sent_frame_id_) + |
63 // |rtp_timestamp_helper_| should have stored a mapping by this point. | 74 static_cast<uint32>(rtp_delta); |
64 NOTREACHED(); | 75 transport_sender_->SendSenderReport(ssrc_, now, now_as_rtp_timestamp); |
65 } | 76 |
66 if (schedule_future_reports) | 77 if (schedule_future_reports) |
67 ScheduleNextRtcpReport(); | 78 ScheduleNextRtcpReport(); |
68 } | 79 } |
69 | 80 |
70 void FrameSender::OnReceivedRtt(base::TimeDelta rtt, | 81 void FrameSender::OnReceivedRtt(base::TimeDelta rtt, |
71 base::TimeDelta avg_rtt, | 82 base::TimeDelta avg_rtt, |
72 base::TimeDelta min_rtt, | 83 base::TimeDelta min_rtt, |
73 base::TimeDelta max_rtt) { | 84 base::TimeDelta max_rtt) { |
74 rtt_available_ = true; | 85 rtt_available_ = true; |
75 rtt_ = rtt; | 86 rtt_ = rtt; |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 | 133 |
123 void FrameSender::ResendForKickstart() { | 134 void FrameSender::ResendForKickstart() { |
124 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 135 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
125 DCHECK(!last_send_time_.is_null()); | 136 DCHECK(!last_send_time_.is_null()); |
126 VLOG(1) << "Resending last packet of frame " << last_sent_frame_id_ | 137 VLOG(1) << "Resending last packet of frame " << last_sent_frame_id_ |
127 << " to kick-start."; | 138 << " to kick-start."; |
128 last_send_time_ = cast_environment_->Clock()->NowTicks(); | 139 last_send_time_ = cast_environment_->Clock()->NowTicks(); |
129 transport_sender_->ResendFrameForKickstart(ssrc_, last_sent_frame_id_); | 140 transport_sender_->ResendFrameForKickstart(ssrc_, last_sent_frame_id_); |
130 } | 141 } |
131 | 142 |
| 143 void FrameSender::RecordLatestFrameTimestamps(uint32 frame_id, |
| 144 base::TimeTicks reference_time, |
| 145 RtpTimestamp rtp_timestamp) { |
| 146 DCHECK(!reference_time.is_null()); |
| 147 frame_reference_times_[frame_id % arraysize(frame_reference_times_)] = |
| 148 reference_time; |
| 149 frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)] = |
| 150 rtp_timestamp; |
| 151 } |
| 152 |
| 153 base::TimeTicks FrameSender::GetRecordedReferenceTime(uint32 frame_id) const { |
| 154 return frame_reference_times_[frame_id % arraysize(frame_reference_times_)]; |
| 155 } |
| 156 |
| 157 RtpTimestamp FrameSender::GetRecordedRtpTimestamp(uint32 frame_id) const { |
| 158 return frame_rtp_timestamps_[frame_id % arraysize(frame_rtp_timestamps_)]; |
| 159 } |
| 160 |
132 } // namespace cast | 161 } // namespace cast |
133 } // namespace media | 162 } // namespace media |
OLD | NEW |