mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2904 lines
103 KiB
2904 lines
103 KiB
/****************************************************************************
|
|
wave.c
|
|
|
|
Level 1 kitchen sink DLL wave support module
|
|
|
|
Copyright (c) 1990-2001 Microsoft Corporation
|
|
|
|
Changes for NT :
|
|
Change parameters for MapWaveId to return the driver index rather
|
|
than a pointer
|
|
|
|
change list of include files
|
|
|
|
widen function parameters and return codes
|
|
|
|
Change WINAPI to APIENTRY
|
|
****************************************************************************/
|
|
|
|
#include "winmmi.h"
|
|
|
|
/****************************************************************************
|
|
|
|
local structures
|
|
|
|
****************************************************************************/
|
|
|
|
typedef struct wavedev_tag {
|
|
PWAVEDRV wavedrv;
|
|
UINT wDevice;
|
|
DWORD_PTR dwDrvUser;
|
|
UINT uDeviceID;
|
|
DWORD fdwHandle;
|
|
} WAVEDEV, *PWAVEDEV;
|
|
|
|
extern UINT gRealWaveOutPreferredId;
|
|
extern UINT gRealWaveInPreferredId;
|
|
extern BOOL WaveMapperInitialized; // Wave mapper safely loaded
|
|
|
|
/*****************************************************************************
|
|
* @doc INTERNAL WAVE validation code for WAVEHDRs
|
|
*
|
|
****************************************************************************/
|
|
|
|
#define IsWaveHeaderPrepared(hWave, lpwh) ((lpwh)->dwFlags & WHDR_PREPARED)
|
|
#define MarkWaveHeaderPrepared(hWave, lpwh) ((lpwh)->dwFlags |= WHDR_PREPARED)
|
|
#define MarkWaveHeaderUnprepared(hWave, lpwh) ((lpwh)->dwFlags &=~WHDR_PREPARED)
|
|
|
|
/*****************************************************************************
|
|
* @doc INTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | wavePrepareHeader | This function prepares the header and data
|
|
* if the driver returns MMSYSERR_NOTSUPPORTED.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it
|
|
* specifies an error number.
|
|
****************************************************************************/
|
|
STATIC MMRESULT wavePrepareHeader(LPWAVEHDR lpWaveHdr, UINT wSize)
|
|
{
|
|
if (!HugePageLock(lpWaveHdr, (DWORD)sizeof(WAVEHDR)))
|
|
return MMSYSERR_NOMEM;
|
|
|
|
if (!HugePageLock(lpWaveHdr->lpData, lpWaveHdr->dwBufferLength)) {
|
|
HugePageUnlock(lpWaveHdr, (DWORD)sizeof(WAVEHDR));
|
|
return MMSYSERR_NOMEM;
|
|
}
|
|
|
|
lpWaveHdr->dwFlags |= WHDR_PREPARED;
|
|
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc INTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveUnprepareHeader | This function unprepares the header and
|
|
* data if the driver returns MMSYSERR_NOTSUPPORTED.
|
|
*
|
|
* @rdesc Currently always returns MMSYSERR_NOERROR.
|
|
****************************************************************************/
|
|
STATIC MMRESULT waveUnprepareHeader(LPWAVEHDR lpWaveHdr, UINT wSize)
|
|
{
|
|
HugePageUnlock(lpWaveHdr->lpData, lpWaveHdr->dwBufferLength);
|
|
HugePageUnlock(lpWaveHdr, (DWORD)sizeof(WAVEHDR));
|
|
|
|
lpWaveHdr->dwFlags &= ~WHDR_PREPARED;
|
|
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* @doc INTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveReferenceDriverById | This function maps a logical id
|
|
* to a device driver and physical id.
|
|
*
|
|
* @parm IN PWAVEDRV | pwavedrvZ | The list of wave drivers.
|
|
*
|
|
* @parm IN UINT | id | The logical id to be mapped.
|
|
*
|
|
* @parm OUT PWAVEDRV* OPTIONAL | ppwavedrv | Pointer to WAVEDRV structure
|
|
* describing the driver supporting the id.
|
|
*
|
|
* @parm OUT UINT* OPTIONAL | pport | The driver-relative device number. If
|
|
* the caller supplies this buffer then it must also supply ppwavedrv.
|
|
*
|
|
* @rdesc The return value is zero if successful, MMSYSERR_BADDEVICEID if
|
|
* the id is out of range.
|
|
*
|
|
* @comm If the caller specifies ppwavedrv then this function increments
|
|
* the wavedrv's usage before returning. The caller must ensure
|
|
* the usage is eventually decremented.
|
|
*
|
|
****************************************************************************/
|
|
MMRESULT waveReferenceDriverById(
|
|
IN PWAVEDRV pwavedrvZ,
|
|
IN UINT id,
|
|
OUT PWAVEDRV *ppwavedrv OPTIONAL,
|
|
OUT UINT *pport OPTIONAL
|
|
)
|
|
{
|
|
PWAVEDRV pwavedrv;
|
|
MMRESULT mmr;
|
|
|
|
// Should not be called asking for port but not wavedrv
|
|
WinAssert(!(pport && !ppwavedrv));
|
|
|
|
if (id == WAVE_MAPPER) {
|
|
/*
|
|
** Make sure we've tried to load it
|
|
*/
|
|
WaveMapperInit();
|
|
// WinAssert(((WaveMapperInitialized) || (0 == wTotalWaveInDevs + wTotalWaveOutDevs)));
|
|
}
|
|
|
|
EnterNumDevs("waveReferenceDriverById");
|
|
|
|
if (WAVE_MAPPER == id)
|
|
{
|
|
id = 0;
|
|
for (pwavedrv = pwavedrvZ->Next; pwavedrv != pwavedrvZ; pwavedrv = pwavedrv->Next)
|
|
{
|
|
if (pwavedrv->fdwDriver & MMDRV_MAPPER) break;
|
|
}
|
|
} else {
|
|
for (pwavedrv = pwavedrvZ->Next; pwavedrv != pwavedrvZ; pwavedrv = pwavedrv->Next)
|
|
{
|
|
if (pwavedrv->fdwDriver & MMDRV_MAPPER) continue;
|
|
if (pwavedrv->NumDevs > id) break;
|
|
id -= pwavedrv->NumDevs;
|
|
}
|
|
}
|
|
|
|
if (pwavedrv != pwavedrvZ)
|
|
{
|
|
if (ppwavedrv) {
|
|
mregIncUsagePtr(pwavedrv);
|
|
*ppwavedrv = pwavedrv;
|
|
if (pport) *pport = id;
|
|
}
|
|
mmr = MMSYSERR_NOERROR;
|
|
} else {
|
|
mmr = MMSYSERR_BADDEVICEID;
|
|
}
|
|
|
|
LeaveNumDevs("waveReferenceDriverById");
|
|
|
|
return mmr;
|
|
}
|
|
|
|
PCWSTR waveReferenceDevInterfaceById(PWAVEDRV pdrvZ, UINT_PTR id)
|
|
{
|
|
|
|
PWAVEDRV pdrv;
|
|
PCWSTR DevInterface;
|
|
|
|
if ((pdrvZ == &waveoutdrvZ && ValidateHandle((HANDLE)id, TYPE_WAVEOUT)) ||
|
|
(pdrvZ == &waveindrvZ && ValidateHandle((HANDLE)id, TYPE_WAVEIN)))
|
|
{
|
|
DevInterface = ((PWAVEDEV)id)->wavedrv->cookie;
|
|
if (DevInterface) wdmDevInterfaceInc(DevInterface);
|
|
return DevInterface;
|
|
}
|
|
|
|
if (!waveReferenceDriverById(pdrvZ, (UINT)id, &pdrv, NULL))
|
|
{
|
|
DevInterface = pdrv->cookie;
|
|
if (DevInterface) wdmDevInterfaceInc(DevInterface);
|
|
mregDecUsagePtr(pdrv);
|
|
return DevInterface;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc INTERNAL WAVE
|
|
*
|
|
* @func MMRESULT | waveMessage | This function sends messages to the waveform
|
|
* output device drivers.
|
|
*
|
|
* @parm HWAVE | hWave | The handle to the audio device.
|
|
*
|
|
* @parm UINT | wMsg | The message to send.
|
|
*
|
|
* @parm DWORD | dwP1 | Parameter 1.
|
|
*
|
|
* @parm DWORD | dwP2 | Parameter 2.
|
|
*
|
|
* @rdesc Returns the value returned from the driver.
|
|
****************************************************************************/
|
|
STATIC MMRESULT waveMessage(HWAVE hWave, UINT msg, DWORD_PTR dwP1, DWORD_PTR dwP2)
|
|
{
|
|
MMRESULT mrc;
|
|
|
|
ENTER_MM_HANDLE(hWave); // Serialize on handle
|
|
|
|
ReleaseHandleListResource();
|
|
|
|
// Is handle deserted?
|
|
if (IsHandleDeserted(hWave))
|
|
{
|
|
LEAVE_MM_HANDLE(hWave);
|
|
return (MMSYSERR_NODRIVER);
|
|
}
|
|
|
|
// Are we busy (in the middle of an open/close)?
|
|
if (IsHandleBusy(hWave))
|
|
{
|
|
LEAVE_MM_HANDLE(hWave);
|
|
return (MMSYSERR_HANDLEBUSY);
|
|
}
|
|
|
|
// ISSUE: We should no longer have to check for invalid handle... every
|
|
// function that calls this check with with a read lock on the handle
|
|
// resource.
|
|
if (BAD_HANDLE(hWave, TYPE_WAVEOUT) && BAD_HANDLE(hWave, TYPE_WAVEIN)) {
|
|
WinAssert(!"Bad Handle within waveMessage");
|
|
mrc = MMSYSERR_INVALHANDLE;
|
|
} else {
|
|
mrc = (MMRESULT)(*(((PWAVEDEV)hWave)->wavedrv->drvMessage))
|
|
(((PWAVEDEV)hWave)->wDevice, msg, ((PWAVEDEV)hWave)->dwDrvUser, dwP1, dwP2);
|
|
}
|
|
|
|
LEAVE_MM_HANDLE(hWave);
|
|
|
|
return mrc;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* @doc INTERNAL WAVE
|
|
*
|
|
* @func MMRESULT | waveIDMessage | This function sends a message to the device
|
|
* ID specified. It also performs error checking on the ID passed.
|
|
*
|
|
* @parm PWAVEDRV | wavedrv | Pointer to the input or output device list.
|
|
*
|
|
* @parm UINT | wTotalNumDevs | Total number of devices in device list.
|
|
*
|
|
* @parm UINT | uDeviceID | Device ID to send message to.
|
|
*
|
|
* @parm UINT | wMessage | The message to send.
|
|
*
|
|
* @parm DWORD | dwParam1 | Parameter 1.
|
|
*
|
|
* @parm DWORD | dwParam2 | Parameter 2.
|
|
*
|
|
* @rdesc The return value is the low word of the returned message.
|
|
***************************************************************************/
|
|
// ISSUE-2001/01/09-FrankYe This should take UINT_PTR uDeviceID if we expect
|
|
// it to accept handles. If we change it, then review all calls to this
|
|
// function.
|
|
STATIC MMRESULT waveIDMessage(
|
|
PWAVEDRV pwavedrvZ,
|
|
UINT wTotalNumDevs,
|
|
UINT_PTR uDeviceID,
|
|
UINT wMessage,
|
|
DWORD_PTR dwParam1,
|
|
DWORD_PTR dwParam2)
|
|
{
|
|
DWORD mmr;
|
|
DWORD dwClass;
|
|
UINT port;
|
|
PWAVEDRV wavedrv;
|
|
|
|
if (uDeviceID>=wTotalNumDevs && uDeviceID!=WAVE_MAPPER) {
|
|
// this cannot be a device ID.
|
|
// it could be a wave handle. Try it.
|
|
// First we have to verify which type of handle it is (OUT or IN)
|
|
// We can work this out as waveIDMessage is only ever called with
|
|
// pwavedrvZ == &waveoutdrvZ or &waveindrvZ
|
|
|
|
if ((pwavedrvZ == &waveoutdrvZ && ValidateHandle((HANDLE)uDeviceID, TYPE_WAVEOUT))
|
|
|| (pwavedrvZ == &waveindrvZ && ValidateHandle((HANDLE)uDeviceID, TYPE_WAVEIN) ))
|
|
{
|
|
|
|
if (0 != (((PWAVEDEV)uDeviceID)->wavedrv->fdwDriver & MMDRV_DESERTED))
|
|
{
|
|
// The driver has been deserted, all calls should return
|
|
// MMSYSERR_NODRIVER.
|
|
return MMSYSERR_NODRIVER;
|
|
}
|
|
|
|
dprintf2(("waveIDMessage passed ID==%x, translating to handle", uDeviceID));
|
|
// to preserve as much compatibility with previous code paths
|
|
// we do NOT call waveMessage as that calls ENTER_MM_HANDLE
|
|
|
|
return (MMRESULT)(*(((PWAVEDEV)uDeviceID)->wavedrv->drvMessage))
|
|
(((PWAVEDEV)uDeviceID)->wDevice,
|
|
wMessage,
|
|
((PWAVEDEV)uDeviceID)->dwDrvUser, dwParam1, dwParam2);
|
|
} else {
|
|
return(MMSYSERR_BADDEVICEID);
|
|
}
|
|
}
|
|
|
|
mmr = waveReferenceDriverById(pwavedrvZ, (UINT)uDeviceID, &wavedrv, &port);
|
|
if (mmr)
|
|
{
|
|
return mmr;
|
|
}
|
|
|
|
if (pwavedrvZ == &waveindrvZ)
|
|
dwClass = TYPE_WAVEIN;
|
|
else if (pwavedrvZ == &waveoutdrvZ)
|
|
dwClass = TYPE_WAVEOUT;
|
|
else
|
|
dwClass = TYPE_UNKNOWN;
|
|
|
|
if (!wavedrv->drvMessage)
|
|
{
|
|
mmr = MMSYSERR_NODRIVER;
|
|
}
|
|
else if (!mregHandleInternalMessages(wavedrv, dwClass, port, wMessage, dwParam1, dwParam2, &mmr))
|
|
{
|
|
mmr = (MMRESULT)((*(wavedrv->drvMessage))(port, wMessage, 0L, dwParam1, dwParam2));
|
|
}
|
|
|
|
mregDecUsagePtr(wavedrv);
|
|
return mmr;
|
|
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api UINT | waveOutGetNumDevs | This function retrieves the number of
|
|
* waveform output devices present in the system.
|
|
*
|
|
* @rdesc Returns the number of waveform output devices present in the system.
|
|
*
|
|
* @xref waveOutGetDevCaps
|
|
****************************************************************************/
|
|
UINT APIENTRY waveOutGetNumDevs(void)
|
|
{
|
|
UINT cDevs;
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
if (WinmmRunningInServer)
|
|
{
|
|
if (0 == wTotalWaveOutDevs)
|
|
{
|
|
Squirt("Returning 1 for CSRSS process.");
|
|
|
|
return 1;
|
|
}
|
|
|
|
return wTotalWaveOutDevs;
|
|
}
|
|
|
|
EnterNumDevs("waveOutGetNumDevs");
|
|
cDevs = wTotalWaveOutDevs;
|
|
LeaveNumDevs("waveOutGetNumDevs");
|
|
|
|
dprintf3(("waveOutGetNumDevs returning %d devices", wTotalWaveOutDevs));
|
|
|
|
return cDevs;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveOutMessage | This function sends messages to the waveform
|
|
* output device drivers.
|
|
*
|
|
* @parm HWAVEOUT | hWaveOut | The handle to the audio device.
|
|
*
|
|
* @parm UINT | msg | The message to send.
|
|
*
|
|
* @parm DWORD | dw1 | Parameter 1.
|
|
*
|
|
* @parm DWORD | dw2 | Parameter 2.
|
|
*
|
|
* @rdesc Returns the value returned from the driver.
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveOutMessage(HWAVEOUT hWaveOut, UINT msg, DWORD_PTR dw1, DWORD_PTR dw2)
|
|
{
|
|
ClientUpdatePnpInfo();
|
|
|
|
AcquireHandleListResourceShared();
|
|
|
|
if (BAD_HANDLE((HWAVE)hWaveOut, TYPE_WAVEOUT))
|
|
{
|
|
ReleaseHandleListResource();
|
|
return waveIDMessage(&waveoutdrvZ, wTotalWaveOutDevs, (UINT)(UINT_PTR)hWaveOut, msg, dw1, dw2);
|
|
}
|
|
else
|
|
{
|
|
return waveMessage((HWAVE)hWaveOut, msg, dw1, dw2);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveOutGetDevCaps | This function queries a specified waveform
|
|
* device to determine its capabilities.
|
|
*
|
|
* @parm UINT | uDeviceID | Identifies the waveform output device.
|
|
*
|
|
* @parm LPWAVEOUTCAPS | lpCaps | Specifies a far pointer to a <t WAVEOUTCAPS>
|
|
* structure. This structure is filled with information about the
|
|
* capabilities of the device.
|
|
*
|
|
* @parm UINT | wSize | Specifies the size of the <t WAVEOUTCAPS> structure.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
|
|
* @flag MMSYSERR_NODRIVER | The driver was not installed.
|
|
*
|
|
* @comm Use <f waveOutGetNumDevs> to determine the number of waveform output
|
|
* devices present in the system. The device ID specified by <p uDeviceID>
|
|
* varies from zero to one less than the number of devices present.
|
|
* The WAVE_MAPPER constant may also be used as a device id. Only
|
|
* <p wSize> bytes (or less) of information is copied to the location
|
|
* pointed to by <p lpCaps>. If <p wSize> is zero, nothing is copied, and
|
|
* the function returns zero.
|
|
*
|
|
* @xref waveOutGetNumDevs
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveOutGetDevCapsW(UINT_PTR uDeviceID, LPWAVEOUTCAPSW lpCaps, UINT wSize)
|
|
{
|
|
DWORD_PTR dwParam1, dwParam2;
|
|
MDEVICECAPSEX mdCaps;
|
|
PWAVEDRV waveoutdrv;
|
|
PCWSTR DevInterface;
|
|
MMRESULT mmr;
|
|
|
|
if (wSize == 0)
|
|
return MMSYSERR_NOERROR;
|
|
|
|
V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
|
|
|
|
// Because some 32-bit applications use the value 0x0000FFFF for
|
|
// WAVE_MAPPER instead of 0xFFFFFFFF, we clamp up to the correct value.
|
|
// This just happened to work on Win9x because WinMM would thunk down
|
|
// to MMSystem and send down the lower word to the 16-bit interface.
|
|
if (uDeviceID == LOWORD(WAVE_MAPPER)) {
|
|
uDeviceID = WAVE_MAPPER;
|
|
}
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
DevInterface = waveReferenceDevInterfaceById(&waveoutdrvZ, uDeviceID);
|
|
dwParam2 = (DWORD_PTR)DevInterface;
|
|
|
|
if (0 == dwParam2)
|
|
{
|
|
dwParam1 = (DWORD_PTR)lpCaps;
|
|
dwParam2 = (DWORD)wSize;
|
|
}
|
|
else
|
|
{
|
|
mdCaps.cbSize = (DWORD)wSize;
|
|
mdCaps.pCaps = lpCaps;
|
|
dwParam1 = (DWORD_PTR)&mdCaps;
|
|
}
|
|
|
|
//
|
|
// Don't allow non proper drivers in TS environement
|
|
//
|
|
// ISSUE-2001/01/09-FrankYe Instead of cast to UINT. Should check whether
|
|
// this is a handle and get wavedrv from handle if it is.
|
|
waveoutdrv = NULL;
|
|
if ((!waveReferenceDriverById(&waveoutdrvZ, (UINT)uDeviceID, &waveoutdrv, NULL)) &&
|
|
lstrcmpW(waveoutdrv->wszSessProtocol, SessionProtocolName))
|
|
{
|
|
mmr = MMSYSERR_NODRIVER;
|
|
}
|
|
else
|
|
{
|
|
AcquireHandleListResourceShared();
|
|
|
|
if (BAD_HANDLE((HWAVE)uDeviceID, TYPE_WAVEOUT))
|
|
{
|
|
int cRecursion;
|
|
|
|
ReleaseHandleListResource();
|
|
|
|
// Unless it's the mapper, increment the recursion depth counter. Then,
|
|
// check whether this thread is now recursing through waveOutGetDevCaps. If it
|
|
// is, then disable preferred device reordering.
|
|
cRecursion = PtrToInt(TlsGetValue(gTlsIndex));
|
|
if ((uDeviceID != WAVE_MAPPER) && (waveoutdrv) && (waveoutdrv->fdwDriver & MMDRV_PREXP)) TlsSetValue(gTlsIndex, IntToPtr(cRecursion + 1));
|
|
if (cRecursion) gfDisablePreferredDeviceReordering = TRUE;
|
|
|
|
mmr = waveIDMessage(&waveoutdrvZ, wTotalWaveOutDevs, (UINT)uDeviceID, WODM_GETDEVCAPS, dwParam1, dwParam2);
|
|
|
|
// Restore recursion counter
|
|
TlsSetValue(gTlsIndex, IntToPtr(cRecursion));
|
|
}
|
|
else
|
|
{
|
|
mmr = (MMRESULT)waveMessage((HWAVE)uDeviceID, WODM_GETDEVCAPS, dwParam1, dwParam2);
|
|
}
|
|
|
|
}
|
|
|
|
if (waveoutdrv) mregDecUsagePtr(waveoutdrv);
|
|
if (DevInterface) wdmDevInterfaceDec(DevInterface);
|
|
return mmr;
|
|
|
|
}
|
|
|
|
MMRESULT APIENTRY waveOutGetDevCapsA(UINT_PTR uDeviceID, LPWAVEOUTCAPSA lpCaps, UINT wSize)
|
|
{
|
|
WAVEOUTCAPS2W wDevCaps2;
|
|
WAVEOUTCAPS2A aDevCaps2;
|
|
DWORD_PTR dwParam1, dwParam2;
|
|
MDEVICECAPSEX mdCaps;
|
|
MMRESULT mmRes;
|
|
PWAVEDRV waveoutdrv;
|
|
PCWSTR DevInterface;
|
|
|
|
if (wSize == 0)
|
|
return MMSYSERR_NOERROR;
|
|
|
|
V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
|
|
|
|
// Because some 32-bit applications use the value 0x0000FFFF for
|
|
// WAVE_MAPPER instead of 0xFFFFFFFF, we clamp up to the correct value.
|
|
// This just happened to work on Win9x because WinMM would thunk down
|
|
// to MMSystem and send down the lower word to the 16-bit interface.
|
|
if (uDeviceID == LOWORD(WAVE_MAPPER)) {
|
|
uDeviceID = WAVE_MAPPER;
|
|
}
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
DevInterface = waveReferenceDevInterfaceById(&waveoutdrvZ, uDeviceID);
|
|
dwParam2 = (DWORD_PTR)DevInterface;
|
|
|
|
memset(&wDevCaps2, 0, sizeof(wDevCaps2));
|
|
|
|
if (0 == dwParam2)
|
|
{
|
|
dwParam1 = (DWORD_PTR)&wDevCaps2;
|
|
dwParam2 = (DWORD)sizeof(wDevCaps2);
|
|
}
|
|
else
|
|
{
|
|
mdCaps.cbSize = (DWORD)sizeof(wDevCaps2);
|
|
mdCaps.pCaps = &wDevCaps2;
|
|
dwParam1 = (DWORD_PTR)&mdCaps;
|
|
}
|
|
|
|
//
|
|
// Don't allow non proper drivers in TS environement
|
|
//
|
|
// ISSUE-2001/01/09-FrankYe Bad cast to UINT. Should check whether this
|
|
// is a handle and get wavedrv from handle if it is.
|
|
waveoutdrv = NULL;
|
|
if ( uDeviceID < wTotalWaveOutDevs &&
|
|
!waveReferenceDriverById(&waveoutdrvZ, (UINT)uDeviceID, &waveoutdrv, NULL) &&
|
|
lstrcmpW(waveoutdrv->wszSessProtocol, SessionProtocolName) )
|
|
{
|
|
mregDecUsagePtr(waveoutdrv);
|
|
if (DevInterface) wdmDevInterfaceDec(DevInterface);
|
|
return MMSYSERR_NODRIVER;
|
|
}
|
|
|
|
AcquireHandleListResourceShared();
|
|
|
|
if (BAD_HANDLE((HWAVE)uDeviceID, TYPE_WAVEOUT))
|
|
{
|
|
ReleaseHandleListResource();
|
|
mmRes = waveIDMessage(&waveoutdrvZ, wTotalWaveOutDevs, (UINT)uDeviceID,
|
|
WODM_GETDEVCAPS, dwParam1, dwParam2);
|
|
}
|
|
else
|
|
{
|
|
mmRes = waveMessage((HWAVE)uDeviceID,
|
|
WODM_GETDEVCAPS,
|
|
dwParam1,
|
|
dwParam2);
|
|
}
|
|
|
|
if (waveoutdrv) mregDecUsagePtr(waveoutdrv);
|
|
if (DevInterface) wdmDevInterfaceDec(DevInterface);
|
|
|
|
//
|
|
// Make sure the call worked before proceeding with the thunk.
|
|
//
|
|
if ( mmRes != MMSYSERR_NOERROR ) {
|
|
return mmRes;
|
|
}
|
|
|
|
aDevCaps2.wMid = wDevCaps2.wMid;
|
|
aDevCaps2.wPid = wDevCaps2.wPid;
|
|
aDevCaps2.vDriverVersion = wDevCaps2.vDriverVersion;
|
|
aDevCaps2.dwFormats = wDevCaps2.dwFormats;
|
|
aDevCaps2.wChannels = wDevCaps2.wChannels;
|
|
aDevCaps2.dwSupport = wDevCaps2.dwSupport;
|
|
aDevCaps2.ManufacturerGuid = wDevCaps2.ManufacturerGuid;
|
|
aDevCaps2.ProductGuid = wDevCaps2.ProductGuid;
|
|
aDevCaps2.NameGuid = wDevCaps2.NameGuid;
|
|
|
|
// copy and convert lpwText to lpText here.
|
|
Iwcstombs(aDevCaps2.szPname, wDevCaps2.szPname, MAXPNAMELEN);
|
|
|
|
//
|
|
// now copy the required amount into the callers buffer.
|
|
//
|
|
CopyMemory( lpCaps, &aDevCaps2, min(wSize, sizeof(aDevCaps2)));
|
|
|
|
return mmRes;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveOutGetVolume | This function queries the current volume
|
|
* setting of a waveform output device.
|
|
*
|
|
* @parm UINT | uDeviceID | Identifies the waveform output device.
|
|
*
|
|
* @parm LPDWORD | lpdwVolume | Specifies a far pointer to a location to
|
|
* be filled with the current volume setting. The low-order word of
|
|
* this location contains the left channel volume setting, and the high-order
|
|
* word contains the right channel setting. A value of 0xFFFF represents
|
|
* full volume, and a value of 0x0000 is silence.
|
|
*
|
|
* If a device does not support both left and right volume
|
|
* control, the low-order word of the specified location contains
|
|
* the mono volume level.
|
|
*
|
|
* The full 16-bit setting(s)
|
|
* set with <f waveOutSetVolume> is returned, regardless of whether
|
|
* the device supports the full 16 bits of volume-level control.
|
|
*
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
|
|
* @flag MMSYSERR_NODRIVER | The driver was not installed.
|
|
*
|
|
* @comm Not all devices support volume changes. To determine whether the
|
|
* device supports volume control, use the WAVECAPS_VOLUME
|
|
* flag to test the <e WAVEOUTCAPS.dwSupport> field of the <t WAVEOUTCAPS>
|
|
* structure (filled by <f waveOutGetDevCaps>).
|
|
*
|
|
* To determine whether the device supports volume control on both
|
|
* the left and right channels, use the WAVECAPS_VOLUME
|
|
* flag to test the <e WAVEOUTCAPS.dwSupport> field of the <t WAVEOUTCAPS>
|
|
* structure (filled by <f waveOutGetDevCaps>).
|
|
*
|
|
* @xref waveOutSetVolume
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveOutGetVolume(HWAVEOUT hwo, LPDWORD lpdwVolume)
|
|
{
|
|
PCWSTR DevInterface;
|
|
MMRESULT mmr;
|
|
|
|
V_WPOINTER(lpdwVolume, sizeof(DWORD), MMSYSERR_INVALPARAM);
|
|
|
|
// Because some 32-bit applications use the value 0x0000FFFF for
|
|
// WAVE_MAPPER instead of 0xFFFFFFFF, we clamp up to the correct value.
|
|
// This just happened to work on Win9x because WinMM would thunk down
|
|
// to MMSystem and send down the lower word to the 16-bit interface.
|
|
if ((UINT_PTR)hwo == LOWORD(WAVE_MAPPER)) {
|
|
(UINT_PTR)hwo = WAVE_MAPPER;
|
|
}
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
DevInterface = waveReferenceDevInterfaceById(&waveoutdrvZ, (UINT_PTR)hwo);
|
|
|
|
AcquireHandleListResourceShared();
|
|
|
|
if (BAD_HANDLE(hwo, TYPE_WAVEOUT))
|
|
{
|
|
ReleaseHandleListResource();
|
|
mmr = waveIDMessage(&waveoutdrvZ, wTotalWaveOutDevs, PtrToUint(hwo), WODM_GETVOLUME, (DWORD_PTR)lpdwVolume, (DWORD_PTR)DevInterface);
|
|
}
|
|
else
|
|
{
|
|
mmr = (MMRESULT)waveMessage((HWAVE)hwo, WODM_GETVOLUME, (DWORD_PTR)lpdwVolume, (DWORD_PTR)DevInterface);
|
|
}
|
|
|
|
if (DevInterface) wdmDevInterfaceDec(DevInterface);
|
|
return mmr;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveOutSetVolume | This function sets the volume of a
|
|
* waveform output device.
|
|
*
|
|
* @parm UINT | uDeviceID | Identifies the waveform output device.
|
|
*
|
|
* @parm DWORD | dwVolume | Specifies the new volume setting. The
|
|
* low-order word contains the left channel volume setting, and the
|
|
* high-order word contains the right channel setting. A value of
|
|
* 0xFFFF represents full volume, and a value of 0x0000 is silence.
|
|
*
|
|
* If a device does
|
|
* not support both left and right volume control, the low-order word of
|
|
* <p dwVolume> specifies the volume level, and the high-order word is
|
|
* ignored.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
|
|
* @flag MMSYSERR_NODRIVER | The driver was not installed.
|
|
*
|
|
* @comm Not all devices support volume changes. To determine whether the
|
|
* device supports volume control, use the WAVECAPS_VOLUME
|
|
* flag to test the <e WAVEOUTCAPS.dwSupport> field of the <t WAVEOUTCAPS>
|
|
* structure (filled by <f waveOutGetDevCaps>).
|
|
*
|
|
* To determine whether the device supports volume control on both the
|
|
* left and right channels, use the WAVECAPS_LRVOLUME flag
|
|
* flag to test the <e WAVEOUTCAPS.dwSupport> field of the <t WAVEOUTCAPS>
|
|
* structure (filled by <f waveOutGetDevCaps>).
|
|
*
|
|
* Most devices don't support the full 16 bits of volume level control
|
|
* and will not use the high-order bits of the requested volume setting.
|
|
* For example, for a device that supports 4 bits of volume control,
|
|
* requested volume level values of 0x4000, 0x4fff, and 0x43be
|
|
* all produce the same physical volume setting, 0x4000. The
|
|
* <f waveOutGetVolume> function returns the full 16-bit setting set
|
|
* with <f waveOutSetVolume>.
|
|
*
|
|
* Volume settings are interpreted logarithmically. This means the
|
|
* perceived increase in volume is the same when increasing the
|
|
* volume level from 0x5000 to 0x6000 as it is from 0x4000 to 0x5000.
|
|
*
|
|
* @xref waveOutGetVolume
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveOutSetVolume(HWAVEOUT hwo, DWORD dwVolume)
|
|
{
|
|
PCWSTR DevInterface;
|
|
MMRESULT mmr;
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
// Because some 32-bit applications use the value 0x0000FFFF for
|
|
// WAVE_MAPPER instead of 0xFFFFFFFF, we clamp up to the correct value.
|
|
// This just happened to work on Win9x because WinMM would thunk down
|
|
// to MMSystem and send down the lower word to the 16-bit interface.
|
|
if ((UINT_PTR)hwo == LOWORD(WAVE_MAPPER)) {
|
|
(UINT_PTR)hwo = WAVE_MAPPER;
|
|
}
|
|
|
|
DevInterface = waveReferenceDevInterfaceById(&waveoutdrvZ, (UINT_PTR)hwo);
|
|
|
|
AcquireHandleListResourceShared();
|
|
|
|
if (BAD_HANDLE(hwo, TYPE_WAVEOUT))
|
|
{
|
|
ReleaseHandleListResource();
|
|
mmr = waveIDMessage(&waveoutdrvZ, wTotalWaveOutDevs, PtrToUint(hwo), WODM_SETVOLUME, dwVolume, (DWORD_PTR)DevInterface);
|
|
}
|
|
else
|
|
{
|
|
mmr = (MMRESULT)waveMessage((HWAVE)hwo, WODM_SETVOLUME, dwVolume, (DWORD_PTR)DevInterface);
|
|
}
|
|
|
|
if (DevInterface) wdmDevInterfaceDec(DevInterface);
|
|
return mmr;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc INTERNAL WAVE
|
|
*
|
|
* @func UINT | waveGetErrorText | This function retrieves a textual
|
|
* description of the error identified by the specified error number.
|
|
*
|
|
* @parm UINT | wError | Specifies the error number.
|
|
*
|
|
* @parm LPTSTR | lpText | Specifies a far pointer to a buffer which
|
|
* is filled with the textual error description.
|
|
*
|
|
* @parm UINT | wSize | Specifies the length in characters of the buffer
|
|
* pointed to by <p lpText>.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_BADERRNUM | Specified error number is out of range.
|
|
*
|
|
* @comm If the textual error description is longer than the specified buffer,
|
|
* the description is truncated. The returned error string is always
|
|
* null-terminated. If <p wSize> is zero, nothing is copied and MMSYSERR_NOERROR
|
|
* is returned. All error descriptions are less than 80 characters long.
|
|
****************************************************************************/
|
|
|
|
STATIC MMRESULT waveGetErrorTextW(UINT wError, LPWSTR lpText, UINT wSize)
|
|
{
|
|
lpText[0] = 0;
|
|
|
|
#if MMSYSERR_BASE
|
|
if (((wError < MMSYSERR_BASE) || (wError > MMSYSERR_LASTERROR)) && ((wError < WAVERR_BASE) || (wError > WAVERR_LASTERROR)))
|
|
#else
|
|
if ((wError > MMSYSERR_LASTERROR) && ((wError < WAVERR_BASE) || (wError > WAVERR_LASTERROR)))
|
|
#endif
|
|
return MMSYSERR_BADERRNUM;
|
|
|
|
if (wSize > 1)
|
|
{
|
|
if (!LoadStringW(ghInst, wError, lpText, wSize))
|
|
return MMSYSERR_BADERRNUM;
|
|
}
|
|
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
STATIC MMRESULT waveGetErrorTextA(UINT wError, LPSTR lpText, UINT wSize)
|
|
{
|
|
lpText[0] = 0;
|
|
|
|
#if MMSYSERR_BASE
|
|
if (((wError < MMSYSERR_BASE) || (wError > MMSYSERR_LASTERROR)) && ((wError < WAVERR_BASE) || (wError > WAVERR_LASTERROR)))
|
|
#else
|
|
if ((wError > MMSYSERR_LASTERROR) && ((wError < WAVERR_BASE) || (wError > WAVERR_LASTERROR)))
|
|
#endif
|
|
return MMSYSERR_BADERRNUM;
|
|
|
|
if (wSize > 1)
|
|
{
|
|
if (!LoadStringA(ghInst, wError, lpText, wSize))
|
|
return MMSYSERR_BADERRNUM;
|
|
}
|
|
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveOutGetErrorText | This function retrieves a
|
|
* textual description of the error identified by the specified
|
|
* error number.
|
|
*
|
|
* @parm UINT | wError | Specifies the error number.
|
|
*
|
|
* @parm LPTSTR | lpText | Specifies a far pointer to a buffer to be
|
|
* filled with the textual error description.
|
|
*
|
|
* @parm UINT | wSize | Specifies the length in characters of the buffer
|
|
* pointed to by <p lpText>.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_BADERRNUM | Specified error number is out of range.
|
|
*
|
|
* @comm If the textual error description is longer than the specified buffer,
|
|
* the description is truncated. The returned error string is always
|
|
* null-terminated. If <p wSize> is zero, nothing is copied, and the function
|
|
* returns zero. All error descriptions are less than MAXERRORLENGTH characters long.
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveOutGetErrorTextW(UINT wError, LPWSTR lpText, UINT wSize)
|
|
{
|
|
if (wSize == 0)
|
|
return MMSYSERR_NOERROR;
|
|
|
|
V_WPOINTER(lpText, wSize*sizeof(WCHAR), MMSYSERR_INVALPARAM);
|
|
|
|
return waveGetErrorTextW(wError, lpText, wSize);
|
|
}
|
|
|
|
MMRESULT APIENTRY waveOutGetErrorTextA(UINT wError, LPSTR lpText, UINT wSize)
|
|
{
|
|
if (wSize == 0)
|
|
return MMSYSERR_NOERROR;
|
|
|
|
V_WPOINTER(lpText, wSize, MMSYSERR_INVALPARAM);
|
|
|
|
return waveGetErrorTextA(wError, lpText, wSize );
|
|
}
|
|
|
|
/****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveOutOpen | This function opens a specified waveform output
|
|
* device for playback.
|
|
*
|
|
* @parm LPHWAVEOUT | lphWaveOut | Specifies a far pointer to an HWAVEOUT
|
|
* handle. This location is filled with a handle identifying the opened
|
|
* waveform output device. Use the handle to identify the device when
|
|
* calling other waveform output functions. This parameter may be
|
|
* NULL if the WAVE_FORMAT_QUERY flag is specified for <p dwFlags>.
|
|
*
|
|
* @parm UINT | uDeviceID | Identifies the waveform output device to open.
|
|
* Use a valid device ID or the following flag:
|
|
*
|
|
* @flag WAVE_MAPPER | If this flag is specified, the function
|
|
* selects a waveform output device
|
|
* capable of playing the given format.
|
|
*
|
|
* @parm LPWAVEFORMATEX | lpFormat | Specifies a pointer to a <t WAVEFORMATEX>
|
|
* structure that identifies the format of the waveform data
|
|
* to be sent to the waveform output device.
|
|
*
|
|
* @parm DWORD | dwCallback | Specifies the address of a callback
|
|
* function or a handle to a window called during waveform
|
|
* playback to process messages related to the progress of the playback.
|
|
* Specify NULL for this parameter if no callback is desired.
|
|
*
|
|
* @parm DWORD | dwCallbackInstance | Specifies user instance data
|
|
* passed to the callback. This parameter is not used with
|
|
* window callbacks.
|
|
*
|
|
* @parm DWORD | dwFlags | Specifies flags for opening the device.
|
|
* @flag WAVE_FORMAT_QUERY | If this flag is specified, the device is
|
|
* queried to determine if it supports the given format but is not
|
|
* actually opened.
|
|
* @flag WAVE_ALLOWSYNC | If this flag is not specified, then the
|
|
* device will fail to open if it is a synchronous device.
|
|
* @flag CALLBACK_WINDOW | If this flag is specified, <p dwCallback> is
|
|
* assumed to be a window handle.
|
|
* @flag CALLBACK_FUNCTION | If this flag is specified, <p dwCallback> is
|
|
* assumed to be a callback procedure address.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
|
|
* @flag MMSYSERR_ALLOCATED | Specified resource is already allocated.
|
|
* @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
|
|
* @flag WAVERR_BADFORMAT | Attempted to open with an unsupported wave format.
|
|
*
|
|
* @comm Use <f waveOutGetNumDevs> to determine the number of waveform output
|
|
* devices present in the system. The device ID specified by <p uDeviceID>
|
|
* varies from zero to one less than the number of devices present.
|
|
* The WAVE_MAPPER constant may also be used as a device id.
|
|
*
|
|
* The <t WAVEFORMAT> structure pointed to by <p lpFormat> may be extended
|
|
* to include type-specific information for certain data formats.
|
|
* For example, for PCM data, an extra WORD is added to specify the number
|
|
* of bits per sample. Use the <t PCMWAVEFORMAT> structure in this case.
|
|
*
|
|
* If a window is chosen to receive callback information, the following
|
|
* messages are sent to the window procedure function to indicate the
|
|
* progress of waveform output: <m MM_WOM_OPEN>, <m MM_WOM_CLOSE>,
|
|
* <m MM_WOM_DONE>
|
|
*
|
|
* If a function is chosen to receive callback information, the following
|
|
* messages are sent to the function to indicate the progress of waveform
|
|
* output: <m WOM_OPEN>, <m WOM_CLOSE>, <m WOM_DONE>. The callback function
|
|
* must reside in a DLL. You do not have to use <f MakeProcInstance> to get
|
|
* a procedure-instance address for the callback function.
|
|
*
|
|
* @cb void CALLBACK | WaveOutFunc | <f WaveOutFunc> is a placeholder for the
|
|
* application-supplied function name. The actual name must be exported by
|
|
* including it in an EXPORTS statement in the DLL's module-definition file.
|
|
*
|
|
* @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform device
|
|
* associated with the callback.
|
|
*
|
|
* @parm UINT | wMsg | Specifies a waveform output message.
|
|
*
|
|
* @parm DWORD | dwInstance | Specifies the user instance data
|
|
* specified with <f waveOutOpen>.
|
|
*
|
|
* @parm DWORD | dwParam1 | Specifies a parameter for the message.
|
|
*
|
|
* @parm DWORD | dwParam2 | Specifies a parameter for the message.
|
|
*
|
|
* @comm Because the callback is accessed at interrupt time, it must reside
|
|
* in a DLL and its code segment must be specified as FIXED in the
|
|
* module-definition file for the DLL. Any data that the callback accesses
|
|
* must be in a FIXED data segment as well. The callback may not make any
|
|
* system calls except for <f PostMessage>, <f timeGetSystemTime>,
|
|
* <f timeGetTime>, <f timeSetEvent>, <f timeKillEvent>,
|
|
* <f midiOutShortMsg>, <f midiOutLongMsg>, and <f OutputDebugStr>.
|
|
*
|
|
* @xref waveOutClose
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveOutOpen(LPHWAVEOUT lphWaveOut, UINT uDeviceID,
|
|
LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback,
|
|
DWORD_PTR dwInstance, DWORD dwFlags)
|
|
{
|
|
WAVEOPENDESC wo;
|
|
PWAVEDEV pdev;
|
|
PWAVEDRV wavedrv;
|
|
UINT port;
|
|
MMRESULT wRet;
|
|
DWORD_PTR dwDrvUser;
|
|
int cRecursion;
|
|
|
|
V_RPOINTER(lpFormat, sizeof(WAVEFORMAT), MMSYSERR_INVALPARAM);
|
|
V_DCALLBACK(dwCallback, HIWORD(dwFlags), MMSYSERR_INVALPARAM);
|
|
// Because some 32-bit applications use the value 0x0000FFFF for
|
|
// WAVE_MAPPER instead of 0xFFFFFFFF, we clamp up to the correct value.
|
|
// This just happened to work on Win9x because WinMM would thunk down
|
|
// to MMSystem and send down the lower word to the 16-bit interface.
|
|
if (uDeviceID == LOWORD(WAVE_MAPPER)) {
|
|
uDeviceID = WAVE_MAPPER;
|
|
}
|
|
if (uDeviceID == WAVE_MAPPER) {
|
|
V_FLAGS(LOWORD(dwFlags), WAVE_VALID & ~(WAVE_MAPPED), waveOutOpen, MMSYSERR_INVALFLAG);
|
|
} else {
|
|
V_FLAGS(LOWORD(dwFlags), WAVE_VALID, waveOutOpen, MMSYSERR_INVALFLAG);
|
|
}
|
|
if ((lpFormat->wFormatTag != WAVE_FORMAT_PCM)) {
|
|
V_RPOINTER(lpFormat, sizeof(WAVEFORMATEX), MMSYSERR_INVALPARAM);
|
|
if ((lpFormat->cbSize)) {
|
|
V_RPOINTER(lpFormat + 1, lpFormat->cbSize, MMSYSERR_INVALPARAM);
|
|
}
|
|
}
|
|
|
|
if ((dwFlags & WAVE_FORMAT_QUERY)) {
|
|
lphWaveOut = NULL;
|
|
} else
|
|
{
|
|
V_WPOINTER(lphWaveOut, sizeof(HWAVEOUT), MMSYSERR_INVALPARAM);
|
|
// WAVE_FORMAT_DIRECT was bounced on Win95. Now we
|
|
// accept this flag.
|
|
//
|
|
// if (dwFlags & WAVE_FORMAT_DIRECT)
|
|
// return MMSYSERR_INVALFLAG;
|
|
*lphWaveOut = NULL;
|
|
}
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
if ((!wTotalWaveOutDevs) || waveReferenceDriverById(&waveoutdrvZ, (dwFlags & WAVE_MAPPED) ? WAVE_MAPPER : uDeviceID, &wavedrv, &port))
|
|
{
|
|
return MMSYSERR_BADDEVICEID;
|
|
}
|
|
|
|
//
|
|
// check if the device is appropriate for the current TS session
|
|
//
|
|
if (!(wavedrv->fdwDriver & MMDRV_MAPPER) &&
|
|
lstrcmpW(wavedrv->wszSessProtocol, SessionProtocolName))
|
|
{
|
|
mregDecUsagePtr(wavedrv);
|
|
return MMSYSERR_NODRIVER;
|
|
}
|
|
|
|
/* Default wave mapper :
|
|
*
|
|
* If a wave mapper is installed as a separate DLL then all wave mapper
|
|
* messages are routed to it. If no wave mapper is installed, simply
|
|
* loop through the wave devices looking for a match.
|
|
*/
|
|
// ISSUE-2001/01/06-FrankYe This logic looks broken for the WAVE_MAPPER case
|
|
if ((uDeviceID == WAVE_MAPPER) && !wavedrv->drvMessage) {
|
|
MMRESULT wErr;
|
|
|
|
mregDecUsagePtr(wavedrv);
|
|
wErr = MMSYSERR_ALLOCATED;
|
|
|
|
if (dwFlags & WAVE_MAPPED)
|
|
{
|
|
if (wErr = waveReferenceDriverById(&waveoutdrvZ, uDeviceID, &wavedrv, &port))
|
|
return wErr;
|
|
|
|
if (mregHandleInternalMessages(wavedrv,
|
|
MMDRVI_WAVEOUT,
|
|
port,
|
|
DRV_QUERYMAPPABLE,
|
|
0, 0, &wErr) ||
|
|
(MMSYSERR_NOERROR != wErr))
|
|
{
|
|
mregDecUsagePtr(wavedrv);
|
|
return wErr;
|
|
}
|
|
wErr = waveOutOpen(lphWaveOut, uDeviceID, lpFormat, dwCallback, dwInstance, dwFlags & ~WAVE_MAPPED);
|
|
mregDecUsagePtr(wavedrv);
|
|
}
|
|
else
|
|
{
|
|
for (uDeviceID=0; uDeviceID<wTotalWaveOutDevs; uDeviceID++) {
|
|
wErr = waveOutOpen(lphWaveOut, uDeviceID, lpFormat, dwCallback, dwInstance, dwFlags);
|
|
if (!wErr)
|
|
break;
|
|
}
|
|
}
|
|
return wErr;
|
|
|
|
}
|
|
|
|
if (dwFlags & WAVE_FORMAT_QUERY)
|
|
pdev = NULL;
|
|
else {
|
|
if (!(pdev = (PWAVEDEV)NewHandle(TYPE_WAVEOUT, wavedrv->cookie, sizeof(WAVEDEV))))
|
|
{
|
|
mregDecUsagePtr(wavedrv);
|
|
return MMSYSERR_NOMEM;
|
|
}
|
|
|
|
ENTER_MM_HANDLE(pdev);
|
|
SetHandleFlag(pdev, MMHANDLE_BUSY);
|
|
ReleaseHandleListResource();
|
|
|
|
pdev->wavedrv = wavedrv;
|
|
pdev->wDevice = port;
|
|
pdev->uDeviceID = uDeviceID;
|
|
pdev->fdwHandle = 0;
|
|
}
|
|
|
|
wo.hWave = (HWAVE)pdev;
|
|
wo.dwCallback = dwCallback;
|
|
wo.dwInstance = dwInstance;
|
|
wo.uMappedDeviceID = uDeviceID;
|
|
wo.lpFormat = (LPWAVEFORMAT)lpFormat; // cast away the CONST to eliminate wng
|
|
wo.dnDevNode = (DWORD_PTR)wavedrv->cookie;
|
|
|
|
// Unless it's the mapper, increment the recursion depth counter. Then,
|
|
// check whether this thread is now recursing through waveOutOpen. If it
|
|
// is, then disable preferred device reordering.
|
|
cRecursion = PtrToInt(TlsGetValue(gTlsIndex));
|
|
if (uDeviceID != WAVE_MAPPER) TlsSetValue(gTlsIndex, IntToPtr(cRecursion + 1));
|
|
if ((uDeviceID != WAVE_MAPPER) && (wavedrv->fdwDriver & MMDRV_PREXP)) TlsSetValue(gTlsIndex, IntToPtr(cRecursion + 1));
|
|
if (cRecursion) gfDisablePreferredDeviceReordering = TRUE;
|
|
|
|
wRet = ((*(wavedrv->drvMessage))
|
|
(port, WODM_OPEN, (DWORD_PTR)&dwDrvUser, (DWORD_PTR)(LPWAVEOPENDESC)&wo, dwFlags));
|
|
|
|
// Restore recursion counter
|
|
TlsSetValue(gTlsIndex, IntToPtr(cRecursion));
|
|
|
|
if (pdev) {
|
|
// Mark as not busy on successful open...
|
|
if (!wRet)
|
|
ClearHandleFlag(pdev, MMHANDLE_BUSY);
|
|
|
|
LEAVE_MM_HANDLE(pdev);
|
|
|
|
if (wRet)
|
|
FreeHandle((HWAVEOUT)pdev);
|
|
else {
|
|
// Inc usage since we opened a handle on it
|
|
mregIncUsagePtr(wavedrv);
|
|
*lphWaveOut = (HWAVEOUT)pdev;
|
|
pdev->dwDrvUser = dwDrvUser;
|
|
}
|
|
}
|
|
|
|
mregDecUsagePtr(wavedrv);
|
|
return wRet;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveOutClose | This function closes the specified waveform
|
|
* output device.
|
|
*
|
|
* @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
|
|
* device. If the function is successful, the handle is no
|
|
* longer valid after this call.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag WAVERR_STILLPLAYING | There are still buffers in the queue.
|
|
* @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
|
|
* thread.
|
|
*
|
|
* @comm If the device is still playing a waveform, the close
|
|
* operation will fail. Use <f waveOutReset> to terminate waveform
|
|
* playback before calling <f waveOutClose>.
|
|
*
|
|
* @xref waveOutOpen waveOutReset
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveOutClose(HWAVEOUT hWaveOut)
|
|
{
|
|
MMRESULT wRet;
|
|
PWAVEDRV pwavedrv;
|
|
PWAVEDEV pDev = (PWAVEDEV)hWaveOut;
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
|
|
|
|
ENTER_MM_HANDLE((HWAVE)hWaveOut);
|
|
ReleaseHandleListResource();
|
|
|
|
if (IsHandleDeserted(hWaveOut))
|
|
{
|
|
// This handle has been deserted. Let's just free it.
|
|
|
|
LEAVE_MM_HANDLE((HWAVE)hWaveOut);
|
|
FreeHandle(hWaveOut);
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
if (IsHandleBusy(hWaveOut))
|
|
{
|
|
// Not quite invalid, but marked as closed.
|
|
|
|
LEAVE_MM_HANDLE(hWaveOut);
|
|
return (MMSYSERR_HANDLEBUSY);
|
|
}
|
|
|
|
// Marking handle as 'invalid/closed'.
|
|
SetHandleFlag(hWaveOut, MMHANDLE_BUSY);
|
|
|
|
pwavedrv = pDev->wavedrv;
|
|
|
|
wRet = (MMRESULT)(*(pwavedrv->drvMessage))(pDev->wDevice, WODM_CLOSE, pDev->dwDrvUser, 0L, 0L);
|
|
|
|
if (MMSYSERR_NOERROR != wRet)
|
|
{
|
|
// Error closing, set the flag as valid.
|
|
ClearHandleFlag(hWaveOut, MMHANDLE_BUSY);
|
|
}
|
|
|
|
LEAVE_MM_HANDLE((HWAVE)hWaveOut);
|
|
|
|
if (!wRet)
|
|
{
|
|
FreeHandle(hWaveOut);
|
|
mregDecUsagePtr(pwavedrv);
|
|
return wRet;
|
|
}
|
|
|
|
return wRet;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveOutPrepareHeader | This function prepares a
|
|
* waveform data block for playback.
|
|
*
|
|
* @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
|
|
* device.
|
|
*
|
|
* @parm LPWAVEHDR | lpWaveOutHdr | Specifies a pointer to a
|
|
* <t WAVEHDR> structure that identifies the data block to be prepared.
|
|
*
|
|
* @parm UINT | wSize | Specifies the size of the <t WAVEHDR> structure.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
|
|
* @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
|
|
* thread.
|
|
*
|
|
* @comm The <t WAVEHDR> data structure and the data block pointed to by its
|
|
* <e WAVEHDR.lpData> field must be allocated with <f GlobalAlloc> using the
|
|
* GMEM_MOVEABLE and GMEM_SHARE flags, and locked with <f GlobalLock>.
|
|
* Preparing a header that has already been prepared has no effect, and
|
|
* the function returns zero.
|
|
*
|
|
* @xref waveOutUnprepareHeader
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveOutPrepareHeader(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr, UINT wSize)
|
|
{
|
|
MMRESULT wRet;
|
|
|
|
V_HEADER(lpWaveOutHdr, wSize, TYPE_WAVEOUT, MMSYSERR_INVALPARAM);
|
|
|
|
if (IsWaveHeaderPrepared(hWaveOut, lpWaveOutHdr))
|
|
{
|
|
DebugErr(DBF_WARNING,"waveOutPrepareHeader: header is already prepared.");
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
|
|
|
|
lpWaveOutHdr->dwFlags &= (WHDR_BEGINLOOP | WHDR_ENDLOOP);
|
|
|
|
wRet = waveMessage((HWAVE)hWaveOut, WODM_PREPARE, (DWORD_PTR)lpWaveOutHdr, (DWORD)wSize);
|
|
|
|
if (wRet == MMSYSERR_NOTSUPPORTED)
|
|
wRet = wavePrepareHeader(lpWaveOutHdr, wSize);
|
|
|
|
if (wRet == MMSYSERR_NOERROR)
|
|
MarkWaveHeaderPrepared(hWaveOut, lpWaveOutHdr);
|
|
|
|
return wRet;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveOutUnprepareHeader | This function cleans up the
|
|
* preparation performed by <f waveOutPrepareHeader>. The function
|
|
* must be called after
|
|
* the device driver is finished with a data block. You must call this
|
|
* function before freeing the data buffer.
|
|
*
|
|
* @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
|
|
* device.
|
|
*
|
|
* @parm LPWAVEHDR | lpWaveOutHdr | Specifies a pointer to a <t WAVEHDR>
|
|
* structure identifying the data block to be cleaned up.
|
|
*
|
|
* @parm UINT | wSize | Specifies the size of the <t WAVEHDR> structure.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag WAVERR_STILLPLAYING | <p lpWaveOutHdr> is still in the queue.
|
|
* @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
|
|
* thread.
|
|
*
|
|
* @comm This function is the complementary function to
|
|
* <f waveOutPrepareHeader>. You must call this function before freeing the
|
|
* data buffer with <f GlobalFree>.
|
|
* After passing a buffer to the device driver with <f waveOutWrite>, you
|
|
* must wait until the driver is finished with the buffer before calling
|
|
* <f waveOutUnprepareHeader>.
|
|
*
|
|
* Unpreparing a buffer that has not been
|
|
* prepared has no effect, and the function returns zero.
|
|
*
|
|
* @xref waveOutPrepareHeader
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveOutUnprepareHeader(HWAVEOUT hWaveOut,
|
|
LPWAVEHDR lpWaveOutHdr, UINT wSize)
|
|
{
|
|
MMRESULT wRet;
|
|
|
|
V_HEADER(lpWaveOutHdr, wSize, TYPE_WAVEOUT, MMSYSERR_INVALPARAM);
|
|
|
|
if(lpWaveOutHdr->dwFlags & WHDR_INQUEUE)
|
|
{
|
|
DebugErr(DBF_WARNING,"waveOutUnprepareHeader: header still in queue.");
|
|
return WAVERR_STILLPLAYING;
|
|
}
|
|
|
|
if (!IsWaveHeaderPrepared(hWaveOut, lpWaveOutHdr))
|
|
{
|
|
DebugErr(DBF_WARNING,"waveOutUnprepareHeader: header is not prepared.");
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
|
|
|
|
wRet = waveMessage((HWAVE)hWaveOut, WODM_UNPREPARE, (DWORD_PTR)lpWaveOutHdr, (DWORD)wSize);
|
|
|
|
if (wRet == MMSYSERR_NOTSUPPORTED)
|
|
wRet = waveUnprepareHeader(lpWaveOutHdr, wSize);
|
|
|
|
if ((wRet == MMSYSERR_NODRIVER) && (IsHandleDeserted(hWaveOut)))
|
|
{
|
|
wRet = MMSYSERR_NOERROR;
|
|
}
|
|
|
|
if (wRet == MMSYSERR_NOERROR)
|
|
MarkWaveHeaderUnprepared(hWaveOut, lpWaveOutHdr);
|
|
|
|
return wRet;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveOutWrite | This function sends a data block to the
|
|
* specified waveform output device.
|
|
*
|
|
* @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
|
|
* device.
|
|
*
|
|
* @parm LPWAVEHDR | lpWaveOutHdr | Specifies a far pointer to a <t WAVEHDR>
|
|
* structure containing information about the data block.
|
|
*
|
|
* @parm UINT | wSize | Specifies the size of the <t WAVEHDR> structure.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag WAVERR_UNPREPARED | <p lpWaveOutHdr> hasn't been prepared.
|
|
* @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
|
|
* thread.
|
|
*
|
|
* @comm The data buffer must be prepared with <f waveOutPrepareHeader> before
|
|
* it is passed to <f waveOutWrite>. The <t WAVEHDR> data structure
|
|
* and the data buffer pointed to by its <e WAVEHDR.lpData> field must be allocated
|
|
* with <f GlobalAlloc> using the GMEM_MOVEABLE and GMEM_SHARE flags, and
|
|
* locked with <f GlobalLock>. Unless the device is paused by calling
|
|
* <f waveOutPause>, playback begins when the first data block is sent to
|
|
* the device.
|
|
*
|
|
* @xref waveOutPrepareHeader waveOutPause waveOutReset waveOutRestart
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveOutWrite(HWAVEOUT hWaveOut, LPWAVEHDR lpWaveOutHdr, UINT wSize)
|
|
{
|
|
V_HEADER(lpWaveOutHdr, wSize, TYPE_WAVEOUT, MMSYSERR_INVALPARAM);
|
|
|
|
if (!IsWaveHeaderPrepared(hWaveOut, lpWaveOutHdr))
|
|
{
|
|
DebugErr(DBF_WARNING,"waveOutWrite: header not prepared");
|
|
return WAVERR_UNPREPARED;
|
|
}
|
|
|
|
if (lpWaveOutHdr->dwFlags & WHDR_INQUEUE)
|
|
{
|
|
DebugErr(DBF_WARNING,"waveOutWrite: header is still in queue");
|
|
return WAVERR_STILLPLAYING;
|
|
}
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
|
|
lpWaveOutHdr->dwFlags &= ~WHDR_DONE;
|
|
|
|
return waveMessage((HWAVE)hWaveOut, WODM_WRITE, (DWORD_PTR)lpWaveOutHdr, (DWORD)wSize);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveOutPause | This function pauses playback on a specified
|
|
* waveform output device. The current playback position is saved. Use
|
|
* <f waveOutRestart> to resume playback from the current playback position.
|
|
*
|
|
* @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
|
|
* device.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
|
|
* thread.
|
|
*
|
|
* @comm Calling this function when the output is already paused has no
|
|
* effect, and the function returns zero.
|
|
*
|
|
* @xref waveOutRestart waveOutBreakLoop
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveOutPause(HWAVEOUT hWaveOut)
|
|
{
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
|
|
|
|
return waveMessage((HWAVE)hWaveOut, WODM_PAUSE, 0L, 0L);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveOutRestart | This function restarts a paused waveform
|
|
* output device.
|
|
*
|
|
* @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
|
|
* device.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
|
|
* thread.
|
|
*
|
|
* @comm Calling this function when the output is not paused has no
|
|
* effect, and the function returns zero.
|
|
*
|
|
* @xref waveOutPause waveOutBreakLoop
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveOutRestart(HWAVEOUT hWaveOut)
|
|
{
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
|
|
|
|
return waveMessage((HWAVE)hWaveOut, WODM_RESTART, 0L, 0L);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveOutReset | This function stops playback on a given waveform
|
|
* output device and resets the current position to 0. All pending
|
|
* playback buffers are marked as done and returned to the application.
|
|
*
|
|
* @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
|
|
* device.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
|
|
* thread.
|
|
*
|
|
* @xref waveOutWrite waveOutClose
|
|
/****************************************************************************/
|
|
MMRESULT APIENTRY waveOutReset(HWAVEOUT hWaveOut)
|
|
{
|
|
MMRESULT mmr;
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
|
|
|
|
mmr = waveMessage((HWAVE)hWaveOut, WODM_RESET, 0L, 0L);
|
|
|
|
if ((MMSYSERR_NODRIVER == mmr) && (IsHandleDeserted(hWaveOut)))
|
|
{
|
|
mmr = MMSYSERR_NOERROR;
|
|
}
|
|
|
|
return (mmr);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveOutBreakLoop | This function breaks a loop on a
|
|
* given waveform output device and allows playback to continue with the
|
|
* next block in the driver list.
|
|
*
|
|
* @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
|
|
* device.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
|
|
* thread.
|
|
*
|
|
* @comm Waveform looping is controlled by the <e WAVEHDR.dwLoops> and
|
|
* <e WAVEHDR.dwFlags> fields in the <t WAVEHDR> structures passed to the device
|
|
* with <f waveOutWrite>. Use the WHDR_BEGINLOOP and WHDR_ENDLOOP flags
|
|
* in the <e WAVEHDR.dwFlags> field to specify the beginning and ending data
|
|
* blocks for looping.
|
|
*
|
|
* To loop on a single block, specify both flags for the same block.
|
|
* To specify the number of loops, use the <e WAVEHDR.dwLoops> field in
|
|
* the <t WAVEHDR> structure for the first block in the loop.
|
|
*
|
|
* The blocks making up the loop are played to the end before the loop
|
|
* is terminated.
|
|
*
|
|
* Calling this function when the nothing is playing or looping has no
|
|
* effect, and the function returns zero.
|
|
*
|
|
* @xref waveOutWrite waveOutPause waveOutRestart
|
|
/****************************************************************************/
|
|
MMRESULT APIENTRY waveOutBreakLoop(HWAVEOUT hWaveOut)
|
|
{
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
|
|
|
|
return waveMessage((HWAVE)hWaveOut, WODM_BREAKLOOP, 0L, 0L);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveOutGetPosition | This function retrieves the current
|
|
* playback position of the specified waveform output device.
|
|
*
|
|
* @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
|
|
* device.
|
|
*
|
|
* @parm LPMMTIME | lpInfo | Specifies a far pointer to an <t MMTIME>
|
|
* structure.
|
|
*
|
|
* @parm UINT | wSize | Specifies the size of the <t MMTIME> structure.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
|
|
* thread.
|
|
*
|
|
* @comm Before calling <f waveOutGetPosition>, set the <e MMTIME.wType> field of the
|
|
* MMTIME structure to indicate the time format that you desire. After
|
|
* calling <f waveOutGetPosition>, check the <e MMTIME.wType> field
|
|
* to determine if the desired time format is supported. If the desired
|
|
* format is not supported, <e MMTIME.wType> will specify an alternative format.
|
|
*
|
|
* The position is set to zero when the device is opened or reset.
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveOutGetPosition(HWAVEOUT hWaveOut, LPMMTIME lpInfo,
|
|
UINT wSize)
|
|
{
|
|
V_WPOINTER(lpInfo, wSize, MMSYSERR_INVALPARAM);
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
|
|
|
|
return waveMessage((HWAVE)hWaveOut, WODM_GETPOS, (DWORD_PTR)lpInfo, (DWORD)wSize);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveOutGetPitch | This function queries the the current pitch
|
|
* setting of a waveform output device.
|
|
*
|
|
* @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
|
|
* device.
|
|
*
|
|
* @parm LPDWORD | lpdwPitch | Specifies a far pointer to a location
|
|
* to be filled with the current pitch multiplier setting. The pitch
|
|
* multiplier indicates the current change in pitch from the original
|
|
* authored setting. The pitch multiplier must be a positive value.
|
|
*
|
|
* The pitch multiplier is specified as a fixed-point value. The high-order word
|
|
* of the DWORD location contains the signed integer part of the number,
|
|
* and the low-order word contains the fractional part. The fraction is
|
|
* expressed as a WORD in which a value of 0x8000 represents one half,
|
|
* and 0x4000 represents one quarter. For example, the value 0x00010000
|
|
* specifies a multiplier of 1.0 (no pitch change), and a value of
|
|
* 0x000F8000 specifies a multiplier of 15.5.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
|
|
* @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
|
|
* thread.
|
|
*
|
|
* @comm Changing the pitch does not change the playback rate, sample
|
|
* rate, or playback time. Not all devices support
|
|
* pitch changes. To determine whether the device supports pitch control,
|
|
* use the WAVECAPS_PITCH flag to test the <e WAVEOUTCAPS.dwSupport>
|
|
* field of the <t WAVEOUTCAPS> structure (filled by <f waveOutGetDevCaps>).
|
|
*
|
|
* @xref waveOutSetPitch waveOutGetPlaybackRate waveOutSetPlaybackRate
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveOutGetPitch(HWAVEOUT hWaveOut, LPDWORD lpdwPitch)
|
|
{
|
|
V_WPOINTER(lpdwPitch, sizeof(DWORD), MMSYSERR_INVALPARAM);
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
|
|
|
|
return waveMessage((HWAVE)hWaveOut, WODM_GETPITCH, (DWORD_PTR)lpdwPitch, 0L);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveOutSetPitch | This function sets the pitch of a waveform
|
|
* output device.
|
|
*
|
|
* @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform
|
|
* output device.
|
|
*
|
|
* @parm DWORD | dwPitch | Specifies the new pitch multiplier setting.
|
|
* The pitch multiplier setting indicates the current change in pitch
|
|
* from the original authored setting. The pitch multiplier must be a
|
|
* positive value.
|
|
*
|
|
* The pitch multiplier is specified as a fixed-point value. The high-order word
|
|
* location contains the signed integer part of the number,
|
|
* and the low-order word contains the fractional part. The fraction is
|
|
* expressed as a WORD in which a value of 0x8000 represents one half,
|
|
* and 0x4000 represents one quarter.
|
|
* For example, the value 0x00010000 specifies a multiplier
|
|
* of 1.0 (no pitch change), and a value of 0x000F8000 specifies a
|
|
* multiplier of 15.5.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
|
|
* @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
|
|
* thread.
|
|
*
|
|
* @comm Changing the pitch does not change the playback rate or the sample
|
|
* rate. The playback time is also unchanged. Not all devices support
|
|
* pitch changes. To determine whether the device supports pitch control,
|
|
* use the WAVECAPS_PITCH flag to test the <e WAVEOUTCAPS.dwSupport>
|
|
* field of the <t WAVEOUTCAPS> structure (filled by <f waveOutGetDevCaps>).
|
|
*
|
|
* @xref waveOutGetPitch waveOutSetPlaybackRate waveOutGetPlaybackRate
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveOutSetPitch(HWAVEOUT hWaveOut, DWORD dwPitch)
|
|
{
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
|
|
|
|
return waveMessage((HWAVE)hWaveOut, WODM_SETPITCH, dwPitch, 0L);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveOutGetPlaybackRate | This function queries the
|
|
* current playback rate setting of a waveform output device.
|
|
*
|
|
* @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform output
|
|
* device.
|
|
*
|
|
* @parm LPDWORD | lpdwRate | Specifies a far pointer to a location
|
|
* to be filled with the current playback rate. The playback rate setting
|
|
* is a multiplier indicating the current change in playback rate from
|
|
* the original authored setting. The playback rate multiplier must be
|
|
* a positive value.
|
|
*
|
|
* The rate is specified as a fixed-point value. The high-order word
|
|
* of the DWORD location contains the signed integer part of the number,
|
|
* and the low-order word contains the fractional part. The fraction is
|
|
* expressed as a WORD in which a value of 0x8000 represents one half,
|
|
* and 0x4000 represents one quarter. For example, the value 0x00010000
|
|
* specifies a multiplier of 1.0 (no playback rate change), and a value
|
|
* of 0x000F8000 specifies a multiplier of 15.5.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
|
|
* @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
|
|
* thread.
|
|
*
|
|
* @comm Changing the playback rate does not change the sample rate but does
|
|
* change the playback time.
|
|
*
|
|
* Not all devices support playback rate changes. To determine whether a
|
|
* device supports playback rate changes, use
|
|
* the WAVECAPS_PLAYBACKRATE flag to test the <e WAVEOUTCAPS.dwSupport> field of the
|
|
* <t WAVEOUTCAPS> structure (filled by <f waveOutGetDevCaps>).
|
|
*
|
|
* @xref waveOutSetPlaybackRate waveOutSetPitch waveOutGetPitch
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveOutGetPlaybackRate(HWAVEOUT hWaveOut, LPDWORD lpdwRate)
|
|
{
|
|
V_WPOINTER(lpdwRate, sizeof(DWORD), MMSYSERR_INVALPARAM);
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
|
|
|
|
return waveMessage((HWAVE)hWaveOut, WODM_GETPLAYBACKRATE, (DWORD_PTR)lpdwRate, 0L);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveOutSetPlaybackRate | This function sets the
|
|
* playback rate of a waveform output device.
|
|
*
|
|
* @parm HWAVEOUT | hWaveOut | Specifies a handle to the waveform
|
|
* output device.
|
|
*
|
|
* @parm DWORD | dwRate | Specifies the new playback rate setting.
|
|
* The playback rate setting is a multiplier indicating the current
|
|
* change in playback rate from the original authored setting. The playback
|
|
* rate multiplier must be a positive value.
|
|
*
|
|
* The rate is specified as a fixed-point value. The high-order word
|
|
* contains the signed integer part of the number,
|
|
* and the low-order word contains the fractional part. The fraction is
|
|
* expressed as a WORD in which a value of 0x8000 represents one half,
|
|
* and 0x4000 represents one quarter.
|
|
* For example, the value 0x00010000 specifies a multiplier of 1.0 (no
|
|
* playback rate change), and a value of 0x000F8000 specifies a
|
|
* multiplier of 15.5.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag MMSYSERR_NOTSUPPORTED | Function isn't supported.
|
|
* @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
|
|
* thread.
|
|
*
|
|
* @comm Changing the playback rate does not change the sample rate but does
|
|
* change the playback time.
|
|
*
|
|
* Not all devices support playback rate changes. To determine whether a
|
|
* device supports playback rate changes,
|
|
* use the WAVECAPS_PLAYBACKRATE flag to test the <e WAVEOUTCAPS.dwSupport> field of the
|
|
* <t WAVEOUTCAPS> structure (filled by <f waveOutGetDevCaps>).
|
|
*
|
|
* @xref waveOutGetPlaybackRate waveOutSetPitch waveOutGetPitch
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveOutSetPlaybackRate(HWAVEOUT hWaveOut, DWORD dwRate)
|
|
{
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
|
|
|
|
return waveMessage((HWAVE)hWaveOut, WODM_SETPLAYBACKRATE, dwRate, 0L);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api UINT | waveInGetNumDevs | This function returns the number of waveform
|
|
* input devices.
|
|
*
|
|
* @rdesc Returns the number of waveform input devices present in the system.
|
|
*
|
|
* @xref waveInGetDevCaps
|
|
****************************************************************************/
|
|
UINT APIENTRY waveInGetNumDevs(void)
|
|
{
|
|
ClientUpdatePnpInfo();
|
|
|
|
dprintf3(("waveInGetNumDevs returning %d devices", wTotalWaveInDevs));
|
|
|
|
// EnterNumDevs("waveInGetNumDevs");
|
|
return wTotalWaveInDevs;
|
|
// LeaveNumDevs("waveInGetNumDevs");
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// MMRESULT waveOutDesertHandle
|
|
//
|
|
// Description:
|
|
// Cleans up the wave out handle and marks it as deserted.
|
|
//
|
|
// Arguments:
|
|
// HWAVEOUT hWaveOut: Wave out handle
|
|
//
|
|
// Return (MMRESULT): Error code.
|
|
//
|
|
// History:
|
|
// 01/25/99 Fwong Adding Pnp Support.
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
MMRESULT waveOutDesertHandle
|
|
(
|
|
HWAVEOUT hWaveOut
|
|
)
|
|
{
|
|
MMRESULT mmr;
|
|
PWAVEDEV pDev = (PWAVEDEV)hWaveOut;
|
|
|
|
V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
|
|
|
|
ENTER_MM_HANDLE((HWAVE)hWaveOut);
|
|
ReleaseHandleListResource();
|
|
|
|
if (IsHandleDeserted(hWaveOut))
|
|
{
|
|
LEAVE_MM_HANDLE((HWAVE)hWaveOut);
|
|
return (MMSYSERR_NOERROR);
|
|
}
|
|
|
|
if (IsHandleBusy(hWaveOut))
|
|
{
|
|
// Not quite invalid, but marked as closed.
|
|
|
|
LEAVE_MM_HANDLE(hWaveOut);
|
|
return (MMSYSERR_HANDLEBUSY);
|
|
}
|
|
|
|
// Marking handle as deserted
|
|
SetHandleFlag(hWaveOut, MMHANDLE_DESERTED);
|
|
|
|
// Since the handle was invalidated, we have to send the message ourselves...
|
|
|
|
(*(pDev->wavedrv->drvMessage))(pDev->wDevice, WODM_RESET, pDev->dwDrvUser, 0L, 0L);
|
|
(*(pDev->wavedrv->drvMessage))(pDev->wDevice, WODM_CLOSE, pDev->dwDrvUser, 0L, 0L);
|
|
|
|
LEAVE_MM_HANDLE((HWAVE)hWaveOut);
|
|
|
|
// ISSUE-2001/01/14-FrankYe Probably don't want to dec usage here,
|
|
// dec on close instead.
|
|
mregDecUsagePtr(pDev->wavedrv);
|
|
|
|
return MMSYSERR_NOERROR;
|
|
} // waveOutDesertHandle()
|
|
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveInMessage | This function sends messages to the waveform
|
|
* output device drivers.
|
|
*
|
|
* @parm HWAVEIN | hWave | The handle to the audio device.
|
|
*
|
|
* @parm UINT | wMsg | The message to send.
|
|
*
|
|
* @parm DWORD | dw1 | Parameter 1.
|
|
*
|
|
* @parm DWORD | dw2 | Parameter 2.
|
|
*
|
|
* @rdesc Returns the value returned from the driver.
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveInMessage(HWAVEIN hWaveIn, UINT msg, DWORD_PTR dw1, DWORD_PTR dw2)
|
|
{
|
|
ClientUpdatePnpInfo();
|
|
|
|
AcquireHandleListResourceShared();
|
|
|
|
if (BAD_HANDLE((HWAVE)hWaveIn, TYPE_WAVEIN))
|
|
{
|
|
ReleaseHandleListResource();
|
|
return waveIDMessage(&waveindrvZ, wTotalWaveInDevs, PtrToUint(hWaveIn), msg, dw1, dw2);
|
|
}
|
|
else
|
|
{
|
|
return waveMessage((HWAVE)hWaveIn, msg, dw1, dw2);
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveInGetDevCaps | This function queries a specified waveform
|
|
* input device to determine its capabilities.
|
|
*
|
|
* @parm UINT | uDeviceID | Identifies the waveform input device.
|
|
*
|
|
* @parm LPWAVEINCAPS | lpCaps | Specifies a far pointer to a <t WAVEINCAPS>
|
|
* structure. This structure is filled with information about the
|
|
* capabilities of the device.
|
|
*
|
|
* @parm UINT | wSize | Specifies the size of the <t WAVEINCAPS> structure.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
|
|
* @flag MMSYSERR_NODRIVER | The driver was not installed.
|
|
*
|
|
* @comm Use <f waveInGetNumDevs> to determine the number of waveform input
|
|
* devices present in the system. The device ID specified by <p uDeviceID>
|
|
* varies from zero to one less than the number of devices present.
|
|
* The WAVE_MAPPER constant may also be used as a device id. Only
|
|
* <p wSize> bytes (or less) of information is copied to the location
|
|
* pointed to by <p lpCaps>. If <p wSize> is zero, nothing is copied, and
|
|
* the function returns zero.
|
|
*
|
|
* @xref waveInGetNumDevs
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveInGetDevCapsW(UINT_PTR uDeviceID, LPWAVEINCAPSW lpCaps,UINT wSize)
|
|
{
|
|
DWORD_PTR dwParam1, dwParam2;
|
|
MDEVICECAPSEX mdCaps;
|
|
PWAVEDRV waveindrv;
|
|
PCWSTR DevInterface;
|
|
MMRESULT mmr;
|
|
|
|
if (wSize == 0)
|
|
return MMSYSERR_NOERROR;
|
|
|
|
V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
DevInterface = waveReferenceDevInterfaceById(&waveindrvZ, uDeviceID);
|
|
dwParam2 = (DWORD_PTR)DevInterface;
|
|
|
|
if (0 == dwParam2)
|
|
{
|
|
dwParam1 = (DWORD_PTR)lpCaps;
|
|
dwParam2 = (DWORD)wSize;
|
|
}
|
|
else
|
|
{
|
|
mdCaps.cbSize = (DWORD)wSize;
|
|
mdCaps.pCaps = lpCaps;
|
|
dwParam1 = (DWORD_PTR)&mdCaps;
|
|
}
|
|
|
|
//
|
|
// Don't allow non proper drivers in TS environement
|
|
//
|
|
// ISSUE-2001/01/09-FrankYe Instead of cast to UINT. Should check whether
|
|
// this is a handle and get wavedrv from handle if it is.
|
|
waveindrv = NULL;
|
|
if ((!waveReferenceDriverById(&waveindrvZ, (UINT)uDeviceID, &waveindrv, NULL)) &&
|
|
lstrcmpW(waveindrv->wszSessProtocol, SessionProtocolName))
|
|
{
|
|
mmr = MMSYSERR_NODRIVER;
|
|
}
|
|
else
|
|
{
|
|
AcquireHandleListResourceShared();
|
|
|
|
if (BAD_HANDLE((HWAVE)uDeviceID, TYPE_WAVEIN))
|
|
{
|
|
ReleaseHandleListResource();
|
|
mmr = waveIDMessage(&waveindrvZ, wTotalWaveInDevs, (UINT)uDeviceID, WIDM_GETDEVCAPS, dwParam1, dwParam2);
|
|
}
|
|
else
|
|
{
|
|
mmr = (MMRESULT)waveMessage((HWAVE)uDeviceID, WIDM_GETDEVCAPS, dwParam1, dwParam2);
|
|
}
|
|
}
|
|
|
|
if (waveindrv) mregDecUsagePtr(waveindrv);
|
|
if (DevInterface) wdmDevInterfaceDec(DevInterface);
|
|
return mmr;
|
|
}
|
|
|
|
MMRESULT APIENTRY waveInGetDevCapsA(UINT_PTR uDeviceID, LPWAVEINCAPSA lpCaps,UINT wSize)
|
|
{
|
|
WAVEINCAPS2W wDevCaps2;
|
|
WAVEINCAPS2A aDevCaps2;
|
|
DWORD_PTR dwParam1, dwParam2;
|
|
MDEVICECAPSEX mdCaps;
|
|
PCWSTR DevInterface;
|
|
PWAVEDRV waveindrv;
|
|
MMRESULT mmRes;
|
|
|
|
if (wSize == 0)
|
|
return MMSYSERR_NOERROR;
|
|
|
|
V_WPOINTER(lpCaps, wSize, MMSYSERR_INVALPARAM);
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
DevInterface = waveReferenceDevInterfaceById(&waveindrvZ, uDeviceID);
|
|
dwParam2 = (DWORD_PTR)DevInterface;
|
|
|
|
memset(&wDevCaps2, 0, sizeof(wDevCaps2));
|
|
|
|
if (0 == dwParam2)
|
|
{
|
|
dwParam1 = (DWORD_PTR)&wDevCaps2;
|
|
dwParam2 = (DWORD)sizeof(wDevCaps2);
|
|
}
|
|
else
|
|
{
|
|
mdCaps.cbSize = (DWORD)sizeof(wDevCaps2);
|
|
mdCaps.pCaps = &wDevCaps2;
|
|
dwParam1 = (DWORD_PTR)&mdCaps;
|
|
}
|
|
|
|
//
|
|
// Don't allow non proper drivers in TS environement
|
|
//
|
|
// ISSUE-2001/01/09-FrankYe Bad cast to UINT. Should check whether this
|
|
// is a handle and get wavedrv from handle if it is.
|
|
waveindrv = NULL;
|
|
if ( uDeviceID < wTotalWaveInDevs &&
|
|
!waveReferenceDriverById(&waveindrvZ, (UINT)uDeviceID, &waveindrv, NULL) &&
|
|
lstrcmpW(waveindrv->wszSessProtocol, SessionProtocolName) )
|
|
{
|
|
mregDecUsagePtr(waveindrv);
|
|
if (DevInterface) wdmDevInterfaceDec(DevInterface);
|
|
return MMSYSERR_NODRIVER;
|
|
}
|
|
|
|
AcquireHandleListResourceShared();
|
|
|
|
if (BAD_HANDLE((HWAVE)uDeviceID, TYPE_WAVEIN))
|
|
{
|
|
ReleaseHandleListResource();
|
|
mmRes = waveIDMessage( &waveindrvZ, wTotalWaveInDevs, (UINT)uDeviceID,
|
|
WIDM_GETDEVCAPS, dwParam1, dwParam2);
|
|
}
|
|
else
|
|
{
|
|
mmRes = waveMessage((HWAVE)uDeviceID, WIDM_GETDEVCAPS,
|
|
dwParam1, dwParam2);
|
|
}
|
|
|
|
if (waveindrv) mregDecUsagePtr(waveindrv);
|
|
if (DevInterface) wdmDevInterfaceDec(DevInterface);
|
|
|
|
//
|
|
// Make sure the call worked before proceeding with the thunk.
|
|
//
|
|
if ( mmRes != MMSYSERR_NOERROR ) {
|
|
return mmRes;
|
|
}
|
|
|
|
aDevCaps2.wMid = wDevCaps2.wMid;
|
|
aDevCaps2.wPid = wDevCaps2.wPid;
|
|
aDevCaps2.vDriverVersion = wDevCaps2.vDriverVersion;
|
|
aDevCaps2.dwFormats = wDevCaps2.dwFormats;
|
|
aDevCaps2.wChannels = wDevCaps2.wChannels;
|
|
aDevCaps2.ManufacturerGuid = wDevCaps2.ManufacturerGuid;
|
|
aDevCaps2.ProductGuid = wDevCaps2.ProductGuid;
|
|
aDevCaps2.NameGuid = wDevCaps2.NameGuid;
|
|
|
|
// copy and convert unicode to ascii here.
|
|
Iwcstombs(aDevCaps2.szPname, wDevCaps2.szPname, MAXPNAMELEN);
|
|
|
|
//
|
|
// now copy the required amount into the callers buffer.
|
|
//
|
|
CopyMemory( lpCaps, &aDevCaps2, min(wSize, sizeof(aDevCaps2)));
|
|
|
|
return mmRes;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveInGetErrorText | This function retrieves a textual
|
|
* description of the error identified by the specified error number.
|
|
*
|
|
* @parm UINT | wError | Specifies the error number.
|
|
*
|
|
* @parm LPTSTR | lpText | Specifies a far pointer to the buffer to be
|
|
* filled with the textual error description.
|
|
*
|
|
* @parm UINT | wSize | Specifies the length in characters of the buffer
|
|
* pointed to by <p lpText>.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_BADERRNUM | Specified error number is out of range.
|
|
*
|
|
* @comm If the textual error description is longer than the specified buffer,
|
|
* the description is truncated. The returned error string is always
|
|
* null-terminated. If <p wSize> is zero, nothing is copied, and the function
|
|
* returns zero. All error descriptions are less than MAXERRORLENGTH characters long.
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveInGetErrorTextW(UINT wError, LPWSTR lpText, UINT wSize)
|
|
{
|
|
if (wSize == 0)
|
|
return MMSYSERR_NOERROR;
|
|
|
|
V_WPOINTER(lpText, wSize*sizeof(WCHAR), MMSYSERR_INVALPARAM);
|
|
|
|
return waveGetErrorTextW(wError, lpText, wSize);
|
|
}
|
|
|
|
MMRESULT APIENTRY waveInGetErrorTextA(UINT wError, LPSTR lpText, UINT wSize)
|
|
{
|
|
if (wSize == 0)
|
|
return MMSYSERR_NOERROR;
|
|
|
|
V_WPOINTER(lpText, wSize, MMSYSERR_INVALPARAM);
|
|
|
|
return waveGetErrorTextA(wError, lpText, wSize );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveInOpen | This function opens a specified waveform
|
|
* input device for recording.
|
|
*
|
|
* @parm LPHWAVEIN | lphWaveIn | Specifies a far pointer to a HWAVEIN
|
|
* handle. This location is filled with a handle identifying the opened
|
|
* waveform input device. Use this handle to identify the device when
|
|
* calling other waveform input functions. This parameter may be NULL
|
|
* if the WAVE_FORMAT_QUERY flag is specified for <p dwFlags>.
|
|
*
|
|
* @parm UINT | uDeviceID | Identifies the waveform input device to open. Use
|
|
* a valid device ID or the following flag:
|
|
*
|
|
* @flag WAVE_MAPPER | If this flag is specified, the function
|
|
* selects a waveform input device capable of recording in the
|
|
* given format.
|
|
*
|
|
* @parm LPWAVEFORMATEX | lpFormat | Specifies a pointer to a <t WAVEFORMATEX>
|
|
* data structure that identifies the desired format for recording
|
|
* waveform data.
|
|
*
|
|
* @parm DWORD | dwCallback | Specifies the address of a callback
|
|
* function or a handle to a window called during waveform
|
|
* recording to process messages related to the progress of recording.
|
|
*
|
|
* @parm DWORD | dwCallbackInstance | Specifies user
|
|
* instance data passed to the callback. This parameter is not
|
|
* used with window callbacks.
|
|
*
|
|
* @parm DWORD | dwFlags | Specifies flags for opening the device.
|
|
* @flag WAVE_FORMAT_QUERY | If this flag is specified, the device will
|
|
* be queried to determine if it supports the given format but will not
|
|
* actually be opened.
|
|
* @flag WAVE_ALLOWSYNC | If this flag is not specified, then the
|
|
* device will fail to open if it is a synchronous device.
|
|
* @flag CALLBACK_WINDOW | If this flag is specified, <p dwCallback> is
|
|
* assumed to be a window handle.
|
|
* @flag CALLBACK_FUNCTION | If this flag is specified, <p dwCallback> is
|
|
* assumed to be a callback procedure address.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_BADDEVICEID | Specified device ID is out of range.
|
|
* @flag MMSYSERR_ALLOCATED | Specified resource is already allocated.
|
|
* @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
|
|
* @flag WAVERR_BADFORMAT | Attempted to open with an unsupported wave format.
|
|
*
|
|
* @comm Use <f waveInGetNumDevs> to determine the number of waveform input
|
|
* devices present in the system. The device ID specified by <p uDeviceID>
|
|
* varies from zero to one less than the number of devices present.
|
|
* The WAVE_MAPPER constant may also be used as a device id.
|
|
*
|
|
* If a window is chosen to receive callback information, the following
|
|
* messages are sent to the window procedure function to indicate the
|
|
* progress of waveform input: <m MM_WIM_OPEN>, <m MM_WIM_CLOSE>,
|
|
* <m MM_WIM_DATA>
|
|
*
|
|
* If a function is chosen to receive callback information, the following
|
|
* messages are sent to the function to indicate the progress of waveform
|
|
* input: <m WIM_OPEN>, <m WIM_CLOSE>, <m WIM_DATA>. The callback function
|
|
* must reside in a DLL. You do not have to use <f MakeProcInstance> to get
|
|
* a procedure-instance address for the callback function.
|
|
*
|
|
* @cb void CALLBACK | WaveInFunc | <f WaveInFunc> is a placeholder for the
|
|
* application-supplied function name. The actual name must be exported by
|
|
* including it in an EXPORTS statement in the DLL's module-definition file.
|
|
*
|
|
* @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform device
|
|
* associated with the callback.
|
|
*
|
|
* @parm UINT | wMsg | Specifies a waveform input device.
|
|
*
|
|
* @parm DWORD | dwInstance | Specifies the user instance
|
|
* data specified with <f waveInOpen>.
|
|
*
|
|
* @parm DWORD | dwParam1 | Specifies a parameter for the message.
|
|
*
|
|
* @parm DWORD | dwParam2 | Specifies a parameter for the message.
|
|
*
|
|
* @comm Because the callback is accessed at interrupt time, it must reside
|
|
* in a DLL and its code segment must be specified as FIXED in the
|
|
* module-definition file for the DLL. Any data that the callback accesses
|
|
* must be in a FIXED data segment as well. The callback may not make any
|
|
* system calls except for <f PostMessage>, <f timeGetSystemTime>,
|
|
* <f timeGetTime>, <f timeSetEvent>, <f timeKillEvent>,
|
|
* <f midiOutShortMsg>, <f midiOutLongMsg>, and <f OutputDebugStr>.
|
|
*
|
|
* @xref waveInClose
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveInOpen(LPHWAVEIN lphWaveIn, UINT uDeviceID,
|
|
LPCWAVEFORMATEX lpFormat, DWORD_PTR dwCallback,
|
|
DWORD_PTR dwInstance, DWORD dwFlags)
|
|
{
|
|
WAVEOPENDESC wo;
|
|
UINT port;
|
|
PWAVEDEV pdev;
|
|
PWAVEDRV wavedrv;
|
|
MMRESULT wRet;
|
|
DWORD_PTR dwDrvUser;
|
|
|
|
V_RPOINTER(lpFormat, sizeof(WAVEFORMAT), MMSYSERR_INVALPARAM);
|
|
V_DCALLBACK(dwCallback, HIWORD(dwFlags), MMSYSERR_INVALPARAM);
|
|
// Because some 32-bit applications use the value 0x0000FFFF for
|
|
// WAVE_MAPPER instead of 0xFFFFFFFF, we clamp up to the correct value.
|
|
// This just happened to work on Win9x because WinMM would thunk down
|
|
// to MMSystem and send down the lower word to the 16-bit interface.
|
|
if (uDeviceID == LOWORD(WAVE_MAPPER)) {
|
|
uDeviceID = WAVE_MAPPER;
|
|
}
|
|
if (uDeviceID == WAVE_MAPPER) {
|
|
V_FLAGS(LOWORD(dwFlags), WAVE_VALID & ~(WAVE_MAPPED), waveInOpen, MMSYSERR_INVALFLAG);
|
|
} else {
|
|
V_FLAGS(LOWORD(dwFlags), WAVE_VALID, waveInOpen, MMSYSERR_INVALFLAG);
|
|
}
|
|
|
|
if (lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
|
|
V_RPOINTER(lpFormat, sizeof(WAVEFORMATEX), MMSYSERR_INVALPARAM);
|
|
if (lpFormat->cbSize) {
|
|
V_RPOINTER(lpFormat + 1, lpFormat->cbSize, MMSYSERR_INVALPARAM);
|
|
}
|
|
}
|
|
|
|
if (dwFlags & WAVE_FORMAT_QUERY) {
|
|
lphWaveIn = NULL;
|
|
} else {
|
|
V_WPOINTER((LPVOID)lphWaveIn, sizeof(HWAVEIN), MMSYSERR_INVALPARAM);
|
|
// WAVE_FORMAT_DIRECT was bounced on Win95. Now we
|
|
// accept this flag
|
|
//
|
|
// if (dwFlags & WAVE_FORMAT_DIRECT)
|
|
// return MMSYSERR_INVALFLAG;
|
|
*lphWaveIn = NULL;
|
|
}
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
if ((!wTotalWaveInDevs) || waveReferenceDriverById(&waveindrvZ, (dwFlags & WAVE_MAPPED) ? WAVE_MAPPER : uDeviceID, &wavedrv, &port))
|
|
{
|
|
return MMSYSERR_BADDEVICEID;
|
|
}
|
|
|
|
//
|
|
// check if the device is appropriate for the current TS session
|
|
//
|
|
if (!(wavedrv->fdwDriver & MMDRV_MAPPER) &&
|
|
lstrcmpW(wavedrv->wszSessProtocol, SessionProtocolName))
|
|
{
|
|
mregDecUsagePtr(wavedrv);
|
|
return MMSYSERR_NODRIVER;
|
|
}
|
|
|
|
/* Default wave mapper :
|
|
*
|
|
* If a wave mapper is installed as a separate DLL then all wave mapper
|
|
* messages are routed to it. If no wave mapper is installed, simply
|
|
* loop through the wave devices looking for a match.
|
|
*/
|
|
// ISSUE-2001/01/06-FrankYe This logic looks broken for the WAVE_MAPPED case
|
|
if ((uDeviceID == WAVE_MAPPER && !wavedrv->drvMessage)) {
|
|
UINT wErr;
|
|
|
|
mregDecUsagePtr(wavedrv);
|
|
wErr = MMSYSERR_ALLOCATED;
|
|
|
|
if (dwFlags & WAVE_MAPPED)
|
|
{
|
|
if (wErr = waveReferenceDriverById(&waveindrvZ, uDeviceID, &wavedrv, &port))
|
|
return wErr;
|
|
|
|
if (mregHandleInternalMessages(wavedrv,
|
|
MMDRVI_WAVEIN,
|
|
port,
|
|
DRV_QUERYMAPPABLE,
|
|
0, 0, &wErr) ||
|
|
(MMSYSERR_NOERROR != wErr))
|
|
{
|
|
mregDecUsagePtr(wavedrv);
|
|
return wErr;
|
|
}
|
|
wErr = waveInOpen(lphWaveIn, uDeviceID, lpFormat, dwCallback, dwInstance, dwFlags & ~WAVE_MAPPED);
|
|
mregDecUsagePtr(wavedrv);
|
|
}
|
|
else
|
|
{
|
|
for (uDeviceID=0; uDeviceID<wTotalWaveInDevs; uDeviceID++) {
|
|
wErr = waveInOpen(lphWaveIn, uDeviceID, lpFormat, dwCallback, dwInstance, dwFlags);
|
|
if (!wErr)
|
|
break;
|
|
}
|
|
}
|
|
return wErr;
|
|
}
|
|
|
|
if (dwFlags & WAVE_FORMAT_QUERY)
|
|
pdev = NULL;
|
|
else {
|
|
if (!(pdev = (PWAVEDEV)NewHandle(TYPE_WAVEIN, wavedrv->cookie, sizeof(WAVEDEV))))
|
|
return MMSYSERR_NOMEM;
|
|
|
|
ENTER_MM_HANDLE(pdev);
|
|
SetHandleFlag(pdev, MMHANDLE_BUSY);
|
|
ReleaseHandleListResource();
|
|
|
|
pdev->wavedrv = wavedrv;
|
|
pdev->wDevice = port;
|
|
pdev->uDeviceID = uDeviceID;
|
|
pdev->fdwHandle = 0;
|
|
}
|
|
|
|
wo.hWave = (HWAVE)pdev;
|
|
wo.dwCallback = dwCallback;
|
|
wo.dwInstance = dwInstance;
|
|
wo.uMappedDeviceID = uDeviceID;
|
|
wo.lpFormat = (LPWAVEFORMAT)lpFormat; // cast away the CONST to eliminate wng
|
|
wo.dnDevNode = (DWORD_PTR)wavedrv->cookie;
|
|
|
|
wRet = (MMRESULT)((*(wavedrv->drvMessage))
|
|
(port, WIDM_OPEN, (DWORD_PTR)&dwDrvUser, (DWORD_PTR)(LPWAVEOPENDESC)&wo, dwFlags));
|
|
|
|
if (pdev) {
|
|
// Mark as not busy on successful open...
|
|
if (!wRet)
|
|
ClearHandleFlag(pdev, MMHANDLE_BUSY);
|
|
|
|
LEAVE_MM_HANDLE(pdev);
|
|
|
|
if (wRet)
|
|
FreeHandle((HWAVEIN)pdev);
|
|
else {
|
|
// Inc usage since we opened a handle on it
|
|
mregIncUsagePtr(wavedrv);
|
|
*lphWaveIn = (HWAVEIN)pdev;
|
|
pdev->dwDrvUser = dwDrvUser;
|
|
}
|
|
}
|
|
|
|
mregDecUsagePtr(wavedrv);
|
|
return wRet;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveInClose | This function closes the specified waveform
|
|
* input device.
|
|
*
|
|
* @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input device.
|
|
* If the function is successful, the handle is no longer
|
|
* valid after this call.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag WAVERR_STILLPLAYING | There are still buffers in the queue.
|
|
*
|
|
* @comm If there are input buffers that have been sent with
|
|
* <f waveInAddBuffer>, and haven't been returned to the application,
|
|
* the close operation will fail. Call <f waveInReset> to mark all
|
|
* pending buffers as done.
|
|
*
|
|
* @xref waveInOpen waveInReset
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveInClose(HWAVEIN hWaveIn)
|
|
{
|
|
MMRESULT wRet;
|
|
PWAVEDRV pwavedrv;
|
|
PWAVEDEV pDev = (PWAVEDEV)hWaveIn;
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
|
|
|
|
ENTER_MM_HANDLE((HWAVE)hWaveIn);
|
|
ReleaseHandleListResource();
|
|
|
|
if (IsHandleDeserted(hWaveIn))
|
|
{
|
|
// This handle has been deserted. Let's just free it.
|
|
|
|
LEAVE_MM_HANDLE((HWAVE)hWaveIn);
|
|
FreeHandle(hWaveIn);
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
if (IsHandleBusy(hWaveIn))
|
|
{
|
|
// Not quite invalid, but marked as closed.
|
|
|
|
LEAVE_MM_HANDLE(hWaveIn);
|
|
return (MMSYSERR_HANDLEBUSY);
|
|
}
|
|
|
|
// Marking handle as 'invalid/closed'.
|
|
SetHandleFlag(hWaveIn, MMHANDLE_BUSY);
|
|
|
|
pwavedrv = pDev->wavedrv;
|
|
|
|
wRet = (MMRESULT)(*(pwavedrv->drvMessage))(pDev->wDevice, WIDM_CLOSE, pDev->dwDrvUser, 0L, 0L);
|
|
|
|
if (MMSYSERR_NOERROR != wRet)
|
|
{
|
|
ClearHandleFlag(hWaveIn, MMHANDLE_BUSY);
|
|
}
|
|
|
|
LEAVE_MM_HANDLE((HWAVE)hWaveIn);
|
|
|
|
if (!wRet)
|
|
{
|
|
FreeHandle(hWaveIn);
|
|
mregDecUsagePtr(pwavedrv);
|
|
return wRet;
|
|
}
|
|
|
|
return wRet;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveInPrepareHeader | This function prepares a buffer
|
|
* for waveform input.
|
|
*
|
|
* @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input
|
|
* device.
|
|
*
|
|
* @parm LPWAVEHDR | lpWaveInHdr | Specifies a pointer to a
|
|
* <t WAVEHDR> structure that identifies the buffer to be prepared.
|
|
*
|
|
* @parm UINT | wSize | Specifies the size of the <t WAVEHDR> structure.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag MMSYSERR_NOMEM | Unable to allocate or lock memory.
|
|
* @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveIn> is in use on another
|
|
* thread.
|
|
*
|
|
* @comm The <t WAVEHDR> data structure and the data block pointed to by its
|
|
* <e WAVEHDR.lpData> field must be allocated with <f GlobalAlloc> using the
|
|
* GMEM_MOVEABLE and GMEM_SHARE flags, and locked with <f GlobalLock>.
|
|
* Preparing a header that has already been prepared will have no effect,
|
|
* and the function will return zero.
|
|
*
|
|
* @xref waveInUnprepareHeader
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveInPrepareHeader(HWAVEIN hWaveIn, LPWAVEHDR lpWaveInHdr,
|
|
UINT wSize)
|
|
{
|
|
MMRESULT wRet;
|
|
|
|
V_HEADER(lpWaveInHdr, wSize, TYPE_WAVEIN, MMSYSERR_INVALPARAM);
|
|
|
|
if (IsWaveHeaderPrepared(hWaveIn, lpWaveInHdr))
|
|
{
|
|
DebugErr(DBF_WARNING,"waveInPrepareHeader: header is already prepared.");
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
lpWaveInHdr->dwFlags = 0;
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
|
|
|
|
wRet = waveMessage((HWAVE)hWaveIn, WIDM_PREPARE, (DWORD_PTR)lpWaveInHdr, (DWORD)wSize);
|
|
|
|
if (wRet == MMSYSERR_NOTSUPPORTED)
|
|
wRet = wavePrepareHeader(lpWaveInHdr, wSize);
|
|
|
|
if (wRet == MMSYSERR_NOERROR)
|
|
MarkWaveHeaderPrepared(hWaveIn, lpWaveInHdr);
|
|
|
|
return wRet;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveInUnprepareHeader | This function cleans up the
|
|
* preparation performed by <f waveInPrepareHeader>. The function must
|
|
* be called after the device
|
|
* driver fills a data buffer and returns it to the application. You
|
|
* must call this function before freeing the data buffer.
|
|
*
|
|
* @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input
|
|
* device.
|
|
*
|
|
* @parm LPWAVEHDR | lpWaveInHdr | Specifies a pointer to a <t WAVEHDR>
|
|
* structure identifying the data buffer to be cleaned up.
|
|
*
|
|
* @parm UINT | wSize | Specifies the size of the <t WAVEHDR> structure.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag WAVERR_STILLPLAYING | <p lpWaveInHdr> is still in the queue.
|
|
* @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveIn> is in use on another
|
|
* thread.
|
|
*
|
|
* @comm This function is the complementary function to <f waveInPrepareHeader>.
|
|
* You must call this function before freeing the data buffer with <f GlobalFree>.
|
|
* After passing a buffer to the device driver with <f waveInAddBuffer>, you
|
|
* must wait until the driver is finished with the buffer before calling
|
|
* <f waveInUnprepareHeader>. Unpreparing a buffer that has not been
|
|
* prepared has no effect, and the function returns zero.
|
|
*
|
|
* @xref waveInPrepareHeader
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveInUnprepareHeader(HWAVEIN hWaveIn, LPWAVEHDR lpWaveInHdr, UINT wSize)
|
|
{
|
|
MMRESULT wRet;
|
|
|
|
V_HEADER(lpWaveInHdr, wSize, TYPE_WAVEIN, MMSYSERR_INVALPARAM);
|
|
|
|
if (lpWaveInHdr->dwFlags & WHDR_INQUEUE)
|
|
{
|
|
DebugErr(DBF_WARNING, "waveInUnprepareHeader: buffer still in queue.");
|
|
return WAVERR_STILLPLAYING;
|
|
}
|
|
|
|
if (!IsWaveHeaderPrepared(hWaveIn, lpWaveInHdr))
|
|
{
|
|
DebugErr(DBF_WARNING,"waveInUnprepareHeader: header is not prepared.");
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
|
|
|
|
wRet = waveMessage((HWAVE)hWaveIn, WIDM_UNPREPARE, (DWORD_PTR)lpWaveInHdr, (DWORD)wSize);
|
|
|
|
if (wRet == MMSYSERR_NOTSUPPORTED)
|
|
wRet = waveUnprepareHeader(lpWaveInHdr, wSize);
|
|
|
|
if ((wRet == MMSYSERR_NODRIVER) && (IsHandleDeserted(hWaveIn)))
|
|
{
|
|
wRet = MMSYSERR_NOERROR;
|
|
}
|
|
|
|
if (wRet == MMSYSERR_NOERROR)
|
|
MarkWaveHeaderUnprepared(hWaveIn, lpWaveInHdr);
|
|
|
|
return wRet;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveInAddBuffer | This function sends an input buffer to a
|
|
* waveform input device. When the buffer is filled, it is sent back
|
|
* to the application.
|
|
*
|
|
* @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input device.
|
|
*
|
|
* @parm LPWAVEHDR | lpWaveInHdr | Specifies a far pointer to a <t WAVEHDR>
|
|
* structure that identifies the buffer.
|
|
*
|
|
* @parm UINT | wSize | Specifies the size of the <t WAVEHDR> structure.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag WAVERR_UNPREPARED | <p lpWaveInHdr> hasn't been prepared.
|
|
* @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveIn> is in use on another
|
|
* thread.
|
|
*
|
|
* @comm The data buffer must be prepared with <f waveInPrepareHeader> before
|
|
* it is passed to <f waveInAddBuffer>. The <t WAVEHDR> data structure
|
|
* and the data buffer pointed to by its <e WAVEHDR.lpData> field must be allocated
|
|
* with <f GlobalAlloc> using the GMEM_MOVEABLE and GMEM_SHARE flags, and
|
|
* locked with <f GlobalLock>.
|
|
*
|
|
* @xref waveInPrepareHeader
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveInAddBuffer(HWAVEIN hWaveIn, LPWAVEHDR lpWaveInHdr,
|
|
UINT wSize)
|
|
{
|
|
V_HEADER(lpWaveInHdr, wSize, TYPE_WAVEIN, MMSYSERR_INVALPARAM);
|
|
|
|
if (!IsWaveHeaderPrepared(hWaveIn, lpWaveInHdr))
|
|
{
|
|
DebugErr(DBF_WARNING, "waveInAddBuffer: buffer not prepared.");
|
|
return WAVERR_UNPREPARED;
|
|
}
|
|
|
|
if (lpWaveInHdr->dwFlags & WHDR_INQUEUE)
|
|
{
|
|
DebugErr(DBF_WARNING, "waveInAddBuffer: buffer already in queue.");
|
|
return WAVERR_STILLPLAYING;
|
|
}
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
|
|
|
|
return waveMessage((HWAVE)hWaveIn, WIDM_ADDBUFFER, (DWORD_PTR)lpWaveInHdr, (DWORD)wSize);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveInStart | This function starts input on the specified
|
|
* waveform input device.
|
|
*
|
|
* @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input device.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveIn> is in use on another
|
|
* thread.
|
|
*
|
|
* @comm Buffers are returned to the client when full or when <f waveInReset>
|
|
* is called (the <e WAVEHDR.dwBytesRecorded> field in the header will contain the
|
|
* actual length of data). If there are no buffers in the queue, the data is
|
|
* thrown away without notification to the client, and input continues.
|
|
*
|
|
* Calling this function when input is already started has no effect, and
|
|
* the function returns zero.
|
|
*
|
|
* @xref waveInStop waveInReset
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveInStart(HWAVEIN hWaveIn)
|
|
{
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
|
|
|
|
return waveMessage((HWAVE)hWaveIn, WIDM_START, 0L, 0L);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveInStop | This function stops waveform input.
|
|
*
|
|
* @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input
|
|
* device.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveIn> is in use on another
|
|
* thread.
|
|
*
|
|
* @comm If there are any buffers in the queue, the current buffer will be
|
|
* marked as done (the <e WAVEHDR.dwBytesRecorded> field in the header will contain
|
|
* the actual length of data), but any empty buffers in the queue will remain
|
|
* there. Calling this function when input is not started has no effect,
|
|
* and the function returns zero.
|
|
*
|
|
* @xref waveInStart waveInReset
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveInStop(HWAVEIN hWaveIn)
|
|
{
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
|
|
|
|
return waveMessage((HWAVE)hWaveIn, WIDM_STOP, 0L, 0L);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveInReset | This function stops input on a given waveform
|
|
* input device and resets the current position to 0. All pending
|
|
* buffers are marked as done and returned to the application.
|
|
*
|
|
* @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input device.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
* @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveIn> is in use on another
|
|
* thread.
|
|
*
|
|
* @xref waveInStart waveInStop waveInAddBuffer waveInClose
|
|
/****************************************************************************/
|
|
MMRESULT APIENTRY waveInReset(HWAVEIN hWaveIn)
|
|
{
|
|
MMRESULT mmr;
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
|
|
|
|
mmr = waveMessage((HWAVE)hWaveIn, WIDM_RESET, 0L, 0L);
|
|
|
|
if ((MMSYSERR_NODRIVER == mmr) && (IsHandleDeserted(hWaveIn)))
|
|
{
|
|
mmr = MMSYSERR_NOERROR;
|
|
}
|
|
|
|
return (mmr);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveInGetPosition | This function retrieves the current input
|
|
* position of the specified waveform input device.
|
|
*
|
|
* @parm HWAVEIN | hWaveIn | Specifies a handle to the waveform input device.
|
|
*
|
|
* @parm LPMMTIME | lpInfo | Specifies a far pointer to an <t MMTIME>
|
|
* structure.
|
|
*
|
|
* @parm UINT | wSize | Specifies the size of the <t MMTIME> structure.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | Specified device handle is invalid.
|
|
*
|
|
* @comm Before calling <f waveInGetPosition>, set the <e MMTIME.wType> field of the
|
|
* <t MMTIME> structure to indicate the time format that you desire. After
|
|
* calling <f waveInGetPosition>, be sure to check the <e MMTIME.wType> field to
|
|
* determine if the desired time format is supported. If the desired
|
|
* format is not supported, <e MMTIME.wType> will specify an alternative format.
|
|
*
|
|
* The position is set to zero when the device is opened or reset.
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveInGetPosition(HWAVEIN hWaveIn, LPMMTIME lpInfo,
|
|
UINT wSize)
|
|
{
|
|
V_WPOINTER(lpInfo, wSize, MMSYSERR_INVALPARAM);
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
|
|
|
|
return waveMessage((HWAVE)hWaveIn, WIDM_GETPOS, (DWORD_PTR)lpInfo, (DWORD)wSize);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// MMRESULT waveInDesertHandle
|
|
//
|
|
// Description:
|
|
// Cleans up the wave in handle and marks it as deserted.
|
|
//
|
|
// Arguments:
|
|
// HWAVEIN hWaveIn: Wave in handle
|
|
//
|
|
// Return (MMRESULT): Error code.
|
|
//
|
|
// History:
|
|
// 01/25/99 Fwong Adding Pnp Support.
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
MMRESULT waveInDesertHandle
|
|
(
|
|
HWAVEIN hWaveIn
|
|
)
|
|
{
|
|
MMRESULT mmr;
|
|
PWAVEDEV pDev = (PWAVEDEV)hWaveIn;
|
|
|
|
V_HANDLE_ACQ(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
|
|
|
|
ENTER_MM_HANDLE((HWAVE)hWaveIn);
|
|
ReleaseHandleListResource();
|
|
|
|
if (IsHandleDeserted(hWaveIn))
|
|
{
|
|
LEAVE_MM_HANDLE((HWAVE)hWaveIn);
|
|
return (MMSYSERR_NOERROR);
|
|
}
|
|
|
|
if (IsHandleBusy(hWaveIn))
|
|
{
|
|
// Not quite invalid, but marked as closed.
|
|
|
|
LEAVE_MM_HANDLE(hWaveIn);
|
|
return (MMSYSERR_HANDLEBUSY);
|
|
}
|
|
|
|
// Marking handle as deserted
|
|
SetHandleFlag(hWaveIn, MMHANDLE_DESERTED);
|
|
|
|
// Since the handle was invalidated, we have to send the message ourselves...
|
|
|
|
(*(pDev->wavedrv->drvMessage))(pDev->wDevice, WIDM_RESET, pDev->dwDrvUser, 0L, 0L);
|
|
(*(pDev->wavedrv->drvMessage))(pDev->wDevice, WIDM_CLOSE, pDev->dwDrvUser, 0L, 0L);
|
|
|
|
LEAVE_MM_HANDLE((HWAVE)hWaveIn);
|
|
|
|
// ISSUE-2001/01/14-FrankYe Probably don't want to dec usage here,
|
|
// dec on close instead.
|
|
mregDecUsagePtr(pDev->wavedrv);
|
|
|
|
return MMSYSERR_NOERROR;
|
|
} // waveInDesertHandle()
|
|
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveInGetID | This function gets the device ID for a
|
|
* waveform input device.
|
|
*
|
|
* @parm HWAVEIN | hWaveIn | Specifies the handle to the waveform
|
|
* input device.
|
|
* @parm PUINT | lpuDeviceID | Specifies a pointer to the UINT-sized memory
|
|
* location to be filled with the device ID.
|
|
*
|
|
* @rdesc Returns zero if successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | The <p hWaveIn> parameter specifies an
|
|
* invalid handle.
|
|
* @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveIn> is in use on another
|
|
* thread.
|
|
*
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveInGetID(HWAVEIN hWaveIn, PUINT lpuDeviceID)
|
|
{
|
|
V_WPOINTER(lpuDeviceID, sizeof(UINT), MMSYSERR_INVALPARAM);
|
|
V_HANDLE_ACQ(hWaveIn, TYPE_WAVEIN, MMSYSERR_INVALHANDLE);
|
|
|
|
*lpuDeviceID = ((PWAVEDEV)hWaveIn)->uDeviceID;
|
|
|
|
ReleaseHandleListResource();
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* @doc EXTERNAL WAVE
|
|
*
|
|
* @api MMRESULT | waveOutGetID | This function gets the device ID for a
|
|
* waveform output device.
|
|
*
|
|
* @parm HWAVEOUT | hWaveOut | Specifies the handle to the waveform
|
|
* output device.
|
|
* @parm PUINT | lpuDeviceID | Specifies a pointer to the UINT-sized memory
|
|
* location to be filled with the device ID.
|
|
*
|
|
* @rdesc Returns zero if successful. Otherwise, it returns
|
|
* an error number. Possible error returns are:
|
|
* @flag MMSYSERR_INVALHANDLE | The <p hWaveIn> parameter specifies an
|
|
* invalid handle.
|
|
* @flag MMSYSERR_HANDLEBUSY | The handle <p hWaveOut> is in use on another
|
|
* thread.
|
|
****************************************************************************/
|
|
MMRESULT APIENTRY waveOutGetID(HWAVEOUT hWaveOut, PUINT lpuDeviceID)
|
|
{
|
|
V_WPOINTER(lpuDeviceID, sizeof(UINT), MMSYSERR_INVALPARAM);
|
|
V_HANDLE_ACQ(hWaveOut, TYPE_WAVEOUT, MMSYSERR_INVALHANDLE);
|
|
|
|
*lpuDeviceID = ((PWAVEDEV)hWaveOut)->uDeviceID;
|
|
|
|
ReleaseHandleListResource();
|
|
return MMSYSERR_NOERROR;
|
|
}
|