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

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

Issue 1703473002: Make AudioOutputDevice restartable and reinitializable (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@new_mixing
Patch Set: Created 4 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
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_device.h" 5 #include "media/audio/audio_output_device.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 #include <utility> 9 #include <utility>
10 10
11 #include "base/callback_helpers.h" 11 #include "base/callback_helpers.h"
12 #include "base/macros.h" 12 #include "base/macros.h"
13 #include "base/threading/thread_restrictions.h" 13 #include "base/threading/thread_restrictions.h"
14 #include "base/time/time.h" 14 #include "base/time/time.h"
15 #include "base/trace_event/trace_event.h" 15 #include "base/trace_event/trace_event.h"
16 #include "build/build_config.h" 16 #include "build/build_config.h"
17 #include "media/audio/audio_output_controller.h" 17 #include "media/audio/audio_output_controller.h"
18 #include "media/base/limits.h" 18 #include "media/base/limits.h"
19 19
20 #include "base/debug/stack_trace.h"
21
20 namespace media { 22 namespace media {
21 23
22 // Takes care of invoking the render callback on the audio thread. 24 // Takes care of invoking the render callback on the audio thread.
23 // An instance of this class is created for each capture stream in 25 // An instance of this class is created for each capture stream in
24 // OnStreamCreated(). 26 // OnStreamCreated().
25 class AudioOutputDevice::AudioThreadCallback 27 class AudioOutputDevice::AudioThreadCallback
26 : public AudioDeviceThread::Callback { 28 : public AudioDeviceThread::Callback {
27 public: 29 public:
28 AudioThreadCallback(const AudioParameters& audio_parameters, 30 AudioThreadCallback(const AudioParameters& audio_parameters,
29 base::SharedMemoryHandle memory, 31 base::SharedMemoryHandle memory,
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
70 static_assert(IDLE < AUTHORIZING, "invalid enum value assignment 1"); 72 static_assert(IDLE < AUTHORIZING, "invalid enum value assignment 1");
71 static_assert(AUTHORIZING < AUTHORIZED, "invalid enum value assignment 2"); 73 static_assert(AUTHORIZING < AUTHORIZED, "invalid enum value assignment 2");
72 static_assert(AUTHORIZED < CREATING_STREAM, 74 static_assert(AUTHORIZED < CREATING_STREAM,
73 "invalid enum value assignment 3"); 75 "invalid enum value assignment 3");
74 static_assert(CREATING_STREAM < PAUSED, "invalid enum value assignment 4"); 76 static_assert(CREATING_STREAM < PAUSED, "invalid enum value assignment 4");
75 static_assert(PAUSED < PLAYING, "invalid enum value assignment 5"); 77 static_assert(PAUSED < PLAYING, "invalid enum value assignment 5");
76 } 78 }
77 79
78 void AudioOutputDevice::Initialize(const AudioParameters& params, 80 void AudioOutputDevice::Initialize(const AudioParameters& params,
79 RenderCallback* callback) { 81 RenderCallback* callback) {
80 DCHECK(!callback_) << "Calling Initialize() twice?";
81 DCHECK(params.IsValid()); 82 DCHECK(params.IsValid());
82 audio_parameters_ = params; 83 task_runner()->PostTask(
83 callback_ = callback; 84 FROM_HERE,
85 base::Bind(&AudioOutputDevice::InitializeOnIOThread,
86 this, params, callback));
84 } 87 }
85 88
86 AudioOutputDevice::~AudioOutputDevice() { 89 AudioOutputDevice::~AudioOutputDevice() {
87 // The current design requires that the user calls Stop() before deleting 90 // The current design requires that the user calls Stop() before deleting
88 // this class. 91 // this class. Since this object is reference counted, we're the only one
89 DCHECK(audio_thread_.IsStopped()); 92 // accessing data when we destruct.
93 DCHECK(state_ == IDLE || state_ == IPC_CLOSED);
94 audio_thread_.Stop(base::MessageLoop::current());
90 } 95 }
91 96
92 void AudioOutputDevice::RequestDeviceAuthorization() { 97 void AudioOutputDevice::RequestDeviceAuthorization() {
93 task_runner()->PostTask( 98 task_runner()->PostTask(
94 FROM_HERE, 99 FROM_HERE,
95 base::Bind(&AudioOutputDevice::RequestDeviceAuthorizationOnIOThread, 100 base::Bind(&AudioOutputDevice::RequestDeviceAuthorizationOnIOThread,
96 this)); 101 this));
97 } 102 }
98 103
99 void AudioOutputDevice::Start() { 104 void AudioOutputDevice::Start() {
100 DCHECK(callback_) << "Initialize hasn't been called";
101 task_runner()->PostTask(FROM_HERE, 105 task_runner()->PostTask(FROM_HERE,
102 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this, 106 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this));
103 audio_parameters_));
104 } 107 }
105 108
106 void AudioOutputDevice::Stop() { 109 void AudioOutputDevice::Stop() {
107 { 110 {
108 base::AutoLock auto_lock(audio_thread_lock_); 111 base::AutoLock auto_lock(audio_thread_lock_);
109 audio_thread_.Stop(base::MessageLoop::current()); 112 audio_thread_.StopRun();
110 stopping_hack_ = true; 113 stopping_hack_ = true;
111 } 114 }
112 115
113 task_runner()->PostTask(FROM_HERE, 116 task_runner()->PostTask(FROM_HERE,
114 base::Bind(&AudioOutputDevice::ShutDownOnIOThread, this)); 117 base::Bind(&AudioOutputDevice::StopOnIOThread, this));
115 } 118 }
116 119
117 void AudioOutputDevice::Play() { 120 void AudioOutputDevice::Play() {
118 task_runner()->PostTask(FROM_HERE, 121 task_runner()->PostTask(FROM_HERE,
119 base::Bind(&AudioOutputDevice::PlayOnIOThread, this)); 122 base::Bind(&AudioOutputDevice::PlayOnIOThread, this));
120 } 123 }
121 124
122 void AudioOutputDevice::Pause() { 125 void AudioOutputDevice::Pause() {
123 task_runner()->PostTask(FROM_HERE, 126 task_runner()->PostTask(FROM_HERE,
124 base::Bind(&AudioOutputDevice::PauseOnIOThread, this)); 127 base::Bind(&AudioOutputDevice::PauseOnIOThread, this));
(...skipping 28 matching lines...) Expand all
153 return output_params_; 156 return output_params_;
154 } 157 }
155 158
156 OutputDeviceStatus AudioOutputDevice::GetDeviceStatus() { 159 OutputDeviceStatus AudioOutputDevice::GetDeviceStatus() {
157 CHECK(!task_runner()->BelongsToCurrentThread()); 160 CHECK(!task_runner()->BelongsToCurrentThread());
158 did_receive_auth_.Wait(); 161 did_receive_auth_.Wait();
159 return device_status_; 162 return device_status_;
160 } 163 }
161 164
162 void AudioOutputDevice::RequestDeviceAuthorizationOnIOThread() { 165 void AudioOutputDevice::RequestDeviceAuthorizationOnIOThread() {
166 printf("****** AudioOutputDevice::RequestDeviceAuthorizationOnIOThread this = %p, state_ = %d\n",
167 this, state_);
163 DCHECK(task_runner()->BelongsToCurrentThread()); 168 DCHECK(task_runner()->BelongsToCurrentThread());
164 DCHECK_EQ(state_, IDLE); 169 DCHECK_EQ(state_, IDLE);
165 state_ = AUTHORIZING; 170 state_ = AUTHORIZING;
171
172 // TODO(grunell): Store authorization so that we don't have to authorize
173 // again when re-starting. This involves mostly changes on the browser side:
174 // associate authorization by a new id (currently the stream id), don't forget
175 // authorization away after start or stop. Here we would have to explicitly
176 // make the browser side forget authorization in the dtor with a new
177 // AudioOutputIPC function.
166 ipc_->RequestDeviceAuthorization(this, session_id_, device_id_, 178 ipc_->RequestDeviceAuthorization(this, session_id_, device_id_,
167 security_origin_); 179 security_origin_);
168 } 180 }
169 181
170 void AudioOutputDevice::CreateStreamOnIOThread(const AudioParameters& params) { 182 void AudioOutputDevice::InitializeOnIOThread(const AudioParameters& params,
183 RenderCallback* callback) {
171 DCHECK(task_runner()->BelongsToCurrentThread()); 184 DCHECK(task_runner()->BelongsToCurrentThread());
185 DCHECK(!callback_);
186 audio_parameters_ = params;
187 callback_ = callback;
188 }
189
190 void AudioOutputDevice::CreateStreamOnIOThread() {
191 printf("****** AudioOutputDevice::CreateStreamOnIOThread this = %p, state_ = % d\n",
192 this, state_);
193 DCHECK(task_runner()->BelongsToCurrentThread());
194 DCHECK(callback_ || state_ == IPC_CLOSED);
195
172 switch (state_) { 196 switch (state_) {
173 case IPC_CLOSED: 197 case IPC_CLOSED:
174 if (callback_) 198 if (callback_)
175 callback_->OnRenderError(); 199 callback_->OnRenderError();
176 break; 200 break;
177 201
178 case IDLE: 202 case IDLE:
179 if (did_receive_auth_.IsSignaled() && device_id_.empty() && 203 if (did_receive_auth_.IsSignaled() && device_id_.empty() &&
180 security_origin_.unique()) { 204 security_origin_.unique()) {
181 state_ = CREATING_STREAM; 205 state_ = CREATING_STREAM;
182 ipc_->CreateStream(this, params); 206 ipc_->CreateStream(this, audio_parameters_);
183 } else { 207 } else {
184 RequestDeviceAuthorizationOnIOThread(); 208 RequestDeviceAuthorizationOnIOThread();
185 start_on_authorized_ = true; 209 start_on_authorized_ = true;
186 } 210 }
187 break; 211 break;
188 212
189 case AUTHORIZING: 213 case AUTHORIZING:
190 start_on_authorized_ = true; 214 start_on_authorized_ = true;
191 break; 215 break;
192 216
193 case AUTHORIZED: 217 case AUTHORIZED:
194 state_ = CREATING_STREAM; 218 state_ = CREATING_STREAM;
195 ipc_->CreateStream(this, params); 219 ipc_->CreateStream(this, audio_parameters_);
196 start_on_authorized_ = false; 220 start_on_authorized_ = false;
197 break; 221 break;
198 222
199 case CREATING_STREAM: 223 case CREATING_STREAM:
200 case PAUSED: 224 case PAUSED:
201 case PLAYING: 225 case PLAYING:
202 NOTREACHED(); 226 NOTREACHED();
203 break; 227 break;
204 } 228 }
205 } 229 }
206 230
207 void AudioOutputDevice::PlayOnIOThread() { 231 void AudioOutputDevice::PlayOnIOThread() {
232 printf("****** AudioOutputDevice::PlayOnIOThread this = %p, state_ = %d\n",
233 this, state_);
208 DCHECK(task_runner()->BelongsToCurrentThread()); 234 DCHECK(task_runner()->BelongsToCurrentThread());
209 if (state_ == PAUSED) { 235 if (state_ == PAUSED) {
210 TRACE_EVENT_ASYNC_BEGIN0( 236 TRACE_EVENT_ASYNC_BEGIN0(
211 "audio", "StartingPlayback", audio_callback_.get()); 237 "audio", "StartingPlayback", audio_callback_.get());
212 ipc_->PlayStream(); 238 ipc_->PlayStream();
213 state_ = PLAYING; 239 state_ = PLAYING;
214 play_on_start_ = false; 240 play_on_start_ = false;
215 } else { 241 } else {
216 play_on_start_ = true; 242 play_on_start_ = true;
217 } 243 }
218 } 244 }
219 245
220 void AudioOutputDevice::PauseOnIOThread() { 246 void AudioOutputDevice::PauseOnIOThread() {
247 printf("****** AudioOutputDevice::PauseOnIOThread this = %p, state_ = %d\n",
248 this, state_);
221 DCHECK(task_runner()->BelongsToCurrentThread()); 249 DCHECK(task_runner()->BelongsToCurrentThread());
222 if (state_ == PLAYING) { 250 if (state_ == PLAYING) {
223 TRACE_EVENT_ASYNC_END0( 251 TRACE_EVENT_ASYNC_END0(
224 "audio", "StartingPlayback", audio_callback_.get()); 252 "audio", "StartingPlayback", audio_callback_.get());
225 ipc_->PauseStream(); 253 ipc_->PauseStream();
226 state_ = PAUSED; 254 state_ = PAUSED;
227 } 255 }
228 play_on_start_ = false; 256 play_on_start_ = false;
229 } 257 }
230 258
231 void AudioOutputDevice::ShutDownOnIOThread() { 259 void AudioOutputDevice::StopOnIOThread() {
260 printf("****** AudioOutputDevice::StopOnIOThread this = %p, state_ = %d\n",
261 this, state_);
232 DCHECK(task_runner()->BelongsToCurrentThread()); 262 DCHECK(task_runner()->BelongsToCurrentThread());
233 263
234 // Close the stream, if we haven't already. 264 // Close the stream, if we haven't already.
235 if (state_ >= AUTHORIZING) { 265 if (state_ >= AUTHORIZING) {
236 ipc_->CloseStream(); 266 ipc_->CloseStream();
237 state_ = IDLE; 267 state_ = IDLE;
238 } 268 }
239 start_on_authorized_ = false; 269 start_on_authorized_ = false;
240 270
241 // We can run into an issue where ShutDownOnIOThread is called right after 271 // We can run into an issue where StopOnIOThread is called right after
242 // OnStreamCreated is called in cases where Start/Stop are called before we 272 // OnStreamCreated is called in cases where Start/Stop are called before we
243 // get the OnStreamCreated callback. To handle that corner case, we call 273 // get the OnStreamCreated callback. To handle that corner case, we call
244 // Stop(). In most cases, the thread will already be stopped. 274 // Stop(). In most cases, the thread will already be stopped.
245 //
246 // Another situation is when the IO thread goes away before Stop() is called
247 // in which case, we cannot use the message loop to close the thread handle
248 // and can't rely on the main thread existing either.
249 base::AutoLock auto_lock_(audio_thread_lock_); 275 base::AutoLock auto_lock_(audio_thread_lock_);
250 base::ThreadRestrictions::ScopedAllowIO allow_io; 276 audio_thread_.StopRun();
251 audio_thread_.Stop(NULL);
252 audio_callback_.reset(); 277 audio_callback_.reset();
253 stopping_hack_ = false; 278 stopping_hack_ = false;
279 callback_ = nullptr;
254 } 280 }
255 281
256 void AudioOutputDevice::SetVolumeOnIOThread(double volume) { 282 void AudioOutputDevice::SetVolumeOnIOThread(double volume) {
257 DCHECK(task_runner()->BelongsToCurrentThread()); 283 DCHECK(task_runner()->BelongsToCurrentThread());
258 if (state_ >= CREATING_STREAM) 284 if (state_ >= CREATING_STREAM)
259 ipc_->SetVolume(volume); 285 ipc_->SetVolume(volume);
260 } 286 }
261 287
262 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegateState state) { 288 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegateState state) {
289 printf("****** AudioOutputDevice::OnStateChanged this = %p, state_ = %d, state = %d\n",
290 this, state_, state);
263 DCHECK(task_runner()->BelongsToCurrentThread()); 291 DCHECK(task_runner()->BelongsToCurrentThread());
264 292
265 // Do nothing if the stream has been closed. 293 // Do nothing if the stream has been closed.
266 if (state_ < CREATING_STREAM) 294 if (state_ < CREATING_STREAM)
267 return; 295 return;
268 296
269 // TODO(miu): Clean-up inconsistent and incomplete handling here. 297 // TODO(miu): Clean-up inconsistent and incomplete handling here.
270 // http://crbug.com/180640 298 // http://crbug.com/180640
271 switch (state) { 299 switch (state) {
272 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING: 300 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING:
273 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED: 301 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED:
274 break; 302 break;
275 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR: 303 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR:
276 DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(ERROR)"; 304 DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(ERROR)";
277 // Don't dereference the callback object if the audio thread 305 // The callback object is cleared in Stop().
278 // is stopped or stopping. That could mean that the callback 306 if (callback_)
279 // object has been deleted.
280 // TODO(tommi): Add an explicit contract for clearing the callback
281 // object. Possibly require calling Initialize again or provide
282 // a callback object via Start() and clear it in Stop().
283 if (!audio_thread_.IsStopped())
284 callback_->OnRenderError(); 307 callback_->OnRenderError();
285 break; 308 break;
286 default: 309 default:
287 NOTREACHED(); 310 NOTREACHED();
288 break; 311 break;
289 } 312 }
290 } 313 }
291 314
292 void AudioOutputDevice::OnDeviceAuthorized( 315 void AudioOutputDevice::OnDeviceAuthorized(
293 OutputDeviceStatus device_status, 316 OutputDeviceStatus device_status,
294 const media::AudioParameters& output_params) { 317 const media::AudioParameters& output_params) {
318 printf("****** AudioOutputDevice::OnDeviceAuthorized this = %p, state_ = %d, d evice_status = %d\n",
319 this, state_, device_status);
295 DCHECK(task_runner()->BelongsToCurrentThread()); 320 DCHECK(task_runner()->BelongsToCurrentThread());
296 DCHECK_EQ(state_, AUTHORIZING); 321 DCHECK_EQ(state_, AUTHORIZING);
297 322
298 // It may happen that a second authorization is received as a result to a 323 // It may happen that a second authorization is received as a result to a
299 // call to Start() after Stop(). If the status for the second authorization 324 // call to Start() after Stop(). If the status for the second authorization
300 // differs from the first, it will not be reflected in |device_status_| 325 // differs from the first, it will not be reflected in |device_status_|
301 // to avoid a race. 326 // to avoid a race.
302 // This scenario is unlikely. If it occurs, the new value will be 327 // This scenario is unlikely. If it occurs, the new value will be
303 // different from OUTPUT_DEVICE_STATUS_OK, so the AudioOutputDevice 328 // different from OUTPUT_DEVICE_STATUS_OK, so the AudioOutputDevice
304 // will enter the IPC_CLOSED state anyway, which is the safe thing to do. 329 // will enter the IPC_CLOSED state anyway, which is the safe thing to do.
305 // This is preferable to holding a lock. 330 // This is preferable to holding a lock.
306 if (!did_receive_auth_.IsSignaled()) 331 if (!did_receive_auth_.IsSignaled())
307 device_status_ = device_status; 332 device_status_ = device_status;
308 333
309 if (device_status == OUTPUT_DEVICE_STATUS_OK) { 334 if (device_status == OUTPUT_DEVICE_STATUS_OK) {
310 state_ = AUTHORIZED; 335 state_ = AUTHORIZED;
311 if (!did_receive_auth_.IsSignaled()) { 336 if (!did_receive_auth_.IsSignaled()) {
312 output_params_ = output_params; 337 output_params_ = output_params;
313 did_receive_auth_.Signal(); 338 did_receive_auth_.Signal();
314 } 339 }
315 if (start_on_authorized_) 340 if (start_on_authorized_)
316 CreateStreamOnIOThread(audio_parameters_); 341 CreateStreamOnIOThread();
317 } else { 342 } else {
318 // Closing IPC forces a Signal(), so no clients are locked waiting 343 // Closing IPC forces a Signal(), so no clients are locked waiting
319 // indefinitely after this method returns. 344 // indefinitely after this method returns.
320 ipc_->CloseStream(); 345 ipc_->CloseStream();
321 OnIPCClosed(); 346 OnIPCClosed();
322 if (callback_) 347 if (callback_)
323 callback_->OnRenderError(); 348 callback_->OnRenderError();
324 } 349 }
325 } 350 }
326 351
327 void AudioOutputDevice::OnStreamCreated( 352 void AudioOutputDevice::OnStreamCreated(
328 base::SharedMemoryHandle handle, 353 base::SharedMemoryHandle handle,
329 base::SyncSocket::Handle socket_handle, 354 base::SyncSocket::Handle socket_handle,
330 int length) { 355 int length) {
356 printf("****** AudioOutputDevice::OnStreamCreated this = %p, state_ = %d\n",
357 this, state_);
331 DCHECK(task_runner()->BelongsToCurrentThread()); 358 DCHECK(task_runner()->BelongsToCurrentThread());
332 DCHECK(base::SharedMemory::IsHandleValid(handle)); 359 DCHECK(base::SharedMemory::IsHandleValid(handle));
333 #if defined(OS_WIN) 360 #if defined(OS_WIN)
334 DCHECK(socket_handle); 361 DCHECK(socket_handle);
335 #else 362 #else
336 DCHECK_GE(socket_handle, 0); 363 DCHECK_GE(socket_handle, 0);
337 #endif 364 #endif
338 DCHECK_GT(length, 0); 365 DCHECK_GT(length, 0);
339 366
340 if (state_ != CREATING_STREAM) 367 if (state_ != CREATING_STREAM)
341 return; 368 return;
342 369
343 // We can receive OnStreamCreated() on the IO thread after the client has 370 // We can receive OnStreamCreated() on the IO thread after the client has
344 // called Stop() but before ShutDownOnIOThread() is processed. In such a 371 // called Stop() but before StopOnIOThread() is processed. In such a
345 // situation |callback_| might point to freed memory. Instead of starting 372 // situation |callback_| might point to freed memory. Instead of starting
346 // |audio_thread_| do nothing and wait for ShutDownOnIOThread() to get called. 373 // |audio_thread_| do nothing and wait for StopOnIOThread() to get called.
347 // 374 //
348 // TODO(scherkus): The real fix is to have sane ownership semantics. The fact 375 // TODO(scherkus): The real fix is to have sane ownership semantics. The fact
349 // that |callback_| (which should own and outlive this object!) can point to 376 // that |callback_| (which should own and outlive this object!) can point to
350 // freed memory is a mess. AudioRendererSink should be non-refcounted so that 377 // freed memory is a mess. AudioRendererSink should be non-refcounted so that
351 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and 378 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and
352 // delete as they see fit. AudioOutputDevice should internally use WeakPtr 379 // delete as they see fit. AudioOutputDevice should internally use WeakPtr
353 // to handle teardown and thread hopping. See http://crbug.com/151051 for 380 // to handle teardown and thread hopping. See http://crbug.com/151051 for
354 // details. 381 // details.
355 { 382 {
356 base::AutoLock auto_lock(audio_thread_lock_); 383 base::AutoLock auto_lock(audio_thread_lock_);
357 if (stopping_hack_) 384 if (stopping_hack_)
358 return; 385 return;
359 386
360 DCHECK(audio_thread_.IsStopped());
361 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback( 387 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback(
362 audio_parameters_, handle, length, callback_)); 388 audio_parameters_, handle, length, callback_));
363 audio_thread_.Start(audio_callback_.get(), socket_handle, 389
364 "AudioOutputDevice", true); 390 // If the audio thread hasn't been started before, start it.
391 if (audio_thread_.IsStopped()) {
392 printf("****** Starting audio thread.\n");
393 audio_thread_.Start("AudioOutputDevice", true);
394 }
395 audio_thread_.StartRun(audio_callback_.get(), socket_handle);
396
365 state_ = PAUSED; 397 state_ = PAUSED;
366 398
367 // We handle the case where Play() and/or Pause() may have been called 399 // We handle the case where Play() and/or Pause() may have been called
368 // multiple times before OnStreamCreated() gets called. 400 // multiple times before OnStreamCreated() gets called.
369 if (play_on_start_) 401 if (play_on_start_)
370 PlayOnIOThread(); 402 PlayOnIOThread();
371 } 403 }
372 } 404 }
373 405
374 void AudioOutputDevice::OnIPCClosed() { 406 void AudioOutputDevice::OnIPCClosed() {
407 printf("****** AudioOutputDevice::OnIPCClosed this = %p, state_ = %d\n",
408 this, state_);
375 DCHECK(task_runner()->BelongsToCurrentThread()); 409 DCHECK(task_runner()->BelongsToCurrentThread());
376 state_ = IPC_CLOSED; 410 state_ = IPC_CLOSED;
377 ipc_.reset(); 411 ipc_.reset();
378 412
379 // Signal to unblock any blocked threads waiting for parameters 413 // Signal to unblock any blocked threads waiting for parameters
380 did_receive_auth_.Signal(); 414 did_receive_auth_.Signal();
381 } 415 }
382 416
383 void AudioOutputDevice::WillDestroyCurrentMessageLoop() { 417 void AudioOutputDevice::WillDestroyCurrentMessageLoop() {
384 LOG(ERROR) << "IO loop going away before the audio device has been stopped"; 418 LOG(ERROR) << "IO loop going away before the audio device has been stopped";
385 ShutDownOnIOThread(); 419 StopOnIOThread();
386 } 420 }
387 421
388 // AudioOutputDevice::AudioThreadCallback 422 // AudioOutputDevice::AudioThreadCallback
389 423
390 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback( 424 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback(
391 const AudioParameters& audio_parameters, 425 const AudioParameters& audio_parameters,
392 base::SharedMemoryHandle memory, 426 base::SharedMemoryHandle memory,
393 int memory_length, 427 int memory_length,
394 AudioRendererSink::RenderCallback* render_callback) 428 AudioRendererSink::RenderCallback* render_callback)
395 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length, 1), 429 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length, 1),
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
435 469
436 // Update the audio-delay measurement, inform about the number of skipped 470 // Update the audio-delay measurement, inform about the number of skipped
437 // frames, and ask client to render audio. Since |output_bus_| is wrapping 471 // frames, and ask client to render audio. Since |output_bus_| is wrapping
438 // the shared memory the Render() call is writing directly into the shared 472 // the shared memory the Render() call is writing directly into the shared
439 // memory. 473 // memory.
440 render_callback_->Render(output_bus_.get(), audio_delay_milliseconds, 474 render_callback_->Render(output_bus_.get(), audio_delay_milliseconds,
441 frames_skipped); 475 frames_skipped);
442 } 476 }
443 477
444 } // namespace media 478 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698