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

Side by Side Diff: media/audio/audio_output_controller.cc

Issue 9121062: Remove "high"-latency audio code path (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: more to delete! 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 "media/audio/audio_output_controller.h" 5 #include "media/audio/audio_output_controller.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/debug/trace_event.h" 8 #include "base/debug/trace_event.h"
9 #include "base/message_loop.h" 9 #include "base/message_loop.h"
10 #include "base/synchronization/waitable_event.h" 10 #include "base/synchronization/waitable_event.h"
11 #include "base/threading/platform_thread.h" 11 #include "base/threading/platform_thread.h"
12 #include "base/time.h" 12 #include "base/time.h"
13 13
14 using base::Time; 14 using base::Time;
15 using base::WaitableEvent; 15 using base::WaitableEvent;
16 16
17 namespace media { 17 namespace media {
18 18
19 // Signal a pause in low-latency mode. 19 // Signal a pause in low-latency mode.
20 const int AudioOutputController::kPauseMark = -1; 20 const int AudioOutputController::kPauseMark = -1;
21 21
22 // Polling-related constants. 22 // Polling-related constants.
23 const int AudioOutputController::kPollNumAttempts = 3; 23 const int AudioOutputController::kPollNumAttempts = 3;
24 const int AudioOutputController::kPollPauseInMilliseconds = 3; 24 const int AudioOutputController::kPollPauseInMilliseconds = 3;
25 25
26 AudioOutputController::AudioOutputController(AudioManager* audio_manager, 26 AudioOutputController::AudioOutputController(AudioManager* audio_manager,
27 EventHandler* handler, 27 EventHandler* handler,
28 uint32 capacity,
29 SyncReader* sync_reader) 28 SyncReader* sync_reader)
30 : audio_manager_(audio_manager), 29 : audio_manager_(audio_manager),
31 handler_(handler), 30 handler_(handler),
32 stream_(NULL), 31 stream_(NULL),
33 volume_(1.0), 32 volume_(1.0),
34 state_(kEmpty), 33 state_(kEmpty),
35 buffer_(0, capacity),
36 pending_request_(false),
37 sync_reader_(sync_reader), 34 sync_reader_(sync_reader),
38 message_loop_(NULL), 35 message_loop_(NULL),
39 number_polling_attempts_left_(0), 36 number_polling_attempts_left_(0),
40 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)) { 37 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)) {
41 } 38 }
42 39
43 AudioOutputController::~AudioOutputController() { 40 AudioOutputController::~AudioOutputController() {
44 DCHECK_EQ(kClosed, state_); 41 DCHECK_EQ(kClosed, state_);
45 DCHECK(message_loop_); 42 DCHECK(message_loop_);
46 43
47 if (!message_loop_.get() || message_loop_->BelongsToCurrentThread()) { 44 if (!message_loop_.get() || message_loop_->BelongsToCurrentThread()) {
48 DoStopCloseAndClearStream(NULL); 45 DoStopCloseAndClearStream(NULL);
49 } else { 46 } else {
50 WaitableEvent completion(true /* manual reset */, 47 WaitableEvent completion(true /* manual reset */,
51 false /* initial state */); 48 false /* initial state */);
52 message_loop_->PostTask(FROM_HERE, 49 message_loop_->PostTask(FROM_HERE,
53 base::Bind(&AudioOutputController::DoStopCloseAndClearStream, 50 base::Bind(&AudioOutputController::DoStopCloseAndClearStream,
54 base::Unretained(this), 51 base::Unretained(this),
55 &completion)); 52 &completion));
56 completion.Wait(); 53 completion.Wait();
57 } 54 }
58 } 55 }
59 56
60 // static 57 // static
61 scoped_refptr<AudioOutputController> AudioOutputController::Create( 58 scoped_refptr<AudioOutputController> AudioOutputController::Create(
62 AudioManager* audio_manager, 59 AudioManager* audio_manager,
63 EventHandler* event_handler, 60 EventHandler* event_handler,
64 const AudioParameters& params, 61 const AudioParameters& params,
65 uint32 buffer_capacity) {
66 DCHECK(audio_manager);
67 if (!params.IsValid() || !audio_manager)
68 return NULL;
69
70 // Starts the audio controller thread.
71 scoped_refptr<AudioOutputController> controller(new AudioOutputController(
72 audio_manager, event_handler, buffer_capacity, NULL));
73
74 controller->message_loop_ = audio_manager->GetMessageLoop();
75 controller->message_loop_->PostTask(FROM_HERE, base::Bind(
76 &AudioOutputController::DoCreate, base::Unretained(controller.get()),
77 params));
78 return controller;
79 }
80
81 // static
82 scoped_refptr<AudioOutputController> AudioOutputController::CreateLowLatency(
83 AudioManager* audio_manager,
84 EventHandler* event_handler,
85 const AudioParameters& params,
86 SyncReader* sync_reader) { 62 SyncReader* sync_reader) {
87 DCHECK(audio_manager); 63 DCHECK(audio_manager);
88 DCHECK(sync_reader); 64 DCHECK(sync_reader);
89 65
90 if (!params.IsValid() || !audio_manager) 66 if (!params.IsValid() || !audio_manager)
91 return NULL; 67 return NULL;
92 68
93 // Starts the audio controller thread. 69 // Starts the audio controller thread.
94 scoped_refptr<AudioOutputController> controller(new AudioOutputController( 70 scoped_refptr<AudioOutputController> controller(new AudioOutputController(
95 audio_manager, event_handler, 0, sync_reader)); 71 audio_manager, event_handler, sync_reader));
96 72
97 controller->message_loop_ = audio_manager->GetMessageLoop(); 73 controller->message_loop_ = audio_manager->GetMessageLoop();
98 controller->message_loop_->PostTask(FROM_HERE, base::Bind( 74 controller->message_loop_->PostTask(FROM_HERE, base::Bind(
99 &AudioOutputController::DoCreate, base::Unretained(controller.get()), 75 &AudioOutputController::DoCreate, base::Unretained(controller.get()),
100 params)); 76 params));
101 return controller; 77 return controller;
102 } 78 }
103 79
104 void AudioOutputController::Play() { 80 void AudioOutputController::Play() {
105 DCHECK(message_loop_); 81 DCHECK(message_loop_);
(...skipping 19 matching lines...) Expand all
125 message_loop_->PostTask(FROM_HERE, base::Bind( 101 message_loop_->PostTask(FROM_HERE, base::Bind(
126 &AudioOutputController::DoClose, base::Unretained(this), closed_task)); 102 &AudioOutputController::DoClose, base::Unretained(this), closed_task));
127 } 103 }
128 104
129 void AudioOutputController::SetVolume(double volume) { 105 void AudioOutputController::SetVolume(double volume) {
130 DCHECK(message_loop_); 106 DCHECK(message_loop_);
131 message_loop_->PostTask(FROM_HERE, base::Bind( 107 message_loop_->PostTask(FROM_HERE, base::Bind(
132 &AudioOutputController::DoSetVolume, base::Unretained(this), volume)); 108 &AudioOutputController::DoSetVolume, base::Unretained(this), volume));
133 } 109 }
134 110
135 void AudioOutputController::EnqueueData(const uint8* data, uint32 size) {
136 // Write data to the push source and ask for more data if needed.
137 base::AutoLock auto_lock(lock_);
138 pending_request_ = false;
139 // If |size| is set to 0, it indicates that the audio source doesn't have
140 // more data right now, and so it doesn't make sense to send additional
141 // request.
142 if (size) {
143 buffer_.Append(data, size);
144 SubmitOnMoreData_Locked();
145 }
146 }
147
148 void AudioOutputController::DoCreate(const AudioParameters& params) { 111 void AudioOutputController::DoCreate(const AudioParameters& params) {
149 DCHECK(message_loop_->BelongsToCurrentThread()); 112 DCHECK(message_loop_->BelongsToCurrentThread());
150 113
151 // Close() can be called before DoCreate() is executed. 114 // Close() can be called before DoCreate() is executed.
152 if (state_ == kClosed) 115 if (state_ == kClosed)
153 return; 116 return;
154 DCHECK_EQ(kEmpty, state_); 117 DCHECK_EQ(kEmpty, state_);
155 118
156 DoStopCloseAndClearStream(NULL); 119 DoStopCloseAndClearStream(NULL);
157 stream_ = audio_manager_->MakeAudioOutputStreamProxy(params); 120 stream_ = audio_manager_->MakeAudioOutputStreamProxy(params);
(...skipping 12 matching lines...) Expand all
170 } 133 }
171 134
172 // We have successfully opened the stream. Set the initial volume. 135 // We have successfully opened the stream. Set the initial volume.
173 stream_->SetVolume(volume_); 136 stream_->SetVolume(volume_);
174 137
175 // Finally set the state to kCreated. 138 // Finally set the state to kCreated.
176 state_ = kCreated; 139 state_ = kCreated;
177 140
178 // And then report we have been created. 141 // And then report we have been created.
179 handler_->OnCreated(this); 142 handler_->OnCreated(this);
180
181 // If in normal latency mode then start buffering.
182 if (!LowLatencyMode()) {
183 base::AutoLock auto_lock(lock_);
184 SubmitOnMoreData_Locked();
185 }
186 } 143 }
187 144
188 void AudioOutputController::DoPlay() { 145 void AudioOutputController::DoPlay() {
189 DCHECK(message_loop_->BelongsToCurrentThread()); 146 DCHECK(message_loop_->BelongsToCurrentThread());
190 147
191 // We can start from created or paused state. 148 // We can start from created or paused state.
192 if (state_ != kCreated && state_ != kPaused) 149 if (state_ != kCreated && state_ != kPaused)
193 return; 150 return;
194 151
195 if (LowLatencyMode()) { 152 state_ = kStarting;
196 state_ = kStarting;
197 153
198 // Ask for first packet. 154 // Ask for first packet.
199 sync_reader_->UpdatePendingBytes(0); 155 sync_reader_->UpdatePendingBytes(0);
200 156
201 // Cannot start stream immediately, should give renderer some time 157 // Cannot start stream immediately, should give renderer some time
202 // to deliver data. 158 // to deliver data.
203 number_polling_attempts_left_ = kPollNumAttempts; 159 number_polling_attempts_left_ = kPollNumAttempts;
scherkus (not reviewing) 2012/01/28 02:12:52 I know you didn't write this but this seems odd i
vrk (LEFT CHROMIUM) 2012/01/31 23:53:08 Done. Details in the bug! (crbug.com/112196)
204 message_loop_->PostDelayedTask( 160 message_loop_->PostDelayedTask(
205 FROM_HERE, 161 FROM_HERE,
206 base::Bind(&AudioOutputController::PollAndStartIfDataReady, 162 base::Bind(&AudioOutputController::PollAndStartIfDataReady,
207 weak_this_.GetWeakPtr()), 163 weak_this_.GetWeakPtr()),
208 kPollPauseInMilliseconds); 164 kPollPauseInMilliseconds);
209 } else {
210 StartStream();
211 }
212 } 165 }
213 166
214 void AudioOutputController::PollAndStartIfDataReady() { 167 void AudioOutputController::PollAndStartIfDataReady() {
215 DCHECK(message_loop_->BelongsToCurrentThread()); 168 DCHECK(message_loop_->BelongsToCurrentThread());
216 169
217 // Being paranoid: do nothing if state unexpectedly changed. 170 // Being paranoid: do nothing if state unexpectedly changed.
218 if ((state_ != kStarting) && (state_ != kPausedWhenStarting)) 171 if ((state_ != kStarting) && (state_ != kPausedWhenStarting))
219 return; 172 return;
220 173
221 bool pausing = (state_ == kPausedWhenStarting); 174 bool pausing = (state_ == kPausedWhenStarting);
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
263 state_ = kPausedWhenStarting; 216 state_ = kPausedWhenStarting;
264 break; 217 break;
265 case kPlaying: 218 case kPlaying:
266 state_ = kPaused; 219 state_ = kPaused;
267 220
268 // Then we stop the audio device. This is not the perfect solution 221 // Then we stop the audio device. This is not the perfect solution
269 // because it discards all the internal buffer in the audio device. 222 // because it discards all the internal buffer in the audio device.
270 // TODO(hclam): Actually pause the audio device. 223 // TODO(hclam): Actually pause the audio device.
271 stream_->Stop(); 224 stream_->Stop();
272 225
273 if (LowLatencyMode()) { 226 // Send a special pause mark to the low-latency audio thread.
274 // Send a special pause mark to the low-latency audio thread. 227 sync_reader_->UpdatePendingBytes(kPauseMark);
275 sync_reader_->UpdatePendingBytes(kPauseMark);
276 }
277 228
278 handler_->OnPaused(this); 229 handler_->OnPaused(this);
279 break; 230 break;
280 default: 231 default:
281 return; 232 return;
282 } 233 }
283 } 234 }
284 235
285 void AudioOutputController::DoFlush() { 236 void AudioOutputController::DoFlush() {
286 DCHECK(message_loop_->BelongsToCurrentThread()); 237 DCHECK(message_loop_->BelongsToCurrentThread());
287 238
288 // TODO(hclam): Actually flush the audio device. 239 // TODO(hclam): Actually flush the audio device.
289
290 // If we are in the regular latency mode then flush the push source.
291 if (!sync_reader_) {
292 if (state_ != kPaused)
293 return;
294 base::AutoLock auto_lock(lock_);
295 buffer_.Clear();
296 }
297 } 240 }
298 241
299 void AudioOutputController::DoClose(const base::Closure& closed_task) { 242 void AudioOutputController::DoClose(const base::Closure& closed_task) {
300 DCHECK(message_loop_->BelongsToCurrentThread()); 243 DCHECK(message_loop_->BelongsToCurrentThread());
301 244
302 if (state_ != kClosed) { 245 if (state_ != kClosed) {
303 DoStopCloseAndClearStream(NULL); 246 DoStopCloseAndClearStream(NULL);
304 247 sync_reader_->Close();
305 if (LowLatencyMode()) {
306 sync_reader_->Close();
307 }
308
309 state_ = kClosed; 248 state_ = kClosed;
310 } 249 }
311 250
312 closed_task.Run(); 251 closed_task.Run();
313 } 252 }
314 253
315 void AudioOutputController::DoSetVolume(double volume) { 254 void AudioOutputController::DoSetVolume(double volume) {
316 DCHECK(message_loop_->BelongsToCurrentThread()); 255 DCHECK(message_loop_->BelongsToCurrentThread());
317 256
318 // Saves the volume to a member first. We may not be able to set the volume 257 // Saves the volume to a member first. We may not be able to set the volume
(...skipping 17 matching lines...) Expand all
336 DCHECK(message_loop_->BelongsToCurrentThread()); 275 DCHECK(message_loop_->BelongsToCurrentThread());
337 if (state_ != kClosed) 276 if (state_ != kClosed)
338 handler_->OnError(this, code); 277 handler_->OnError(this, code);
339 } 278 }
340 279
341 uint32 AudioOutputController::OnMoreData( 280 uint32 AudioOutputController::OnMoreData(
342 AudioOutputStream* stream, uint8* dest, 281 AudioOutputStream* stream, uint8* dest,
343 uint32 max_size, AudioBuffersState buffers_state) { 282 uint32 max_size, AudioBuffersState buffers_state) {
344 TRACE_EVENT0("audio", "AudioOutputController::OnMoreData"); 283 TRACE_EVENT0("audio", "AudioOutputController::OnMoreData");
345 284
346 // If regular latency mode is used.
347 if (!sync_reader_) {
348 base::AutoLock auto_lock(lock_);
349
350 // Save current buffers state.
351 buffers_state_ = buffers_state;
352
353 if (state_ != kPlaying) {
354 // Don't read anything. Save the number of bytes in the hardware buffer.
355 return 0;
356 }
357
358 uint32 size = buffer_.Read(dest, max_size);
359 buffers_state_.pending_bytes += size;
360 SubmitOnMoreData_Locked();
361 return size;
362 }
363
364 // Low latency mode.
365 { 285 {
366 // Check state and do nothing if we are not playing. 286 // Check state and do nothing if we are not playing.
367 // We are on the hardware audio thread, so lock is needed. 287 // We are on the hardware audio thread, so lock is needed.
368 base::AutoLock auto_lock(lock_); 288 base::AutoLock auto_lock(lock_);
369 if (state_ != kPlaying) { 289 if (state_ != kPlaying) {
370 return 0; 290 return 0;
371 } 291 }
372 } 292 }
373 uint32 size = sync_reader_->Read(dest, max_size); 293 uint32 size = sync_reader_->Read(dest, max_size);
374 sync_reader_->UpdatePendingBytes(buffers_state.total_bytes() + size); 294 sync_reader_->UpdatePendingBytes(buffers_state.total_bytes() + size);
375 return size; 295 return size;
376 } 296 }
377 297
378 void AudioOutputController::WaitTillDataReady() { 298 void AudioOutputController::WaitTillDataReady() {
379 if (LowLatencyMode() && !sync_reader_->DataReady()) { 299 if (!sync_reader_->DataReady()) {
380 // In the different place we use different mechanism to poll, get max 300 // In the different place we use different mechanism to poll, get max
381 // polling delay from constants used there. 301 // polling delay from constants used there.
382 const base::TimeDelta kMaxPollingDelay = base::TimeDelta::FromMilliseconds( 302 const base::TimeDelta kMaxPollingDelay = base::TimeDelta::FromMilliseconds(
383 kPollNumAttempts * kPollPauseInMilliseconds); 303 kPollNumAttempts * kPollPauseInMilliseconds);
384 Time start_time = Time::Now(); 304 Time start_time = Time::Now();
385 do { 305 do {
386 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1)); 306 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
387 } while (!sync_reader_->DataReady() && 307 } while (!sync_reader_->DataReady() &&
388 Time::Now() - start_time < kMaxPollingDelay); 308 Time::Now() - start_time < kMaxPollingDelay);
389 } 309 }
390 } 310 }
391 311
392 void AudioOutputController::OnError(AudioOutputStream* stream, int code) { 312 void AudioOutputController::OnError(AudioOutputStream* stream, int code) {
393 // Handle error on the audio controller thread. 313 // Handle error on the audio controller thread.
394 message_loop_->PostTask(FROM_HERE, base::Bind( 314 message_loop_->PostTask(FROM_HERE, base::Bind(
395 &AudioOutputController::DoReportError, base::Unretained(this), code)); 315 &AudioOutputController::DoReportError, base::Unretained(this), code));
396 } 316 }
397 317
398 void AudioOutputController::SubmitOnMoreData_Locked() {
399 lock_.AssertAcquired();
400
401 if (buffer_.forward_bytes() > buffer_.forward_capacity())
402 return;
403
404 if (pending_request_)
405 return;
406 pending_request_ = true;
407
408 AudioBuffersState buffers_state = buffers_state_;
409 buffers_state.pending_bytes += buffer_.forward_bytes();
410
411 // If we need more data then call the event handler to ask for more data.
412 // It is okay that we don't lock in this block because the parameters are
413 // correct and in the worst case we are just asking more data than needed.
414 base::AutoUnlock auto_unlock(lock_);
415 handler_->OnMoreData(this, buffers_state);
416 }
417
418 void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent *done) { 318 void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent *done) {
419 DCHECK(message_loop_->BelongsToCurrentThread()); 319 DCHECK(message_loop_->BelongsToCurrentThread());
420 320
421 // Allow calling unconditionally and bail if we don't have a stream_ to close. 321 // Allow calling unconditionally and bail if we don't have a stream_ to close.
422 if (stream_ != NULL) { 322 if (stream_ != NULL) {
423 stream_->Stop(); 323 stream_->Stop();
424 stream_->Close(); 324 stream_->Close();
425 stream_ = NULL; 325 stream_ = NULL;
426 weak_this_.InvalidateWeakPtrs(); 326 weak_this_.InvalidateWeakPtrs();
427 } 327 }
428 328
429 // Should be last in the method, do not touch "this" from here on. 329 // Should be last in the method, do not touch "this" from here on.
430 if (done != NULL) 330 if (done != NULL)
431 done->Signal(); 331 done->Signal();
432 } 332 }
433 333
434 } // namespace media 334 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698