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

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

Issue 3192017: Revert 57254 - Share one thread between all AudioOutputControllers instead of... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 10 years, 4 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) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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/message_loop.h"
8
9 // The following parameters limit the request buffer and packet size from the 7 // The following parameters limit the request buffer and packet size from the
10 // renderer to avoid renderer from requesting too much memory. 8 // renderer to avoid renderer from requesting too much memory.
11 static const uint32 kMegabytes = 1024 * 1024; 9 static const uint32 kMegabytes = 1024 * 1024;
12 static const uint32 kMaxHardwareBufferSize = 2 * kMegabytes; 10 static const uint32 kMaxHardwareBufferSize = 2 * kMegabytes;
13 static const int kMaxChannels = 32; 11 static const int kMaxChannels = 32;
14 static const int kMaxBitsPerSample = 64; 12 static const int kMaxBitsPerSample = 64;
15 static const int kMaxSampleRate = 192000; 13 static const int kMaxSampleRate = 192000;
16 14
17 // Return true if the parameters for creating an audio stream is valid. 15 // Return true if the parameters for creating an audio stream is valid.
18 // Return false otherwise. 16 // Return false otherwise.
(...skipping 11 matching lines...) Expand all
30 } 28 }
31 return true; 29 return true;
32 } 30 }
33 31
34 namespace media { 32 namespace media {
35 33
36 AudioOutputController::AudioOutputController(EventHandler* handler, 34 AudioOutputController::AudioOutputController(EventHandler* handler,
37 uint32 capacity, 35 uint32 capacity,
38 SyncReader* sync_reader) 36 SyncReader* sync_reader)
39 : handler_(handler), 37 : handler_(handler),
40 stream_(NULL),
41 volume_(1.0), 38 volume_(1.0),
42 state_(kEmpty), 39 state_(kEmpty),
43 hardware_pending_bytes_(0), 40 hardware_pending_bytes_(0),
44 buffer_capacity_(capacity), 41 buffer_capacity_(capacity),
45 sync_reader_(sync_reader) { 42 sync_reader_(sync_reader),
43 thread_("AudioOutputControllerThread") {
46 } 44 }
47 45
48 AudioOutputController::~AudioOutputController() { 46 AudioOutputController::~AudioOutputController() {
49 DCHECK(kClosed == state_); 47 DCHECK(kClosed == state_);
50 } 48 }
51 49
52 // static 50 // static
53 scoped_refptr<AudioOutputController> AudioOutputController::Create( 51 scoped_refptr<AudioOutputController> AudioOutputController::Create(
54 EventHandler* event_handler, 52 EventHandler* event_handler,
55 AudioManager::Format format, 53 AudioManager::Format format,
56 int channels, 54 int channels,
57 int sample_rate, 55 int sample_rate,
58 int bits_per_sample, 56 int bits_per_sample,
59 uint32 hardware_buffer_size, 57 uint32 hardware_buffer_size,
60 uint32 buffer_capacity) { 58 uint32 buffer_capacity) {
61 59
62 if (!CheckParameters(channels, sample_rate, bits_per_sample, 60 if (!CheckParameters(channels, sample_rate, bits_per_sample,
63 hardware_buffer_size)) 61 hardware_buffer_size))
64 return NULL; 62 return NULL;
65 63
66 // Starts the audio controller thread. 64 // Starts the audio controller thread.
67 scoped_refptr<AudioOutputController> controller = new AudioOutputController( 65 scoped_refptr<AudioOutputController> controller = new AudioOutputController(
68 event_handler, buffer_capacity, NULL); 66 event_handler, buffer_capacity, NULL);
69 67
70 controller->message_loop_ = 68 // Start the audio controller thread and post a task to create the
71 AudioManager::GetAudioManager()->GetMessageLoop(); 69 // audio stream.
72 controller->message_loop_->PostTask( 70 controller->thread_.Start();
71 controller->thread_.message_loop()->PostTask(
73 FROM_HERE, 72 FROM_HERE,
74 NewRunnableMethod(controller.get(), &AudioOutputController::DoCreate, 73 NewRunnableMethod(controller.get(), &AudioOutputController::DoCreate,
75 format, channels, sample_rate, bits_per_sample, 74 format, channels, sample_rate, bits_per_sample,
76 hardware_buffer_size)); 75 hardware_buffer_size));
77 return controller; 76 return controller;
78 } 77 }
79 78
80 // static 79 // static
81 scoped_refptr<AudioOutputController> AudioOutputController::CreateLowLatency( 80 scoped_refptr<AudioOutputController> AudioOutputController::CreateLowLatency(
82 EventHandler* event_handler, 81 EventHandler* event_handler,
83 AudioManager::Format format, 82 AudioManager::Format format,
84 int channels, 83 int channels,
85 int sample_rate, 84 int sample_rate,
86 int bits_per_sample, 85 int bits_per_sample,
87 uint32 hardware_buffer_size, 86 uint32 hardware_buffer_size,
88 SyncReader* sync_reader) { 87 SyncReader* sync_reader) {
89 88
90 DCHECK(sync_reader); 89 DCHECK(sync_reader);
91 90
92 if (!CheckParameters(channels, sample_rate, bits_per_sample, 91 if (!CheckParameters(channels, sample_rate, bits_per_sample,
93 hardware_buffer_size)) 92 hardware_buffer_size))
94 return NULL; 93 return NULL;
95 94
96 // Starts the audio controller thread. 95 // Starts the audio controller thread.
97 scoped_refptr<AudioOutputController> controller = new AudioOutputController( 96 scoped_refptr<AudioOutputController> controller = new AudioOutputController(
98 event_handler, 0, sync_reader); 97 event_handler, 0, sync_reader);
99 98
100 controller->message_loop_ = 99 // Start the audio controller thread and post a task to create the
101 AudioManager::GetAudioManager()->GetMessageLoop(); 100 // audio stream.
102 controller->message_loop_->PostTask( 101 controller->thread_.Start();
102 controller->thread_.message_loop()->PostTask(
103 FROM_HERE, 103 FROM_HERE,
104 NewRunnableMethod(controller.get(), &AudioOutputController::DoCreate, 104 NewRunnableMethod(controller.get(), &AudioOutputController::DoCreate,
105 format, channels, sample_rate, bits_per_sample, 105 format, channels, sample_rate, bits_per_sample,
106 hardware_buffer_size)); 106 hardware_buffer_size));
107 return controller; 107 return controller;
108 } 108 }
109 109
110 void AudioOutputController::Play() { 110 void AudioOutputController::Play() {
111 DCHECK(message_loop_); 111 DCHECK(thread_.IsRunning());
112 message_loop_->PostTask( 112 thread_.message_loop()->PostTask(
113 FROM_HERE, 113 FROM_HERE,
114 NewRunnableMethod(this, &AudioOutputController::DoPlay)); 114 NewRunnableMethod(this, &AudioOutputController::DoPlay));
115 } 115 }
116 116
117 void AudioOutputController::Pause() { 117 void AudioOutputController::Pause() {
118 DCHECK(message_loop_); 118 DCHECK(thread_.IsRunning());
119 message_loop_->PostTask( 119 thread_.message_loop()->PostTask(
120 FROM_HERE, 120 FROM_HERE,
121 NewRunnableMethod(this, &AudioOutputController::DoPause)); 121 NewRunnableMethod(this, &AudioOutputController::DoPause));
122 } 122 }
123 123
124 void AudioOutputController::Flush() { 124 void AudioOutputController::Flush() {
125 DCHECK(message_loop_); 125 DCHECK(thread_.IsRunning());
126 message_loop_->PostTask( 126 thread_.message_loop()->PostTask(
127 FROM_HERE, 127 FROM_HERE,
128 NewRunnableMethod(this, &AudioOutputController::DoFlush)); 128 NewRunnableMethod(this, &AudioOutputController::DoFlush));
129 } 129 }
130 130
131 void AudioOutputController::Close() { 131 void AudioOutputController::Close() {
132 { 132 if (!thread_.IsRunning()) {
133 AutoLock auto_lock(lock_); 133 // If the thread is not running make sure we are stopped.
134 // Don't do anything if the stream is already closed. 134 DCHECK_EQ(kClosed, state_);
135 if (state_ == kClosed) 135 return;
136 return;
137 state_ = kClosed;
138 } 136 }
139 137
140 message_loop_->PostTask( 138 // Wait for all tasks to complete on the audio thread.
139 thread_.message_loop()->PostTask(
141 FROM_HERE, 140 FROM_HERE,
142 NewRunnableMethod(this, &AudioOutputController::DoClose)); 141 NewRunnableMethod(this, &AudioOutputController::DoClose));
142 thread_.Stop();
143 } 143 }
144 144
145 void AudioOutputController::SetVolume(double volume) { 145 void AudioOutputController::SetVolume(double volume) {
146 DCHECK(message_loop_); 146 DCHECK(thread_.IsRunning());
147 message_loop_->PostTask( 147 thread_.message_loop()->PostTask(
148 FROM_HERE, 148 FROM_HERE,
149 NewRunnableMethod(this, &AudioOutputController::DoSetVolume, volume)); 149 NewRunnableMethod(this, &AudioOutputController::DoSetVolume, volume));
150 } 150 }
151 151
152 void AudioOutputController::EnqueueData(const uint8* data, uint32 size) { 152 void AudioOutputController::EnqueueData(const uint8* data, uint32 size) {
153 // Write data to the push source and ask for more data if needed. 153 // Write data to the push source and ask for more data if needed.
154 AutoLock auto_lock(lock_); 154 AutoLock auto_lock(lock_);
155 push_source_.Write(data, size); 155 push_source_.Write(data, size);
156 SubmitOnMoreData_Locked(); 156 SubmitOnMoreData_Locked();
157 } 157 }
158 158
159 void AudioOutputController::DoCreate(AudioManager::Format format, int channels, 159 void AudioOutputController::DoCreate(AudioManager::Format format, int channels,
160 int sample_rate, int bits_per_sample, 160 int sample_rate, int bits_per_sample,
161 uint32 hardware_buffer_size) { 161 uint32 hardware_buffer_size) {
162 DCHECK_EQ(message_loop_, MessageLoop::current()); 162 DCHECK_EQ(thread_.message_loop(), MessageLoop::current());
163 163 DCHECK_EQ(kEmpty, state_);
164 AutoLock auto_lock(lock_);
165
166 // Close() can be called before DoCreate() is executed.
167 if (state_ == kClosed)
168 return;
169 DCHECK(state_ == kEmpty);
170 164
171 // Create the stream in the first place. 165 // Create the stream in the first place.
172 stream_ = AudioManager::GetAudioManager()->MakeAudioOutputStream( 166 stream_ = AudioManager::GetAudioManager()->MakeAudioOutputStream(
173 format, channels, sample_rate, bits_per_sample); 167 format, channels, sample_rate, bits_per_sample);
174 168
175 if (!stream_) { 169 if (!stream_) {
176 // TODO(hclam): Define error types. 170 // TODO(hclam): Define error types.
177 handler_->OnError(this, 0); 171 handler_->OnError(this, 0);
178 return; 172 return;
179 } 173 }
(...skipping 10 matching lines...) Expand all
190 stream_->SetVolume(volume_); 184 stream_->SetVolume(volume_);
191 185
192 // Finally set the state to kCreated. 186 // Finally set the state to kCreated.
193 state_ = kCreated; 187 state_ = kCreated;
194 188
195 // And then report we have been created. 189 // And then report we have been created.
196 handler_->OnCreated(this); 190 handler_->OnCreated(this);
197 191
198 // If in normal latency mode then start buffering. 192 // If in normal latency mode then start buffering.
199 if (!LowLatencyMode()) { 193 if (!LowLatencyMode()) {
194 AutoLock auto_lock(lock_);
200 SubmitOnMoreData_Locked(); 195 SubmitOnMoreData_Locked();
201 } 196 }
202 } 197 }
203 198
204 void AudioOutputController::DoPlay() { 199 void AudioOutputController::DoPlay() {
205 DCHECK_EQ(message_loop_, MessageLoop::current()); 200 DCHECK_EQ(thread_.message_loop(), MessageLoop::current());
201
202 // We can start from created or paused state.
203 if (state_ != kCreated && state_ != kPaused)
204 return;
206 205
207 State old_state; 206 State old_state;
208 // Update the |state_| to kPlaying. 207 // Update the |state_| to kPlaying.
209 { 208 {
210 AutoLock auto_lock(lock_); 209 AutoLock auto_lock(lock_);
211 // We can start from created or paused state.
212 if (state_ != kCreated && state_ != kPaused)
213 return;
214 old_state = state_; 210 old_state = state_;
215 state_ = kPlaying; 211 state_ = kPlaying;
216 } 212 }
217 213
218 // We start the AudioOutputStream lazily. 214 // We start the AudioOutputStream lazily.
219 stream_->Start(this); 215 stream_->Start(this);
220 216
221 // Tell the event handler that we are now playing. 217 // Tell the event handler that we are now playing.
222 handler_->OnPlaying(this); 218 handler_->OnPlaying(this);
223 } 219 }
224 220
225 void AudioOutputController::DoPause() { 221 void AudioOutputController::DoPause() {
226 DCHECK_EQ(message_loop_, MessageLoop::current()); 222 DCHECK_EQ(thread_.message_loop(), MessageLoop::current());
223
224 // We can pause from started state.
225 if (state_ != kPlaying)
226 return;
227 227
228 // Sets the |state_| to kPaused so we don't draw more audio data. 228 // Sets the |state_| to kPaused so we don't draw more audio data.
229 { 229 {
230 AutoLock auto_lock(lock_); 230 AutoLock auto_lock(lock_);
231 // We can pause from started state.
232 if (state_ != kPlaying)
233 return;
234 state_ = kPaused; 231 state_ = kPaused;
235 } 232 }
236 233
237 // Then we stop the audio device. This is not the perfect solution because 234 // Then we stop the audio device. This is not the perfect solution because
238 // it discards all the internal buffer in the audio device. 235 // it discards all the internal buffer in the audio device.
239 // TODO(hclam): Actually pause the audio device. 236 // TODO(hclam): Actually pause the audio device.
240 stream_->Stop(); 237 stream_->Stop();
241 238
242 handler_->OnPaused(this); 239 handler_->OnPaused(this);
243 } 240 }
244 241
245 void AudioOutputController::DoFlush() { 242 void AudioOutputController::DoFlush() {
246 DCHECK_EQ(message_loop_, MessageLoop::current()); 243 DCHECK_EQ(thread_.message_loop(), MessageLoop::current());
244
245 if (state_ != kPaused)
246 return;
247 247
248 // TODO(hclam): Actually flush the audio device. 248 // TODO(hclam): Actually flush the audio device.
249 249
250 // If we are in the regular latency mode then flush the push source. 250 // If we are in the regular latency mode then flush the push source.
251 if (!sync_reader_) { 251 if (!sync_reader_) {
252 AutoLock auto_lock(lock_); 252 AutoLock auto_lock(lock_);
253 if (state_ != kPaused)
254 return;
255 push_source_.ClearAll(); 253 push_source_.ClearAll();
256 } 254 }
257 } 255 }
258 256
259 void AudioOutputController::DoClose() { 257 void AudioOutputController::DoClose() {
260 DCHECK_EQ(message_loop_, MessageLoop::current()); 258 DCHECK_EQ(thread_.message_loop(), MessageLoop::current());
261 DCHECK_EQ(kClosed, state_); 259 DCHECK_NE(kClosed, state_);
260
262 // |stream_| can be null if creating the device failed in DoCreate(). 261 // |stream_| can be null if creating the device failed in DoCreate().
263 if (stream_) { 262 if (stream_) {
264 stream_->Stop(); 263 stream_->Stop();
265 stream_->Close(); 264 stream_->Close();
266 // After stream is closed it is destroyed, so don't keep a reference to it. 265 // After stream is closed it is destroyed, so don't keep a reference to it.
267 stream_ = NULL; 266 stream_ = NULL;
268 } 267 }
268
269 // Update the current state. Since the stream is closed at this point
270 // there's no other threads reading |state_| so we don't need to lock.
271 state_ = kClosed;
269 } 272 }
270 273
271 void AudioOutputController::DoSetVolume(double volume) { 274 void AudioOutputController::DoSetVolume(double volume) {
272 DCHECK_EQ(message_loop_, MessageLoop::current()); 275 DCHECK_EQ(thread_.message_loop(), MessageLoop::current());
273 276
274 // Saves the volume to a member first. We may not be able to set the volume 277 // Saves the volume to a member first. We may not be able to set the volume
275 // right away but when the stream is created we'll set the volume. 278 // right away but when the stream is created we'll set the volume.
276 volume_ = volume; 279 volume_ = volume;
277 280
278 { 281 if (state_ != kPlaying && state_ != kPaused && state_ != kCreated)
279 AutoLock auto_lock(lock_); 282 return;
280 if (state_ != kPlaying && state_ != kPaused && state_ != kCreated)
281 return;
282 }
283 283
284 stream_->SetVolume(volume_); 284 stream_->SetVolume(volume_);
285 } 285 }
286 286
287 void AudioOutputController::DoReportError(int code) { 287 void AudioOutputController::DoReportError(int code) {
288 DCHECK_EQ(message_loop_, MessageLoop::current()); 288 DCHECK_EQ(thread_.message_loop(), MessageLoop::current());
289 handler_->OnError(this, code); 289 handler_->OnError(this, code);
290 } 290 }
291 291
292 uint32 AudioOutputController::OnMoreData(AudioOutputStream* stream, 292 uint32 AudioOutputController::OnMoreData(AudioOutputStream* stream,
293 void* dest, 293 void* dest,
294 uint32 max_size, 294 uint32 max_size,
295 uint32 pending_bytes) { 295 uint32 pending_bytes) {
296 // If regular latency mode is used. 296 // If regular latency mode is used.
297 if (!sync_reader_) { 297 if (!sync_reader_) {
298 AutoLock auto_lock(lock_); 298 AutoLock auto_lock(lock_);
(...skipping 26 matching lines...) Expand all
325 if (LowLatencyMode()) { 325 if (LowLatencyMode()) {
326 sync_reader_->Close(); 326 sync_reader_->Close();
327 } else { 327 } else {
328 AutoLock auto_lock(lock_); 328 AutoLock auto_lock(lock_);
329 push_source_.OnClose(NULL); 329 push_source_.OnClose(NULL);
330 } 330 }
331 } 331 }
332 332
333 void AudioOutputController::OnError(AudioOutputStream* stream, int code) { 333 void AudioOutputController::OnError(AudioOutputStream* stream, int code) {
334 // Handle error on the audio controller thread. 334 // Handle error on the audio controller thread.
335 message_loop_->PostTask( 335 thread_.message_loop()->PostTask(
336 FROM_HERE, 336 FROM_HERE,
337 NewRunnableMethod(this, &AudioOutputController::DoReportError, code)); 337 NewRunnableMethod(this, &AudioOutputController::DoReportError, code));
338 } 338 }
339 339
340 void AudioOutputController::SubmitOnMoreData_Locked() { 340 void AudioOutputController::SubmitOnMoreData_Locked() {
341 lock_.AssertAcquired(); 341 lock_.AssertAcquired();
342 342
343 if (push_source_.UnProcessedBytes() > buffer_capacity_) 343 if (push_source_.UnProcessedBytes() > buffer_capacity_)
344 return; 344 return;
345 345
346 base::Time timestamp = last_callback_time_; 346 base::Time timestamp = last_callback_time_;
347 uint32 pending_bytes = hardware_pending_bytes_ + 347 uint32 pending_bytes = hardware_pending_bytes_ +
348 push_source_.UnProcessedBytes(); 348 push_source_.UnProcessedBytes();
349 349
350 // If we need more data then call the event handler to ask for more data. 350 // If we need more data then call the event handler to ask for more data.
351 // It is okay that we don't lock in this block because the parameters are 351 // It is okay that we don't lock in this block because the parameters are
352 // correct and in the worst case we are just asking more data than needed. 352 // correct and in the worst case we are just asking more data than needed.
353 AutoUnlock auto_unlock(lock_); 353 AutoUnlock auto_unlock(lock_);
354 handler_->OnMoreData(this, timestamp, pending_bytes); 354 handler_->OnMoreData(this, timestamp, pending_bytes);
355 } 355 }
356 356
357 } // namespace media 357 } // 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