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

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

Issue 295603004: [Cast] Aggressively send sender reports until first receiver report is received. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 7 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
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/audio_sender/audio_sender.h" 5 #include "media/cast/audio_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/audio_sender/audio_encoder.h" 10 #include "media/cast/audio_sender/audio_encoder.h"
11 #include "media/cast/transport/cast_transport_defines.h" 11 #include "media/cast/transport/cast_transport_defines.h"
12 12
13 namespace media { 13 namespace media {
14 namespace cast { 14 namespace cast {
15 15
16 const int64 kMinSchedulingDelayMs = 1; 16 const int kNumAggressiveReportsSentAtStart = 100;
17 17 const int kMinSchedulingDelayMs = 1;
18 class LocalRtcpAudioSenderFeedback : public RtcpSenderFeedback {
19 public:
20 explicit LocalRtcpAudioSenderFeedback(AudioSender* audio_sender)
21 : audio_sender_(audio_sender) {}
22
23 virtual void OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback)
24 OVERRIDE {
25 if (!cast_feedback.missing_frames_and_packets_.empty()) {
26 audio_sender_->ResendPackets(cast_feedback.missing_frames_and_packets_);
27 }
28 VLOG(2) << "Received audio ACK "
29 << static_cast<int>(cast_feedback.ack_frame_id_);
30 }
31
32 private:
33 AudioSender* audio_sender_;
34
35 DISALLOW_IMPLICIT_CONSTRUCTORS(LocalRtcpAudioSenderFeedback);
36 };
37 18
38 // TODO(mikhal): Reduce heap allocation when not needed. 19 // TODO(mikhal): Reduce heap allocation when not needed.
39 AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment, 20 AudioSender::AudioSender(scoped_refptr<CastEnvironment> cast_environment,
40 const AudioSenderConfig& audio_config, 21 const AudioSenderConfig& audio_config,
41 transport::CastTransportSender* const transport_sender) 22 transport::CastTransportSender* const transport_sender)
42 : cast_environment_(cast_environment), 23 : cast_environment_(cast_environment),
43 transport_sender_(transport_sender), 24 transport_sender_(transport_sender),
44 rtp_timestamp_helper_(audio_config.frequency), 25 rtp_timestamp_helper_(audio_config.frequency),
45 rtcp_feedback_(new LocalRtcpAudioSenderFeedback(this)),
46 rtcp_(cast_environment, 26 rtcp_(cast_environment,
47 rtcp_feedback_.get(), 27 this,
48 transport_sender_, 28 transport_sender_,
49 NULL, // paced sender. 29 NULL, // paced sender.
50 NULL, 30 NULL,
51 audio_config.rtcp_mode, 31 audio_config.rtcp_mode,
52 base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval), 32 base::TimeDelta::FromMilliseconds(audio_config.rtcp_interval),
53 audio_config.rtp_config.ssrc, 33 audio_config.rtp_config.ssrc,
54 audio_config.incoming_feedback_ssrc, 34 audio_config.incoming_feedback_ssrc,
55 audio_config.rtcp_c_name, 35 audio_config.rtcp_c_name,
56 true), 36 true),
57 timers_initialized_(false), 37 num_aggressive_rtcp_reports_sent_(0),
58 cast_initialization_cb_(STATUS_AUDIO_UNINITIALIZED), 38 cast_initialization_cb_(STATUS_AUDIO_UNINITIALIZED),
59 weak_factory_(this) { 39 weak_factory_(this) {
60 rtcp_.SetCastReceiverEventHistorySize(kReceiverRtcpEventHistorySize); 40 rtcp_.SetCastReceiverEventHistorySize(kReceiverRtcpEventHistorySize);
61 if (!audio_config.use_external_encoder) { 41 if (!audio_config.use_external_encoder) {
62 audio_encoder_.reset( 42 audio_encoder_.reset(
63 new AudioEncoder(cast_environment, 43 new AudioEncoder(cast_environment,
64 audio_config, 44 audio_config,
65 base::Bind(&AudioSender::SendEncodedAudioFrame, 45 base::Bind(&AudioSender::SendEncodedAudioFrame,
66 weak_factory_.GetWeakPtr()))); 46 weak_factory_.GetWeakPtr())));
67 cast_initialization_cb_ = audio_encoder_->InitializationResult(); 47 cast_initialization_cb_ = audio_encoder_->InitializationResult();
68 } 48 }
69 49
70 media::cast::transport::CastTransportAudioConfig transport_config; 50 media::cast::transport::CastTransportAudioConfig transport_config;
71 transport_config.codec = audio_config.codec; 51 transport_config.codec = audio_config.codec;
72 transport_config.rtp.config = audio_config.rtp_config; 52 transport_config.rtp.config = audio_config.rtp_config;
73 transport_config.frequency = audio_config.frequency; 53 transport_config.frequency = audio_config.frequency;
74 transport_config.channels = audio_config.channels; 54 transport_config.channels = audio_config.channels;
75 transport_config.rtp.max_outstanding_frames = 55 transport_config.rtp.max_outstanding_frames =
76 audio_config.rtp_config.max_delay_ms / 100 + 1; 56 audio_config.rtp_config.max_delay_ms / 100 + 1;
77 transport_sender_->InitializeAudio(transport_config); 57 transport_sender_->InitializeAudio(transport_config);
78 } 58 }
79 59
80 AudioSender::~AudioSender() {} 60 AudioSender::~AudioSender() {}
81 61
82 void AudioSender::InitializeTimers() {
83 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
84 if (!timers_initialized_) {
85 timers_initialized_ = true;
86 ScheduleNextRtcpReport();
87 }
88 }
89
90 void AudioSender::InsertAudio(scoped_ptr<AudioBus> audio_bus, 62 void AudioSender::InsertAudio(scoped_ptr<AudioBus> audio_bus,
91 const base::TimeTicks& recorded_time) { 63 const base::TimeTicks& recorded_time) {
92 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 64 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
93 DCHECK(audio_encoder_.get()) << "Invalid internal state"; 65 DCHECK(audio_encoder_.get()) << "Invalid internal state";
94 audio_encoder_->InsertAudio(audio_bus.Pass(), recorded_time); 66 audio_encoder_->InsertAudio(audio_bus.Pass(), recorded_time);
95 } 67 }
96 68
97 void AudioSender::SendEncodedAudioFrame( 69 void AudioSender::SendEncodedAudioFrame(
98 scoped_ptr<transport::EncodedFrame> audio_frame) { 70 scoped_ptr<transport::EncodedFrame> audio_frame) {
99 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 71 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
100 DCHECK(!audio_frame->reference_time.is_null()); 72 DCHECK(!audio_frame->reference_time.is_null());
101 rtp_timestamp_helper_.StoreLatestTime(audio_frame->reference_time, 73 rtp_timestamp_helper_.StoreLatestTime(audio_frame->reference_time,
102 audio_frame->rtp_timestamp); 74 audio_frame->rtp_timestamp);
103 InitializeTimers(); 75
76 // At the start of the session, it's important to send reports before each
77 // frame so that the receiver can properly compute playout times. The reason
78 // more than one report is sent is because transmission is not guaranteed,
79 // only best effort, so we send enough that one should almost certainly get
80 // through.
81 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) {
82 // SendRtcpReport() will schedule future reports to be made if this is the
83 // last "aggressive report."
84 ++num_aggressive_rtcp_reports_sent_;
85 const bool is_last_aggressive_report =
86 (num_aggressive_rtcp_reports_sent_ == kNumAggressiveReportsSentAtStart);
87 VLOG_IF(1, is_last_aggressive_report) << "Sending last aggressive report.";
88 SendRtcpReport(is_last_aggressive_report);
89 }
90
104 transport_sender_->InsertCodedAudioFrame(*audio_frame); 91 transport_sender_->InsertCodedAudioFrame(*audio_frame);
105 } 92 }
106 93
107 void AudioSender::ResendPackets( 94 void AudioSender::ResendPackets(
108 const MissingFramesAndPacketsMap& missing_frames_and_packets) { 95 const MissingFramesAndPacketsMap& missing_frames_and_packets) {
109 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 96 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
110 transport_sender_->ResendPackets(true, missing_frames_and_packets); 97 transport_sender_->ResendPackets(true, missing_frames_and_packets);
111 } 98 }
112 99
113 void AudioSender::IncomingRtcpPacket(scoped_ptr<Packet> packet) { 100 void AudioSender::IncomingRtcpPacket(scoped_ptr<Packet> packet) {
114 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 101 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
115 rtcp_.IncomingRtcpPacket(&packet->front(), packet->size()); 102 rtcp_.IncomingRtcpPacket(&packet->front(), packet->size());
116 } 103 }
117 104
118 void AudioSender::ScheduleNextRtcpReport() { 105 void AudioSender::ScheduleNextRtcpReport() {
119 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 106 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
120 base::TimeDelta time_to_next = 107 base::TimeDelta time_to_next =
121 rtcp_.TimeToSendNextRtcpReport() - cast_environment_->Clock()->NowTicks(); 108 rtcp_.TimeToSendNextRtcpReport() - cast_environment_->Clock()->NowTicks();
122 109
123 time_to_next = std::max( 110 time_to_next = std::max(
124 time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs)); 111 time_to_next, base::TimeDelta::FromMilliseconds(kMinSchedulingDelayMs));
125 112
126 cast_environment_->PostDelayedTask( 113 cast_environment_->PostDelayedTask(
127 CastEnvironment::MAIN, 114 CastEnvironment::MAIN,
128 FROM_HERE, 115 FROM_HERE,
129 base::Bind(&AudioSender::SendRtcpReport, weak_factory_.GetWeakPtr()), 116 base::Bind(&AudioSender::SendRtcpReport,
117 weak_factory_.GetWeakPtr(),
118 true),
130 time_to_next); 119 time_to_next);
131 } 120 }
132 121
133 void AudioSender::SendRtcpReport() { 122 void AudioSender::SendRtcpReport(bool schedule_future_reports) {
134 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); 123 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
135 const base::TimeTicks now = cast_environment_->Clock()->NowTicks(); 124 const base::TimeTicks now = cast_environment_->Clock()->NowTicks();
136 uint32 now_as_rtp_timestamp = 0; 125 uint32 now_as_rtp_timestamp = 0;
137 if (rtp_timestamp_helper_.GetCurrentTimeAsRtpTimestamp( 126 if (rtp_timestamp_helper_.GetCurrentTimeAsRtpTimestamp(
138 now, &now_as_rtp_timestamp)) { 127 now, &now_as_rtp_timestamp)) {
139 rtcp_.SendRtcpFromRtpSender(now, now_as_rtp_timestamp); 128 rtcp_.SendRtcpFromRtpSender(now, now_as_rtp_timestamp);
129 } else {
130 // |rtp_timestamp_helper_| should have stored a mapping by this point.
131 NOTREACHED();
140 } 132 }
141 ScheduleNextRtcpReport(); 133 if (schedule_future_reports)
134 ScheduleNextRtcpReport();
135 }
136
137 void AudioSender::OnReceivedCastFeedback(const RtcpCastMessage& cast_feedback) {
138 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
139
140 if (rtcp_.is_rtt_available()) {
141 // Having the RTT values implies the receiver sent back a receiver report
142 // based on it having received a report from here. Therefore, ensure this
143 // sender stops aggressively sending reports.
144 if (num_aggressive_rtcp_reports_sent_ < kNumAggressiveReportsSentAtStart) {
145 VLOG(1) << "No longer a need to send reports aggressively (sent "
146 << num_aggressive_rtcp_reports_sent_ << ").";
147 num_aggressive_rtcp_reports_sent_ = kNumAggressiveReportsSentAtStart;
148 ScheduleNextRtcpReport();
149 }
150 }
151
152 if (!cast_feedback.missing_frames_and_packets_.empty()) {
153 ResendPackets(cast_feedback.missing_frames_and_packets_);
154 }
155 VLOG(2) << "Received audio ACK "
156 << static_cast<int>(cast_feedback.ack_frame_id_);
142 } 157 }
143 158
144 } // namespace cast 159 } // namespace cast
145 } // namespace media 160 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698