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

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

Issue 3185022: Share one thread between all AudioOutputControllers instead of creating one per stream. (Closed)
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
« 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
7 // The following parameters limit the request buffer and packet size from the 9 // The following parameters limit the request buffer and packet size from the
8 // renderer to avoid renderer from requesting too much memory. 10 // renderer to avoid renderer from requesting too much memory.
9 static const uint32 kMegabytes = 1024 * 1024; 11 static const uint32 kMegabytes = 1024 * 1024;
10 static const uint32 kMaxHardwareBufferSize = 2 * kMegabytes; 12 static const uint32 kMaxHardwareBufferSize = 2 * kMegabytes;
11 static const int kMaxChannels = 32; 13 static const int kMaxChannels = 32;
12 static const int kMaxBitsPerSample = 64; 14 static const int kMaxBitsPerSample = 64;
13 static const int kMaxSampleRate = 192000; 15 static const int kMaxSampleRate = 192000;
14 16
15 // Return true if the parameters for creating an audio stream is valid. 17 // Return true if the parameters for creating an audio stream is valid.
16 // Return false otherwise. 18 // Return false otherwise.
(...skipping 11 matching lines...) Expand all
28 } 30 }
29 return true; 31 return true;
30 } 32 }
31 33
32 namespace media { 34 namespace media {
33 35
34 AudioOutputController::AudioOutputController(EventHandler* handler, 36 AudioOutputController::AudioOutputController(EventHandler* handler,
35 uint32 capacity, 37 uint32 capacity,
36 SyncReader* sync_reader) 38 SyncReader* sync_reader)
37 : handler_(handler), 39 : handler_(handler),
40 stream_(NULL),
38 volume_(1.0), 41 volume_(1.0),
39 state_(kEmpty), 42 state_(kEmpty),
40 hardware_pending_bytes_(0), 43 hardware_pending_bytes_(0),
41 buffer_capacity_(capacity), 44 buffer_capacity_(capacity),
42 sync_reader_(sync_reader), 45 sync_reader_(sync_reader) {
43 thread_("AudioOutputControllerThread") {
44 } 46 }
45 47
46 AudioOutputController::~AudioOutputController() { 48 AudioOutputController::~AudioOutputController() {
47 DCHECK(kClosed == state_); 49 DCHECK(kClosed == state_);
48 } 50 }
49 51
50 // static 52 // static
51 scoped_refptr<AudioOutputController> AudioOutputController::Create( 53 scoped_refptr<AudioOutputController> AudioOutputController::Create(
52 EventHandler* event_handler, 54 EventHandler* event_handler,
53 AudioManager::Format format, 55 AudioManager::Format format,
54 int channels, 56 int channels,
55 int sample_rate, 57 int sample_rate,
56 int bits_per_sample, 58 int bits_per_sample,
57 uint32 hardware_buffer_size, 59 uint32 hardware_buffer_size,
58 uint32 buffer_capacity) { 60 uint32 buffer_capacity) {
59 61
60 if (!CheckParameters(channels, sample_rate, bits_per_sample, 62 if (!CheckParameters(channels, sample_rate, bits_per_sample,
61 hardware_buffer_size)) 63 hardware_buffer_size))
62 return NULL; 64 return NULL;
63 65
64 // Starts the audio controller thread. 66 // Starts the audio controller thread.
65 scoped_refptr<AudioOutputController> controller = new AudioOutputController( 67 scoped_refptr<AudioOutputController> controller = new AudioOutputController(
66 event_handler, buffer_capacity, NULL); 68 event_handler, buffer_capacity, NULL);
67 69
68 // Start the audio controller thread and post a task to create the 70 controller->message_loop_ =
69 // audio stream. 71 AudioManager::GetAudioManager()->GetMessageLoop();
70 controller->thread_.Start(); 72 controller->message_loop_->PostTask(
71 controller->thread_.message_loop()->PostTask(
72 FROM_HERE, 73 FROM_HERE,
73 NewRunnableMethod(controller.get(), &AudioOutputController::DoCreate, 74 NewRunnableMethod(controller.get(), &AudioOutputController::DoCreate,
74 format, channels, sample_rate, bits_per_sample, 75 format, channels, sample_rate, bits_per_sample,
75 hardware_buffer_size)); 76 hardware_buffer_size));
76 return controller; 77 return controller;
77 } 78 }
78 79
79 // static 80 // static
80 scoped_refptr<AudioOutputController> AudioOutputController::CreateLowLatency( 81 scoped_refptr<AudioOutputController> AudioOutputController::CreateLowLatency(
81 EventHandler* event_handler, 82 EventHandler* event_handler,
82 AudioManager::Format format, 83 AudioManager::Format format,
83 int channels, 84 int channels,
84 int sample_rate, 85 int sample_rate,
85 int bits_per_sample, 86 int bits_per_sample,
86 uint32 hardware_buffer_size, 87 uint32 hardware_buffer_size,
87 SyncReader* sync_reader) { 88 SyncReader* sync_reader) {
88 89
89 DCHECK(sync_reader); 90 DCHECK(sync_reader);
90 91
91 if (!CheckParameters(channels, sample_rate, bits_per_sample, 92 if (!CheckParameters(channels, sample_rate, bits_per_sample,
92 hardware_buffer_size)) 93 hardware_buffer_size))
93 return NULL; 94 return NULL;
94 95
95 // Starts the audio controller thread. 96 // Starts the audio controller thread.
96 scoped_refptr<AudioOutputController> controller = new AudioOutputController( 97 scoped_refptr<AudioOutputController> controller = new AudioOutputController(
97 event_handler, 0, sync_reader); 98 event_handler, 0, sync_reader);
98 99
99 // Start the audio controller thread and post a task to create the 100 controller->message_loop_ =
100 // audio stream. 101 AudioManager::GetAudioManager()->GetMessageLoop();
101 controller->thread_.Start(); 102 controller->message_loop_->PostTask(
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(thread_.IsRunning()); 111 DCHECK(message_loop_);
112 thread_.message_loop()->PostTask( 112 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(thread_.IsRunning()); 118 DCHECK(message_loop_);
119 thread_.message_loop()->PostTask( 119 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(thread_.IsRunning()); 125 DCHECK(message_loop_);
126 thread_.message_loop()->PostTask( 126 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 if (!thread_.IsRunning()) { 132 {
133 // If the thread is not running make sure we are stopped. 133 AutoLock auto_lock(lock_);
134 DCHECK_EQ(kClosed, state_); 134 // Don't do anything if the stream is already closed.
135 return; 135 if (state_ == kClosed)
136 return;
137 state_ = kClosed;
136 } 138 }
137 139
138 // Wait for all tasks to complete on the audio thread. 140 message_loop_->PostTask(
139 thread_.message_loop()->PostTask(
140 FROM_HERE, 141 FROM_HERE,
141 NewRunnableMethod(this, &AudioOutputController::DoClose)); 142 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(thread_.IsRunning()); 146 DCHECK(message_loop_);
147 thread_.message_loop()->PostTask( 147 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(thread_.message_loop(), MessageLoop::current()); 162 DCHECK_EQ(message_loop_, MessageLoop::current());
163 DCHECK_EQ(kEmpty, state_); 163
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);
164 170
165 // Create the stream in the first place. 171 // Create the stream in the first place.
166 stream_ = AudioManager::GetAudioManager()->MakeAudioOutputStream( 172 stream_ = AudioManager::GetAudioManager()->MakeAudioOutputStream(
167 format, channels, sample_rate, bits_per_sample); 173 format, channels, sample_rate, bits_per_sample);
168 174
169 if (!stream_) { 175 if (!stream_) {
170 // TODO(hclam): Define error types. 176 // TODO(hclam): Define error types.
171 handler_->OnError(this, 0); 177 handler_->OnError(this, 0);
172 return; 178 return;
173 } 179 }
(...skipping 10 matching lines...) Expand all
184 stream_->SetVolume(volume_); 190 stream_->SetVolume(volume_);
185 191
186 // Finally set the state to kCreated. 192 // Finally set the state to kCreated.
187 state_ = kCreated; 193 state_ = kCreated;
188 194
189 // And then report we have been created. 195 // And then report we have been created.
190 handler_->OnCreated(this); 196 handler_->OnCreated(this);
191 197
192 // If in normal latency mode then start buffering. 198 // If in normal latency mode then start buffering.
193 if (!LowLatencyMode()) { 199 if (!LowLatencyMode()) {
194 AutoLock auto_lock(lock_);
195 SubmitOnMoreData_Locked(); 200 SubmitOnMoreData_Locked();
196 } 201 }
197 } 202 }
198 203
199 void AudioOutputController::DoPlay() { 204 void AudioOutputController::DoPlay() {
200 DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); 205 DCHECK_EQ(message_loop_, MessageLoop::current());
201
202 // We can start from created or paused state.
203 if (state_ != kCreated && state_ != kPaused)
204 return;
205 206
206 State old_state; 207 State old_state;
207 // Update the |state_| to kPlaying. 208 // Update the |state_| to kPlaying.
208 { 209 {
209 AutoLock auto_lock(lock_); 210 AutoLock auto_lock(lock_);
211 // We can start from created or paused state.
212 if (state_ != kCreated && state_ != kPaused)
213 return;
210 old_state = state_; 214 old_state = state_;
211 state_ = kPlaying; 215 state_ = kPlaying;
212 } 216 }
213 217
214 // We start the AudioOutputStream lazily. 218 // We start the AudioOutputStream lazily.
215 stream_->Start(this); 219 stream_->Start(this);
216 220
217 // Tell the event handler that we are now playing. 221 // Tell the event handler that we are now playing.
218 handler_->OnPlaying(this); 222 handler_->OnPlaying(this);
219 } 223 }
220 224
221 void AudioOutputController::DoPause() { 225 void AudioOutputController::DoPause() {
222 DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); 226 DCHECK_EQ(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;
231 state_ = kPaused; 234 state_ = kPaused;
232 } 235 }
233 236
234 // Then we stop the audio device. This is not the perfect solution because 237 // Then we stop the audio device. This is not the perfect solution because
235 // it discards all the internal buffer in the audio device. 238 // it discards all the internal buffer in the audio device.
236 // TODO(hclam): Actually pause the audio device. 239 // TODO(hclam): Actually pause the audio device.
237 stream_->Stop(); 240 stream_->Stop();
238 241
239 handler_->OnPaused(this); 242 handler_->OnPaused(this);
240 } 243 }
241 244
242 void AudioOutputController::DoFlush() { 245 void AudioOutputController::DoFlush() {
243 DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); 246 DCHECK_EQ(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;
253 push_source_.ClearAll(); 255 push_source_.ClearAll();
254 } 256 }
255 } 257 }
256 258
257 void AudioOutputController::DoClose() { 259 void AudioOutputController::DoClose() {
258 DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); 260 DCHECK_EQ(message_loop_, MessageLoop::current());
259 DCHECK_NE(kClosed, state_); 261 DCHECK_EQ(kClosed, state_);
260
261 // |stream_| can be null if creating the device failed in DoCreate(). 262 // |stream_| can be null if creating the device failed in DoCreate().
262 if (stream_) { 263 if (stream_) {
263 stream_->Stop(); 264 stream_->Stop();
264 stream_->Close(); 265 stream_->Close();
265 // After stream is closed it is destroyed, so don't keep a reference to it. 266 // After stream is closed it is destroyed, so don't keep a reference to it.
266 stream_ = NULL; 267 stream_ = NULL;
267 } 268 }
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;
272 } 269 }
273 270
274 void AudioOutputController::DoSetVolume(double volume) { 271 void AudioOutputController::DoSetVolume(double volume) {
275 DCHECK_EQ(thread_.message_loop(), MessageLoop::current()); 272 DCHECK_EQ(message_loop_, MessageLoop::current());
276 273
277 // Saves the volume to a member first. We may not be able to set the volume 274 // Saves the volume to a member first. We may not be able to set the volume
278 // right away but when the stream is created we'll set the volume. 275 // right away but when the stream is created we'll set the volume.
279 volume_ = volume; 276 volume_ = volume;
280 277
281 if (state_ != kPlaying && state_ != kPaused && state_ != kCreated) 278 {
282 return; 279 AutoLock auto_lock(lock_);
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(thread_.message_loop(), MessageLoop::current()); 288 DCHECK_EQ(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 thread_.message_loop()->PostTask( 335 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