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

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: Code review (dalecurtis@). 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
« no previous file with comments | « media/audio/audio_output_device.h ('k') | media/audio/audio_output_device_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/audio/audio_output_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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
50 }; 50 };
51 51
52 AudioOutputDevice::AudioOutputDevice( 52 AudioOutputDevice::AudioOutputDevice(
53 std::unique_ptr<AudioOutputIPC> ipc, 53 std::unique_ptr<AudioOutputIPC> ipc,
54 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, 54 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner,
55 int session_id, 55 int session_id,
56 const std::string& device_id, 56 const std::string& device_id,
57 const url::Origin& security_origin, 57 const url::Origin& security_origin,
58 base::TimeDelta authorization_timeout) 58 base::TimeDelta authorization_timeout)
59 : ScopedTaskRunnerObserver(io_task_runner), 59 : ScopedTaskRunnerObserver(io_task_runner),
60 callback_(NULL),
61 ipc_(std::move(ipc)), 60 ipc_(std::move(ipc)),
62 state_(IDLE), 61 state_(IDLE),
63 start_on_authorized_(false), 62 start_on_authorized_(false),
64 play_on_start_(true), 63 play_on_start_(true),
65 session_id_(session_id), 64 session_id_(session_id),
66 device_id_(device_id), 65 device_id_(device_id),
67 security_origin_(security_origin), 66 security_origin_(security_origin),
67 render_callback_(nullptr),
68 stopping_hack_(false), 68 stopping_hack_(false),
69 did_receive_auth_(base::WaitableEvent::ResetPolicy::MANUAL, 69 did_receive_auth_(base::WaitableEvent::ResetPolicy::MANUAL,
70 base::WaitableEvent::InitialState::NOT_SIGNALED), 70 base::WaitableEvent::InitialState::NOT_SIGNALED),
71 device_status_(OUTPUT_DEVICE_STATUS_ERROR_INTERNAL), 71 device_status_(OUTPUT_DEVICE_STATUS_ERROR_INTERNAL),
72 auth_timeout_(authorization_timeout) { 72 auth_timeout_(authorization_timeout) {
73 CHECK(ipc_); 73 CHECK(ipc_);
74 74
75 // The correctness of the code depends on the relative values assigned in the 75 // The correctness of the code depends on the relative values assigned in the
76 // State enum. 76 // State enum.
77 static_assert(IPC_CLOSED < IDLE, "invalid enum value assignment 0"); 77 static_assert(IPC_CLOSED < IDLE, "invalid enum value assignment 0");
78 static_assert(IDLE < AUTHORIZING, "invalid enum value assignment 1"); 78 static_assert(IDLE < AUTHORIZING, "invalid enum value assignment 1");
79 static_assert(AUTHORIZING < AUTHORIZED, "invalid enum value assignment 2"); 79 static_assert(AUTHORIZING < AUTHORIZED, "invalid enum value assignment 2");
80 static_assert(AUTHORIZED < CREATING_STREAM, 80 static_assert(AUTHORIZED < CREATING_STREAM,
81 "invalid enum value assignment 3"); 81 "invalid enum value assignment 3");
82 static_assert(CREATING_STREAM < PAUSED, "invalid enum value assignment 4"); 82 static_assert(CREATING_STREAM < PAUSED, "invalid enum value assignment 4");
83 static_assert(PAUSED < PLAYING, "invalid enum value assignment 5"); 83 static_assert(PAUSED < PLAYING, "invalid enum value assignment 5");
84
85 control_thread_checker_.DetachFromThread();
84 } 86 }
85 87
86 void AudioOutputDevice::Initialize(const AudioParameters& params, 88 void AudioOutputDevice::Initialize(
87 RenderCallback* callback) { 89 const AudioParameters& params,
88 DCHECK(!callback_) << "Calling Initialize() twice?"; 90 AudioRendererSink::RenderCallback* callback) {
91 DCHECK(control_thread_checker_.CalledOnValidThread());
92 DCHECK(!render_callback_) << "Already initialized.";
89 DCHECK(params.IsValid()); 93 DCHECK(params.IsValid());
90 audio_parameters_ = params; 94 audio_parameters_ = params;
91 callback_ = callback; 95 {
DaleCurtis 2016/06/16 16:39:14 Drop the lock? DCHECK(!thread.started()) ?
Henrik Grunell 2016/06/16 20:23:00 SG, I'll do that tomorrow.
96 base::AutoLock auto_lock(lock_);
97 render_callback_ = callback;
98 }
92 } 99 }
93 100
94 AudioOutputDevice::~AudioOutputDevice() { 101 AudioOutputDevice::~AudioOutputDevice() {
95 // The current design requires that the user calls Stop() before deleting 102 // The current design requires that the user calls Stop() before deleting
96 // this class. 103 // this class to ensure that stream and authorization data is cleaned up on
104 // the browser side, and that we don't get more IPC calls from AudioOutputIPC.
105 // With all posted tasks on IO thread done and no more IPC calls, it's safe to
106 // access |audio_thread_| here on any thread.
97 DCHECK(audio_thread_.IsStopped()); 107 DCHECK(audio_thread_.IsStopped());
98 } 108 }
99 109
100 void AudioOutputDevice::RequestDeviceAuthorization() { 110 void AudioOutputDevice::RequestDeviceAuthorization() {
101 task_runner()->PostTask( 111 task_runner()->PostTask(
102 FROM_HERE, 112 FROM_HERE,
103 base::Bind(&AudioOutputDevice::RequestDeviceAuthorizationOnIOThread, 113 base::Bind(&AudioOutputDevice::RequestDeviceAuthorizationOnIOThread,
104 this)); 114 this));
105 } 115 }
106 116
107 void AudioOutputDevice::Start() { 117 void AudioOutputDevice::Start() {
108 DCHECK(callback_) << "Initialize hasn't been called"; 118 DCHECK(control_thread_checker_.CalledOnValidThread());
109 task_runner()->PostTask(FROM_HERE, 119 DCHECK(render_callback_) << "Not initialized.";
110 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this, 120 task_runner()->PostTask(
111 audio_parameters_)); 121 FROM_HERE, base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this));
112 } 122 }
113 123
114 void AudioOutputDevice::Stop() { 124 void AudioOutputDevice::Stop() {
125 DCHECK(control_thread_checker_.CalledOnValidThread());
115 { 126 {
116 base::AutoLock auto_lock(audio_thread_lock_); 127 base::AutoLock auto_lock(lock_);
117 audio_thread_.Stop(base::MessageLoop::current()); 128 audio_thread_.Stop(base::MessageLoop::current());
118 stopping_hack_ = true; 129 stopping_hack_ = true;
130 render_callback_ = nullptr;
119 } 131 }
120 132
121 task_runner()->PostTask(FROM_HERE, 133 task_runner()->PostTask(FROM_HERE,
122 base::Bind(&AudioOutputDevice::ShutDownOnIOThread, this)); 134 base::Bind(&AudioOutputDevice::StopOnIOThread, this));
123 } 135 }
124 136
125 void AudioOutputDevice::Play() { 137 void AudioOutputDevice::Play() {
126 task_runner()->PostTask(FROM_HERE, 138 task_runner()->PostTask(FROM_HERE,
127 base::Bind(&AudioOutputDevice::PlayOnIOThread, this)); 139 base::Bind(&AudioOutputDevice::PlayOnIOThread, this));
128 } 140 }
129 141
130 void AudioOutputDevice::Pause() { 142 void AudioOutputDevice::Pause() {
DaleCurtis 2016/06/16 22:00:53 Note: This is called from the Render thread by Ren
131 task_runner()->PostTask(FROM_HERE, 143 task_runner()->PostTask(FROM_HERE,
132 base::Bind(&AudioOutputDevice::PauseOnIOThread, this)); 144 base::Bind(&AudioOutputDevice::PauseOnIOThread, this));
133 } 145 }
134 146
135 bool AudioOutputDevice::SetVolume(double volume) { 147 bool AudioOutputDevice::SetVolume(double volume) {
136 if (volume < 0 || volume > 1.0) 148 if (volume < 0 || volume > 1.0)
137 return false; 149 return false;
138 150
139 if (!task_runner()->PostTask(FROM_HERE, 151 if (!task_runner()->PostTask(FROM_HERE,
140 base::Bind(&AudioOutputDevice::SetVolumeOnIOThread, this, volume))) { 152 base::Bind(&AudioOutputDevice::SetVolumeOnIOThread, this, volume))) {
141 return false; 153 return false;
142 } 154 }
143 155
144 return true; 156 return true;
145 } 157 }
146 158
147 OutputDeviceInfo AudioOutputDevice::GetOutputDeviceInfo() { 159 OutputDeviceInfo AudioOutputDevice::GetOutputDeviceInfo() {
148 CHECK(!task_runner()->BelongsToCurrentThread()); 160 CHECK(!task_runner()->BelongsToCurrentThread());
149 did_receive_auth_.Wait(); 161 did_receive_auth_.Wait();
150 return OutputDeviceInfo(AudioDeviceDescription::UseSessionIdToSelectDevice( 162 return OutputDeviceInfo(AudioDeviceDescription::UseSessionIdToSelectDevice(
151 session_id_, device_id_) 163 session_id_, device_id_)
152 ? matched_device_id_ 164 ? matched_device_id_
153 : device_id_, 165 : device_id_,
154 device_status_, output_params_); 166 device_status_, output_params_);
155 } 167 }
156 168
169 void AudioOutputDevice::ReportRenderError() {
170 base::AutoLock auto_lock(lock_);
171 if (render_callback_)
172 render_callback_->OnRenderError();
173 }
174
157 void AudioOutputDevice::RequestDeviceAuthorizationOnIOThread() { 175 void AudioOutputDevice::RequestDeviceAuthorizationOnIOThread() {
158 DCHECK(task_runner()->BelongsToCurrentThread()); 176 DCHECK(task_runner()->BelongsToCurrentThread());
159 DCHECK_EQ(state_, IDLE); 177 DCHECK_EQ(state_, IDLE);
160 state_ = AUTHORIZING; 178 state_ = AUTHORIZING;
179
180 // TODO(grunell): Store authorization so that we don't have to authorize
181 // again when restarting. http://crbug.com/608619.
161 ipc_->RequestDeviceAuthorization(this, session_id_, device_id_, 182 ipc_->RequestDeviceAuthorization(this, session_id_, device_id_,
162 security_origin_); 183 security_origin_);
163 184
164 // Create the timer on the thread it's used on. It's guaranteed to be 185 // Create the timer on the thread it's used on. It's guaranteed to be
165 // deleted on the same thread since users must call Stop() before deleting 186 // deleted on the same thread since users must call Stop() before deleting
166 // AudioOutputDevice; see ShutDownOnIOThread(). 187 // AudioOutputDevice; see ShutDownOnIOThread().
167 auth_timeout_action_.reset(new base::OneShotTimer()); 188 auth_timeout_action_.reset(new base::OneShotTimer());
168 auth_timeout_action_->Start( 189 auth_timeout_action_->Start(
169 FROM_HERE, auth_timeout_, 190 FROM_HERE, auth_timeout_,
170 base::Bind(&AudioOutputDevice::OnDeviceAuthorized, this, 191 base::Bind(&AudioOutputDevice::OnDeviceAuthorized, this,
171 OUTPUT_DEVICE_STATUS_ERROR_TIMED_OUT, media::AudioParameters(), 192 OUTPUT_DEVICE_STATUS_ERROR_TIMED_OUT, media::AudioParameters(),
172 std::string())); 193 std::string()));
173 } 194 }
174 195
175 void AudioOutputDevice::CreateStreamOnIOThread(const AudioParameters& params) { 196 void AudioOutputDevice::CreateStreamOnIOThread() {
176 DCHECK(task_runner()->BelongsToCurrentThread()); 197 DCHECK(task_runner()->BelongsToCurrentThread());
198
177 switch (state_) { 199 switch (state_) {
178 case IPC_CLOSED: 200 case IPC_CLOSED:
179 if (callback_) 201 ReportRenderError();
180 callback_->OnRenderError();
181 break; 202 break;
182 203
183 case IDLE: 204 case IDLE:
184 if (did_receive_auth_.IsSignaled() && device_id_.empty() && 205 if (did_receive_auth_.IsSignaled() && device_id_.empty() &&
185 security_origin_.unique()) { 206 security_origin_.unique()) {
186 state_ = CREATING_STREAM; 207 state_ = CREATING_STREAM;
187 ipc_->CreateStream(this, params); 208 ipc_->CreateStream(this, audio_parameters_);
188 } else { 209 } else {
189 RequestDeviceAuthorizationOnIOThread(); 210 RequestDeviceAuthorizationOnIOThread();
190 start_on_authorized_ = true; 211 start_on_authorized_ = true;
191 } 212 }
192 break; 213 break;
193 214
194 case AUTHORIZING: 215 case AUTHORIZING:
195 start_on_authorized_ = true; 216 start_on_authorized_ = true;
196 break; 217 break;
197 218
198 case AUTHORIZED: 219 case AUTHORIZED:
199 state_ = CREATING_STREAM; 220 state_ = CREATING_STREAM;
200 ipc_->CreateStream(this, params); 221 ipc_->CreateStream(this, audio_parameters_);
201 start_on_authorized_ = false; 222 start_on_authorized_ = false;
202 break; 223 break;
203 224
204 case CREATING_STREAM: 225 case CREATING_STREAM:
205 case PAUSED: 226 case PAUSED:
206 case PLAYING: 227 case PLAYING:
207 NOTREACHED(); 228 NOTREACHED();
208 break; 229 break;
209 } 230 }
210 } 231 }
211 232
212 void AudioOutputDevice::PlayOnIOThread() { 233 void AudioOutputDevice::PlayOnIOThread() {
213 DCHECK(task_runner()->BelongsToCurrentThread()); 234 DCHECK(task_runner()->BelongsToCurrentThread());
214 if (state_ == PAUSED) { 235 if (state_ == PAUSED) {
215 TRACE_EVENT_ASYNC_BEGIN0( 236 TRACE_EVENT_ASYNC_BEGIN0("audio", "StartingPlayback",
216 "audio", "StartingPlayback", audio_callback_.get()); 237 audio_thread_callback_.get());
217 ipc_->PlayStream(); 238 ipc_->PlayStream();
218 state_ = PLAYING; 239 state_ = PLAYING;
219 play_on_start_ = false; 240 play_on_start_ = false;
220 } else { 241 } else {
221 play_on_start_ = true; 242 play_on_start_ = true;
222 } 243 }
223 } 244 }
224 245
225 void AudioOutputDevice::PauseOnIOThread() { 246 void AudioOutputDevice::PauseOnIOThread() {
226 DCHECK(task_runner()->BelongsToCurrentThread()); 247 DCHECK(task_runner()->BelongsToCurrentThread());
227 if (state_ == PLAYING) { 248 if (state_ == PLAYING) {
228 TRACE_EVENT_ASYNC_END0( 249 TRACE_EVENT_ASYNC_END0("audio", "StartingPlayback",
229 "audio", "StartingPlayback", audio_callback_.get()); 250 audio_thread_callback_.get());
230 ipc_->PauseStream(); 251 ipc_->PauseStream();
231 state_ = PAUSED; 252 state_ = PAUSED;
232 } 253 }
233 play_on_start_ = false; 254 play_on_start_ = false;
234 } 255 }
235 256
236 void AudioOutputDevice::ShutDownOnIOThread() { 257 void AudioOutputDevice::StopOnIOThread() {
237 DCHECK(task_runner()->BelongsToCurrentThread()); 258 DCHECK(task_runner()->BelongsToCurrentThread());
238 259
239 // Close the stream, if we haven't already. 260 // Close the stream, if we haven't already. After CloseStream(), we are
261 // guaranteed to not get IPC calls for any outstanding operations. This holds
262 // also if we restart, i.e. request authorization and create a new stream,
263 // before the previous request and/or create stream finished.
240 if (state_ >= AUTHORIZING) { 264 if (state_ >= AUTHORIZING) {
241 ipc_->CloseStream(); 265 ipc_->CloseStream();
242 state_ = IDLE; 266 state_ = IDLE;
243 } 267 }
244 start_on_authorized_ = false; 268 start_on_authorized_ = false;
245 269
270 // We need to re-authorize after stopping.
271 did_receive_auth_.Reset();
272
246 // Destoy the timer on the thread it's used on. 273 // Destoy the timer on the thread it's used on.
247 auth_timeout_action_.reset(); 274 auth_timeout_action_.reset();
248 275
249 // We can run into an issue where ShutDownOnIOThread is called right after 276 // We can run into an issue where ShutDownOnIOThread is called right after
250 // OnStreamCreated is called in cases where Start/Stop are called before we 277 // OnStreamCreated is called in cases where Start/Stop are called before we
251 // get the OnStreamCreated callback. To handle that corner case, we call 278 // get the OnStreamCreated callback. To handle that corner case, we call
252 // Stop(). In most cases, the thread will already be stopped. 279 // Stop(). In most cases, the thread will already be stopped.
253 // 280 //
254 // Another situation is when the IO thread goes away before Stop() is called 281 // Another situation is when the IO thread goes away before Stop() is called
255 // in which case, we cannot use the message loop to close the thread handle 282 // in which case, we cannot use the message loop to close the thread handle
256 // and can't rely on the main thread existing either. 283 // and can't rely on the main thread existing either.
257 base::AutoLock auto_lock_(audio_thread_lock_); 284 base::AutoLock auto_lock_(lock_);
DaleCurtis 2016/06/16 16:39:14 I'm worried this can deadlock now. You're waiting
Henrik Grunell 2016/06/16 20:23:00 This lock is never grabbed on the audio render thr
DaleCurtis 2016/06/16 22:00:53 No, I had forgotten we're not using your old patch
258 base::ThreadRestrictions::ScopedAllowIO allow_io; 285 base::ThreadRestrictions::ScopedAllowIO allow_io;
259 audio_thread_.Stop(NULL); 286 audio_thread_.Stop(NULL);
260 audio_callback_.reset(); 287 audio_thread_callback_.reset();
261 stopping_hack_ = false; 288 stopping_hack_ = false;
289 play_on_start_ = true;
262 } 290 }
263 291
264 void AudioOutputDevice::SetVolumeOnIOThread(double volume) { 292 void AudioOutputDevice::SetVolumeOnIOThread(double volume) {
265 DCHECK(task_runner()->BelongsToCurrentThread()); 293 DCHECK(task_runner()->BelongsToCurrentThread());
266 if (state_ >= CREATING_STREAM) 294 if (state_ >= CREATING_STREAM)
267 ipc_->SetVolume(volume); 295 ipc_->SetVolume(volume);
268 } 296 }
269 297
270 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegateState state) { 298 void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegateState state) {
271 DCHECK(task_runner()->BelongsToCurrentThread()); 299 DCHECK(task_runner()->BelongsToCurrentThread());
(...skipping 10 matching lines...) Expand all
282 break; 310 break;
283 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR: 311 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR:
284 DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(ERROR)"; 312 DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(ERROR)";
285 // Don't dereference the callback object if the audio thread 313 // Don't dereference the callback object if the audio thread
286 // is stopped or stopping. That could mean that the callback 314 // is stopped or stopping. That could mean that the callback
287 // object has been deleted. 315 // object has been deleted.
288 // TODO(tommi): Add an explicit contract for clearing the callback 316 // TODO(tommi): Add an explicit contract for clearing the callback
289 // object. Possibly require calling Initialize again or provide 317 // object. Possibly require calling Initialize again or provide
290 // a callback object via Start() and clear it in Stop(). 318 // a callback object via Start() and clear it in Stop().
291 if (!audio_thread_.IsStopped()) 319 if (!audio_thread_.IsStopped())
292 callback_->OnRenderError(); 320 ReportRenderError();
293 break; 321 break;
294 default: 322 default:
295 NOTREACHED(); 323 NOTREACHED();
296 break; 324 break;
297 } 325 }
298 } 326 }
299 327
300 void AudioOutputDevice::OnDeviceAuthorized( 328 void AudioOutputDevice::OnDeviceAuthorized(
301 OutputDeviceStatus device_status, 329 OutputDeviceStatus device_status,
302 const media::AudioParameters& output_params, 330 const media::AudioParameters& output_params,
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 matched_device_id_.empty()); 366 matched_device_id_.empty());
339 matched_device_id_ = matched_device_id; 367 matched_device_id_ = matched_device_id;
340 368
341 DVLOG(1) << "AudioOutputDevice authorized, session_id: " << session_id_ 369 DVLOG(1) << "AudioOutputDevice authorized, session_id: " << session_id_
342 << ", device_id: " << device_id_ 370 << ", device_id: " << device_id_
343 << ", matched_device_id: " << matched_device_id_; 371 << ", matched_device_id: " << matched_device_id_;
344 372
345 did_receive_auth_.Signal(); 373 did_receive_auth_.Signal();
346 } 374 }
347 if (start_on_authorized_) 375 if (start_on_authorized_)
348 CreateStreamOnIOThread(audio_parameters_); 376 CreateStreamOnIOThread();
349 } else { 377 } else {
350 // Closing IPC forces a Signal(), so no clients are locked waiting 378 // Closing IPC forces a Signal(), so no clients are locked waiting
351 // indefinitely after this method returns. 379 // indefinitely after this method returns.
352 ipc_->CloseStream(); 380 ipc_->CloseStream();
353 OnIPCClosed(); 381 OnIPCClosed();
354 if (callback_) 382 ReportRenderError();
355 callback_->OnRenderError();
356 } 383 }
357 } 384 }
358 385
359 void AudioOutputDevice::OnStreamCreated( 386 void AudioOutputDevice::OnStreamCreated(
360 base::SharedMemoryHandle handle, 387 base::SharedMemoryHandle handle,
361 base::SyncSocket::Handle socket_handle, 388 base::SyncSocket::Handle socket_handle,
362 int length) { 389 int length) {
363 DCHECK(task_runner()->BelongsToCurrentThread()); 390 DCHECK(task_runner()->BelongsToCurrentThread());
364 DCHECK(base::SharedMemory::IsHandleValid(handle)); 391 DCHECK(base::SharedMemory::IsHandleValid(handle));
365 #if defined(OS_WIN) 392 #if defined(OS_WIN)
366 DCHECK(socket_handle); 393 DCHECK(socket_handle);
367 #else 394 #else
368 DCHECK_GE(socket_handle, 0); 395 DCHECK_GE(socket_handle, 0);
369 #endif 396 #endif
370 DCHECK_GT(length, 0); 397 DCHECK_GT(length, 0);
371 398
372 if (state_ != CREATING_STREAM) 399 if (state_ != CREATING_STREAM)
373 return; 400 return;
374 401
375 // We can receive OnStreamCreated() on the IO thread after the client has 402 // We can receive OnStreamCreated() on the IO thread after the client has
376 // called Stop() but before ShutDownOnIOThread() is processed. In such a 403 // called Stop() but before ShutDownOnIOThread() is processed. In such a
377 // situation |callback_| might point to freed memory. Instead of starting 404 // situation |callback_| might point to freed memory. Instead of starting
378 // |audio_thread_| do nothing and wait for ShutDownOnIOThread() to get called. 405 // |audio_thread_| do nothing and wait for ShutDownOnIOThread() to get called.
379 // 406 //
380 // TODO(scherkus): The real fix is to have sane ownership semantics. The fact 407 // TODO(grunell): AudioRendererSink should be non-refcounted and
381 // that |callback_| (which should own and outlive this object!) can point to 408 // AudioOutputDevice should internally use WeakPtr to handle teardown and
382 // freed memory is a mess. AudioRendererSink should be non-refcounted so that 409 // thread hopping. See http://crbug.com/151051 for details.
383 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and 410 // Note however that switching the IPC to Mojo will remove usage of the IO
384 // delete as they see fit. AudioOutputDevice should internally use WeakPtr 411 // thread, so we'll eliminate thread concurrency issues here then. See
385 // to handle teardown and thread hopping. See http://crbug.com/151051 for 412 // http://crbug.com/606707.
386 // details. 413
387 { 414 {
388 base::AutoLock auto_lock(audio_thread_lock_); 415 base::AutoLock auto_lock(lock_);
389 if (stopping_hack_) 416 if (stopping_hack_)
390 return; 417 return;
391 418
392 DCHECK(audio_thread_.IsStopped()); 419 DCHECK(audio_thread_.IsStopped());
393 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback( 420 audio_thread_callback_.reset(new AudioOutputDevice::AudioThreadCallback(
394 audio_parameters_, handle, length, callback_)); 421 audio_parameters_, handle, length, render_callback_));
395 audio_thread_.Start(audio_callback_.get(), socket_handle, 422 audio_thread_.Start(audio_thread_callback_.get(), socket_handle,
396 "AudioOutputDevice", true); 423 "AudioOutputDevice", true);
397 state_ = PAUSED; 424 state_ = PAUSED;
398 425
399 // We handle the case where Play() and/or Pause() may have been called 426 // We handle the case where Play() and/or Pause() may have been called
400 // multiple times before OnStreamCreated() gets called. 427 // multiple times before OnStreamCreated() gets called.
401 if (play_on_start_) 428 if (play_on_start_)
402 PlayOnIOThread(); 429 PlayOnIOThread();
403 } 430 }
404 } 431 }
405 432
406 void AudioOutputDevice::OnIPCClosed() { 433 void AudioOutputDevice::OnIPCClosed() {
407 DCHECK(task_runner()->BelongsToCurrentThread()); 434 DCHECK(task_runner()->BelongsToCurrentThread());
408 state_ = IPC_CLOSED; 435 state_ = IPC_CLOSED;
409 ipc_.reset(); 436 ipc_.reset();
410 437
411 // Signal to unblock any blocked threads waiting for parameters 438 // Signal to unblock any blocked threads waiting for parameters
412 did_receive_auth_.Signal(); 439 did_receive_auth_.Signal();
413 } 440 }
414 441
415 void AudioOutputDevice::WillDestroyCurrentMessageLoop() { 442 void AudioOutputDevice::WillDestroyCurrentMessageLoop() {
416 LOG(ERROR) << "IO loop going away before the audio device has been stopped"; 443 LOG(ERROR) << "IO loop going away before the audio device has been stopped";
417 ShutDownOnIOThread(); 444 StopOnIOThread();
418 } 445 }
419 446
420 // AudioOutputDevice::AudioThreadCallback 447 // AudioOutputDevice::AudioThreadCallback
421 448
422 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback( 449 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback(
423 const AudioParameters& audio_parameters, 450 const AudioParameters& audio_parameters,
424 base::SharedMemoryHandle memory, 451 base::SharedMemoryHandle memory,
425 int memory_length, 452 int memory_length,
426 AudioRendererSink::RenderCallback* render_callback) 453 AudioRendererSink::RenderCallback* render_callback)
427 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length, 1), 454 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length, 1),
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
471 498
472 // Update the audio-delay measurement, inform about the number of skipped 499 // Update the audio-delay measurement, inform about the number of skipped
473 // frames, and ask client to render audio. Since |output_bus_| is wrapping 500 // frames, and ask client to render audio. Since |output_bus_| is wrapping
474 // the shared memory the Render() call is writing directly into the shared 501 // the shared memory the Render() call is writing directly into the shared
475 // memory. 502 // memory.
476 render_callback_->Render(output_bus_.get(), std::round(frames_delayed), 503 render_callback_->Render(output_bus_.get(), std::round(frames_delayed),
477 frames_skipped); 504 frames_skipped);
478 } 505 }
479 506
480 } // namespace media 507 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/audio_output_device.h ('k') | media/audio/audio_output_device_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698