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

Side by Side Diff: content/renderer/media/audio_renderer_impl.cc

Issue 9347029: Decouple 'give me more data' and 'rendered end of stream' audio callbacks. (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Created 8 years, 10 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 (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "content/renderer/media/audio_renderer_impl.h" 5 #include "content/renderer/media/audio_renderer_impl.h"
6 6
7 #include <math.h> 7 #include <math.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 10
(...skipping 21 matching lines...) Expand all
32 if (sample_rate <= 48000) 32 if (sample_rate <= 48000)
33 return kNominalBufferSize; 33 return kNominalBufferSize;
34 else if (sample_rate <= 96000) 34 else if (sample_rate <= 96000)
35 return kNominalBufferSize * 2; 35 return kNominalBufferSize * 2;
36 return kNominalBufferSize * 4; 36 return kNominalBufferSize * 4;
37 } 37 }
38 38
39 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) 39 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink)
40 : AudioRendererBase(), 40 : AudioRendererBase(),
41 bytes_per_second_(0), 41 bytes_per_second_(0),
42 stopped_(false), 42 state_(NOT_PLAYING),
43 sink_(sink), 43 sink_(sink),
44 is_initialized_(false) { 44 is_initialized_(false) {
45 } 45 }
46 46
47 AudioRendererImpl::~AudioRendererImpl() { 47 AudioRendererImpl::~AudioRendererImpl() {
48 DCHECK(signal_end_of_stream_callback_.IsCancelled());
49 if (!signal_end_of_stream_callback_.IsCancelled())
50 signal_end_of_stream_callback_.Cancel();
48 } 51 }
49 52
50 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) { 53 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) {
51 if (bytes_per_second_) { 54 if (bytes_per_second_) {
52 return base::TimeDelta::FromMicroseconds( 55 return base::TimeDelta::FromMicroseconds(
53 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_); 56 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_);
54 } 57 }
55 return base::TimeDelta(); 58 return base::TimeDelta();
56 } 59 }
57 60
58 void AudioRendererImpl::UpdateEarliestEndTime(int bytes_filled, 61 void AudioRendererImpl::UpdateEarliestEndTime(int bytes_filled,
59 base::TimeDelta request_delay, 62 base::TimeDelta request_delay,
60 base::Time time_now) { 63 base::Time time_now) {
61 if (bytes_filled != 0) { 64 if (bytes_filled != 0) {
62 base::TimeDelta predicted_play_time = ConvertToDuration(bytes_filled); 65 base::TimeDelta predicted_play_time = ConvertToDuration(bytes_filled);
63 float playback_rate = GetPlaybackRate(); 66 float playback_rate = GetPlaybackRate();
64 if (playback_rate != 1.0f) { 67 if (playback_rate != 1.0f) {
65 predicted_play_time = base::TimeDelta::FromMicroseconds( 68 predicted_play_time = base::TimeDelta::FromMicroseconds(
66 static_cast<int64>(ceil(predicted_play_time.InMicroseconds() * 69 static_cast<int64>(ceil(predicted_play_time.InMicroseconds() *
67 playback_rate))); 70 playback_rate)));
68 } 71 }
69 earliest_end_time_ = 72 base::AutoLock auto_lock(audio_renderer_impl_lock_);
73 set_earliest_end_time(
70 std::max(earliest_end_time_, 74 std::max(earliest_end_time_,
71 time_now + request_delay + predicted_play_time); 75 time_now + request_delay + predicted_play_time));
72 } 76 }
73 } 77 }
74 78
75 bool AudioRendererImpl::OnInitialize(int bits_per_channel, 79 bool AudioRendererImpl::OnInitialize(int bits_per_channel,
76 ChannelLayout channel_layout, 80 ChannelLayout channel_layout,
77 int sample_rate) { 81 int sample_rate) {
78 // We use the AUDIO_PCM_LINEAR flag because AUDIO_PCM_LOW_LATENCY 82 // We use the AUDIO_PCM_LINEAR flag because AUDIO_PCM_LOW_LATENCY
79 // does not currently support all the sample-rates that we require. 83 // does not currently support all the sample-rates that we require.
80 // Please see: http://code.google.com/p/chromium/issues/detail?id=103627 84 // Please see: http://code.google.com/p/chromium/issues/detail?id=103627
81 // for more details. 85 // for more details.
(...skipping 17 matching lines...) Expand all
99 103
100 sink_->Start(); 104 sink_->Start();
101 is_initialized_ = true; 105 is_initialized_ = true;
102 return true; 106 return true;
103 } 107 }
104 108
105 return false; 109 return false;
106 } 110 }
107 111
108 void AudioRendererImpl::OnStop() { 112 void AudioRendererImpl::OnStop() {
109 if (stopped_) 113 base::AutoLock auto_lock(audio_renderer_impl_lock_);
114 if (state_ == STOPPED)
110 return; 115 return;
111 116 signal_end_of_stream_callback_.Cancel();
112 DCHECK(sink_.get()); 117 DCHECK(sink_.get());
113 sink_->Stop(); 118 sink_->Stop();
114 119 state_ = STOPPED;
115 stopped_ = true;
116 } 120 }
117 121
118 void AudioRendererImpl::SetPlaybackRate(float rate) { 122 void AudioRendererImpl::SetPlaybackRate(float rate) {
119 DCHECK_LE(0.0f, rate); 123 DCHECK_LE(0.0f, rate);
120 124
121 // Handle the case where we stopped due to IO message loop dying. 125 // Handle the case where we stopped due to IO message loop dying.
122 if (stopped_) { 126 if (stopped()) {
123 AudioRendererBase::SetPlaybackRate(rate); 127 AudioRendererBase::SetPlaybackRate(rate);
124 return; 128 return;
125 } 129 }
126 130
127 // We have two cases here: 131 // We have two cases here:
128 // Play: GetPlaybackRate() == 0.0 && rate != 0.0 132 // Play: GetPlaybackRate() == 0.0 && rate != 0.0
129 // Pause: GetPlaybackRate() != 0.0 && rate == 0.0 133 // Pause: GetPlaybackRate() != 0.0 && rate == 0.0
130 if (GetPlaybackRate() == 0.0f && rate != 0.0f) { 134 if (GetPlaybackRate() == 0.0f && rate != 0.0f) {
131 DoPlay(); 135 DoPlay();
132 } else if (GetPlaybackRate() != 0.0f && rate == 0.0f) { 136 } else if (GetPlaybackRate() != 0.0f && rate == 0.0f) {
133 // Pause is easy, we can always pause. 137 // Pause is easy, we can always pause.
134 DoPause(); 138 DoPause();
135 } 139 }
136 AudioRendererBase::SetPlaybackRate(rate); 140 AudioRendererBase::SetPlaybackRate(rate);
137 } 141 }
138 142
139 void AudioRendererImpl::Pause(const base::Closure& callback) { 143 void AudioRendererImpl::Pause(const base::Closure& callback) {
140 AudioRendererBase::Pause(callback); 144 AudioRendererBase::Pause(callback);
141 if (stopped_) 145 if (stopped())
142 return; 146 return;
143 147
144 DoPause(); 148 DoPause();
145 } 149 }
146 150
147 void AudioRendererImpl::Seek(base::TimeDelta time, 151 void AudioRendererImpl::Seek(base::TimeDelta time,
148 const media::FilterStatusCB& cb) { 152 const media::FilterStatusCB& cb) {
149 AudioRendererBase::Seek(time, cb); 153 AudioRendererBase::Seek(time, cb);
150 if (stopped_) 154 if (stopped())
151 return; 155 return;
152 156
153 DoSeek(); 157 DoSeek();
154 } 158 }
155 159
156 void AudioRendererImpl::Play(const base::Closure& callback) { 160 void AudioRendererImpl::Play(const base::Closure& callback) {
157 AudioRendererBase::Play(callback); 161 AudioRendererBase::Play(callback);
158 if (stopped_) 162 if (stopped())
159 return; 163 return;
160 164
161 if (GetPlaybackRate() != 0.0f) { 165 if (GetPlaybackRate() != 0.0f) {
162 DoPlay(); 166 DoPlay();
163 } else { 167 } else {
164 DoPause(); 168 DoPause();
165 } 169 }
166 } 170 }
167 171
168 void AudioRendererImpl::SetVolume(float volume) { 172 void AudioRendererImpl::SetVolume(float volume) {
169 if (stopped_) 173 if (stopped())
170 return; 174 return;
175
171 DCHECK(sink_.get()); 176 DCHECK(sink_.get());
172 sink_->SetVolume(volume); 177 sink_->SetVolume(volume);
173 } 178 }
174 179
180 void AudioRendererImpl::DoSetOrCheckMessageLoopProxy() {
181 if (pipeline_message_loop_proxy_.get() == NULL) {
182 pipeline_message_loop_proxy_ = current_message_loop_proxy();
183 } else {
184 DCHECK_EQ(pipeline_message_loop_proxy_.get(), current_message_loop_proxy());
185 }
186 }
187
175 void AudioRendererImpl::DoPlay() { 188 void AudioRendererImpl::DoPlay() {
176 earliest_end_time_ = base::Time::Now(); 189 DoSetOrCheckMessageLoopProxy();
190 base::AutoLock auto_lock(audio_renderer_impl_lock_);
191 set_earliest_end_time(base::Time::Now());
192 signal_end_of_stream_callback_.Reset(
193 base::Bind(&AudioRendererImpl::DoSignalEndOfStream, AsWeakPtr()));
scherkus (not reviewing) 2012/03/03 02:24:32 are weak pointers enforced by cancellable callback
194 state_ = PLAYING;
177 DCHECK(sink_.get()); 195 DCHECK(sink_.get());
178 sink_->Play(); 196 sink_->Play();
179 } 197 }
180 198
181 void AudioRendererImpl::DoPause() { 199 void AudioRendererImpl::DoPause() {
200 DoSetOrCheckMessageLoopProxy();
scherkus (not reviewing) 2012/03/03 02:24:32 I would strongly prefer having pipeline set the me
201 base::AutoLock auto_lock(audio_renderer_impl_lock_);
202 signal_end_of_stream_callback_.Cancel();
203 state_ = NOT_PLAYING;
182 DCHECK(sink_.get()); 204 DCHECK(sink_.get());
183 sink_->Pause(false); 205 sink_->Pause(false);
184 } 206 }
185 207
186 void AudioRendererImpl::DoSeek() { 208 void AudioRendererImpl::DoSeek() {
187 earliest_end_time_ = base::Time::Now(); 209 DoSetOrCheckMessageLoopProxy();
210 base::AutoLock auto_lock(audio_renderer_impl_lock_);
211 signal_end_of_stream_callback_.Cancel();
212 state_ = NOT_PLAYING;
213 set_earliest_end_time(base::Time::Now());
188 214
189 // Pause and flush the stream when we seek to a new location. 215 // Pause and flush the stream when we seek to a new location.
190 DCHECK(sink_.get()); 216 DCHECK(sink_.get());
191 sink_->Pause(true); 217 sink_->Pause(true);
192 } 218 }
193 219
194 size_t AudioRendererImpl::Render(const std::vector<float*>& audio_data, 220 size_t AudioRendererImpl::Render(const std::vector<float*>& audio_data,
195 size_t number_of_frames, 221 size_t number_of_frames,
196 size_t audio_delay_milliseconds) { 222 size_t audio_delay_milliseconds) {
197 if (stopped_ || GetPlaybackRate() == 0.0f) { 223 if (state_ == STOPPED || GetPlaybackRate() == 0.0f) {
198 // Output silence if stopped. 224 // Output silence if stopped.
199 for (size_t i = 0; i < audio_data.size(); ++i) 225 for (size_t i = 0; i < audio_data.size(); ++i)
200 memset(audio_data[i], 0, sizeof(float) * number_of_frames); 226 memset(audio_data[i], 0, sizeof(audio_data[i][0]) * number_of_frames);
201 return 0; 227 return 0;
202 } 228 }
203 229
204 // Adjust the playback delay. 230 // Adjust the playback delay.
205 base::TimeDelta request_delay = 231 base::TimeDelta request_delay =
206 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds); 232 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds);
207 233
208 // Finally we need to adjust the delay according to playback rate. 234 // Finally we need to adjust the delay according to playback rate.
209 if (GetPlaybackRate() != 1.0f) { 235 if (GetPlaybackRate() != 1.0f) {
210 request_delay = base::TimeDelta::FromMicroseconds( 236 request_delay = base::TimeDelta::FromMicroseconds(
(...skipping 21 matching lines...) Expand all
232 channels, 258 channels,
233 channel_index, 259 channel_index,
234 bytes_per_frame / channels, 260 bytes_per_frame / channels,
235 filled_frames); 261 filled_frames);
236 262
237 // If FillBuffer() didn't give us enough data then zero out the remainder. 263 // If FillBuffer() didn't give us enough data then zero out the remainder.
238 if (filled_frames < number_of_frames) { 264 if (filled_frames < number_of_frames) {
239 int frames_to_zero = number_of_frames - filled_frames; 265 int frames_to_zero = number_of_frames - filled_frames;
240 memset(audio_data[channel_index] + filled_frames, 266 memset(audio_data[channel_index] + filled_frames,
241 0, 267 0,
242 sizeof(float) * frames_to_zero); 268 sizeof(audio_data[channel_index][0]) * frames_to_zero);
243 } 269 }
244 } 270 }
245 return filled_frames; 271 return filled_frames;
246 } 272 }
247 273
248 void AudioRendererImpl::OnRenderError() { 274 void AudioRendererImpl::OnRenderError() {
249 host()->DisableAudioRenderer(); 275 host()->DisableAudioRenderer();
250 } 276 }
251 277
278 int64 AudioRendererImpl::OnRenderEndOfStreamDelay() {
279 audio_renderer_impl_lock_.AssertAcquired();
280 return (earliest_end_time() - base::Time::Now()).InMilliseconds();
281 }
282
252 void AudioRendererImpl::OnRenderEndOfStream() { 283 void AudioRendererImpl::OnRenderEndOfStream() {
253 // TODO(enal): schedule callback instead of polling. 284 base::AutoLock auto_lock(audio_renderer_impl_lock_);
254 if (base::Time::Now() >= earliest_end_time_) 285 if (state_ == PLAYING) {
255 SignalEndOfStream(); 286 state_ = ENDED_EVENT_SCHEDULED;
287 int64 delay_ms = OnRenderEndOfStreamDelay();
288 if (delay_ms <= 0) {
scherkus (not reviewing) 2012/03/03 02:24:32 if the delay time was calculated to be <=0 wouldn'
289 pipeline_message_loop_proxy_->PostTask(
290 FROM_HERE,
291 signal_end_of_stream_callback_.callback());
292 } else {
293 pipeline_message_loop_proxy_->PostDelayedTask(
294 FROM_HERE,
295 signal_end_of_stream_callback_.callback(),
296 delay_ms);
297 }
298 }
256 } 299 }
300
301 void AudioRendererImpl::DoSignalEndOfStream() {
302 DCHECK_EQ(pipeline_message_loop_proxy_.get(), current_message_loop_proxy());
303 SignalEndOfStream();
304 signal_end_of_stream_callback_.Cancel();
305 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698