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

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: No thread re-use. Also rebase. Created 4 years, 6 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 9
10 #include <cmath> 10 #include <cmath>
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); 47 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback);
48 }; 48 };
49 49
50 AudioOutputDevice::AudioOutputDevice( 50 AudioOutputDevice::AudioOutputDevice(
51 std::unique_ptr<AudioOutputIPC> ipc, 51 std::unique_ptr<AudioOutputIPC> ipc,
52 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, 52 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
53 int session_id, 53 int session_id,
54 const std::string& device_id, 54 const std::string& device_id,
55 const url::Origin& security_origin) 55 const url::Origin& security_origin)
56 : ScopedTaskRunnerObserver(io_task_runner), 56 : ScopedTaskRunnerObserver(io_task_runner),
57 callback_(NULL), 57 render_callback_(nullptr),
58 ipc_(std::move(ipc)), 58 ipc_(std::move(ipc)),
59 state_(IDLE), 59 state_(IDLE),
60 start_on_authorized_(false), 60 start_on_authorized_(false),
61 play_on_start_(true), 61 play_on_start_(true),
62 session_id_(session_id), 62 session_id_(session_id),
63 device_id_(device_id), 63 device_id_(device_id),
64 security_origin_(security_origin), 64 security_origin_(security_origin),
65 stopping_hack_(false),
66 did_receive_auth_(base::WaitableEvent::ResetPolicy::MANUAL, 65 did_receive_auth_(base::WaitableEvent::ResetPolicy::MANUAL,
67 base::WaitableEvent::InitialState::NOT_SIGNALED), 66 base::WaitableEvent::InitialState::NOT_SIGNALED),
68 device_status_(OUTPUT_DEVICE_STATUS_ERROR_INTERNAL) { 67 device_status_(OUTPUT_DEVICE_STATUS_ERROR_INTERNAL) {
69 CHECK(ipc_); 68 CHECK(ipc_);
70 69
71 // The correctness of the code depends on the relative values assigned in the 70 // The correctness of the code depends on the relative values assigned in the
72 // State enum. 71 // State enum.
73 static_assert(IPC_CLOSED < IDLE, "invalid enum value assignment 0"); 72 static_assert(IPC_CLOSED < IDLE, "invalid enum value assignment 0");
74 static_assert(IDLE < AUTHORIZING, "invalid enum value assignment 1"); 73 static_assert(IDLE < AUTHORIZING, "invalid enum value assignment 1");
75 static_assert(AUTHORIZING < AUTHORIZED, "invalid enum value assignment 2"); 74 static_assert(AUTHORIZING < AUTHORIZED, "invalid enum value assignment 2");
76 static_assert(AUTHORIZED < CREATING_STREAM, 75 static_assert(AUTHORIZED < CREATING_STREAM,
77 "invalid enum value assignment 3"); 76 "invalid enum value assignment 3");
78 static_assert(CREATING_STREAM < PAUSED, "invalid enum value assignment 4"); 77 static_assert(CREATING_STREAM < PAUSED, "invalid enum value assignment 4");
79 static_assert(PAUSED < PLAYING, "invalid enum value assignment 5"); 78 static_assert(PAUSED < PLAYING, "invalid enum value assignment 5");
80 } 79 }
81 80
82 void AudioOutputDevice::Initialize(const AudioParameters& params, 81 void AudioOutputDevice::Initialize(
83 RenderCallback* callback) { 82 const AudioParameters& params,
84 DCHECK(!callback_) << "Calling Initialize() twice?"; 83 AudioRendererSink::RenderCallback* callback) {
85 DCHECK(params.IsValid()); 84 DCHECK(params.IsValid());
86 audio_parameters_ = params; 85
87 callback_ = callback; 86 // We set the callback synchronously here, so that it's serialized with
87 // clearing it in Stop(). Note that after this it is possible to get stale
88 // callbacks from previous runs (i.e. from before Stop() was called earlier).
89 // This is because Stop() and Initialize() could be called before
90 // StopOnIOThread() gets to execute; it's in that function we pause the
91 // AudioDeviceThread. We gate callbacks in this class, but after setting a
92 // callback again here, the gate is open.
93 //
94 // Using the IO thread at all in this class will go away soon when we move IPC
95 // to use Mojo, and we'll then get rid of the thread hopping and locks. See
96 // http://crbug.com/606707.
97 {
98 base::AutoLock auto_lock(render_callback_lock_);
99 DCHECK(!render_callback_) << "Already initialized.";
100 render_callback_ = callback;
101 }
102
103 task_runner()->PostTask(
104 FROM_HERE,
105 base::Bind(&AudioOutputDevice::InitializeOnIOThread, this, params));
88 } 106 }
89 107
90 AudioOutputDevice::~AudioOutputDevice() { 108 AudioOutputDevice::~AudioOutputDevice() {
91 // The current design requires that the user calls Stop() before deleting 109 // The current design requires that the user calls Stop() before deleting
92 // this class. 110 // this class to ensure that stream and authorization data is cleaned up on
111 // the browser side, and that we don't get more IPC calls from AudioOutputIPC.
112 // With all posted tasks on IO thread done and no more IPC calls, it's safe to
113 // access |audio_thread_| here on any thread.
114 DCHECK(!render_callback_);
93 DCHECK(audio_thread_.IsStopped()); 115 DCHECK(audio_thread_.IsStopped());
DaleCurtis 2016/06/09 22:37:27 This won't be true with the code you have currentl
Henrik Grunell 2016/06/13 13:43:43 This class is ref counted so all pending tasks wil
94 } 116 }
95 117
96 void AudioOutputDevice::RequestDeviceAuthorization() { 118 void AudioOutputDevice::RequestDeviceAuthorization() {
97 task_runner()->PostTask( 119 task_runner()->PostTask(
98 FROM_HERE, 120 FROM_HERE,
99 base::Bind(&AudioOutputDevice::RequestDeviceAuthorizationOnIOThread, 121 base::Bind(&AudioOutputDevice::RequestDeviceAuthorizationOnIOThread,
100 this)); 122 this));
101 } 123 }
102 124
103 void AudioOutputDevice::Start() { 125 void AudioOutputDevice::Start() {
104 DCHECK(callback_) << "Initialize hasn't been called"; 126 #if !defined(NDEBUG)
105 task_runner()->PostTask(FROM_HERE, 127 {
106 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this, 128 base::AutoLock auto_lock(render_callback_lock_);
DaleCurtis 2016/06/09 22:37:27 This doesn't need a lock since it can only be read
Henrik Grunell 2016/06/13 13:43:43 Done.
107 audio_parameters_)); 129 DCHECK(render_callback_) << "Not initialized.";
130 }
131 #endif
132
133 task_runner()->PostTask(
134 FROM_HERE, base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this));
108 } 135 }
109 136
110 void AudioOutputDevice::Stop() { 137 void AudioOutputDevice::Stop() {
138 // Clear the callback synchronously to ensure no callbacks after returning.
111 { 139 {
112 base::AutoLock auto_lock(audio_thread_lock_); 140 base::AutoLock auto_lock(render_callback_lock_);
113 audio_thread_.Stop(base::MessageLoop::current()); 141 render_callback_ = nullptr;
114 stopping_hack_ = true;
115 } 142 }
116 143
117 task_runner()->PostTask(FROM_HERE, 144 task_runner()->PostTask(FROM_HERE,
118 base::Bind(&AudioOutputDevice::ShutDownOnIOThread, this)); 145 base::Bind(&AudioOutputDevice::StopOnIOThread, this));
119 } 146 }
120 147
121 void AudioOutputDevice::Play() { 148 void AudioOutputDevice::Play() {
122 task_runner()->PostTask(FROM_HERE, 149 task_runner()->PostTask(FROM_HERE,
123 base::Bind(&AudioOutputDevice::PlayOnIOThread, this)); 150 base::Bind(&AudioOutputDevice::PlayOnIOThread, this));
124 } 151 }
125 152
126 void AudioOutputDevice::Pause() { 153 void AudioOutputDevice::Pause() {
127 task_runner()->PostTask(FROM_HERE, 154 task_runner()->PostTask(FROM_HERE,
128 base::Bind(&AudioOutputDevice::PauseOnIOThread, this)); 155 base::Bind(&AudioOutputDevice::PauseOnIOThread, this));
(...skipping 14 matching lines...) Expand all
143 OutputDeviceInfo AudioOutputDevice::GetOutputDeviceInfo() { 170 OutputDeviceInfo AudioOutputDevice::GetOutputDeviceInfo() {
144 CHECK(!task_runner()->BelongsToCurrentThread()); 171 CHECK(!task_runner()->BelongsToCurrentThread());
145 did_receive_auth_.Wait(); 172 did_receive_auth_.Wait();
146 return OutputDeviceInfo(AudioDeviceDescription::UseSessionIdToSelectDevice( 173 return OutputDeviceInfo(AudioDeviceDescription::UseSessionIdToSelectDevice(
147 session_id_, device_id_) 174 session_id_, device_id_)
148 ? matched_device_id_ 175 ? matched_device_id_
149 : device_id_, 176 : device_id_,
150 device_status_, output_params_); 177 device_status_, output_params_);
151 } 178 }
152 179
180 int AudioOutputDevice::Render(media::AudioBus* audio_bus,
181 uint32_t frames_delayed,
182 uint32_t frames_skipped) {
183 base::AutoLock auto_lock(render_callback_lock_);
184 return render_callback_
185 ? render_callback_->Render(audio_bus, frames_delayed,
186 frames_skipped)
187 : 0;
188 }
189
190 void AudioOutputDevice::OnRenderError() {
191 base::AutoLock auto_lock(render_callback_lock_);
192 if (render_callback_)
193 render_callback_->OnRenderError();
194 }
195
153 void AudioOutputDevice::RequestDeviceAuthorizationOnIOThread() { 196 void AudioOutputDevice::RequestDeviceAuthorizationOnIOThread() {
154 DCHECK(task_runner()->BelongsToCurrentThread()); 197 DCHECK(task_runner()->BelongsToCurrentThread());
155 DCHECK_EQ(state_, IDLE); 198 DCHECK_EQ(state_, IDLE);
156 state_ = AUTHORIZING; 199 state_ = AUTHORIZING;
200
201 // TODO(grunell): Store authorization so that we don't have to authorize
202 // again when restarting. http://crbug.com/608619.
157 ipc_->RequestDeviceAuthorization(this, session_id_, device_id_, 203 ipc_->RequestDeviceAuthorization(this, session_id_, device_id_,
158 security_origin_); 204 security_origin_);
159 } 205 }
160 206
161 void AudioOutputDevice::CreateStreamOnIOThread(const AudioParameters& params) { 207 void AudioOutputDevice::InitializeOnIOThread(const AudioParameters& params) {
162 DCHECK(task_runner()->BelongsToCurrentThread()); 208 DCHECK(task_runner()->BelongsToCurrentThread());
209 audio_parameters_ = params;
210 }
211
212 void AudioOutputDevice::CreateStreamOnIOThread() {
213 DCHECK(task_runner()->BelongsToCurrentThread());
214
163 switch (state_) { 215 switch (state_) {
164 case IPC_CLOSED: 216 case IPC_CLOSED:
165 if (callback_) 217 OnRenderError();
166 callback_->OnRenderError();
167 break; 218 break;
168 219
169 case IDLE: 220 case IDLE:
170 if (did_receive_auth_.IsSignaled() && device_id_.empty() && 221 if (did_receive_auth_.IsSignaled() && device_id_.empty() &&
171 security_origin_.unique()) { 222 security_origin_.unique()) {
172 state_ = CREATING_STREAM; 223 state_ = CREATING_STREAM;
173 ipc_->CreateStream(this, params); 224 ipc_->CreateStream(this, audio_parameters_);
174 } else { 225 } else {
175 RequestDeviceAuthorizationOnIOThread(); 226 RequestDeviceAuthorizationOnIOThread();
176 start_on_authorized_ = true; 227 start_on_authorized_ = true;
177 } 228 }
178 break; 229 break;
179 230
180 case AUTHORIZING: 231 case AUTHORIZING:
181 start_on_authorized_ = true; 232 start_on_authorized_ = true;
182 break; 233 break;
183 234
184 case AUTHORIZED: 235 case AUTHORIZED:
185 state_ = CREATING_STREAM; 236 state_ = CREATING_STREAM;
186 ipc_->CreateStream(this, params); 237 ipc_->CreateStream(this, audio_parameters_);
187 start_on_authorized_ = false; 238 start_on_authorized_ = false;
188 break; 239 break;
189 240
190 case CREATING_STREAM: 241 case CREATING_STREAM:
191 case PAUSED: 242 case PAUSED:
192 case PLAYING: 243 case PLAYING:
193 NOTREACHED(); 244 NOTREACHED();
194 break; 245 break;
195 } 246 }
196 } 247 }
197 248
198 void AudioOutputDevice::PlayOnIOThread() { 249 void AudioOutputDevice::PlayOnIOThread() {
199 DCHECK(task_runner()->BelongsToCurrentThread()); 250 DCHECK(task_runner()->BelongsToCurrentThread());
200 if (state_ == PAUSED) { 251 if (state_ == PAUSED) {
201 TRACE_EVENT_ASYNC_BEGIN0( 252 TRACE_EVENT_ASYNC_BEGIN0("audio", "StartingPlayback",
202 "audio", "StartingPlayback", audio_callback_.get()); 253 audio_thread_callback_.get());
203 ipc_->PlayStream(); 254 ipc_->PlayStream();
204 state_ = PLAYING; 255 state_ = PLAYING;
205 play_on_start_ = false; 256 play_on_start_ = false;
206 } else { 257 } else {
207 play_on_start_ = true; 258 play_on_start_ = true;
208 } 259 }
209 } 260 }
210 261
211 void AudioOutputDevice::PauseOnIOThread() { 262 void AudioOutputDevice::PauseOnIOThread() {
212 DCHECK(task_runner()->BelongsToCurrentThread()); 263 DCHECK(task_runner()->BelongsToCurrentThread());
213 if (state_ == PLAYING) { 264 if (state_ == PLAYING) {
214 TRACE_EVENT_ASYNC_END0( 265 TRACE_EVENT_ASYNC_END0("audio", "StartingPlayback",
215 "audio", "StartingPlayback", audio_callback_.get()); 266 audio_thread_callback_.get());
216 ipc_->PauseStream(); 267 ipc_->PauseStream();
217 state_ = PAUSED; 268 state_ = PAUSED;
218 } 269 }
219 play_on_start_ = false; 270 play_on_start_ = false;
220 } 271 }
221 272
222 void AudioOutputDevice::ShutDownOnIOThread() { 273 void AudioOutputDevice::StopOnIOThread() {
223 DCHECK(task_runner()->BelongsToCurrentThread()); 274 DCHECK(task_runner()->BelongsToCurrentThread());
224 275
225 // Close the stream, if we haven't already. 276 // Close the stream, if we haven't already. After CloseStream(), we are
277 // guaranteed to not get IPC calls for any outstanding operations. This holds
278 // also if we restart, i.e. request authorization and create a new stream,
279 // before the previous request and/or create stream finished.
226 if (state_ >= AUTHORIZING) { 280 if (state_ >= AUTHORIZING) {
227 ipc_->CloseStream(); 281 ipc_->CloseStream();
228 state_ = IDLE; 282 state_ = IDLE;
229 } 283 }
230 start_on_authorized_ = false; 284 start_on_authorized_ = false;
285 // TODO BEFORE COMMIT: Do we need this?
DaleCurtis 2016/06/09 22:37:27 I think you still do unless we're okay spinning up
Henrik Grunell 2016/06/13 13:43:43 Kept as is.
286 base::ThreadRestrictions::ScopedAllowIO allow_io;
287 audio_thread_.Stop(nullptr);
288 audio_thread_callback_.reset();
289 play_on_start_ = true;
231 290
232 // We can run into an issue where ShutDownOnIOThread is called right after 291 // We need to re-authorize after stopping.
233 // OnStreamCreated is called in cases where Start/Stop are called before we 292 did_receive_auth_.Reset();
234 // get the OnStreamCreated callback. To handle that corner case, we call
235 // Stop(). In most cases, the thread will already be stopped.
236 //
237 // Another situation is when the IO thread goes away before Stop() is called
238 // in which case, we cannot use the message loop to close the thread handle
239 // and can't rely on the main thread existing either.
240 base::AutoLock auto_lock_(audio_thread_lock_);
241 base::ThreadRestrictions::ScopedAllowIO allow_io;
242 audio_thread_.Stop(NULL);
243 audio_callback_.reset();
244 stopping_hack_ = false;
245 } 293 }
246 294
247 void AudioOutputDevice::SetVolumeOnIOThread(double volume) { 295 void AudioOutputDevice::SetVolumeOnIOThread(double volume) {
248 DCHECK(task_runner()->BelongsToCurrentThread()); 296 DCHECK(task_runner()->BelongsToCurrentThread());
249 if (state_ >= CREATING_STREAM) 297 if (state_ >= CREATING_STREAM)
250 ipc_->SetVolume(volume); 298 ipc_->SetVolume(volume);
251 } 299 }
252 300
253 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegateState state) { 301 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegateState state) {
254 DCHECK(task_runner()->BelongsToCurrentThread()); 302 DCHECK(task_runner()->BelongsToCurrentThread());
255 303
256 // Do nothing if the stream has been closed. 304 // Do nothing if the stream has been closed.
257 if (state_ < CREATING_STREAM) 305 if (state_ < CREATING_STREAM)
258 return; 306 return;
259 307
260 // TODO(miu): Clean-up inconsistent and incomplete handling here. 308 // TODO(miu): Clean-up inconsistent and incomplete handling here.
261 // http://crbug.com/180640 309 // http://crbug.com/180640
262 switch (state) { 310 switch (state) {
263 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING: 311 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING:
264 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED: 312 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED:
265 break; 313 break;
266 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR: 314 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR:
267 DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(ERROR)"; 315 DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(ERROR)";
268 // Don't dereference the callback object if the audio thread 316 OnRenderError();
269 // is stopped or stopping. That could mean that the callback
270 // object has been deleted.
271 // TODO(tommi): Add an explicit contract for clearing the callback
272 // object. Possibly require calling Initialize again or provide
273 // a callback object via Start() and clear it in Stop().
274 if (!audio_thread_.IsStopped())
275 callback_->OnRenderError();
276 break; 317 break;
277 default: 318 default:
278 NOTREACHED(); 319 NOTREACHED();
279 break; 320 break;
280 } 321 }
281 } 322 }
282 323
283 void AudioOutputDevice::OnDeviceAuthorized( 324 void AudioOutputDevice::OnDeviceAuthorized(
284 OutputDeviceStatus device_status, 325 OutputDeviceStatus device_status,
285 const media::AudioParameters& output_params, 326 const media::AudioParameters& output_params,
(...skipping 25 matching lines...) Expand all
311 matched_device_id_.empty()); 352 matched_device_id_.empty());
312 matched_device_id_ = matched_device_id; 353 matched_device_id_ = matched_device_id;
313 354
314 DVLOG(1) << "AudioOutputDevice authorized, session_id: " << session_id_ 355 DVLOG(1) << "AudioOutputDevice authorized, session_id: " << session_id_
315 << ", device_id: " << device_id_ 356 << ", device_id: " << device_id_
316 << ", matched_device_id: " << matched_device_id_; 357 << ", matched_device_id: " << matched_device_id_;
317 358
318 did_receive_auth_.Signal(); 359 did_receive_auth_.Signal();
319 } 360 }
320 if (start_on_authorized_) 361 if (start_on_authorized_)
321 CreateStreamOnIOThread(audio_parameters_); 362 CreateStreamOnIOThread();
322 } else { 363 } else {
323 // Closing IPC forces a Signal(), so no clients are locked waiting 364 // Closing IPC forces a Signal(), so no clients are locked waiting
324 // indefinitely after this method returns. 365 // indefinitely after this method returns.
325 ipc_->CloseStream(); 366 ipc_->CloseStream();
326 OnIPCClosed(); 367 OnIPCClosed();
327 if (callback_) 368 OnRenderError();
328 callback_->OnRenderError();
329 } 369 }
330 } 370 }
331 371
332 void AudioOutputDevice::OnStreamCreated( 372 void AudioOutputDevice::OnStreamCreated(
333 base::SharedMemoryHandle handle, 373 base::SharedMemoryHandle handle,
334 base::SyncSocket::Handle socket_handle, 374 base::SyncSocket::Handle socket_handle,
335 int length) { 375 int length) {
336 DCHECK(task_runner()->BelongsToCurrentThread()); 376 DCHECK(task_runner()->BelongsToCurrentThread());
337 DCHECK(base::SharedMemory::IsHandleValid(handle)); 377 DCHECK(base::SharedMemory::IsHandleValid(handle));
338 #if defined(OS_WIN) 378 #if defined(OS_WIN)
339 DCHECK(socket_handle); 379 DCHECK(socket_handle);
340 #else 380 #else
341 DCHECK_GE(socket_handle, 0); 381 DCHECK_GE(socket_handle, 0);
342 #endif 382 #endif
343 DCHECK_GT(length, 0); 383 DCHECK_GT(length, 0);
344 384
345 if (state_ != CREATING_STREAM) 385 if (state_ != CREATING_STREAM)
346 return; 386 return;
347 387
348 // We can receive OnStreamCreated() on the IO thread after the client has 388 // We can receive OnStreamCreated() on the IO thread after the client has
DaleCurtis 2016/06/09 22:37:27 But aren't you still spinning up a new thread in t
Henrik Grunell 2016/06/13 13:43:43 Yes, a thread will start without needing it, and l
DaleCurtis 2016/06/13 18:52:32 Ah, I forgot this is an interface, we can't use a
Henrik Grunell 2016/06/13 20:12:20 That's a good idea, I'll do that.
349 // called Stop() but before ShutDownOnIOThread() is processed. In such a 389 // called Stop() but before StopOnIOThread() is processed. This is OK, since
350 // situation |callback_| might point to freed memory. Instead of starting 390 // we pass callbacks though |this| and clear |render_callback_| in Stop().
351 // |audio_thread_| do nothing and wait for ShutDownOnIOThread() to get called.
352 // 391 //
353 // TODO(scherkus): The real fix is to have sane ownership semantics. The fact 392 // TODO(grunell): AudioRendererSink should be non-refcounted and
354 // that |callback_| (which should own and outlive this object!) can point to 393 // AudioOutputDevice should internally use WeakPtr to handle teardown and
355 // freed memory is a mess. AudioRendererSink should be non-refcounted so that 394 // thread hopping. See http://crbug.com/151051 for details.
356 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and 395 // Note however that switching the IPC to Mojo will remove usage of the IO
357 // delete as they see fit. AudioOutputDevice should internally use WeakPtr 396 // thread, so we'll eliminate thread concurrency issues here then. See
358 // to handle teardown and thread hopping. See http://crbug.com/151051 for 397 // http://crbug.com/606707.
359 // details.
360 {
361 base::AutoLock auto_lock(audio_thread_lock_);
362 if (stopping_hack_)
363 return;
364 398
365 DCHECK(audio_thread_.IsStopped()); 399 DCHECK(audio_thread_.IsStopped());
366 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback( 400 audio_thread_callback_.reset(new AudioOutputDevice::AudioThreadCallback(
367 audio_parameters_, handle, length, callback_)); 401 audio_parameters_, handle, length, this));
368 audio_thread_.Start(audio_callback_.get(), socket_handle, 402 audio_thread_.Start(audio_thread_callback_.get(), socket_handle,
369 "AudioOutputDevice", true); 403 "AudioOutputDevice", true);
370 state_ = PAUSED;
371 404
372 // We handle the case where Play() and/or Pause() may have been called 405 state_ = PAUSED;
373 // multiple times before OnStreamCreated() gets called. 406
374 if (play_on_start_) 407 // We handle the case where Play() and/or Pause() may have been called
375 PlayOnIOThread(); 408 // multiple times before OnStreamCreated() gets called.
376 } 409 if (play_on_start_)
410 PlayOnIOThread();
377 } 411 }
378 412
379 void AudioOutputDevice::OnIPCClosed() { 413 void AudioOutputDevice::OnIPCClosed() {
380 DCHECK(task_runner()->BelongsToCurrentThread()); 414 DCHECK(task_runner()->BelongsToCurrentThread());
381 state_ = IPC_CLOSED; 415 state_ = IPC_CLOSED;
382 ipc_.reset(); 416 ipc_.reset();
383 417
384 // Signal to unblock any blocked threads waiting for parameters 418 // Signal to unblock any blocked threads waiting for parameters
385 did_receive_auth_.Signal(); 419 did_receive_auth_.Signal();
386 } 420 }
387 421
388 void AudioOutputDevice::WillDestroyCurrentMessageLoop() { 422 void AudioOutputDevice::WillDestroyCurrentMessageLoop() {
389 LOG(ERROR) << "IO loop going away before the audio device has been stopped"; 423 LOG(ERROR) << "IO loop going away before the audio device has been stopped";
390 ShutDownOnIOThread(); 424 StopOnIOThread();
391 } 425 }
392 426
393 // AudioOutputDevice::AudioThreadCallback 427 // AudioOutputDevice::AudioThreadCallback
394 428
395 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback( 429 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback(
396 const AudioParameters& audio_parameters, 430 const AudioParameters& audio_parameters,
397 base::SharedMemoryHandle memory, 431 base::SharedMemoryHandle memory,
398 int memory_length, 432 int memory_length,
399 AudioRendererSink::RenderCallback* render_callback) 433 AudioRendererSink::RenderCallback* render_callback)
400 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length, 1), 434 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length, 1),
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
444 478
445 // Update the audio-delay measurement, inform about the number of skipped 479 // Update the audio-delay measurement, inform about the number of skipped
446 // frames, and ask client to render audio. Since |output_bus_| is wrapping 480 // frames, and ask client to render audio. Since |output_bus_| is wrapping
447 // the shared memory the Render() call is writing directly into the shared 481 // the shared memory the Render() call is writing directly into the shared
448 // memory. 482 // memory.
449 render_callback_->Render(output_bus_.get(), std::round(frames_delayed), 483 render_callback_->Render(output_bus_.get(), std::round(frames_delayed),
450 frames_skipped); 484 frames_skipped);
451 } 485 }
452 486
453 } // namespace media 487 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698