audio_low_latency_output_win.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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
3// found in the LICENSE file.
4
5#include "media/audio/win/audio_low_latency_output_win.h"
6
7#include <Functiondiscoverykeys_devpkey.h>
8
9#include "base/command_line.h"
10#include "base/debug/trace_event.h"
11#include "base/logging.h"
12#include "base/memory/scoped_ptr.h"
13#include "base/metrics/histogram.h"
14#include "base/strings/utf_string_conversions.h"
15#include "base/win/scoped_propvariant.h"
16#include "media/audio/win/audio_manager_win.h"
17#include "media/audio/win/avrt_wrapper_win.h"
18#include "media/audio/win/core_audio_util_win.h"
19#include "media/base/limits.h"
20#include "media/base/media_switches.h"
21
22using base::win::ScopedComPtr;
23using base::win::ScopedCOMInitializer;
24using base::win::ScopedCoMem;
25
26namespace media {
27
28// Compare two sets of audio parameters and return true if they are equal.
29// Note that bits_per_sample() is excluded from this comparison since Core
30// Audio can deal with most bit depths. As an example, if the native/mixing
31// bit depth is 32 bits (default), opening at 16 or 24 still works fine and
32// the audio engine will do the required conversion for us. Channel count is
33// excluded since Open() will fail anyways and it doesn't impact buffering.
34static bool CompareAudioParametersNoBitDepthOrChannels(
35    const media::AudioParameters& a, const media::AudioParameters& b) {
36  return (a.format() == b.format() &&
37          a.sample_rate() == b.sample_rate() &&
38          a.frames_per_buffer() == b.frames_per_buffer());
39}
40
41// static
42AUDCLNT_SHAREMODE WASAPIAudioOutputStream::GetShareMode() {
43  const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
44  if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio))
45    return AUDCLNT_SHAREMODE_EXCLUSIVE;
46  return AUDCLNT_SHAREMODE_SHARED;
47}
48
49// static
50int WASAPIAudioOutputStream::HardwareSampleRate(const std::string& device_id) {
51  WAVEFORMATPCMEX format;
52  ScopedComPtr<IAudioClient> client;
53  if (device_id.empty()) {
54    client = CoreAudioUtil::CreateDefaultClient(eRender, eConsole);
55  } else {
56    ScopedComPtr<IMMDevice> device(CoreAudioUtil::CreateDevice(device_id));
57    if (!device)
58      return 0;
59    client = CoreAudioUtil::CreateClient(device);
60  }
61
62  if (!client || FAILED(CoreAudioUtil::GetSharedModeMixFormat(client, &format)))
63    return 0;
64
65  return static_cast<int>(format.Format.nSamplesPerSec);
66}
67
68WASAPIAudioOutputStream::WASAPIAudioOutputStream(AudioManagerWin* manager,
69                                                 const std::string& device_id,
70                                                 const AudioParameters& params,
71                                                 ERole device_role)
72    : creating_thread_id_(base::PlatformThread::CurrentId()),
73      manager_(manager),
74      opened_(false),
75      audio_parameters_are_valid_(false),
76      volume_(1.0),
77      endpoint_buffer_size_frames_(0),
78      device_id_(device_id),
79      device_role_(device_role),
80      share_mode_(GetShareMode()),
81      num_written_frames_(0),
82      source_(NULL),
83      audio_bus_(AudioBus::Create(params)) {
84  DCHECK(manager_);
85  VLOG(1) << "WASAPIAudioOutputStream::WASAPIAudioOutputStream()";
86  VLOG_IF(1, share_mode_ == AUDCLNT_SHAREMODE_EXCLUSIVE)
87      << "Core Audio (WASAPI) EXCLUSIVE MODE is enabled.";
88
89  if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) {
90    // Verify that the input audio parameters are identical (bit depth and
91    // channel count are excluded) to the preferred (native) audio parameters.
92    // Open() will fail if this is not the case.
93    AudioParameters preferred_params;
94    HRESULT hr = device_id_.empty() ?
95        CoreAudioUtil::GetPreferredAudioParameters(eRender, device_role,
96                                                   &preferred_params) :
97        CoreAudioUtil::GetPreferredAudioParameters(device_id_,
98                                                   &preferred_params);
99    audio_parameters_are_valid_ = SUCCEEDED(hr) &&
100        CompareAudioParametersNoBitDepthOrChannels(params, preferred_params);
101    LOG_IF(WARNING, !audio_parameters_are_valid_)
102        << "Input and preferred parameters are not identical. "
103        << "Device id: " << device_id_;
104  }
105
106  // Load the Avrt DLL if not already loaded. Required to support MMCSS.
107  bool avrt_init = avrt::Initialize();
108  DCHECK(avrt_init) << "Failed to load the avrt.dll";
109
110  // Set up the desired render format specified by the client. We use the
111  // WAVE_FORMAT_EXTENSIBLE structure to ensure that multiple channel ordering
112  // and high precision data can be supported.
113
114  // Begin with the WAVEFORMATEX structure that specifies the basic format.
115  WAVEFORMATEX* format = &format_.Format;
116  format->wFormatTag = WAVE_FORMAT_EXTENSIBLE;
117  format->nChannels = params.channels();
118  format->nSamplesPerSec = params.sample_rate();
119  format->wBitsPerSample = params.bits_per_sample();
120  format->nBlockAlign = (format->wBitsPerSample / 8) * format->nChannels;
121  format->nAvgBytesPerSec = format->nSamplesPerSec * format->nBlockAlign;
122  format->cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
123
124  // Add the parts which are unique to WAVE_FORMAT_EXTENSIBLE.
125  format_.Samples.wValidBitsPerSample = params.bits_per_sample();
126  format_.dwChannelMask = CoreAudioUtil::GetChannelConfig(device_id, eRender);
127  format_.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
128
129  // Store size (in different units) of audio packets which we expect to
130  // get from the audio endpoint device in each render event.
131  packet_size_frames_ = params.frames_per_buffer();
132  packet_size_bytes_ = params.GetBytesPerBuffer();
133  packet_size_ms_ = (1000.0 * packet_size_frames_) / params.sample_rate();
134  VLOG(1) << "Number of bytes per audio frame  : " << format->nBlockAlign;
135  VLOG(1) << "Number of audio frames per packet: " << packet_size_frames_;
136  VLOG(1) << "Number of bytes per packet       : " << packet_size_bytes_;
137  VLOG(1) << "Number of milliseconds per packet: " << packet_size_ms_;
138
139  // All events are auto-reset events and non-signaled initially.
140
141  // Create the event which the audio engine will signal each time
142  // a buffer becomes ready to be processed by the client.
143  audio_samples_render_event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL));
144  DCHECK(audio_samples_render_event_.IsValid());
145
146  // Create the event which will be set in Stop() when capturing shall stop.
147  stop_render_event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL));
148  DCHECK(stop_render_event_.IsValid());
149}
150
151WASAPIAudioOutputStream::~WASAPIAudioOutputStream() {}
152
153bool WASAPIAudioOutputStream::Open() {
154  VLOG(1) << "WASAPIAudioOutputStream::Open()";
155  DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_);
156  if (opened_)
157    return true;
158
159  // Audio parameters must be identical to the preferred set of parameters
160  // if shared mode (default) is utilized.
161  if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) {
162    if (!audio_parameters_are_valid_) {
163      LOG(ERROR) << "Audio parameters are not valid.";
164      return false;
165    }
166  }
167
168  // Create an IAudioClient interface for the default rendering IMMDevice.
169  ScopedComPtr<IAudioClient> audio_client;
170  if (device_id_.empty()) {
171    audio_client = CoreAudioUtil::CreateDefaultClient(eRender, device_role_);
172  } else {
173    ScopedComPtr<IMMDevice> device(CoreAudioUtil::CreateDevice(device_id_));
174    DLOG_IF(ERROR, !device) << "Failed to open device: " << device_id_;
175    if (device)
176      audio_client = CoreAudioUtil::CreateClient(device);
177  }
178
179  if (!audio_client)
180    return false;
181
182  // Extra sanity to ensure that the provided device format is still valid.
183  if (!CoreAudioUtil::IsFormatSupported(audio_client,
184                                        share_mode_,
185                                        &format_)) {
186    return false;
187  }
188
189  HRESULT hr = S_FALSE;
190  if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) {
191    // Initialize the audio stream between the client and the device in shared
192    // mode and using event-driven buffer handling.
193    hr = CoreAudioUtil::SharedModeInitialize(
194        audio_client, &format_, audio_samples_render_event_.Get(),
195        &endpoint_buffer_size_frames_);
196    if (FAILED(hr))
197      return false;
198
199    // We know from experience that the best possible callback sequence is
200    // achieved when the packet size (given by the native device period)
201    // is an even multiple of the endpoint buffer size.
202    // Examples: 48kHz => 960 % 480, 44.1kHz => 896 % 448 or 882 % 441.
203    if (endpoint_buffer_size_frames_ % packet_size_frames_ != 0) {
204      LOG(ERROR) << "Bailing out due to non-perfect timing.";
205      return false;
206    }
207  } else {
208    // TODO(henrika): break out to CoreAudioUtil::ExclusiveModeInitialize()
209    // when removing the enable-exclusive-audio flag.
210    hr = ExclusiveModeInitialization(audio_client,
211                                     audio_samples_render_event_.Get(),
212                                     &endpoint_buffer_size_frames_);
213    if (FAILED(hr))
214      return false;
215
216    // The buffer scheme for exclusive mode streams is not designed for max
217    // flexibility. We only allow a "perfect match" between the packet size set
218    // by the user and the actual endpoint buffer size.
219    if (endpoint_buffer_size_frames_ != packet_size_frames_) {
220      LOG(ERROR) << "Bailing out due to non-perfect timing.";
221      return false;
222    }
223  }
224
225  // Create an IAudioRenderClient client for an initialized IAudioClient.
226  // The IAudioRenderClient interface enables us to write output data to
227  // a rendering endpoint buffer.
228  ScopedComPtr<IAudioRenderClient> audio_render_client =
229      CoreAudioUtil::CreateRenderClient(audio_client);
230  if (!audio_render_client)
231    return false;
232
233   // Store valid COM interfaces.
234  audio_client_ = audio_client;
235  audio_render_client_ = audio_render_client;
236
237  opened_ = true;
238  return true;
239}
240
241void WASAPIAudioOutputStream::Start(AudioSourceCallback* callback) {
242  VLOG(1) << "WASAPIAudioOutputStream::Start()";
243  DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_);
244  CHECK(callback);
245  CHECK(opened_);
246
247  if (render_thread_) {
248    CHECK_EQ(callback, source_);
249    return;
250  }
251
252  source_ = callback;
253
254  // Create and start the thread that will drive the rendering by waiting for
255  // render events.
256  render_thread_.reset(
257      new base::DelegateSimpleThread(this, "wasapi_render_thread"));
258  render_thread_->Start();
259  if (!render_thread_->HasBeenStarted()) {
260    LOG(ERROR) << "Failed to start WASAPI render thread.";
261    StopThread();
262    callback->OnError(this);
263    return;
264  }
265
266  // Ensure that the endpoint buffer is prepared with silence.
267  if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) {
268    if (!CoreAudioUtil::FillRenderEndpointBufferWithSilence(
269             audio_client_, audio_render_client_)) {
270      LOG(ERROR) << "Failed to prepare endpoint buffers with silence.";
271      StopThread();
272      callback->OnError(this);
273      return;
274    }
275  }
276  num_written_frames_ = endpoint_buffer_size_frames_;
277
278  // Start streaming data between the endpoint buffer and the audio engine.
279  HRESULT hr = audio_client_->Start();
280  if (FAILED(hr)) {
281    LOG_GETLASTERROR(ERROR)
282        << "Failed to start output streaming: " << std::hex << hr;
283    StopThread();
284    callback->OnError(this);
285  }
286}
287
288void WASAPIAudioOutputStream::Stop() {
289  VLOG(1) << "WASAPIAudioOutputStream::Stop()";
290  DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_);
291  if (!render_thread_)
292    return;
293
294  // Stop output audio streaming.
295  HRESULT hr = audio_client_->Stop();
296  if (FAILED(hr)) {
297    LOG_GETLASTERROR(ERROR)
298        << "Failed to stop output streaming: " << std::hex << hr;
299    source_->OnError(this);
300  }
301
302  // Make a local copy of |source_| since StopThread() will clear it.
303  AudioSourceCallback* callback = source_;
304  StopThread();
305
306  // Flush all pending data and reset the audio clock stream position to 0.
307  hr = audio_client_->Reset();
308  if (FAILED(hr)) {
309    LOG_GETLASTERROR(ERROR)
310        << "Failed to reset streaming: " << std::hex << hr;
311    callback->OnError(this);
312  }
313
314  // Extra safety check to ensure that the buffers are cleared.
315  // If the buffers are not cleared correctly, the next call to Start()
316  // would fail with AUDCLNT_E_BUFFER_ERROR at IAudioRenderClient::GetBuffer().
317  // This check is is only needed for shared-mode streams.
318  if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) {
319    UINT32 num_queued_frames = 0;
320    audio_client_->GetCurrentPadding(&num_queued_frames);
321    DCHECK_EQ(0u, num_queued_frames);
322  }
323}
324
325void WASAPIAudioOutputStream::Close() {
326  VLOG(1) << "WASAPIAudioOutputStream::Close()";
327  DCHECK_EQ(GetCurrentThreadId(), creating_thread_id_);
328
329  // It is valid to call Close() before calling open or Start().
330  // It is also valid to call Close() after Start() has been called.
331  Stop();
332
333  // Inform the audio manager that we have been closed. This will cause our
334  // destruction.
335  manager_->ReleaseOutputStream(this);
336}
337
338void WASAPIAudioOutputStream::SetVolume(double volume) {
339  VLOG(1) << "SetVolume(volume=" << volume << ")";
340  float volume_float = static_cast<float>(volume);
341  if (volume_float < 0.0f || volume_float > 1.0f) {
342    return;
343  }
344  volume_ = volume_float;
345}
346
347void WASAPIAudioOutputStream::GetVolume(double* volume) {
348  VLOG(1) << "GetVolume()";
349  *volume = static_cast<double>(volume_);
350}
351
352void WASAPIAudioOutputStream::Run() {
353  ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA);
354
355  // Increase the thread priority.
356  render_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio);
357
358  // Enable MMCSS to ensure that this thread receives prioritized access to
359  // CPU resources.
360  DWORD task_index = 0;
361  HANDLE mm_task = avrt::AvSetMmThreadCharacteristics(L"Pro Audio",
362                                                      &task_index);
363  bool mmcss_is_ok =
364      (mm_task && avrt::AvSetMmThreadPriority(mm_task, AVRT_PRIORITY_CRITICAL));
365  if (!mmcss_is_ok) {
366    // Failed to enable MMCSS on this thread. It is not fatal but can lead
367    // to reduced QoS at high load.
368    DWORD err = GetLastError();
369    LOG(WARNING) << "Failed to enable MMCSS (error code=" << err << ").";
370  }
371
372  HRESULT hr = S_FALSE;
373
374  bool playing = true;
375  bool error = false;
376  HANDLE wait_array[] = { stop_render_event_,
377                          audio_samples_render_event_ };
378  UINT64 device_frequency = 0;
379
380  // The IAudioClock interface enables us to monitor a stream's data
381  // rate and the current position in the stream. Allocate it before we
382  // start spinning.
383  ScopedComPtr<IAudioClock> audio_clock;
384  hr = audio_client_->GetService(__uuidof(IAudioClock),
385                                 audio_clock.ReceiveVoid());
386  if (SUCCEEDED(hr)) {
387    // The device frequency is the frequency generated by the hardware clock in
388    // the audio device. The GetFrequency() method reports a constant frequency.
389    hr = audio_clock->GetFrequency(&device_frequency);
390  }
391  error = FAILED(hr);
392  PLOG_IF(ERROR, error) << "Failed to acquire IAudioClock interface: "
393                        << std::hex << hr;
394
395  // Keep rendering audio until the stop event or the stream-switch event
396  // is signaled. An error event can also break the main thread loop.
397  while (playing && !error) {
398    // Wait for a close-down event, stream-switch event or a new render event.
399    DWORD wait_result = WaitForMultipleObjects(arraysize(wait_array),
400                                               wait_array,
401                                               FALSE,
402                                               INFINITE);
403
404    switch (wait_result) {
405      case WAIT_OBJECT_0 + 0:
406        // |stop_render_event_| has been set.
407        playing = false;
408        break;
409      case WAIT_OBJECT_0 + 1:
410        // |audio_samples_render_event_| has been set.
411        error = !RenderAudioFromSource(audio_clock, device_frequency);
412        break;
413      default:
414        error = true;
415        break;
416    }
417  }
418
419  if (playing && error) {
420    // Stop audio rendering since something has gone wrong in our main thread
421    // loop. Note that, we are still in a "started" state, hence a Stop() call
422    // is required to join the thread properly.
423    audio_client_->Stop();
424    PLOG(ERROR) << "WASAPI rendering failed.";
425  }
426
427  // Disable MMCSS.
428  if (mm_task && !avrt::AvRevertMmThreadCharacteristics(mm_task)) {
429    PLOG(WARNING) << "Failed to disable MMCSS";
430  }
431}
432
433bool WASAPIAudioOutputStream::RenderAudioFromSource(
434    IAudioClock* audio_clock, UINT64 device_frequency) {
435  TRACE_EVENT0("audio", "RenderAudioFromSource");
436
437  HRESULT hr = S_FALSE;
438  UINT32 num_queued_frames = 0;
439  uint8* audio_data = NULL;
440
441  // Contains how much new data we can write to the buffer without
442  // the risk of overwriting previously written data that the audio
443  // engine has not yet read from the buffer.
444  size_t num_available_frames = 0;
445
446  if (share_mode_ == AUDCLNT_SHAREMODE_SHARED) {
447    // Get the padding value which represents the amount of rendering
448    // data that is queued up to play in the endpoint buffer.
449    hr = audio_client_->GetCurrentPadding(&num_queued_frames);
450    num_available_frames =
451        endpoint_buffer_size_frames_ - num_queued_frames;
452    if (FAILED(hr)) {
453      DLOG(ERROR) << "Failed to retrieve amount of available space: "
454                  << std::hex << hr;
455      return false;
456    }
457  } else {
458    // While the stream is running, the system alternately sends one
459    // buffer or the other to the client. This form of double buffering
460    // is referred to as "ping-ponging". Each time the client receives
461    // a buffer from the system (triggers this event) the client must
462    // process the entire buffer. Calls to the GetCurrentPadding method
463    // are unnecessary because the packet size must always equal the
464    // buffer size. In contrast to the shared mode buffering scheme,
465    // the latency for an event-driven, exclusive-mode stream depends
466    // directly on the buffer size.
467    num_available_frames = endpoint_buffer_size_frames_;
468  }
469
470  // Check if there is enough available space to fit the packet size
471  // specified by the client.
472  if (num_available_frames < packet_size_frames_)
473    return true;
474
475  DLOG_IF(ERROR, num_available_frames % packet_size_frames_ != 0)
476      << "Non-perfect timing detected (num_available_frames="
477      << num_available_frames << ", packet_size_frames="
478      << packet_size_frames_ << ")";
479
480  // Derive the number of packets we need to get from the client to
481  // fill up the available area in the endpoint buffer.
482  // |num_packets| will always be one for exclusive-mode streams and
483  // will be one in most cases for shared mode streams as well.
484  // However, we have found that two packets can sometimes be
485  // required.
486  size_t num_packets = (num_available_frames / packet_size_frames_);
487
488  for (size_t n = 0; n < num_packets; ++n) {
489    // Grab all available space in the rendering endpoint buffer
490    // into which the client can write a data packet.
491    hr = audio_render_client_->GetBuffer(packet_size_frames_,
492                                         &audio_data);
493    if (FAILED(hr)) {
494      DLOG(ERROR) << "Failed to use rendering audio buffer: "
495                 << std::hex << hr;
496      return false;
497    }
498
499    // Derive the audio delay which corresponds to the delay between
500    // a render event and the time when the first audio sample in a
501    // packet is played out through the speaker. This delay value
502    // can typically be utilized by an acoustic echo-control (AEC)
503    // unit at the render side.
504    UINT64 position = 0;
505    int audio_delay_bytes = 0;
506    hr = audio_clock->GetPosition(&position, NULL);
507    if (SUCCEEDED(hr)) {
508      // Stream position of the sample that is currently playing
509      // through the speaker.
510      double pos_sample_playing_frames = format_.Format.nSamplesPerSec *
511          (static_cast<double>(position) / device_frequency);
512
513      // Stream position of the last sample written to the endpoint
514      // buffer. Note that, the packet we are about to receive in
515      // the upcoming callback is also included.
516      size_t pos_last_sample_written_frames =
517          num_written_frames_ + packet_size_frames_;
518
519      // Derive the actual delay value which will be fed to the
520      // render client using the OnMoreData() callback.
521      audio_delay_bytes = (pos_last_sample_written_frames -
522          pos_sample_playing_frames) *  format_.Format.nBlockAlign;
523    }
524
525    // Read a data packet from the registered client source and
526    // deliver a delay estimate in the same callback to the client.
527    // A time stamp is also stored in the AudioBuffersState. This
528    // time stamp can be used at the client side to compensate for
529    // the delay between the usage of the delay value and the time
530    // of generation.
531
532    int frames_filled = source_->OnMoreData(
533        audio_bus_.get(), AudioBuffersState(0, audio_delay_bytes));
534    uint32 num_filled_bytes = frames_filled * format_.Format.nBlockAlign;
535    DCHECK_LE(num_filled_bytes, packet_size_bytes_);
536
537    // Note: If this ever changes to output raw float the data must be
538    // clipped and sanitized since it may come from an untrusted
539    // source such as NaCl.
540    const int bytes_per_sample = format_.Format.wBitsPerSample >> 3;
541    audio_bus_->Scale(volume_);
542    audio_bus_->ToInterleaved(
543        frames_filled, bytes_per_sample, audio_data);
544
545
546    // Release the buffer space acquired in the GetBuffer() call.
547    // Render silence if we were not able to fill up the buffer totally.
548    DWORD flags = (num_filled_bytes < packet_size_bytes_) ?
549        AUDCLNT_BUFFERFLAGS_SILENT : 0;
550    audio_render_client_->ReleaseBuffer(packet_size_frames_, flags);
551
552    num_written_frames_ += packet_size_frames_;
553  }
554
555  return true;
556}
557
558HRESULT WASAPIAudioOutputStream::ExclusiveModeInitialization(
559    IAudioClient* client, HANDLE event_handle, uint32* endpoint_buffer_size) {
560  DCHECK_EQ(share_mode_, AUDCLNT_SHAREMODE_EXCLUSIVE);
561
562  float f = (1000.0 * packet_size_frames_) / format_.Format.nSamplesPerSec;
563  REFERENCE_TIME requested_buffer_duration =
564      static_cast<REFERENCE_TIME>(f * 10000.0 + 0.5);
565
566  DWORD stream_flags = AUDCLNT_STREAMFLAGS_NOPERSIST;
567  bool use_event = (event_handle != NULL &&
568                    event_handle != INVALID_HANDLE_VALUE);
569  if (use_event)
570    stream_flags |= AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
571  VLOG(2) << "stream_flags: 0x" << std::hex << stream_flags;
572
573  // Initialize the audio stream between the client and the device.
574  // For an exclusive-mode stream that uses event-driven buffering, the
575  // caller must specify nonzero values for hnsPeriodicity and
576  // hnsBufferDuration, and the values of these two parameters must be equal.
577  // The Initialize method allocates two buffers for the stream. Each buffer
578  // is equal in duration to the value of the hnsBufferDuration parameter.
579  // Following the Initialize call for a rendering stream, the caller should
580  // fill the first of the two buffers before starting the stream.
581  HRESULT hr = S_FALSE;
582  hr = client->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE,
583                          stream_flags,
584                          requested_buffer_duration,
585                          requested_buffer_duration,
586                          reinterpret_cast<WAVEFORMATEX*>(&format_),
587                          NULL);
588  if (FAILED(hr)) {
589    if (hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) {
590      LOG(ERROR) << "AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED";
591
592      UINT32 aligned_buffer_size = 0;
593      client->GetBufferSize(&aligned_buffer_size);
594      VLOG(1) << "Use aligned buffer size instead: " << aligned_buffer_size;
595
596      // Calculate new aligned periodicity. Each unit of reference time
597      // is 100 nanoseconds.
598      REFERENCE_TIME aligned_buffer_duration = static_cast<REFERENCE_TIME>(
599          (10000000.0 * aligned_buffer_size / format_.Format.nSamplesPerSec)
600          + 0.5);
601
602      // It is possible to re-activate and re-initialize the audio client
603      // at this stage but we bail out with an error code instead and
604      // combine it with a log message which informs about the suggested
605      // aligned buffer size which should be used instead.
606      VLOG(1) << "aligned_buffer_duration: "
607              << static_cast<double>(aligned_buffer_duration / 10000.0)
608              << " [ms]";
609    } else if (hr == AUDCLNT_E_INVALID_DEVICE_PERIOD) {
610      // We will get this error if we try to use a smaller buffer size than
611      // the minimum supported size (usually ~3ms on Windows 7).
612      LOG(ERROR) << "AUDCLNT_E_INVALID_DEVICE_PERIOD";
613    }
614    return hr;
615  }
616
617  if (use_event) {
618    hr = client->SetEventHandle(event_handle);
619    if (FAILED(hr)) {
620      VLOG(1) << "IAudioClient::SetEventHandle: " << std::hex << hr;
621      return hr;
622    }
623  }
624
625  UINT32 buffer_size_in_frames = 0;
626  hr = client->GetBufferSize(&buffer_size_in_frames);
627  if (FAILED(hr)) {
628    VLOG(1) << "IAudioClient::GetBufferSize: " << std::hex << hr;
629    return hr;
630  }
631
632  *endpoint_buffer_size = buffer_size_in_frames;
633  VLOG(2) << "endpoint buffer size: " << buffer_size_in_frames;
634  return hr;
635}
636
637void WASAPIAudioOutputStream::StopThread() {
638  if (render_thread_ ) {
639    if (render_thread_->HasBeenStarted()) {
640      // Wait until the thread completes and perform cleanup.
641      SetEvent(stop_render_event_.Get());
642      render_thread_->Join();
643    }
644
645    render_thread_.reset();
646
647    // Ensure that we don't quit the main thread loop immediately next
648    // time Start() is called.
649    ResetEvent(stop_render_event_.Get());
650  }
651
652  source_ = NULL;
653}
654
655}  // namespace media
656