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

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: Changes from olka@, adding callback lock, removing stopping hack, rebase. Created 4 years, 7 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 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_(true, false), 65 did_receive_auth_(true, false),
67 device_status_(OUTPUT_DEVICE_STATUS_ERROR_INTERNAL) { 66 device_status_(OUTPUT_DEVICE_STATUS_ERROR_INTERNAL) {
68 CHECK(ipc_); 67 CHECK(ipc_);
69 68
70 // The correctness of the code depends on the relative values assigned in the 69 // The correctness of the code depends on the relative values assigned in the
71 // State enum. 70 // State enum.
72 static_assert(IPC_CLOSED < IDLE, "invalid enum value assignment 0"); 71 static_assert(IPC_CLOSED < IDLE, "invalid enum value assignment 0");
73 static_assert(IDLE < AUTHORIZING, "invalid enum value assignment 1"); 72 static_assert(IDLE < AUTHORIZING, "invalid enum value assignment 1");
74 static_assert(AUTHORIZING < AUTHORIZED, "invalid enum value assignment 2"); 73 static_assert(AUTHORIZING < AUTHORIZED, "invalid enum value assignment 2");
75 static_assert(AUTHORIZED < CREATING_STREAM, 74 static_assert(AUTHORIZED < CREATING_STREAM,
76 "invalid enum value assignment 3"); 75 "invalid enum value assignment 3");
77 static_assert(CREATING_STREAM < PAUSED, "invalid enum value assignment 4"); 76 static_assert(CREATING_STREAM < PAUSED, "invalid enum value assignment 4");
78 static_assert(PAUSED < PLAYING, "invalid enum value assignment 5"); 77 static_assert(PAUSED < PLAYING, "invalid enum value assignment 5");
79 } 78 }
80 79
81 void AudioOutputDevice::Initialize(const AudioParameters& params, 80 void AudioOutputDevice::Initialize(
82 RenderCallback* callback) { 81 const AudioParameters& params,
82 AudioRendererSink::RenderCallback* callback) {
83 DCHECK(params.IsValid());
84 task_runner()->PostTask(
85 FROM_HERE, base::Bind(&AudioOutputDevice::InitializeOnIOThread, this,
86 params, callback));
87
88 // We set the callback synchronously here, so that it's serialized with
89 // clearing it in Stop(). Note that after this it is possible to get stale
90 // callbacks from previous runs (i.e. from before Stop() was called earlier).
91 // Using the IO thread will go away soon when we move IPC to use Mojo, and
92 // we'll then get rid of the thread hopping and locks.
93 // http://crbug.com/606707.
94 base::AutoLock auto_lock(callback_lock_);
83 DCHECK(!callback_) << "Calling Initialize() twice?"; 95 DCHECK(!callback_) << "Calling Initialize() twice?";
84 DCHECK(params.IsValid());
85 audio_parameters_ = params;
86 callback_ = callback; 96 callback_ = callback;
87 } 97 }
88 98
89 AudioOutputDevice::~AudioOutputDevice() { 99 AudioOutputDevice::~AudioOutputDevice() {
100 // I'm not sure if Stop() should remain mandatory. The purpose of that was
101 // to fix object lifetime issues. Probably we can do it in a cleaner way.
90 // The current design requires that the user calls Stop() before deleting 102 // The current design requires that the user calls Stop() before deleting
91 // this class. 103 // this class. Since this object is reference counted, we're the only one
92 DCHECK(audio_thread_.IsStopped()); 104 // accessing data when we destruct.
105 DCHECK(state_ == IDLE || state_ == IPC_CLOSED);
106 // We need to ensure all the object lifetime stuff still works.
107 // Or even better, fix it to be more clear.
108 audio_thread_.Stop(base::MessageLoop::current());
93 } 109 }
94 110
95 void AudioOutputDevice::RequestDeviceAuthorization() { 111 void AudioOutputDevice::RequestDeviceAuthorization() {
96 task_runner()->PostTask( 112 task_runner()->PostTask(
97 FROM_HERE, 113 FROM_HERE,
98 base::Bind(&AudioOutputDevice::RequestDeviceAuthorizationOnIOThread, 114 base::Bind(&AudioOutputDevice::RequestDeviceAuthorizationOnIOThread,
99 this)); 115 this));
100 } 116 }
101 117
102 void AudioOutputDevice::Start() { 118 void AudioOutputDevice::Start() {
103 DCHECK(callback_) << "Initialize hasn't been called"; 119 #if !defined(NDEBUG)
104 task_runner()->PostTask(FROM_HERE, 120 {
105 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this, 121 base::AutoLock auto_lock(callback_lock_);
106 audio_parameters_)); 122 DCHECK(callback_) << "Initialize hasn't been called";
123 }
124 #endif
125
126 task_runner()->PostTask(
127 FROM_HERE, base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this));
107 } 128 }
108 129
109 void AudioOutputDevice::Stop() { 130 void AudioOutputDevice::Stop() {
110 { 131 {
111 base::AutoLock auto_lock(audio_thread_lock_); 132 // TODO: Add comment why we do this,
112 audio_thread_.Stop(base::MessageLoop::current()); 133 base::AutoLock auto_lock(callback_lock_);
113 stopping_hack_ = true; 134 callback_ = nullptr;
114 } 135 }
115 136
116 task_runner()->PostTask(FROM_HERE, 137 task_runner()->PostTask(FROM_HERE,
117 base::Bind(&AudioOutputDevice::ShutDownOnIOThread, this)); 138 base::Bind(&AudioOutputDevice::StopOnIOThread, this));
118 } 139 }
119 140
120 void AudioOutputDevice::Play() { 141 void AudioOutputDevice::Play() {
121 task_runner()->PostTask(FROM_HERE, 142 task_runner()->PostTask(FROM_HERE,
122 base::Bind(&AudioOutputDevice::PlayOnIOThread, this)); 143 base::Bind(&AudioOutputDevice::PlayOnIOThread, this));
123 } 144 }
124 145
125 void AudioOutputDevice::Pause() { 146 void AudioOutputDevice::Pause() {
126 task_runner()->PostTask(FROM_HERE, 147 task_runner()->PostTask(FROM_HERE,
127 base::Bind(&AudioOutputDevice::PauseOnIOThread, this)); 148 base::Bind(&AudioOutputDevice::PauseOnIOThread, this));
(...skipping 14 matching lines...) Expand all
142 OutputDeviceInfo AudioOutputDevice::GetOutputDeviceInfo() { 163 OutputDeviceInfo AudioOutputDevice::GetOutputDeviceInfo() {
143 CHECK(!task_runner()->BelongsToCurrentThread()); 164 CHECK(!task_runner()->BelongsToCurrentThread());
144 did_receive_auth_.Wait(); 165 did_receive_auth_.Wait();
145 return OutputDeviceInfo(AudioDeviceDescription::UseSessionIdToSelectDevice( 166 return OutputDeviceInfo(AudioDeviceDescription::UseSessionIdToSelectDevice(
146 session_id_, device_id_) 167 session_id_, device_id_)
147 ? matched_device_id_ 168 ? matched_device_id_
148 : device_id_, 169 : device_id_,
149 device_status_, output_params_); 170 device_status_, output_params_);
150 } 171 }
151 172
173 int AudioOutputDevice::Render(media::AudioBus* audio_bus,
174 uint32_t frames_delayed,
175 uint32_t frames_skipped) {
176 base::AutoLock auto_lock(callback_lock_);
177 return callback_
178 ? callback_->Render(audio_bus, frames_delayed, frames_skipped)
179 : 0;
180 }
181
182 void AudioOutputDevice::OnRenderError() {
183 base::AutoLock auto_lock(callback_lock_);
184 if (callback_)
185 callback_->OnRenderError();
186 }
187
152 void AudioOutputDevice::RequestDeviceAuthorizationOnIOThread() { 188 void AudioOutputDevice::RequestDeviceAuthorizationOnIOThread() {
153 DCHECK(task_runner()->BelongsToCurrentThread()); 189 DCHECK(task_runner()->BelongsToCurrentThread());
154 DCHECK_EQ(state_, IDLE); 190 DCHECK_EQ(state_, IDLE);
155 state_ = AUTHORIZING; 191 state_ = AUTHORIZING;
192
193 // TODO(grunell): Store authorization so that we don't have to authorize
194 // again when re-starting. This involves mostly changes on the browser side:
195 // associate authorization by a new id (currently the stream id), don't forget
196 // authorization away after start or stop. Here we would have to explicitly
197 // make the browser side forget authorization in the dtor with a new
198 // AudioOutputIPC function.
156 ipc_->RequestDeviceAuthorization(this, session_id_, device_id_, 199 ipc_->RequestDeviceAuthorization(this, session_id_, device_id_,
157 security_origin_); 200 security_origin_);
158 } 201 }
159 202
160 void AudioOutputDevice::CreateStreamOnIOThread(const AudioParameters& params) { 203 void AudioOutputDevice::InitializeOnIOThread(
204 const AudioParameters& params,
205 AudioRendererSink::RenderCallback* callback) {
161 DCHECK(task_runner()->BelongsToCurrentThread()); 206 DCHECK(task_runner()->BelongsToCurrentThread());
207 audio_parameters_ = params;
208 }
209
210 void AudioOutputDevice::CreateStreamOnIOThread() {
211 DCHECK(task_runner()->BelongsToCurrentThread());
212
162 switch (state_) { 213 switch (state_) {
163 case IPC_CLOSED: 214 case IPC_CLOSED: {
215 base::AutoLock auto_lock(callback_lock_);
164 if (callback_) 216 if (callback_)
165 callback_->OnRenderError(); 217 callback_->OnRenderError();
166 break; 218 } break;
167 219
168 case IDLE: 220 case IDLE:
169 if (did_receive_auth_.IsSignaled() && device_id_.empty() && 221 if (did_receive_auth_.IsSignaled() && device_id_.empty() &&
170 security_origin_.unique()) { 222 security_origin_.unique()) {
171 state_ = CREATING_STREAM; 223 state_ = CREATING_STREAM;
172 ipc_->CreateStream(this, params); 224 ipc_->CreateStream(this, audio_parameters_);
173 } else { 225 } else {
174 RequestDeviceAuthorizationOnIOThread(); 226 RequestDeviceAuthorizationOnIOThread();
175 start_on_authorized_ = true; 227 start_on_authorized_ = true;
176 } 228 }
177 break; 229 break;
178 230
179 case AUTHORIZING: 231 case AUTHORIZING:
180 start_on_authorized_ = true; 232 start_on_authorized_ = true;
181 break; 233 break;
182 234
183 case AUTHORIZED: 235 case AUTHORIZED:
184 state_ = CREATING_STREAM; 236 state_ = CREATING_STREAM;
185 ipc_->CreateStream(this, params); 237 // TODO: This could use new parameters for an old start operation. Needs
238 // to be fixed.
239 ipc_->CreateStream(this, audio_parameters_);
186 start_on_authorized_ = false; 240 start_on_authorized_ = false;
187 break; 241 break;
188 242
189 case CREATING_STREAM: 243 case CREATING_STREAM:
190 case PAUSED: 244 case PAUSED:
191 case PLAYING: 245 case PLAYING:
192 NOTREACHED(); 246 NOTREACHED();
193 break; 247 break;
194 } 248 }
195 } 249 }
(...skipping 15 matching lines...) Expand all
211 DCHECK(task_runner()->BelongsToCurrentThread()); 265 DCHECK(task_runner()->BelongsToCurrentThread());
212 if (state_ == PLAYING) { 266 if (state_ == PLAYING) {
213 TRACE_EVENT_ASYNC_END0( 267 TRACE_EVENT_ASYNC_END0(
214 "audio", "StartingPlayback", audio_callback_.get()); 268 "audio", "StartingPlayback", audio_callback_.get());
215 ipc_->PauseStream(); 269 ipc_->PauseStream();
216 state_ = PAUSED; 270 state_ = PAUSED;
217 } 271 }
218 play_on_start_ = false; 272 play_on_start_ = false;
219 } 273 }
220 274
221 void AudioOutputDevice::ShutDownOnIOThread() { 275 void AudioOutputDevice::StopOnIOThread() {
222 DCHECK(task_runner()->BelongsToCurrentThread()); 276 DCHECK(task_runner()->BelongsToCurrentThread());
223 277
224 // Close the stream, if we haven't already. 278 // Close the stream, if we haven't already.
225 if (state_ >= AUTHORIZING) { 279 if (state_ >= AUTHORIZING) {
226 ipc_->CloseStream(); 280 ipc_->CloseStream();
227 state_ = IDLE; 281 state_ = IDLE;
228 } 282 }
229 start_on_authorized_ = false; 283 start_on_authorized_ = false;
230 284
231 // We can run into an issue where ShutDownOnIOThread is called right after 285 // We can run into an issue where StopOnIOThread is called right after
232 // OnStreamCreated is called in cases where Start/Stop are called before we 286 // OnStreamCreated is called in cases where Start/Stop are called before we
233 // get the OnStreamCreated callback. To handle that corner case, we call 287 // get the OnStreamCreated callback. To handle that corner case, we call
234 // Stop(). In most cases, the thread will already be stopped. 288 // Stop(). In most cases, the thread will already be stopped.
235 // 289
236 // Another situation is when the IO thread goes away before Stop() is called
237 // in which case, we cannot use the message loop to close the thread handle
238 // and can't rely on the main thread existing either.
239 base::AutoLock auto_lock_(audio_thread_lock_); 290 base::AutoLock auto_lock_(audio_thread_lock_);
240 base::ThreadRestrictions::ScopedAllowIO allow_io; 291 audio_thread_.Pause();
241 audio_thread_.Stop(NULL);
242 audio_callback_.reset(); 292 audio_callback_.reset();
243 stopping_hack_ = false;
244 } 293 }
245 294
246 void AudioOutputDevice::SetVolumeOnIOThread(double volume) { 295 void AudioOutputDevice::SetVolumeOnIOThread(double volume) {
247 DCHECK(task_runner()->BelongsToCurrentThread()); 296 DCHECK(task_runner()->BelongsToCurrentThread());
248 if (state_ >= CREATING_STREAM) 297 if (state_ >= CREATING_STREAM)
249 ipc_->SetVolume(volume); 298 ipc_->SetVolume(volume);
250 } 299 }
251 300
252 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegateState state) { 301 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegateState state) {
253 DCHECK(task_runner()->BelongsToCurrentThread()); 302 DCHECK(task_runner()->BelongsToCurrentThread());
254 303
255 // Do nothing if the stream has been closed. 304 // Do nothing if the stream has been closed.
256 if (state_ < CREATING_STREAM) 305 if (state_ < CREATING_STREAM)
257 return; 306 return;
258 307
259 // TODO(miu): Clean-up inconsistent and incomplete handling here. 308 // TODO(miu): Clean-up inconsistent and incomplete handling here.
260 // http://crbug.com/180640 309 // http://crbug.com/180640
261 switch (state) { 310 switch (state) {
262 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING: 311 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PLAYING:
263 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED: 312 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED:
264 break; 313 break;
265 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR: 314 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR:
266 DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(ERROR)"; 315 DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(ERROR)";
267 // Don't dereference the callback object if the audio thread 316 // The callback object is cleared in Stop().
268 // is stopped or stopping. That could mean that the callback 317 {
269 // object has been deleted. 318 base::AutoLock auto_lock(callback_lock_);
270 // TODO(tommi): Add an explicit contract for clearing the callback 319 if (callback_)
271 // object. Possibly require calling Initialize again or provide 320 callback_->OnRenderError();
272 // a callback object via Start() and clear it in Stop(). 321 }
273 if (!audio_thread_.IsStopped())
274 callback_->OnRenderError();
275 break; 322 break;
276 default: 323 default:
277 NOTREACHED(); 324 NOTREACHED();
278 break; 325 break;
279 } 326 }
280 } 327 }
281 328
282 void AudioOutputDevice::OnDeviceAuthorized( 329 void AudioOutputDevice::OnDeviceAuthorized(
283 OutputDeviceStatus device_status, 330 OutputDeviceStatus device_status,
284 const media::AudioParameters& output_params, 331 const media::AudioParameters& output_params,
(...skipping 25 matching lines...) Expand all
310 matched_device_id_.empty()); 357 matched_device_id_.empty());
311 matched_device_id_ = matched_device_id; 358 matched_device_id_ = matched_device_id;
312 359
313 DVLOG(1) << "AudioOutputDevice authorized, session_id: " << session_id_ 360 DVLOG(1) << "AudioOutputDevice authorized, session_id: " << session_id_
314 << ", device_id: " << device_id_ 361 << ", device_id: " << device_id_
315 << ", matched_device_id: " << matched_device_id_; 362 << ", matched_device_id: " << matched_device_id_;
316 363
317 did_receive_auth_.Signal(); 364 did_receive_auth_.Signal();
318 } 365 }
319 if (start_on_authorized_) 366 if (start_on_authorized_)
320 CreateStreamOnIOThread(audio_parameters_); 367 CreateStreamOnIOThread();
321 } else { 368 } else {
322 // Closing IPC forces a Signal(), so no clients are locked waiting 369 // Closing IPC forces a Signal(), so no clients are locked waiting
323 // indefinitely after this method returns. 370 // indefinitely after this method returns.
324 ipc_->CloseStream(); 371 ipc_->CloseStream();
325 OnIPCClosed(); 372 OnIPCClosed();
373 base::AutoLock auto_lock(callback_lock_);
326 if (callback_) 374 if (callback_)
327 callback_->OnRenderError(); 375 callback_->OnRenderError();
328 } 376 }
329 } 377 }
330 378
331 void AudioOutputDevice::OnStreamCreated( 379 void AudioOutputDevice::OnStreamCreated(
332 base::SharedMemoryHandle handle, 380 base::SharedMemoryHandle handle,
333 base::SyncSocket::Handle socket_handle, 381 base::SyncSocket::Handle socket_handle,
334 int length) { 382 int length) {
335 DCHECK(task_runner()->BelongsToCurrentThread()); 383 DCHECK(task_runner()->BelongsToCurrentThread());
336 DCHECK(base::SharedMemory::IsHandleValid(handle)); 384 DCHECK(base::SharedMemory::IsHandleValid(handle));
337 #if defined(OS_WIN) 385 #if defined(OS_WIN)
338 DCHECK(socket_handle); 386 DCHECK(socket_handle);
339 #else 387 #else
340 DCHECK_GE(socket_handle, 0); 388 DCHECK_GE(socket_handle, 0);
341 #endif 389 #endif
342 DCHECK_GT(length, 0); 390 DCHECK_GT(length, 0);
343 391
344 if (state_ != CREATING_STREAM) 392 if (state_ != CREATING_STREAM)
345 return; 393 return;
346 394
395 // TODO: Update the comment.
396
347 // We can receive OnStreamCreated() on the IO thread after the client has 397 // We can receive OnStreamCreated() on the IO thread after the client has
348 // called Stop() but before ShutDownOnIOThread() is processed. In such a 398 // called Stop() but before StopOnIOThread() is processed. In such a
349 // situation |callback_| might point to freed memory. Instead of starting 399 // situation |callback_| might point to freed memory. Instead of starting
350 // |audio_thread_| do nothing and wait for ShutDownOnIOThread() to get called. 400 // |audio_thread_| do nothing and wait for StopOnIOThread() to get called.
351 // 401 //
352 // TODO(scherkus): The real fix is to have sane ownership semantics. The fact 402 // TODO(scherkus): The real fix is to have sane ownership semantics. The fact
353 // that |callback_| (which should own and outlive this object!) can point to 403 // that |callback_| (which should own and outlive this object!) can point to
354 // freed memory is a mess. AudioRendererSink should be non-refcounted so that 404 // freed memory is a mess. AudioRendererSink should be non-refcounted so that
355 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and 405 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and
356 // delete as they see fit. AudioOutputDevice should internally use WeakPtr 406 // delete as they see fit. AudioOutputDevice should internally use WeakPtr
357 // to handle teardown and thread hopping. See http://crbug.com/151051 for 407 // to handle teardown and thread hopping. See http://crbug.com/151051 for
358 // details. 408 // details.
359 { 409 {
360 base::AutoLock auto_lock(audio_thread_lock_); 410 base::AutoLock auto_lock(audio_thread_lock_);
361 if (stopping_hack_)
362 return;
363 411
364 DCHECK(audio_thread_.IsStopped()); 412 DCHECK(audio_thread_.IsStopped());
365 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback( 413 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback(
366 audio_parameters_, handle, length, callback_)); 414 audio_parameters_, handle, length, this));
367 audio_thread_.Start(audio_callback_.get(), socket_handle, 415
368 "AudioOutputDevice", true); 416 // If the audio thread hasn't been started before, start it.
417 if (audio_thread_.IsStopped()) {
418 audio_thread_.Start("AudioOutputDevice", true);
419 }
420 audio_thread_.Play(audio_callback_.get(), socket_handle);
421
369 state_ = PAUSED; 422 state_ = PAUSED;
370 423
371 // We handle the case where Play() and/or Pause() may have been called 424 // We handle the case where Play() and/or Pause() may have been called
372 // multiple times before OnStreamCreated() gets called. 425 // multiple times before OnStreamCreated() gets called.
373 if (play_on_start_) 426 if (play_on_start_)
374 PlayOnIOThread(); 427 PlayOnIOThread();
375 } 428 }
376 } 429 }
377 430
378 void AudioOutputDevice::OnIPCClosed() { 431 void AudioOutputDevice::OnIPCClosed() {
379 DCHECK(task_runner()->BelongsToCurrentThread()); 432 DCHECK(task_runner()->BelongsToCurrentThread());
380 state_ = IPC_CLOSED; 433 state_ = IPC_CLOSED;
381 ipc_.reset(); 434 ipc_.reset();
382 435
383 // Signal to unblock any blocked threads waiting for parameters 436 // Signal to unblock any blocked threads waiting for parameters
384 did_receive_auth_.Signal(); 437 did_receive_auth_.Signal();
385 } 438 }
386 439
387 void AudioOutputDevice::WillDestroyCurrentMessageLoop() { 440 void AudioOutputDevice::WillDestroyCurrentMessageLoop() {
388 LOG(ERROR) << "IO loop going away before the audio device has been stopped"; 441 LOG(ERROR) << "IO loop going away before the audio device has been stopped";
389 ShutDownOnIOThread(); 442 StopOnIOThread();
390 } 443 }
391 444
392 // AudioOutputDevice::AudioThreadCallback 445 // AudioOutputDevice::AudioThreadCallback
393 446
394 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback( 447 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback(
395 const AudioParameters& audio_parameters, 448 const AudioParameters& audio_parameters,
396 base::SharedMemoryHandle memory, 449 base::SharedMemoryHandle memory,
397 int memory_length, 450 int memory_length,
398 AudioRendererSink::RenderCallback* render_callback) 451 AudioRendererSink::RenderCallback* render_callback)
399 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length, 1), 452 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length, 1),
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
443 496
444 // Update the audio-delay measurement, inform about the number of skipped 497 // Update the audio-delay measurement, inform about the number of skipped
445 // frames, and ask client to render audio. Since |output_bus_| is wrapping 498 // frames, and ask client to render audio. Since |output_bus_| is wrapping
446 // the shared memory the Render() call is writing directly into the shared 499 // the shared memory the Render() call is writing directly into the shared
447 // memory. 500 // memory.
448 render_callback_->Render(output_bus_.get(), std::round(frames_delayed), 501 render_callback_->Render(output_bus_.get(), std::round(frames_delayed),
449 frames_skipped); 502 frames_skipped);
450 } 503 }
451 504
452 } // namespace media 505 } // namespace media
OLDNEW
« media/audio/audio_device_thread.h ('K') | « media/audio/audio_output_device.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698