Introduction
Reading audio devices based on their categories is quite simple when it comes to DirectX. With a few lines of code, the tutorial here gives just a hint of the many powerful features of DirectX.
Suppose!
Suppose that you need to read the audio inputs that are available on your system. As a hardware programmer, you would need to know a hefty number of things to get access to the audio inputs, but here, with the help of DirectX, the simplicity is just awesome. The point to remember here is that the hardware must have its driver fully installed in order to access the various ports, i.e., mic jack, aux in, etc., to be accessed by DirectX. DirectX will only support the input devices that are exposed by the hardware driver itself.
Using the code
Simply using the COM classes and interfaces, we jump into the source code by first declaring the pointers to the interfaces.
HRESULT hr;
ICreateDevEnum *pDeviceEnum = NULL;
IEnumMoniker *pEnumCat = NULL;
The program is very simple, and is console based. First, we need to create a device enumeration. A device enumeration allows us to get hold of or "read in" the audio devices that are available on the system. Here, we need to specify the category of devices that we are trying to read or get hold of. The "CLSID_AudioInputDeviceCategory
", as in the code below:
hr = pDeviceEnum->CreateClassEnumerator(CLSID_AudioInputDeviceCategory, &pEnumCat, 0);
Whereas in DirectX, this category refers to audio input filters too. DirectX defines these filters as different categories, and we can access
specific hardware by changing the "CLSID_Xxx
" term. For example, some of the other categories defined in DirectX are "CLSID_VideoInputDeviceCategory
", "CLSID_AudioRendererCategory
", etc. From these names, you can easily infer what they can be used for. The other usefulness of using device enumeration via Class ID is that suppose we have two sound cards and both of them support the same filters, using this enumeration, we can treat them distinctively as separate instances. After the enumeration, we cannot simply use pin properties or access any other methods for the devices in the AudioInputDeviceCategory
. To do this, we have to use Monikers. A Moniker is an interface that refers to a specific audio device, and then we use IMoniker
and IPropertyBag
to bind devices to the moniker and read the properties of the devices, respectively. The IPropertyBag
interface holds the keys to the device properties, as shown in the code below:
while(pEnumCat->Next(1, &pDeviceMonik, &cFetched) == S_OK)
{
IPropertyBag *pPropBag;
hr = pDeviceMonik->BindToStorage(0, 0, IID_IPropertyBag,
(void **)&pPropBag);
if (SUCCEEDED(hr))
{
VARIANT varName, varCLSid;
VariantInit(&varName);
VariantInit(&varCLSid);
hr = pPropBag->Read(L"FriendlyName", &varName, 0);
if (SUCCEEDED(hr))
{
wcout<<varName.bstrVal<<endl;
}
hr = pPropBag->Read(L"CLSID", &varCLSid, 0);
if (SUCCEEDED(hr))
{
wcout<<varCLSid.bstrVal<<endl;
}
VariantClear(&varName);
VariantClear(&varCLSid);
pPropBag->Release();
}
pDeviceMonik->Release();
}
The last and final step is to use a VARIANT
data type (which is a structure itself) that stores the property values of the device. We read the properties of the device using IPropertyBag
, but we use VARIANT
to store these properties. The output of the program is where we access the VARIANT
type varCLSid
and varName
. The properly bstrVal
converts the string for output.
A screenshot below shows the audio input devices on my system. Note that the "Friendly Name" of the specific device is exactly the same as we see in Graphedit.
References