Getting the Preferred Audio Device Number

来源:互联网 发布:python常用函数 编辑:程序博客网 时间:2024/06/05 00:08

Getting the Preferred Audio Device Number

Why You Need This

If you only program for people who have a single piece of audio hardware, then you don't. But many Windows users have more than one output—for example, the motherboard's built-in audio and an added PCI SoundBlaster card. They can select their "preferred device" (that is, the one with the speakers attached :-) using Windows Sounds and Multimedia control panel. (For Google's benefit, at this point we'll stop to note that the "preferred audio device" is the same thing as the "default audio device".)

Windows refers to audio input and output devices by device numbers. Windows API audio functions generally require a device number. Once you have the device number, you can get the device name, properties and so forth. Some functions will let you pass the constant WAVE_MAPPER (which is a signed long of value -1) in lieu of a device number, which will automatically route the sound to the preferred device.

Note that you can't just assume that device 0 is the default device, or even a reasonable device; on my laptop, device 0 is my wretched WinModem. It's not a great output device for playing MP3 files. Actually it's not really good for anything.

Sometimes you aren't given the opportunity to pass WAVE_MAPPER (say you are using someone else's audio tools) or you are doing something tricky like requesting the device name. Then there's no getting around determining what the device number is.

Getting The Preferred Device Number

There is a Windows API call to do this, but it is a general purpose messaging API and not trivial to use. (And note that this only works on Windows ME, Win2k or later.) Here's what Microsoft has in the way of documentation:

  • Definition of the WaveOutMessage Function (Necessary but not sufficient reading.)
  • "Accessing the Preferred Device ID", a Microsoft Developer Note. (Tells how to do it, assuming you already know how.)

If you program with the Windows API all day long, then you are all set. But if you're just some pathetic Visual Basic hack like I am, this is not sufficient. Visual Basic doesn't have any more clue than I do about the value of DRVM_MAPPER_PREFERRED_GET and the API Manager is no help. This constant is defined in mmddk.h, which you can get by downloading and installing 90 MB of the soon-to-cost-$199 Win2k Driver Developer Kit or (because I'm annoyed at them about this) clicking here.

Strangely, the API Viewer thinks it knows about the WaveOutMessage message function. This is kind of unfortunate, because what it knows isn't right.

' This is WRONG WRONG WRONG WRONGPublic Const WAVE_MAPPER = -1&Public Declare Function waveOutMessage Lib "winmm.dll" Alias "waveOutMessage" _(ByVal hWaveOut As Long, ByVal msg As Long, ByVal dw1 As Long, ByVal dw2 As _ Long) As Long'' NO STOP EVIL BAD
Now I'm just an uneducated foon when it comes to VB, but passing a parameter by value just can't be right when the function is expecting a pointer. Paste this in a module instead:
Option ExplicitPublic Declare Function waveOutMessage Lib "winmm.dll" (ByVal hWaveOut _As Long, ByVal msg As Long, dw1_ptr As Long, dw2_ptr As Long) As LongPrivate Const WAVE_MAPPER As Long = -1&Private Const DRVM_MAPPER As Long = &H2000&Private Const DRVM_MAPPER_PREFERRED_GET As Long = DRVM_MAPPER + 21Private Const MMSYSERR_NOERROR = 0  '  no error'Public Function GetPreferredWaveoutDevice() As LongDim errcode As LongDim DWord1Ptr As Long    errcode = waveOutMessage(WAVE_MAPPER, DRVM_MAPPER_PREFERRED_GET, DWord1Ptr, 0)If errcode = MMSYSERR_NOERROR Then    GetPreferredWaveoutDevice = DWord1PtrElse    GetPreferredWaveoutDevice = -1End IfEnd Function

One hopes that passing WAVE_MAPPER by value is equivalent to specifing the device handle as WAVE_MAPPER cast as HWAVEOUT, as we are instructed to do. The above seems to work correctly and returns MMSYSERR_NOERROR, but it might not be completely correct. Mail me if I goofed.

Since I write in Labview a lot more often than in VB, I went ahead and made a Labview VI to do the same thing. Take your pick:

  • (Visual Basic) GetAudioDeviceNumberVB.zip
  • (Labview) GetAudioDeviceNumberLV.zip

You can figure out how to get the preferred audio input device or preferred MIDI device using the same technique; see Microsoft's developer note for the details.

Rob Calhoun
02 Oct 2002
rob at sign calhoun dot net.