1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
|
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/audio/audio_io.h"
#include <windows.h>
#include <objbase.h> // This has to be before initguid.h
#include <initguid.h>
#include <mmsystem.h>
#include <setupapi.h>
#include "base/basictypes.h"
#include "base/scoped_ptr.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "media/audio/fake_audio_input_stream.h"
#include "media/audio/fake_audio_output_stream.h"
#include "media/audio/win/audio_manager_win.h"
#include "media/audio/win/wavein_input_win.h"
#include "media/audio/win/waveout_output_win.h"
#include "media/base/limits.h"
// Libraries required for the SetupAPI and Wbem APIs used here.
#pragma comment(lib, "setupapi.lib")
// The following are defined in various DDK headers, and we (re)define them
// here to avoid adding the DDK as a chrome dependency.
#define DRV_QUERYDEVICEINTERFACE 0x80c
#define DRVM_MAPPER_PREFERRED_GET 0x2015
#define DRV_QUERYDEVICEINTERFACESIZE 0x80d
DEFINE_GUID(AM_KSCATEGORY_AUDIO, 0x6994ad04, 0x93ef, 0x11d0,
0xa3, 0xcc, 0x00, 0xa0, 0xc9, 0x22, 0x31, 0x96);
namespace {
// Up to 8 channels can be passed to the driver.
// This should work, given the right drivers, but graceful error handling is
// needed.
const int kWinMaxChannels = 8;
const int kWinMaxInputChannels = 2;
// We use 3 buffers for recording audio so that if a recording callback takes
// some time to return we won't lose audio. More buffers while recording are
// ok because they don't introduce any delay in recording, unlike in playback
// where you first need to fill in that number of buffers before starting to
// play.
const int kNumInputBuffers = 3;
// Returns a string containing the given device's description and installed
// driver version.
string16 GetDeviceAndDriverInfo(HDEVINFO device_info,
SP_DEVINFO_DATA* device_data) {
// Save the old install params setting and set a flag for the
// SetupDiBuildDriverInfoList below to return only the installed drivers.
SP_DEVINSTALL_PARAMS old_device_install_params;
old_device_install_params.cbSize = sizeof(old_device_install_params);
SetupDiGetDeviceInstallParams(device_info, device_data,
&old_device_install_params);
SP_DEVINSTALL_PARAMS device_install_params = old_device_install_params;
device_install_params.FlagsEx |= DI_FLAGSEX_INSTALLEDDRIVER;
SetupDiSetDeviceInstallParams(device_info, device_data,
&device_install_params);
SP_DRVINFO_DATA driver_data;
driver_data.cbSize = sizeof(driver_data);
string16 device_and_driver_info;
if (SetupDiBuildDriverInfoList(device_info, device_data,
SPDIT_COMPATDRIVER)) {
if (SetupDiEnumDriverInfo(device_info, device_data, SPDIT_COMPATDRIVER, 0,
&driver_data)) {
DWORDLONG version = driver_data.DriverVersion;
device_and_driver_info = string16(driver_data.Description) + L" v" +
base::IntToString16((version >> 48) & 0xffff) + L"." +
base::IntToString16((version >> 32) & 0xffff) + L"." +
base::IntToString16((version >> 16) & 0xffff) + L"." +
base::IntToString16(version & 0xffff);
}
SetupDiDestroyDriverInfoList(device_info, device_data, SPDIT_COMPATDRIVER);
}
SetupDiSetDeviceInstallParams(device_info, device_data,
&old_device_install_params);
return device_and_driver_info;
}
} // namespace
bool AudioManagerWin::HasAudioOutputDevices() {
return (::waveOutGetNumDevs() != 0);
}
bool AudioManagerWin::HasAudioInputDevices() {
return (::waveInGetNumDevs() != 0);
}
// Factory for the implementations of AudioOutputStream. Two implementations
// should suffice most windows user's needs.
// - PCMWaveOutAudioOutputStream: Based on the waveOutWrite API (in progress)
// - PCMDXSoundAudioOutputStream: Based on DirectSound or XAudio (future work).
AudioOutputStream* AudioManagerWin::MakeAudioOutputStream(
AudioParameters params) {
if (!params.IsValid() || (params.channels > kWinMaxChannels))
return NULL;
if (params.format == AudioParameters::AUDIO_MOCK) {
return FakeAudioOutputStream::MakeFakeStream(params);
} else if (params.format == AudioParameters::AUDIO_PCM_LINEAR) {
return new PCMWaveOutAudioOutputStream(this, params, 3, WAVE_MAPPER);
} else if (params.format == AudioParameters::AUDIO_PCM_LOW_LATENCY) {
// TODO(cpu): waveout cannot hit 20ms latency. Use other method.
return new PCMWaveOutAudioOutputStream(this, params, 2, WAVE_MAPPER);
}
return NULL;
}
// Factory for the implementations of AudioInputStream.
AudioInputStream* AudioManagerWin::MakeAudioInputStream(
AudioParameters params) {
if (!params.IsValid() || (params.channels > kWinMaxInputChannels))
return NULL;
if (params.format == AudioParameters::AUDIO_MOCK) {
return FakeAudioInputStream::MakeFakeStream(params);
} else if (params.format == AudioParameters::AUDIO_PCM_LINEAR) {
return new PCMWaveInAudioInputStream(this, params, kNumInputBuffers,
WAVE_MAPPER);
}
return NULL;
}
void AudioManagerWin::ReleaseOutputStream(PCMWaveOutAudioOutputStream* stream) {
if (stream)
delete stream;
}
void AudioManagerWin::ReleaseInputStream(PCMWaveInAudioInputStream* stream) {
if (stream)
delete stream;
}
void AudioManagerWin::MuteAll() {
}
void AudioManagerWin::UnMuteAll() {
}
AudioManagerWin::~AudioManagerWin() {
}
string16 AudioManagerWin::GetAudioInputDeviceModel() {
// Get the default audio capture device and its device interface name.
DWORD device_id = 0;
waveInMessage(reinterpret_cast<HWAVEIN>(WAVE_MAPPER),
DRVM_MAPPER_PREFERRED_GET,
reinterpret_cast<DWORD_PTR>(&device_id), NULL);
ULONG device_interface_name_size = 0;
waveInMessage(reinterpret_cast<HWAVEIN>(device_id),
DRV_QUERYDEVICEINTERFACESIZE,
reinterpret_cast<DWORD_PTR>(&device_interface_name_size), 0);
string16 device_interface_name;
string16::value_type* name_ptr = WriteInto(&device_interface_name,
device_interface_name_size / sizeof(string16::value_type));
waveInMessage(reinterpret_cast<HWAVEIN>(device_id),
DRV_QUERYDEVICEINTERFACE,
reinterpret_cast<DWORD_PTR>(name_ptr),
static_cast<DWORD_PTR>(device_interface_name_size));
// Enumerate all audio devices and find the one matching the above device
// interface name.
HDEVINFO device_info = SetupDiGetClassDevs(
&AM_KSCATEGORY_AUDIO, 0, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if (device_info == INVALID_HANDLE_VALUE)
return string16();
DWORD interface_index = 0;
SP_DEVICE_INTERFACE_DATA interface_data;
interface_data.cbSize = sizeof(interface_data);
while (SetupDiEnumDeviceInterfaces(device_info, 0, &AM_KSCATEGORY_AUDIO,
interface_index++, &interface_data)) {
// Query the size of the struct, allocate it and then query the data.
SP_DEVINFO_DATA device_data;
device_data.cbSize = sizeof(device_data);
DWORD interface_detail_size = 0;
SetupDiGetDeviceInterfaceDetail(device_info, &interface_data, 0, 0,
&interface_detail_size, &device_data);
if (!interface_detail_size)
continue;
scoped_array<char> interface_detail_buffer(new char[interface_detail_size]);
SP_DEVICE_INTERFACE_DETAIL_DATA* interface_detail =
reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA*>(
interface_detail_buffer.get());
interface_detail->cbSize = interface_detail_size;
if (!SetupDiGetDeviceInterfaceDetail(device_info, &interface_data,
interface_detail,
interface_detail_size, NULL,
&device_data))
return string16();
bool device_found = (device_interface_name == interface_detail->DevicePath);
if (device_found)
return GetDeviceAndDriverInfo(device_info, &device_data);
}
return string16();
}
// static
AudioManager* AudioManager::CreateAudioManager() {
return new AudioManagerWin();
}
|