Home | History | Annotate | Download | only in win
      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 
     22 using base::win::ScopedComPtr;
     23 using base::win::ScopedCOMInitializer;
     24 using base::win::ScopedCoMem;
     25 
     26 namespace media {
     27 
     28 typedef 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.
     38 static 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. Channel count is
     50 // excluded since Open() will fail anyways and it doesn't impact buffering.
     51 static bool CompareAudioParametersNoBitDepthOrChannels(
     52     const media::AudioParameters& a, const media::AudioParameters& b) {
     53   return (a.format() == b.format() &&
     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.
     66 static 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
     93 AUDCLNT_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
    101 int 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
    109 ChannelLayout WASAPIAudioOutputStream::HardwareChannelLayout() {
    110   return ChannelConfigToChannelLayout(GetChannelConfig());
    111 }
    112 
    113 // static
    114 int WASAPIAudioOutputStream::HardwareSampleRate() {
    115   WAVEFORMATPCMEX format;
    116   return SUCCEEDED(CoreAudioUtil::GetDefaultSharedModeMixFormat(
    117       eRender, eConsole, &format)) ?
    118       static_cast<int>(format.Format.nSamplesPerSec) : 0;
    119 }
    120 
    121 WASAPIAudioOutputStream::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_parameters_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 and
    142     // channel count are excluded) to the preferred (native) audio parameters.
    143     // Open() will fail if this is not the case.
    144     AudioParameters preferred_params;
    145     HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters(
    146         eRender, device_role, &preferred_params);
    147     audio_parameters_are_valid_ = SUCCEEDED(hr) &&
    148         CompareAudioParametersNoBitDepthOrChannels(params, preferred_params);
    149     LOG_IF(WARNING, !audio_parameters_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 
    198 WASAPIAudioOutputStream::~WASAPIAudioOutputStream() {}
    199 
    200 bool 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_parameters_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 
    281 void 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 
    324 void 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 
    367 void 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 
    380 void 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 
    389 void WASAPIAudioOutputStream::GetVolume(double* volume) {
    390   VLOG(1) << "GetVolume()";
    391   *volume = static_cast<double>(volume_);
    392 }
    393 
    394 void 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 
    475 void 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 
    598 void 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 
    606 HRESULT 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