Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(115)

Side by Side Diff: media/cast/sender/audio_sender.cc

Issue 387933005: Cast: Refactor RTCP handling (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix test Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/cast/sender/audio_sender.h ('k') | media/cast/sender/audio_sender_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/net/rtcp/rtcp_defines.h"
13 #include "media/cast/sender/audio_encoder.h" 12 #include "media/cast/sender/audio_encoder.h"
14 13
15 namespace media { 14 namespace media {
16 namespace cast { 15 namespace cast {
17 namespace { 16 namespace {
18 17
19 const int kNumAggressiveReportsSentAtStart = 100; 18 const int kNumAggressiveReportsSentAtStart = 100;
20 const int kMinSchedulingDelayMs = 1; 19 const int kMinSchedulingDelayMs = 1;
21 20
22 // TODO(miu): This should be specified in AudioSenderConfig, but currently it is 21 // TODO(miu): This should be specified in AudioSenderConfig, but currently it is
23 // fixed to 100 FPS (i.e., 10 ms per frame), and AudioEncoder assumes this as 22 // fixed to 100 FPS (i.e., 10 ms per frame), and AudioEncoder assumes this as
24 // well. 23 // well.
25 const int kAudioFrameRate = 100; 24 const int kAudioFrameRate = 100;
26 25
27 // Helper function to compute the maximum unacked audio frames that is sent. 26 // Helper function to compute the maximum unacked audio frames that is sent.
28 int GetMaxUnackedFrames(base::TimeDelta target_delay) { 27 int GetMaxUnackedFrames(base::TimeDelta target_delay) {
29 // As long as it doesn't go over |kMaxUnackedFrames|, it is okay to send more 28 // As long as it doesn't go over |kMaxUnackedFrames|, it is okay to send more
30 // audio data than the target delay would suggest. Audio packets are tiny and 29 // audio data than the target delay would suggest. Audio packets are tiny and
31 // receiver has the ability to drop any one of the packets. 30 // receiver has the ability to drop any one of the packets.
32 // We send up to three times of the target delay of audio frames. 31 // We send up to three times of the target delay of audio frames.
33 int frames = 32 int frames =
34 1 + 3 * target_delay * kAudioFrameRate / base::TimeDelta::FromSeconds(1); 33 1 + 3 * target_delay * kAudioFrameRate / base::TimeDelta::FromSeconds(1);
35 return std::min(kMaxUnackedFrames, frames); 34 return std::min(kMaxUnackedFrames, frames);
36 } 35 }
37 } // namespace 36 } // namespace
38 37
39 AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment, 38 AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment,
40 const AudioSenderConfig& audio_config, 39 const AudioSenderConfig& audio_config,
41 CastTransportSender* const transport_sender) 40 CastTransportSender* const transport_sender)
42 : cast_environment_(cast_environment), 41 : FrameSender(
42 cast_environment,
43 transport_sender,
44 base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval),
45 audio_config.frequency,
46 audio_config.ssrc),
43 target_playout_delay_(audio_config.target_playout_delay), 47 target_playout_delay_(audio_config.target_playout_delay),
44 transport_sender_(transport_sender),
45 max_unacked_frames_(GetMaxUnackedFrames(target_playout_delay_)), 48 max_unacked_frames_(GetMaxUnackedFrames(target_playout_delay_)),
46 configured_encoder_bitrate_(audio_config.bitrate), 49 configured_encoder_bitrate_(audio_config.bitrate),
47 rtcp_(cast_environment,
48 this,
49 transport_sender_,
50 NULL, // paced sender.
51 NULL,
52 audio_config.rtcp_mode,
53 base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval),
54 audio_config.ssrc,
55 audio_config.incoming_feedback_ssrc,
56 audio_config.rtcp_c_name,
57 AUDIO_EVENT),
58 rtp_timestamp_helper_(audio_config.frequency),
59 num_aggressive_rtcp_reports_sent_(0), 50 num_aggressive_rtcp_reports_sent_(0),
60 last_sent_frame_id_(0), 51 last_sent_frame_id_(0),
61 latest_acked_frame_id_(0), 52 latest_acked_frame_id_(0),
62 duplicate_ack_counter_(0), 53 duplicate_ack_counter_(0),
63 cast_initialization_status_(STATUS_AUDIO_UNINITIALIZED), 54 cast_initialization_status_(STATUS_AUDIO_UNINITIALIZED),
64 weak_factory_(this) { 55 weak_factory_(this) {
65 VLOG(1) << "max_unacked_frames " << max_unacked_frames_; 56 VLOG(1) << "max_unacked_frames " << max_unacked_frames_;
66 DCHECK_GT(max_unacked_frames_, 0); 57 DCHECK_GT(max_unacked_frames_, 0);
67 58
68 if (!audio_config.use_external_encoder) { 59 if (!audio_config.use_external_encoder) {
69 audio_encoder_.reset( 60 audio_encoder_.reset(
70 new AudioEncoder(cast_environment, 61 new AudioEncoder(cast_environment,
71 audio_config.channels, 62 audio_config.channels,
72 audio_config.frequency, 63 audio_config.frequency,
73 audio_config.bitrate, 64 audio_config.bitrate,
74 audio_config.codec, 65 audio_config.codec,
75 base::Bind(&AudioSender::SendEncodedAudioFrame, 66 base::Bind(&AudioSender::SendEncodedAudioFrame,
76 weak_factory_.GetWeakPtr()))); 67 weak_factory_.GetWeakPtr())));
77 cast_initialization_status_ = audio_encoder_->InitializationResult(); 68 cast_initialization_status_ = audio_encoder_->InitializationResult();
78 } else { 69 } else {
79 NOTREACHED(); // No support for external audio encoding. 70 NOTREACHED(); // No support for external audio encoding.
80 cast_initialization_status_ = STATUS_AUDIO_UNINITIALIZED; 71 cast_initialization_status_ = STATUS_AUDIO_UNINITIALIZED;
81 } 72 }
82 73
83 media::cast::CastTransportRtpConfig transport_config; 74 media::cast::CastTransportRtpConfig transport_config;
84 transport_config.ssrc = audio_config.ssrc; 75 transport_config.ssrc = audio_config.ssrc;
76 transport_config.feedback_ssrc = audio_config.incoming_feedback_ssrc;
77 transport_config.c_name = audio_config.rtcp_c_name;
85 transport_config.rtp_payload_type = audio_config.rtp_payload_type; 78 transport_config.rtp_payload_type = audio_config.rtp_payload_type;
86 // TODO(miu): AudioSender needs to be like VideoSender in providing an upper 79 // TODO(miu): AudioSender needs to be like VideoSender in providing an upper
87 // limit on the number of in-flight frames. 80 // limit on the number of in-flight frames.
88 transport_config.stored_frames = max_unacked_frames_; 81 transport_config.stored_frames = max_unacked_frames_;
89 transport_config.aes_key = audio_config.aes_key; 82 transport_config.aes_key = audio_config.aes_key;
90 transport_config.aes_iv_mask = audio_config.aes_iv_mask; 83 transport_config.aes_iv_mask = audio_config.aes_iv_mask;
91 transport_sender_->InitializeAudio(transport_config);
92 84
93 rtcp_.SetCastReceiverEventHistorySize(kReceiverRtcpEventHistorySize); 85 transport_sender->InitializeAudio(
94 86 transport_config,
87 base::Bind(&AudioSender::OnReceivedCastFeedback,
88 weak_factory_.GetWeakPtr()),
89 base::Bind(&AudioSender::OnReceivedRtt, weak_factory_.GetWeakPtr()));
95 memset(frame_id_to_rtp_timestamp_, 0, sizeof(frame_id_to_rtp_timestamp_)); 90 memset(frame_id_to_rtp_timestamp_, 0, sizeof(frame_id_to_rtp_timestamp_));
96 } 91 }
97 92
98 AudioSender::~AudioSender() {} 93 AudioSender::~AudioSender() {}
99 94
100 void AudioSender::InsertAudio(scoped_ptr<AudioBus> audio_bus, 95 void AudioSender::InsertAudio(scoped_ptr<AudioBus> audio_bus,
101 const base::TimeTicks& recorded_time) { 96 const base::TimeTicks& recorded_time) {
102 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 97 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
103 if (cast_initialization_status_ != STATUS_AUDIO_INITIALIZED) { 98 if (cast_initialization_status_ != STATUS_AUDIO_INITIALIZED) {
104 NOTREACHED(); 99 NOTREACHED();
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 ++num_aggressive_rtcp_reports_sent_; 149 ++num_aggressive_rtcp_reports_sent_;
155 const bool is_last_aggressive_report = 150 const bool is_last_aggressive_report =
156 (num_aggressive_rtcp_reports_sent_ == kNumAggressiveReportsSentAtStart); 151 (num_aggressive_rtcp_reports_sent_ == kNumAggressiveReportsSentAtStart);
157 VLOG_IF(1, is_last_aggressive_report) << "Sending last aggressive report."; 152 VLOG_IF(1, is_last_aggressive_report) << "Sending last aggressive report.";
158 SendRtcpReport(is_last_aggressive_report); 153 SendRtcpReport(is_last_aggressive_report);
159 } 154 }
160 155
161 transport_sender_->InsertCodedAudioFrame(*encoded_frame); 156 transport_sender_->InsertCodedAudioFrame(*encoded_frame);
162 } 157 }
163 158
164 void AudioSender::IncomingRtcpPacket(scoped_ptr<Packet> packet) {
165 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
166 rtcp_.IncomingRtcpPacket(&packet->front(), packet->size());
167 }
168
169 void AudioSender::ScheduleNextRtcpReport() {
170 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
171 base::TimeDelta time_to_next =
172 rtcp_.TimeToSendNextRtcpReport() - cast_environment_->Clock()->NowTicks();
173
174 time_to_next = std::max(
175 time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs));
176
177 cast_environment_->PostDelayedTask(
178 CastEnvironment::MAIN,
179 FROM_HERE,
180 base::Bind(&AudioSender::SendRtcpReport,
181 weak_factory_.GetWeakPtr(),
182 true),
183 time_to_next);
184 }
185
186 void AudioSender::SendRtcpReport(bool schedule_future_reports) {
187 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
188 const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
189 uint32 now_as_rtp_timestamp = 0;
190 if (rtp_timestamp_helper_.GetCurrentTimeAsRtpTimestamp(
191 now, &now_as_rtp_timestamp)) {
192 rtcp_.SendRtcpFromRtpSender(now, now_as_rtp_timestamp);
193 } else {
194 // |rtp_timestamp_helper_| should have stored a mapping by this point.
195 NOTREACHED();
196 }
197 if (schedule_future_reports)
198 ScheduleNextRtcpReport();
199 }
200
201 void AudioSender::ScheduleNextResendCheck() { 159 void AudioSender::ScheduleNextResendCheck() {
202 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 160 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
203 DCHECK(!last_send_time_.is_null()); 161 DCHECK(!last_send_time_.is_null());
204 base::TimeDelta time_to_next = 162 base::TimeDelta time_to_next =
205 last_send_time_ - cast_environment_->Clock()->NowTicks() + 163 last_send_time_ - cast_environment_->Clock()->NowTicks() +
206 target_playout_delay_; 164 target_playout_delay_;
207 time_to_next = std::max( 165 time_to_next = std::max(
208 time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); 166 time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs));
209 cast_environment_->PostDelayedTask( 167 cast_environment_->PostDelayedTask(
210 CastEnvironment::MAIN, 168 CastEnvironment::MAIN,
(...skipping 14 matching lines...) Expand all
225 VLOG(1) << "ACK timeout; last acked frame: " << latest_acked_frame_id_; 183 VLOG(1) << "ACK timeout; last acked frame: " << latest_acked_frame_id_;
226 ResendForKickstart(); 184 ResendForKickstart();
227 } 185 }
228 } 186 }
229 ScheduleNextResendCheck(); 187 ScheduleNextResendCheck();
230 } 188 }
231 189
232 void AudioSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) { 190 void AudioSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) {
233 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 191 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
234 192
235 if (rtcp_.is_rtt_available()) { 193 if (is_rtt_available()) {
236 // Having the RTT values implies the receiver sent back a receiver report 194 // Having the RTT values implies the receiver sent back a receiver report
237 // based on it having received a report from here. Therefore, ensure this 195 // based on it having received a report from here. Therefore, ensure this
238 // sender stops aggressively sending reports. 196 // sender stops aggressively sending reports.
239 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) { 197 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) {
240 VLOG(1) << "No longer a need to send reports aggressively (sent " 198 VLOG(1) << "No longer a need to send reports aggressively (sent "
241 << num_aggressive_rtcp_reports_sent_ << ")."; 199 << num_aggressive_rtcp_reports_sent_ << ").";
242 num_aggressive_rtcp_reports_sent_ = kNumAggressiveReportsSentAtStart; 200 num_aggressive_rtcp_reports_sent_ = kNumAggressiveReportsSentAtStart;
243 ScheduleNextRtcpReport(); 201 ScheduleNextRtcpReport();
244 } 202 }
245 } 203 }
246 204
247 if (last_send_time_.is_null()) 205 if (last_send_time_.is_null())
248 return; // Cannot get an ACK without having first sent a frame. 206 return; // Cannot get an ACK without having first sent a frame.
249 207
250 if (cast_feedback.missing_frames_and_packets_.empty()) { 208 if (cast_feedback.missing_frames_and_packets.empty()) {
251 // We only count duplicate ACKs when we have sent newer frames. 209 // We only count duplicate ACKs when we have sent newer frames.
252 if (latest_acked_frame_id_ == cast_feedback.ack_frame_id_ && 210 if (latest_acked_frame_id_ == cast_feedback.ack_frame_id &&
253 latest_acked_frame_id_ != last_sent_frame_id_) { 211 latest_acked_frame_id_ != last_sent_frame_id_) {
254 duplicate_ack_counter_++; 212 duplicate_ack_counter_++;
255 } else { 213 } else {
256 duplicate_ack_counter_ = 0; 214 duplicate_ack_counter_ = 0;
257 } 215 }
258 // TODO(miu): The values "2" and "3" should be derived from configuration. 216 // TODO(miu): The values "2" and "3" should be derived from configuration.
259 if (duplicate_ack_counter_ >= 2 && duplicate_ack_counter_ % 3 == 2) { 217 if (duplicate_ack_counter_ >= 2 && duplicate_ack_counter_ % 3 == 2) {
260 VLOG(1) << "Received duplicate ACK for frame " << latest_acked_frame_id_; 218 VLOG(1) << "Received duplicate ACK for frame " << latest_acked_frame_id_;
261 ResendForKickstart(); 219 ResendForKickstart();
262 } 220 }
263 } else { 221 } else {
264 // Only count duplicated ACKs if there is no NACK request in between. 222 // Only count duplicated ACKs if there is no NACK request in between.
265 // This is to avoid aggresive resend. 223 // This is to avoid aggresive resend.
266 duplicate_ack_counter_ = 0; 224 duplicate_ack_counter_ = 0;
267 225
268 base::TimeDelta rtt;
269 base::TimeDelta avg_rtt;
270 base::TimeDelta min_rtt;
271 base::TimeDelta max_rtt;
272 rtcp_.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt);
273
274 // A NACK is also used to cancel pending re-transmissions. 226 // A NACK is also used to cancel pending re-transmissions.
275 transport_sender_->ResendPackets( 227 transport_sender_->ResendPackets(
276 true, cast_feedback.missing_frames_and_packets_, false, min_rtt); 228 true, cast_feedback.missing_frames_and_packets, false, min_rtt_);
277 } 229 }
278 230
279 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); 231 const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
280 232
281 const RtpTimestamp rtp_timestamp = 233 const RtpTimestamp rtp_timestamp =
282 frame_id_to_rtp_timestamp_[cast_feedback.ack_frame_id_ & 0xff]; 234 frame_id_to_rtp_timestamp_[cast_feedback.ack_frame_id & 0xff];
283 cast_environment_->Logging()->InsertFrameEvent(now, 235 cast_environment_->Logging()->InsertFrameEvent(now,
284 FRAME_ACK_RECEIVED, 236 FRAME_ACK_RECEIVED,
285 AUDIO_EVENT, 237 AUDIO_EVENT,
286 rtp_timestamp, 238 rtp_timestamp,
287 cast_feedback.ack_frame_id_); 239 cast_feedback.ack_frame_id);
288 240
289 const bool is_acked_out_of_order = 241 const bool is_acked_out_of_order =
290 static_cast<int32>(cast_feedback.ack_frame_id_ - 242 static_cast<int32>(cast_feedback.ack_frame_id -
291 latest_acked_frame_id_) < 0; 243 latest_acked_frame_id_) < 0;
292 VLOG(2) << "Received ACK" << (is_acked_out_of_order ? " out-of-order" : "") 244 VLOG(2) << "Received ACK" << (is_acked_out_of_order ? " out-of-order" : "")
293 << " for frame " << cast_feedback.ack_frame_id_; 245 << " for frame " << cast_feedback.ack_frame_id;
294 if (!is_acked_out_of_order) { 246 if (!is_acked_out_of_order) {
295 // Cancel resends of acked frames. 247 // Cancel resends of acked frames.
296 MissingFramesAndPacketsMap missing_frames_and_packets; 248 MissingFramesAndPacketsMap missing_frames_and_packets;
297 PacketIdSet missing; 249 PacketIdSet missing;
298 while (latest_acked_frame_id_ != cast_feedback.ack_frame_id_) { 250 while (latest_acked_frame_id_ != cast_feedback.ack_frame_id) {
299 latest_acked_frame_id_++; 251 latest_acked_frame_id_++;
300 missing_frames_and_packets[latest_acked_frame_id_] = missing; 252 missing_frames_and_packets[latest_acked_frame_id_] = missing;
301 } 253 }
302 transport_sender_->ResendPackets( 254 transport_sender_->ResendPackets(
303 true, missing_frames_and_packets, true, base::TimeDelta()); 255 true, missing_frames_and_packets, true, base::TimeDelta());
304 latest_acked_frame_id_ = cast_feedback.ack_frame_id_; 256 latest_acked_frame_id_ = cast_feedback.ack_frame_id;
305 } 257 }
306 } 258 }
307 259
308 bool AudioSender::AreTooManyFramesInFlight() const { 260 bool AudioSender::AreTooManyFramesInFlight() const {
309 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 261 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
310 int frames_in_flight = 0; 262 int frames_in_flight = 0;
311 if (!last_send_time_.is_null()) { 263 if (!last_send_time_.is_null()) {
312 frames_in_flight += 264 frames_in_flight +=
313 static_cast<int32>(last_sent_frame_id_ - latest_acked_frame_id_); 265 static_cast<int32>(last_sent_frame_id_ - latest_acked_frame_id_);
314 } 266 }
(...skipping 11 matching lines...) Expand all
326 // Send the first packet of the last encoded frame to kick start 278 // Send the first packet of the last encoded frame to kick start
327 // retransmission. This gives enough information to the receiver what 279 // retransmission. This gives enough information to the receiver what
328 // packets and frames are missing. 280 // packets and frames are missing.
329 MissingFramesAndPacketsMap missing_frames_and_packets; 281 MissingFramesAndPacketsMap missing_frames_and_packets;
330 PacketIdSet missing; 282 PacketIdSet missing;
331 missing.insert(kRtcpCastLastPacket); 283 missing.insert(kRtcpCastLastPacket);
332 missing_frames_and_packets.insert( 284 missing_frames_and_packets.insert(
333 std::make_pair(last_sent_frame_id_, missing)); 285 std::make_pair(last_sent_frame_id_, missing));
334 last_send_time_ = cast_environment_->Clock()->NowTicks(); 286 last_send_time_ = cast_environment_->Clock()->NowTicks();
335 287
336 base::TimeDelta rtt;
337 base::TimeDelta avg_rtt;
338 base::TimeDelta min_rtt;
339 base::TimeDelta max_rtt;
340 rtcp_.Rtt(&rtt, &avg_rtt, &min_rtt, &max_rtt);
341
342 // Sending this extra packet is to kick-start the session. There is 288 // Sending this extra packet is to kick-start the session. There is
343 // no need to optimize re-transmission for this case. 289 // no need to optimize re-transmission for this case.
344 transport_sender_->ResendPackets( 290 transport_sender_->ResendPackets(
345 true, missing_frames_and_packets, false, min_rtt); 291 true, missing_frames_and_packets, false, min_rtt_);
346 } 292 }
347 293
348 } // namespace cast 294 } // namespace cast
349 } // namespace media 295 } // namespace media
OLDNEW
« no previous file with comments | « media/cast/sender/audio_sender.h ('k') | media/cast/sender/audio_sender_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698