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

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

Issue 11882010: Clean-up and bug fixes in AudioOutputController: (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remove all the NDEBUG. Created 7 years, 11 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"
11 #include "base/threading/platform_thread.h" 10 #include "base/threading/platform_thread.h"
12 #include "base/threading/thread_restrictions.h"
13 #include "base/time.h" 11 #include "base/time.h"
14 #include "build/build_config.h" 12 #include "build/build_config.h"
15 #include "media/audio/shared_memory_util.h" 13 #include "media/audio/shared_memory_util.h"
16 14
17 using base::Time; 15 using base::Time;
18 using base::TimeDelta; 16 using base::TimeDelta;
19 using base::WaitableEvent;
20 17
21 namespace media { 18 namespace media {
22 19
23 // Polling-related constants. 20 // Polling-related constants.
24 const int AudioOutputController::kPollNumAttempts = 3; 21 const int AudioOutputController::kPollNumAttempts = 3;
25 const int AudioOutputController::kPollPauseInMilliseconds = 3; 22 const int AudioOutputController::kPollPauseInMilliseconds = 3;
26 23
27 AudioOutputController::AudioOutputController(AudioManager* audio_manager, 24 AudioOutputController::AudioOutputController(AudioManager* audio_manager,
28 EventHandler* handler, 25 EventHandler* handler,
29 const AudioParameters& params, 26 const AudioParameters& params,
30 SyncReader* sync_reader) 27 SyncReader* sync_reader)
31 : audio_manager_(audio_manager), 28 : audio_manager_(audio_manager),
32 params_(params), 29 params_(params),
33 handler_(handler), 30 handler_(handler),
34 stream_(NULL), 31 stream_(NULL),
35 diverting_to_stream_(NULL), 32 diverting_to_stream_(NULL),
36 volume_(1.0), 33 volume_(1.0),
37 state_(kEmpty), 34 state_(kEmpty),
35 num_allowed_io_(0),
38 sync_reader_(sync_reader), 36 sync_reader_(sync_reader),
39 message_loop_(audio_manager->GetMessageLoop()), 37 message_loop_(audio_manager->GetMessageLoop()),
40 number_polling_attempts_left_(0), 38 number_polling_attempts_left_(0),
41 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)) { 39 ALLOW_THIS_IN_INITIALIZER_LIST(weak_this_(this)) {
40 DCHECK(audio_manager);
41 DCHECK(handler_);
42 DCHECK(sync_reader_);
43 DCHECK(message_loop_);
42 } 44 }
43 45
44 AudioOutputController::~AudioOutputController() { 46 AudioOutputController::~AudioOutputController() {
45 DCHECK_EQ(kClosed, state_); 47 DCHECK_EQ(kClosed, state_);
46
47 if (message_loop_->BelongsToCurrentThread()) {
48 DoStopCloseAndClearStream(NULL);
49 } else {
50 // http://crbug.com/120973
51 base::ThreadRestrictions::ScopedAllowWait allow_wait;
52 WaitableEvent completion(true /* manual reset */,
53 false /* initial state */);
54 message_loop_->PostTask(FROM_HERE,
55 base::Bind(&AudioOutputController::DoStopCloseAndClearStream,
56 base::Unretained(this),
57 &completion));
58 completion.Wait();
59 }
60 } 48 }
61 49
62 // static 50 // static
63 scoped_refptr<AudioOutputController> AudioOutputController::Create( 51 scoped_refptr<AudioOutputController> AudioOutputController::Create(
64 AudioManager* audio_manager, 52 AudioManager* audio_manager,
65 EventHandler* event_handler, 53 EventHandler* event_handler,
66 const AudioParameters& params, 54 const AudioParameters& params,
67 SyncReader* sync_reader) { 55 SyncReader* sync_reader) {
68 DCHECK(audio_manager); 56 DCHECK(audio_manager);
69 DCHECK(sync_reader); 57 DCHECK(sync_reader);
70 58
71 if (!params.IsValid() || !audio_manager) 59 if (!params.IsValid() || !audio_manager)
72 return NULL; 60 return NULL;
73 61
74 scoped_refptr<AudioOutputController> controller(new AudioOutputController( 62 scoped_refptr<AudioOutputController> controller(new AudioOutputController(
75 audio_manager, event_handler, params, sync_reader)); 63 audio_manager, event_handler, params, sync_reader));
76 controller->message_loop_->PostTask(FROM_HERE, base::Bind( 64 controller->message_loop_->PostTask(FROM_HERE, base::Bind(
77 &AudioOutputController::DoCreate, controller)); 65 &AudioOutputController::DoCreate, controller, false));
78 return controller; 66 return controller;
79 } 67 }
80 68
81 void AudioOutputController::Play() { 69 void AudioOutputController::Play() {
82 DCHECK(message_loop_);
83 message_loop_->PostTask(FROM_HERE, base::Bind( 70 message_loop_->PostTask(FROM_HERE, base::Bind(
84 &AudioOutputController::DoPlay, this)); 71 &AudioOutputController::DoPlay, this));
85 } 72 }
86 73
87 void AudioOutputController::Pause() { 74 void AudioOutputController::Pause() {
88 DCHECK(message_loop_);
89 message_loop_->PostTask(FROM_HERE, base::Bind( 75 message_loop_->PostTask(FROM_HERE, base::Bind(
90 &AudioOutputController::DoPause, this)); 76 &AudioOutputController::DoPause, this));
91 } 77 }
92 78
93 void AudioOutputController::Flush() { 79 void AudioOutputController::Flush() {
94 DCHECK(message_loop_);
95 message_loop_->PostTask(FROM_HERE, base::Bind( 80 message_loop_->PostTask(FROM_HERE, base::Bind(
96 &AudioOutputController::DoFlush, this)); 81 &AudioOutputController::DoFlush, this));
97 } 82 }
98 83
99 void AudioOutputController::Close(const base::Closure& closed_task) { 84 void AudioOutputController::Close(const base::Closure& closed_task) {
100 DCHECK(!closed_task.is_null()); 85 DCHECK(!closed_task.is_null());
101 DCHECK(message_loop_);
102 message_loop_->PostTaskAndReply(FROM_HERE, base::Bind( 86 message_loop_->PostTaskAndReply(FROM_HERE, base::Bind(
103 &AudioOutputController::DoClose, this), closed_task); 87 &AudioOutputController::DoClose, this), closed_task);
104 } 88 }
105 89
106 void AudioOutputController::SetVolume(double volume) { 90 void AudioOutputController::SetVolume(double volume) {
107 DCHECK(message_loop_);
108 message_loop_->PostTask(FROM_HERE, base::Bind( 91 message_loop_->PostTask(FROM_HERE, base::Bind(
109 &AudioOutputController::DoSetVolume, this, volume)); 92 &AudioOutputController::DoSetVolume, this, volume));
110 } 93 }
111 94
112 void AudioOutputController::DoCreate() { 95 void AudioOutputController::DoCreate(bool is_for_device_change) {
113 DCHECK(message_loop_->BelongsToCurrentThread()); 96 DCHECK(message_loop_->BelongsToCurrentThread());
114 97
115 // Close() can be called before DoCreate() is executed. 98 // Close() can be called before DoCreate() is executed.
116 if (state_ == kClosed) 99 if (state_ == kClosed)
117 return; 100 return;
118 DCHECK(state_ == kEmpty || state_ == kRecreating) << state_;
119 101
120 DoStopCloseAndClearStream(NULL); // Calls RemoveOutputDeviceChangeListener(). 102 DoStopCloseAndClearStream(); // Calls RemoveOutputDeviceChangeListener().
103 DCHECK_EQ(kEmpty, state_);
121 104
122 stream_ = diverting_to_stream_ ? diverting_to_stream_ : 105 stream_ = diverting_to_stream_ ? diverting_to_stream_ :
123 audio_manager_->MakeAudioOutputStreamProxy(params_); 106 audio_manager_->MakeAudioOutputStreamProxy(params_);
124 if (!stream_) { 107 if (!stream_) {
125 state_ = kError; 108 state_ = kError;
126 109
127 // TODO(hclam): Define error types. 110 // TODO(hclam): Define error types.
128 handler_->OnError(this, 0); 111 handler_->OnError(this, 0);
129 return; 112 return;
130 } 113 }
131 114
132 if (!stream_->Open()) { 115 if (!stream_->Open()) {
116 DoStopCloseAndClearStream();
133 state_ = kError; 117 state_ = kError;
134 DoStopCloseAndClearStream(NULL);
135 118
136 // TODO(hclam): Define error types. 119 // TODO(hclam): Define error types.
137 handler_->OnError(this, 0); 120 handler_->OnError(this, 0);
138 return; 121 return;
139 } 122 }
140 123
141 // Everything started okay, so re-register for state change callbacks if 124 // Everything started okay, so re-register for state change callbacks if
142 // stream_ was created via AudioManager. 125 // stream_ was created via AudioManager.
143 if (stream_ != diverting_to_stream_) 126 if (stream_ != diverting_to_stream_)
144 audio_manager_->AddOutputDeviceChangeListener(this); 127 audio_manager_->AddOutputDeviceChangeListener(this);
145 128
146 // We have successfully opened the stream. Set the initial volume. 129 // We have successfully opened the stream. Set the initial volume.
147 stream_->SetVolume(volume_); 130 stream_->SetVolume(volume_);
148 131
149 // Finally set the state to kCreated. 132 // Finally set the state to kCreated.
150 State original_state = state_;
151 state_ = kCreated; 133 state_ = kCreated;
152 134
153 // And then report we have been created if we haven't done so already. 135 // And then report we have been created if we haven't done so already.
154 if (original_state != kRecreating) 136 if (!is_for_device_change)
155 handler_->OnCreated(this); 137 handler_->OnCreated(this);
156 } 138 }
157 139
158 void AudioOutputController::DoPlay() { 140 void AudioOutputController::DoPlay() {
159 DCHECK(message_loop_->BelongsToCurrentThread()); 141 DCHECK(message_loop_->BelongsToCurrentThread());
160 142
161 // We can start from created or paused state. 143 // We can start from created or paused state.
162 if (state_ != kCreated && state_ != kPaused) { 144 if (state_ != kCreated && state_ != kPaused)
163 // If a pause is pending drop it. Otherwise the controller might hang since
164 // the corresponding play event has already occurred.
165 if (state_ == kPausedWhenStarting)
166 state_ = kStarting;
167 return; 145 return;
168 }
169 146
170 state_ = kStarting; 147 state_ = kStarting;
171 148
172 // Ask for first packet. 149 // Ask for first packet.
173 sync_reader_->UpdatePendingBytes(0); 150 sync_reader_->UpdatePendingBytes(0);
174 151
175 // Cannot start stream immediately, should give renderer some time 152 // Cannot start stream immediately, should give renderer some time
176 // to deliver data. 153 // to deliver data.
177 // TODO(vrk): The polling here and in WaitTillDataReady() is pretty clunky. 154 // TODO(vrk): The polling here and in WaitTillDataReady() is pretty clunky.
178 // Refine the API such that polling is no longer needed. (crbug.com/112196) 155 // Refine the API such that polling is no longer needed. (crbug.com/112196)
179 number_polling_attempts_left_ = kPollNumAttempts; 156 number_polling_attempts_left_ = kPollNumAttempts;
180 DCHECK(!weak_this_.HasWeakPtrs()); 157 DCHECK(!weak_this_.HasWeakPtrs());
181 message_loop_->PostDelayedTask( 158 message_loop_->PostDelayedTask(
182 FROM_HERE, 159 FROM_HERE,
183 base::Bind(&AudioOutputController::PollAndStartIfDataReady, 160 base::Bind(&AudioOutputController::PollAndStartIfDataReady,
184 weak_this_.GetWeakPtr()), 161 weak_this_.GetWeakPtr()),
185 TimeDelta::FromMilliseconds(kPollPauseInMilliseconds)); 162 TimeDelta::FromMilliseconds(kPollPauseInMilliseconds));
186 } 163 }
187 164
188 void AudioOutputController::PollAndStartIfDataReady() { 165 void AudioOutputController::PollAndStartIfDataReady() {
189 DCHECK(message_loop_->BelongsToCurrentThread()); 166 DCHECK(message_loop_->BelongsToCurrentThread());
190 167
191 // Being paranoid: do nothing if state unexpectedly changed. 168 DCHECK_EQ(kStarting, state_);
192 if ((state_ != kStarting) && (state_ != kPausedWhenStarting))
193 return;
194 169
195 bool pausing = (state_ == kPausedWhenStarting);
196 // If we are ready to start the stream, start it. 170 // If we are ready to start the stream, start it.
197 // Of course we may have to stop it immediately...
198 if (--number_polling_attempts_left_ == 0 || 171 if (--number_polling_attempts_left_ == 0 ||
199 pausing ||
200 sync_reader_->DataReady()) { 172 sync_reader_->DataReady()) {
201 StartStream(); 173 StartStream();
202 if (pausing) {
203 DoPause();
204 }
205 } else { 174 } else {
206 message_loop_->PostDelayedTask( 175 message_loop_->PostDelayedTask(
207 FROM_HERE, 176 FROM_HERE,
208 base::Bind(&AudioOutputController::PollAndStartIfDataReady, 177 base::Bind(&AudioOutputController::PollAndStartIfDataReady,
209 weak_this_.GetWeakPtr()), 178 weak_this_.GetWeakPtr()),
210 TimeDelta::FromMilliseconds(kPollPauseInMilliseconds)); 179 TimeDelta::FromMilliseconds(kPollPauseInMilliseconds));
211 } 180 }
212 } 181 }
213 182
214 void AudioOutputController::StartStream() { 183 void AudioOutputController::StartStream() {
215 DCHECK(message_loop_->BelongsToCurrentThread()); 184 DCHECK(message_loop_->BelongsToCurrentThread());
216 state_ = kPlaying; 185 state_ = kPlaying;
217 186
218 // We start the AudioOutputStream lazily. 187 // We start the AudioOutputStream lazily.
188 AllowEntryToOnMoreIOData();
219 stream_->Start(this); 189 stream_->Start(this);
220 190
221 // Tell the event handler that we are now playing. 191 // Tell the event handler that we are now playing.
222 handler_->OnPlaying(this); 192 handler_->OnPlaying(this);
223 } 193 }
224 194
195 void AudioOutputController::StopStream() {
196 DCHECK(message_loop_->BelongsToCurrentThread());
197
198 if (state_ == kStarting) {
199 // Cancel in-progress polling start.
200 weak_this_.InvalidateWeakPtrs();
201 state_ = kPaused;
202 } else if (state_ == kPlaying) {
203 stream_->Stop();
204 DisallowEntryToOnMoreIOData();
205 state_ = kPaused;
206 }
207 }
208
225 void AudioOutputController::DoPause() { 209 void AudioOutputController::DoPause() {
226 DCHECK(message_loop_->BelongsToCurrentThread()); 210 DCHECK(message_loop_->BelongsToCurrentThread());
227 211
228 if (stream_) { 212 StopStream();
229 // Then we stop the audio device. This is not the perfect solution
230 // because it discards all the internal buffer in the audio device.
231 // TODO(hclam): Actually pause the audio device.
232 stream_->Stop();
233 }
234 213
235 switch (state_) { 214 if (state_ != kPaused)
236 case kStarting: 215 return;
237 // We were asked to pause while starting. There is delayed task that will
238 // try starting playback, and there is no way to remove that task from the
239 // queue. If we stop now that task will be executed anyway.
240 // Delay pausing, let delayed task to do pause after it start playback.
241 state_ = kPausedWhenStarting;
242 break;
243 case kPlaying:
244 state_ = kPaused;
245 216
246 // Send a special pause mark to the low-latency audio thread. 217 // Send a special pause mark to the low-latency audio thread.
247 sync_reader_->UpdatePendingBytes(kPauseMark); 218 sync_reader_->UpdatePendingBytes(kPauseMark);
248 219
249 handler_->OnPaused(this); 220 handler_->OnPaused(this);
250 break;
251 default:
252 return;
253 }
254 } 221 }
255 222
256 void AudioOutputController::DoFlush() { 223 void AudioOutputController::DoFlush() {
257 DCHECK(message_loop_->BelongsToCurrentThread()); 224 DCHECK(message_loop_->BelongsToCurrentThread());
258 225
259 // TODO(hclam): Actually flush the audio device. 226 // TODO(hclam): Actually flush the audio device.
260 } 227 }
261 228
262 void AudioOutputController::DoClose() { 229 void AudioOutputController::DoClose() {
263 DCHECK(message_loop_->BelongsToCurrentThread()); 230 DCHECK(message_loop_->BelongsToCurrentThread());
264 231
265 if (state_ != kClosed) { 232 if (state_ != kClosed) {
266 DoStopCloseAndClearStream(NULL); 233 DoStopCloseAndClearStream();
267 sync_reader_->Close(); 234 sync_reader_->Close();
268 state_ = kClosed; 235 state_ = kClosed;
269 } 236 }
270 } 237 }
271 238
272 void AudioOutputController::DoSetVolume(double volume) { 239 void AudioOutputController::DoSetVolume(double volume) {
273 DCHECK(message_loop_->BelongsToCurrentThread()); 240 DCHECK(message_loop_->BelongsToCurrentThread());
274 241
275 // Saves the volume to a member first. We may not be able to set the volume 242 // Saves the volume to a member first. We may not be able to set the volume
276 // right away but when the stream is created we'll set the volume. 243 // right away but when the stream is created we'll set the volume.
277 volume_ = volume; 244 volume_ = volume;
278 245
279 switch (state_) { 246 switch (state_) {
280 case kCreated: 247 case kCreated:
281 case kStarting: 248 case kStarting:
282 case kPausedWhenStarting:
283 case kPlaying: 249 case kPlaying:
284 case kPaused: 250 case kPaused:
285 stream_->SetVolume(volume_); 251 stream_->SetVolume(volume_);
286 break; 252 break;
287 default: 253 default:
288 return; 254 return;
289 } 255 }
290 } 256 }
291 257
292 void AudioOutputController::DoReportError(int code) { 258 void AudioOutputController::DoReportError(int code) {
293 DCHECK(message_loop_->BelongsToCurrentThread()); 259 DCHECK(message_loop_->BelongsToCurrentThread());
294 if (state_ != kClosed) 260 if (state_ != kClosed)
295 handler_->OnError(this, code); 261 handler_->OnError(this, code);
296 } 262 }
297 263
298 int AudioOutputController::OnMoreData(AudioBus* dest, 264 int AudioOutputController::OnMoreData(AudioBus* dest,
299 AudioBuffersState buffers_state) { 265 AudioBuffersState buffers_state) {
300 return OnMoreIOData(NULL, dest, buffers_state); 266 return OnMoreIOData(NULL, dest, buffers_state);
301 } 267 }
302 268
303 int AudioOutputController::OnMoreIOData(AudioBus* source, 269 int AudioOutputController::OnMoreIOData(AudioBus* source,
304 AudioBus* dest, 270 AudioBus* dest,
305 AudioBuffersState buffers_state) { 271 AudioBuffersState buffers_state) {
272 DisallowEntryToOnMoreIOData();
306 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData"); 273 TRACE_EVENT0("audio", "AudioOutputController::OnMoreIOData");
307 274
308 { 275 const int frames = sync_reader_->Read(source, dest);
309 // Check state and do nothing if we are not playing. 276 DCHECK_LE(0, frames);
310 // We are on the hardware audio thread, so lock is needed.
311 base::AutoLock auto_lock(lock_);
312 if (state_ != kPlaying) {
313 return 0;
314 }
315 }
316
317 int frames = sync_reader_->Read(source, dest);
318 sync_reader_->UpdatePendingBytes( 277 sync_reader_->UpdatePendingBytes(
319 buffers_state.total_bytes() + frames * params_.GetBytesPerFrame()); 278 buffers_state.total_bytes() + frames * params_.GetBytesPerFrame());
279
280 AllowEntryToOnMoreIOData();
320 return frames; 281 return frames;
321 } 282 }
322 283
323 void AudioOutputController::WaitTillDataReady() { 284 void AudioOutputController::WaitTillDataReady() {
324 #if defined(OS_WIN) || defined(OS_MACOSX) 285 #if defined(OS_WIN) || defined(OS_MACOSX)
325 base::Time start = base::Time::Now(); 286 base::Time start = base::Time::Now();
326 // Wait for up to 1.5 seconds for DataReady(). 1.5 seconds was chosen because 287 // Wait for up to 1.5 seconds for DataReady(). 1.5 seconds was chosen because
327 // it's larger than the playback time of the WaveOut buffer size using the 288 // it's larger than the playback time of the WaveOut buffer size using the
328 // minimum supported sample rate: 4096 / 3000 = ~1.4 seconds. Even a client 289 // minimum supported sample rate: 4096 / 3000 = ~1.4 seconds. Even a client
329 // expecting real time playout should be able to fill in this time. 290 // expecting real time playout should be able to fill in this time.
330 const base::TimeDelta max_wait = base::TimeDelta::FromMilliseconds(1500); 291 const base::TimeDelta max_wait = base::TimeDelta::FromMilliseconds(1500);
331 while (!sync_reader_->DataReady() && 292 while (!sync_reader_->DataReady() &&
332 ((base::Time::Now() - start) < max_wait)) { 293 ((base::Time::Now() - start) < max_wait)) {
333 base::PlatformThread::YieldCurrentThread(); 294 base::PlatformThread::YieldCurrentThread();
334 } 295 }
335 #else 296 #else
336 // WaitTillDataReady() is deprecated and should not be used. 297 // WaitTillDataReady() is deprecated and should not be used.
337 CHECK(false); 298 CHECK(false);
338 #endif 299 #endif
339 } 300 }
340 301
341 void AudioOutputController::OnError(AudioOutputStream* stream, int code) { 302 void AudioOutputController::OnError(AudioOutputStream* stream, int code) {
342 // Handle error on the audio controller thread. 303 // Handle error on the audio controller thread.
343 message_loop_->PostTask(FROM_HERE, base::Bind( 304 message_loop_->PostTask(FROM_HERE, base::Bind(
344 &AudioOutputController::DoReportError, this, code)); 305 &AudioOutputController::DoReportError, this, code));
345 } 306 }
346 307
347 void AudioOutputController::DoStopCloseAndClearStream(WaitableEvent* done) { 308 void AudioOutputController::DoStopCloseAndClearStream() {
348 DCHECK(message_loop_->BelongsToCurrentThread()); 309 DCHECK(message_loop_->BelongsToCurrentThread());
349 310
350 // Allow calling unconditionally and bail if we don't have a stream_ to close. 311 // Allow calling unconditionally and bail if we don't have a stream_ to close.
351 if (stream_) { 312 if (stream_) {
352 // De-register from state change callbacks if stream_ was created via 313 // De-register from state change callbacks if stream_ was created via
353 // AudioManager. 314 // AudioManager.
354 if (stream_ != diverting_to_stream_) 315 if (stream_ != diverting_to_stream_)
355 audio_manager_->RemoveOutputDeviceChangeListener(this); 316 audio_manager_->RemoveOutputDeviceChangeListener(this);
356 317
357 stream_->Stop(); 318 StopStream();
358 stream_->Close(); 319 stream_->Close();
359 if (stream_ == diverting_to_stream_) 320 if (stream_ == diverting_to_stream_)
360 diverting_to_stream_ = NULL; 321 diverting_to_stream_ = NULL;
361 stream_ = NULL; 322 stream_ = NULL;
362
363 weak_this_.InvalidateWeakPtrs();
364 } 323 }
365 324
366 // Should be last in the method, do not touch "this" from here on. 325 state_ = kEmpty;
367 if (done)
368 done->Signal();
369 } 326 }
370 327
371 void AudioOutputController::OnDeviceChange() { 328 void AudioOutputController::OnDeviceChange() {
372 DCHECK(message_loop_->BelongsToCurrentThread()); 329 DCHECK(message_loop_->BelongsToCurrentThread());
373 330
374 // Recreate the stream (DoCreate() will first shut down an existing stream). 331 // Recreate the stream (DoCreate() will first shut down an existing stream).
375 // Exit if we ran into an error. 332 // Exit if we ran into an error.
376 const State original_state = state_; 333 const State original_state = state_;
377 state_ = kRecreating; 334 DoCreate(true);
378 DoCreate();
379 if (!stream_ || state_ == kError) 335 if (!stream_ || state_ == kError)
380 return; 336 return;
381 337
382 // Get us back to the original state or an equivalent state. 338 // Get us back to the original state or an equivalent state.
383 switch (original_state) { 339 switch (original_state) {
384 case kStarting: 340 case kStarting:
385 case kPlaying: 341 case kPlaying:
386 DoPlay(); 342 DoPlay();
387 return; 343 return;
388 case kCreated: 344 case kCreated:
389 case kPausedWhenStarting:
390 case kPaused: 345 case kPaused:
391 // From the outside these three states are equivalent. 346 // From the outside these two states are equivalent.
392 return; 347 return;
393 default: 348 default:
394 NOTREACHED() << "Invalid original state."; 349 NOTREACHED() << "Invalid original state.";
395 } 350 }
396 } 351 }
397 352
398 const AudioParameters& AudioOutputController::GetAudioParameters() { 353 const AudioParameters& AudioOutputController::GetAudioParameters() {
399 return params_; 354 return params_;
400 } 355 }
401 356
(...skipping 28 matching lines...) Expand all
430 if (state_ == kClosed) 385 if (state_ == kClosed)
431 return; 386 return;
432 387
433 // Note: OnDeviceChange() will cause the existing stream (the consumer of the 388 // Note: OnDeviceChange() will cause the existing stream (the consumer of the
434 // diverted audio data) to be closed, and diverting_to_stream_ will be set 389 // diverted audio data) to be closed, and diverting_to_stream_ will be set
435 // back to NULL. 390 // back to NULL.
436 OnDeviceChange(); 391 OnDeviceChange();
437 DCHECK(!diverting_to_stream_); 392 DCHECK(!diverting_to_stream_);
438 } 393 }
439 394
395 void AudioOutputController::AllowEntryToOnMoreIOData() {
396 DCHECK(base::AtomicRefCountIsZero(&num_allowed_io_));
397 base::AtomicRefCountInc(&num_allowed_io_);
398 }
399
400 void AudioOutputController::DisallowEntryToOnMoreIOData() {
401 const bool is_zero = !base::AtomicRefCountDec(&num_allowed_io_);
402 DCHECK(is_zero);
403 }
404
440 } // namespace media 405 } // 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