OLD | NEW |
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 Loading... |
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 |
OLD | NEW |