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_input_win.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/strings/utf_string_conversions.h"
     10 #include "media/audio/win/audio_manager_win.h"
     11 #include "media/audio/win/avrt_wrapper_win.h"
     12 #include "media/base/audio_bus.h"
     13 
     14 using base::win::ScopedComPtr;
     15 using base::win::ScopedCOMInitializer;
     16 
     17 namespace media {
     18 namespace {
     19 
     20 // Returns true if |device| represents the default communication capture device.
     21 bool IsDefaultCommunicationDevice(IMMDeviceEnumerator* enumerator,
     22                                   IMMDevice* device) {
     23   ScopedComPtr<IMMDevice> communications;
     24   if (FAILED(enumerator->GetDefaultAudioEndpoint(eCapture, eCommunications,
     25                                                  communications.Receive()))) {
     26     return false;
     27   }
     28 
     29   base::win::ScopedCoMem<WCHAR> communications_id, device_id;
     30   device->GetId(&device_id);
     31   communications->GetId(&communications_id);
     32   return lstrcmpW(communications_id, device_id) == 0;
     33 }
     34 
     35 }  // namespace
     36 
     37 WASAPIAudioInputStream::WASAPIAudioInputStream(AudioManagerWin* manager,
     38                                                const AudioParameters& params,
     39                                                const std::string& device_id)
     40     : manager_(manager),
     41       capture_thread_(NULL),
     42       opened_(false),
     43       started_(false),
     44       frame_size_(0),
     45       packet_size_frames_(0),
     46       packet_size_bytes_(0),
     47       endpoint_buffer_size_frames_(0),
     48       effects_(params.effects()),
     49       device_id_(device_id),
     50       perf_count_to_100ns_units_(0.0),
     51       ms_to_frame_count_(0.0),
     52       sink_(NULL),
     53       audio_bus_(media::AudioBus::Create(params)) {
     54   DCHECK(manager_);
     55 
     56   // Load the Avrt DLL if not already loaded. Required to support MMCSS.
     57   bool avrt_init = avrt::Initialize();
     58   DCHECK(avrt_init) << "Failed to load the Avrt.dll";
     59 
     60   // Set up the desired capture format specified by the client.
     61   format_.nSamplesPerSec = params.sample_rate();
     62   format_.wFormatTag = WAVE_FORMAT_PCM;
     63   format_.wBitsPerSample = params.bits_per_sample();
     64   format_.nChannels = params.channels();
     65   format_.nBlockAlign = (format_.wBitsPerSample / 8) * format_.nChannels;
     66   format_.nAvgBytesPerSec = format_.nSamplesPerSec * format_.nBlockAlign;
     67   format_.cbSize = 0;
     68 
     69   // Size in bytes of each audio frame.
     70   frame_size_ = format_.nBlockAlign;
     71   // Store size of audio packets which we expect to get from the audio
     72   // endpoint device in each capture event.
     73   packet_size_frames_ = params.GetBytesPerBuffer() / format_.nBlockAlign;
     74   packet_size_bytes_ = params.GetBytesPerBuffer();
     75   DVLOG(1) << "Number of bytes per audio frame  : " << frame_size_;
     76   DVLOG(1) << "Number of audio frames per packet: " << packet_size_frames_;
     77 
     78   // All events are auto-reset events and non-signaled initially.
     79 
     80   // Create the event which the audio engine will signal each time
     81   // a buffer becomes ready to be processed by the client.
     82   audio_samples_ready_event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL));
     83   DCHECK(audio_samples_ready_event_.IsValid());
     84 
     85   // Create the event which will be set in Stop() when capturing shall stop.
     86   stop_capture_event_.Set(CreateEvent(NULL, FALSE, FALSE, NULL));
     87   DCHECK(stop_capture_event_.IsValid());
     88 
     89   ms_to_frame_count_ = static_cast<double>(params.sample_rate()) / 1000.0;
     90 
     91   LARGE_INTEGER performance_frequency;
     92   if (QueryPerformanceFrequency(&performance_frequency)) {
     93     perf_count_to_100ns_units_ =
     94         (10000000.0 / static_cast<double>(performance_frequency.QuadPart));
     95   } else {
     96     DLOG(ERROR) << "High-resolution performance counters are not supported.";
     97   }
     98 }
     99 
    100 WASAPIAudioInputStream::~WASAPIAudioInputStream() {}
    101 
    102 bool WASAPIAudioInputStream::Open() {
    103   DCHECK(CalledOnValidThread());
    104   // Verify that we are not already opened.
    105   if (opened_)
    106     return false;
    107 
    108   // Obtain a reference to the IMMDevice interface of the capturing
    109   // device with the specified unique identifier or role which was
    110   // set at construction.
    111   HRESULT hr = SetCaptureDevice();
    112   if (FAILED(hr))
    113     return false;
    114 
    115   // Obtain an IAudioClient interface which enables us to create and initialize
    116   // an audio stream between an audio application and the audio engine.
    117   hr = ActivateCaptureDevice();
    118   if (FAILED(hr))
    119     return false;
    120 
    121   // Retrieve the stream format which the audio engine uses for its internal
    122   // processing/mixing of shared-mode streams. This function call is for
    123   // diagnostic purposes only and only in debug mode.
    124 #ifndef NDEBUG
    125   hr = GetAudioEngineStreamFormat();
    126 #endif
    127 
    128   // Verify that the selected audio endpoint supports the specified format
    129   // set during construction.
    130   if (!DesiredFormatIsSupported())
    131     return false;
    132 
    133   // Initialize the audio stream between the client and the device using
    134   // shared mode and a lowest possible glitch-free latency.
    135   hr = InitializeAudioEngine();
    136 
    137   opened_ = SUCCEEDED(hr);
    138   return opened_;
    139 }
    140 
    141 void WASAPIAudioInputStream::Start(AudioInputCallback* callback) {
    142   DCHECK(CalledOnValidThread());
    143   DCHECK(callback);
    144   DLOG_IF(ERROR, !opened_) << "Open() has not been called successfully";
    145   if (!opened_)
    146     return;
    147 
    148   if (started_)
    149     return;
    150 
    151   DCHECK(!sink_);
    152   sink_ = callback;
    153 
    154   // Starts periodic AGC microphone measurements if the AGC has been enabled
    155   // using SetAutomaticGainControl().
    156   StartAgc();
    157 
    158   // Create and start the thread that will drive the capturing by waiting for
    159   // capture events.
    160   capture_thread_ =
    161       new base::DelegateSimpleThread(this, "wasapi_capture_thread");
    162   capture_thread_->Start();
    163 
    164   // Start streaming data between the endpoint buffer and the audio engine.
    165   HRESULT hr = audio_client_->Start();
    166   DLOG_IF(ERROR, FAILED(hr)) << "Failed to start input streaming.";
    167 
    168   if (SUCCEEDED(hr) && audio_render_client_for_loopback_)
    169     hr = audio_render_client_for_loopback_->Start();
    170 
    171   started_ = SUCCEEDED(hr);
    172 }
    173 
    174 void WASAPIAudioInputStream::Stop() {
    175   DCHECK(CalledOnValidThread());
    176   DVLOG(1) << "WASAPIAudioInputStream::Stop()";
    177   if (!started_)
    178     return;
    179 
    180   // Stops periodic AGC microphone measurements.
    181   StopAgc();
    182 
    183   // Shut down the capture thread.
    184   if (stop_capture_event_.IsValid()) {
    185     SetEvent(stop_capture_event_.Get());
    186   }
    187 
    188   // Stop the input audio streaming.
    189   HRESULT hr = audio_client_->Stop();
    190   if (FAILED(hr)) {
    191     LOG(ERROR) << "Failed to stop input streaming.";
    192   }
    193 
    194   // Wait until the thread completes and perform cleanup.
    195   if (capture_thread_) {
    196     SetEvent(stop_capture_event_.Get());
    197     capture_thread_->Join();
    198     capture_thread_ = NULL;
    199   }
    200 
    201   started_ = false;
    202   sink_ = NULL;
    203 }
    204 
    205 void WASAPIAudioInputStream::Close() {
    206   DVLOG(1) << "WASAPIAudioInputStream::Close()";
    207   // It is valid to call Close() before calling open or Start().
    208   // It is also valid to call Close() after Start() has been called.
    209   Stop();
    210 
    211   // Inform the audio manager that we have been closed. This will cause our
    212   // destruction.
    213   manager_->ReleaseInputStream(this);
    214 }
    215 
    216 double WASAPIAudioInputStream::GetMaxVolume() {
    217   // Verify that Open() has been called succesfully, to ensure that an audio
    218   // session exists and that an ISimpleAudioVolume interface has been created.
    219   DLOG_IF(ERROR, !opened_) << "Open() has not been called successfully";
    220   if (!opened_)
    221     return 0.0;
    222 
    223   // The effective volume value is always in the range 0.0 to 1.0, hence
    224   // we can return a fixed value (=1.0) here.
    225   return 1.0;
    226 }
    227 
    228 void WASAPIAudioInputStream::SetVolume(double volume) {
    229   DVLOG(1) << "SetVolume(volume=" << volume << ")";
    230   DCHECK(CalledOnValidThread());
    231   DCHECK_GE(volume, 0.0);
    232   DCHECK_LE(volume, 1.0);
    233 
    234   DLOG_IF(ERROR, !opened_) << "Open() has not been called successfully";
    235   if (!opened_)
    236     return;
    237 
    238   // Set a new master volume level. Valid volume levels are in the range
    239   // 0.0 to 1.0. Ignore volume-change events.
    240   HRESULT hr = simple_audio_volume_->SetMasterVolume(static_cast<float>(volume),
    241       NULL);
    242   DLOG_IF(WARNING, FAILED(hr)) << "Failed to set new input master volume.";
    243 
    244   // Update the AGC volume level based on the last setting above. Note that,
    245   // the volume-level resolution is not infinite and it is therefore not
    246   // possible to assume that the volume provided as input parameter can be
    247   // used directly. Instead, a new query to the audio hardware is required.
    248   // This method does nothing if AGC is disabled.
    249   UpdateAgcVolume();
    250 }
    251 
    252 double WASAPIAudioInputStream::GetVolume() {
    253   DLOG_IF(ERROR, !opened_) << "Open() has not been called successfully";
    254   if (!opened_)
    255     return 0.0;
    256 
    257   // Retrieve the current volume level. The value is in the range 0.0 to 1.0.
    258   float level = 0.0f;
    259   HRESULT hr = simple_audio_volume_->GetMasterVolume(&level);
    260   DLOG_IF(WARNING, FAILED(hr)) << "Failed to get input master volume.";
    261 
    262   return static_cast<double>(level);
    263 }
    264 
    265 // static
    266 AudioParameters WASAPIAudioInputStream::GetInputStreamParameters(
    267     const std::string& device_id) {
    268   int sample_rate = 48000;
    269   ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
    270 
    271   base::win::ScopedCoMem<WAVEFORMATEX> audio_engine_mix_format;
    272   int effects = AudioParameters::NO_EFFECTS;
    273   if (SUCCEEDED(GetMixFormat(device_id, &audio_engine_mix_format, &effects))) {
    274     sample_rate = static_cast<int>(audio_engine_mix_format->nSamplesPerSec);
    275     channel_layout = audio_engine_mix_format->nChannels == 1 ?
    276         CHANNEL_LAYOUT_MONO : CHANNEL_LAYOUT_STEREO;
    277   }
    278 
    279   // Use 10ms frame size as default.
    280   int frames_per_buffer = sample_rate / 100;
    281   return AudioParameters(
    282       AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, 0, sample_rate,
    283       16, frames_per_buffer, effects);
    284 }
    285 
    286 // static
    287 HRESULT WASAPIAudioInputStream::GetMixFormat(const std::string& device_id,
    288                                              WAVEFORMATEX** device_format,
    289                                              int* effects) {
    290   DCHECK(effects);
    291 
    292   // It is assumed that this static method is called from a COM thread, i.e.,
    293   // CoInitializeEx() is not called here to avoid STA/MTA conflicts.
    294   ScopedComPtr<IMMDeviceEnumerator> enumerator;
    295   HRESULT hr = enumerator.CreateInstance(__uuidof(MMDeviceEnumerator), NULL,
    296                                          CLSCTX_INPROC_SERVER);
    297   if (FAILED(hr))
    298     return hr;
    299 
    300   ScopedComPtr<IMMDevice> endpoint_device;
    301   if (device_id == AudioManagerBase::kDefaultDeviceId) {
    302     // Retrieve the default capture audio endpoint.
    303     hr = enumerator->GetDefaultAudioEndpoint(eCapture, eConsole,
    304                                              endpoint_device.Receive());
    305   } else if (device_id == AudioManagerBase::kLoopbackInputDeviceId) {
    306     // Get the mix format of the default playback stream.
    307     hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole,
    308                                              endpoint_device.Receive());
    309   } else {
    310     // Retrieve a capture endpoint device that is specified by an endpoint
    311     // device-identification string.
    312     hr = enumerator->GetDevice(base::UTF8ToUTF16(device_id).c_str(),
    313                                endpoint_device.Receive());
    314   }
    315 
    316   if (FAILED(hr))
    317     return hr;
    318 
    319   *effects = IsDefaultCommunicationDevice(enumerator, endpoint_device) ?
    320       AudioParameters::DUCKING : AudioParameters::NO_EFFECTS;
    321 
    322   ScopedComPtr<IAudioClient> audio_client;
    323   hr = endpoint_device->Activate(__uuidof(IAudioClient),
    324                                  CLSCTX_INPROC_SERVER,
    325                                  NULL,
    326                                  audio_client.ReceiveVoid());
    327   return SUCCEEDED(hr) ? audio_client->GetMixFormat(device_format) : hr;
    328 }
    329 
    330 void WASAPIAudioInputStream::Run() {
    331   ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA);
    332 
    333   // Increase the thread priority.
    334   capture_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio);
    335 
    336   // Enable MMCSS to ensure that this thread receives prioritized access to
    337   // CPU resources.
    338   DWORD task_index = 0;
    339   HANDLE mm_task = avrt::AvSetMmThreadCharacteristics(L"Pro Audio",
    340                                                       &task_index);
    341   bool mmcss_is_ok =
    342       (mm_task && avrt::AvSetMmThreadPriority(mm_task, AVRT_PRIORITY_CRITICAL));
    343   if (!mmcss_is_ok) {
    344     // Failed to enable MMCSS on this thread. It is not fatal but can lead
    345     // to reduced QoS at high load.
    346     DWORD err = GetLastError();
    347     LOG(WARNING) << "Failed to enable MMCSS (error code=" << err << ").";
    348   }
    349 
    350   // Allocate a buffer with a size that enables us to take care of cases like:
    351   // 1) The recorded buffer size is smaller, or does not match exactly with,
    352   //    the selected packet size used in each callback.
    353   // 2) The selected buffer size is larger than the recorded buffer size in
    354   //    each event.
    355   size_t buffer_frame_index = 0;
    356   size_t capture_buffer_size = std::max(
    357       2 * endpoint_buffer_size_frames_ * frame_size_,
    358       2 * packet_size_frames_ * frame_size_);
    359   scoped_ptr<uint8[]> capture_buffer(new uint8[capture_buffer_size]);
    360 
    361   LARGE_INTEGER now_count;
    362   bool recording = true;
    363   bool error = false;
    364   double volume = GetVolume();
    365   HANDLE wait_array[2] = {stop_capture_event_, audio_samples_ready_event_};
    366 
    367   while (recording && !error) {
    368     HRESULT hr = S_FALSE;
    369 
    370     // Wait for a close-down event or a new capture event.
    371     DWORD wait_result = WaitForMultipleObjects(2, wait_array, FALSE, INFINITE);
    372     switch (wait_result) {
    373       case WAIT_FAILED:
    374         error = true;
    375         break;
    376       case WAIT_OBJECT_0 + 0:
    377         // |stop_capture_event_| has been set.
    378         recording = false;
    379         break;
    380       case WAIT_OBJECT_0 + 1:
    381         {
    382           // |audio_samples_ready_event_| has been set.
    383           BYTE* data_ptr = NULL;
    384           UINT32 num_frames_to_read = 0;
    385           DWORD flags = 0;
    386           UINT64 device_position = 0;
    387           UINT64 first_audio_frame_timestamp = 0;
    388 
    389           // Retrieve the amount of data in the capture endpoint buffer,
    390           // replace it with silence if required, create callbacks for each
    391           // packet and store non-delivered data for the next event.
    392           hr = audio_capture_client_->GetBuffer(&data_ptr,
    393                                                 &num_frames_to_read,
    394                                                 &flags,
    395                                                 &device_position,
    396                                                 &first_audio_frame_timestamp);
    397           if (FAILED(hr)) {
    398             DLOG(ERROR) << "Failed to get data from the capture buffer";
    399             continue;
    400           }
    401 
    402           if (num_frames_to_read != 0) {
    403             size_t pos = buffer_frame_index * frame_size_;
    404             size_t num_bytes = num_frames_to_read * frame_size_;
    405             DCHECK_GE(capture_buffer_size, pos + num_bytes);
    406 
    407             if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
    408               // Clear out the local buffer since silence is reported.
    409               memset(&capture_buffer[pos], 0, num_bytes);
    410             } else {
    411               // Copy captured data from audio engine buffer to local buffer.
    412               memcpy(&capture_buffer[pos], data_ptr, num_bytes);
    413             }
    414 
    415             buffer_frame_index += num_frames_to_read;
    416           }
    417 
    418           hr = audio_capture_client_->ReleaseBuffer(num_frames_to_read);
    419           DLOG_IF(ERROR, FAILED(hr)) << "Failed to release capture buffer";
    420 
    421           // Derive a delay estimate for the captured audio packet.
    422           // The value contains two parts (A+B), where A is the delay of the
    423           // first audio frame in the packet and B is the extra delay
    424           // contained in any stored data. Unit is in audio frames.
    425           QueryPerformanceCounter(&now_count);
    426           double audio_delay_frames =
    427               ((perf_count_to_100ns_units_ * now_count.QuadPart -
    428                 first_audio_frame_timestamp) / 10000.0) * ms_to_frame_count_ +
    429                 buffer_frame_index - num_frames_to_read;
    430 
    431           // Get a cached AGC volume level which is updated once every second
    432           // on the audio manager thread. Note that, |volume| is also updated
    433           // each time SetVolume() is called through IPC by the render-side AGC.
    434           GetAgcVolume(&volume);
    435 
    436           // Deliver captured data to the registered consumer using a packet
    437           // size which was specified at construction.
    438           uint32 delay_frames = static_cast<uint32>(audio_delay_frames + 0.5);
    439           while (buffer_frame_index >= packet_size_frames_) {
    440             // Copy data to audio bus to match the OnData interface.
    441             uint8* audio_data = reinterpret_cast<uint8*>(capture_buffer.get());
    442             audio_bus_->FromInterleaved(
    443                 audio_data, audio_bus_->frames(), format_.wBitsPerSample / 8);
    444 
    445             // Deliver data packet, delay estimation and volume level to
    446             // the user.
    447             sink_->OnData(
    448                 this, audio_bus_.get(), delay_frames * frame_size_, volume);
    449 
    450             // Store parts of the recorded data which can't be delivered
    451             // using the current packet size. The stored section will be used
    452             // either in the next while-loop iteration or in the next
    453             // capture event.
    454             memmove(&capture_buffer[0],
    455                     &capture_buffer[packet_size_bytes_],
    456                     (buffer_frame_index - packet_size_frames_) * frame_size_);
    457 
    458             buffer_frame_index -= packet_size_frames_;
    459             delay_frames -= packet_size_frames_;
    460           }
    461         }
    462         break;
    463       default:
    464         error = true;
    465         break;
    466     }
    467   }
    468 
    469   if (recording && error) {
    470     // TODO(henrika): perhaps it worth improving the cleanup here by e.g.
    471     // stopping the audio client, joining the thread etc.?
    472     NOTREACHED() << "WASAPI capturing failed with error code "
    473                  << GetLastError();
    474   }
    475 
    476   // Disable MMCSS.
    477   if (mm_task && !avrt::AvRevertMmThreadCharacteristics(mm_task)) {
    478     PLOG(WARNING) << "Failed to disable MMCSS";
    479   }
    480 }
    481 
    482 void WASAPIAudioInputStream::HandleError(HRESULT err) {
    483   NOTREACHED() << "Error code: " << err;
    484   if (sink_)
    485     sink_->OnError(this);
    486 }
    487 
    488 HRESULT WASAPIAudioInputStream::SetCaptureDevice() {
    489   DCHECK(!endpoint_device_);
    490 
    491   ScopedComPtr<IMMDeviceEnumerator> enumerator;
    492   HRESULT hr = enumerator.CreateInstance(__uuidof(MMDeviceEnumerator),
    493                                          NULL, CLSCTX_INPROC_SERVER);
    494   if (FAILED(hr))
    495     return hr;
    496 
    497   // Retrieve the IMMDevice by using the specified role or the specified
    498   // unique endpoint device-identification string.
    499 
    500   if (effects_ & AudioParameters::DUCKING) {
    501     // Ducking has been requested and it is only supported for the default
    502     // communication device.  So, let's open up the communication device and
    503     // see if the ID of that device matches the requested ID.
    504     // We consider a kDefaultDeviceId as well as an explicit device id match,
    505     // to be valid matches.
    506     hr = enumerator->GetDefaultAudioEndpoint(eCapture, eCommunications,
    507                                              endpoint_device_.Receive());
    508     if (endpoint_device_ && device_id_ != AudioManagerBase::kDefaultDeviceId) {
    509       base::win::ScopedCoMem<WCHAR> communications_id;
    510       endpoint_device_->GetId(&communications_id);
    511       if (device_id_ !=
    512           base::WideToUTF8(static_cast<WCHAR*>(communications_id))) {
    513         DLOG(WARNING) << "Ducking has been requested for a non-default device."
    514                          "Not supported.";
    515         endpoint_device_.Release();  // Fall back on code below.
    516       }
    517     }
    518   }
    519 
    520   if (!endpoint_device_) {
    521     if (device_id_ == AudioManagerBase::kDefaultDeviceId) {
    522       // Retrieve the default capture audio endpoint for the specified role.
    523       // Note that, in Windows Vista, the MMDevice API supports device roles
    524       // but the system-supplied user interface programs do not.
    525       hr = enumerator->GetDefaultAudioEndpoint(eCapture, eConsole,
    526                                                endpoint_device_.Receive());
    527     } else if (device_id_ == AudioManagerBase::kLoopbackInputDeviceId) {
    528       // Capture the default playback stream.
    529       hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole,
    530                                                endpoint_device_.Receive());
    531     } else {
    532       hr = enumerator->GetDevice(base::UTF8ToUTF16(device_id_).c_str(),
    533                                  endpoint_device_.Receive());
    534     }
    535   }
    536 
    537   if (FAILED(hr))
    538     return hr;
    539 
    540   // Verify that the audio endpoint device is active, i.e., the audio
    541   // adapter that connects to the endpoint device is present and enabled.
    542   DWORD state = DEVICE_STATE_DISABLED;
    543   hr = endpoint_device_->GetState(&state);
    544   if (FAILED(hr))
    545     return hr;
    546 
    547   if (!(state & DEVICE_STATE_ACTIVE)) {
    548     DLOG(ERROR) << "Selected capture device is not active.";
    549     hr = E_ACCESSDENIED;
    550   }
    551 
    552   return hr;
    553 }
    554 
    555 HRESULT WASAPIAudioInputStream::ActivateCaptureDevice() {
    556   // Creates and activates an IAudioClient COM object given the selected
    557   // capture endpoint device.
    558   HRESULT hr = endpoint_device_->Activate(__uuidof(IAudioClient),
    559                                           CLSCTX_INPROC_SERVER,
    560                                           NULL,
    561                                           audio_client_.ReceiveVoid());
    562   return hr;
    563 }
    564 
    565 HRESULT WASAPIAudioInputStream::GetAudioEngineStreamFormat() {
    566   HRESULT hr = S_OK;
    567 #ifndef NDEBUG
    568   // The GetMixFormat() method retrieves the stream format that the
    569   // audio engine uses for its internal processing of shared-mode streams.
    570   // The method always uses a WAVEFORMATEXTENSIBLE structure, instead
    571   // of a stand-alone WAVEFORMATEX structure, to specify the format.
    572   // An WAVEFORMATEXTENSIBLE structure can specify both the mapping of
    573   // channels to speakers and the number of bits of precision in each sample.
    574   base::win::ScopedCoMem<WAVEFORMATEXTENSIBLE> format_ex;
    575   hr = audio_client_->GetMixFormat(
    576       reinterpret_cast<WAVEFORMATEX**>(&format_ex));
    577 
    578   // See http://msdn.microsoft.com/en-us/windows/hardware/gg463006#EFH
    579   // for details on the WAVE file format.
    580   WAVEFORMATEX format = format_ex->Format;
    581   DVLOG(2) << "WAVEFORMATEX:";
    582   DVLOG(2) << "  wFormatTags    : 0x" << std::hex << format.wFormatTag;
    583   DVLOG(2) << "  nChannels      : " << format.nChannels;
    584   DVLOG(2) << "  nSamplesPerSec : " << format.nSamplesPerSec;
    585   DVLOG(2) << "  nAvgBytesPerSec: " << format.nAvgBytesPerSec;
    586   DVLOG(2) << "  nBlockAlign    : " << format.nBlockAlign;
    587   DVLOG(2) << "  wBitsPerSample : " << format.wBitsPerSample;
    588   DVLOG(2) << "  cbSize         : " << format.cbSize;
    589 
    590   DVLOG(2) << "WAVEFORMATEXTENSIBLE:";
    591   DVLOG(2) << " wValidBitsPerSample: " <<
    592       format_ex->Samples.wValidBitsPerSample;
    593   DVLOG(2) << " dwChannelMask      : 0x" << std::hex <<
    594       format_ex->dwChannelMask;
    595   if (format_ex->SubFormat == KSDATAFORMAT_SUBTYPE_PCM)
    596     DVLOG(2) << " SubFormat          : KSDATAFORMAT_SUBTYPE_PCM";
    597   else if (format_ex->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
    598     DVLOG(2) << " SubFormat          : KSDATAFORMAT_SUBTYPE_IEEE_FLOAT";
    599   else if (format_ex->SubFormat == KSDATAFORMAT_SUBTYPE_WAVEFORMATEX)
    600     DVLOG(2) << " SubFormat          : KSDATAFORMAT_SUBTYPE_WAVEFORMATEX";
    601 #endif
    602   return hr;
    603 }
    604 
    605 bool WASAPIAudioInputStream::DesiredFormatIsSupported() {
    606   // An application that uses WASAPI to manage shared-mode streams can rely
    607   // on the audio engine to perform only limited format conversions. The audio
    608   // engine can convert between a standard PCM sample size used by the
    609   // application and the floating-point samples that the engine uses for its
    610   // internal processing. However, the format for an application stream
    611   // typically must have the same number of channels and the same sample
    612   // rate as the stream format used by the device.
    613   // Many audio devices support both PCM and non-PCM stream formats. However,
    614   // the audio engine can mix only PCM streams.
    615   base::win::ScopedCoMem<WAVEFORMATEX> closest_match;
    616   HRESULT hr = audio_client_->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED,
    617                                                 &format_,
    618                                                 &closest_match);
    619   DLOG_IF(ERROR, hr == S_FALSE) << "Format is not supported "
    620                                 << "but a closest match exists.";
    621   return (hr == S_OK);
    622 }
    623 
    624 HRESULT WASAPIAudioInputStream::InitializeAudioEngine() {
    625   DWORD flags;
    626   // Use event-driven mode only fo regular input devices. For loopback the
    627   // EVENTCALLBACK flag is specified when intializing
    628   // |audio_render_client_for_loopback_|.
    629   if (device_id_ == AudioManagerBase::kLoopbackInputDeviceId) {
    630     flags = AUDCLNT_STREAMFLAGS_LOOPBACK | AUDCLNT_STREAMFLAGS_NOPERSIST;
    631   } else {
    632     flags =
    633       AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST;
    634   }
    635 
    636   // Initialize the audio stream between the client and the device.
    637   // We connect indirectly through the audio engine by using shared mode.
    638   // Note that, |hnsBufferDuration| is set of 0, which ensures that the
    639   // buffer is never smaller than the minimum buffer size needed to ensure
    640   // that glitches do not occur between the periodic processing passes.
    641   // This setting should lead to lowest possible latency.
    642   HRESULT hr = audio_client_->Initialize(AUDCLNT_SHAREMODE_SHARED,
    643                                          flags,
    644                                          0,  // hnsBufferDuration
    645                                          0,
    646                                          &format_,
    647                                          NULL);
    648   if (FAILED(hr))
    649     return hr;
    650 
    651   // Retrieve the length of the endpoint buffer shared between the client
    652   // and the audio engine. The buffer length determines the maximum amount
    653   // of capture data that the audio engine can read from the endpoint buffer
    654   // during a single processing pass.
    655   // A typical value is 960 audio frames <=> 20ms @ 48kHz sample rate.
    656   hr = audio_client_->GetBufferSize(&endpoint_buffer_size_frames_);
    657   if (FAILED(hr))
    658     return hr;
    659 
    660   DVLOG(1) << "endpoint buffer size: " << endpoint_buffer_size_frames_
    661            << " [frames]";
    662 
    663 #ifndef NDEBUG
    664   // The period between processing passes by the audio engine is fixed for a
    665   // particular audio endpoint device and represents the smallest processing
    666   // quantum for the audio engine. This period plus the stream latency between
    667   // the buffer and endpoint device represents the minimum possible latency
    668   // that an audio application can achieve.
    669   // TODO(henrika): possibly remove this section when all parts are ready.
    670   REFERENCE_TIME device_period_shared_mode = 0;
    671   REFERENCE_TIME device_period_exclusive_mode = 0;
    672   HRESULT hr_dbg = audio_client_->GetDevicePeriod(
    673       &device_period_shared_mode, &device_period_exclusive_mode);
    674   if (SUCCEEDED(hr_dbg)) {
    675     DVLOG(1) << "device period: "
    676              << static_cast<double>(device_period_shared_mode / 10000.0)
    677              << " [ms]";
    678   }
    679 
    680   REFERENCE_TIME latency = 0;
    681   hr_dbg = audio_client_->GetStreamLatency(&latency);
    682   if (SUCCEEDED(hr_dbg)) {
    683     DVLOG(1) << "stream latency: " << static_cast<double>(latency / 10000.0)
    684              << " [ms]";
    685   }
    686 #endif
    687 
    688   // Set the event handle that the audio engine will signal each time a buffer
    689   // becomes ready to be processed by the client.
    690   //
    691   // In loopback case the capture device doesn't receive any events, so we
    692   // need to create a separate playback client to get notifications. According
    693   // to MSDN:
    694   //
    695   //   A pull-mode capture client does not receive any events when a stream is
    696   //   initialized with event-driven buffering and is loopback-enabled. To
    697   //   work around this, initialize a render stream in event-driven mode. Each
    698   //   time the client receives an event for the render stream, it must signal
    699   //   the capture client to run the capture thread that reads the next set of
    700   //   samples from the capture endpoint buffer.
    701   //
    702   // http://msdn.microsoft.com/en-us/library/windows/desktop/dd316551(v=vs.85).aspx
    703   if (device_id_ == AudioManagerBase::kLoopbackInputDeviceId) {
    704     hr = endpoint_device_->Activate(
    705         __uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL,
    706         audio_render_client_for_loopback_.ReceiveVoid());
    707     if (FAILED(hr))
    708       return hr;
    709 
    710     hr = audio_render_client_for_loopback_->Initialize(
    711         AUDCLNT_SHAREMODE_SHARED,
    712         AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST,
    713         0, 0, &format_, NULL);
    714     if (FAILED(hr))
    715       return hr;
    716 
    717     hr = audio_render_client_for_loopback_->SetEventHandle(
    718         audio_samples_ready_event_.Get());
    719   } else {
    720     hr = audio_client_->SetEventHandle(audio_samples_ready_event_.Get());
    721   }
    722 
    723   if (FAILED(hr))
    724     return hr;
    725 
    726   // Get access to the IAudioCaptureClient interface. This interface
    727   // enables us to read input data from the capture endpoint buffer.
    728   hr = audio_client_->GetService(__uuidof(IAudioCaptureClient),
    729                                  audio_capture_client_.ReceiveVoid());
    730   if (FAILED(hr))
    731     return hr;
    732 
    733   // Obtain a reference to the ISimpleAudioVolume interface which enables
    734   // us to control the master volume level of an audio session.
    735   hr = audio_client_->GetService(__uuidof(ISimpleAudioVolume),
    736                                  simple_audio_volume_.ReceiveVoid());
    737   return hr;
    738 }
    739 
    740 }  // namespace media
    741