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