0

Is it possible to get a list of audio cards (not endpoints) in Win32?

This information would be really useful when constructing full-duplex audio streams, to be sure both input and output share the same hardware clock.

So far, I found PKEY_DeviceInterface_FriendlyName, which comes close, but probably cannot be used when 2 exact same audio cards are plugged in.

I also found Enumerating audio adapters in WinAPI, and while the WMI query in the accepted answer retrieves the results I'm looking for, I see no easy way to correlate those to a WASAPI endpoint device id.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Sjoerd van Kreel
  • 1,000
  • 6
  • 19
  • `PKEY_AudioEndpoint_GUID` is possibly helpful, as it maps from WASAPI endpoint ID to a DirectSound GUID, opening up a ton more functions to query information. https://learn.microsoft.com/en-us/windows/win32/coreaudio/pkey-audioendpoint-guid – Ben Voigt Feb 11 '21 at 21:07
  • Doesnt that basically leave me with creating IDirectSound8 from that guid, then querying for DSCAPS/DSCCAPS (https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ee416821(v=vs.85))? I see nothing in DirectSound that provides me with more info than WASAPI does, am i missing something? – Sjoerd van Kreel Feb 11 '21 at 22:06
  • DSCAPS looks like a lot more information than you get from `IMMDevice` but I still don't see anything that answers (these endpoints are part of the same adapter device and share a clock) either directly or through inference. Just thought I'd mention it in case you were already familiar with doing that in DirectSound. – Ben Voigt Feb 11 '21 at 22:09
  • I see, thanks. Unfortunately I don't see the info i need in there. – Sjoerd van Kreel Feb 11 '21 at 22:12
  • Btw just figured i could use the device topology api. Here is a nice example of going from a single endpoint device (IMMDevice::GetId()) to the full topology for the containing hardware: https://learn.microsoft.com/en-us/windows/win32/coreaudio/device-topologies. The example code in GetHardwareDeviceTopology (IMMDevice in, IDeviceTopology out) looked really promising. Unfortunately on my system this still results in 3 values for IDeviceTopology::GetDeviceId for a single card. – Sjoerd van Kreel Feb 11 '21 at 22:13
  • Another thing to try is that if `IMMDevice::GetPropertyStore()` mentions `PKEY_FriendlyName`, you might also be able to query other device properties such as `DEVPKEY_Parent` – Ben Voigt Feb 11 '21 at 22:14
  • DEVPKEY_Parent sounds promising. Where can i find it? Its neither here https://learn.microsoft.com/en-us/windows/win32/coreaudio/device-properties nor here https://learn.microsoft.com/en-us/windows/win32/coreaudio/audio-endpoint-properties. – Sjoerd van Kreel Feb 11 '21 at 22:17
  • oops, I meant `DEVPKEY_Device_Parent`, part of the Device Manager API. https://learn.microsoft.com/en-us/windows-hardware/drivers/install/devpkey-device-parent – Ben Voigt Feb 11 '21 at 22:20
  • @SjoerdvanKreel - what you really need get and for what ? deviceId ? for which interface ? how then use this string ? – RbMm Feb 11 '21 at 22:20
  • @BenVoigt will investigate, thanks a lot! Guess ill be digging into the device driver API's :) – Sjoerd van Kreel Feb 11 '21 at 22:23
  • @RbMm I want to be able to tell if 2 IMMDevice instances, for example analog in/analog out, but also analog out/digital out, or line-in vs mic-in, reside on the same audio card. – Sjoerd van Kreel Feb 11 '21 at 22:24
  • i am not sure (not work with this interfaces) are `IMMDevice::GetId` return exactly device id string. how it look like ? i mean example of concrete string ( say *HDAUDIO\FUNC_01&VEN_8086&DEV_280B&SUBSYS_80860101&REV_1000\4&2B2ECA69&0&0201* or how ?) if it exactly device id - possible use CM_ api for this, say `CM_Get_Parent`, `CM_Get_DevNode_PropertyW`, `CM_Locate_DevNodeW` etc – RbMm Feb 11 '21 at 22:30
  • Still wondering though, i'd thought topology API would be a perfect fit for this. Got an E-MU card which returns the same adapter id's for both input and output, but built-in realtek gives this {2}.\\?\hdaudio#func_01&ven_10ec&dev_0892&subsys_1849d892&rev_1003#4&21a4c4ce&0&0001#{6994ad04-93ef-11d0-a3cc-00a0c9223196}\rtlineintopo for input, and same thing but ending in "singlelineouttopo" for output. Looks like input and output have their own topologies on that card. – Sjoerd van Kreel Feb 11 '21 at 22:32
  • @RbMm IMMDevice::GetId returns something much simpler like "{0.0.0.00000000}.{ecd97c22-6c82-48c7-a61d-5bac566f7afa}". The stuff you post though looks suspiciously similar to device topology output, maybe I should use device topology and device driver API's together. – Sjoerd van Kreel Feb 11 '21 at 22:35
  • strings begin with \\?\ and ended with #{..} - this is device interface string. in concrete case this is [`KSCATEGORY_AUDIO`](https://learn.microsoft.com/en-us/windows-hardware/drivers/install/kscategory-audio) device interface. from it you can get device id string, etc. but i not sure - what you have as input and what want got finally – RbMm Feb 11 '21 at 22:38
  • this is example what possible get from CM_ api - https://pastebin.com/WBeyiuz3 – RbMm Feb 11 '21 at 22:43
  • @RdMm i have as input the result of IMMDevice::GetId(). For example let's say i have one IMMDevice representing analog capture with id {0.0....}{guid1} and another one representing analog output, on the same card, with id {0.0...}{guid2}. Then i seek a function that translates both of them to the same audio adapter id for example {2}.\\?\hdaudio#func_01&ven_10ec&dev_0892&subsys_1849d892&rev_1003#4&21a4c4ce&0&0001#{6994ad04-93ef-11d0-a3cc-00a0c9223196}. Stuff you posted looks interesting, will check it out. – Sjoerd van Kreel Feb 11 '21 at 22:55
  • ok, this mean `IMMDevice::GetId` return [*Device Instance ID*](https://docs.microsoft.com/en-us/windows-hardware/drivers/install/device-instance-ids) but truncated - need append SWD\MMDEVAPI\ to string as prefix. after this string can be used as input for [`CM_Locate_DevNodeW`](https://docs.microsoft.com/en-us/windows/win32/api/cfgmgr32/nf-cfgmgr32-cm_locate_devnodew). and returned `DEVINST` can be used for [`CM_Get_DevNode_PropertyW`](https://docs.microsoft.com/en-us/windows/win32/api/cfgmgr32/nf-cfgmgr32-cm_get_devnode_propertyw), with `DEVPKEY_Device_...`, get parent, child, sibling.. – RbMm Feb 12 '21 at 02:25
  • Use IMMDevice::OpenPropertyStore and ask for PKEY_Endpoint_Devnode (fmtid={b3f8fa53-0004-438e-9003-51a46e139bfc} pid=2) this should get you a string that's close to device instance id. – Simon Mourier Feb 12 '21 at 17:50
  • @SimonMourier where is PKEY_Endpoint_Devnode declared? Its not in functiondiscoverykeys_devpkey.h with the rest of the property keys, also i cannot find it being documented anywhere. – Sjoerd van Kreel Feb 13 '21 at 20:19
  • I gave you it's value/definition. You'll have to declare it "manually" before you can query for it. Or get all the properties for the store and you'll see it's in the set. – Simon Mourier Feb 13 '21 at 22:06
  • @SimonMourier this is exactly what I was looking for, thanks! One thing though, I'm concerned about using undocumented features. In this case not only undocumented but also not even supplied in windows system headers. Is this guaranteed to work from windows 7 onwards? – Sjoerd van Kreel Feb 14 '21 at 11:05
  • @SjoerdvanKreel - I do have this on Windows 10, and it's been there for 10 years, but nothing's guaranteed. – Simon Mourier Feb 14 '21 at 16:38

1 Answers1

0

Turns out my premise was wrong. Apparently just because multiple endpoints reside on the same physical device it does not mean they share the same clock (although it might be the case). See here: https://portaudio.music.columbia.narkive.com/0qYpAMkP/understanding-multiple-streams and here: https://audiophilestyle.com/forums/topic/19715-hq-player/page/584/, so that basically defeats the purpose of my question. Thanks for the help anyway, everyone.

Sjoerd van Kreel
  • 1,000
  • 6
  • 19