waveout_output_win.cc revision 868fa2fe829687343ffae624259930155e16dbd8
15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// found in the LICENSE file. 45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "media/audio/win/waveout_output_win.h" 65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <windows.h> 85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <mmsystem.h> 95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#pragma comment(lib, "winmm.lib") 105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/atomicops.h" 125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/basictypes.h" 135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/debug/trace_event.h" 145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/logging.h" 155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "media/audio/audio_io.h" 165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "media/audio/win/audio_manager_win.h" 175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace media { 195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Some general thoughts about the waveOut API which is badly documented : 215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// - We use CALLBACK_EVENT mode in which XP signals events such as buffer 225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// releases. 235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// - We use RegisterWaitForSingleObject() so one of threads in thread pool 245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// automatically calls our callback that feeds more data to Windows. 255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// - Windows does not provide a way to query if the device is playing or paused 265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// thus it forces you to maintain state, which naturally is not exactly 275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// synchronized to the actual device state. 285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Sixty four MB is the maximum buffer size per AudioOutputStream. 305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static const uint32 kMaxOpenBufferSize = 1024 * 1024 * 64; 315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// See Also 335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// http://www.thx.com/consumer/home-entertainment/home-theater/surround-sound-speaker-set-up/ 345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// http://en.wikipedia.org/wiki/Surround_sound 355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static const int kMaxChannelsToMask = 8; 375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static const unsigned int kChannelsToMask[kMaxChannelsToMask + 1] = { 385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 0, 395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // 1 = Mono 405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) SPEAKER_FRONT_CENTER, 415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // 2 = Stereo 425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT, 435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // 3 = Stereo + Center 445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER, 455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // 4 = Quad 465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | 475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT, 485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // 5 = 5.0 491675a649fd7a8b3cb80ffddae2dc181f122353c5Ben Murdoch SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | 501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT, 511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // 6 = 5.1 521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | 531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | 545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT, 555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // 7 = 6.1 561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | 571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | 581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | 591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci SPEAKER_BACK_CENTER, 601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci // 8 = 7.1 615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | 625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | 635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | 645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT 655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // TODO(fbarchard): Add additional masks for 7.2 and beyond. 665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}; 675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)inline size_t PCMWaveOutAudioOutputStream::BufferSize() const { 695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) // Round size of buffer up to the nearest 16 bytes. 705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return (sizeof(WAVEHDR) + buffer_size_ + 15u) & static_cast<size_t>(~15); 715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)} 725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)inline WAVEHDR* PCMWaveOutAudioOutputStream::GetBuffer(int n) const { 74 DCHECK_GE(n, 0); 75 DCHECK_LT(n, num_buffers_); 76 return reinterpret_cast<WAVEHDR*>(&buffers_[n * BufferSize()]); 77} 78 79PCMWaveOutAudioOutputStream::PCMWaveOutAudioOutputStream( 80 AudioManagerWin* manager, const AudioParameters& params, int num_buffers, 81 UINT device_id) 82 : state_(PCMA_BRAND_NEW), 83 manager_(manager), 84 device_id_(device_id), 85 waveout_(NULL), 86 callback_(NULL), 87 num_buffers_(num_buffers), 88 buffer_size_(params.GetBytesPerBuffer()), 89 volume_(1), 90 channels_(params.channels()), 91 pending_bytes_(0), 92 waiting_handle_(NULL), 93 audio_bus_(AudioBus::Create(params)) { 94 format_.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; 95 format_.Format.nChannels = params.channels(); 96 format_.Format.nSamplesPerSec = params.sample_rate(); 97 format_.Format.wBitsPerSample = params.bits_per_sample(); 98 format_.Format.cbSize = sizeof(format_) - sizeof(WAVEFORMATEX); 99 // The next are computed from above. 100 format_.Format.nBlockAlign = (format_.Format.nChannels * 101 format_.Format.wBitsPerSample) / 8; 102 format_.Format.nAvgBytesPerSec = format_.Format.nBlockAlign * 103 format_.Format.nSamplesPerSec; 104 if (params.channels() > kMaxChannelsToMask) { 105 format_.dwChannelMask = kChannelsToMask[kMaxChannelsToMask]; 106 } else { 107 format_.dwChannelMask = kChannelsToMask[params.channels()]; 108 } 109 format_.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; 110 format_.Samples.wValidBitsPerSample = params.bits_per_sample(); 111} 112 113PCMWaveOutAudioOutputStream::~PCMWaveOutAudioOutputStream() { 114 DCHECK(NULL == waveout_); 115} 116 117bool PCMWaveOutAudioOutputStream::Open() { 118 if (state_ != PCMA_BRAND_NEW) 119 return false; 120 if (BufferSize() * num_buffers_ > kMaxOpenBufferSize) 121 return false; 122 if (num_buffers_ < 2 || num_buffers_ > 5) 123 return false; 124 125 // Create buffer event. 126 buffer_event_.Set(::CreateEvent(NULL, // Security attributes. 127 FALSE, // It will auto-reset. 128 FALSE, // Initial state. 129 NULL)); // No name. 130 if (!buffer_event_.Get()) 131 return false; 132 133 // Open the device. 134 // We'll be getting buffer_event_ events when it's time to refill the buffer. 135 MMRESULT result = ::waveOutOpen( 136 &waveout_, 137 device_id_, 138 reinterpret_cast<LPCWAVEFORMATEX>(&format_), 139 reinterpret_cast<DWORD_PTR>(buffer_event_.Get()), 140 NULL, 141 CALLBACK_EVENT); 142 if (result != MMSYSERR_NOERROR) 143 return false; 144 145 SetupBuffers(); 146 state_ = PCMA_READY; 147 return true; 148} 149 150void PCMWaveOutAudioOutputStream::SetupBuffers() { 151 buffers_.reset(new char[BufferSize() * num_buffers_]); 152 for (int ix = 0; ix != num_buffers_; ++ix) { 153 WAVEHDR* buffer = GetBuffer(ix); 154 buffer->lpData = reinterpret_cast<char*>(buffer) + sizeof(WAVEHDR); 155 buffer->dwBufferLength = buffer_size_; 156 buffer->dwBytesRecorded = 0; 157 buffer->dwFlags = WHDR_DONE; 158 buffer->dwLoops = 0; 159 // Tell windows sound drivers about our buffers. Not documented what 160 // this does but we can guess that causes the OS to keep a reference to 161 // the memory pages so the driver can use them without worries. 162 ::waveOutPrepareHeader(waveout_, buffer, sizeof(WAVEHDR)); 163 } 164} 165 166void PCMWaveOutAudioOutputStream::FreeBuffers() { 167 for (int ix = 0; ix != num_buffers_; ++ix) { 168 ::waveOutUnprepareHeader(waveout_, GetBuffer(ix), sizeof(WAVEHDR)); 169 } 170 buffers_.reset(); 171} 172 173// Initially we ask the source to fill up all audio buffers. If we don't do 174// this then we would always get the driver callback when it is about to run 175// samples and that would leave too little time to react. 176void PCMWaveOutAudioOutputStream::Start(AudioSourceCallback* callback) { 177 if (state_ != PCMA_READY) 178 return; 179 callback_ = callback; 180 181 // Reset buffer event, it can be left in the arbitrary state if we 182 // previously stopped the stream. Can happen because we are stopping 183 // callbacks before stopping playback itself. 184 if (!::ResetEvent(buffer_event_.Get())) { 185 HandleError(MMSYSERR_ERROR); 186 return; 187 } 188 189 // Start watching for buffer events. 190 if (!::RegisterWaitForSingleObject(&waiting_handle_, 191 buffer_event_.Get(), 192 &BufferCallback, 193 this, 194 INFINITE, 195 WT_EXECUTEDEFAULT)) { 196 HandleError(MMSYSERR_ERROR); 197 waiting_handle_ = NULL; 198 return; 199 } 200 201 state_ = PCMA_PLAYING; 202 203 // Queue the buffers. 204 pending_bytes_ = 0; 205 for (int ix = 0; ix != num_buffers_; ++ix) { 206 WAVEHDR* buffer = GetBuffer(ix); 207 QueueNextPacket(buffer); // Read more data. 208 pending_bytes_ += buffer->dwBufferLength; 209 } 210 211 // From now on |pending_bytes_| would be accessed by callback thread. 212 // Most likely waveOutPause() or waveOutRestart() has its own memory barrier, 213 // but issuing our own is safer. 214 base::subtle::MemoryBarrier(); 215 216 MMRESULT result = ::waveOutPause(waveout_); 217 if (result != MMSYSERR_NOERROR) { 218 HandleError(result); 219 return; 220 } 221 222 // Send the buffers to the audio driver. Note that the device is paused 223 // so we avoid entering the callback method while still here. 224 for (int ix = 0; ix != num_buffers_; ++ix) { 225 result = ::waveOutWrite(waveout_, GetBuffer(ix), sizeof(WAVEHDR)); 226 if (result != MMSYSERR_NOERROR) { 227 HandleError(result); 228 break; 229 } 230 } 231 result = ::waveOutRestart(waveout_); 232 if (result != MMSYSERR_NOERROR) { 233 HandleError(result); 234 return; 235 } 236} 237 238// Stopping is tricky if we want it be fast. 239// For now just do it synchronously and avoid all the complexities. 240// TODO(enal): if we want faster Stop() we can create singleton that keeps track 241// of all currently playing streams. Then you don't have to wait 242// till all callbacks are completed. Of course access to singleton 243// should be under its own lock, and checking the liveness and 244// acquiring the lock on stream should be done atomically. 245void PCMWaveOutAudioOutputStream::Stop() { 246 if (state_ != PCMA_PLAYING) 247 return; 248 state_ = PCMA_STOPPING; 249 base::subtle::MemoryBarrier(); 250 251 // Stop watching for buffer event, wait till all the callbacks are complete. 252 // Should be done before ::waveOutReset() call to avoid race condition when 253 // callback that is currently active and already checked that stream is still 254 // being played calls ::waveOutWrite() after ::waveOutReset() returns, later 255 // causing ::waveOutClose() to fail with WAVERR_STILLPLAYING. 256 // TODO(enal): that delays actual stopping of playback. Alternative can be 257 // to call ::waveOutReset() twice, once before 258 // ::UnregisterWaitEx() and once after. 259 if (waiting_handle_) { 260 if (!::UnregisterWaitEx(waiting_handle_, INVALID_HANDLE_VALUE)) { 261 state_ = PCMA_PLAYING; 262 HandleError(MMSYSERR_ERROR); 263 return; 264 } 265 waiting_handle_ = NULL; 266 } 267 268 // Stop playback. 269 MMRESULT res = ::waveOutReset(waveout_); 270 if (res != MMSYSERR_NOERROR) { 271 state_ = PCMA_PLAYING; 272 HandleError(res); 273 return; 274 } 275 276 // Wait for lock to ensure all outstanding callbacks have completed. 277 base::AutoLock auto_lock(lock_); 278 279 // waveOutReset() leaves buffers in the unpredictable state, causing 280 // problems if we want to close, release, or reuse them. Fix the states. 281 for (int ix = 0; ix != num_buffers_; ++ix) { 282 GetBuffer(ix)->dwFlags = WHDR_PREPARED; 283 } 284 285 // Don't use callback after Stop(). 286 callback_ = NULL; 287 288 state_ = PCMA_READY; 289} 290 291// We can Close in any state except that trying to close a stream that is 292// playing Windows generates an error. We cannot propagate it to the source, 293// as callback_ is set to NULL. Just print it and hope somebody somehow 294// will find it... 295void PCMWaveOutAudioOutputStream::Close() { 296 // Force Stop() to ensure it's safe to release buffers and free the stream. 297 Stop(); 298 299 if (waveout_) { 300 FreeBuffers(); 301 302 // waveOutClose() generates a WIM_CLOSE callback. In case Start() was never 303 // called, force a reset to ensure close succeeds. 304 MMRESULT res = ::waveOutReset(waveout_); 305 DCHECK_EQ(res, static_cast<MMRESULT>(MMSYSERR_NOERROR)); 306 res = ::waveOutClose(waveout_); 307 DCHECK_EQ(res, static_cast<MMRESULT>(MMSYSERR_NOERROR)); 308 state_ = PCMA_CLOSED; 309 waveout_ = NULL; 310 } 311 312 // Tell the audio manager that we have been released. This can result in 313 // the manager destroying us in-place so this needs to be the last thing 314 // we do on this function. 315 manager_->ReleaseOutputStream(this); 316} 317 318void PCMWaveOutAudioOutputStream::SetVolume(double volume) { 319 if (!waveout_) 320 return; 321 volume_ = static_cast<float>(volume); 322} 323 324void PCMWaveOutAudioOutputStream::GetVolume(double* volume) { 325 if (!waveout_) 326 return; 327 *volume = volume_; 328} 329 330void PCMWaveOutAudioOutputStream::HandleError(MMRESULT error) { 331 DLOG(WARNING) << "PCMWaveOutAudio error " << error; 332 if (callback_) 333 callback_->OnError(this); 334} 335 336void PCMWaveOutAudioOutputStream::QueueNextPacket(WAVEHDR *buffer) { 337 DCHECK_EQ(channels_, format_.Format.nChannels); 338 // Call the source which will fill our buffer with pleasant sounds and 339 // return to us how many bytes were used. 340 // TODO(fbarchard): Handle used 0 by queueing more. 341 342 // TODO(sergeyu): Specify correct hardware delay for AudioBuffersState. 343 int frames_filled = callback_->OnMoreData( 344 audio_bus_.get(), AudioBuffersState(pending_bytes_, 0)); 345 uint32 used = frames_filled * audio_bus_->channels() * 346 format_.Format.wBitsPerSample / 8; 347 348 if (used <= buffer_size_) { 349 // Note: If this ever changes to output raw float the data must be clipped 350 // and sanitized since it may come from an untrusted source such as NaCl. 351 audio_bus_->Scale(volume_); 352 audio_bus_->ToInterleaved( 353 frames_filled, format_.Format.wBitsPerSample / 8, buffer->lpData); 354 355 buffer->dwBufferLength = used * format_.Format.nChannels / channels_; 356 } else { 357 HandleError(0); 358 return; 359 } 360 buffer->dwFlags = WHDR_PREPARED; 361} 362 363// One of the threads in our thread pool asynchronously calls this function when 364// buffer_event_ is signalled. Search through all the buffers looking for freed 365// ones, fills them with data, and "feed" the Windows. 366// Note: by searching through all the buffers we guarantee that we fill all the 367// buffers, even when "event loss" happens, i.e. if Windows signals event 368// when it did not flip into unsignaled state from the previous signal. 369void NTAPI PCMWaveOutAudioOutputStream::BufferCallback(PVOID lpParameter, 370 BOOLEAN timer_fired) { 371 TRACE_EVENT0("audio", "PCMWaveOutAudioOutputStream::BufferCallback"); 372 373 DCHECK(!timer_fired); 374 PCMWaveOutAudioOutputStream* stream = 375 reinterpret_cast<PCMWaveOutAudioOutputStream*>(lpParameter); 376 377 // Lock the stream so callbacks do not interfere with each other. 378 // Several callbacks can be called simultaneously by different threads in the 379 // thread pool if some of the callbacks are slow, or system is very busy and 380 // scheduled callbacks are not called on time. 381 base::AutoLock auto_lock(stream->lock_); 382 if (stream->state_ != PCMA_PLAYING) 383 return; 384 385 for (int ix = 0; ix != stream->num_buffers_; ++ix) { 386 WAVEHDR* buffer = stream->GetBuffer(ix); 387 if (buffer->dwFlags & WHDR_DONE) { 388 // Before we queue the next packet, we need to adjust the number of 389 // pending bytes since the last write to hardware. 390 stream->pending_bytes_ -= buffer->dwBufferLength; 391 stream->QueueNextPacket(buffer); 392 393 // QueueNextPacket() can take a long time, especially if several of them 394 // were called back-to-back. Check if we are stopping now. 395 if (stream->state_ != PCMA_PLAYING) 396 return; 397 398 // Time to send the buffer to the audio driver. Since we are reusing 399 // the same buffers we can get away without calling waveOutPrepareHeader. 400 MMRESULT result = ::waveOutWrite(stream->waveout_, 401 buffer, 402 sizeof(WAVEHDR)); 403 if (result != MMSYSERR_NOERROR) 404 stream->HandleError(result); 405 stream->pending_bytes_ += buffer->dwBufferLength; 406 } 407 } 408} 409 410} // namespace media 411