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 "base/memory/scoped_ptr.h"
      6 #include "base/synchronization/waitable_event.h"
      7 #include "base/win/scoped_com_initializer.h"
      8 #include "base/win/scoped_handle.h"
      9 #include "media/audio/win/core_audio_util_win.h"
     10 #include "testing/gmock/include/gmock/gmock.h"
     11 #include "testing/gtest/include/gtest/gtest.h"
     12 
     13 using base::win::ScopedCOMInitializer;
     14 
     15 namespace media {
     16 
     17 class CoreAudioUtilWinTest : public ::testing::Test {
     18  protected:
     19   // The test runs on a COM thread in the multithreaded apartment (MTA).
     20   // If we don't initialize the COM library on a thread before using COM,
     21   // all function calls will return CO_E_NOTINITIALIZED.
     22   CoreAudioUtilWinTest()
     23       : com_init_(ScopedCOMInitializer::kMTA) {
     24     DCHECK(com_init_.succeeded());
     25   }
     26   virtual ~CoreAudioUtilWinTest() {}
     27 
     28   bool CanRunAudioTest() {
     29     bool core_audio = CoreAudioUtil::IsSupported();
     30     if (!core_audio)
     31       return false;
     32     int capture_devices = CoreAudioUtil::NumberOfActiveDevices(eCapture);
     33     int render_devices = CoreAudioUtil::NumberOfActiveDevices(eRender);
     34     return ((capture_devices > 0) && (render_devices > 0));
     35   }
     36 
     37   ScopedCOMInitializer com_init_;
     38 };
     39 
     40 TEST_F(CoreAudioUtilWinTest, NumberOfActiveDevices) {
     41   if (!CanRunAudioTest())
     42     return;
     43 
     44   int render_devices = CoreAudioUtil::NumberOfActiveDevices(eRender);
     45   EXPECT_GT(render_devices, 0);
     46   int capture_devices = CoreAudioUtil::NumberOfActiveDevices(eCapture);
     47   EXPECT_GT(capture_devices, 0);
     48   int total_devices = CoreAudioUtil::NumberOfActiveDevices(eAll);
     49   EXPECT_EQ(total_devices, render_devices + capture_devices);
     50 }
     51 
     52 TEST_F(CoreAudioUtilWinTest, CreateDeviceEnumerator) {
     53   if (!CanRunAudioTest())
     54     return;
     55 
     56   ScopedComPtr<IMMDeviceEnumerator> enumerator =
     57       CoreAudioUtil::CreateDeviceEnumerator();
     58   EXPECT_TRUE(enumerator);
     59 }
     60 
     61 TEST_F(CoreAudioUtilWinTest, CreateDefaultDevice) {
     62   if (!CanRunAudioTest())
     63     return;
     64 
     65   struct {
     66     EDataFlow flow;
     67     ERole role;
     68   } data[] = {
     69     {eRender, eConsole},
     70     {eRender, eCommunications},
     71     {eRender, eMultimedia},
     72     {eCapture, eConsole},
     73     {eCapture, eCommunications},
     74     {eCapture, eMultimedia}
     75   };
     76 
     77   // Create default devices for all flow/role combinations above.
     78   ScopedComPtr<IMMDevice> audio_device;
     79   for (int i = 0; i < arraysize(data); ++i) {
     80     audio_device =
     81         CoreAudioUtil::CreateDefaultDevice(data[i].flow, data[i].role);
     82     EXPECT_TRUE(audio_device);
     83     EXPECT_EQ(data[i].flow, CoreAudioUtil::GetDataFlow(audio_device));
     84   }
     85 
     86   // Only eRender and eCapture are allowed as flow parameter.
     87   audio_device = CoreAudioUtil::CreateDefaultDevice(eAll, eConsole);
     88   EXPECT_FALSE(audio_device);
     89 }
     90 
     91 TEST_F(CoreAudioUtilWinTest, CreateDevice) {
     92   if (!CanRunAudioTest())
     93     return;
     94 
     95   // Get name and ID of default device used for playback.
     96   ScopedComPtr<IMMDevice> default_render_device =
     97       CoreAudioUtil::CreateDefaultDevice(eRender, eConsole);
     98   AudioDeviceName default_render_name;
     99   EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDeviceName(default_render_device,
    100                                                      &default_render_name)));
    101 
    102   // Use the uniqe ID as input to CreateDevice() and create a corresponding
    103   // IMMDevice.
    104   ScopedComPtr<IMMDevice> audio_device =
    105       CoreAudioUtil::CreateDevice(default_render_name.unique_id);
    106   EXPECT_TRUE(audio_device);
    107 
    108   // Verify that the two IMMDevice interfaces represents the same endpoint
    109   // by comparing their unique IDs.
    110   AudioDeviceName device_name;
    111   EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDeviceName(audio_device,
    112                                                      &device_name)));
    113   EXPECT_EQ(default_render_name.unique_id, device_name.unique_id);
    114 }
    115 
    116 TEST_F(CoreAudioUtilWinTest, GetDefaultDeviceName) {
    117   if (!CanRunAudioTest())
    118     return;
    119 
    120   struct {
    121     EDataFlow flow;
    122     ERole role;
    123   } data[] = {
    124     {eRender, eConsole},
    125     {eRender, eCommunications},
    126     {eCapture, eConsole},
    127     {eCapture, eCommunications}
    128   };
    129 
    130   // Get name and ID of default devices for all flow/role combinations above.
    131   ScopedComPtr<IMMDevice> audio_device;
    132   AudioDeviceName device_name;
    133   for (int i = 0; i < arraysize(data); ++i) {
    134     audio_device =
    135         CoreAudioUtil::CreateDefaultDevice(data[i].flow, data[i].role);
    136     EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDeviceName(audio_device,
    137                                                        &device_name)));
    138     EXPECT_FALSE(device_name.device_name.empty());
    139     EXPECT_FALSE(device_name.unique_id.empty());
    140   }
    141 }
    142 
    143 TEST_F(CoreAudioUtilWinTest, GetFriendlyName) {
    144   if (!CanRunAudioTest())
    145     return;
    146 
    147   // Get name and ID of default device used for recording.
    148   ScopedComPtr<IMMDevice> audio_device =
    149       CoreAudioUtil::CreateDefaultDevice(eCapture, eConsole);
    150   AudioDeviceName device_name;
    151   HRESULT hr = CoreAudioUtil::GetDeviceName(audio_device, &device_name);
    152   EXPECT_TRUE(SUCCEEDED(hr));
    153 
    154   // Use unique ID as input to GetFriendlyName() and compare the result
    155   // with the already obtained friendly name for the default capture device.
    156   std::string friendly_name = CoreAudioUtil::GetFriendlyName(
    157       device_name.unique_id);
    158   EXPECT_EQ(friendly_name, device_name.device_name);
    159 
    160   // Same test as above but for playback.
    161   audio_device = CoreAudioUtil::CreateDefaultDevice(eRender, eConsole);
    162   hr = CoreAudioUtil::GetDeviceName(audio_device, &device_name);
    163   EXPECT_TRUE(SUCCEEDED(hr));
    164   friendly_name = CoreAudioUtil::GetFriendlyName(device_name.unique_id);
    165   EXPECT_EQ(friendly_name, device_name.device_name);
    166 }
    167 
    168 TEST_F(CoreAudioUtilWinTest, DeviceIsDefault) {
    169   if (!CanRunAudioTest())
    170     return;
    171 
    172   // Verify that the default render device is correctly identified as a
    173   // default device.
    174   ScopedComPtr<IMMDevice> audio_device =
    175       CoreAudioUtil::CreateDefaultDevice(eRender, eConsole);
    176   AudioDeviceName name;
    177   EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDeviceName(audio_device, &name)));
    178   const std::string id = name.unique_id;
    179   EXPECT_TRUE(CoreAudioUtil::DeviceIsDefault(eRender, eConsole, id));
    180   EXPECT_FALSE(CoreAudioUtil::DeviceIsDefault(eCapture, eConsole, id));
    181 }
    182 
    183 TEST_F(CoreAudioUtilWinTest, CreateDefaultClient) {
    184   if (!CanRunAudioTest())
    185     return;
    186 
    187   EDataFlow data[] = {eRender, eCapture};
    188 
    189   for (int i = 0; i < arraysize(data); ++i) {
    190     ScopedComPtr<IAudioClient> client;
    191     client = CoreAudioUtil::CreateDefaultClient(data[i], eConsole);
    192     EXPECT_TRUE(client);
    193   }
    194 }
    195 
    196 TEST_F(CoreAudioUtilWinTest, CreateClient) {
    197   if (!CanRunAudioTest())
    198     return;
    199 
    200   EDataFlow data[] = {eRender, eCapture};
    201 
    202   for (int i = 0; i < arraysize(data); ++i) {
    203     ScopedComPtr<IMMDevice> device;
    204     ScopedComPtr<IAudioClient> client;
    205     device = CoreAudioUtil::CreateDefaultDevice(data[i], eConsole);
    206     EXPECT_TRUE(device);
    207     EXPECT_EQ(data[i], CoreAudioUtil::GetDataFlow(device));
    208     client = CoreAudioUtil::CreateClient(device);
    209     EXPECT_TRUE(client);
    210   }
    211 }
    212 
    213 TEST_F(CoreAudioUtilWinTest, GetSharedModeMixFormat) {
    214   if (!CanRunAudioTest())
    215     return;
    216 
    217   ScopedComPtr<IMMDevice> device;
    218   ScopedComPtr<IAudioClient> client;
    219   device = CoreAudioUtil::CreateDefaultDevice(eRender, eConsole);
    220   EXPECT_TRUE(device);
    221   client = CoreAudioUtil::CreateClient(device);
    222   EXPECT_TRUE(client);
    223 
    224   // Perform a simple sanity test of the aquired format structure.
    225   WAVEFORMATPCMEX format;
    226   EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client,
    227                                                               &format)));
    228   EXPECT_GE(format.Format.nChannels, 1);
    229   EXPECT_GE(format.Format.nSamplesPerSec, 8000u);
    230   EXPECT_GE(format.Format.wBitsPerSample, 16);
    231   EXPECT_GE(format.Samples.wValidBitsPerSample, 16);
    232   EXPECT_EQ(format.Format.wFormatTag, WAVE_FORMAT_EXTENSIBLE);
    233 }
    234 
    235 TEST_F(CoreAudioUtilWinTest, IsChannelLayoutSupported) {
    236   if (!CanRunAudioTest())
    237     return;
    238 
    239   // The preferred channel layout should always be supported. Being supported
    240   // means that it is possible to initialize a shared mode stream with the
    241   // particular channel layout.
    242   AudioParameters mix_params;
    243   HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters(eRender, eConsole,
    244                                                           &mix_params);
    245   EXPECT_TRUE(SUCCEEDED(hr));
    246   EXPECT_TRUE(mix_params.IsValid());
    247   EXPECT_TRUE(CoreAudioUtil::IsChannelLayoutSupported(
    248       eRender, eConsole, mix_params.channel_layout()));
    249 
    250   // Check if it is possible to modify the channel layout to stereo for a
    251   // device which reports that it prefers to be openen up in an other
    252   // channel configuration.
    253   if (mix_params.channel_layout() != CHANNEL_LAYOUT_STEREO) {
    254     ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
    255     // TODO(henrika): it might be too pessimistic to assume false as return
    256     // value here.
    257     EXPECT_FALSE(CoreAudioUtil::IsChannelLayoutSupported(
    258         eRender, eConsole, channel_layout));
    259   }
    260 }
    261 
    262 TEST_F(CoreAudioUtilWinTest, GetDevicePeriod) {
    263   if (!CanRunAudioTest())
    264     return;
    265 
    266   EDataFlow data[] = {eRender, eCapture};
    267 
    268   // Verify that the device periods are valid for the default render and
    269   // capture devices.
    270   for (int i = 0; i < arraysize(data); ++i) {
    271     ScopedComPtr<IAudioClient> client;
    272     REFERENCE_TIME shared_time_period = 0;
    273     REFERENCE_TIME exclusive_time_period = 0;
    274     client = CoreAudioUtil::CreateDefaultClient(data[i], eConsole);
    275     EXPECT_TRUE(client);
    276     EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDevicePeriod(
    277         client, AUDCLNT_SHAREMODE_SHARED, &shared_time_period)));
    278     EXPECT_GT(shared_time_period, 0);
    279     EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetDevicePeriod(
    280         client, AUDCLNT_SHAREMODE_EXCLUSIVE, &exclusive_time_period)));
    281     EXPECT_GT(exclusive_time_period, 0);
    282     EXPECT_LE(exclusive_time_period, shared_time_period);
    283   }
    284 }
    285 
    286 TEST_F(CoreAudioUtilWinTest, GetPreferredAudioParameters) {
    287   if (!CanRunAudioTest())
    288     return;
    289 
    290   EDataFlow data[] = {eRender, eCapture};
    291 
    292   // Verify that the preferred audio parameters are OK for the default render
    293   // and capture devices.
    294   for (int i = 0; i < arraysize(data); ++i) {
    295     ScopedComPtr<IAudioClient> client;
    296     AudioParameters params;
    297     client = CoreAudioUtil::CreateDefaultClient(data[i], eConsole);
    298     EXPECT_TRUE(client);
    299     EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters(client,
    300                                                                      &params)));
    301     EXPECT_TRUE(params.IsValid());
    302   }
    303 }
    304 
    305 TEST_F(CoreAudioUtilWinTest, SharedModeInitialize) {
    306   if (!CanRunAudioTest())
    307     return;
    308 
    309   ScopedComPtr<IAudioClient> client;
    310   client = CoreAudioUtil::CreateDefaultClient(eRender, eConsole);
    311   EXPECT_TRUE(client);
    312 
    313   WAVEFORMATPCMEX format;
    314   EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client,
    315                                                               &format)));
    316 
    317   // Perform a shared-mode initialization without event-driven buffer handling.
    318   uint32 endpoint_buffer_size = 0;
    319   HRESULT hr = CoreAudioUtil::SharedModeInitialize(client, &format, NULL,
    320                                                    &endpoint_buffer_size);
    321   EXPECT_TRUE(SUCCEEDED(hr));
    322   EXPECT_GT(endpoint_buffer_size, 0u);
    323 
    324   // It is only possible to create a client once.
    325   hr = CoreAudioUtil::SharedModeInitialize(client, &format, NULL,
    326                                            &endpoint_buffer_size);
    327   EXPECT_FALSE(SUCCEEDED(hr));
    328   EXPECT_EQ(hr, AUDCLNT_E_ALREADY_INITIALIZED);
    329 
    330   // Verify that it is possible to reinitialize the client after releasing it.
    331   client = CoreAudioUtil::CreateDefaultClient(eRender, eConsole);
    332   EXPECT_TRUE(client);
    333   hr = CoreAudioUtil::SharedModeInitialize(client, &format, NULL,
    334                                            &endpoint_buffer_size);
    335   EXPECT_TRUE(SUCCEEDED(hr));
    336   EXPECT_GT(endpoint_buffer_size, 0u);
    337 
    338   // Use a non-supported format and verify that initialization fails.
    339   // A simple way to emulate an invalid format is to use the shared-mode
    340   // mixing format and modify the preferred sample.
    341   client = CoreAudioUtil::CreateDefaultClient(eRender, eConsole);
    342   EXPECT_TRUE(client);
    343   format.Format.nSamplesPerSec = format.Format.nSamplesPerSec + 1;
    344   EXPECT_FALSE(CoreAudioUtil::IsFormatSupported(
    345                   client, AUDCLNT_SHAREMODE_SHARED, &format));
    346   hr = CoreAudioUtil::SharedModeInitialize(client, &format, NULL,
    347                                            &endpoint_buffer_size);
    348   EXPECT_TRUE(FAILED(hr));
    349   EXPECT_EQ(hr, E_INVALIDARG);
    350 
    351   // Finally, perform a shared-mode initialization using event-driven buffer
    352   // handling. The event handle will be signaled when an audio buffer is ready
    353   // to be processed by the client (not verified here).
    354   // The event handle should be in the nonsignaled state.
    355   base::win::ScopedHandle event_handle(::CreateEvent(NULL, TRUE, FALSE, NULL));
    356   client = CoreAudioUtil::CreateDefaultClient(eRender, eConsole);
    357   EXPECT_TRUE(client);
    358   EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client,
    359                                                               &format)));
    360   EXPECT_TRUE(CoreAudioUtil::IsFormatSupported(
    361                   client, AUDCLNT_SHAREMODE_SHARED, &format));
    362   hr = CoreAudioUtil::SharedModeInitialize(client, &format, event_handle.Get(),
    363                                            &endpoint_buffer_size);
    364   EXPECT_TRUE(SUCCEEDED(hr));
    365   EXPECT_GT(endpoint_buffer_size, 0u);
    366 }
    367 
    368 TEST_F(CoreAudioUtilWinTest, CreateRenderAndCaptureClients) {
    369   if (!CanRunAudioTest())
    370     return;
    371 
    372   EDataFlow data[] = {eRender, eCapture};
    373 
    374   WAVEFORMATPCMEX format;
    375   uint32 endpoint_buffer_size = 0;
    376 
    377   for (int i = 0; i < arraysize(data); ++i) {
    378     ScopedComPtr<IAudioClient> client;
    379     ScopedComPtr<IAudioRenderClient> render_client;
    380     ScopedComPtr<IAudioCaptureClient> capture_client;
    381 
    382     client = CoreAudioUtil::CreateDefaultClient(data[i], eConsole);
    383     EXPECT_TRUE(client);
    384     EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client,
    385                                                                 &format)));
    386     if (data[i] == eRender) {
    387       // It is not possible to create a render client using an unitialized
    388       // client interface.
    389       render_client = CoreAudioUtil::CreateRenderClient(client);
    390       EXPECT_FALSE(render_client);
    391 
    392       // Do a proper initialization and verify that it works this time.
    393       CoreAudioUtil::SharedModeInitialize(client, &format, NULL,
    394                                           &endpoint_buffer_size);
    395       render_client = CoreAudioUtil::CreateRenderClient(client);
    396       EXPECT_TRUE(render_client);
    397       EXPECT_GT(endpoint_buffer_size, 0u);
    398     } else if (data[i] == eCapture) {
    399       // It is not possible to create a capture client using an unitialized
    400       // client interface.
    401       capture_client = CoreAudioUtil::CreateCaptureClient(client);
    402       EXPECT_FALSE(capture_client);
    403 
    404       // Do a proper initialization and verify that it works this time.
    405       CoreAudioUtil::SharedModeInitialize(client, &format, NULL,
    406                                           &endpoint_buffer_size);
    407       capture_client = CoreAudioUtil::CreateCaptureClient(client);
    408       EXPECT_TRUE(capture_client);
    409       EXPECT_GT(endpoint_buffer_size, 0u);
    410     }
    411   }
    412 }
    413 
    414 TEST_F(CoreAudioUtilWinTest, FillRenderEndpointBufferWithSilence) {
    415   if (!CanRunAudioTest())
    416     return;
    417 
    418   // Create default clients using the default mixing format for shared mode.
    419   ScopedComPtr<IAudioClient> client(
    420       CoreAudioUtil::CreateDefaultClient(eRender, eConsole));
    421   EXPECT_TRUE(client);
    422 
    423   WAVEFORMATPCMEX format;
    424   uint32 endpoint_buffer_size = 0;
    425   EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetSharedModeMixFormat(client,
    426                                                               &format)));
    427   CoreAudioUtil::SharedModeInitialize(client, &format, NULL,
    428                                       &endpoint_buffer_size);
    429   EXPECT_GT(endpoint_buffer_size, 0u);
    430 
    431   ScopedComPtr<IAudioRenderClient> render_client(
    432       CoreAudioUtil::CreateRenderClient(client));
    433   EXPECT_TRUE(render_client);
    434 
    435   // The endpoint audio buffer should not be filled up by default after being
    436   // created.
    437   UINT32 num_queued_frames = 0;
    438   client->GetCurrentPadding(&num_queued_frames);
    439   EXPECT_EQ(num_queued_frames, 0u);
    440 
    441   // Fill it up with zeros and verify that the buffer is full.
    442   // It is not possible to verify that the actual data consists of zeros
    443   // since we can't access data that has already been sent to the endpoint
    444   // buffer.
    445   EXPECT_TRUE(CoreAudioUtil::FillRenderEndpointBufferWithSilence(
    446                   client, render_client));
    447   client->GetCurrentPadding(&num_queued_frames);
    448   EXPECT_EQ(num_queued_frames, endpoint_buffer_size);
    449 }
    450 
    451 //
    452 
    453 }  // namespace media
    454