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