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

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: Rebase ToT yet again 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
« no previous file with comments | « media/audio/audio_output_controller.h ('k') | media/audio/audio_output_controller_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // TODO(vrk): The polling here and in WaitTillDataReady() is pretty clunky.
204 message_loop_->PostDelayedTask( 160 // Refine the API such that polling is no longer needed. (crbug.com/112196)
205 FROM_HERE, 161 number_polling_attempts_left_ = kPollNumAttempts;
206 base::Bind(&AudioOutputController::PollAndStartIfDataReady, 162 message_loop_->PostDelayedTask(
207 weak_this_.GetWeakPtr()), 163 FROM_HERE,
208 kPollPauseInMilliseconds); 164 base::Bind(&AudioOutputController::PollAndStartIfDataReady,
209 } else { 165 weak_this_.GetWeakPtr()),
210 StartStream(); 166 kPollPauseInMilliseconds);
211 }
212 } 167 }
213 168
214 void AudioOutputController::PollAndStartIfDataReady() { 169 void AudioOutputController::PollAndStartIfDataReady() {
215 DCHECK(message_loop_->BelongsToCurrentThread()); 170 DCHECK(message_loop_->BelongsToCurrentThread());
216 171
217 // Being paranoid: do nothing if state unexpectedly changed. 172 // Being paranoid: do nothing if state unexpectedly changed.
218 if ((state_ != kStarting) && (state_ != kPausedWhenStarting)) 173 if ((state_ != kStarting) && (state_ != kPausedWhenStarting))
219 return; 174 return;
220 175
221 bool pausing = (state_ == kPausedWhenStarting); 176 bool pausing = (state_ == kPausedWhenStarting);
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
263 state_ = kPausedWhenStarting; 218 state_ = kPausedWhenStarting;
264 break; 219 break;
265 case kPlaying: 220 case kPlaying:
266 state_ = kPaused; 221 state_ = kPaused;
267 222
268 // Then we stop the audio device. This is not the perfect solution 223 // Then we stop the audio device. This is not the perfect solution
269 // because it discards all the internal buffer in the audio device. 224 // because it discards all the internal buffer in the audio device.
270 // TODO(hclam): Actually pause the audio device. 225 // TODO(hclam): Actually pause the audio device.
271 stream_->Stop(); 226 stream_->Stop();
272 227
273 if (LowLatencyMode()) { 228 // Send a special pause mark to the low-latency audio thread.
274 // Send a special pause mark to the low-latency audio thread. 229 sync_reader_->UpdatePendingBytes(kPauseMark);
275 sync_reader_->UpdatePendingBytes(kPauseMark);
276 }
277 230
278 handler_->OnPaused(this); 231 handler_->OnPaused(this);
279 break; 232 break;
280 default: 233 default:
281 return; 234 return;
282 } 235 }
283 } 236 }
284 237
285 void AudioOutputController::DoFlush() { 238 void AudioOutputController::DoFlush() {
286 DCHECK(message_loop_->BelongsToCurrentThread()); 239 DCHECK(message_loop_->BelongsToCurrentThread());
287 240
288 // TODO(hclam): Actually flush the audio device. 241 // 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 } 242 }
298 243
299 void AudioOutputController::DoClose(const base::Closure& closed_task) { 244 void AudioOutputController::DoClose(const base::Closure& closed_task) {
300 DCHECK(message_loop_->BelongsToCurrentThread()); 245 DCHECK(message_loop_->BelongsToCurrentThread());
301 246
302 if (state_ != kClosed) { 247 if (state_ != kClosed) {
303 DoStopCloseAndClearStream(NULL); 248 DoStopCloseAndClearStream(NULL);
304 249 sync_reader_->Close();
305 if (LowLatencyMode()) {
306 sync_reader_->Close();
307 }
308
309 state_ = kClosed; 250 state_ = kClosed;
310 } 251 }
311 252
312 closed_task.Run(); 253 closed_task.Run();
313 } 254 }
314 255
315 void AudioOutputController::DoSetVolume(double volume) { 256 void AudioOutputController::DoSetVolume(double volume) {
316 DCHECK(message_loop_->BelongsToCurrentThread()); 257 DCHECK(message_loop_->BelongsToCurrentThread());
317 258
318 // Saves the volume to a member first. We may not be able to set the volume 259 // 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()); 277 DCHECK(message_loop_->BelongsToCurrentThread());
337 if (state_ != kClosed) 278 if (state_ != kClosed)
338 handler_->OnError(this, code); 279 handler_->OnError(this, code);
339 } 280 }
340 281
341 uint32 AudioOutputController::OnMoreData( 282 uint32 AudioOutputController::OnMoreData(
342 AudioOutputStream* stream, uint8* dest, 283 AudioOutputStream* stream, uint8* dest,
343 uint32 max_size, AudioBuffersState buffers_state) { 284 uint32 max_size, AudioBuffersState buffers_state) {
344 TRACE_EVENT0("audio", "AudioOutputController::OnMoreData"); 285 TRACE_EVENT0("audio", "AudioOutputController::OnMoreData");
345 286
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 { 287 {
366 // Check state and do nothing if we are not playing. 288 // Check state and do nothing if we are not playing.
367 // We are on the hardware audio thread, so lock is needed. 289 // We are on the hardware audio thread, so lock is needed.
368 base::AutoLock auto_lock(lock_); 290 base::AutoLock auto_lock(lock_);
369 if (state_ != kPlaying) { 291 if (state_ != kPlaying) {
370 return 0; 292 return 0;
371 } 293 }
372 } 294 }
373 uint32 size = sync_reader_->Read(dest, max_size); 295 uint32 size = sync_reader_->Read(dest, max_size);
374 sync_reader_->UpdatePendingBytes(buffers_state.total_bytes() + size); 296 sync_reader_->UpdatePendingBytes(buffers_state.total_bytes() + size);
375 return size; 297 return size;
376 } 298 }
377 299
378 void AudioOutputController::WaitTillDataReady() { 300 void AudioOutputController::WaitTillDataReady() {
379 if (LowLatencyMode() && !sync_reader_->DataReady()) { 301 if (!sync_reader_->DataReady()) {
380 // In the different place we use different mechanism to poll, get max 302 // In the different place we use different mechanism to poll, get max
381 // polling delay from constants used there. 303 // polling delay from constants used there.
382 const base::TimeDelta kMaxPollingDelay = base::TimeDelta::FromMilliseconds( 304 const base::TimeDelta kMaxPollingDelay = base::TimeDelta::FromMilliseconds(
383 kPollNumAttempts * kPollPauseInMilliseconds); 305 kPollNumAttempts * kPollPauseInMilliseconds);
384 Time start_time = Time::Now(); 306 Time start_time = Time::Now();
385 do { 307 do {
386 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1)); 308 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
387 } while (!sync_reader_->DataReady() && 309 } while (!sync_reader_->DataReady() &&
388 Time::Now() - start_time < kMaxPollingDelay); 310 Time::Now() - start_time < kMaxPollingDelay);
389 } 311 }
390 } 312 }
391 313
392 void AudioOutputController::OnError(AudioOutputStream* stream, int code) { 314 void AudioOutputController::OnError(AudioOutputStream* stream, int code) {
393 // Handle error on the audio controller thread. 315 // Handle error on the audio controller thread.
394 message_loop_->PostTask(FROM_HERE, base::Bind( 316 message_loop_->PostTask(FROM_HERE, base::Bind(
395 &AudioOutputController::DoReportError, base::Unretained(this), code)); 317 &AudioOutputController::DoReportError, base::Unretained(this), code));
396 } 318 }
397 319
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) { 320 void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent *done) {
419 DCHECK(message_loop_->BelongsToCurrentThread()); 321 DCHECK(message_loop_->BelongsToCurrentThread());
420 322
421 // Allow calling unconditionally and bail if we don't have a stream_ to close. 323 // Allow calling unconditionally and bail if we don't have a stream_ to close.
422 if (stream_ != NULL) { 324 if (stream_ != NULL) {
423 stream_->Stop(); 325 stream_->Stop();
424 stream_->Close(); 326 stream_->Close();
425 stream_ = NULL; 327 stream_ = NULL;
426 weak_this_.InvalidateWeakPtrs(); 328 weak_this_.InvalidateWeakPtrs();
427 } 329 }
428 330
429 // Should be last in the method, do not touch "this" from here on. 331 // Should be last in the method, do not touch "this" from here on.
430 if (done != NULL) 332 if (done != NULL)
431 done->Signal(); 333 done->Signal();
432 } 334 }
433 335
434 } // namespace media 336 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/audio_output_controller.h ('k') | media/audio/audio_output_controller_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698