15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/audio_io.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h> 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <objbase.h> // This has to be before initguid.h 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <initguid.h> 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <mmsystem.h> 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <setupapi.h> 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/command_line.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 18ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch#include "base/message_loop/message_loop.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/path_service.h" 20a3f7b4e666c476898878fa745f637129375cd889Ben Murdoch#include "base/process/launch.h" 21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_number_conversions.h" 22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/win/windows_version.h" 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/audio_parameters.h" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/win/audio_device_listener_win.h" 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/win/audio_low_latency_input_win.h" 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/win/audio_low_latency_output_win.h" 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/win/audio_manager_win.h" 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/audio/win/core_audio_util_win.h" 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/win/device_enumeration_win.h" 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/win/wavein_input_win.h" 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/audio/win/waveout_output_win.h" 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "media/base/bind_to_current_loop.h" 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "media/base/channel_layout.h" 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/limits.h" 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "media/base/media_switches.h" 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Libraries required for the SetupAPI and Wbem APIs used here. 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#pragma comment(lib, "setupapi.lib") 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// The following are defined in various DDK headers, and we (re)define them here 422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// to avoid adding the DDK as a chrome dependency. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define DRV_QUERYDEVICEINTERFACE 0x80c 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define DRVM_MAPPER_PREFERRED_GET 0x2015 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define DRV_QUERYDEVICEINTERFACESIZE 0x80d 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DEFINE_GUID(AM_KSCATEGORY_AUDIO, 0x6994ad04, 0x93ef, 0x11d0, 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0xa3, 0xcc, 0x00, 0xa0, 0xc9, 0x22, 0x31, 0x96); 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace media { 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Maximum number of output streams that can be open simultaneously. 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kMaxOutputStreams = 50; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Up to 8 channels can be passed to the driver. This should work, given the 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// right drivers, but graceful error handling is needed. 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kWinMaxChannels = 8; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We use 3 buffers for recording audio so that if a recording callback takes 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// some time to return we won't lose audio. More buffers while recording are 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ok because they don't introduce any delay in recording, unlike in playback 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// where you first need to fill in that number of buffers before starting to 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// play. 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kNumInputBuffers = 3; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Buffer size to use for input and output stream when a proper size can't be 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// determined from the system 672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)static const int kFallbackBufferSize = 2048; 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int GetVersionPartAsInt(DWORDLONG num) { 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return static_cast<int>(num & 0xffff); 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns a string containing the given device's description and installed 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// driver version. 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)static base::string16 GetDeviceAndDriverInfo(HDEVINFO device_info, 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) SP_DEVINFO_DATA* device_data) { 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Save the old install params setting and set a flag for the 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // SetupDiBuildDriverInfoList below to return only the installed drivers. 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SP_DEVINSTALL_PARAMS old_device_install_params; 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) old_device_install_params.cbSize = sizeof(old_device_install_params); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetupDiGetDeviceInstallParams(device_info, device_data, 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &old_device_install_params); 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SP_DEVINSTALL_PARAMS device_install_params = old_device_install_params; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) device_install_params.FlagsEx |= DI_FLAGSEX_INSTALLEDDRIVER; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetupDiSetDeviceInstallParams(device_info, device_data, 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &device_install_params); 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SP_DRVINFO_DATA driver_data; 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) driver_data.cbSize = sizeof(driver_data); 905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 device_and_driver_info; 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (SetupDiBuildDriverInfoList(device_info, device_data, 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SPDIT_COMPATDRIVER)) { 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (SetupDiEnumDriverInfo(device_info, device_data, SPDIT_COMPATDRIVER, 0, 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &driver_data)) { 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORDLONG version = driver_data.DriverVersion; 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) device_and_driver_info = base::string16(driver_data.Description) + L" v" + 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString16(GetVersionPartAsInt((version >> 48))) + L"." + 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString16(GetVersionPartAsInt((version >> 32))) + L"." + 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString16(GetVersionPartAsInt((version >> 16))) + L"." + 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::IntToString16(GetVersionPartAsInt(version)); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetupDiDestroyDriverInfoList(device_info, device_data, SPDIT_COMPATDRIVER); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetupDiSetDeviceInstallParams(device_info, device_data, 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &old_device_install_params); 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return device_and_driver_info; 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)static int NumberOfWaveOutBuffers() { 1124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Use the user provided buffer count if provided. 1134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) int buffers = 0; 1144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) std::string buffers_str(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 1154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) switches::kWaveOutBuffers)); 1164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) if (base::StringToInt(buffers_str, &buffers) && buffers > 0) { 1174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return buffers; 1184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 1194e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 1204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // Use 4 buffers for Vista, 3 for everyone else: 1214e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // - The entire Windows audio stack was rewritten for Windows Vista and wave 1224e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // out performance was degraded compared to XP. 1234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // - The regression was fixed in Windows 7 and most configurations will work 1244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // with 2, but some (e.g., some Sound Blasters) still need 3. 1254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) // - Some XP configurations (even multi-processor ones) also need 3. 1264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) return (base::win::GetVersion() == base::win::VERSION_VISTA) ? 4 : 3; 1274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)} 1284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)AudioManagerWin::AudioManagerWin(AudioLogFactory* audio_log_factory) 1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : AudioManagerBase(audio_log_factory), 1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // |CoreAudioUtil::IsSupported()| uses static variables to avoid doing 1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // multiple initializations. This is however not thread safe. 1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // So, here we call it explicitly before we kick off the audio thread 1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // or do any other work. 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) enumeration_type_(CoreAudioUtil::IsSupported() ? 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kMMDeviceEnumeration : kWaveEnumeration) { 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetMaxOutputStreamsAllowed(kMaxOutputStreams); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // WARNING: This is executed on the UI loop, do not add any code here which 1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // loads libraries or attempts to call out into the OS. Instead add such code 1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // to the InitializeOnAudioThread() method below. 1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Task must be posted last to avoid races from handing out "this" to the 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // audio thread. 1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GetTaskRunner()->PostTask(FROM_HERE, base::Bind( 1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &AudioManagerWin::InitializeOnAudioThread, base::Unretained(this))); 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioManagerWin::~AudioManagerWin() { 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // It's safe to post a task here since Shutdown() will wait for all tasks to 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // complete before returning. 1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) GetTaskRunner()->PostTask(FROM_HERE, base::Bind( 1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) &AudioManagerWin::ShutdownOnAudioThread, base::Unretained(this))); 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Shutdown(); 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AudioManagerWin::HasAudioOutputDevices() { 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (::waveOutGetNumDevs() != 0); 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool AudioManagerWin::HasAudioInputDevices() { 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (::waveInGetNumDevs() != 0); 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AudioManagerWin::InitializeOnAudioThread() { 1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (core_audio_supported()) { 1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // AudioDeviceListenerWin must be initialized on a COM thread and should 1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // only be used if WASAPI / Core Audio is supported. 1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) output_device_listener_.reset(new AudioDeviceListenerWin(BindToCurrentLoop( 1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Bind(&AudioManagerWin::NotifyAllOutputDeviceChangeListeners, 1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::Unretained(this))))); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AudioManagerWin::ShutdownOnAudioThread() { 1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(GetTaskRunner()->BelongsToCurrentThread()); 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output_device_listener_.reset(); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)base::string16 AudioManagerWin::GetAudioInputDeviceModel() { 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Get the default audio capture device and its device interface name. 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD device_id = 0; 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) waveInMessage(reinterpret_cast<HWAVEIN>(WAVE_MAPPER), 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DRVM_MAPPER_PREFERRED_GET, 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<DWORD_PTR>(&device_id), NULL); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ULONG device_interface_name_size = 0; 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) waveInMessage(reinterpret_cast<HWAVEIN>(device_id), 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DRV_QUERYDEVICEINTERFACESIZE, 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<DWORD_PTR>(&device_interface_name_size), 0); 1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) size_t bytes_in_char16 = sizeof(base::string16::value_type); 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(0u, device_interface_name_size % bytes_in_char16); 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (device_interface_name_size <= bytes_in_char16) 1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return base::string16(); // No audio capture device. 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16 device_interface_name; 1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::string16::value_type* name_ptr = WriteInto(&device_interface_name, 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) device_interface_name_size / bytes_in_char16); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) waveInMessage(reinterpret_cast<HWAVEIN>(device_id), 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DRV_QUERYDEVICEINTERFACE, 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<DWORD_PTR>(name_ptr), 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<DWORD_PTR>(device_interface_name_size)); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Enumerate all audio devices and find the one matching the above device 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // interface name. 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HDEVINFO device_info = SetupDiGetClassDevs( 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &AM_KSCATEGORY_AUDIO, 0, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (device_info == INVALID_HANDLE_VALUE) 2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return base::string16(); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD interface_index = 0; 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SP_DEVICE_INTERFACE_DATA interface_data; 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) interface_data.cbSize = sizeof(interface_data); 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (SetupDiEnumDeviceInterfaces(device_info, 0, &AM_KSCATEGORY_AUDIO, 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) interface_index++, &interface_data)) { 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Query the size of the struct, allocate it and then query the data. 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SP_DEVINFO_DATA device_data; 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) device_data.cbSize = sizeof(device_data); 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DWORD interface_detail_size = 0; 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SetupDiGetDeviceInterfaceDetail(device_info, &interface_data, 0, 0, 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &interface_detail_size, &device_data); 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!interface_detail_size) 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 226c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) scoped_ptr<char[]> interface_detail_buffer(new char[interface_detail_size]); 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SP_DEVICE_INTERFACE_DETAIL_DATA* interface_detail = 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA*>( 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) interface_detail_buffer.get()); 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) interface_detail->cbSize = interface_detail_size; 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!SetupDiGetDeviceInterfaceDetail(device_info, &interface_data, 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) interface_detail, 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) interface_detail_size, NULL, 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &device_data)) 2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return base::string16(); 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool device_found = (device_interface_name == interface_detail->DevicePath); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (device_found) 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return GetDeviceAndDriverInfo(device_info, &device_data); 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return base::string16(); 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AudioManagerWin::ShowAudioInputSettings() { 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::wstring program; 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string argument; 2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!core_audio_supported()) { 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) program = L"sndvol32.exe"; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) argument = "-R"; 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) program = L"control.exe"; 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) argument = "mmsys.cpl,,1"; 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) base::FilePath path; 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PathService::Get(base::DIR_SYSTEM, &path); 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) path = path.Append(program); 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CommandLine command_line(path); 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) command_line.AppendArg(argument); 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::LaunchProcess(command_line, base::LaunchOptions(), NULL); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 26558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void AudioManagerWin::GetAudioDeviceNamesImpl( 26658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) bool input, 26758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) AudioDeviceNames* device_names) { 26858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) DCHECK(device_names->empty()); 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Enumerate all active audio-endpoint capture devices. 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (enumeration_type() == kWaveEnumeration) { 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Utilize the Wave API for Windows XP. 27258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (input) 27358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) GetInputDeviceNamesWinXP(device_names); 27458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) else 27558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) GetOutputDeviceNamesWinXP(device_names); 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Utilize the MMDevice API (part of Core Audio) for Vista and higher. 27858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (input) 27958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) GetInputDeviceNamesWin(device_names); 28058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) else 28158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) GetOutputDeviceNamesWin(device_names); 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Always add default device parameters as first element. 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!device_names->empty()) { 28658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) AudioDeviceName name; 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name.device_name = AudioManagerBase::kDefaultDeviceName; 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name.unique_id = AudioManagerBase::kDefaultDeviceId; 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) device_names->push_front(name); 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 29358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void AudioManagerWin::GetAudioInputDeviceNames(AudioDeviceNames* device_names) { 29458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) GetAudioDeviceNamesImpl(true, device_names); 29558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 29658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 29758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)void AudioManagerWin::GetAudioOutputDeviceNames( 29858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) AudioDeviceNames* device_names) { 29958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) GetAudioDeviceNamesImpl(false, device_names); 30058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 30158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AudioParameters AudioManagerWin::GetInputStreamParameters( 3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const std::string& device_id) { 304cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) AudioParameters parameters; 3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!core_audio_supported()) { 306cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Windows Wave implementation is being used. 307cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) parameters = AudioParameters( 3081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO, 48000, 3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 16, kFallbackBufferSize, AudioParameters::NO_EFFECTS); 310cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else { 311cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) parameters = WASAPIAudioInputStream::GetInputStreamParameters(device_id); 3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int user_buffer_size = GetUserBufferSize(); 315cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (user_buffer_size) { 316cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) parameters.Reset(parameters.format(), parameters.channel_layout(), 3171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci parameters.channels(), parameters.sample_rate(), 3181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci parameters.bits_per_sample(), user_buffer_size); 319cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 320cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 321cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return parameters; 3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 32458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)std::string AudioManagerWin::GetAssociatedOutputDeviceID( 32558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const std::string& input_device_id) { 3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!core_audio_supported()) { 327d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) NOTIMPLEMENTED() 328d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) << "GetAssociatedOutputDeviceID is not supported on this OS"; 329d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return std::string(); 330d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) } 33158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return CoreAudioUtil::GetMatchingOutputDeviceID(input_device_id); 33258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 33358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Factory for the implementations of AudioOutputStream for AUDIO_PCM_LINEAR 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// mode. 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - PCMWaveOutAudioOutputStream: Based on the waveOut API. 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioOutputStream* AudioManagerWin::MakeLinearOutputStream( 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AudioParameters& params) { 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (params.channels() > kWinMaxChannels) 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new PCMWaveOutAudioOutputStream(this, 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params, 34558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) NumberOfWaveOutBuffers(), 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) WAVE_MAPPER); 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Factory for the implementations of AudioOutputStream for 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AUDIO_PCM_LOW_LATENCY mode. Two implementations should suffice most 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// windows user's needs. 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - PCMWaveOutAudioOutputStream: Based on the waveOut API. 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - WASAPIAudioOutputStream: Based on Core Audio (WASAPI) API. 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioOutputStream* AudioManagerWin::MakeLowLatencyOutputStream( 35558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const AudioParameters& params, 3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& device_id) { 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (params.channels() > kWinMaxChannels) 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!core_audio_supported()) { 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Fall back to Windows Wave implementation on Windows XP or lower. 3631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) DLOG_IF(ERROR, !device_id.empty() && 3641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) device_id != AudioManagerBase::kDefaultDeviceId) 36558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) << "Opening by device id not supported by PCMWaveOutAudioOutputStream"; 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Using WaveOut since WASAPI requires at least Vista."; 3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return new PCMWaveOutAudioOutputStream( 36858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) this, params, NumberOfWaveOutBuffers(), WAVE_MAPPER); 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // Pass an empty string to indicate that we want the default device 3721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // since we consistently only check for an empty string in 3731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // WASAPIAudioOutputStream. 3741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) return new WASAPIAudioOutputStream(this, 3751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) device_id == AudioManagerBase::kDefaultDeviceId ? 3761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) std::string() : device_id, 377a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) params, 378a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) params.effects() & AudioParameters::DUCKING ? eCommunications : eConsole); 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Factory for the implementations of AudioInputStream for AUDIO_PCM_LINEAR 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// mode. 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioInputStream* AudioManagerWin::MakeLinearInputStream( 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AudioParameters& params, const std::string& device_id) { 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format()); 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return CreatePCMWaveInAudioInputStream(params, device_id); 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Factory for the implementations of AudioInputStream for 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// AUDIO_PCM_LOW_LATENCY mode. 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream( 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AudioParameters& params, const std::string& device_id) { 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(AudioParameters::AUDIO_PCM_LOW_LATENCY, params.format()); 3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DVLOG(1) << "MakeLowLatencyInputStream: " << device_id; 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AudioInputStream* stream = NULL; 3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!core_audio_supported()) { 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Fall back to Windows Wave implementation on Windows XP or lower. 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DVLOG(1) << "Using WaveIn since WASAPI requires at least Vista."; 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stream = CreatePCMWaveInAudioInputStream(params, device_id); 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stream = new WASAPIAudioInputStream(this, params, device_id); 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return stream; 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 40758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)std::string AudioManagerWin::GetDefaultOutputDeviceID() { 4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (!core_audio_supported()) 40958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return std::string(); 41058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) return CoreAudioUtil::GetDefaultOutputDeviceID(); 41158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)} 41258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters( 41458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) const std::string& output_device_id, 4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const AudioParameters& input_params) { 4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DLOG_IF(ERROR, !core_audio_supported() && !output_device_id.empty()) 41758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) << "CoreAudio is required to open non-default devices."; 41858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) 4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); 4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; 421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int sample_rate = 48000; 422c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) int buffer_size = kFallbackBufferSize; 4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int bits_per_sample = 16; 424a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) int effects = AudioParameters::NO_EFFECTS; 4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool use_input_params = !core_audio_supported(); 4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (core_audio_supported()) { 42758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) { 42858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // TODO(rtoy): tune these values for best possible WebAudio 42958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // performance. WebRTC works well at 48kHz and a buffer size of 480 43058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // samples will be used for this case. Note that exclusive mode is 43158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // experimental. This sample rate will be combined with a buffer size of 43258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) // 256 samples, which corresponds to an output delay of ~5.33ms. 43358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) sample_rate = 48000; 43458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) buffer_size = 256; 43558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (input_params.IsValid()) 43658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) channel_layout = input_params.channel_layout(); 437c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } else { 43858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) AudioParameters params; 43958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters( 44058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) output_device_id.empty() ? 44158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) GetDefaultOutputDeviceID() : output_device_id, 44258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) ¶ms); 44358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (SUCCEEDED(hr)) { 44458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) bits_per_sample = params.bits_per_sample(); 44558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) buffer_size = params.frames_per_buffer(); 44658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) channel_layout = params.channel_layout(); 44758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) sample_rate = params.sample_rate(); 448a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) effects = params.effects(); 44958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } else { 450a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // TODO(tommi): This should never happen really and I'm not sure that 451a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // setting use_input_params is the right thing to do since WASAPI i 452a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // definitely supported (see core_audio_supported() above) and 453a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) // |use_input_params| is only for cases when it isn't supported. 454a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DLOG(ERROR) << "GetPreferredAudioParameters failed: " << std::hex << hr; 45558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) use_input_params = true; 45658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) } 457c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (input_params.IsValid()) { 4610f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) // If the user has enabled checking supported channel layouts or we don't 4620f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) // have a valid channel layout yet, try to use the input layout. See bugs 4630f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) // http://crbug.com/259165 and http://crbug.com/311906 for more details. 4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (core_audio_supported() && 4650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) (cmd_line->HasSwitch(switches::kTrySupportedChannelLayouts) || 4660f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) channel_layout == CHANNEL_LAYOUT_UNSUPPORTED)) { 467c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Check if it is possible to open up at the specified input channel 468c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // layout but avoid checking if the specified layout is the same as the 469c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // hardware (preferred) layout. We do this extra check to avoid the 470c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // CoreAudioUtil::IsChannelLayoutSupported() overhead in most cases. 471c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (input_params.channel_layout() != channel_layout) { 4721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // TODO(henrika): Internally, IsChannelLayoutSupported does many of the 4731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // operations that have already been done such as opening up a client 4741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // and fetching the WAVEFORMATPCMEX format. Ideally we should only do 4751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // that once. Then here, we can check the layout from the data we 4761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) // already hold. 477c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (CoreAudioUtil::IsChannelLayoutSupported( 4781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) output_device_id, eRender, eConsole, 4791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) input_params.channel_layout())) { 480c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // Open up using the same channel layout as the source if it is 481c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) // supported by the hardware. 482c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) channel_layout = input_params.channel_layout(); 483c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) VLOG(1) << "Hardware channel layout is not used; using same layout" 484c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) << " as the source instead (" << channel_layout << ")"; 485c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 486c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 487c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) } 4881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 489a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) effects |= input_params.effects(); 490c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if (use_input_params) { 4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // If WASAPI isn't supported we'll fallback to WaveOut, which will take 4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // care of resampling and bits per sample changes. By setting these 4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // equal to the input values, AudioOutputResampler will skip resampling 4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // and bit per sample differences (since the input parameters will match 4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // the output parameters). 4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) bits_per_sample = input_params.bits_per_sample(); 497c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) buffer_size = input_params.frames_per_buffer(); 49858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) channel_layout = input_params.channel_layout(); 49958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) sample_rate = input_params.sample_rate(); 5002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int user_buffer_size = GetUserBufferSize(); 5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (user_buffer_size) 5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) buffer_size = user_buffer_size; 5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return AudioParameters( 5081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, 509a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) sample_rate, bits_per_sample, buffer_size, effects); 5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AudioInputStream* AudioManagerWin::CreatePCMWaveInAudioInputStream( 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const AudioParameters& params, 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& device_id) { 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string xp_device_id = device_id; 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (device_id != AudioManagerBase::kDefaultDeviceId && 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) enumeration_type_ == kMMDeviceEnumeration) { 51858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) xp_device_id = ConvertToWinXPInputDeviceId(device_id); 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (xp_device_id.empty()) { 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DLOG(ERROR) << "Cannot find a waveIn device which matches the device ID " 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << device_id; 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return NULL; 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new PCMWaveInAudioInputStream(this, params, kNumInputBuffers, 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) xp_device_id); 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// static 531a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)AudioManager* CreateAudioManager(AudioLogFactory* audio_log_factory) { 532a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return new AudioManagerWin(audio_log_factory); 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace media 536