audio_output_device.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// found in the LICENSE file. 4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "media/audio/audio_output_device.h" 6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/basictypes.h" 8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/debug/trace_event.h" 9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/message_loop.h" 10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/threading/thread_restrictions.h" 11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/time/time.h" 12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "media/audio/audio_output_controller.h" 13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "media/audio/audio_util.h" 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "media/audio/shared_memory_util.h" 155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "media/base/limits.h" 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace media { 18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Takes care of invoking the render callback on the audio thread. 20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// An instance of this class is created for each capture stream in 21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// OnStreamCreated(). 22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class AudioOutputDevice::AudioThreadCallback 23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : public AudioDeviceThread::Callback { 24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public: 25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) AudioThreadCallback(const AudioParameters& audio_parameters, 26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) base::SharedMemoryHandle memory, 27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int memory_length, 28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) AudioRendererSink::RenderCallback* render_callback); 29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual ~AudioThreadCallback(); 30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void MapSharedMemory() OVERRIDE; 32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Called whenever we receive notifications about pending data. 34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) virtual void Process(int pending_data) OVERRIDE; 35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private: 37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) AudioRendererSink::RenderCallback* render_callback_; 38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_ptr<AudioBus> input_bus_; 39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_ptr<AudioBus> output_bus_; 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); 41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}; 42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)AudioOutputDevice::AudioOutputDevice( 44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_ptr<AudioOutputIPC> ipc, 45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) const scoped_refptr<base::MessageLoopProxy>& io_loop) 46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) : ScopedLoopObserver(io_loop), 47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) callback_(NULL), 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ipc_(ipc.Pass()), 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) state_(IDLE), 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) play_on_start_(true), 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) session_id_(-1), 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) stopping_hack_(false) { 535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CHECK(ipc_); 545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // The correctness of the code depends on the relative values assigned in the 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // State enum. 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) COMPILE_ASSERT(IPC_CLOSED < IDLE, invalid_enum_value_assignment_0); 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) COMPILE_ASSERT(IDLE < CREATING_STREAM, invalid_enum_value_assignment_1); 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) COMPILE_ASSERT(CREATING_STREAM < PAUSED, invalid_enum_value_assignment_2); 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) COMPILE_ASSERT(PAUSED < PLAYING, invalid_enum_value_assignment_3); 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AudioOutputDevice::InitializeUnifiedStream(const AudioParameters& params, 645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RenderCallback* callback, 655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int session_id) { 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(!callback_) << "Calling InitializeUnifiedStream() twice?"; 67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) DCHECK(params.IsValid()); 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) audio_parameters_ = params; 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) callback_ = callback; 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) session_id_ = session_id; 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)} 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AudioOutputDevice::Initialize(const AudioParameters& params, 74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) RenderCallback* callback) { 75 InitializeUnifiedStream(params, callback, 0); 76} 77 78AudioOutputDevice::~AudioOutputDevice() { 79 // The current design requires that the user calls Stop() before deleting 80 // this class. 81 DCHECK(audio_thread_.IsStopped()); 82} 83 84void AudioOutputDevice::Start() { 85 DCHECK(callback_) << "Initialize hasn't been called"; 86 message_loop()->PostTask(FROM_HERE, 87 base::Bind(&AudioOutputDevice::CreateStreamOnIOThread, this, 88 audio_parameters_)); 89} 90 91void AudioOutputDevice::Stop() { 92 { 93 base::AutoLock auto_lock(audio_thread_lock_); 94 audio_thread_.Stop(base::MessageLoop::current()); 95 stopping_hack_ = true; 96 } 97 98 message_loop()->PostTask(FROM_HERE, 99 base::Bind(&AudioOutputDevice::ShutDownOnIOThread, this)); 100} 101 102void AudioOutputDevice::Play() { 103 message_loop()->PostTask(FROM_HERE, 104 base::Bind(&AudioOutputDevice::PlayOnIOThread, this)); 105} 106 107void AudioOutputDevice::Pause() { 108 message_loop()->PostTask(FROM_HERE, 109 base::Bind(&AudioOutputDevice::PauseOnIOThread, this)); 110} 111 112bool AudioOutputDevice::SetVolume(double volume) { 113 if (volume < 0 || volume > 1.0) 114 return false; 115 116 if (!message_loop()->PostTask(FROM_HERE, 117 base::Bind(&AudioOutputDevice::SetVolumeOnIOThread, this, volume))) { 118 return false; 119 } 120 121 return true; 122} 123 124void AudioOutputDevice::CreateStreamOnIOThread(const AudioParameters& params) { 125 DCHECK(message_loop()->BelongsToCurrentThread()); 126 if (state_ == IDLE) { 127 state_ = CREATING_STREAM; 128 ipc_->CreateStream(this, params, session_id_); 129 } 130} 131 132void AudioOutputDevice::PlayOnIOThread() { 133 DCHECK(message_loop()->BelongsToCurrentThread()); 134 if (state_ == PAUSED) { 135 ipc_->PlayStream(); 136 state_ = PLAYING; 137 play_on_start_ = false; 138 } else { 139 play_on_start_ = true; 140 } 141} 142 143void AudioOutputDevice::PauseOnIOThread() { 144 DCHECK(message_loop()->BelongsToCurrentThread()); 145 if (state_ == PLAYING) { 146 ipc_->PauseStream(); 147 state_ = PAUSED; 148 } 149 play_on_start_ = false; 150} 151 152void AudioOutputDevice::ShutDownOnIOThread() { 153 DCHECK(message_loop()->BelongsToCurrentThread()); 154 155 // Close the stream, if we haven't already. 156 if (state_ >= CREATING_STREAM) { 157 ipc_->CloseStream(); 158 state_ = IDLE; 159 } 160 161 // We can run into an issue where ShutDownOnIOThread is called right after 162 // OnStreamCreated is called in cases where Start/Stop are called before we 163 // get the OnStreamCreated callback. To handle that corner case, we call 164 // Stop(). In most cases, the thread will already be stopped. 165 // 166 // Another situation is when the IO thread goes away before Stop() is called 167 // in which case, we cannot use the message loop to close the thread handle 168 // and can't rely on the main thread existing either. 169 base::AutoLock auto_lock_(audio_thread_lock_); 170 base::ThreadRestrictions::ScopedAllowIO allow_io; 171 audio_thread_.Stop(NULL); 172 audio_callback_.reset(); 173 stopping_hack_ = false; 174} 175 176void AudioOutputDevice::SetVolumeOnIOThread(double volume) { 177 DCHECK(message_loop()->BelongsToCurrentThread()); 178 if (state_ >= CREATING_STREAM) 179 ipc_->SetVolume(volume); 180} 181 182void AudioOutputDevice::OnStateChanged(AudioOutputIPCDelegate::State state) { 183 DCHECK(message_loop()->BelongsToCurrentThread()); 184 185 // Do nothing if the stream has been closed. 186 if (state_ < CREATING_STREAM) 187 return; 188 189 // TODO(miu): Clean-up inconsistent and incomplete handling here. 190 // http://crbug.com/180640 191 switch (state) { 192 case AudioOutputIPCDelegate::kPlaying: 193 case AudioOutputIPCDelegate::kPaused: 194 break; 195 case AudioOutputIPCDelegate::kError: 196 DLOG(WARNING) << "AudioOutputDevice::OnStateChanged(kError)"; 197 // Don't dereference the callback object if the audio thread 198 // is stopped or stopping. That could mean that the callback 199 // object has been deleted. 200 // TODO(tommi): Add an explicit contract for clearing the callback 201 // object. Possibly require calling Initialize again or provide 202 // a callback object via Start() and clear it in Stop(). 203 if (!audio_thread_.IsStopped()) 204 callback_->OnRenderError(); 205 break; 206 default: 207 NOTREACHED(); 208 break; 209 } 210} 211 212void AudioOutputDevice::OnStreamCreated( 213 base::SharedMemoryHandle handle, 214 base::SyncSocket::Handle socket_handle, 215 int length) { 216 DCHECK(message_loop()->BelongsToCurrentThread()); 217#if defined(OS_WIN) 218 DCHECK(handle); 219 DCHECK(socket_handle); 220#else 221 DCHECK_GE(handle.fd, 0); 222 DCHECK_GE(socket_handle, 0); 223#endif 224 DCHECK_GT(length, 0); 225 226 if (state_ != CREATING_STREAM) 227 return; 228 229 // We can receive OnStreamCreated() on the IO thread after the client has 230 // called Stop() but before ShutDownOnIOThread() is processed. In such a 231 // situation |callback_| might point to freed memory. Instead of starting 232 // |audio_thread_| do nothing and wait for ShutDownOnIOThread() to get called. 233 // 234 // TODO(scherkus): The real fix is to have sane ownership semantics. The fact 235 // that |callback_| (which should own and outlive this object!) can point to 236 // freed memory is a mess. AudioRendererSink should be non-refcounted so that 237 // owners (WebRtcAudioDeviceImpl, AudioRendererImpl, etc...) can Stop() and 238 // delete as they see fit. AudioOutputDevice should internally use WeakPtr 239 // to handle teardown and thread hopping. See http://crbug.com/151051 for 240 // details. 241 base::AutoLock auto_lock(audio_thread_lock_); 242 if (stopping_hack_) 243 return; 244 245 DCHECK(audio_thread_.IsStopped()); 246 audio_callback_.reset(new AudioOutputDevice::AudioThreadCallback( 247 audio_parameters_, handle, length, callback_)); 248 audio_thread_.Start(audio_callback_.get(), socket_handle, 249 "AudioOutputDevice"); 250 state_ = PAUSED; 251 252 // We handle the case where Play() and/or Pause() may have been called 253 // multiple times before OnStreamCreated() gets called. 254 if (play_on_start_) 255 PlayOnIOThread(); 256} 257 258void AudioOutputDevice::OnIPCClosed() { 259 DCHECK(message_loop()->BelongsToCurrentThread()); 260 state_ = IPC_CLOSED; 261 ipc_.reset(); 262} 263 264void AudioOutputDevice::WillDestroyCurrentMessageLoop() { 265 LOG(ERROR) << "IO loop going away before the audio device has been stopped"; 266 ShutDownOnIOThread(); 267} 268 269// AudioOutputDevice::AudioThreadCallback 270 271AudioOutputDevice::AudioThreadCallback::AudioThreadCallback( 272 const AudioParameters& audio_parameters, 273 base::SharedMemoryHandle memory, 274 int memory_length, 275 AudioRendererSink::RenderCallback* render_callback) 276 : AudioDeviceThread::Callback(audio_parameters, 277 memory, 278 memory_length, 279 1), 280 render_callback_(render_callback) { 281} 282 283AudioOutputDevice::AudioThreadCallback::~AudioThreadCallback() { 284} 285 286void AudioOutputDevice::AudioThreadCallback::MapSharedMemory() { 287 CHECK_EQ(total_segments_, 1); 288 CHECK(shared_memory_.Map(TotalSharedMemorySizeInBytes(memory_length_))); 289 290 // Calculate output and input memory size. 291 int output_memory_size = AudioBus::CalculateMemorySize(audio_parameters_); 292 int input_channels = audio_parameters_.input_channels(); 293 int frames = audio_parameters_.frames_per_buffer(); 294 int input_memory_size = 295 AudioBus::CalculateMemorySize(input_channels, frames); 296 297 int io_size = output_memory_size + input_memory_size; 298 299 DCHECK_EQ(memory_length_, io_size); 300 301 output_bus_ = 302 AudioBus::WrapMemory(audio_parameters_, shared_memory_.memory()); 303 304 if (input_channels > 0) { 305 // The input data is after the output data. 306 char* input_data = 307 static_cast<char*>(shared_memory_.memory()) + output_memory_size; 308 input_bus_ = 309 AudioBus::WrapMemory(input_channels, frames, input_data); 310 } 311} 312 313// Called whenever we receive notifications about pending data. 314void AudioOutputDevice::AudioThreadCallback::Process(int pending_data) { 315 if (pending_data == kPauseMark) { 316 memset(shared_memory_.memory(), 0, memory_length_); 317 SetActualDataSizeInBytes(&shared_memory_, memory_length_, 0); 318 return; 319 } 320 321 // Convert the number of pending bytes in the render buffer 322 // into milliseconds. 323 int audio_delay_milliseconds = pending_data / bytes_per_ms_; 324 325 TRACE_EVENT0("audio", "AudioOutputDevice::FireRenderCallback"); 326 327 // Update the audio-delay measurement then ask client to render audio. Since 328 // |output_bus_| is wrapping the shared memory the Render() call is writing 329 // directly into the shared memory. 330 int input_channels = audio_parameters_.input_channels(); 331 size_t num_frames = audio_parameters_.frames_per_buffer(); 332 333 if (input_bus_.get() && input_channels > 0) { 334 render_callback_->RenderIO(input_bus_.get(), 335 output_bus_.get(), 336 audio_delay_milliseconds); 337 } else { 338 num_frames = render_callback_->Render(output_bus_.get(), 339 audio_delay_milliseconds); 340 } 341 342 // Let the host know we are done. 343 // TODO(dalecurtis): Technically this is not always correct. Due to channel 344 // padding for alignment, there may be more data available than this. We're 345 // relying on AudioSyncReader::Read() to parse this with that in mind. Rename 346 // these methods to Set/GetActualFrameCount(). 347 SetActualDataSizeInBytes( 348 &shared_memory_, memory_length_, 349 num_frames * sizeof(*output_bus_->channel(0)) * output_bus_->channels()); 350} 351 352} // namespace media. 353