Find DeviceNumber of Audio Device Name. How?

Get help with using AutoHotkey and its commands and hotkeys
KilliK
Posts: 224
Joined: 10 Mar 2016, 21:19

Find DeviceNumber of Audio Device Name. How?

01 Dec 2019, 18:39

Hello.

I have created a script which I use in conjunction with VoiceMeeter Banana, to independently alter the volumes of my audio devices (both real and virtual).
I use the SoundSet command with the respective DeviceNumber of the audio device, which I got from the soundcard analysis script as it was explained here:
https://www.autohotkey.com/docs/commands/SoundGet.htm

The script works fine, but I discovered a problem today. Somehow all the DeviceNumbers have changed, which means I need to reconfigure the script with the new numbers. This is not a good solution, because the numbers might change again in the future.
So I need to somehow know which each audio device name, as it is shown in Windows Sound Panel, corresponds to which DeviceNumber, before I initialize my script.

I did some digging and I found Lexikos' VA.ahk script which has more advanced audio functions than AHK's native commands, and also its reference tutorial.
https://autohotkey.com/board/topic/21984-vista-audio-control-functions/
https://ahkscript.github.io/VistaAudio/

So, which commands do I use and how in order to find out the DeviceNumber of let's say my audio device "Speakers"?
scriptor2016
Posts: 569
Joined: 21 Dec 2015, 02:34

Re: Find DeviceNumber of Audio Device Name. How?

01 Dec 2019, 20:52

This mutes/unmutes your "Speakers" - which corresponds with the word MASTER in the code below

Code: Select all

z::
soundset, +1,MASTER,MUTE 
return
to mute/unmute other devices, change the word MASTER to the proper word which matches the device you wish to control. The list is under "Control Type". The list is found here:

https://www.autohotkey.com/docs/commands/SoundSet.htm


If you're unsure of which word you're looking for, then go into your windows sound properties and then into the "Speakers" category, and look for the little sound volume icons beside each device. Then, run the script, press 'z' and whichever icon turns into a little icon with a red slash through it means you just muted that device. So whichever word(Control Type) you have in place of MASTER is the corresponding device
KilliK
Posts: 224
Joined: 10 Mar 2016, 21:19

Re: Find DeviceNumber of Audio Device Name. How?

01 Dec 2019, 21:32

I figured out how to map the device names with their corresponding mixer numbers using Lexicos' VA.ahk script, but I have discovered another problem with his script. it completely crashes my script when I run it in a loop.
Here is my code:

Code: Select all

#include VA.ahk

Loop 14 ;total number of my mixer devices
{
VA_dev:= VA_GetDevice(A_Index)
msgbox % VA_dev
VA_dev_name:= VA_GetDeviceName(VA_dev)
msgbox % VA_dev_name
if (VA_dev_name = "Speakers") {
speakersv:= A_Index
}
}
the loop works and I associate my device Speakers with its Mixer number, but when A_Index reaches 13, my script completely crashes and exits.
here is the thing though, if I dont use Loop and instead use the number 13 directly as an input variable for VA_GetDevice, the script doesnt crash, and then the VA_GetDevice function gives me the number 0 as a returned value, and the VA_GetDeviceName gives me an empty value.

Code: Select all

var:=13
VA_dev:= VA_GetDevice(var)
msgbox % VA_dev
VA_dev_name:= VA_GetDeviceName(VA_dev)
msgbox % VA_dev_name
So, what is the problem with the VA.ahk script? why does my script crashes when VA.ahk returns an empty value during a loop, but it doesnt crash when it returns the empty value when I run its commands only once?

anyway, the code works and the mixer numbers 13 and 14 dont give a device name, so I can break the loop when VA_GetDevice returns 0 and before it crashes with VA_GetDevice.
I am just asking to see if it is a bug with VA.ahk or I am doing something wrong.
lexikos
Posts: 6668
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

Re: Find DeviceNumber of Audio Device Name. How?

07 Dec 2019, 18:17

VA_GetDeviceName doesn't do any error-checking. Try this version:

Code: Select all

VA_GetDeviceName(device)
{
    static PKEY_Device_FriendlyName
    if !VarSetCapacity(PKEY_Device_FriendlyName)
        VarSetCapacity(PKEY_Device_FriendlyName, 20)
        ,VA_GUID(PKEY_Device_FriendlyName :="{A45C254E-DF1C-4EFD-8020-67D146A850E0}")
        ,NumPut(14, PKEY_Device_FriendlyName, 16)
    VarSetCapacity(prop, 24)
    if VA_IMMDevice_OpenPropertyStore(device, 0, store) = 0
    {
        ; store->GetValue(.., [out] prop)
        if DllCall(NumGet(NumGet(store+0)+5*A_PtrSize), "ptr", store, "ptr", &PKEY_Device_FriendlyName, "ptr", &prop) = 0
            VA_WStrOut(deviceName := NumGet(prop,8))
        ObjRelease(store)
    }
    return deviceName
}
The order of devices is defined by the system/the IMMDeviceEnumerator interface. SoundGet and SoundSet use the following in v1:

Code: Select all

			hr = deviceEnum->EnumAudioEndpoints(eAll, DEVICE_STATE_ACTIVE | DEVICE_STATE_UNPLUGGED, &devices);
			if (SUCCEEDED(hr))
			{
				hr = devices->Item((UINT)device_index, &aDevice);
				devices->Release();
			}
VA_GetDevice uses different values depending on the device_desc parameter. If you pass just an integer, it calls Item() like above, but passes the equivalent of eAll, DEVICE_STATE_ACTIVE. In other words, the numbering may differ if you have any enabled devices which are unplugged.

Since disabled devices are excluded, disabling or enabling a device may change the numbers of any enabled devices. Installing or connecting a new sound device (including USB headsets and video cards with HDMI outputs) could as well. Windows 10 feature updates are (with the exception of 1903->1909) essentially Windows upgrade installations, and in theory might affect the ordering since (I think) all of the device drivers are reinstalled (except in the unfortunate cases where devices are left without drivers...).


Since the device number is just an index in a collection and depends on the parameters you use to build the collection, the only way to "get" the device number of a device given its name is to get the whole collection using the same parameters as SoundSet/SoundGet, then find the one with that name. So basically what you're doing, except for unplugged devices.

You could make it more efficient and more reliable by taking a copy of VA_GetDevice, changing the parameters of EnumAudioEndpoints (from flow, 1 to 2, 9, i.e. eAll, DEVICE_STATE_ACTIVE | DEVICE_STATE_UNPLUGGED) and returning the device number instead of the device pointer. Basically, ObjRelease(device) and return index.

If you are looping through the devices by calling VA_dev := VA_GetDevice(A_Index), or using VA_GetDevice in other ways, it may be important to release each interface pointer once you are finished with it; e.g. ObjRelease(VA_dev) at the end of each iteration.


I have just released v2.0-a108. Since Vista is now the lowest common denominator for v2, the Sound functions in this release can use names, and the vestiges of the pre-Vista mixer API were removed. SoundGetName and SoundGetInterface can be used by scripts like yours, allowing consistency between the built-in Sound functions and scripts. Some parts of VA.ahk will no longer be needed, although most of the interface wrappers are still relevant.

Return to “Ask For Help”

Who is online

Users browsing this forum: 087t0876, Bing [Bot], Google [Bot], theon and 236 guests