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/audio_sender.h" | 5 #include "media/cast/sender/audio_sender.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
10 #include "media/cast/cast_defines.h" | 10 #include "media/cast/cast_defines.h" |
11 #include "media/cast/net/cast_transport_config.h" | 11 #include "media/cast/net/cast_transport_config.h" |
12 #include "media/cast/sender/audio_encoder.h" | 12 #include "media/cast/sender/audio_encoder.h" |
13 | 13 |
14 namespace media { | 14 namespace media { |
15 namespace cast { | 15 namespace cast { |
16 namespace { | 16 namespace { |
17 | 17 |
18 const int kNumAggressiveReportsSentAtStart = 100; | 18 const int kNumAggressiveReportsSentAtStart = 100; |
19 const int kMinSchedulingDelayMs = 1; | |
20 | 19 |
21 // TODO(miu): This should be specified in AudioSenderConfig, but currently it is | 20 // TODO(miu): This should be specified in AudioSenderConfig, but currently it is |
22 // fixed to 100 FPS (i.e., 10 ms per frame), and AudioEncoder assumes this as | 21 // fixed to 100 FPS (i.e., 10 ms per frame), and AudioEncoder assumes this as |
23 // well. | 22 // well. |
24 const int kAudioFrameRate = 100; | 23 const int kAudioFrameRate = 100; |
25 | 24 |
26 } // namespace | 25 } // namespace |
27 | 26 |
28 AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment, | 27 AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment, |
29 const AudioSenderConfig& audio_config, | 28 const AudioSenderConfig& audio_config, |
30 CastTransportSender* const transport_sender) | 29 CastTransportSender* const transport_sender) |
31 : FrameSender( | 30 : FrameSender( |
32 cast_environment, | 31 cast_environment, |
33 transport_sender, | 32 transport_sender, |
34 base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval), | 33 base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval), |
35 audio_config.frequency, | 34 audio_config.frequency, |
36 audio_config.ssrc, | 35 audio_config.ssrc, |
37 kAudioFrameRate * 2.0, // We lie to increase max outstanding frames. | 36 kAudioFrameRate * 2.0, // We lie to increase max outstanding frames. |
38 audio_config.target_playout_delay), | 37 audio_config.target_playout_delay), |
39 configured_encoder_bitrate_(audio_config.bitrate), | 38 configured_encoder_bitrate_(audio_config.bitrate), |
40 num_aggressive_rtcp_reports_sent_(0), | |
41 last_sent_frame_id_(0), | |
42 latest_acked_frame_id_(0), | |
43 duplicate_ack_counter_(0), | |
44 cast_initialization_status_(STATUS_AUDIO_UNINITIALIZED), | |
45 weak_factory_(this) { | 39 weak_factory_(this) { |
| 40 cast_initialization_status_ = STATUS_AUDIO_UNINITIALIZED; |
46 VLOG(1) << "max_unacked_frames " << max_unacked_frames_; | 41 VLOG(1) << "max_unacked_frames " << max_unacked_frames_; |
47 DCHECK_GT(max_unacked_frames_, 0); | 42 DCHECK_GT(max_unacked_frames_, 0); |
48 | 43 |
49 if (!audio_config.use_external_encoder) { | 44 if (!audio_config.use_external_encoder) { |
50 audio_encoder_.reset( | 45 audio_encoder_.reset( |
51 new AudioEncoder(cast_environment, | 46 new AudioEncoder(cast_environment, |
52 audio_config.channels, | 47 audio_config.channels, |
53 audio_config.frequency, | 48 audio_config.frequency, |
54 audio_config.bitrate, | 49 audio_config.bitrate, |
55 audio_config.codec, | 50 audio_config.codec, |
(...skipping 13 matching lines...) Expand all Loading... |
69 // limit on the number of in-flight frames. | 64 // limit on the number of in-flight frames. |
70 transport_config.stored_frames = max_unacked_frames_; | 65 transport_config.stored_frames = max_unacked_frames_; |
71 transport_config.aes_key = audio_config.aes_key; | 66 transport_config.aes_key = audio_config.aes_key; |
72 transport_config.aes_iv_mask = audio_config.aes_iv_mask; | 67 transport_config.aes_iv_mask = audio_config.aes_iv_mask; |
73 | 68 |
74 transport_sender->InitializeAudio( | 69 transport_sender->InitializeAudio( |
75 transport_config, | 70 transport_config, |
76 base::Bind(&AudioSender::OnReceivedCastFeedback, | 71 base::Bind(&AudioSender::OnReceivedCastFeedback, |
77 weak_factory_.GetWeakPtr()), | 72 weak_factory_.GetWeakPtr()), |
78 base::Bind(&AudioSender::OnReceivedRtt, weak_factory_.GetWeakPtr())); | 73 base::Bind(&AudioSender::OnReceivedRtt, weak_factory_.GetWeakPtr())); |
79 memset(frame_id_to_rtp_timestamp_, 0, sizeof(frame_id_to_rtp_timestamp_)); | |
80 } | 74 } |
81 | 75 |
82 AudioSender::~AudioSender() {} | 76 AudioSender::~AudioSender() {} |
83 | 77 |
84 void AudioSender::InsertAudio(scoped_ptr<AudioBus> audio_bus, | 78 void AudioSender::InsertAudio(scoped_ptr<AudioBus> audio_bus, |
85 const base::TimeTicks& recorded_time) { | 79 const base::TimeTicks& recorded_time) { |
86 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 80 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
87 if (cast_initialization_status_ != STATUS_AUDIO_INITIALIZED) { | 81 if (cast_initialization_status_ != STATUS_AUDIO_INITIALIZED) { |
88 NOTREACHED(); | 82 NOTREACHED(); |
89 return; | 83 return; |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 SendRtcpReport(is_last_aggressive_report); | 136 SendRtcpReport(is_last_aggressive_report); |
143 } | 137 } |
144 | 138 |
145 if (send_target_playout_delay_) { | 139 if (send_target_playout_delay_) { |
146 encoded_frame->new_playout_delay_ms = | 140 encoded_frame->new_playout_delay_ms = |
147 target_playout_delay_.InMilliseconds(); | 141 target_playout_delay_.InMilliseconds(); |
148 } | 142 } |
149 transport_sender_->InsertCodedAudioFrame(*encoded_frame); | 143 transport_sender_->InsertCodedAudioFrame(*encoded_frame); |
150 } | 144 } |
151 | 145 |
152 void AudioSender::ScheduleNextResendCheck() { | |
153 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
154 DCHECK(!last_send_time_.is_null()); | |
155 base::TimeDelta time_to_next = | |
156 last_send_time_ - cast_environment_->Clock()->NowTicks() + | |
157 target_playout_delay_; | |
158 time_to_next = std::max( | |
159 time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); | |
160 cast_environment_->PostDelayedTask( | |
161 CastEnvironment::MAIN, | |
162 FROM_HERE, | |
163 base::Bind(&AudioSender::ResendCheck, weak_factory_.GetWeakPtr()), | |
164 time_to_next); | |
165 } | |
166 | |
167 void AudioSender::ResendCheck() { | |
168 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
169 DCHECK(!last_send_time_.is_null()); | |
170 const base::TimeDelta time_since_last_send = | |
171 cast_environment_->Clock()->NowTicks() - last_send_time_; | |
172 if (time_since_last_send > target_playout_delay_) { | |
173 if (latest_acked_frame_id_ == last_sent_frame_id_) { | |
174 // Last frame acked, no point in doing anything | |
175 } else { | |
176 VLOG(1) << "ACK timeout; last acked frame: " << latest_acked_frame_id_; | |
177 ResendForKickstart(); | |
178 } | |
179 } | |
180 ScheduleNextResendCheck(); | |
181 } | |
182 | |
183 void AudioSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) { | 146 void AudioSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) { |
184 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 147 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
185 | 148 |
186 if (is_rtt_available()) { | 149 if (is_rtt_available()) { |
187 // Having the RTT values implies the receiver sent back a receiver report | 150 // Having the RTT values implies the receiver sent back a receiver report |
188 // based on it having received a report from here. Therefore, ensure this | 151 // based on it having received a report from here. Therefore, ensure this |
189 // sender stops aggressively sending reports. | 152 // sender stops aggressively sending reports. |
190 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) { | 153 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) { |
191 VLOG(1) << "No longer a need to send reports aggressively (sent " | 154 VLOG(1) << "No longer a need to send reports aggressively (sent " |
192 << num_aggressive_rtcp_reports_sent_ << ")."; | 155 << num_aggressive_rtcp_reports_sent_ << ")."; |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
250 if (!last_send_time_.is_null()) { | 213 if (!last_send_time_.is_null()) { |
251 frames_in_flight += | 214 frames_in_flight += |
252 static_cast<int32>(last_sent_frame_id_ - latest_acked_frame_id_); | 215 static_cast<int32>(last_sent_frame_id_ - latest_acked_frame_id_); |
253 } | 216 } |
254 VLOG(2) << frames_in_flight | 217 VLOG(2) << frames_in_flight |
255 << " frames in flight; last sent: " << last_sent_frame_id_ | 218 << " frames in flight; last sent: " << last_sent_frame_id_ |
256 << " latest acked: " << latest_acked_frame_id_; | 219 << " latest acked: " << latest_acked_frame_id_; |
257 return frames_in_flight >= max_unacked_frames_; | 220 return frames_in_flight >= max_unacked_frames_; |
258 } | 221 } |
259 | 222 |
260 void AudioSender::ResendForKickstart() { | |
261 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | |
262 DCHECK(!last_send_time_.is_null()); | |
263 VLOG(1) << "Resending last packet of frame " << last_sent_frame_id_ | |
264 << " to kick-start."; | |
265 last_send_time_ = cast_environment_->Clock()->NowTicks(); | |
266 transport_sender_->ResendFrameForKickstart(ssrc_, last_sent_frame_id_); | |
267 } | |
268 | |
269 } // namespace cast | 223 } // namespace cast |
270 } // namespace media | 224 } // namespace media |
OLD | NEW |