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" |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 } | 214 } |
215 // TODO(miu): The values "2" and "3" should be derived from configuration. | 215 // TODO(miu): The values "2" and "3" should be derived from configuration. |
216 if (duplicate_ack_counter_ >= 2 && duplicate_ack_counter_ % 3 == 2) { | 216 if (duplicate_ack_counter_ >= 2 && duplicate_ack_counter_ % 3 == 2) { |
217 VLOG(1) << "Received duplicate ACK for frame " << latest_acked_frame_id_; | 217 VLOG(1) << "Received duplicate ACK for frame " << latest_acked_frame_id_; |
218 ResendForKickstart(); | 218 ResendForKickstart(); |
219 } | 219 } |
220 } else { | 220 } else { |
221 // Only count duplicated ACKs if there is no NACK request in between. | 221 // Only count duplicated ACKs if there is no NACK request in between. |
222 // This is to avoid aggresive resend. | 222 // This is to avoid aggresive resend. |
223 duplicate_ack_counter_ = 0; | 223 duplicate_ack_counter_ = 0; |
224 | |
225 // A NACK is also used to cancel pending re-transmissions. | |
226 transport_sender_->ResendPackets( | |
227 true, cast_feedback.missing_frames_and_packets, false, min_rtt_); | |
228 } | 224 } |
229 | 225 |
230 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); | 226 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); |
231 | 227 |
232 const RtpTimestamp rtp_timestamp = | 228 const RtpTimestamp rtp_timestamp = |
233 frame_id_to_rtp_timestamp_[cast_feedback.ack_frame_id & 0xff]; | 229 frame_id_to_rtp_timestamp_[cast_feedback.ack_frame_id & 0xff]; |
234 cast_environment_->Logging()->InsertFrameEvent(now, | 230 cast_environment_->Logging()->InsertFrameEvent(now, |
235 FRAME_ACK_RECEIVED, | 231 FRAME_ACK_RECEIVED, |
236 AUDIO_EVENT, | 232 AUDIO_EVENT, |
237 rtp_timestamp, | 233 rtp_timestamp, |
238 cast_feedback.ack_frame_id); | 234 cast_feedback.ack_frame_id); |
239 | 235 |
240 const bool is_acked_out_of_order = | 236 const bool is_acked_out_of_order = |
241 static_cast<int32>(cast_feedback.ack_frame_id - | 237 static_cast<int32>(cast_feedback.ack_frame_id - |
242 latest_acked_frame_id_) < 0; | 238 latest_acked_frame_id_) < 0; |
243 VLOG(2) << "Received ACK" << (is_acked_out_of_order ? " out-of-order" : "") | 239 VLOG(2) << "Received ACK" << (is_acked_out_of_order ? " out-of-order" : "") |
244 << " for frame " << cast_feedback.ack_frame_id; | 240 << " for frame " << cast_feedback.ack_frame_id; |
245 if (!is_acked_out_of_order) { | 241 if (!is_acked_out_of_order) { |
246 // Cancel resends of acked frames. | 242 // Cancel resends of acked frames. |
247 MissingFramesAndPacketsMap missing_frames_and_packets; | 243 std::set<uint32> cancel_sending_frames; |
248 PacketIdSet missing; | |
249 while (latest_acked_frame_id_ != cast_feedback.ack_frame_id) { | 244 while (latest_acked_frame_id_ != cast_feedback.ack_frame_id) { |
250 latest_acked_frame_id_++; | 245 latest_acked_frame_id_++; |
251 missing_frames_and_packets[latest_acked_frame_id_] = missing; | 246 cancel_sending_frames.insert(latest_acked_frame_id_); |
252 } | 247 } |
253 transport_sender_->ResendPackets( | 248 transport_sender_->CancelSendingFrames(ssrc_, cancel_sending_frames); |
254 true, missing_frames_and_packets, true, base::TimeDelta()); | |
255 latest_acked_frame_id_ = cast_feedback.ack_frame_id; | 249 latest_acked_frame_id_ = cast_feedback.ack_frame_id; |
256 } | 250 } |
257 } | 251 } |
258 | 252 |
259 bool AudioSender::AreTooManyFramesInFlight() const { | 253 bool AudioSender::AreTooManyFramesInFlight() const { |
260 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 254 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
261 int frames_in_flight = 0; | 255 int frames_in_flight = 0; |
262 if (!last_send_time_.is_null()) { | 256 if (!last_send_time_.is_null()) { |
263 frames_in_flight += | 257 frames_in_flight += |
264 static_cast<int32>(last_sent_frame_id_ - latest_acked_frame_id_); | 258 static_cast<int32>(last_sent_frame_id_ - latest_acked_frame_id_); |
265 } | 259 } |
266 VLOG(2) << frames_in_flight | 260 VLOG(2) << frames_in_flight |
267 << " frames in flight; last sent: " << last_sent_frame_id_ | 261 << " frames in flight; last sent: " << last_sent_frame_id_ |
268 << " latest acked: " << latest_acked_frame_id_; | 262 << " latest acked: " << latest_acked_frame_id_; |
269 return frames_in_flight >= max_unacked_frames_; | 263 return frames_in_flight >= max_unacked_frames_; |
270 } | 264 } |
271 | 265 |
272 void AudioSender::ResendForKickstart() { | 266 void AudioSender::ResendForKickstart() { |
273 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 267 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
274 DCHECK(!last_send_time_.is_null()); | 268 DCHECK(!last_send_time_.is_null()); |
275 VLOG(1) << "Resending last packet of frame " << last_sent_frame_id_ | 269 VLOG(1) << "Resending last packet of frame " << last_sent_frame_id_ |
276 << " to kick-start."; | 270 << " to kick-start."; |
277 // Send the first packet of the last encoded frame to kick start | |
278 // retransmission. This gives enough information to the receiver what | |
279 // packets and frames are missing. | |
280 MissingFramesAndPacketsMap missing_frames_and_packets; | |
281 PacketIdSet missing; | |
282 missing.insert(kRtcpCastLastPacket); | |
283 missing_frames_and_packets.insert( | |
284 std::make_pair(last_sent_frame_id_, missing)); | |
285 last_send_time_ = cast_environment_->Clock()->NowTicks(); | 271 last_send_time_ = cast_environment_->Clock()->NowTicks(); |
286 | 272 transport_sender_->ResendFrameForKickstart(ssrc_, last_sent_frame_id_); |
287 // Sending this extra packet is to kick-start the session. There is | |
288 // no need to optimize re-transmission for this case. | |
289 transport_sender_->ResendPackets( | |
290 true, missing_frames_and_packets, false, min_rtt_); | |
291 } | 273 } |
292 | 274 |
293 } // namespace cast | 275 } // namespace cast |
294 } // namespace media | 276 } // namespace media |
OLD | NEW |