Here is a set of utility C# classes that allow you to get information on audio devices and audio session, including process information. They use the Windows Core Audio Library, and only work on Windows 7 or higher:
// sample program
class Program
{
static void Main(string[] args)
{
// dump all audio devices
foreach (AudioDevice device in AudioUtilities.GetAllDevices())
{
Console.WriteLine(device.FriendlyName);
}
// dump all audio sessions
foreach (AudioSession session in AudioUtilities.GetAllSessions())
{
if (session.Process != null)
{
// only the one associated with a defined process
Console.WriteLine(session.Process.ProcessName);
}
}
}
}
// audio utilities
public static class AudioUtilities
{
private static IAudioSessionManager2 GetAudioSessionManager()
{
IMMDevice speakers = GetSpeakers();
if (speakers == null)
return null;
// win7+ only
object o;
if (speakers.Activate(typeof(IAudioSessionManager2).GUID, CLSCTX.CLSCTX_ALL, IntPtr.Zero, out o) != 0 || o == null)
return null;
return o as IAudioSessionManager2;
}
public static AudioDevice GetSpeakersDevice()
{
return CreateDevice(GetSpeakers());
}
private static AudioDevice CreateDevice(IMMDevice dev)
{
if (dev == null)
return null;
string id;
dev.GetId(out id);
DEVICE_STATE state;
dev.GetState(out state);
Dictionary<string, object> properties = new Dictionary<string, object>();
IPropertyStore store;
dev.OpenPropertyStore(STGM.STGM_READ, out store);
if (store != null)
{
int propCount;
store.GetCount(out propCount);
for (int j = 0; j < propCount; j++)
{
PROPERTYKEY pk;
if (store.GetAt(j, out pk) == 0)
{
PROPVARIANT value = new PROPVARIANT();
int hr = store.GetValue(ref pk, ref value);
object v = value.GetValue();
try
{
if (value.vt != VARTYPE.VT_BLOB) // for some reason, this fails?
{
PropVariantClear(ref value);
}
}
catch
{
}
string name = pk.ToString();
properties[name] = v;
}
}
}
return new AudioDevice(id, (AudioDeviceState)state, properties);
}
public static IList<AudioDevice> GetAllDevices()
{
List<AudioDevice> list = new List<AudioDevice>();
IMMDeviceEnumerator deviceEnumerator = null;
try
{
deviceEnumerator = (IMMDeviceEnumerator)(new MMDeviceEnumerator());
}
catch
{
}
if (deviceEnumerator == null)
return list;
IMMDeviceCollection collection;
deviceEnumerator.EnumAudioEndpoints(EDataFlow.eAll, DEVICE_STATE.MASK_ALL, out collection);
if (collection == null)
return list;
int count;
collection.GetCount(out count);
for (int i = 0; i < count; i++)
{
IMMDevice dev;
collection.Item(i, out dev);
if (dev != null)
{
list.Add(CreateDevice(dev));
}
}
return list;
}
private static IMMDevice GetSpeakers()
{
// get the speakers (1st render + multimedia) device
try
{
IMMDeviceEnumerator deviceEnumerator = (IMMDeviceEnumerator)(new MMDeviceEnumerator());
IMMDevice speakers;
deviceEnumerator.GetDefaultAudioEndpoint(EDataFlow.eRender, ERole.eMultimedia, out speakers);
return speakers;
}
catch
{
return null;
}
}
public static IList<AudioSession> GetAllSessions()
{
List<AudioSession> list = new List<AudioSession>();
IAudioSessionManager2 mgr = GetAudioSessionManager();
if (mgr == null)
return list;
IAudioSessionEnumerator sessionEnumerator;
mgr.GetSessionEnumerator(out sessionEnumerator);
int count;
sessionEnumerator.GetCount(out count);
for (int i = 0; i < count; i++)
{
IAudioSessionControl ctl;
sessionEnumerator.GetSession(i, out ctl);
if (ctl == null)
continue;
IAudioSessionControl2 ctl2 = ctl as IAudioSessionControl2;
if (ctl2 != null)
{
list.Add(new AudioSession(ctl2));
}
}
Marshal.ReleaseComObject(sessionEnumerator);
Marshal.ReleaseComObject(mgr);
return list;
}
public static AudioSession GetProcessSession()
{
int id = Process.GetCurrentProcess().Id;
foreach (AudioSession session in GetAllSessions())
{
if (session.ProcessId == id)
return session;
session.Dispose();
}
return null;
}
[DllImport("ole32.dll")]
private static extern int PropVariantClear(ref PROPVARIANT pvar);
[ComImport]
[Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
private class MMDeviceEnumerator
{
}
[Flags]
private enum CLSCTX
{
CLSCTX_INPROC_SERVER = 0x1,
CLSCTX_INPROC_HANDLER = 0x2,
CLSCTX_LOCAL_SERVER = 0x4,
CLSCTX_REMOTE_SERVER = 0x10,
CLSCTX_ALL = CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER
}
private enum STGM
{
STGM_READ = 0x00000000,
}
private enum EDataFlow
{
eRender,
eCapture,
eAll,
}
private enum ERole
{
eConsole,
eMultimedia,
eCommunications,
}
private enum DEVICE_STATE
{
ACTIVE = 0x00000001,
DISABLED = 0x00000002,
NOTPRESENT = 0x00000004,
UNPLUGGED = 0x00000008,
MASK_ALL = 0x0000000F
}
[StructLayout(LayoutKind.Sequential)]
private struct PROPERTYKEY
{
public Guid fmtid;
public int pid;
public override string ToString()
{
return fmtid.ToString("B") + " " + pid;
}
}
// NOTE: we only define what we handle
[Flags]
private enum VARTYPE : short
{
VT_I4 = 3,
VT_BOOL = 11,
VT_UI4 = 19,
VT_LPWSTR = 31,
VT_BLOB = 65,
VT_CLSID = 72,
}
[StructLayout(LayoutKind.Sequential)]
private struct PROPVARIANT
{
public VARTYPE vt;
public ushort wReserved1;
public ushort wReserved2;
public ushort wReserved3;
public PROPVARIANTunion union;
public object GetValue()
{
switch (vt)
{
case VARTYPE.VT_BOOL:
return union.boolVal != 0;
case VARTYPE.VT_LPWSTR:
return Marshal.PtrToStringUni(union.pwszVal);
case VARTYPE.VT_UI4:
return union.lVal;
case VARTYPE.VT_CLSID:
return (Guid)Marshal.PtrToStructure(union.puuid, typeof(Guid));
default:
return vt.ToString() + ":?";
}
}
}
[StructLayout(LayoutKind.Explicit)]
private struct PROPVARIANTunion
{
[FieldOffset(0)]
public int lVal;
[FieldOffset(0)]
public ulong uhVal;
[FieldOffset(0)]
public short boolVal;
[FieldOffset(0)]
public IntPtr pwszVal;
[FieldOffset(0)]
public IntPtr puuid;
}
[Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IMMDeviceEnumerator
{
[PreserveSig]
int EnumAudioEndpoints(EDataFlow dataFlow, DEVICE_STATE dwStateMask, out IMMDeviceCollection ppDevices);
[PreserveSig]
int GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, out IMMDevice ppEndpoint);
[PreserveSig]
int GetDevice([MarshalAs(UnmanagedType.LPWStr)] string pwstrId, out IMMDevice ppDevice);
[PreserveSig]
int RegisterEndpointNotificationCallback(IMMNotificationClient pClient);
[PreserveSig]
int UnregisterEndpointNotificationCallback(IMMNotificationClient pClient);
}
[Guid("7991EEC9-7E89-4D85-8390-6C703CEC60C0"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IMMNotificationClient
{
void OnDeviceStateChanged([MarshalAs(UnmanagedType.LPWStr)] string pwstrDeviceId, DEVICE_STATE dwNewState);
void OnDeviceAdded([MarshalAs(UnmanagedType.LPWStr)] string pwstrDeviceId);
void OnDeviceRemoved([MarshalAs(UnmanagedType.LPWStr)] string deviceId);
void OnDefaultDeviceChanged(EDataFlow flow, ERole role, string pwstrDefaultDeviceId);
void OnPropertyValueChanged([MarshalAs(UnmanagedType.LPWStr)] string pwstrDeviceId, PROPERTYKEY key);
}
[Guid("0BD7A1BE-7A1A-44DB-8397-CC5392387B5E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IMMDeviceCollection
{
[PreserveSig]
int GetCount(out int pcDevices);
[PreserveSig]
int Item(int nDevice, out IMMDevice ppDevice);
}
[Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IMMDevice
{
[PreserveSig]
int Activate([MarshalAs(UnmanagedType.LPStruct)] Guid riid, CLSCTX dwClsCtx, IntPtr pActivationParams, [MarshalAs(UnmanagedType.IUnknown)] out object ppInterface);
[PreserveSig]
int OpenPropertyStore(STGM stgmAccess, out IPropertyStore ppProperties);
[PreserveSig]
int GetId([MarshalAs(UnmanagedType.LPWStr)] out string ppstrId);
[PreserveSig]
int GetState(out DEVICE_STATE pdwState);
}
[Guid("6f79d558-3e96-4549-a1d1-7d75d2288814"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IPropertyDescription
{
[PreserveSig]
int GetPropertyKey(out PROPERTYKEY pkey);
[PreserveSig]
int GetCanonicalName(out IntPtr ppszName);
[PreserveSig]
int GetPropertyType(out short pvartype);
[PreserveSig]
int GetDisplayName(out IntPtr ppszName);
// WARNING: the rest is undefined. you *can't* implement it, only use it.
}
[Guid("886d8eeb-8cf2-4446-8d02-cdba1dbdcf99"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IPropertyStore
{
[PreserveSig]
int GetCount(out int cProps);
[PreserveSig]
int GetAt(int iProp, out PROPERTYKEY pkey);
[PreserveSig]
int GetValue(ref PROPERTYKEY key, ref PROPVARIANT pv);
[PreserveSig]
int SetValue(ref PROPERTYKEY key, ref PROPVARIANT propvar);
[PreserveSig]
int Commit();
}
[Guid("BFA971F1-4D5E-40BB-935E-967039BFBEE4"), InterfaceTy