| 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/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  Loading... | 
| 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  Loading... | 
| 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  Loading... | 
| 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 | 
| OLD | NEW | 
|---|