| 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 |