| Index: media/cast/audio_sender/audio_sender.cc
|
| diff --git a/media/cast/audio_sender/audio_sender.cc b/media/cast/audio_sender/audio_sender.cc
|
| index 4a288d31e4a6c0fb94e9b3373a8a3fce0e4eaf26..513665a78ea4c8b6370ac45269b955100b2ab2c9 100644
|
| --- a/media/cast/audio_sender/audio_sender.cc
|
| +++ b/media/cast/audio_sender/audio_sender.cc
|
| @@ -13,27 +13,8 @@
|
| namespace media {
|
| namespace cast {
|
|
|
| -const int64 kMinSchedulingDelayMs = 1;
|
| -
|
| -class LocalRtcpAudioSenderFeedback : public RtcpSenderFeedback {
|
| - public:
|
| - explicit LocalRtcpAudioSenderFeedback(AudioSender* audio_sender)
|
| - : audio_sender_(audio_sender) {}
|
| -
|
| - virtual void OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback)
|
| - OVERRIDE {
|
| - if (!cast_feedback.missing_frames_and_packets_.empty()) {
|
| - audio_sender_->ResendPackets(cast_feedback.missing_frames_and_packets_);
|
| - }
|
| - VLOG(2) << "Received audio ACK "
|
| - << static_cast<int>(cast_feedback.ack_frame_id_);
|
| - }
|
| -
|
| - private:
|
| - AudioSender* audio_sender_;
|
| -
|
| - DISALLOW_IMPLICIT_CONSTRUCTORS(LocalRtcpAudioSenderFeedback);
|
| -};
|
| +const int kNumAggressiveReportsSentAtStart = 100;
|
| +const int kMinSchedulingDelayMs = 1;
|
|
|
| // TODO(mikhal): Reduce heap allocation when not needed.
|
| AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment,
|
| @@ -42,9 +23,8 @@ AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment,
|
| : cast_environment_(cast_environment),
|
| transport_sender_(transport_sender),
|
| rtp_timestamp_helper_(audio_config.frequency),
|
| - rtcp_feedback_(new LocalRtcpAudioSenderFeedback(this)),
|
| rtcp_(cast_environment,
|
| - rtcp_feedback_.get(),
|
| + this,
|
| transport_sender_,
|
| NULL, // paced sender.
|
| NULL,
|
| @@ -54,7 +34,7 @@ AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment,
|
| audio_config.incoming_feedback_ssrc,
|
| audio_config.rtcp_c_name,
|
| true),
|
| - timers_initialized_(false),
|
| + num_aggressive_rtcp_reports_sent_(0),
|
| cast_initialization_cb_(STATUS_AUDIO_UNINITIALIZED),
|
| weak_factory_(this) {
|
| rtcp_.SetCastReceiverEventHistorySize(kReceiverRtcpEventHistorySize);
|
| @@ -79,14 +59,6 @@ AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment,
|
|
|
| AudioSender::~AudioSender() {}
|
|
|
| -void AudioSender::InitializeTimers() {
|
| - DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
|
| - if (!timers_initialized_) {
|
| - timers_initialized_ = true;
|
| - ScheduleNextRtcpReport();
|
| - }
|
| -}
|
| -
|
| void AudioSender::InsertAudio(scoped_ptr<AudioBus> audio_bus,
|
| const base::TimeTicks& recorded_time) {
|
| DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
|
| @@ -100,7 +72,22 @@ void AudioSender::SendEncodedAudioFrame(
|
| DCHECK(!audio_frame->reference_time.is_null());
|
| rtp_timestamp_helper_.StoreLatestTime(audio_frame->reference_time,
|
| audio_frame->rtp_timestamp);
|
| - InitializeTimers();
|
| +
|
| + // At the start of the session, it's important to send reports before each
|
| + // frame so that the receiver can properly compute playout times. The reason
|
| + // more than one report is sent is because transmission is not guaranteed,
|
| + // only best effort, so we send enough that one should almost certainly get
|
| + // through.
|
| + if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) {
|
| + // SendRtcpReport() will schedule future reports to be made if this is the
|
| + // last "aggressive report."
|
| + ++num_aggressive_rtcp_reports_sent_;
|
| + const bool is_last_aggressive_report =
|
| + (num_aggressive_rtcp_reports_sent_ == kNumAggressiveReportsSentAtStart);
|
| + VLOG_IF(1, is_last_aggressive_report) << "Sending last aggressive report.";
|
| + SendRtcpReport(is_last_aggressive_report);
|
| + }
|
| +
|
| transport_sender_->InsertCodedAudioFrame(*audio_frame);
|
| }
|
|
|
| @@ -126,19 +113,47 @@ void AudioSender::ScheduleNextRtcpReport() {
|
| cast_environment_->PostDelayedTask(
|
| CastEnvironment::MAIN,
|
| FROM_HERE,
|
| - base::Bind(&AudioSender::SendRtcpReport, weak_factory_.GetWeakPtr()),
|
| + base::Bind(&AudioSender::SendRtcpReport,
|
| + weak_factory_.GetWeakPtr(),
|
| + true),
|
| time_to_next);
|
| }
|
|
|
| -void AudioSender::SendRtcpReport() {
|
| +void AudioSender::SendRtcpReport(bool schedule_future_reports) {
|
| DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
|
| const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
|
| uint32 now_as_rtp_timestamp = 0;
|
| if (rtp_timestamp_helper_.GetCurrentTimeAsRtpTimestamp(
|
| now, &now_as_rtp_timestamp)) {
|
| rtcp_.SendRtcpFromRtpSender(now, now_as_rtp_timestamp);
|
| + } else {
|
| + // |rtp_timestamp_helper_| should have stored a mapping by this point.
|
| + NOTREACHED();
|
| + }
|
| + if (schedule_future_reports)
|
| + ScheduleNextRtcpReport();
|
| +}
|
| +
|
| +void AudioSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) {
|
| + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
|
| +
|
| + if (rtcp_.is_rtt_available()) {
|
| + // Having the RTT values implies the receiver sent back a receiver report
|
| + // based on it having received a report from here. Therefore, ensure this
|
| + // sender stops aggressively sending reports.
|
| + if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) {
|
| + VLOG(1) << "No longer a need to send reports aggressively (sent "
|
| + << num_aggressive_rtcp_reports_sent_ << ").";
|
| + num_aggressive_rtcp_reports_sent_ = kNumAggressiveReportsSentAtStart;
|
| + ScheduleNextRtcpReport();
|
| + }
|
| + }
|
| +
|
| + if (!cast_feedback.missing_frames_and_packets_.empty()) {
|
| + ResendPackets(cast_feedback.missing_frames_and_packets_);
|
| }
|
| - ScheduleNextRtcpReport();
|
| + VLOG(2) << "Received audio ACK "
|
| + << static_cast<int>(cast_feedback.ack_frame_id_);
|
| }
|
|
|
| } // namespace cast
|
|
|