| 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 28 matching lines...) Expand all Loading... |
| 39 void MapSharedMemory() override; | 39 void MapSharedMemory() override; |
| 40 | 40 |
| 41 // Called whenever we receive notifications about pending data. | 41 // Called whenever we receive notifications about pending data. |
| 42 void Process(uint32_t pending_data) override; | 42 void Process(uint32_t pending_data) override; |
| 43 | 43 |
| 44 // Returns whether the current thread is the audio device thread or not. | 44 // Returns whether the current thread is the audio device thread or not. |
| 45 // Will always return true if DCHECKs are not enabled. | 45 // Will always return true if DCHECKs are not enabled. |
| 46 bool CurrentThreadIsAudioDeviceThread(); | 46 bool CurrentThreadIsAudioDeviceThread(); |
| 47 | 47 |
| 48 private: | 48 private: |
| 49 const int bytes_per_frame_; |
| 49 AudioRendererSink::RenderCallback* render_callback_; | 50 AudioRendererSink::RenderCallback* render_callback_; |
| 50 std::unique_ptr<AudioBus> output_bus_; | 51 std::unique_ptr<AudioBus> output_bus_; |
| 51 uint64_t callback_num_; | 52 uint64_t callback_num_; |
| 52 | 53 |
| 53 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); | 54 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); |
| 54 }; | 55 }; |
| 55 | 56 |
| 56 AudioOutputDevice::AudioOutputDevice( | 57 AudioOutputDevice::AudioOutputDevice( |
| 57 std::unique_ptr<AudioOutputIPC> ipc, | 58 std::unique_ptr<AudioOutputIPC> ipc, |
| 58 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, | 59 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner, |
| (...skipping 29 matching lines...) Expand all Loading... |
| 88 } | 89 } |
| 89 | 90 |
| 90 void AudioOutputDevice::Initialize(const AudioParameters& params, | 91 void AudioOutputDevice::Initialize(const AudioParameters& params, |
| 91 RenderCallback* callback) { | 92 RenderCallback* callback) { |
| 92 DCHECK(!callback_) << "Calling Initialize() twice?"; | 93 DCHECK(!callback_) << "Calling Initialize() twice?"; |
| 93 DCHECK(params.IsValid()); | 94 DCHECK(params.IsValid()); |
| 94 audio_parameters_ = params; | 95 audio_parameters_ = params; |
| 95 callback_ = callback; | 96 callback_ = callback; |
| 96 } | 97 } |
| 97 | 98 |
| 98 AudioOutputDevice::~AudioOutputDevice() { | 99 AudioOutputDevice::~AudioOutputDevice() {} |
| 99 // The current design requires that the user calls Stop() before deleting | |
| 100 // this class. | |
| 101 DCHECK(audio_thread_.IsStopped()); | |
| 102 } | |
| 103 | 100 |
| 104 void AudioOutputDevice::RequestDeviceAuthorization() { | 101 void AudioOutputDevice::RequestDeviceAuthorization() { |
| 105 task_runner()->PostTask( | 102 task_runner()->PostTask( |
| 106 FROM_HERE, | 103 FROM_HERE, |
| 107 base::Bind(&AudioOutputDevice::RequestDeviceAuthorizationOnIOThread, | 104 base::Bind(&AudioOutputDevice::RequestDeviceAuthorizationOnIOThread, |
| 108 this)); | 105 this)); |
| 109 } | 106 } |
| 110 | 107 |
| 111 void AudioOutputDevice::Start() { | 108 void AudioOutputDevice::Start() { |
| 112 DCHECK(callback_) << "Initialize hasn't been called"; | 109 DCHECK(callback_) << "Initialize hasn't been called"; |
| 113 task_runner()->PostTask(FROM_HERE, | 110 task_runner()->PostTask(FROM_HERE, |
| 114 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this, | 111 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this, |
| 115 audio_parameters_)); | 112 audio_parameters_)); |
| 116 } | 113 } |
| 117 | 114 |
| 118 void AudioOutputDevice::Stop() { | 115 void AudioOutputDevice::Stop() { |
| 119 { | 116 { |
| 120 base::AutoLock auto_lock(audio_thread_lock_); | 117 base::AutoLock auto_lock(audio_thread_lock_); |
| 121 audio_thread_.Stop(base::MessageLoop::current()); | 118 audio_thread_.reset(); |
| 122 stopping_hack_ = true; | 119 stopping_hack_ = true; |
| 123 } | 120 } |
| 124 | 121 |
| 125 task_runner()->PostTask(FROM_HERE, | 122 task_runner()->PostTask(FROM_HERE, |
| 126 base::Bind(&AudioOutputDevice::ShutDownOnIOThread, this)); | 123 base::Bind(&AudioOutputDevice::ShutDownOnIOThread, this)); |
| 127 } | 124 } |
| 128 | 125 |
| 129 void AudioOutputDevice::Play() { | 126 void AudioOutputDevice::Play() { |
| 130 task_runner()->PostTask(FROM_HERE, | 127 task_runner()->PostTask(FROM_HERE, |
| 131 base::Bind(&AudioOutputDevice::PlayOnIOThread, this)); | 128 base::Bind(&AudioOutputDevice::PlayOnIOThread, this)); |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 // We can run into an issue where ShutDownOnIOThread is called right after | 257 // We can run into an issue where ShutDownOnIOThread is called right after |
| 261 // OnStreamCreated is called in cases where Start/Stop are called before we | 258 // OnStreamCreated is called in cases where Start/Stop are called before we |
| 262 // get the OnStreamCreated callback. To handle that corner case, we call | 259 // get the OnStreamCreated callback. To handle that corner case, we call |
| 263 // Stop(). In most cases, the thread will already be stopped. | 260 // Stop(). In most cases, the thread will already be stopped. |
| 264 // | 261 // |
| 265 // Another situation is when the IO thread goes away before Stop() is called | 262 // Another situation is when the IO thread goes away before Stop() is called |
| 266 // in which case, we cannot use the message loop to close the thread handle | 263 // in which case, we cannot use the message loop to close the thread handle |
| 267 // and can't rely on the main thread existing either. | 264 // and can't rely on the main thread existing either. |
| 268 base::AutoLock auto_lock_(audio_thread_lock_); | 265 base::AutoLock auto_lock_(audio_thread_lock_); |
| 269 base::ThreadRestrictions::ScopedAllowIO allow_io; | 266 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 270 audio_thread_.Stop(NULL); | 267 audio_thread_.reset(); |
| 271 audio_callback_.reset(); | 268 audio_callback_.reset(); |
| 272 stopping_hack_ = false; | 269 stopping_hack_ = false; |
| 273 } | 270 } |
| 274 | 271 |
| 275 void AudioOutputDevice::SetVolumeOnIOThread(double volume) { | 272 void AudioOutputDevice::SetVolumeOnIOThread(double volume) { |
| 276 DCHECK(task_runner()->BelongsToCurrentThread()); | 273 DCHECK(task_runner()->BelongsToCurrentThread()); |
| 277 if (state_ >= CREATING_STREAM) | 274 if (state_ >= CREATING_STREAM) |
| 278 ipc_->SetVolume(volume); | 275 ipc_->SetVolume(volume); |
| 279 } | 276 } |
| 280 | 277 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 292 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED: | 289 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_PAUSED: |
| 293 break; | 290 break; |
| 294 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR: | 291 case AUDIO_OUTPUT_IPC_DELEGATE_STATE_ERROR: |
| 295 DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(ERROR)"; | 292 DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(ERROR)"; |
| 296 // Don't dereference the callback object if the audio thread | 293 // Don't dereference the callback object if the audio thread |
| 297 // is stopped or stopping. That could mean that the callback | 294 // is stopped or stopping. That could mean that the callback |
| 298 // object has been deleted. | 295 // object has been deleted. |
| 299 // TODO(tommi): Add an explicit contract for clearing the callback | 296 // TODO(tommi): Add an explicit contract for clearing the callback |
| 300 // object. Possibly require calling Initialize again or provide | 297 // object. Possibly require calling Initialize again or provide |
| 301 // a callback object via Start() and clear it in Stop(). | 298 // a callback object via Start() and clear it in Stop(). |
| 302 if (!audio_thread_.IsStopped()) | 299 { |
| 303 callback_->OnRenderError(); | 300 base::AutoLock auto_lock_(audio_thread_lock_); |
| 301 if (audio_thread_) |
| 302 callback_->OnRenderError(); |
| 303 } |
| 304 break; | 304 break; |
| 305 default: | 305 default: |
| 306 NOTREACHED(); | 306 NOTREACHED(); |
| 307 break; | 307 break; |
| 308 } | 308 } |
| 309 } | 309 } |
| 310 | 310 |
| 311 void AudioOutputDevice::OnDeviceAuthorized( | 311 void AudioOutputDevice::OnDeviceAuthorized( |
| 312 OutputDeviceStatus device_status, | 312 OutputDeviceStatus device_status, |
| 313 const media::AudioParameters& output_params, | 313 const media::AudioParameters& output_params, |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 393 // freed memory is a mess. AudioRendererSink should be non-refcounted so that | 393 // freed memory is a mess. AudioRendererSink should be non-refcounted so that |
| 394 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and | 394 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and |
| 395 // delete as they see fit. AudioOutputDevice should internally use WeakPtr | 395 // delete as they see fit. AudioOutputDevice should internally use WeakPtr |
| 396 // to handle teardown and thread hopping. See http://crbug.com/151051 for | 396 // to handle teardown and thread hopping. See http://crbug.com/151051 for |
| 397 // details. | 397 // details. |
| 398 { | 398 { |
| 399 base::AutoLock auto_lock(audio_thread_lock_); | 399 base::AutoLock auto_lock(audio_thread_lock_); |
| 400 if (stopping_hack_) | 400 if (stopping_hack_) |
| 401 return; | 401 return; |
| 402 | 402 |
| 403 DCHECK(audio_thread_.IsStopped()); | 403 DCHECK(!audio_thread_); |
| 404 DCHECK(!audio_callback_); |
| 405 |
| 404 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback( | 406 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback( |
| 405 audio_parameters_, handle, length, callback_)); | 407 audio_parameters_, handle, length, callback_)); |
| 406 audio_thread_.Start(audio_callback_.get(), socket_handle, | 408 audio_thread_.reset(new AudioDeviceThread( |
| 407 "AudioOutputDevice", true); | 409 audio_callback_.get(), socket_handle, "AudioOutputDevice")); |
| 408 state_ = PAUSED; | 410 state_ = PAUSED; |
| 409 | 411 |
| 410 // We handle the case where Play() and/or Pause() may have been called | 412 // We handle the case where Play() and/or Pause() may have been called |
| 411 // multiple times before OnStreamCreated() gets called. | 413 // multiple times before OnStreamCreated() gets called. |
| 412 if (play_on_start_) | 414 if (play_on_start_) |
| 413 PlayOnIOThread(); | 415 PlayOnIOThread(); |
| 414 } | 416 } |
| 415 } | 417 } |
| 416 | 418 |
| 417 void AudioOutputDevice::OnIPCClosed() { | 419 void AudioOutputDevice::OnIPCClosed() { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 429 } | 431 } |
| 430 | 432 |
| 431 // AudioOutputDevice::AudioThreadCallback | 433 // AudioOutputDevice::AudioThreadCallback |
| 432 | 434 |
| 433 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback( | 435 AudioOutputDevice::AudioThreadCallback::AudioThreadCallback( |
| 434 const AudioParameters& audio_parameters, | 436 const AudioParameters& audio_parameters, |
| 435 base::SharedMemoryHandle memory, | 437 base::SharedMemoryHandle memory, |
| 436 int memory_length, | 438 int memory_length, |
| 437 AudioRendererSink::RenderCallback* render_callback) | 439 AudioRendererSink::RenderCallback* render_callback) |
| 438 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length, 1), | 440 : AudioDeviceThread::Callback(audio_parameters, memory, memory_length, 1), |
| 441 bytes_per_frame_(audio_parameters.GetBytesPerFrame()), |
| 439 render_callback_(render_callback), | 442 render_callback_(render_callback), |
| 440 callback_num_(0) {} | 443 callback_num_(0) {} |
| 441 | 444 |
| 442 AudioOutputDevice::AudioThreadCallback::~AudioThreadCallback() { | 445 AudioOutputDevice::AudioThreadCallback::~AudioThreadCallback() { |
| 443 } | 446 } |
| 444 | 447 |
| 445 void AudioOutputDevice::AudioThreadCallback::MapSharedMemory() { | 448 void AudioOutputDevice::AudioThreadCallback::MapSharedMemory() { |
| 446 CHECK_EQ(total_segments_, 1); | 449 CHECK_EQ(total_segments_, 1); |
| 447 CHECK(shared_memory_.Map(memory_length_)); | 450 CHECK(shared_memory_.Map(memory_length_)); |
| 448 DCHECK_EQ(static_cast<size_t>(memory_length_), | 451 DCHECK_EQ(static_cast<size_t>(memory_length_), |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 487 render_callback_->Render(output_bus_.get(), std::round(frames_delayed), | 490 render_callback_->Render(output_bus_.get(), std::round(frames_delayed), |
| 488 frames_skipped); | 491 frames_skipped); |
| 489 } | 492 } |
| 490 | 493 |
| 491 bool AudioOutputDevice::AudioThreadCallback:: | 494 bool AudioOutputDevice::AudioThreadCallback:: |
| 492 CurrentThreadIsAudioDeviceThread() { | 495 CurrentThreadIsAudioDeviceThread() { |
| 493 return thread_checker_.CalledOnValidThread(); | 496 return thread_checker_.CalledOnValidThread(); |
| 494 } | 497 } |
| 495 | 498 |
| 496 } // namespace media | 499 } // namespace media |
| OLD | NEW |