How to enumerate DirectSound
devices
by Joe Plante
This drove me crazy, because I spent a few hours trying to figure out
how to do this because there aren't many tutorials dedicated to device
enumeration. A lot of them just use the primary sound driver (a.k.a.
NULL). It turned out to be incredibly easy. If you haven't used
callback prodecures/functions, basically a part of DirectSoundEnumerate
will call the callback function with the data you need. Just take a
look at my example code. Note the part where I put in "Moo!". You can
put anything there, or even NULL if you don't want to pass anything to
the callback function. I kept the functions simple since printf is a
good common denominator for programs.
You need to include DSound.lib. This example code is designed for a
multibyte character build.
#include <Dsound.h>
#include <stdio.h>
int main()
{
BOOL CALLBACK
DSEnumProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID
lpContext );
// this is all you
have to do. You don't even need to have a DirectSound device set up
//
// To demonstrate
lpContext, I am sending over "Moo!". "Moo!" doesn't do anything in this
case
if (
(DirectSoundEnumerate(DSEnumProc, (LPVOID)"Moo!")) == DS_OK )
{
printf("Operation completed successfully.\n");
}
else
{
printf("Houston, we have a problem.\n");
}
system("pause");
return 42;
}
// The way I understand it: the 4
parameters describe the item. lpContext is a generic parameter
// you can pass. This function runs once for every sound output device
it detects
//
// The GUID is what you would need to pass to DirectSound
BOOL CALLBACK
DSEnumProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID
lpContext )
{
printf("lpContext =
%s\n", (char *)lpContext);
printf("Device
description = %s\n", lpszDesc);
printf("Driver name
= %s\n", lpszDrvName);
printf("\n");
return TRUE;
}
A little fancier, perhaps to show how you might use lpContext
#include <Dsound.h>
#include <stdio.h>
#include <vector>
using std::vector;
//(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID
lpContext )
struct SoundCardInfo
{
LPGUID lpGuid;
char description[100];
};
int main()
{
BOOL CALLBACK DSEnumProc(LPGUID lpGUID, LPCTSTR lpszDesc,
LPCTSTR lpszDrvName, LPVOID lpContext );
vector<SoundCardInfo *> soundCardList;
// this is all you have to do. You don't even need to have
a DirectSound device set up
if ( (DirectSoundEnumerate(DSEnumProc,
(LPVOID)&soundCardList)) == DS_OK )
{
printf("Operation completed
successfully.\n");
}
else
{
printf("Houston, we have a problem.\n");
}
for ( size_t s = 0; s < soundCardList.size(); s++)
{
printf("Sound card detected: %s\n",
soundCardList.at(s)->description);
}
for ( size_t s = 0; s < soundCardList.size(); s++)
{
// remember to deallocate the pointers
delete soundCardList.at(s)->lpGuid;
delete soundCardList.at(s);
}
system("pause");
return 42;
}
// The way I understand it: the 4 parameters describe the item.
lpContext is a generic parameter
// you can pass. This function runs once for every sound output device
it detects
//
// The GUID is what you would need to pass to DirectSound
BOOL CALLBACK DSEnumProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR
lpszDrvName, LPVOID lpContext )
{
// this is a list of sound cards and GUIDs
vector<SoundCardInfo *> *soundCardList =
(vector<SoundCardInfo *> *)lpContext;
SoundCardInfo *sci = new SoundCardInfo();
// move the needed info into the data
structure
//memcpy(&(sci->guid), lpGUID, sizeof(GUID));
strcpy(sci->description, lpszDesc);
sci->lpGuid = NULL;
// NULL is the primary sound driver. Make sure you don't
memcpy from NULL. Visual Studio doesn't like it when you do that
if ( lpGUID != NULL )
{
// put the sound card information into
the vector of pointers
sci->lpGuid = new GUID();
// something went wrong trying to
allocate the RAM. Remember that "lp" in lpGUID means "long pointer",
which is about the same as *GUID
if ( sci->lpGuid == NULL )
{
return TRUE;
}
// copy the GUID over
memcpy(sci->lpGuid, lpGUID,
sizeof(GUID));
}
// and add the information to the list
soundCardList->push_back(sci);
return TRUE;
}