I am using dotNet c# . I need to identify default video and audio device I do know that I can enumerate audio device but how to determine default one ? ManagementObjectSearc
The currently selected default device will always appear as ID 0.
Super late to the party, but I recently worked to figure out how to get audio device information without relying on a 3rd party project like NAudio. The registry appears to keep up with changes to the audio playback and recording devices. This should provide you the means to obtain the names of the enabled or active audio recording or playback devices. Can't say that it will work flawlessly forever, but it works for me right now. I'm a novice at C#, so keep that in mind when reading through the comments.
using Microsoft.Win32;
using System;
namespace RetrieveAudioDeviceInfo
{
class Program
{
static void Main(string[] args)
{
string RequestedDeviceStatus = "Active"; // Initialize string variable for storing audio device status of interest. Valid input = "Active" or "Enabled"
string RequestedDeviceType = "Playback"; // Initialize string variable for storing audio device type of interest. Valid input = "Playback" or "Recording"
if (!String.Equals(RequestedDeviceStatus, "Active", StringComparison.OrdinalIgnoreCase) && !String.Equals(RequestedDeviceStatus, "Enabled", StringComparison.OrdinalIgnoreCase)) // Check RequestedDeviceStatus to ensure valid input was provided
{
Console.WriteLine("Invalid AudioDeviceStatus specified. Info request canceled"); // Output info to event log
Console.ReadLine(); // Wait for user input
return; // Immediately stop processing the inline function
}
string DeviceRegistryName; // Declare string variable for storing the registry name for the device type of interest
if (String.Equals(RequestedDeviceType, "Playback", StringComparison.OrdinalIgnoreCase)) // Check if info request is for playback devices
DeviceRegistryName = "Render"; // Set the DeviceRegistryName
else if (String.Equals(RequestedDeviceType, "Recording", StringComparison.OrdinalIgnoreCase)) // Check if info request is for recording devices
DeviceRegistryName = "Capture"; // Set the DeviceRegistryName
else
{
Console.WriteLine("Invalid AudioDeviceType specified. Info request canceled"); // Output info to event log
Console.ReadLine(); // Wait for user input
return; // Immediately stop processing the inline function
}
RegistryKey RootKey; // Initialize RegistryKey for containing the root (base) key to evaluate
if (Environment.Is64BitOperatingSystem) // Check if operating system is 64-bit
RootKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64); // Opens registry's LocalMachine key with a 64-bit view
else
RootKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32); // Opens registry's LocalMachine key with a 32-bit view
string AudioKey = @"SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio"; // Parent registry key for audio devices
string DeviceName, DeviceType; // Declare string variables for storing audio device information
string[] ActiveDeviceRoles = null; // Initialize string array for storing information about the active devices for each audio role
using (RegistryKey ChildKey = RootKey.OpenSubKey(AudioKey)) // Open subkey of AudioKey and store in ChildKey. "using" implemented for proper disposal.
{
foreach (string ChildKeyName in ChildKey.GetSubKeyNames()) // Loop through each SubKeyName in ChildKey
{
if (ChildKeyName == DeviceRegistryName) // Check if ChildKeyName is "Render" (signifies registry folder for audio playback devices)
{
using (RegistryKey RenderKey = ChildKey.OpenSubKey(ChildKeyName)) // Open subkey of ChildKey and store in RenderKey. "using" implemented for proper disposal.
{
DateTime[] ActiveDeviceRoleTimes = null; // Initialize DateTime array for storing times when audio devices last held a particular audio role
int j = 1; // Initialize integer variable for tracking audio playback device count
foreach (string DeviceKeyName in RenderKey.GetSubKeyNames()) // Loop through each SubKeyName in RenderKey
{
using (RegistryKey DeviceKey = RenderKey.OpenSubKey(DeviceKeyName)) // Open subkey of RenderKey and store in DeviceKey. "using" implemented for proper disposal.
{
if (Convert.ToInt32(DeviceKey.GetValue("DeviceState")) == 1) // Check if current audio device is enabled
{
string CurrentDeviceInfo; // Declare string variable for storing information about the current audio device
using (RegistryKey DeviceKeyProperties = DeviceKey.OpenSubKey("Properties")) // Open "Properties" subkey of DeviceKey and store in DeviceKeyProperties. "using" implemented for proper disposal.
{
DeviceName = DeviceKeyProperties.GetValue("{b3f8fa53-0004-438e-9003-51a46e139bfc},6").ToString(); // Retrieve the current device's name from the registry
DeviceType = DeviceKeyProperties.GetValue("{a45c254e-df1c-4efd-8020-67d146a850e0},2").ToString(); // Retrieve the current device's type from the registry
CurrentDeviceInfo = DeviceType + " (" + DeviceName + ")"; // Combine the DeviceName and DeviceType info similar to how VoiceAttack displays this data in the Options menu
if (String.Equals(RequestedDeviceStatus, "Enabled", StringComparison.OrdinalIgnoreCase)) // Check if user wants to show which audio devices are enabled
{
Console.WriteLine("Audio " + RequestedDeviceType + " Device " + j++ + " = " + CurrentDeviceInfo); // Output the CurrentDeviceInfo to the event log
continue; // Continue with next index in parent for loop
}
}
string[] roles = { "Role:0", "Role:1", "Role:2" }; // Initialize string array for storing the names of the different audio roles
DateTime[] CurrentDeviceRoleTimes = new DateTime[roles.Length]; // Initialize DateTime array for storing times when the current audio devices last held a particular audio role
//Console.WriteLine("Audio " + RequestedDeviceType + " Device " + j++ + " = " + CurrentDeviceInfo); // Output the CurrentDeviceInfo to the event log. Useful for debuging
for (int i = 0; i < roles.Length; i++) // Loop based on the size of the roles string array
{
byte[] RegistryData = (byte[])DeviceKey.GetValue(roles[i]); // Extract audio device role data from the registry
if (RegistryData == null) // Check if the extracted data is null
continue; // Continue to next index in parent for loop
CurrentDeviceRoleTimes[i] = GetRoleDateTime(RegistryData); // Retrieve role information from registry, convert this data to a DateTime, and store it
//Console.WriteLine(roles[i] + " = " + CurrentDeviceRoleTimes[i].ToString()); // Output info to event log. Useful for debuging
}
if (ActiveDeviceRoles == null || ActiveDeviceRoles.Length == 0) // Check if ActiveDeviceRoles is null or empty
{
ActiveDeviceRoles = new string[roles.Length]; // Initialize ActiveDeviceRoles string array
ActiveDeviceRoleTimes = new DateTime[roles.Length]; // Initialize ActiveDeviceRoleTImes DateTime array
}
for (int i = 0; i < roles.Length; i++) // Loop based on the size of the roles string array
{
if (ActiveDeviceRoleTimes[i] < CurrentDeviceRoleTimes[i]) // Check if the ActiveDeviceRoleTime at the current index is less than the CurrentDeviceRoleTime at this index
{
ActiveDeviceRoles[i] = CurrentDeviceInfo; // Set ActiveDeviceRoles at current index to CurrentDeviceInfo
ActiveDeviceRoleTimes[i] = CurrentDeviceRoleTimes[i]; // Set ActiveDeviceRoleTime at current index to corresponding CurrentDeviceRoleTime at this index
}
}
}
}
}
}
}
}
}
if (!String.Equals(RequestedDeviceStatus, "Enabled", StringComparison.OrdinalIgnoreCase)) // Check if user does NOT want to see the enabled devices
{
if (ActiveDeviceRoles != null) // Check if ActiveDeviceRoles is not null (i.e., enabled device data has been found and stored)
{
for (int i = 0; i < ActiveDeviceRoles.Length; i++) // Loop based on the size of the ActiveDeviceRoles string array
{
string RoleName = null; // Initialize string variable for storing role description
switch (i) // Create switch statement based on integer i
{
case 0: // For case where i = 0
RoleName = "Default"; // Set RoleName
break; // Break out of switch statement
case 1: // For case where i = 1
// There is the "Multimedia" role, but I don't believe this is currently used by Windows.
// The code for this role will remain for possible future use.
//RoleName = "Multimedia"; // Set RoleName
//break; // Break out of switch statement
continue; // Immediately continue with next index in parent for loop
case 2: // For case where i = 2
RoleName = "Communications"; // Set RoleName
break; // Break out of switch statement
}
if (ActiveDeviceRoles[i] == null) // Check if ActiveDeviceRole at current index is null
Console.WriteLine("{0} {1} Device = {2}", RoleName, RequestedDeviceType, "Not Set"); // Output info to event log
else
Console.WriteLine("{0} {1} Device = {2}", RoleName, RequestedDeviceType, ActiveDeviceRoles[i]); // Output info to event log
}
}
else
Console.WriteLine("No audio playback devices enabled"); // Output info to event log
}
Console.ReadLine();
}
// Function for converting registry data for an audio device into corresponding DateTime information
static DateTime GetRoleDateTime(byte[] binary)
{
if (binary == null || binary.Length != 16) // Check if binary is null or the length is not 16
throw new ArgumentException("Error converting registry data to DateTime"); // Throw an exception
int year = Convert.ToInt32(binary[0] + binary[1]*256); // Extract year from registy data
int month = Convert.ToInt32(binary[2]); // Extract month from registy data
int day = Convert.ToInt32(binary[6]); // Extract day from registy data
int hour = Convert.ToInt32(binary[8]); // Extract hour from registy data
int minute = Convert.ToInt32(binary[10]); // Extract minute from registy data
int seconds = Convert.ToInt32(binary[12]); // Extract seconds from registy data
int milliseconds = Convert.ToInt32(binary[14] + binary[15]*256); // Extract milliseconds from registy data
return new DateTime(year, month, day, hour, minute, seconds, milliseconds).ToLocalTime(); // Return the converted DateTime data
}
}
}
// References:
// https://stackoverflow.com/questions/14668091/read-registry-binary-and-convert-to-string
// https://msdn.microsoft.com/en-us/library/system.datetime.frombinary(v=vs.110).aspx
// https://social.msdn.microsoft.com/Forums/vstudio/en-US/382c06b1-a660-47da-a6e6-a7b27404581a/regbinary-value-from-registry-to-date-format-conversion?forum=csharpgeneral
// http://nircmd.nirsoft.net/setdefaultsounddevice.html
// https://stackoverflow.com/questions/3121957/how-can-i-do-a-case-insensitive-string-comparison
Thanks to the hard work by @Exergist, and some reading of the code, I acheived the same result in Python so that I can use pyaudio properly. Also, I had to use Level:0 not Role:0. Here is my final result
import winreg as wr
import platform
def is_os_64bit():
return platform.machine().endswith('64')
def get_active_device():
read_access = wr.KEY_READ | wr.KEY_WOW64_64KEY if is_os_64bit() else wr.KEY_READ
audio_path = r'SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Render'
child_key = wr.OpenKeyEx(wr.HKEY_LOCAL_MACHINE, audio_path, 0, read_access)
devices = wr.QueryInfoKey(child_key)[0]
active_last_used = -1
active_device_name = None
for i in range(devices):
device_key_path = f'{audio_path}\\{wr.EnumKey(child_key, i)}'
device_key = wr.OpenKeyEx(wr.HKEY_LOCAL_MACHINE, device_key_path, 0, read_access)
if wr.QueryValueEx(device_key, 'DeviceState')[0] == 1:
properties_path = f'{device_key_path}\\Properties'
properties = wr.OpenKeyEx(wr.HKEY_LOCAL_MACHINE, properties_path, 0, read_access)
device_name = wr.QueryValueEx(properties, '{b3f8fa53-0004-438e-9003-51a46e139bfc},6')[0]
device_type = wr.QueryValueEx(properties, '{a45c254e-df1c-4efd-8020-67d146a850e0},2')[0]
pa_name = f'{device_type} ({device_name})' # name shown in PyAudio
last_used = wr.QueryValueEx(device_key, 'Level:0')[0]
if last_used > active_last_used: # the bigger the number, the more recent it was used
active_last_used = last_used
active_device_name = pa_name
return active_device_name