2011-05-15 20:26:25 -07:00
/**
* OpenAL cross platform audio library
* Copyright ( C ) 2011 by authors .
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation ; either
* version 2 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Library General Public License for more details .
*
* You should have received a copy of the GNU Library General Public
* License along with this library ; if not , write to the
* Free Software Foundation , Inc . , 59 Temple Place - Suite 330 ,
* Boston , MA 02111 - 1307 , USA .
* Or go to http : //www.gnu.org/copyleft/lgpl.html
*/
# include "config.h"
2011-05-16 04:13:37 -07:00
# define COBJMACROS
2011-05-15 20:26:25 -07:00
# define _WIN32_WINNT 0x0500
# include <stdlib.h>
# include <stdio.h>
# include <memory.h>
2011-05-16 04:13:37 -07:00
# include <mmdeviceapi.h>
# include <audioclient.h>
2011-05-15 20:26:25 -07:00
# include <cguid.h>
# include <mmreg.h>
# ifndef _WAVEFORMATEXTENSIBLE_
# include <ks.h>
# include <ksmedia.h>
# endif
# include "alMain.h"
# include "AL/al.h"
# include "AL/alc.h"
DEFINE_GUID ( KSDATAFORMAT_SUBTYPE_PCM , 0x00000001 , 0x0000 , 0x0010 , 0x80 , 0x00 , 0x00 , 0xaa , 0x00 , 0x38 , 0x9b , 0x71 ) ;
DEFINE_GUID ( KSDATAFORMAT_SUBTYPE_IEEE_FLOAT , 0x00000003 , 0x0000 , 0x0010 , 0x80 , 0x00 , 0x00 , 0xaa , 0x00 , 0x38 , 0x9b , 0x71 ) ;
2011-05-16 04:13:37 -07:00
# define MONO SPEAKER_FRONT_CENTER
# define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
# define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
# define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
# define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
# define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
static IMMDeviceEnumerator * Enumerator = NULL ;
2011-05-15 20:26:25 -07:00
typedef struct {
2011-05-16 04:13:37 -07:00
IMMDevice * mmdev ;
IAudioClient * client ;
2011-05-15 20:26:25 -07:00
volatile int killNow ;
ALvoid * thread ;
} MMDevApiData ;
2011-05-16 04:13:37 -07:00
static const ALCchar mmDevice [ ] = " WASAPI Default " ;
2011-05-15 20:26:25 -07:00
2011-05-17 04:54:09 -07:00
static ALCboolean MakeExtensible ( WAVEFORMATEXTENSIBLE * out , const WAVEFORMATEX * in )
{
memset ( out , 0 , sizeof ( * out ) ) ;
if ( in - > wFormatTag = = WAVE_FORMAT_EXTENSIBLE )
* out = * ( WAVEFORMATEXTENSIBLE * ) in ;
else if ( in - > wFormatTag = = WAVE_FORMAT_PCM )
{
out - > Format = * in ;
out - > Format . wFormatTag = WAVE_FORMAT_EXTENSIBLE ;
out - > Format . cbSize = sizeof ( * out ) - sizeof ( * in ) ;
if ( out - > Format . nChannels = = 1 )
out - > dwChannelMask = MONO ;
else if ( out - > Format . nChannels = = 2 )
out - > dwChannelMask = STEREO ;
out - > SubFormat = KSDATAFORMAT_SUBTYPE_PCM ;
}
else if ( in - > wFormatTag = = WAVE_FORMAT_IEEE_FLOAT )
{
out - > Format = * in ;
out - > Format . wFormatTag = WAVE_FORMAT_EXTENSIBLE ;
out - > Format . cbSize = sizeof ( * out ) - sizeof ( * in ) ;
if ( out - > Format . nChannels = = 1 )
out - > dwChannelMask = MONO ;
else if ( out - > Format . nChannels = = 2 )
out - > dwChannelMask = STEREO ;
out - > SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT ;
}
else
{
AL_PRINT ( " Unhandled format tag: 0x%04x \n " , in - > wFormatTag ) ;
return ALC_FALSE ;
}
return ALC_TRUE ;
}
2011-05-15 20:26:25 -07:00
static void * MMDevApiLoad ( void )
{
2011-05-16 04:13:37 -07:00
if ( ! Enumerator )
{
void * mme = NULL ;
2011-05-16 10:31:38 -07:00
HRESULT hr = CoInitializeEx ( NULL , COINIT_APARTMENTTHREADED ) ;
if ( FAILED ( hr ) )
hr = CoInitializeEx ( NULL , COINIT_MULTITHREADED ) ;
2011-05-16 04:13:37 -07:00
if ( SUCCEEDED ( hr ) )
{
hr = CoCreateInstance ( & CLSID_MMDeviceEnumerator , NULL , CLSCTX_INPROC_SERVER , & IID_IMMDeviceEnumerator , & mme ) ;
if ( FAILED ( hr ) )
CoUninitialize ( ) ;
else
Enumerator = mme ;
}
}
return Enumerator ;
}
static ALuint MMDevApiProc ( ALvoid * ptr )
{
ALCdevice * device = ptr ;
MMDevApiData * data = device - > ExtraData ;
union {
IAudioRenderClient * iface ;
void * ptr ;
} render ;
UINT32 written , len ;
BYTE * buffer ;
HRESULT hr ;
hr = IAudioClient_GetService ( data - > client , & IID_IAudioRenderClient , & render . ptr ) ;
if ( FAILED ( hr ) )
{
AL_PRINT ( " Failed to get AudioRenderClient service: 0x%08lx \n " , hr ) ;
aluHandleDisconnect ( device ) ;
return 0 ;
}
SetRTPriority ( ) ;
while ( ! data - > killNow )
{
hr = IAudioClient_GetCurrentPadding ( data - > client , & written ) ;
if ( FAILED ( hr ) )
{
AL_PRINT ( " Failed to get padding: 0x%08lx \n " , hr ) ;
aluHandleDisconnect ( device ) ;
break ;
}
len = device - > UpdateSize * device - > NumUpdates - written ;
if ( len < device - > UpdateSize )
{
Sleep ( 10 ) ;
continue ;
}
len - = len % device - > UpdateSize ;
hr = IAudioRenderClient_GetBuffer ( render . iface , len , & buffer ) ;
if ( SUCCEEDED ( hr ) )
{
aluMixData ( device , buffer , len ) ;
hr = IAudioRenderClient_ReleaseBuffer ( render . iface , len , 0 ) ;
}
if ( FAILED ( hr ) )
{
AL_PRINT ( " Failed to buffer data: 0x%08lx \n " , hr ) ;
aluHandleDisconnect ( device ) ;
break ;
}
}
IAudioRenderClient_Release ( render . iface ) ;
return 0 ;
2011-05-15 20:26:25 -07:00
}
static ALCboolean MMDevApiOpenPlayback ( ALCdevice * device , const ALCchar * deviceName )
{
2011-05-16 04:13:37 -07:00
MMDevApiData * data = NULL ;
void * client = NULL ;
HRESULT hr ;
2011-05-15 20:26:25 -07:00
if ( ! MMDevApiLoad ( ) )
return ALC_FALSE ;
if ( ! deviceName )
deviceName = mmDevice ;
else if ( strcmp ( deviceName , mmDevice ) ! = 0 )
return ALC_FALSE ;
//Initialise requested device
2011-05-16 04:13:37 -07:00
data = calloc ( 1 , sizeof ( MMDevApiData ) ) ;
if ( ! data )
2011-05-15 20:26:25 -07:00
{
alcSetError ( device , ALC_OUT_OF_MEMORY ) ;
return ALC_FALSE ;
}
//MMDevApi Init code
2011-05-16 04:13:37 -07:00
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint ( Enumerator , eRender , eMultimedia , & data - > mmdev ) ;
if ( SUCCEEDED ( hr ) )
hr = IMMDevice_Activate ( data - > mmdev , & IID_IAudioClient , CLSCTX_INPROC_SERVER , NULL , & client ) ;
2011-05-15 20:26:25 -07:00
if ( FAILED ( hr ) )
{
2011-05-16 04:13:37 -07:00
if ( data - > mmdev )
IMMDevice_Release ( data - > mmdev ) ;
data - > mmdev = NULL ;
free ( data ) ;
2011-05-15 20:26:25 -07:00
AL_PRINT ( " Device init failed: 0x%08lx \n " , hr ) ;
return ALC_FALSE ;
}
2011-05-16 04:13:37 -07:00
data - > client = client ;
2011-05-15 20:26:25 -07:00
device - > szDeviceName = strdup ( deviceName ) ;
2011-05-16 04:13:37 -07:00
device - > ExtraData = data ;
2011-05-15 20:26:25 -07:00
return ALC_TRUE ;
}
static void MMDevApiClosePlayback ( ALCdevice * device )
{
2011-05-16 04:13:37 -07:00
MMDevApiData * data = device - > ExtraData ;
IAudioClient_Release ( data - > client ) ;
data - > client = NULL ;
IMMDevice_Release ( data - > mmdev ) ;
data - > mmdev = NULL ;
2011-05-15 20:26:25 -07:00
2011-05-16 04:13:37 -07:00
free ( data ) ;
2011-05-15 20:26:25 -07:00
device - > ExtraData = NULL ;
}
static ALCboolean MMDevApiResetPlayback ( ALCdevice * device )
{
2011-05-16 04:13:37 -07:00
MMDevApiData * data = device - > ExtraData ;
WAVEFORMATEXTENSIBLE OutputType ;
WAVEFORMATEX * wfx = NULL ;
HRESULT hr ;
hr = IAudioClient_GetMixFormat ( data - > client , & wfx ) ;
if ( FAILED ( hr ) )
{
AL_PRINT ( " Failed to get mix format: 0x%08lx \n " , hr ) ;
return ALC_FALSE ;
}
2011-05-17 04:54:09 -07:00
if ( ! MakeExtensible ( & OutputType , wfx ) )
2011-05-16 04:13:37 -07:00
{
2011-05-17 04:54:09 -07:00
CoTaskMemFree ( wfx ) ;
return ALC_FALSE ;
2011-05-16 04:13:37 -07:00
}
CoTaskMemFree ( wfx ) ;
wfx = NULL ;
2011-05-17 04:54:09 -07:00
if ( ! ( device - > Flags & DEVICE_FREQUENCY_REQUEST ) )
device - > Frequency = OutputType . Format . nSamplesPerSec ;
if ( ! ( device - > Flags & DEVICE_CHANNELS_REQUEST ) )
2011-05-16 04:13:37 -07:00
{
2011-05-17 04:54:09 -07:00
if ( OutputType . Format . nChannels = = 1 & & OutputType . dwChannelMask = = MONO )
device - > FmtChans = DevFmtMono ;
else if ( OutputType . Format . nChannels = = 2 & & OutputType . dwChannelMask = = STEREO )
device - > FmtChans = DevFmtStereo ;
else if ( OutputType . Format . nChannels = = 4 & & OutputType . dwChannelMask = = QUAD )
device - > FmtChans = DevFmtQuad ;
else if ( OutputType . Format . nChannels = = 6 & & OutputType . dwChannelMask = = X5DOT1 )
device - > FmtChans = DevFmtX51 ;
else if ( OutputType . Format . nChannels = = 7 & & OutputType . dwChannelMask = = X6DOT1 )
device - > FmtChans = DevFmtX61 ;
else if ( OutputType . Format . nChannels = = 8 & & OutputType . dwChannelMask = = X7DOT1 )
device - > FmtChans = DevFmtX71 ;
else
AL_PRINT ( " Unhandled channel config: %d -- 0x%08x \n " , OutputType . Format . nChannels , OutputType . dwChannelMask ) ;
2011-05-16 04:13:37 -07:00
}
switch ( device - > FmtChans )
{
case DevFmtMono :
OutputType . Format . nChannels = 1 ;
OutputType . dwChannelMask = MONO ;
break ;
case DevFmtStereo :
OutputType . Format . nChannels = 2 ;
OutputType . dwChannelMask = STEREO ;
break ;
case DevFmtQuad :
OutputType . Format . nChannels = 4 ;
OutputType . dwChannelMask = QUAD ;
break ;
case DevFmtX51 :
OutputType . Format . nChannels = 6 ;
OutputType . dwChannelMask = X5DOT1 ;
break ;
case DevFmtX61 :
OutputType . Format . nChannels = 7 ;
OutputType . dwChannelMask = X6DOT1 ;
break ;
case DevFmtX71 :
OutputType . Format . nChannels = 8 ;
OutputType . dwChannelMask = X7DOT1 ;
break ;
}
2011-05-17 04:54:09 -07:00
switch ( device - > FmtType )
{
case DevFmtByte :
device - > FmtType = DevFmtUByte ;
/* fall-through */
case DevFmtUByte :
OutputType . Format . wBitsPerSample = 8 ;
OutputType . Samples . wValidBitsPerSample = 8 ;
OutputType . SubFormat = KSDATAFORMAT_SUBTYPE_PCM ;
break ;
case DevFmtUShort :
device - > FmtType = DevFmtShort ;
/* fall-through */
case DevFmtShort :
OutputType . Format . wBitsPerSample = 16 ;
OutputType . Samples . wValidBitsPerSample = 16 ;
OutputType . SubFormat = KSDATAFORMAT_SUBTYPE_PCM ;
break ;
case DevFmtFloat :
OutputType . Format . wBitsPerSample = 32 ;
OutputType . Samples . wValidBitsPerSample = 32 ;
OutputType . SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT ;
break ;
}
2011-05-16 04:13:37 -07:00
OutputType . Format . nSamplesPerSec = device - > Frequency ;
2011-05-17 04:54:09 -07:00
OutputType . Format . nBlockAlign = OutputType . Format . nChannels *
OutputType . Format . wBitsPerSample / 8 ;
OutputType . Format . nAvgBytesPerSec = OutputType . Format . nSamplesPerSec *
OutputType . Format . nBlockAlign ;
hr = IAudioClient_IsFormatSupported ( data - > client , AUDCLNT_SHAREMODE_SHARED , & OutputType . Format , & wfx ) ;
if ( FAILED ( hr ) )
hr = IAudioClient_GetMixFormat ( data - > client , & wfx ) ;
if ( FAILED ( hr ) )
{
AL_PRINT ( " Failed to find a supported format \n " ) ;
return ALC_FALSE ;
}
if ( wfx ! = NULL )
{
if ( ! MakeExtensible ( & OutputType , wfx ) )
{
CoTaskMemFree ( wfx ) ;
return ALC_FALSE ;
}
CoTaskMemFree ( wfx ) ;
wfx = NULL ;
if ( device - > Frequency ! = OutputType . Format . nSamplesPerSec )
{
if ( ( device - > Flags & DEVICE_FREQUENCY_REQUEST ) )
AL_PRINT ( " Failed to set %dhz, got %dhz instead \n " , device - > Frequency , OutputType . Format . nSamplesPerSec ) ;
device - > Flags & = ~ DEVICE_FREQUENCY_REQUEST ;
device - > Frequency = OutputType . Format . nSamplesPerSec ;
}
if ( ! ( ( device - > FmtChans = = DevFmtMono & & OutputType . Format . nChannels = = 1 & & OutputType . dwChannelMask = = MONO ) | |
( device - > FmtChans = = DevFmtStereo & & OutputType . Format . nChannels = = 2 & & OutputType . dwChannelMask = = STEREO ) | |
( device - > FmtChans = = DevFmtQuad & & OutputType . Format . nChannels = = 4 & & OutputType . dwChannelMask = = QUAD ) | |
( device - > FmtChans = = DevFmtX51 & & OutputType . Format . nChannels = = 6 & & OutputType . dwChannelMask = = X5DOT1 ) | |
( device - > FmtChans = = DevFmtX61 & & OutputType . Format . nChannels = = 7 & & OutputType . dwChannelMask = = X6DOT1 ) | |
( device - > FmtChans = = DevFmtX71 & & OutputType . Format . nChannels = = 8 & & OutputType . dwChannelMask = = X7DOT1 ) ) )
{
if ( ( device - > Flags & DEVICE_CHANNELS_REQUEST ) )
AL_PRINT ( " Failed to set %s, got %d channels (0x%08x) instead \n " , DevFmtChannelsString ( device - > FmtChans ) , OutputType . Format . nChannels , OutputType . dwChannelMask ) ;
device - > Flags & = ~ DEVICE_CHANNELS_REQUEST ;
if ( OutputType . Format . nChannels = = 1 & & OutputType . dwChannelMask = = MONO )
device - > FmtChans = DevFmtMono ;
else if ( OutputType . Format . nChannels = = 2 & & OutputType . dwChannelMask = = STEREO )
device - > FmtChans = DevFmtStereo ;
else if ( OutputType . Format . nChannels = = 4 & & OutputType . dwChannelMask = = QUAD )
device - > FmtChans = DevFmtQuad ;
else if ( OutputType . Format . nChannels = = 6 & & OutputType . dwChannelMask = = X5DOT1 )
device - > FmtChans = DevFmtX51 ;
else if ( OutputType . Format . nChannels = = 7 & & OutputType . dwChannelMask = = X6DOT1 )
device - > FmtChans = DevFmtX61 ;
else if ( OutputType . Format . nChannels = = 8 & & OutputType . dwChannelMask = = X7DOT1 )
device - > FmtChans = DevFmtX71 ;
else
{
AL_PRINT ( " Unhandled extensible channels: %d -- 0x%08x \n " , OutputType . Format . nChannels , OutputType . dwChannelMask ) ;
device - > FmtChans = DevFmtStereo ;
OutputType . Format . nChannels = 2 ;
OutputType . dwChannelMask = STEREO ;
}
}
if ( IsEqualGUID ( & OutputType . SubFormat , & KSDATAFORMAT_SUBTYPE_PCM ) )
{
if ( OutputType . Samples . wValidBitsPerSample = = 0 )
OutputType . Samples . wValidBitsPerSample = OutputType . Format . wBitsPerSample ;
if ( OutputType . Samples . wValidBitsPerSample ! = OutputType . Format . wBitsPerSample | |
! ( ( device - > FmtType = = DevFmtUByte & & OutputType . Format . wBitsPerSample = = 8 ) | |
( device - > FmtType = = DevFmtShort & & OutputType . Format . wBitsPerSample = = 16 ) ) )
{
AL_PRINT ( " Failed to set %s, got %d/%d-bit instead \n " , DevFmtTypeString ( device - > FmtType ) , OutputType . Samples . wValidBitsPerSample , OutputType . Format . wBitsPerSample ) ;
if ( OutputType . Format . wBitsPerSample = = 8 )
device - > FmtType = DevFmtUByte ;
else if ( OutputType . Format . wBitsPerSample = = 16 )
device - > FmtType = DevFmtShort ;
else
{
device - > FmtType = DevFmtShort ;
OutputType . Format . wBitsPerSample = 16 ;
}
OutputType . Samples . wValidBitsPerSample = OutputType . Format . wBitsPerSample ;
}
}
else if ( IsEqualGUID ( & OutputType . SubFormat , & KSDATAFORMAT_SUBTYPE_IEEE_FLOAT ) )
{
if ( OutputType . Samples . wValidBitsPerSample = = 0 )
OutputType . Samples . wValidBitsPerSample = OutputType . Format . wBitsPerSample ;
if ( OutputType . Samples . wValidBitsPerSample ! = OutputType . Format . wBitsPerSample | |
! ( ( device - > FmtType = = DevFmtFloat & & OutputType . Format . wBitsPerSample = = 32 ) ) )
{
AL_PRINT ( " Failed to set %s, got %d/%d-bit instead \n " , DevFmtTypeString ( device - > FmtType ) , OutputType . Samples . wValidBitsPerSample , OutputType . Format . wBitsPerSample ) ;
if ( OutputType . Format . wBitsPerSample ! = 32 )
{
device - > FmtType = DevFmtFloat ;
OutputType . Format . wBitsPerSample = 32 ;
}
OutputType . Samples . wValidBitsPerSample = OutputType . Format . wBitsPerSample ;
}
}
else
{
AL_PRINT ( " Unhandled format sub-type \n " ) ;
device - > FmtType = DevFmtShort ;
OutputType . Format . wBitsPerSample = 16 ;
OutputType . Samples . wValidBitsPerSample = OutputType . Format . wBitsPerSample ;
}
}
SetDefaultWFXChannelOrder ( device ) ;
2011-05-16 04:13:37 -07:00
hr = IAudioClient_Initialize ( data - > client , AUDCLNT_SHAREMODE_SHARED , 0 ,
( ALuint64 ) device - > UpdateSize * 10000000 /
device - > Frequency * device - > NumUpdates ,
0 , & OutputType . Format , NULL ) ;
if ( FAILED ( hr ) )
{
AL_PRINT ( " Failed to initialize audio client: 0x%08lx \n " , hr ) ;
return ALC_FALSE ;
}
hr = IAudioClient_Start ( data - > client ) ;
if ( FAILED ( hr ) )
{
AL_PRINT ( " Failed to start audio client \n " ) ;
return ALC_FALSE ;
}
data - > thread = StartThread ( MMDevApiProc , device ) ;
if ( ! data - > thread )
{
IAudioClient_Stop ( data - > client ) ;
AL_PRINT ( " Failed to start thread \n " ) ;
return ALC_FALSE ;
}
return ALC_TRUE ;
2011-05-15 20:26:25 -07:00
}
static void MMDevApiStopPlayback ( ALCdevice * device )
{
2011-05-16 04:13:37 -07:00
MMDevApiData * data = device - > ExtraData ;
2011-05-15 20:26:25 -07:00
2011-05-16 04:13:37 -07:00
if ( ! data - > thread )
2011-05-15 20:26:25 -07:00
return ;
2011-05-16 04:13:37 -07:00
data - > killNow = 1 ;
StopThread ( data - > thread ) ;
data - > thread = NULL ;
2011-05-15 20:26:25 -07:00
2011-05-16 04:13:37 -07:00
data - > killNow = 0 ;
2011-05-15 20:26:25 -07:00
2011-05-16 04:13:37 -07:00
IAudioClient_Stop ( data - > client ) ;
2011-05-15 20:26:25 -07:00
}
static ALCboolean MMDevApiOpenCapture ( ALCdevice * device , const ALCchar * deviceName )
{
( void ) device ;
( void ) deviceName ;
return ALC_FALSE ;
}
static const BackendFuncs MMDevApiFuncs = {
MMDevApiOpenPlayback ,
MMDevApiClosePlayback ,
MMDevApiResetPlayback ,
MMDevApiStopPlayback ,
MMDevApiOpenCapture ,
NULL ,
NULL ,
NULL ,
NULL ,
NULL
} ;
void alcMMDevApiInit ( BackendFuncs * FuncList )
{
* FuncList = MMDevApiFuncs ;
}
void alcMMDevApiDeinit ( void )
{
2011-05-16 04:13:37 -07:00
if ( Enumerator )
2011-05-15 20:26:25 -07:00
{
2011-05-16 04:13:37 -07:00
IMMDeviceEnumerator_Release ( Enumerator ) ;
Enumerator = NULL ;
CoUninitialize ( ) ;
2011-05-15 20:26:25 -07:00
}
}
void alcMMDevApiProbe ( int type )
{
if ( ! MMDevApiLoad ( ) ) return ;
if ( type = = DEVICE_PROBE )
AppendDeviceList ( mmDevice ) ;
else if ( type = = ALL_DEVICE_PROBE )
AppendAllDeviceList ( mmDevice ) ;
}