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

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
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "content/common/child_process.h" 12 #include "content/common/child_process.h"
13 #include "content/common/media/audio_messages.h" 13 #include "content/common/media/audio_messages.h"
14 #include "content/renderer/render_thread_impl.h" 14 #include "content/renderer/render_thread_impl.h"
15 #include "media/audio/audio_buffers_state.h" 15 #include "media/audio/audio_buffers_state.h"
16 #include "media/audio/audio_util.h" 16 #include "media/audio/audio_util.h"
17 #include "media/base/filter_host.h" 17 #include "media/base/filter_host.h"
18 18
19 using base::subtle::AtomicWord;
20
19 // We define GetBufferSizeForSampleRate() instead of using 21 // We define GetBufferSizeForSampleRate() instead of using
20 // GetAudioHardwareBufferSize() in audio_util because we're using 22 // GetAudioHardwareBufferSize() in audio_util because we're using
21 // the AUDIO_PCM_LINEAR flag, instead of AUDIO_PCM_LOW_LATENCY, 23 // the AUDIO_PCM_LINEAR flag, instead of AUDIO_PCM_LOW_LATENCY,
22 // which the audio_util functions assume. 24 // which the audio_util functions assume.
23 // 25 //
24 // See: http://code.google.com/p/chromium/issues/detail?id=103627 26 // See: http://code.google.com/p/chromium/issues/detail?id=103627
25 // for a more detailed description of the subtleties. 27 // for a more detailed description of the subtleties.
26 static size_t GetBufferSizeForSampleRate(int sample_rate) { 28 static size_t GetBufferSizeForSampleRate(int sample_rate) {
27 // kNominalBufferSize has been tested on Windows, Mac OS X, and Linux 29 // kNominalBufferSize has been tested on Windows, Mac OS X, and Linux
28 // using the low-latency audio codepath (SyncSocket implementation) 30 // using the low-latency audio codepath (SyncSocket implementation)
29 // with the AUDIO_PCM_LINEAR flag. 31 // with the AUDIO_PCM_LINEAR flag.
30 const size_t kNominalBufferSize = 2048; 32 const size_t kNominalBufferSize = 2048;
31 33
32 if (sample_rate <= 48000) 34 if (sample_rate <= 48000)
33 return kNominalBufferSize; 35 return kNominalBufferSize;
34 else if (sample_rate <= 96000) 36 else if (sample_rate <= 96000)
35 return kNominalBufferSize * 2; 37 return kNominalBufferSize * 2;
36 return kNominalBufferSize * 4; 38 return kNominalBufferSize * 4;
37 } 39 }
38 40
39 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink) 41 AudioRendererImpl::AudioRendererImpl(media::AudioRendererSink* sink)
40 : AudioRendererBase(), 42 : AudioRendererBase(),
41 bytes_per_second_(0), 43 bytes_per_second_(0),
42 stopped_(false), 44 stopped_(false),
43 sink_(sink), 45 sink_(sink),
44 is_initialized_(false) { 46 is_initialized_(false),
47 ended_event_scheduled_(false),
48 io_message_loop_proxy_(ChildProcess::current()->io_message_loop_proxy()),
49 stream_id_(0) {
45 } 50 }
46 51
47 AudioRendererImpl::~AudioRendererImpl() { 52 AudioRendererImpl::~AudioRendererImpl() {
48 } 53 }
49 54
50 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) { 55 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) {
51 if (bytes_per_second_) { 56 if (bytes_per_second_) {
52 return base::TimeDelta::FromMicroseconds( 57 return base::TimeDelta::FromMicroseconds(
53 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_); 58 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_);
54 } 59 }
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
167 172
168 void AudioRendererImpl::SetVolume(float volume) { 173 void AudioRendererImpl::SetVolume(float volume) {
169 if (stopped_) 174 if (stopped_)
170 return; 175 return;
171 DCHECK(sink_.get()); 176 DCHECK(sink_.get());
172 sink_->SetVolume(volume); 177 sink_->SetVolume(volume);
173 } 178 }
174 179
175 void AudioRendererImpl::DoPlay() { 180 void AudioRendererImpl::DoPlay() {
176 earliest_end_time_ = base::Time::Now(); 181 earliest_end_time_ = base::Time::Now();
182 ended_event_scheduled_ = false;
177 DCHECK(sink_.get()); 183 DCHECK(sink_.get());
178 sink_->Play(); 184 sink_->Play();
179 } 185 }
180 186
181 void AudioRendererImpl::DoPause() { 187 void AudioRendererImpl::DoPause() {
188 ++stream_id_;
182 DCHECK(sink_.get()); 189 DCHECK(sink_.get());
183 sink_->Pause(false); 190 sink_->Pause(false);
184 } 191 }
185 192
186 void AudioRendererImpl::DoSeek() { 193 void AudioRendererImpl::DoSeek() {
187 earliest_end_time_ = base::Time::Now(); 194 earliest_end_time_ = base::Time::Now();
195 ended_event_scheduled_ = false;
196 ++stream_id_;
188 197
189 // Pause and flush the stream when we seek to a new location. 198 // Pause and flush the stream when we seek to a new location.
190 DCHECK(sink_.get()); 199 DCHECK(sink_.get());
191 sink_->Pause(true); 200 sink_->Pause(true);
192 } 201 }
193 202
194 size_t AudioRendererImpl::Render(const std::vector<float*>& audio_data, 203 size_t AudioRendererImpl::Render(const std::vector<float*>& audio_data,
195 size_t number_of_frames, 204 size_t number_of_frames,
196 size_t audio_delay_milliseconds) { 205 size_t audio_delay_milliseconds) {
197 if (stopped_ || GetPlaybackRate() == 0.0f) { 206 if (stopped_ || GetPlaybackRate() == 0.0f) {
198 // Output silence if stopped. 207 // Output silence if stopped.
199 for (size_t i = 0; i < audio_data.size(); ++i) 208 for (size_t i = 0; i < audio_data.size(); ++i)
200 memset(audio_data[i], 0, sizeof(float) * number_of_frames); 209 memset(audio_data[i], 0, sizeof(audio_data[i][0]) * number_of_frames);
201 return 0; 210 return 0;
202 } 211 }
203 212
204 // Adjust the playback delay. 213 // Adjust the playback delay.
205 base::TimeDelta request_delay = 214 base::TimeDelta request_delay =
206 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds); 215 base::TimeDelta::FromMilliseconds(audio_delay_milliseconds);
207 216
208 // Finally we need to adjust the delay according to playback rate. 217 // Finally we need to adjust the delay according to playback rate.
209 if (GetPlaybackRate() != 1.0f) { 218 if (GetPlaybackRate() != 1.0f) {
210 request_delay = base::TimeDelta::FromMicroseconds( 219 request_delay = base::TimeDelta::FromMicroseconds(
(...skipping 21 matching lines...) Expand all
232 channels, 241 channels,
233 channel_index, 242 channel_index,
234 bytes_per_frame / channels, 243 bytes_per_frame / channels,
235 filled_frames); 244 filled_frames);
236 245
237 // If FillBuffer() didn't give us enough data then zero out the remainder. 246 // If FillBuffer() didn't give us enough data then zero out the remainder.
238 if (filled_frames < number_of_frames) { 247 if (filled_frames < number_of_frames) {
239 int frames_to_zero = number_of_frames - filled_frames; 248 int frames_to_zero = number_of_frames - filled_frames;
240 memset(audio_data[channel_index] + filled_frames, 249 memset(audio_data[channel_index] + filled_frames,
241 0, 250 0,
242 sizeof(float) * frames_to_zero); 251 sizeof(audio_data[channel_index][0]) * frames_to_zero);
243 } 252 }
244 } 253 }
245 return filled_frames; 254 return filled_frames;
246 } 255 }
247 256
248 void AudioRendererImpl::OnError() { 257 void AudioRendererImpl::OnError() {
249 host()->DisableAudioRenderer(); 258 host()->DisableAudioRenderer();
250 } 259 }
251 260
261 int64 AudioRendererImpl::OnRenderEndOfStreamDelay() {
262 return (earliest_end_time_ - base::Time::Now()).InMilliseconds();
263 }
264
252 void AudioRendererImpl::OnRenderEndOfStream() { 265 void AudioRendererImpl::OnRenderEndOfStream() {
253 // TODO(enal): schedule callback instead of polling. 266 if (!ended_event_scheduled_) {
254 if (base::Time::Now() >= earliest_end_time_) 267 ended_event_scheduled_ = true;
268 int64 delay_ms = OnRenderEndOfStreamDelay();
269 if (delay_ms <= 0) {
270 DoSignalEndOfStream(stream_id_);
271 } else {
272 io_message_loop_proxy_->PostDelayedTask(
273 FROM_HERE,
274 base::Bind(&AudioRendererImpl::DoSignalEndOfStream, this, stream_id_),
275 delay_ms);
scherkus (not reviewing) 2012/02/08 02:10:40 PostDelayedTask() now supports base::TimeDelta and
enal1 2012/02/08 02:43:22 Not MessageLoopProxy::PostDelayedTask(). It is for
scherkus (not reviewing) 2012/02/09 04:52:50 Looks like MLProxy slipped through the cracks! htt
276 }
277 }
278 }
279
280 void AudioRendererImpl::DoSignalEndOfStream(AtomicWord stream_id) {
281 // There is no way to cancel delayed task if we paused or seeked after task
282 // was scheduled, use stream id to catch such case.
283 if (stream_id == stream_id_)
255 SignalEndOfStream(); 284 SignalEndOfStream();
256 } 285 }
OLDNEW
« no previous file with comments | « content/renderer/media/audio_renderer_impl.h ('k') | content/renderer/media/audio_renderer_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698