The technique you use to enumerate audio devices depends on what audio output (or input) driver type you are using. This article shows the technique for each supported output device.
To discover the number of output devices you can use WaveOut.DeviceCount
. Then you can call WaveOut.GetCapabilities
passing in the index of a device to find out its name (and some basic information about its capabilities).
Note that you can also pass an index of -1 which is the "audio mapper". Use this if you want to keep playing audio even when a device is removed (such as USB headphones being unplugged).
Also note that the ProductName
retured is limited to 32 characters, resulting in it often being truncated. This is a limitation of the underlying Windows API and there is unfortunately no easy way to fix it in NAudio.
for (int n = -1; n < WaveOut.DeviceCount; n++)
{
var caps = WaveOut.GetCapabilities(n);
Console.WriteLine($"{n}: {caps.ProductName}");
}
Once you've selected the device you want, you can open it by creating an instance of WaveOut
or WaveOutEvent
and specifying it as the DeviceNumber
:
var outputDevice = new WaveOutEvent() { DeviceNumber = deviceNumber };
Getting details of audio capture devices for WaveIn
is very similar to for WaveOut
:
for (int n = -1; n < WaveIn.DeviceCount; n++)
{
var caps = WaveIn.GetCapabilities(n);
Console.WriteLine($"{n}: {caps.ProductName}");
}
Once you've selected the device you want, you can open it by creating an instance of WaveIn
or WaveInEvent
and specifying it as the DeviceNumber
:
var recordingDevice = new WaveInEvent() { DeviceNumber = deviceNumber };
DirectSoundOut
exposes the Devices
static method allowing you to enumerate through all the output devices. This has the benefit over WaveOut
of not having truncated device names:
foreach (var dev in DirectSoundOut.Devices)
{
Console.WriteLine($"{dev.Guid} {dev.ModuleName} {dev.Description}");
}
Each device has a Guid, and that can be used to open a specific device:
var outputDevice = new DirectSoundOut(deviceGuid);
There are also a couple of special device GUIDs you can use to open the default playback device (DirectSoundOut.DSDEVID_DefaultPlayback
) or default voice playback device (DirectSoundOut.DSDEVID_DefaultVoicePlayback
)
WASAPI playback (render) and recording (capture) devices can both be accessed via the MMDeviceEnumerator
class. This allows you to enumerate only the type of devices you want (DataFlow.Render
or DataFlow.Capture
or DataFlow.All
).
You can also choose whether you want to include devices that are active, or also include disabled, unplugged or otherwise not present devices with the DeviceState
bitmask. Here we show them all:
var enumerator = new MMDeviceEnumerator();
foreach (var wasapi in enumerator.EnumerateAudioEndPoints(DataFlow.All, DeviceState.All))
{
Console.WriteLine($"{wasapi.DataFlow} {wasapi.FriendlyName} {wasapi.DeviceFriendlyName} {wasapi.State}");
}
To open the device you want, simply pass the device in to the appropriate WASAPI class depending on if you are playing back or recording...
var outputDevice = new WasapiOut(mmDevice, ...);
var recordingDevice = new WasapiIn(captureDevice, ...);
var loopbackCapture = new WasapiLoopbackCapture(loopbackDevice);
You can also use the MMEnumerator to request what the default device is for a number of different scenarios (playback or record, and voice, multimedia or 'console'):
enumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
You can discover the registered ASIO drivers on your system with AsioOut.GetDriverNames
. There is no guarantee that the associated soundcard is currently connected to the system.
foreach (var asio in AsioOut.GetDriverNames())
{
Console.WriteLine(asio);
}
You can then use the driver name to open the device:
new AsioOut(driverName);
Finally you can use Windows Management Objects to get hold of details of the sound devices installed. This doesn't map specifically to any of the NAudio output device types, but can be a source of useful information
var objSearcher = new ManagementObjectSearcher(
"SELECT * FROM Win32_SoundDevice");
var objCollection = objSearcher.Get();
foreach (var d in objCollection)
{
Console.WriteLine("=====DEVICE====");
foreach (var p in d.Properties)
{
Console.WriteLine($"{p.Name}:{p.Value}");
}
}