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

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: Remove wave input code Created 3 years, 10 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
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,
tommi (sloooow) - chröme 2017/01/24 21:10:51 some changes, like this one, are due to git cl for
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
139 // multiple initializations. This is however not thread safe.
140 // So, here we call it explicitly before we kick off the audio thread
141 // or do any other work.
142 enumeration_type_(CoreAudioUtil::IsSupported() ? kMMDeviceEnumeration
DaleCurtis 2017/01/24 21:09:30 This may be a race now in the setup of the interna
tommi (sloooow) - chröme 2017/01/24 21:34:57 Ah, thanks for pointing that out. I had forgotten
DaleCurtis 2017/01/24 21:47:26 I think that's the safest change for now. It'd be
143 : kWaveEnumeration) {
144 SetMaxOutputStreamsAllowed(kMaxOutputStreams); 141 SetMaxOutputStreamsAllowed(kMaxOutputStreams);
145 142
146 // WARNING: This is executed on the UI loop, do not add any code here which 143 // 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 144 // loads libraries or attempts to call out into the OS. Instead add such code
148 // to the InitializeOnAudioThread() method below. 145 // to the InitializeOnAudioThread() method below.
149 146
150 // Task must be posted last to avoid races from handing out "this" to the 147 // Task must be posted last to avoid races from handing out "this" to the
151 // audio thread. 148 // audio thread.
152 GetTaskRunner()->PostTask(FROM_HERE, base::Bind( 149 GetTaskRunner()->PostTask(
153 &AudioManagerWin::InitializeOnAudioThread, base::Unretained(this))); 150 FROM_HERE, base::Bind(&AudioManagerWin::InitializeOnAudioThread,
151 base::Unretained(this)));
154 } 152 }
155 153
156 AudioManagerWin::~AudioManagerWin() { 154 AudioManagerWin::~AudioManagerWin() {
157 Shutdown(); 155 Shutdown();
158 } 156 }
159 157
160 bool AudioManagerWin::HasAudioOutputDevices() { 158 bool AudioManagerWin::HasAudioOutputDevices() {
161 return (::waveOutGetNumDevs() != 0); 159 return (::waveOutGetNumDevs() != 0);
162 } 160 }
163 161
164 bool AudioManagerWin::HasAudioInputDevices() { 162 bool AudioManagerWin::HasAudioInputDevices() {
165 return (::waveInGetNumDevs() != 0); 163 return (::waveInGetNumDevs() != 0);
166 } 164 }
167 165
168 void AudioManagerWin::InitializeOnAudioThread() { 166 void AudioManagerWin::InitializeOnAudioThread() {
169 DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 167 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
170 168
171 if (core_audio_supported()) { 169 // AudioDeviceListenerWin must be initialized on a COM thread.
172 // AudioDeviceListenerWin must be initialized on a COM thread and should 170 output_device_listener_.reset(new AudioDeviceListenerWin(BindToCurrentLoop(
173 // only be used if WASAPI / Core Audio is supported. 171 base::Bind(&AudioManagerWin::NotifyAllOutputDeviceChangeListeners,
174 output_device_listener_.reset(new AudioDeviceListenerWin(BindToCurrentLoop( 172 base::Unretained(this)))));
175 base::Bind(&AudioManagerWin::NotifyAllOutputDeviceChangeListeners,
176 base::Unretained(this)))));
177 }
178 } 173 }
179 174
180 base::string16 AudioManagerWin::GetAudioInputDeviceModel() { 175 base::string16 AudioManagerWin::GetAudioInputDeviceModel() {
henrika (OOO until Aug 14) 2017/01/25 12:43:33 Used at https://cs.chromium.org/chromium/src/conte
tommi (sloooow) - chröme 2017/01/25 21:44:33 It's not needed now that Olga has landed her patch
181 // Get the default audio capture device and its device interface name. 176 // Get the default audio capture device and its device interface name.
182 DWORD device_id = 0; 177 DWORD device_id = 0;
183 waveInMessage(reinterpret_cast<HWAVEIN>(WAVE_MAPPER), 178 waveInMessage(reinterpret_cast<HWAVEIN>(WAVE_MAPPER),
184 DRVM_MAPPER_PREFERRED_GET, 179 DRVM_MAPPER_PREFERRED_GET,
185 reinterpret_cast<DWORD_PTR>(&device_id), NULL); 180 reinterpret_cast<DWORD_PTR>(&device_id), NULL);
186 ULONG device_interface_name_size = 0; 181 ULONG device_interface_name_size = 0;
187 waveInMessage(reinterpret_cast<HWAVEIN>(device_id), 182 waveInMessage(reinterpret_cast<HWAVEIN>(device_id),
188 DRV_QUERYDEVICEINTERFACESIZE, 183 DRV_QUERYDEVICEINTERFACESIZE,
189 reinterpret_cast<DWORD_PTR>(&device_interface_name_size), 0); 184 reinterpret_cast<DWORD_PTR>(&device_interface_name_size), 0);
190 size_t bytes_in_char16 = sizeof(base::string16::value_type); 185 size_t bytes_in_char16 = sizeof(base::string16::value_type);
191 DCHECK_EQ(0u, device_interface_name_size % bytes_in_char16); 186 DCHECK_EQ(0u, device_interface_name_size % bytes_in_char16);
192 if (device_interface_name_size <= bytes_in_char16) 187 if (device_interface_name_size <= bytes_in_char16)
193 return base::string16(); // No audio capture device. 188 return base::string16(); // No audio capture device.
194 189
195 base::string16 device_interface_name; 190 base::string16 device_interface_name;
196 base::string16::value_type* name_ptr = base::WriteInto(&device_interface_name, 191 base::string16::value_type* name_ptr = base::WriteInto(
197 device_interface_name_size / bytes_in_char16); 192 &device_interface_name, device_interface_name_size / bytes_in_char16);
198 waveInMessage(reinterpret_cast<HWAVEIN>(device_id), 193 waveInMessage(reinterpret_cast<HWAVEIN>(device_id), DRV_QUERYDEVICEINTERFACE,
199 DRV_QUERYDEVICEINTERFACE,
200 reinterpret_cast<DWORD_PTR>(name_ptr), 194 reinterpret_cast<DWORD_PTR>(name_ptr),
201 static_cast<DWORD_PTR>(device_interface_name_size)); 195 static_cast<DWORD_PTR>(device_interface_name_size));
202 196
203 // Enumerate all audio devices and find the one matching the above device 197 // Enumerate all audio devices and find the one matching the above device
204 // interface name. 198 // interface name.
205 HDEVINFO device_info = SetupDiGetClassDevs( 199 HDEVINFO device_info = SetupDiGetClassDevs(
206 &AM_KSCATEGORY_AUDIO, 0, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); 200 &AM_KSCATEGORY_AUDIO, 0, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
207 if (device_info == INVALID_HANDLE_VALUE) 201 if (device_info == INVALID_HANDLE_VALUE)
208 return base::string16(); 202 return base::string16();
209 203
(...skipping 10 matching lines...) Expand all
220 &interface_detail_size, &device_data); 214 &interface_detail_size, &device_data);
221 if (!interface_detail_size) 215 if (!interface_detail_size)
222 continue; 216 continue;
223 217
224 std::unique_ptr<char[]> interface_detail_buffer( 218 std::unique_ptr<char[]> interface_detail_buffer(
225 new char[interface_detail_size]); 219 new char[interface_detail_size]);
226 SP_DEVICE_INTERFACE_DETAIL_DATA* interface_detail = 220 SP_DEVICE_INTERFACE_DETAIL_DATA* interface_detail =
227 reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA*>( 221 reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA*>(
228 interface_detail_buffer.get()); 222 interface_detail_buffer.get());
229 interface_detail->cbSize = interface_detail_size; 223 interface_detail->cbSize = interface_detail_size;
230 if (!SetupDiGetDeviceInterfaceDetail(device_info, &interface_data, 224 if (!SetupDiGetDeviceInterfaceDetail(
231 interface_detail, 225 device_info, &interface_data, interface_detail,
232 interface_detail_size, NULL, 226 interface_detail_size, NULL, &device_data))
233 &device_data))
234 return base::string16(); 227 return base::string16();
235 228
236 bool device_found = (device_interface_name == interface_detail->DevicePath); 229 bool device_found = (device_interface_name == interface_detail->DevicePath);
237 230
238 if (device_found) 231 if (device_found)
239 return GetDeviceAndDriverInfo(device_info, &device_data); 232 return GetDeviceAndDriverInfo(device_info, &device_data);
240 } 233 }
241 234
242 return base::string16(); 235 return base::string16();
243 } 236 }
244 237
245 void AudioManagerWin::ShowAudioInputSettings() { 238 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; 239 base::FilePath path;
257 PathService::Get(base::DIR_SYSTEM, &path); 240 PathService::Get(base::DIR_SYSTEM, &path);
258 path = path.Append(program); 241 path = path.Append(L"control.exe");
259 base::CommandLine command_line(path); 242 base::CommandLine command_line(path);
260 command_line.AppendArg(argument); 243 command_line.AppendArg("mmsys.cpl,,1");
261 base::LaunchProcess(command_line, base::LaunchOptions()); 244 base::LaunchProcess(command_line, base::LaunchOptions());
262 } 245 }
263 246
264 void AudioManagerWin::GetAudioDeviceNamesImpl( 247 void AudioManagerWin::GetAudioDeviceNamesImpl(bool input,
265 bool input, 248 AudioDeviceNames* device_names) {
266 AudioDeviceNames* device_names) {
267 DCHECK(device_names->empty()); 249 DCHECK(device_names->empty());
268 // Enumerate all active audio-endpoint capture devices. 250 // Enumerate all active audio-endpoint capture devices.
269 if (enumeration_type() == kWaveEnumeration) { 251 if (input)
270 // Utilize the Wave API for Windows XP. 252 GetInputDeviceNamesWin(device_names);
271 if (input) 253 else
272 GetInputDeviceNamesWinXP(device_names); 254 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 255
283 if (!device_names->empty()) { 256 if (!device_names->empty()) {
284 if (enumeration_type() == kMMDeviceEnumeration) 257 device_names->push_front(AudioDeviceName::CreateCommunications());
285 device_names->push_front(AudioDeviceName::CreateCommunications());
286 258
287 // Always add default device parameters as first element. 259 // Always add default device parameters as first element.
288 device_names->push_front(AudioDeviceName::CreateDefault()); 260 device_names->push_front(AudioDeviceName::CreateDefault());
289 } 261 }
290 } 262 }
291 263
292 void AudioManagerWin::GetAudioInputDeviceNames(AudioDeviceNames* device_names) { 264 void AudioManagerWin::GetAudioInputDeviceNames(AudioDeviceNames* device_names) {
293 GetAudioDeviceNamesImpl(true, device_names); 265 GetAudioDeviceNamesImpl(true, device_names);
294 } 266 }
295 267
296 void AudioManagerWin::GetAudioOutputDeviceNames( 268 void AudioManagerWin::GetAudioOutputDeviceNames(
297 AudioDeviceNames* device_names) { 269 AudioDeviceNames* device_names) {
298 GetAudioDeviceNamesImpl(false, device_names); 270 GetAudioDeviceNamesImpl(false, device_names);
299 } 271 }
300 272
301 AudioParameters AudioManagerWin::GetInputStreamParameters( 273 AudioParameters AudioManagerWin::GetInputStreamParameters(
302 const std::string& device_id) { 274 const std::string& device_id) {
303 HRESULT hr = E_FAIL;
304 AudioParameters parameters; 275 AudioParameters parameters;
305 if (core_audio_supported()) { 276 HRESULT hr =
306 hr = CoreAudioUtil::GetPreferredAudioParameters(device_id, false, 277 CoreAudioUtil::GetPreferredAudioParameters(device_id, false, &parameters);
DaleCurtis 2017/01/24 21:09:30 This method will DCHECK() IsSupported(). I don't f
tommi (sloooow) - chröme 2017/01/24 21:34:56 I read over the bug, refreshing my memory. In the
DaleCurtis 2017/01/24 21:47:26 sgtm
307 &parameters);
308 }
309 278
310 if (FAILED(hr) || !parameters.IsValid()) { 279 if (FAILED(hr) || !parameters.IsValid()) {
311 // Windows Wave implementation is being used. 280 // Fall back on default parameters.
281 // TODO(tommi): Is this necessary? I'd guess that things would go wrong
282 // elsewhere if we weren't able to get the preferred audio parameters.
tommi (sloooow) - chröme 2017/01/24 21:10:51 Should we remove this block and return invalid aud
DaleCurtis 2017/01/24 21:47:25 That sgtm, there's not point anymore.
henrika (OOO until Aug 14) 2017/01/25 12:43:33 sgtm
tommi (sloooow) - chröme 2017/01/25 12:49:25 Done. (just return if we failed or params aren't v
312 parameters = 283 parameters =
313 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, 284 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR,
314 CHANNEL_LAYOUT_STEREO, 48000, 16, kFallbackBufferSize); 285 CHANNEL_LAYOUT_STEREO, 48000, 16, kFallbackBufferSize);
315 } 286 }
316 287
317 int user_buffer_size = GetUserBufferSize(); 288 int user_buffer_size = GetUserBufferSize();
318 if (user_buffer_size) 289 if (user_buffer_size)
319 parameters.set_frames_per_buffer(user_buffer_size); 290 parameters.set_frames_per_buffer(user_buffer_size);
320 291
321 return parameters; 292 return parameters;
322 } 293 }
323 294
324 std::string AudioManagerWin::GetAssociatedOutputDeviceID( 295 std::string AudioManagerWin::GetAssociatedOutputDeviceID(
325 const std::string& input_device_id) { 296 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); 297 return CoreAudioUtil::GetMatchingOutputDeviceID(input_device_id);
332 } 298 }
333 299
334 const char* AudioManagerWin::GetName() { 300 const char* AudioManagerWin::GetName() {
335 return "Windows"; 301 return "Windows";
336 } 302 }
337 303
338 // Factory for the implementations of AudioOutputStream for AUDIO_PCM_LINEAR 304 // Factory for the implementations of AudioOutputStream for AUDIO_PCM_LINEAR
339 // mode. 305 // mode.
340 // - PCMWaveOutAudioOutputStream: Based on the waveOut API. 306 // - PCMWaveOutAudioOutputStream: Based on the waveOut API.
341 AudioOutputStream* AudioManagerWin::MakeLinearOutputStream( 307 AudioOutputStream* AudioManagerWin::MakeLinearOutputStream(
342 const AudioParameters& params, 308 const AudioParameters& params,
343 const LogCallback& log_callback) { 309 const LogCallback& log_callback) {
344 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 310 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
345 if (params.channels() > kWinMaxChannels) 311 if (params.channels() > kWinMaxChannels)
346 return NULL; 312 return NULL;
347 313
348 return new PCMWaveOutAudioOutputStream(this, 314 return new PCMWaveOutAudioOutputStream(this, params, NumberOfWaveOutBuffers(),
349 params,
350 NumberOfWaveOutBuffers(),
351 WAVE_MAPPER); 315 WAVE_MAPPER);
352 } 316 }
353 317
354 // Factory for the implementations of AudioOutputStream for 318 // Factory for the implementations of AudioOutputStream for
355 // AUDIO_PCM_LOW_LATENCY mode. Two implementations should suffice most 319 // AUDIO_PCM_LOW_LATENCY mode. Two implementations should suffice most
356 // windows user's needs. 320 // windows user's needs.
357 // - PCMWaveOutAudioOutputStream: Based on the waveOut API. 321 // - PCMWaveOutAudioOutputStream: Based on the waveOut API.
358 // - WASAPIAudioOutputStream: Based on Core Audio (WASAPI) API. 322 // - WASAPIAudioOutputStream: Based on Core Audio (WASAPI) API.
359 AudioOutputStream* AudioManagerWin::MakeLowLatencyOutputStream( 323 AudioOutputStream* AudioManagerWin::MakeLowLatencyOutputStream(
360 const AudioParameters& params, 324 const AudioParameters& params,
361 const std::string& device_id, 325 const std::string& device_id,
362 const LogCallback& log_callback) { 326 const LogCallback& log_callback) {
363 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 327 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format());
364 if (params.channels() > kWinMaxChannels) 328 if (params.channels() > kWinMaxChannels)
365 return NULL; 329 return NULL;
366 330
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 331 // Pass an empty string to indicate that we want the default device
378 // since we consistently only check for an empty string in 332 // since we consistently only check for an empty string in
379 // WASAPIAudioOutputStream. 333 // WASAPIAudioOutputStream.
380 bool communications = 334 bool communications =
381 device_id == AudioDeviceDescription::kCommunicationsDeviceId; 335 device_id == AudioDeviceDescription::kCommunicationsDeviceId;
382 return new WASAPIAudioOutputStream( 336 return new WASAPIAudioOutputStream(
383 this, 337 this,
384 communications || device_id == AudioDeviceDescription::kDefaultDeviceId 338 communications || device_id == AudioDeviceDescription::kDefaultDeviceId
385 ? std::string() 339 ? std::string()
386 : device_id, 340 : device_id,
387 params, communications ? eCommunications : eConsole); 341 params, communications ? eCommunications : eConsole);
388 } 342 }
389 343
390 // Factory for the implementations of AudioInputStream for AUDIO_PCM_LINEAR 344 // Factory for the implementations of AudioInputStream for AUDIO_PCM_LINEAR
391 // mode. 345 // mode.
392 AudioInputStream* AudioManagerWin::MakeLinearInputStream( 346 AudioInputStream* AudioManagerWin::MakeLinearInputStream(
393 const AudioParameters& params, 347 const AudioParameters& params,
394 const std::string& device_id, 348 const std::string& device_id,
395 const LogCallback& log_callback) { 349 const LogCallback& log_callback) {
396 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 350 DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format());
397 return CreatePCMWaveInAudioInputStream(params, device_id); 351 return MakeLowLatencyInputStream(params, device_id, log_callback);
398 } 352 }
399 353
400 // Factory for the implementations of AudioInputStream for 354 // Factory for the implementations of AudioInputStream for
401 // AUDIO_PCM_LOW_LATENCY mode. 355 // AUDIO_PCM_LOW_LATENCY mode.
402 AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream( 356 AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream(
403 const AudioParameters& params, 357 const AudioParameters& params,
404 const std::string& device_id, 358 const std::string& device_id,
405 const LogCallback& log_callback) { 359 const LogCallback& log_callback) {
406 DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 360 // Used for both AUDIO_PCM_LOW_LATENCY and AUDIO_PCM_LINEAR.
407 DVLOG(1) << "MakeLowLatencyInputStream: " << device_id; 361 DVLOG(1) << "MakeLowLatencyInputStream: " << device_id;
408 AudioInputStream* stream = NULL; 362 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 } 363 }
420 364
421 std::string AudioManagerWin::GetDefaultOutputDeviceID() { 365 std::string AudioManagerWin::GetDefaultOutputDeviceID() {
422 if (!core_audio_supported())
423 return std::string();
424 return CoreAudioUtil::GetDefaultOutputDeviceID(); 366 return CoreAudioUtil::GetDefaultOutputDeviceID();
425 } 367 }
426 368
427 AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters( 369 AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters(
428 const std::string& output_device_id, 370 const std::string& output_device_id,
429 const AudioParameters& input_params) { 371 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(); 372 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
434 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; 373 ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
435 int sample_rate = 48000; 374 int sample_rate = 48000;
436 int buffer_size = kFallbackBufferSize; 375 int buffer_size = kFallbackBufferSize;
437 int bits_per_sample = 16; 376 int bits_per_sample = 16;
438 int effects = AudioParameters::NO_EFFECTS; 377 int effects = AudioParameters::NO_EFFECTS;
439 bool use_input_params = !core_audio_supported(); 378 bool use_input_params = false;
440 if (core_audio_supported()) { 379 if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) {
DaleCurtis 2017/01/24 21:09:30 Hmm, I wonder if we should remove the exclusive au
tommi (sloooow) - chröme 2017/01/24 21:34:56 Good question. Perhaps we could add a counter for
DaleCurtis 2017/01/24 21:47:26 If crashes are any indication, there are 9 reports
henrika (OOO until Aug 14) 2017/01/25 12:43:33 Smart to check crashes Dale ;-) I added the suppo
tommi (sloooow) - chröme 2017/01/25 12:49:25 Added TODO for henrik to remove the switch and ass
441 if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) { 380 // TODO(rtoy): tune these values for best possible WebAudio
442 // TODO(rtoy): tune these values for best possible WebAudio 381 // 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 382 // 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 383 // 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 384 // 256 samples, which corresponds to an output delay of ~5.33ms.
446 // 256 samples, which corresponds to an output delay of ~5.33ms. 385 sample_rate = 48000;
447 sample_rate = 48000; 386 buffer_size = 256;
448 buffer_size = 256; 387 if (input_params.IsValid())
449 if (input_params.IsValid()) 388 channel_layout = input_params.channel_layout();
450 channel_layout = input_params.channel_layout(); 389 } else {
390 AudioParameters params;
391 HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters(
392 output_device_id.empty() ? GetDefaultOutputDeviceID()
393 : output_device_id,
394 true, &params);
395 if (SUCCEEDED(hr)) {
396 bits_per_sample = params.bits_per_sample();
397 buffer_size = params.frames_per_buffer();
398 channel_layout = params.channel_layout();
399 sample_rate = params.sample_rate();
400 effects = params.effects();
451 } else { 401 } else {
452 AudioParameters params; 402 // TODO(tommi): This should never happen really and I'm not sure that
453 HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters( 403 // setting use_input_params is the right thing to do since WASAPI i
454 output_device_id.empty() ? GetDefaultOutputDeviceID() 404 // definitely supported (see core_audio_supported() above) and
455 : output_device_id, 405 // |use_input_params| is only for cases when it isn't supported.
456 true, &params); 406 DLOG(ERROR) << "GetPreferredAudioParameters failed: " << std::hex << hr;
457 if (SUCCEEDED(hr)) { 407 use_input_params = true;
tommi (sloooow) - chröme 2017/01/24 21:10:51 this is another thing that I think we may have unn
DaleCurtis 2017/01/24 21:47:26 Since we're keeping WaveOut I think we still need
tommi (sloooow) - chröme 2017/01/25 12:49:25 Makes sense. Looking at the case where input_param
henrika (OOO until Aug 14) 2017/01/25 12:59:42 I kind of have the same feeling. It would probably
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 } 408 }
472 } 409 }
473 410
474 if (input_params.IsValid()) { 411 if (input_params.IsValid()) {
475 // If the user has enabled checking supported channel layouts or we don't 412 // 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 413 // 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. 414 // http://crbug.com/259165 and http://crbug.com/311906 for more details.
478 if (core_audio_supported() && 415 if (cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts) ||
479 (cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts) || 416 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 417 // 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 418 // 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 419 // hardware (preferred) layout. We do this extra check to avoid the
484 // CoreAudioUtil::IsChannelLayoutSupported() overhead in most cases. 420 // CoreAudioUtil::IsChannelLayoutSupported() overhead in most cases.
485 if (input_params.channel_layout() != channel_layout) { 421 if (input_params.channel_layout() != channel_layout) {
486 // TODO(henrika): Internally, IsChannelLayoutSupported does many of the 422 // TODO(henrika): Internally, IsChannelLayoutSupported does many of the
487 // operations that have already been done such as opening up a client 423 // operations that have already been done such as opening up a client
488 // and fetching the WAVEFORMATPCMEX format. Ideally we should only do 424 // and fetching the WAVEFORMATPCMEX format. Ideally we should only do
489 // that once. Then here, we can check the layout from the data we 425 // that once. Then here, we can check the layout from the data we
490 // already hold. 426 // already hold.
(...skipping 26 matching lines...) Expand all
517 int user_buffer_size = GetUserBufferSize(); 453 int user_buffer_size = GetUserBufferSize();
518 if (user_buffer_size) 454 if (user_buffer_size)
519 buffer_size = user_buffer_size; 455 buffer_size = user_buffer_size;
520 456
521 AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, 457 AudioParameters params(AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout,
522 sample_rate, bits_per_sample, buffer_size); 458 sample_rate, bits_per_sample, buffer_size);
523 params.set_effects(effects); 459 params.set_effects(effects);
524 return params; 460 return params;
525 } 461 }
526 462
527 AudioInputStream* AudioManagerWin::CreatePCMWaveInAudioInputStream( 463 // 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( 464 ScopedAudioManagerPtr CreateAudioManager(
547 scoped_refptr<base::SingleThreadTaskRunner> task_runner, 465 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
548 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner, 466 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner,
549 AudioLogFactory* audio_log_factory) { 467 AudioLogFactory* audio_log_factory) {
550 return ScopedAudioManagerPtr( 468 return ScopedAudioManagerPtr(
551 new AudioManagerWin(std::move(task_runner), std::move(worker_task_runner), 469 new AudioManagerWin(std::move(task_runner), std::move(worker_task_runner),
552 audio_log_factory)); 470 audio_log_factory));
553 } 471 }
554 472
555 } // namespace media 473 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698