OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/audio/audio_output_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 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
84 } | 84 } |
85 | 85 |
86 void AudioOutputDevice::Initialize(const AudioParameters& params, | 86 void AudioOutputDevice::Initialize(const AudioParameters& params, |
87 RenderCallback* callback) { | 87 RenderCallback* callback) { |
88 DCHECK(!callback_) << "Calling Initialize() twice?"; | 88 DCHECK(!callback_) << "Calling Initialize() twice?"; |
89 DCHECK(params.IsValid()); | 89 DCHECK(params.IsValid()); |
90 audio_parameters_ = params; | 90 audio_parameters_ = params; |
91 callback_ = callback; | 91 callback_ = callback; |
92 } | 92 } |
93 | 93 |
94 AudioOutputDevice::~AudioOutputDevice() { | 94 AudioOutputDevice::~AudioOutputDevice() {} |
95 // The current design requires that the user calls Stop() before deleting | |
96 // this class. | |
97 DCHECK(audio_thread_.IsStopped()); | |
98 } | |
99 | 95 |
100 void AudioOutputDevice::RequestDeviceAuthorization() { | 96 void AudioOutputDevice::RequestDeviceAuthorization() { |
101 task_runner()->PostTask( | 97 task_runner()->PostTask( |
102 FROM_HERE, | 98 FROM_HERE, |
103 base::Bind(&AudioOutputDevice::RequestDeviceAuthorizationOnIOThread, | 99 base::Bind(&AudioOutputDevice::RequestDeviceAuthorizationOnIOThread, |
104 this)); | 100 this)); |
105 } | 101 } |
106 | 102 |
107 void AudioOutputDevice::Start() { | 103 void AudioOutputDevice::Start() { |
108 DCHECK(callback_) << "Initialize hasn't been called"; | 104 DCHECK(callback_) << "Initialize hasn't been called"; |
109 task_runner()->PostTask(FROM_HERE, | 105 task_runner()->PostTask(FROM_HERE, |
110 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this, | 106 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this, |
111 audio_parameters_)); | 107 audio_parameters_)); |
112 } | 108 } |
113 | 109 |
114 void AudioOutputDevice::Stop() { | 110 void AudioOutputDevice::Stop() { |
115 { | 111 { |
116 base::AutoLock auto_lock(audio_thread_lock_); | 112 base::AutoLock auto_lock(audio_thread_lock_); |
117 audio_thread_.Stop(base::MessageLoop::current()); | 113 audio_thread_.reset(); |
118 stopping_hack_ = true; | 114 stopping_hack_ = true; |
119 } | 115 } |
120 | 116 |
121 task_runner()->PostTask(FROM_HERE, | 117 task_runner()->PostTask(FROM_HERE, |
122 base::Bind(&AudioOutputDevice::ShutDownOnIOThread, this)); | 118 base::Bind(&AudioOutputDevice::ShutDownOnIOThread, this)); |
123 } | 119 } |
124 | 120 |
125 void AudioOutputDevice::Play() { | 121 void AudioOutputDevice::Play() { |
126 task_runner()->PostTask(FROM_HERE, | 122 task_runner()->PostTask(FROM_HERE, |
127 base::Bind(&AudioOutputDevice::PlayOnIOThread, this)); | 123 base::Bind(&AudioOutputDevice::PlayOnIOThread, this)); |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
249 // We can run into an issue where ShutDownOnIOThread is called right after | 245 // 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 | 246 // OnStreamCreated is called in cases where Start/Stop are called before we |
251 // get the OnStreamCreated callback. To handle that corner case, we call | 247 // get the OnStreamCreated callback. To handle that corner case, we call |
252 // Stop(). In most cases, the thread will already be stopped. | 248 // Stop(). In most cases, the thread will already be stopped. |
253 // | 249 // |
254 // Another situation is when the IO thread goes away before Stop() is called | 250 // 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 | 251 // 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. | 252 // and can't rely on the main thread existing either. |
257 base::AutoLock auto_lock_(audio_thread_lock_); | 253 base::AutoLock auto_lock_(audio_thread_lock_); |
258 base::ThreadRestrictions::ScopedAllowIO allow_io; | 254 base::ThreadRestrictions::ScopedAllowIO allow_io; |
259 audio_thread_.Stop(NULL); | 255 audio_thread_.reset(); |
260 audio_callback_.reset(); | 256 audio_callback_.reset(); |
261 stopping_hack_ = false; | 257 stopping_hack_ = false; |
262 } | 258 } |
263 | 259 |
264 void AudioOutputDevice::SetVolumeOnIOThread(double volume) { | 260 void AudioOutputDevice::SetVolumeOnIOThread(double volume) { |
265 DCHECK(task_runner()->BelongsToCurrentThread()); | 261 DCHECK(task_runner()->BelongsToCurrentThread()); |
266 if (state_ >= CREATING_STREAM) | 262 if (state_ >= CREATING_STREAM) |
267 ipc_->SetVolume(volume); | 263 ipc_->SetVolume(volume); |
268 } | 264 } |
269 | 265 |
(...skipping 11 matching lines...) Expand all Loading... |
281 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED: | 277 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED: |
282 break; | 278 break; |
283 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR: | 279 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR: |
284 DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(ERROR)"; | 280 DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(ERROR)"; |
285 // Don't dereference the callback object if the audio thread | 281 // Don't dereference the callback object if the audio thread |
286 // is stopped or stopping. That could mean that the callback | 282 // is stopped or stopping. That could mean that the callback |
287 // object has been deleted. | 283 // object has been deleted. |
288 // TODO(tommi): Add an explicit contract for clearing the callback | 284 // TODO(tommi): Add an explicit contract for clearing the callback |
289 // object. Possibly require calling Initialize again or provide | 285 // object. Possibly require calling Initialize again or provide |
290 // a callback object via Start() and clear it in Stop(). | 286 // a callback object via Start() and clear it in Stop(). |
291 if (!audio_thread_.IsStopped()) | 287 { |
292 callback_->OnRenderError(); | 288 base::AutoLock auto_lock_(audio_thread_lock_); |
| 289 if (audio_thread_) |
| 290 callback_->OnRenderError(); |
| 291 } |
293 break; | 292 break; |
294 default: | 293 default: |
295 NOTREACHED(); | 294 NOTREACHED(); |
296 break; | 295 break; |
297 } | 296 } |
298 } | 297 } |
299 | 298 |
300 void AudioOutputDevice::OnDeviceAuthorized( | 299 void AudioOutputDevice::OnDeviceAuthorized( |
301 OutputDeviceStatus device_status, | 300 OutputDeviceStatus device_status, |
302 const media::AudioParameters& output_params, | 301 const media::AudioParameters& output_params, |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
382 // freed memory is a mess. AudioRendererSink should be non-refcounted so that | 381 // freed memory is a mess. AudioRendererSink should be non-refcounted so that |
383 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and | 382 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and |
384 // delete as they see fit. AudioOutputDevice should internally use WeakPtr | 383 // delete as they see fit. AudioOutputDevice should internally use WeakPtr |
385 // to handle teardown and thread hopping. See http://crbug.com/151051 for | 384 // to handle teardown and thread hopping. See http://crbug.com/151051 for |
386 // details. | 385 // details. |
387 { | 386 { |
388 base::AutoLock auto_lock(audio_thread_lock_); | 387 base::AutoLock auto_lock(audio_thread_lock_); |
389 if (stopping_hack_) | 388 if (stopping_hack_) |
390 return; | 389 return; |
391 | 390 |
392 DCHECK(audio_thread_.IsStopped()); | 391 DCHECK(!audio_thread_); |
| 392 DCHECK(!audio_callback_); |
| 393 |
393 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback( | 394 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback( |
394 audio_parameters_, handle, length, callback_)); | 395 audio_parameters_, handle, length, callback_)); |
395 audio_thread_.Start(audio_callback_.get(), socket_handle, | 396 audio_thread_.reset(new AudioDeviceThread( |
396 "AudioOutputDevice", true); | 397 audio_callback_.get(), socket_handle, "AudioOutputDevice")); |
397 state_ = PAUSED; | 398 state_ = PAUSED; |
398 | 399 |
399 // We handle the case where Play() and/or Pause() may have been called | 400 // We handle the case where Play() and/or Pause() may have been called |
400 // multiple times before OnStreamCreated() gets called. | 401 // multiple times before OnStreamCreated() gets called. |
401 if (play_on_start_) | 402 if (play_on_start_) |
402 PlayOnIOThread(); | 403 PlayOnIOThread(); |
403 } | 404 } |
404 } | 405 } |
405 | 406 |
406 void AudioOutputDevice::OnIPCClosed() { | 407 void AudioOutputDevice::OnIPCClosed() { |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
471 | 472 |
472 // Update the audio-delay measurement, inform about the number of skipped | 473 // Update the audio-delay measurement, inform about the number of skipped |
473 // frames, and ask client to render audio. Since |output_bus_| is wrapping | 474 // 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 | 475 // the shared memory the Render() call is writing directly into the shared |
475 // memory. | 476 // memory. |
476 render_callback_->Render(output_bus_.get(), std::round(frames_delayed), | 477 render_callback_->Render(output_bus_.get(), std::round(frames_delayed), |
477 frames_skipped); | 478 frames_skipped); |
478 } | 479 } |
479 | 480 |
480 } // namespace media | 481 } // namespace media |
OLD | NEW |