- add sources.
[platform/framework/web/crosswalk.git] / src / media / audio / win / core_audio_util_win.cc
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/core_audio_util_win.h"
6
7 #include <audioclient.h>
8 #include <devicetopology.h>
9 #include <functiondiscoverykeys_devpkey.h>
10
11 #include "base/command_line.h"
12 #include "base/logging.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/win/scoped_co_mem.h"
16 #include "base/win/scoped_handle.h"
17 #include "base/win/scoped_propvariant.h"
18 #include "base/win/windows_version.h"
19 #include "media/base/media_switches.h"
20
21 using base::win::ScopedCoMem;
22 using base::win::ScopedHandle;
23
24 namespace media {
25
26 enum { KSAUDIO_SPEAKER_UNSUPPORTED = 0 };
27
28 // Converts Microsoft's channel configuration to ChannelLayout.
29 // This mapping is not perfect but the best we can do given the current
30 // ChannelLayout enumerator and the Windows-specific speaker configurations
31 // defined in ksmedia.h. Don't assume that the channel ordering in
32 // ChannelLayout is exactly the same as the Windows specific configuration.
33 // As an example: KSAUDIO_SPEAKER_7POINT1_SURROUND is mapped to
34 // CHANNEL_LAYOUT_7_1 but the positions of Back L, Back R and Side L, Side R
35 // speakers are different in these two definitions.
36 static ChannelLayout ChannelConfigToChannelLayout(ChannelConfig config) {
37   switch (config) {
38     case KSAUDIO_SPEAKER_DIRECTOUT:
39       DVLOG(2) << "KSAUDIO_SPEAKER_DIRECTOUT=>CHANNEL_LAYOUT_NONE";
40       return CHANNEL_LAYOUT_NONE;
41     case KSAUDIO_SPEAKER_MONO:
42       DVLOG(2) << "KSAUDIO_SPEAKER_MONO=>CHANNEL_LAYOUT_MONO";
43       return CHANNEL_LAYOUT_MONO;
44     case KSAUDIO_SPEAKER_STEREO:
45       DVLOG(2) << "KSAUDIO_SPEAKER_STEREO=>CHANNEL_LAYOUT_STEREO";
46       return CHANNEL_LAYOUT_STEREO;
47     case KSAUDIO_SPEAKER_QUAD:
48       DVLOG(2) << "KSAUDIO_SPEAKER_QUAD=>CHANNEL_LAYOUT_QUAD";
49       return CHANNEL_LAYOUT_QUAD;
50     case KSAUDIO_SPEAKER_SURROUND:
51       DVLOG(2) << "KSAUDIO_SPEAKER_SURROUND=>CHANNEL_LAYOUT_4_0";
52       return CHANNEL_LAYOUT_4_0;
53     case KSAUDIO_SPEAKER_5POINT1:
54       DVLOG(2) << "KSAUDIO_SPEAKER_5POINT1=>CHANNEL_LAYOUT_5_1_BACK";
55       return CHANNEL_LAYOUT_5_1_BACK;
56     case KSAUDIO_SPEAKER_5POINT1_SURROUND:
57       DVLOG(2) << "KSAUDIO_SPEAKER_5POINT1_SURROUND=>CHANNEL_LAYOUT_5_1";
58       return CHANNEL_LAYOUT_5_1;
59     case KSAUDIO_SPEAKER_7POINT1:
60       DVLOG(2) << "KSAUDIO_SPEAKER_7POINT1=>CHANNEL_LAYOUT_7_1_WIDE";
61       return CHANNEL_LAYOUT_7_1_WIDE;
62     case KSAUDIO_SPEAKER_7POINT1_SURROUND:
63       DVLOG(2) << "KSAUDIO_SPEAKER_7POINT1_SURROUND=>CHANNEL_LAYOUT_7_1";
64       return CHANNEL_LAYOUT_7_1;
65     default:
66       DVLOG(2) << "Unsupported channel configuration: " << config;
67       return CHANNEL_LAYOUT_UNSUPPORTED;
68   }
69 }
70
71 // TODO(henrika): add mapping for all types in the ChannelLayout enumerator.
72 static ChannelConfig ChannelLayoutToChannelConfig(ChannelLayout layout) {
73   switch (layout) {
74     case CHANNEL_LAYOUT_NONE:
75       DVLOG(2) << "CHANNEL_LAYOUT_NONE=>KSAUDIO_SPEAKER_UNSUPPORTED";
76       return KSAUDIO_SPEAKER_UNSUPPORTED;
77     case CHANNEL_LAYOUT_UNSUPPORTED:
78       DVLOG(2) << "CHANNEL_LAYOUT_UNSUPPORTED=>KSAUDIO_SPEAKER_UNSUPPORTED";
79       return KSAUDIO_SPEAKER_UNSUPPORTED;
80     case CHANNEL_LAYOUT_MONO:
81       DVLOG(2) << "CHANNEL_LAYOUT_MONO=>KSAUDIO_SPEAKER_MONO";
82       return KSAUDIO_SPEAKER_MONO;
83     case CHANNEL_LAYOUT_STEREO:
84       DVLOG(2) << "CHANNEL_LAYOUT_STEREO=>KSAUDIO_SPEAKER_STEREO";
85       return KSAUDIO_SPEAKER_STEREO;
86     case CHANNEL_LAYOUT_QUAD:
87       DVLOG(2) << "CHANNEL_LAYOUT_QUAD=>KSAUDIO_SPEAKER_QUAD";
88       return KSAUDIO_SPEAKER_QUAD;
89     case CHANNEL_LAYOUT_4_0:
90       DVLOG(2) << "CHANNEL_LAYOUT_4_0=>KSAUDIO_SPEAKER_SURROUND";
91       return KSAUDIO_SPEAKER_SURROUND;
92     case CHANNEL_LAYOUT_5_1_BACK:
93       DVLOG(2) << "CHANNEL_LAYOUT_5_1_BACK=>KSAUDIO_SPEAKER_5POINT1";
94       return KSAUDIO_SPEAKER_5POINT1;
95     case CHANNEL_LAYOUT_5_1:
96       DVLOG(2) << "CHANNEL_LAYOUT_5_1=>KSAUDIO_SPEAKER_5POINT1_SURROUND";
97       return KSAUDIO_SPEAKER_5POINT1_SURROUND;
98     case CHANNEL_LAYOUT_7_1_WIDE:
99       DVLOG(2) << "CHANNEL_LAYOUT_7_1_WIDE=>KSAUDIO_SPEAKER_7POINT1";
100       return KSAUDIO_SPEAKER_7POINT1;
101     case CHANNEL_LAYOUT_7_1:
102       DVLOG(2) << "CHANNEL_LAYOUT_7_1=>KSAUDIO_SPEAKER_7POINT1_SURROUND";
103       return KSAUDIO_SPEAKER_7POINT1_SURROUND;
104     default:
105       DVLOG(2) << "Unsupported channel layout: " << layout;
106       return KSAUDIO_SPEAKER_UNSUPPORTED;
107   }
108 }
109
110 static std::ostream& operator<<(std::ostream& os,
111                                 const WAVEFORMATPCMEX& format) {
112   os << "wFormatTag: 0x" << std::hex << format.Format.wFormatTag
113      << ", nChannels: " << std::dec << format.Format.nChannels
114      << ", nSamplesPerSec: " << format.Format.nSamplesPerSec
115      << ", nAvgBytesPerSec: " << format.Format.nAvgBytesPerSec
116      << ", nBlockAlign: " << format.Format.nBlockAlign
117      << ", wBitsPerSample: " << format.Format.wBitsPerSample
118      << ", cbSize: " << format.Format.cbSize
119      << ", wValidBitsPerSample: " << format.Samples.wValidBitsPerSample
120      << ", dwChannelMask: 0x" << std::hex << format.dwChannelMask;
121   return os;
122 }
123
124 static bool LoadAudiosesDll() {
125   static const wchar_t* const kAudiosesDLL =
126       L"%WINDIR%\\system32\\audioses.dll";
127
128   wchar_t path[MAX_PATH] = {0};
129   ExpandEnvironmentStringsW(kAudiosesDLL, path, arraysize(path));
130   return (LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) != NULL);
131 }
132
133 static bool CanCreateDeviceEnumerator() {
134   ScopedComPtr<IMMDeviceEnumerator> device_enumerator;
135   HRESULT hr = device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator),
136                                                 NULL, CLSCTX_INPROC_SERVER);
137
138   // If we hit CO_E_NOTINITIALIZED, CoInitialize has not been called and it
139   // must be called at least once for each thread that uses the COM library.
140   CHECK_NE(hr, CO_E_NOTINITIALIZED);
141
142   return SUCCEEDED(hr);
143 }
144
145 static std::string GetDeviceID(IMMDevice* device) {
146   ScopedCoMem<WCHAR> device_id_com;
147   std::string device_id;
148   if (SUCCEEDED(device->GetId(&device_id_com)))
149     WideToUTF8(device_id_com, wcslen(device_id_com), &device_id);
150   return device_id;
151 }
152
153 bool CoreAudioUtil::IsSupported() {
154   // It is possible to force usage of WaveXxx APIs by using a command line flag.
155   const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
156   if (cmd_line->HasSwitch(switches::kForceWaveAudio)) {
157     LOG(WARNING) << "Forcing usage of Windows WaveXxx APIs";
158     return false;
159   }
160
161   // Microsoft does not plan to make the Core Audio APIs available for use
162   // with earlier versions of Windows, including Microsoft Windows Server 2003,
163   // Windows XP, Windows Millennium Edition, Windows 2000, and Windows 98.
164   if (base::win::GetVersion() < base::win::VERSION_VISTA)
165     return false;
166
167   // The audio core APIs are implemented in the Mmdevapi.dll and Audioses.dll
168   // system components.
169   // Dependency Walker shows that it is enough to verify possibility to load
170   // the Audioses DLL since it depends on Mmdevapi.dll.
171   // See http://crbug.com/166397 why this extra step is required to guarantee
172   // Core Audio support.
173   static bool g_audioses_dll_available = LoadAudiosesDll();
174   if (!g_audioses_dll_available)
175     return false;
176
177   // Being able to load the Audioses.dll does not seem to be sufficient for
178   // all devices to guarantee Core Audio support. To be 100%, we also verify
179   // that it is possible to a create the IMMDeviceEnumerator interface. If this
180   // works as well we should be home free.
181   static bool g_can_create_device_enumerator = CanCreateDeviceEnumerator();
182   LOG_IF(ERROR, !g_can_create_device_enumerator)
183       << "Failed to create Core Audio device enumerator on thread with ID "
184       << GetCurrentThreadId();
185   return g_can_create_device_enumerator;
186 }
187
188 base::TimeDelta CoreAudioUtil::RefererenceTimeToTimeDelta(REFERENCE_TIME time) {
189   // Each unit of reference time is 100 nanoseconds <=> 0.1 microsecond.
190   return base::TimeDelta::FromMicroseconds(0.1 * time + 0.5);
191 }
192
193 AUDCLNT_SHAREMODE CoreAudioUtil::GetShareMode() {
194   const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
195   if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio))
196     return AUDCLNT_SHAREMODE_EXCLUSIVE;
197   return AUDCLNT_SHAREMODE_SHARED;
198 }
199
200 int CoreAudioUtil::NumberOfActiveDevices(EDataFlow data_flow) {
201   DCHECK(IsSupported());
202   // Create the IMMDeviceEnumerator interface.
203   ScopedComPtr<IMMDeviceEnumerator> device_enumerator =
204       CreateDeviceEnumerator();
205   if (!device_enumerator)
206     return 0;
207
208   // Generate a collection of active (present and not disabled) audio endpoint
209   // devices for the specified data-flow direction.
210   // This method will succeed even if all devices are disabled.
211   ScopedComPtr<IMMDeviceCollection> collection;
212   HRESULT hr = device_enumerator->EnumAudioEndpoints(data_flow,
213                                                      DEVICE_STATE_ACTIVE,
214                                                      collection.Receive());
215   if (FAILED(hr)) {
216     LOG(ERROR) << "IMMDeviceCollection::EnumAudioEndpoints: " << std::hex << hr;
217     return 0;
218   }
219
220   // Retrieve the number of active audio devices for the specified direction
221   UINT number_of_active_devices = 0;
222   collection->GetCount(&number_of_active_devices);
223   DVLOG(2) << ((data_flow == eCapture) ? "[in ] " : "[out] ")
224            << "number of devices: " << number_of_active_devices;
225   return static_cast<int>(number_of_active_devices);
226 }
227
228 ScopedComPtr<IMMDeviceEnumerator> CoreAudioUtil::CreateDeviceEnumerator() {
229   DCHECK(IsSupported());
230   ScopedComPtr<IMMDeviceEnumerator> device_enumerator;
231   HRESULT hr = device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator),
232                                                 NULL, CLSCTX_INPROC_SERVER);
233   CHECK(SUCCEEDED(hr));
234   return device_enumerator;
235 }
236
237 ScopedComPtr<IMMDevice> CoreAudioUtil::CreateDefaultDevice(EDataFlow data_flow,
238                                                            ERole role) {
239   DCHECK(IsSupported());
240   ScopedComPtr<IMMDevice> endpoint_device;
241
242   // Create the IMMDeviceEnumerator interface.
243   ScopedComPtr<IMMDeviceEnumerator> device_enumerator =
244       CreateDeviceEnumerator();
245   if (!device_enumerator)
246     return endpoint_device;
247
248   // Retrieve the default audio endpoint for the specified data-flow
249   // direction and role.
250   HRESULT hr = device_enumerator->GetDefaultAudioEndpoint(
251       data_flow, role, endpoint_device.Receive());
252
253   if (FAILED(hr)) {
254     DVLOG(1) << "IMMDeviceEnumerator::GetDefaultAudioEndpoint: "
255              << std::hex << hr;
256     return endpoint_device;
257   }
258
259   // Verify that the audio endpoint device is active, i.e., that the audio
260   // adapter that connects to the endpoint device is present and enabled.
261   DWORD state = DEVICE_STATE_DISABLED;
262   hr = endpoint_device->GetState(&state);
263   if (SUCCEEDED(hr)) {
264     if (!(state & DEVICE_STATE_ACTIVE)) {
265       DVLOG(1) << "Selected endpoint device is not active";
266       endpoint_device.Release();
267     }
268   }
269   return endpoint_device;
270 }
271
272 std::string CoreAudioUtil::GetDefaultOutputDeviceID() {
273   DCHECK(IsSupported());
274   ScopedComPtr<IMMDevice> device(CreateDefaultDevice(eRender, eConsole));
275   return device ? GetDeviceID(device) : std::string();
276 }
277
278 ScopedComPtr<IMMDevice> CoreAudioUtil::CreateDevice(
279     const std::string& device_id) {
280   DCHECK(IsSupported());
281   ScopedComPtr<IMMDevice> endpoint_device;
282
283   // Create the IMMDeviceEnumerator interface.
284   ScopedComPtr<IMMDeviceEnumerator> device_enumerator =
285       CreateDeviceEnumerator();
286   if (!device_enumerator)
287     return endpoint_device;
288
289   // Retrieve an audio device specified by an endpoint device-identification
290   // string.
291   HRESULT hr = device_enumerator->GetDevice(UTF8ToUTF16(device_id).c_str(),
292                                             endpoint_device.Receive());
293   DVLOG_IF(1, FAILED(hr)) << "IMMDeviceEnumerator::GetDevice: "
294                           << std::hex << hr;
295   return endpoint_device;
296 }
297
298 HRESULT CoreAudioUtil::GetDeviceName(IMMDevice* device, AudioDeviceName* name) {
299   DCHECK(IsSupported());
300
301   // Retrieve unique name of endpoint device.
302   // Example: "{0.0.1.00000000}.{8db6020f-18e3-4f25-b6f5-7726c9122574}".
303   AudioDeviceName device_name;
304   device_name.unique_id = GetDeviceID(device);
305   if (device_name.unique_id.empty())
306     return E_FAIL;
307
308   // Retrieve user-friendly name of endpoint device.
309   // Example: "Microphone (Realtek High Definition Audio)".
310   ScopedComPtr<IPropertyStore> properties;
311   HRESULT hr = device->OpenPropertyStore(STGM_READ, properties.Receive());
312   if (FAILED(hr))
313     return hr;
314   base::win::ScopedPropVariant friendly_name;
315   hr = properties->GetValue(PKEY_Device_FriendlyName, friendly_name.Receive());
316   if (FAILED(hr))
317     return hr;
318   if (friendly_name.get().vt == VT_LPWSTR && friendly_name.get().pwszVal) {
319     WideToUTF8(friendly_name.get().pwszVal,
320                wcslen(friendly_name.get().pwszVal),
321                &device_name.device_name);
322   }
323
324   *name = device_name;
325   DVLOG(2) << "friendly name: " << device_name.device_name;
326   DVLOG(2) << "unique id    : " << device_name.unique_id;
327   return hr;
328 }
329
330 std::string CoreAudioUtil::GetAudioControllerID(IMMDevice* device,
331     IMMDeviceEnumerator* enumerator) {
332   DCHECK(IsSupported());
333
334   // Fetching the controller device id could be as simple as fetching the value
335   // of the "{B3F8FA53-0004-438E-9003-51A46E139BFC},2" property in the property
336   // store of the |device|, but that key isn't defined in any header and
337   // according to MS should not be relied upon.
338   // So, instead, we go deeper, look at the device topology and fetch the
339   // PKEY_Device_InstanceId of the associated physical audio device.
340   ScopedComPtr<IDeviceTopology> topology;
341   ScopedComPtr<IConnector> connector;
342   ScopedCoMem<WCHAR> filter_id;
343   if (FAILED(device->Activate(__uuidof(IDeviceTopology), CLSCTX_ALL, NULL,
344              topology.ReceiveVoid()) ||
345       // For our purposes checking the first connected device should be enough
346       // and if there are cases where there are more than one device connected
347       // we're not sure how to handle that anyway. So we pass 0.
348       FAILED(topology->GetConnector(0, connector.Receive())) ||
349       FAILED(connector->GetDeviceIdConnectedTo(&filter_id)))) {
350     DLOG(ERROR) << "Failed to get the device identifier of the audio device";
351     return std::string();
352   }
353
354   // Now look at the properties of the connected device node and fetch the
355   // instance id (PKEY_Device_InstanceId) of the device node that uniquely
356   // identifies the controller.
357   ScopedComPtr<IMMDevice> device_node;
358   ScopedComPtr<IPropertyStore> properties;
359   base::win::ScopedPropVariant instance_id;
360   if (FAILED(enumerator->GetDevice(filter_id, device_node.Receive())) ||
361       FAILED(device_node->OpenPropertyStore(STGM_READ, properties.Receive())) ||
362       FAILED(properties->GetValue(PKEY_Device_InstanceId,
363                                   instance_id.Receive())) ||
364       instance_id.get().vt != VT_LPWSTR) {
365     DLOG(ERROR) << "Failed to get instance id of the audio device node";
366     return std::string();
367   }
368
369   std::string controller_id;
370   WideToUTF8(instance_id.get().pwszVal,
371              wcslen(instance_id.get().pwszVal),
372              &controller_id);
373
374   return controller_id;
375 }
376
377 std::string CoreAudioUtil::GetMatchingOutputDeviceID(
378     const std::string& input_device_id) {
379   ScopedComPtr<IMMDevice> input_device(CreateDevice(input_device_id));
380   if (!input_device)
381     return std::string();
382
383   // See if we can get id of the associated controller.
384   ScopedComPtr<IMMDeviceEnumerator> enumerator(CreateDeviceEnumerator());
385   std::string controller_id(GetAudioControllerID(input_device, enumerator));
386   if (controller_id.empty())
387     return std::string();
388
389   // Now enumerate the available (and active) output devices and see if any of
390   // them is associated with the same controller.
391   ScopedComPtr<IMMDeviceCollection> collection;
392   enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE,
393       collection.Receive());
394   if (!collection)
395     return std::string();
396
397   UINT count = 0;
398   collection->GetCount(&count);
399   ScopedComPtr<IMMDevice> output_device;
400   for (UINT i = 0; i < count; ++i) {
401     collection->Item(i, output_device.Receive());
402     std::string output_controller_id(GetAudioControllerID(
403         output_device, enumerator));
404     if (output_controller_id == controller_id)
405       break;
406     output_device = NULL;
407   }
408
409   return output_device ? GetDeviceID(output_device) : std::string();
410 }
411
412 std::string CoreAudioUtil::GetFriendlyName(const std::string& device_id) {
413   DCHECK(IsSupported());
414   ScopedComPtr<IMMDevice> audio_device = CreateDevice(device_id);
415   if (!audio_device)
416     return std::string();
417
418   AudioDeviceName device_name;
419   HRESULT hr = GetDeviceName(audio_device, &device_name);
420   if (FAILED(hr))
421     return std::string();
422
423   return device_name.device_name;
424 }
425
426 bool CoreAudioUtil::DeviceIsDefault(EDataFlow flow,
427                                     ERole role,
428                                     const std::string& device_id) {
429   DCHECK(IsSupported());
430   ScopedComPtr<IMMDevice> device = CreateDefaultDevice(flow, role);
431   if (!device)
432     return false;
433
434   std::string str_default(GetDeviceID(device));
435   return device_id.compare(str_default) == 0;
436 }
437
438 EDataFlow CoreAudioUtil::GetDataFlow(IMMDevice* device) {
439   DCHECK(IsSupported());
440   ScopedComPtr<IMMEndpoint> endpoint;
441   HRESULT hr = device->QueryInterface(endpoint.Receive());
442   if (FAILED(hr)) {
443     DVLOG(1) << "IMMDevice::QueryInterface: " << std::hex << hr;
444     return eAll;
445   }
446
447   EDataFlow data_flow;
448   hr = endpoint->GetDataFlow(&data_flow);
449   if (FAILED(hr)) {
450     DVLOG(1) << "IMMEndpoint::GetDataFlow: " << std::hex << hr;
451     return eAll;
452   }
453   return data_flow;
454 }
455
456 ScopedComPtr<IAudioClient> CoreAudioUtil::CreateClient(
457     IMMDevice* audio_device) {
458   DCHECK(IsSupported());
459
460   // Creates and activates an IAudioClient COM object given the selected
461   // endpoint device.
462   ScopedComPtr<IAudioClient> audio_client;
463   HRESULT hr = audio_device->Activate(__uuidof(IAudioClient),
464                                       CLSCTX_INPROC_SERVER,
465                                       NULL,
466                                       audio_client.ReceiveVoid());
467   DVLOG_IF(1, FAILED(hr)) << "IMMDevice::Activate: " << std::hex << hr;
468   return audio_client;
469 }
470
471 ScopedComPtr<IAudioClient> CoreAudioUtil::CreateDefaultClient(
472     EDataFlow data_flow, ERole role) {
473   DCHECK(IsSupported());
474   ScopedComPtr<IMMDevice> default_device(CreateDefaultDevice(data_flow, role));
475   return (default_device ? CreateClient(default_device) :
476       ScopedComPtr<IAudioClient>());
477 }
478
479 ScopedComPtr<IAudioClient> CoreAudioUtil::CreateClient(
480     const std::string& device_id, EDataFlow data_flow, ERole role) {
481   if (device_id.empty())
482     return CreateDefaultClient(data_flow, role);
483
484   ScopedComPtr<IMMDevice> device(CreateDevice(device_id));
485   if (!device)
486     return ScopedComPtr<IAudioClient>();
487
488  return CreateClient(device);
489 }
490
491 HRESULT CoreAudioUtil::GetSharedModeMixFormat(
492     IAudioClient* client, WAVEFORMATPCMEX* format) {
493   DCHECK(IsSupported());
494   ScopedCoMem<WAVEFORMATPCMEX> format_pcmex;
495   HRESULT hr = client->GetMixFormat(
496       reinterpret_cast<WAVEFORMATEX**>(&format_pcmex));
497   if (FAILED(hr))
498     return hr;
499
500   size_t bytes = sizeof(WAVEFORMATEX) + format_pcmex->Format.cbSize;
501   DCHECK_EQ(bytes, sizeof(WAVEFORMATPCMEX));
502
503   memcpy(format, format_pcmex, bytes);
504   DVLOG(2) << *format;
505
506   return hr;
507 }
508
509 bool CoreAudioUtil::IsFormatSupported(IAudioClient* client,
510                                       AUDCLNT_SHAREMODE share_mode,
511                                       const WAVEFORMATPCMEX* format) {
512   DCHECK(IsSupported());
513   ScopedCoMem<WAVEFORMATEXTENSIBLE> closest_match;
514   HRESULT hr = client->IsFormatSupported(
515       share_mode, reinterpret_cast<const WAVEFORMATEX*>(format),
516       reinterpret_cast<WAVEFORMATEX**>(&closest_match));
517
518   // This log can only be triggered for shared mode.
519   DLOG_IF(ERROR, hr == S_FALSE) << "Format is not supported "
520                                 << "but a closest match exists.";
521   // This log can be triggered both for shared and exclusive modes.
522   DLOG_IF(ERROR, hr == AUDCLNT_E_UNSUPPORTED_FORMAT) << "Unsupported format.";
523   if (hr == S_FALSE) {
524     DVLOG(2) << *closest_match;
525   }
526
527   return (hr == S_OK);
528 }
529
530 bool CoreAudioUtil::IsChannelLayoutSupported(const std::string& device_id,
531                                              EDataFlow data_flow,
532                                              ERole role,
533                                              ChannelLayout channel_layout) {
534   DCHECK(IsSupported());
535
536   // First, get the preferred mixing format for shared mode streams.
537
538   ScopedComPtr<IAudioClient> client(CreateClient(device_id, data_flow, role));
539   if (!client)
540     return false;
541
542   WAVEFORMATPCMEX format;
543   HRESULT hr = GetSharedModeMixFormat(client, &format);
544   if (FAILED(hr))
545     return false;
546
547   // Next, check if it is possible to use an alternative format where the
548   // channel layout (and possibly number of channels) is modified.
549
550   // Convert generic channel layout into Windows-specific channel configuration.
551   ChannelConfig new_config = ChannelLayoutToChannelConfig(channel_layout);
552   if (new_config == KSAUDIO_SPEAKER_UNSUPPORTED) {
553     return false;
554   }
555   format.dwChannelMask = new_config;
556
557   // Modify the format if the new channel layout has changed the number of
558   // utilized channels.
559   const int channels = ChannelLayoutToChannelCount(channel_layout);
560   if (channels != format.Format.nChannels) {
561     format.Format.nChannels = channels;
562     format.Format.nBlockAlign = (format.Format.wBitsPerSample / 8) * channels;
563     format.Format.nAvgBytesPerSec = format.Format.nSamplesPerSec *
564                                     format.Format.nBlockAlign;
565   }
566   DVLOG(2) << format;
567
568   // Some devices can initialize a shared-mode stream with a format that is
569   // not identical to the mix format obtained from the GetMixFormat() method.
570   // However, chances of succeeding increases if we use the same number of
571   // channels and the same sample rate as the mix format. I.e, this call will
572   // return true only in those cases where the audio engine is able to support
573   // an even wider range of shared-mode formats where the installation package
574   // for the audio device includes a local effects (LFX) audio processing
575   // object (APO) that can handle format conversions.
576   return CoreAudioUtil::IsFormatSupported(client, AUDCLNT_SHAREMODE_SHARED,
577                                           &format);
578 }
579
580 HRESULT CoreAudioUtil::GetDevicePeriod(IAudioClient* client,
581                                        AUDCLNT_SHAREMODE share_mode,
582                                        REFERENCE_TIME* device_period) {
583   DCHECK(IsSupported());
584
585   // Get the period of the engine thread.
586   REFERENCE_TIME default_period = 0;
587   REFERENCE_TIME minimum_period = 0;
588   HRESULT hr = client->GetDevicePeriod(&default_period, &minimum_period);
589   if (FAILED(hr))
590     return hr;
591
592   *device_period = (share_mode == AUDCLNT_SHAREMODE_SHARED) ? default_period :
593       minimum_period;
594   DVLOG(2) << "device_period: "
595            << RefererenceTimeToTimeDelta(*device_period).InMillisecondsF()
596            << " [ms]";
597   return hr;
598 }
599
600 HRESULT CoreAudioUtil::GetPreferredAudioParameters(
601     IAudioClient* client, AudioParameters* params) {
602   DCHECK(IsSupported());
603   WAVEFORMATPCMEX mix_format;
604   HRESULT hr = GetSharedModeMixFormat(client, &mix_format);
605   if (FAILED(hr))
606     return hr;
607
608   REFERENCE_TIME default_period = 0;
609   hr = GetDevicePeriod(client, AUDCLNT_SHAREMODE_SHARED, &default_period);
610   if (FAILED(hr))
611     return hr;
612
613   // Get the integer mask which corresponds to the channel layout the
614   // audio engine uses for its internal processing/mixing of shared-mode
615   // streams. This mask indicates which channels are present in the multi-
616   // channel stream. The least significant bit corresponds with the Front Left
617   // speaker, the next least significant bit corresponds to the Front Right
618   // speaker, and so on, continuing in the order defined in KsMedia.h.
619   // See http://msdn.microsoft.com/en-us/library/windows/hardware/ff537083.aspx
620   // for more details.
621   ChannelConfig channel_config = mix_format.dwChannelMask;
622
623   // Convert Microsoft's channel configuration to genric ChannelLayout.
624   ChannelLayout channel_layout = ChannelConfigToChannelLayout(channel_config);
625
626   // Some devices don't appear to set a valid channel layout, so guess based on
627   // the number of channels.  See http://crbug.com/311906.
628   if (channel_layout == CHANNEL_LAYOUT_UNSUPPORTED) {
629     VLOG(1) << "Unsupported channel config: "
630             << std::hex << channel_config
631             << ".  Guessing layout by channel count: "
632             << std::dec << mix_format.Format.nChannels;
633     channel_layout = GuessChannelLayout(mix_format.Format.nChannels);
634   }
635
636   // Preferred sample rate.
637   int sample_rate = mix_format.Format.nSamplesPerSec;
638
639   // TODO(henrika): possibly use format.Format.wBitsPerSample here instead.
640   // We use a hard-coded value of 16 bits per sample today even if most audio
641   // engines does the actual mixing in 32 bits per sample.
642   int bits_per_sample = 16;
643
644   // We are using the native device period to derive the smallest possible
645   // buffer size in shared mode. Note that the actual endpoint buffer will be
646   // larger than this size but it will be possible to fill it up in two calls.
647   // TODO(henrika): ensure that this scheme works for capturing as well.
648   int frames_per_buffer = static_cast<int>(sample_rate *
649       RefererenceTimeToTimeDelta(default_period).InSecondsF() + 0.5);
650
651   DVLOG(1) << "channel_layout   : " << channel_layout;
652   DVLOG(1) << "sample_rate      : " << sample_rate;
653   DVLOG(1) << "bits_per_sample  : " << bits_per_sample;
654   DVLOG(1) << "frames_per_buffer: " << frames_per_buffer;
655
656   AudioParameters audio_params(AudioParameters::AUDIO_PCM_LOW_LATENCY,
657                                channel_layout,
658                                sample_rate,
659                                bits_per_sample,
660                                frames_per_buffer);
661
662   *params = audio_params;
663   return hr;
664 }
665
666 HRESULT CoreAudioUtil::GetPreferredAudioParameters(
667     EDataFlow data_flow, ERole role, AudioParameters* params) {
668   DCHECK(IsSupported());
669   ScopedComPtr<IAudioClient> client(CreateDefaultClient(data_flow, role));
670   if (!client) {
671     // Map NULL-pointer to new error code which can be different from the
672     // actual error code. The exact value is not important here.
673     return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
674   }
675   return GetPreferredAudioParameters(client, params);
676 }
677
678 HRESULT CoreAudioUtil::GetPreferredAudioParameters(
679     const std::string& device_id, AudioParameters* params) {
680   DCHECK(IsSupported());
681   ScopedComPtr<IMMDevice> device(CreateDevice(device_id));
682   if (!device) {
683     // Map NULL-pointer to new error code which can be different from the
684     // actual error code. The exact value is not important here.
685     return AUDCLNT_E_DEVICE_INVALIDATED;
686   }
687
688   ScopedComPtr<IAudioClient> client(CreateClient(device));
689   if (!client) {
690     // Map NULL-pointer to new error code which can be different from the
691     // actual error code. The exact value is not important here.
692     return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
693   }
694   return GetPreferredAudioParameters(client, params);
695 }
696
697 ChannelConfig CoreAudioUtil::GetChannelConfig(const std::string& device_id,
698                                               EDataFlow data_flow) {
699   ScopedComPtr<IAudioClient> client(
700       CreateClient(device_id, data_flow, eConsole));
701
702   WAVEFORMATPCMEX format = {0};
703   if (!client || FAILED(GetSharedModeMixFormat(client, &format)))
704     return 0;
705
706   return static_cast<ChannelConfig>(format.dwChannelMask);
707 }
708
709 HRESULT CoreAudioUtil::SharedModeInitialize(IAudioClient* client,
710                                             const WAVEFORMATPCMEX* format,
711                                             HANDLE event_handle,
712                                             uint32* endpoint_buffer_size) {
713   DCHECK(IsSupported());
714
715   // Use default flags (i.e, dont set AUDCLNT_STREAMFLAGS_NOPERSIST) to
716   // ensure that the volume level and muting state for a rendering session
717   // are persistent across system restarts. The volume level and muting
718   // state for a capture session are never persistent.
719   DWORD stream_flags = 0;
720
721   // Enable event-driven streaming if a valid event handle is provided.
722   // After the stream starts, the audio engine will signal the event handle
723   // to notify the client each time a buffer becomes ready to process.
724   // Event-driven buffering is supported for both rendering and capturing.
725   // Both shared-mode and exclusive-mode streams can use event-driven buffering.
726   bool use_event = (event_handle != NULL &&
727                     event_handle != INVALID_HANDLE_VALUE);
728   if (use_event)
729     stream_flags |= AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
730   DVLOG(2) << "stream_flags: 0x" << std::hex << stream_flags;
731
732   // Initialize the shared mode client for minimal delay.
733   HRESULT hr = client->Initialize(AUDCLNT_SHAREMODE_SHARED,
734                                   stream_flags,
735                                   0,
736                                   0,
737                                   reinterpret_cast<const WAVEFORMATEX*>(format),
738                                   NULL);
739   if (FAILED(hr)) {
740     DVLOG(1) << "IAudioClient::Initialize: " << std::hex << hr;
741     return hr;
742   }
743
744   if (use_event) {
745     hr = client->SetEventHandle(event_handle);
746     if (FAILED(hr)) {
747       DVLOG(1) << "IAudioClient::SetEventHandle: " << std::hex << hr;
748       return hr;
749     }
750   }
751
752   UINT32 buffer_size_in_frames = 0;
753   hr = client->GetBufferSize(&buffer_size_in_frames);
754   if (FAILED(hr)) {
755     DVLOG(1) << "IAudioClient::GetBufferSize: " << std::hex << hr;
756     return hr;
757   }
758
759   *endpoint_buffer_size = buffer_size_in_frames;
760   DVLOG(2) << "endpoint buffer size: " << buffer_size_in_frames;
761
762   // TODO(henrika): utilize when delay measurements are added.
763   REFERENCE_TIME  latency = 0;
764   hr = client->GetStreamLatency(&latency);
765   DVLOG(2) << "stream latency: "
766            << RefererenceTimeToTimeDelta(latency).InMillisecondsF() << " [ms]";
767   return hr;
768 }
769
770 ScopedComPtr<IAudioRenderClient> CoreAudioUtil::CreateRenderClient(
771     IAudioClient* client) {
772   DCHECK(IsSupported());
773
774   // Get access to the IAudioRenderClient interface. This interface
775   // enables us to write output data to a rendering endpoint buffer.
776   ScopedComPtr<IAudioRenderClient> audio_render_client;
777   HRESULT hr = client->GetService(__uuidof(IAudioRenderClient),
778                                   audio_render_client.ReceiveVoid());
779   if (FAILED(hr)) {
780     DVLOG(1) << "IAudioClient::GetService: " << std::hex << hr;
781     return ScopedComPtr<IAudioRenderClient>();
782   }
783   return audio_render_client;
784 }
785
786 ScopedComPtr<IAudioCaptureClient> CoreAudioUtil::CreateCaptureClient(
787     IAudioClient* client) {
788   DCHECK(IsSupported());
789
790   // Get access to the IAudioCaptureClient interface. This interface
791   // enables us to read input data from a capturing endpoint buffer.
792   ScopedComPtr<IAudioCaptureClient> audio_capture_client;
793   HRESULT hr = client->GetService(__uuidof(IAudioCaptureClient),
794                                   audio_capture_client.ReceiveVoid());
795   if (FAILED(hr)) {
796     DVLOG(1) << "IAudioClient::GetService: " << std::hex << hr;
797     return ScopedComPtr<IAudioCaptureClient>();
798   }
799   return audio_capture_client;
800 }
801
802 bool CoreAudioUtil::FillRenderEndpointBufferWithSilence(
803     IAudioClient* client, IAudioRenderClient* render_client) {
804   DCHECK(IsSupported());
805
806   UINT32 endpoint_buffer_size = 0;
807   if (FAILED(client->GetBufferSize(&endpoint_buffer_size)))
808     return false;
809
810   UINT32 num_queued_frames = 0;
811   if (FAILED(client->GetCurrentPadding(&num_queued_frames)))
812     return false;
813
814   BYTE* data = NULL;
815   int num_frames_to_fill = endpoint_buffer_size - num_queued_frames;
816   if (FAILED(render_client->GetBuffer(num_frames_to_fill, &data)))
817     return false;
818
819   // Using the AUDCLNT_BUFFERFLAGS_SILENT flag eliminates the need to
820   // explicitly write silence data to the rendering buffer.
821   DVLOG(2) << "filling up " << num_frames_to_fill << " frames with silence";
822   return SUCCEEDED(render_client->ReleaseBuffer(num_frames_to_fill,
823                                                 AUDCLNT_BUFFERFLAGS_SILENT));
824 }
825
826 }  // namespace media