Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1213)

Side by Side Diff: media/audio/win/audio_manager_win.cc

Issue 2646423005: Remove the wave based audio capture implementation for Windows (Closed)
Patch Set: Update histograms and call IsSupported in ctor Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/audio/win/audio_manager_win.h ('k') | media/audio/win/device_enumeration_win.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/audio/win/audio_manager_win.h" 5 #include "media/audio/win/audio_manager_win.h"
6 6
7 #include <windows.h> 7 #include <windows.h>
8 #include <objbase.h> // This has to be before initguid.h 8 #include <objbase.h> // This has to be before initguid.h
9 #include <initguid.h> 9 #include <initguid.h>
10 #include <mmsystem.h> 10 #include <mmsystem.h>
(...skipping 13 matching lines...) Expand all
24 #include "base/strings/string_number_conversions.h" 24 #include "base/strings/string_number_conversions.h"
25 #include "base/strings/string_util.h" 25 #include "base/strings/string_util.h"
26 #include "base/win/windows_version.h" 26 #include "base/win/windows_version.h"
27 #include "media/audio/audio_device_description.h" 27 #include "media/audio/audio_device_description.h"
28 #include "media/audio/audio_io.h" 28 #include "media/audio/audio_io.h"
29 #include "media/audio/win/audio_device_listener_win.h" 29 #include "media/audio/win/audio_device_listener_win.h"
30 #include "media/audio/win/audio_low_latency_input_win.h" 30 #include "media/audio/win/audio_low_latency_input_win.h"
31 #include "media/audio/win/audio_low_latency_output_win.h" 31 #include "media/audio/win/audio_low_latency_output_win.h"
32 #include "media/audio/win/core_audio_util_win.h" 32 #include "media/audio/win/core_audio_util_win.h"
33 #include "media/audio/win/device_enumeration_win.h" 33 #include "media/audio/win/device_enumeration_win.h"
34 #include "media/audio/win/wavein_input_win.h"
35 #include "media/audio/win/waveout_output_win.h" 34 #include "media/audio/win/waveout_output_win.h"
36 #include "media/base/audio_parameters.h" 35 #include "media/base/audio_parameters.h"
37 #include "media/base/bind_to_current_loop.h" 36 #include "media/base/bind_to_current_loop.h"
38 #include "media/base/channel_layout.h" 37 #include "media/base/channel_layout.h"
39 #include "media/base/limits.h" 38 #include "media/base/limits.h"
40 #include "media/base/media_switches.h" 39 #include "media/base/media_switches.h"
41 40
42 // The following are defined in various DDK headers, and we (re)define them here 41 // The following are defined in various DDK headers, and we (re)define them here
43 // to avoid adding the DDK as a chrome dependency. 42 // to avoid adding the DDK as a chrome dependency.
44 #define DRV_QUERYDEVICEINTERFACE 0x80c 43 #define DRV_QUERYDEVICEINTERFACE 0x80c
45 #define DRVM_MAPPER_PREFERRED_GET 0x2015 44 #define DRVM_MAPPER_PREFERRED_GET 0x2015
46 #define DRV_QUERYDEVICEINTERFACESIZE 0x80d 45 #define DRV_QUERYDEVICEINTERFACESIZE 0x80d
47 DEFINE_GUID(AM_KSCATEGORY_AUDIO, 0x6994ad04, 0x93ef, 0x11d0, 46 DEFINE_GUID(AM_KSCATEGORY_AUDIO,
48 0xa3, 0xcc, 0x00, 0xa0, 0xc9, 0x22, 0x31, 0x96); 47 0x6994ad04,
48 0x93ef,
49 0x11d0,
50 0xa3,
51 0xcc,
52 0x00,
53 0xa0,
54 0xc9,
55 0x22,
56 0x31,
57 0x96);
49 58
50 namespace media { 59 namespace media {
51 60
52 // Maximum number of output streams that can be open simultaneously. 61 // Maximum number of output streams that can be open simultaneously.
53 static const int kMaxOutputStreams = 50; 62 static const int kMaxOutputStreams = 50;
54 63
55 // Up to 8 channels can be passed to the driver. This should work, given the 64 // Up to 8 channels can be passed to the driver. This should work, given the
56 // right drivers, but graceful error handling is needed. 65 // right drivers, but graceful error handling is needed.
57 static const int kWinMaxChannels = 8; 66 static const int kWinMaxChannels = 8;
58 67
59 // We use 3 buffers for recording audio so that if a recording callback takes
60 // some time to return we won't lose audio. More buffers while recording are
61 // ok because they don't introduce any delay in recording, unlike in playback
62 // where you first need to fill in that number of buffers before starting to
63 // play.
64 static const int kNumInputBuffers = 3;
65
66 // Buffer size to use for input and output stream when a proper size can't be 68 // Buffer size to use for input and output stream when a proper size can't be
67 // determined from the system 69 // determined from the system
68 static const int kFallbackBufferSize = 2048; 70 static const int kFallbackBufferSize = 2048;
69 71
70 static int GetVersionPartAsInt(DWORDLONG num) { 72 static int GetVersionPartAsInt(DWORDLONG num) {
71 return static_cast<int>(num & 0xffff); 73 return static_cast<int>(num & 0xffff);
72 } 74 }
73 75
74 // Returns a string containing the given device's description and installed 76 // Returns a string containing the given device's description and installed
75 // driver version. 77 // driver version.
(...skipping 11 matching lines...) Expand all
87 &device_install_params); 89 &device_install_params);
88 90
89 SP_DRVINFO_DATA driver_data; 91 SP_DRVINFO_DATA driver_data;
90 driver_data.cbSize = sizeof(driver_data); 92 driver_data.cbSize = sizeof(driver_data);
91 base::string16 device_and_driver_info; 93 base::string16 device_and_driver_info;
92 if (SetupDiBuildDriverInfoList(device_info, device_data, 94 if (SetupDiBuildDriverInfoList(device_info, device_data,
93 SPDIT_COMPATDRIVER)) { 95 SPDIT_COMPATDRIVER)) {
94 if (SetupDiEnumDriverInfo(device_info, device_data, SPDIT_COMPATDRIVER, 0, 96 if (SetupDiEnumDriverInfo(device_info, device_data, SPDIT_COMPATDRIVER, 0,
95 &driver_data)) { 97 &driver_data)) {
96 DWORDLONG version = driver_data.DriverVersion; 98 DWORDLONG version = driver_data.DriverVersion;
97 device_and_driver_info = base::string16(driver_data.Description) + L" v" + 99 device_and_driver_info =
100 base::string16(driver_data.Description) + L" v" +
98 base::IntToString16(GetVersionPartAsInt((version >> 48))) + L"." + 101 base::IntToString16(GetVersionPartAsInt((version >> 48))) + L"." +
99 base::IntToString16(GetVersionPartAsInt((version >> 32))) + L"." + 102 base::IntToString16(GetVersionPartAsInt((version >> 32))) + L"." +
100 base::IntToString16(GetVersionPartAsInt((version >> 16))) + L"." + 103 base::IntToString16(GetVersionPartAsInt((version >> 16))) + L"." +
101 base::IntToString16(GetVersionPartAsInt(version)); 104 base::IntToString16(GetVersionPartAsInt(version));
102 } 105 }
103 SetupDiDestroyDriverInfoList(device_info, device_data, SPDIT_COMPATDRIVER); 106 SetupDiDestroyDriverInfoList(device_info, device_data, SPDIT_COMPATDRIVER);
104 } 107 }
105 108
106 SetupDiSetDeviceInstallParams(device_info, device_data, 109 SetupDiSetDeviceInstallParams(device_info, device_data,
107 &old_device_install_params); 110 &old_device_install_params);
(...skipping 19 matching lines...) Expand all
127 // - Some XP configurations (even multi-processor ones) also need 3. 130 // - Some XP configurations (even multi-processor ones) also need 3.
128 return (base::win::GetVersion() == base::win::VERSION_VISTA) ? 4 : 3; 131 return (base::win::GetVersion() == base::win::VERSION_VISTA) ? 4 : 3;
129 } 132 }
130 133
131 AudioManagerWin::AudioManagerWin( 134 AudioManagerWin::AudioManagerWin(
132 scoped_refptr<base::SingleThreadTaskRunner> task_runner, 135 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
133 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner, 136 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner,
134 AudioLogFactory* audio_log_factory) 137 AudioLogFactory* audio_log_factory)
135 : AudioManagerBase(std::move(task_runner), 138 : AudioManagerBase(std::move(task_runner),
136 std::move(worker_task_runner), 139 std::move(worker_task_runner),
137 audio_log_factory), 140 audio_log_factory) {
138 // |CoreAudioUtil::IsSupported()| uses static variables to avoid doing 141 // |CoreAudioUtil::IsSupported()| uses static variables to avoid doing
139 // multiple initializations. This is however not thread safe. 142 // multiple initializations. This is however not thread safe.
140 // So, here we call it explicitly before we kick off the audio thread 143 // So, here we call it explicitly before we kick off the audio thread
141 // or do any other work. 144 // or do any other work.
142 enumeration_type_(CoreAudioUtil::IsSupported() ? kMMDeviceEnumeration 145 CoreAudioUtil::IsSupported();
143 : kWaveEnumeration) { 146
144 SetMaxOutputStreamsAllowed(kMaxOutputStreams); 147 SetMaxOutputStreamsAllowed(kMaxOutputStreams);
145 148
146 // WARNING: This is executed on the UI loop, do not add any code here which 149 // WARNING: This is executed on the UI loop, do not add any code here which
147 // loads libraries or attempts to call out into the OS. Instead add such code 150 // loads libraries or attempts to call out into the OS. Instead add such code
148 // to the InitializeOnAudioThread() method below. 151 // to the InitializeOnAudioThread() method below.
149 152
150 // Task must be posted last to avoid races from handing out "this" to the 153 // Task must be posted last to avoid races from handing out "this" to the
151 // audio thread. 154 // audio thread.
152 GetTaskRunner()->PostTask(FROM_HERE, base::Bind( 155 GetTaskRunner()->PostTask(
153 &AudioManagerWin::InitializeOnAudioThread, base::Unretained(this))); 156 FROM_HERE, base::Bind(&AudioManagerWin::InitializeOnAudioThread,
157 base::Unretained(this)));
154 } 158 }
155 159
156 AudioManagerWin::~AudioManagerWin() { 160 AudioManagerWin::~AudioManagerWin() {
157 Shutdown(); 161 Shutdown();
158 } 162 }
159 163
160 bool AudioManagerWin::HasAudioOutputDevices() { 164 bool AudioManagerWin::HasAudioOutputDevices() {
161 return (::waveOutGetNumDevs() != 0); 165 return (::waveOutGetNumDevs() != 0);
162 } 166 }
163 167
164 bool AudioManagerWin::HasAudioInputDevices() { 168 bool AudioManagerWin::HasAudioInputDevices() {
165 return (::waveInGetNumDevs() != 0); 169 return (::waveInGetNumDevs() != 0);
166 } 170 }
167 171
168 void AudioManagerWin::InitializeOnAudioThread() { 172 void AudioManagerWin::InitializeOnAudioThread() {
169 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 173 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
170 174
171 if (core_audio_supported()) { 175 // AudioDeviceListenerWin must be initialized on a COM thread.
172 // AudioDeviceListenerWin must be initialized on a COM thread and should 176 output_device_listener_.reset(new AudioDeviceListenerWin(BindToCurrentLoop(
173 // only be used if WASAPI / Core Audio is supported. 177 base::Bind(&AudioManagerWin::NotifyAllOutputDeviceChangeListeners,
174 output_device_listener_.reset(new AudioDeviceListenerWin(BindToCurrentLoop( 178 base::Unretained(this)))));
175 base::Bind(&AudioManagerWin::NotifyAllOutputDeviceChangeListeners,
176 base::Unretained(this)))));
177 }
178 } 179 }
179 180
180 base::string16 AudioManagerWin::GetAudioInputDeviceModel() { 181 base::string16 AudioManagerWin::GetAudioInputDeviceModel() {
181 // Get the default audio capture device and its device interface name. 182 // Get the default audio capture device and its device interface name.
182 DWORD device_id = 0; 183 DWORD device_id = 0;
183 waveInMessage(reinterpret_cast<HWAVEIN>(WAVE_MAPPER), 184 waveInMessage(reinterpret_cast<HWAVEIN>(WAVE_MAPPER),
184 DRVM_MAPPER_PREFERRED_GET, 185 DRVM_MAPPER_PREFERRED_GET,
185 reinterpret_cast<DWORD_PTR>(&device_id), NULL); 186 reinterpret_cast<DWORD_PTR>(&device_id), NULL);
186 ULONG device_interface_name_size = 0; 187 ULONG device_interface_name_size = 0;
187 waveInMessage(reinterpret_cast<HWAVEIN>(device_id), 188 waveInMessage(reinterpret_cast<HWAVEIN>(device_id),
188 DRV_QUERYDEVICEINTERFACESIZE, 189 DRV_QUERYDEVICEINTERFACESIZE,
189 reinterpret_cast<DWORD_PTR>(&device_interface_name_size), 0); 190 reinterpret_cast<DWORD_PTR>(&device_interface_name_size), 0);
190 size_t bytes_in_char16 = sizeof(base::string16::value_type); 191 size_t bytes_in_char16 = sizeof(base::string16::value_type);
191 DCHECK_EQ(0u, device_interface_name_size % bytes_in_char16); 192 DCHECK_EQ(0u, device_interface_name_size % bytes_in_char16);
192 if (device_interface_name_size <= bytes_in_char16) 193 if (device_interface_name_size <= bytes_in_char16)
193 return base::string16(); // No audio capture device. 194 return base::string16(); // No audio capture device.
194 195
195 base::string16 device_interface_name; 196 base::string16 device_interface_name;
196 base::string16::value_type* name_ptr = base::WriteInto(&device_interface_name, 197 base::string16::value_type* name_ptr = base::WriteInto(
197 device_interface_name_size / bytes_in_char16); 198 &device_interface_name, device_interface_name_size / bytes_in_char16);
198 waveInMessage(reinterpret_cast<HWAVEIN>(device_id), 199 waveInMessage(reinterpret_cast<HWAVEIN>(device_id), DRV_QUERYDEVICEINTERFACE,
199 DRV_QUERYDEVICEINTERFACE,
200 reinterpret_cast<DWORD_PTR>(name_ptr), 200 reinterpret_cast<DWORD_PTR>(name_ptr),
201 static_cast<DWORD_PTR>(device_interface_name_size)); 201 static_cast<DWORD_PTR>(device_interface_name_size));
202 202
203 // Enumerate all audio devices and find the one matching the above device 203 // Enumerate all audio devices and find the one matching the above device
204 // interface name. 204 // interface name.
205 HDEVINFO device_info = SetupDiGetClassDevs( 205 HDEVINFO device_info = SetupDiGetClassDevs(
206 &AM_KSCATEGORY_AUDIO, 0, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); 206 &AM_KSCATEGORY_AUDIO, 0, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
207 if (device_info == INVALID_HANDLE_VALUE) 207 if (device_info == INVALID_HANDLE_VALUE)
208 return base::string16(); 208 return base::string16();
209 209
(...skipping 10 matching lines...) Expand all
220 &interface_detail_size, &device_data); 220 &interface_detail_size, &device_data);
221 if (!interface_detail_size) 221 if (!interface_detail_size)
222 continue; 222 continue;
223 223
224 std::unique_ptr<char[]> interface_detail_buffer( 224 std::unique_ptr<char[]> interface_detail_buffer(
225 new char[interface_detail_size]); 225 new char[interface_detail_size]);
226 SP_DEVICE_INTERFACE_DETAIL_DATA* interface_detail = 226 SP_DEVICE_INTERFACE_DETAIL_DATA* interface_detail =
227 reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA*>( 227 reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA*>(
228 interface_detail_buffer.get()); 228 interface_detail_buffer.get());
229 interface_detail->cbSize = interface_detail_size; 229 interface_detail->cbSize = interface_detail_size;
230 if (!SetupDiGetDeviceInterfaceDetail(device_info, &interface_data, 230 if (!SetupDiGetDeviceInterfaceDetail(
231 interface_detail, 231 device_info, &interface_data, interface_detail,
232 interface_detail_size, NULL, 232 interface_detail_size, NULL, &device_data))
233 &device_data))
234 return base::string16(); 233 return base::string16();
235 234
236 bool device_found = (device_interface_name == interface_detail->DevicePath); 235 bool device_found = (device_interface_name == interface_detail->DevicePath);
237 236
238 if (device_found) 237 if (device_found)
239 return GetDeviceAndDriverInfo(device_info, &device_data); 238 return GetDeviceAndDriverInfo(device_info, &device_data);
240 } 239 }
241 240
242 return base::string16(); 241 return base::string16();
243 } 242 }
244 243
245 void AudioManagerWin::ShowAudioInputSettings() { 244 void AudioManagerWin::ShowAudioInputSettings() {
246 std::wstring program;
247 std::string argument;
248 if (!core_audio_supported()) {
249 program = L"sndvol32.exe";
250 argument = "-R";
251 } else {
252 program = L"control.exe";
253 argument = "mmsys.cpl,,1";
254 }
255
256 base::FilePath path; 245 base::FilePath path;
257 PathService::Get(base::DIR_SYSTEM, &path); 246 PathService::Get(base::DIR_SYSTEM, &path);
258 path = path.Append(program); 247 path = path.Append(L"control.exe");
259 base::CommandLine command_line(path); 248 base::CommandLine command_line(path);
260 command_line.AppendArg(argument); 249 command_line.AppendArg("mmsys.cpl,,1");
261 base::LaunchProcess(command_line, base::LaunchOptions()); 250 base::LaunchProcess(command_line, base::LaunchOptions());
262 } 251 }
263 252
264 void AudioManagerWin::GetAudioDeviceNamesImpl( 253 void AudioManagerWin::GetAudioDeviceNamesImpl(bool input,
265 bool input, 254 AudioDeviceNames* device_names) {
266 AudioDeviceNames* device_names) {
267 DCHECK(device_names->empty()); 255 DCHECK(device_names->empty());
268 // Enumerate all active audio-endpoint capture devices. 256 // Enumerate all active audio-endpoint capture devices.
269 if (enumeration_type() == kWaveEnumeration) { 257 if (input)
270 // Utilize the Wave API for Windows XP. 258 GetInputDeviceNamesWin(device_names);
271 if (input) 259 else
272 GetInputDeviceNamesWinXP(device_names); 260 GetOutputDeviceNamesWin(device_names);
273 else
274 GetOutputDeviceNamesWinXP(device_names);
275 } else {
276 // Utilize the MMDevice API (part of Core Audio) for Vista and higher.
277 if (input)
278 GetInputDeviceNamesWin(device_names);
279 else
280 GetOutputDeviceNamesWin(device_names);
281 }
282 261
283 if (!device_names->empty()) { 262 if (!device_names->empty()) {
284 if (enumeration_type() == kMMDeviceEnumeration) 263 device_names->push_front(AudioDeviceName::CreateCommunications());
285 device_names->push_front(AudioDeviceName::CreateCommunications());
286 264
287 // Always add default device parameters as first element. 265 // Always add default device parameters as first element.
288 device_names->push_front(AudioDeviceName::CreateDefault()); 266 device_names->push_front(AudioDeviceName::CreateDefault());
289 } 267 }
290 } 268 }
291 269
292 void AudioManagerWin::GetAudioInputDeviceNames(AudioDeviceNames* device_names) { 270 void AudioManagerWin::GetAudioInputDeviceNames(AudioDeviceNames* device_names) {
293 GetAudioDeviceNamesImpl(true, device_names); 271 GetAudioDeviceNamesImpl(true, device_names);
294 } 272 }
295 273
296 void AudioManagerWin::GetAudioOutputDeviceNames( 274 void AudioManagerWin::GetAudioOutputDeviceNames(
297 AudioDeviceNames* device_names) { 275 AudioDeviceNames* device_names) {
298 GetAudioDeviceNamesImpl(false, device_names); 276 GetAudioDeviceNamesImpl(false, device_names);
299 } 277 }
300 278
301 AudioParameters AudioManagerWin::GetInputStreamParameters( 279 AudioParameters AudioManagerWin::GetInputStreamParameters(
302 const std::string& device_id) { 280 const std::string& device_id) {
303 HRESULT hr = E_FAIL;
304 AudioParameters parameters; 281 AudioParameters parameters;
305 if (core_audio_supported()) { 282 HRESULT hr =
306 hr = CoreAudioUtil::GetPreferredAudioParameters(device_id, false, 283 CoreAudioUtil::GetPreferredAudioParameters(device_id, false, &parameters);
307 &parameters);
308 }
309 284
310 if (FAILED(hr) || !parameters.IsValid()) { 285 if (FAILED(hr) || !parameters.IsValid()) {
311 // Windows Wave implementation is being used. 286 // Fall back on default parameters.
287 // TODO(tommi): Is this necessary? I'd guess that things would go wrong
288 // elsewhere if we weren't able to get the preferred audio parameters.
henrika (OOO until Aug 14) 2017/01/25 12:43:33 Possibly add a LOG(WARNING) just in case.
tommi (sloooow) - chröme 2017/01/25 21:44:33 Done.
312 parameters = 289 parameters =
313 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, 290 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR,
314 CHANNEL_LAYOUT_STEREO, 48000, 16, kFallbackBufferSize); 291 CHANNEL_LAYOUT_STEREO, 48000, 16, kFallbackBufferSize);
315 } 292 }
316 293
317 int user_buffer_size = GetUserBufferSize(); 294 int user_buffer_size = GetUserBufferSize();
318 if (user_buffer_size) 295 if (user_buffer_size)
319 parameters.set_frames_per_buffer(user_buffer_size); 296 parameters.set_frames_per_buffer(user_buffer_size);
320 297
321 return parameters; 298 return parameters;
322 } 299 }
323 300
324 std::string AudioManagerWin::GetAssociatedOutputDeviceID( 301 std::string AudioManagerWin::GetAssociatedOutputDeviceID(
325 const std::string& input_device_id) { 302 const std::string& input_device_id) {
326 if (!core_audio_supported()) {
327 NOTIMPLEMENTED()
328 << "GetAssociatedOutputDeviceID is not supported on this OS";
329 return std::string();
330 }
331 return CoreAudioUtil::GetMatchingOutputDeviceID(input_device_id); 303 return CoreAudioUtil::GetMatchingOutputDeviceID(input_device_id);
332 } 304 }
333 305
334 const char* AudioManagerWin::GetName() { 306 const char* AudioManagerWin::GetName() {
335 return "Windows"; 307 return "Windows";
336 } 308 }
337 309
338 // Factory for the implementations of AudioOutputStream for AUDIO_PCM_LINEAR 310 // Factory for the implementations of AudioOutputStream for AUDIO_PCM_LINEAR
339 // mode. 311 // mode.
340 // - PCMWaveOutAudioOutputStream: Based on the waveOut API. 312 // - PCMWaveOutAudioOutputStream: Based on the waveOut API.
341 AudioOutputStream* AudioManagerWin::MakeLinearOutputStream( 313 AudioOutputStream* AudioManagerWin::MakeLinearOutputStream(
342 const AudioParameters& params, 314 const AudioParameters& params,
343 const LogCallback& log_callback) { 315 const LogCallback& log_callback) {
344 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 316 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
345 if (params.channels() > kWinMaxChannels) 317 if (params.channels() > kWinMaxChannels)
346 return NULL; 318 return NULL;
347 319
348 return new PCMWaveOutAudioOutputStream(this, 320 return new PCMWaveOutAudioOutputStream(this, params, NumberOfWaveOutBuffers(),
349 params,
350 NumberOfWaveOutBuffers(),
351 WAVE_MAPPER); 321 WAVE_MAPPER);
352 } 322 }
353 323
354 // Factory for the implementations of AudioOutputStream for 324 // Factory for the implementations of AudioOutputStream for
355 // AUDIO_PCM_LOW_LATENCY mode. Two implementations should suffice most 325 // AUDIO_PCM_LOW_LATENCY mode. Two implementations should suffice most
356 // windows user's needs. 326 // windows user's needs.
357 // - PCMWaveOutAudioOutputStream: Based on the waveOut API. 327 // - PCMWaveOutAudioOutputStream: Based on the waveOut API.
358 // - WASAPIAudioOutputStream: Based on Core Audio (WASAPI) API. 328 // - WASAPIAudioOutputStream: Based on Core Audio (WASAPI) API.
359 AudioOutputStream* AudioManagerWin::MakeLowLatencyOutputStream( 329 AudioOutputStream* AudioManagerWin::MakeLowLatencyOutputStream(
360 const AudioParameters& params, 330 const AudioParameters& params,
361 const std::string& device_id, 331 const std::string& device_id,
362 const LogCallback& log_callback) { 332 const LogCallback& log_callback) {
363 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 333 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
364 if (params.channels() > kWinMaxChannels) 334 if (params.channels() > kWinMaxChannels)
365 return NULL; 335 return NULL;
366 336
367 if (!core_audio_supported()) {
368 // Fall back to Windows Wave implementation on Windows XP or lower.
369 DLOG_IF(ERROR, !device_id.empty() &&
370 device_id != AudioDeviceDescription::kDefaultDeviceId)
371 << "Opening by device id not supported by PCMWaveOutAudioOutputStream";
372 DVLOG(1) << "Using WaveOut since WASAPI requires at least Vista.";
373 return new PCMWaveOutAudioOutputStream(
374 this, params, NumberOfWaveOutBuffers(), WAVE_MAPPER);
375 }
376
377 // Pass an empty string to indicate that we want the default device 337 // Pass an empty string to indicate that we want the default device
378 // since we consistently only check for an empty string in 338 // since we consistently only check for an empty string in
379 // WASAPIAudioOutputStream. 339 // WASAPIAudioOutputStream.
380 bool communications = 340 bool communications =
381 device_id == AudioDeviceDescription::kCommunicationsDeviceId; 341 device_id == AudioDeviceDescription::kCommunicationsDeviceId;
382 return new WASAPIAudioOutputStream( 342 return new WASAPIAudioOutputStream(
383 this, 343 this,
384 communications || device_id == AudioDeviceDescription::kDefaultDeviceId 344 communications || device_id == AudioDeviceDescription::kDefaultDeviceId
385 ? std::string() 345 ? std::string()
386 : device_id, 346 : device_id,
387 params, communications ? eCommunications : eConsole); 347 params, communications ? eCommunications : eConsole);
388 } 348 }
389 349
390 // Factory for the implementations of AudioInputStream for AUDIO_PCM_LINEAR 350 // Factory for the implementations of AudioInputStream for AUDIO_PCM_LINEAR
391 // mode. 351 // mode.
392 AudioInputStream* AudioManagerWin::MakeLinearInputStream( 352 AudioInputStream* AudioManagerWin::MakeLinearInputStream(
393 const AudioParameters& params, 353 const AudioParameters& params,
394 const std::string& device_id, 354 const std::string& device_id,
395 const LogCallback& log_callback) { 355 const LogCallback& log_callback) {
396 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 356 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
397 return CreatePCMWaveInAudioInputStream(params, device_id); 357 return MakeLowLatencyInputStream(params, device_id, log_callback);
398 } 358 }
399 359
400 // Factory for the implementations of AudioInputStream for 360 // Factory for the implementations of AudioInputStream for
401 // AUDIO_PCM_LOW_LATENCY mode. 361 // AUDIO_PCM_LOW_LATENCY mode.
402 AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream( 362 AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream(
403 const AudioParameters& params, 363 const AudioParameters& params,
404 const std::string& device_id, 364 const std::string& device_id,
405 const LogCallback& log_callback) { 365 const LogCallback& log_callback) {
406 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 366 // Used for both AUDIO_PCM_LOW_LATENCY and AUDIO_PCM_LINEAR.
henrika (OOO until Aug 14) 2017/01/25 12:43:33 Just FYI, I can only find one client (Pepper) that
tommi (sloooow) - chröme 2017/01/25 21:44:33 Yes, Dale knows a bit about that code. I think it
407 DVLOG(1) << "MakeLowLatencyInputStream: " << device_id; 367 DVLOG(1) << "MakeLowLatencyInputStream: " << device_id;
408 AudioInputStream* stream = NULL; 368 return new WASAPIAudioInputStream(this, params, device_id);
409 UMA_HISTOGRAM_BOOLEAN("Media.WindowsCoreAudioInput", core_audio_supported());
410 if (!core_audio_supported()) {
411 // Fall back to Windows Wave implementation on Windows XP or lower.
412 DVLOG(1) << "Using WaveIn since WASAPI requires at least Vista.";
413 stream = CreatePCMWaveInAudioInputStream(params, device_id);
414 } else {
415 stream = new WASAPIAudioInputStream(this, params, device_id);
416 }
417
418 return stream;
419 } 369 }
420 370
421 std::string AudioManagerWin::GetDefaultOutputDeviceID() { 371 std::string AudioManagerWin::GetDefaultOutputDeviceID() {
422 if (!core_audio_supported())
423 return std::string();
424 return CoreAudioUtil::GetDefaultOutputDeviceID(); 372 return CoreAudioUtil::GetDefaultOutputDeviceID();
425 } 373 }
426 374
427 AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters( 375 AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters(
428 const std::string& output_device_id, 376 const std::string& output_device_id,
429 const AudioParameters& input_params) { 377 const AudioParameters& input_params) {
430 DLOG_IF(ERROR, !core_audio_supported() && !output_device_id.empty())
431 << "CoreAudio is required to open non-default devices.";
432
433 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); 378 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
434 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; 379 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
435 int sample_rate = 48000; 380 int sample_rate = 48000;
436 int buffer_size = kFallbackBufferSize; 381 int buffer_size = kFallbackBufferSize;
437 int bits_per_sample = 16; 382 int bits_per_sample = 16;
438 int effects = AudioParameters::NO_EFFECTS; 383 int effects = AudioParameters::NO_EFFECTS;
439 bool use_input_params = !core_audio_supported(); 384 bool use_input_params = false;
440 if (core_audio_supported()) { 385 if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) {
441 if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) { 386 // TODO(rtoy): tune these values for best possible WebAudio
442 // TODO(rtoy): tune these values for best possible WebAudio 387 // performance. WebRTC works well at 48kHz and a buffer size of 480
443 // performance. WebRTC works well at 48kHz and a buffer size of 480 388 // samples will be used for this case. Note that exclusive mode is
444 // samples will be used for this case. Note that exclusive mode is 389 // experimental. This sample rate will be combined with a buffer size of
445 // experimental. This sample rate will be combined with a buffer size of 390 // 256 samples, which corresponds to an output delay of ~5.33ms.
446 // 256 samples, which corresponds to an output delay of ~5.33ms. 391 sample_rate = 48000;
447 sample_rate = 48000; 392 buffer_size = 256;
448 buffer_size = 256; 393 if (input_params.IsValid())
449 if (input_params.IsValid()) 394 channel_layout = input_params.channel_layout();
450 channel_layout = input_params.channel_layout(); 395 } else {
396 AudioParameters params;
397 HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters(
398 output_device_id.empty() ? GetDefaultOutputDeviceID()
399 : output_device_id,
400 true, &params);
401 if (SUCCEEDED(hr)) {
402 bits_per_sample = params.bits_per_sample();
403 buffer_size = params.frames_per_buffer();
404 channel_layout = params.channel_layout();
405 sample_rate = params.sample_rate();
406 effects = params.effects();
451 } else { 407 } else {
452 AudioParameters params; 408 // TODO(tommi): This should never happen really and I'm not sure that
453 HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters( 409 // setting use_input_params is the right thing to do since WASAPI i
454 output_device_id.empty() ? GetDefaultOutputDeviceID() 410 // definitely supported (see core_audio_supported() above) and
455 : output_device_id, 411 // |use_input_params| is only for cases when it isn't supported.
456 true, &params); 412 DLOG(ERROR) << "GetPreferredAudioParameters failed: " << std::hex << hr;
457 if (SUCCEEDED(hr)) { 413 use_input_params = true;
458 bits_per_sample = params.bits_per_sample();
459 buffer_size = params.frames_per_buffer();
460 channel_layout = params.channel_layout();
461 sample_rate = params.sample_rate();
462 effects = params.effects();
463 } else {
464 // TODO(tommi): This should never happen really and I'm not sure that
465 // setting use_input_params is the right thing to do since WASAPI i
466 // definitely supported (see core_audio_supported() above) and
467 // |use_input_params| is only for cases when it isn't supported.
468 DLOG(ERROR) << "GetPreferredAudioParameters failed: " << std::hex << hr;
469 use_input_params = true;
470 }
471 } 414 }
472 } 415 }
473 416
474 if (input_params.IsValid()) { 417 if (input_params.IsValid()) {
475 // If the user has enabled checking supported channel layouts or we don't 418 // If the user has enabled checking supported channel layouts or we don't
476 // have a valid channel layout yet, try to use the input layout. See bugs 419 // have a valid channel layout yet, try to use the input layout. See bugs
477 // http://crbug.com/259165 and http://crbug.com/311906 for more details. 420 // http://crbug.com/259165 and http://crbug.com/311906 for more details.
478 if (core_audio_supported() && 421 if (cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts) ||
479 (cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts) || 422 channel_layout == CHANNEL_LAYOUT_UNSUPPORTED) {
480 channel_layout == CHANNEL_LAYOUT_UNSUPPORTED)) {
481 // Check if it is possible to open up at the specified input channel 423 // Check if it is possible to open up at the specified input channel
482 // layout but avoid checking if the specified layout is the same as the 424 // layout but avoid checking if the specified layout is the same as the
483 // hardware (preferred) layout. We do this extra check to avoid the 425 // hardware (preferred) layout. We do this extra check to avoid the
484 // CoreAudioUtil::IsChannelLayoutSupported() overhead in most cases. 426 // CoreAudioUtil::IsChannelLayoutSupported() overhead in most cases.
485 if (input_params.channel_layout() != channel_layout) { 427 if (input_params.channel_layout() != channel_layout) {
486 // TODO(henrika): Internally, IsChannelLayoutSupported does many of the 428 // TODO(henrika): Internally, IsChannelLayoutSupported does many of the
487 // operations that have already been done such as opening up a client 429 // operations that have already been done such as opening up a client
488 // and fetching the WAVEFORMATPCMEX format. Ideally we should only do 430 // and fetching the WAVEFORMATPCMEX format. Ideally we should only do
489 // that once. Then here, we can check the layout from the data we 431 // that once. Then here, we can check the layout from the data we
490 // already hold. 432 // already hold.
(...skipping 26 matching lines...) Expand all
517 int user_buffer_size = GetUserBufferSize(); 459 int user_buffer_size = GetUserBufferSize();
518 if (user_buffer_size) 460 if (user_buffer_size)
519 buffer_size = user_buffer_size; 461 buffer_size = user_buffer_size;
520 462
521 AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, 463 AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout,
522 sample_rate, bits_per_sample, buffer_size); 464 sample_rate, bits_per_sample, buffer_size);
523 params.set_effects(effects); 465 params.set_effects(effects);
524 return params; 466 return params;
525 } 467 }
526 468
527 AudioInputStream* AudioManagerWin::CreatePCMWaveInAudioInputStream( 469 // static
528 const AudioParameters& params,
529 const std::string& device_id) {
530 std::string xp_device_id = device_id;
531 if (device_id != AudioDeviceDescription::kDefaultDeviceId &&
532 enumeration_type_ == kMMDeviceEnumeration) {
533 xp_device_id = ConvertToWinXPInputDeviceId(device_id);
534 if (xp_device_id.empty()) {
535 DLOG(ERROR) << "Cannot find a waveIn device which matches the device ID "
536 << device_id;
537 return NULL;
538 }
539 }
540
541 return new PCMWaveInAudioInputStream(this, params, kNumInputBuffers,
542 xp_device_id);
543 }
544
545 /// static
546 ScopedAudioManagerPtr CreateAudioManager( 470 ScopedAudioManagerPtr CreateAudioManager(
547 scoped_refptr<base::SingleThreadTaskRunner> task_runner, 471 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
548 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner, 472 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner,
549 AudioLogFactory* audio_log_factory) { 473 AudioLogFactory* audio_log_factory) {
550 return ScopedAudioManagerPtr( 474 return ScopedAudioManagerPtr(
551 new AudioManagerWin(std::move(task_runner), std::move(worker_task_runner), 475 new AudioManagerWin(std::move(task_runner), std::move(worker_task_runner),
552 audio_log_factory)); 476 audio_log_factory));
553 } 477 }
554 478
555 } // namespace media 479 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/win/audio_manager_win.h ('k') | media/audio/win/device_enumeration_win.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698