Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / Win32

A simple console audio input device reader

3.31/5 (9 votes)
30 Nov 2008CPOL2 min read 49.7K   1.9K  
How to read audio input devices in DirectX.

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;    // COM result
ICreateDevEnum *pDeviceEnum = NULL;// Create the System Device Enumerator.
IEnumMoniker *pEnumCat = NULL;// Device enumeration moniker

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)
// Read the devices(filters) one by one
{
    IPropertyBag *pPropBag;
    // now bind the properties to the specific device
    hr = pDeviceMonik->BindToStorage(0, 0, IID_IPropertyBag, 
                                       (void **)&pPropBag);
    if (SUCCEEDED(hr))
    {
        // using VARIANT to store property values
        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);
        // To create an instance of the filter, do the following:
        //IBaseFilter *pFilter;
        //hr = pDeviceMonik->BindToObject(NULL, NULL, IID_IBaseFilter,
           // (void**)&pFilter);
       
        //Remember to release pFilter later.
        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.

graphedit.jpg

console.jpg

References

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)