4545 lines
161 KiB
C
4545 lines
161 KiB
C
//==========================================================================;
|
|
//
|
|
// mixer.c
|
|
//
|
|
// Copyright (c) 1992-2001 Microsoft Corporation
|
|
//
|
|
// Description:
|
|
//
|
|
//
|
|
// History:
|
|
// 6/27/93 cjp [curtisp]
|
|
//
|
|
//==========================================================================;
|
|
#define UNICODE
|
|
#include "winmmi.h"
|
|
#include "mixer.h" // This file drags in a ton of stuff to support the mixers
|
|
|
|
|
|
|
|
PMIXERDEV gpMixerDevHeader = NULL; /* A LL of open devices */
|
|
UINT guTotalMixerDevs; // total mixer devices
|
|
|
|
//
|
|
// mixer device driver list--add one to accomodate the MIXER_MAPPER. note
|
|
// that even if we are not compiling with mapper support we need to add
|
|
// one because other code relies on it (for other device mappers).
|
|
//
|
|
MIXERDRV mixerdrvZ;
|
|
|
|
char gszMxdMessage[] = "mxdMessage";
|
|
TCHAR gszMixer[] = TEXT("mixer");
|
|
|
|
#ifdef MIXER_MAPPER
|
|
TCHAR gszMixerMapper[] = TEXT("mixermapper");
|
|
#endif
|
|
|
|
#ifdef MIXER_MAPPER
|
|
#define MMDRVI_MAPPER 0x8000 // install this driver as the mapper
|
|
#endif
|
|
|
|
//#define MMDRVI_MIXER 0x0006
|
|
#define MMDRVI_HDRV 0x4000 // hdrvr is an installable driver
|
|
#define MMDRVI_REMOVE 0x2000 // remove the driver
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// BOOL MixerCallbackFunc
|
|
//
|
|
// Description:
|
|
//
|
|
// NOTE! we document that a mixer must NEVER call this function at
|
|
// interrupt time! we don't want to fix our code or data segments.
|
|
//
|
|
// Arguments:
|
|
// HMIXER hmx:
|
|
//
|
|
// UINT uMsg:
|
|
//
|
|
// DWORD dwInstance:
|
|
//
|
|
// DWORD dwParam1:
|
|
//
|
|
// DWORD dwParam2:
|
|
//
|
|
// Return (BOOL):
|
|
//
|
|
// History:
|
|
// 07/21/93 cjp [curtisp]
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
BOOL CALLBACK MixerCallbackFunc(
|
|
HMIXER hmx,
|
|
UINT uMsg,
|
|
DWORD_PTR dwInstance,
|
|
DWORD_PTR dwParam1,
|
|
DWORD_PTR dwParam2
|
|
)
|
|
{
|
|
PMIXERDEV pmxdev;
|
|
|
|
//
|
|
// step through all open handles and do callbacks to the appropriate
|
|
// clients...
|
|
//
|
|
|
|
//
|
|
// Serialize access to hande list - only necessary for Win32
|
|
//
|
|
MIXMGR_ENTER;
|
|
|
|
for (pmxdev = gpMixerDevHeader; pmxdev; pmxdev = pmxdev->pmxdevNext)
|
|
{
|
|
//
|
|
// same device? (could also use hmx->uDeviceID)
|
|
//
|
|
if (pmxdev->uDeviceID != dwInstance)
|
|
continue;
|
|
|
|
DriverCallback(pmxdev->dwCallback,
|
|
(HIWORD(pmxdev->fdwOpen) | DCB_NOSWITCH),
|
|
|
|
GetWOWHandle((HANDLE)pmxdev)
|
|
? (HANDLE)(UINT_PTR)GetWOWHandle((HANDLE)pmxdev)
|
|
: (HANDLE)pmxdev,
|
|
|
|
uMsg,
|
|
pmxdev->dwInstance,
|
|
dwParam1,
|
|
dwParam2);
|
|
}
|
|
|
|
MIXMGR_LEAVE;
|
|
|
|
return (TRUE);
|
|
} // MixerCallbackFunc()
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// MMRESULT mixerReferenceDriveryById
|
|
//
|
|
// Description:
|
|
// This function maps a logical id to a device driver and physical id.
|
|
//
|
|
// Arguments:
|
|
// IN UINT uId: The logical id to be mapped.
|
|
//
|
|
// OUT PMIXERDRV* OPTIONAL ppmixerdrv: Pointer to the MIXERDRV structure
|
|
// describing describing the driver supporing the id.
|
|
//
|
|
// OUT UINT* OPTIONAL pport: The driverj-relative device number. If the
|
|
// caller supplies this buffer then it must also supply ppmixerdrv.
|
|
//
|
|
// Return (MMRESULT):
|
|
// The return value is zero if successful, MMSYSERR_BADDEVICEID if the id
|
|
// is out of range.
|
|
//
|
|
// Comments:
|
|
// If the caller specifies ppmixerdrv then this function increments the
|
|
// mixerdrv's usage before returning. The caller must ensure the usage
|
|
// is eventually decremented.
|
|
//
|
|
// History:
|
|
// 03/17/93 cjp [curtisp]
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
MMRESULT mixerReferenceDriverById(
|
|
IN UINT id,
|
|
OUT PMIXERDRV *ppdrv OPTIONAL,
|
|
OUT UINT *pport OPTIONAL
|
|
)
|
|
{
|
|
PMIXERDRV pdrv;
|
|
MMRESULT mmr;
|
|
|
|
// Should not be called asking for port but not mixerdrv
|
|
WinAssert(!(pport && !ppdrv));
|
|
|
|
EnterNumDevs("mixerReferenceDriverById");
|
|
|
|
#ifdef MIXER_MAPPER
|
|
if (MIXER_MAPPER == id)
|
|
{
|
|
id = 0;
|
|
for (pdrv = mixerdrvZ.Next; pdrv != &mixerdrvZ; pdrv = pdrv->Next)
|
|
{
|
|
if (pdrv->fdwDriver & MMDRV_MAPPER) break;
|
|
}
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
for (pdrv = mixerdrvZ.Next; pdrv != &mixerdrvZ; pdrv = pdrv->Next)
|
|
{
|
|
if (pdrv->fdwDriver & MMDRV_MAPPER) continue;
|
|
if (pdrv->NumDevs > id) break;
|
|
id -= pdrv->NumDevs;
|
|
}
|
|
}
|
|
|
|
if (pdrv != &mixerdrvZ)
|
|
{
|
|
if (ppdrv)
|
|
{
|
|
mregIncUsagePtr(pdrv);
|
|
*ppdrv = pdrv;
|
|
if (pport) *pport = id;
|
|
}
|
|
mmr = MMSYSERR_NOERROR;
|
|
} else {
|
|
mmr = MMSYSERR_BADDEVICEID;
|
|
}
|
|
|
|
LeaveNumDevs("mixerReferenceDriverById");
|
|
|
|
return mmr;
|
|
;
|
|
} // IMixerMapId()
|
|
|
|
|
|
PCWSTR mixerReferenceDevInterfaceById(UINT_PTR id)
|
|
{
|
|
PMIXERDRV pdrv;
|
|
PCWSTR DevInterface;
|
|
|
|
if (ValidateHandle((HANDLE)id, TYPE_MIXER))
|
|
{
|
|
DevInterface = ((PMIXERDEV)id)->pmxdrv->cookie;
|
|
if (DevInterface) wdmDevInterfaceInc(DevInterface);
|
|
return DevInterface;
|
|
}
|
|
|
|
if (!mixerReferenceDriverById((UINT)id, &pdrv, NULL))
|
|
{
|
|
DevInterface = pdrv->cookie;
|
|
if (DevInterface) wdmDevInterfaceInc(DevInterface);
|
|
mregDecUsagePtr(pdrv);
|
|
return DevInterface;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// DWORD IMixerMessageHandle
|
|
//
|
|
// Description:
|
|
//
|
|
//
|
|
// Arguments:
|
|
// HMIXER hmx:
|
|
//
|
|
// UINT uMsg:
|
|
//
|
|
// DWORD dwP1:
|
|
//
|
|
// DWORD dwP2:
|
|
//
|
|
// Return (DWORD):
|
|
//
|
|
// History:
|
|
// 03/17/93 cjp [curtisp]
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
DWORD NEAR PASCAL IMixerMessageHandle(
|
|
HMIXER hmx,
|
|
UINT uMsg,
|
|
DWORD_PTR dwP1,
|
|
DWORD_PTR dwP2
|
|
)
|
|
{
|
|
PMIXERDEV pmxd;
|
|
DWORD dwRc;
|
|
|
|
pmxd = (PMIXERDEV)hmx;
|
|
|
|
ENTER_MM_HANDLE(hmx);
|
|
ReleaseHandleListResource();
|
|
|
|
// Is handle deserted?
|
|
if (IsHandleDeserted(hmx))
|
|
{
|
|
LEAVE_MM_HANDLE(hmx);
|
|
return (MMSYSERR_NODRIVER);
|
|
}
|
|
|
|
if (IsHandleBusy(hmx))
|
|
{
|
|
LEAVE_MM_HANDLE(hmx);
|
|
return (MMSYSERR_HANDLEBUSY);
|
|
}
|
|
|
|
EnterCriticalSection(&pmxd->pmxdrv->MixerCritSec);
|
|
|
|
if (BAD_HANDLE(hmx, TYPE_MIXER))
|
|
{
|
|
// Do we still need to check for this?
|
|
|
|
WinAssert(!"Bad Handle within IMixerMessageHandle");
|
|
dwRc = MMSYSERR_INVALHANDLE;
|
|
}
|
|
else
|
|
{
|
|
dwRc = ((*(pmxd->pmxdrv->drvMessage))
|
|
(pmxd->wDevice, uMsg, pmxd->dwDrvUser, dwP1, dwP2));
|
|
}
|
|
|
|
LeaveCriticalSection(&pmxd->pmxdrv->MixerCritSec);
|
|
LEAVE_MM_HANDLE(hmx);
|
|
|
|
return dwRc;
|
|
} // IMixerMessageHandle()
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// DWORD IMixerMessageId
|
|
//
|
|
// Description:
|
|
//
|
|
//
|
|
// Arguments:
|
|
// PMIXERDRV pmxdrv:
|
|
//
|
|
// UINT uTotalNumDevs:
|
|
//
|
|
// UINT uDeviceID:
|
|
//
|
|
// UINT uMsg:
|
|
//
|
|
// DWORD dwParam1:
|
|
//
|
|
// DWORD dwParam2:
|
|
//
|
|
// Return (DWORD):
|
|
//
|
|
// History:
|
|
// 03/17/93 cjp [curtisp]
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
extern void lstrncpyW (LPWSTR pszTarget, LPCWSTR pszSource, size_t cch);
|
|
|
|
DWORD NEAR PASCAL IMixerMessageId(
|
|
UINT uDeviceID,
|
|
UINT uMsg,
|
|
DWORD_PTR dwParam1,
|
|
DWORD_PTR dwParam2
|
|
)
|
|
{
|
|
PMIXERDRV pmxdrv;
|
|
UINT port;
|
|
DWORD dwRc;
|
|
HMIXER hmx;
|
|
PMIXERDEV pmxdev;
|
|
MMRESULT mmr;
|
|
|
|
mmr = mixerReferenceDriverById(uDeviceID, &pmxdrv, &port);
|
|
|
|
if (mmr)
|
|
{
|
|
return mmr;
|
|
}
|
|
|
|
if (mregHandleInternalMessages(pmxdrv, TYPE_MIXER, port, uMsg, dwParam1, dwParam2, &mmr))
|
|
{
|
|
mregDecUsagePtr(pmxdrv);
|
|
return mmr;
|
|
}
|
|
|
|
dwRc = mixerOpen(&hmx, uDeviceID, 0L, 0L, MIXER_OBJECTF_MIXER);
|
|
|
|
// Should we go through IMixerMessageHandle???
|
|
if (MMSYSERR_NOERROR == dwRc)
|
|
{
|
|
pmxdev = (PMIXERDEV)hmx;
|
|
pmxdrv = pmxdev->pmxdrv;
|
|
|
|
if (!pmxdrv->drvMessage)
|
|
{
|
|
dwRc = MMSYSERR_NODRIVER;
|
|
}
|
|
else
|
|
{
|
|
EnterCriticalSection( &pmxdrv->MixerCritSec);
|
|
|
|
dwRc = ((*(pmxdrv->drvMessage))
|
|
(port, uMsg, pmxdev->dwDrvUser, dwParam1, dwParam2));
|
|
|
|
LeaveCriticalSection( &pmxdrv->MixerCritSec);
|
|
}
|
|
|
|
mixerClose(hmx);
|
|
}
|
|
|
|
mregDecUsagePtr(pmxdrv);
|
|
|
|
return dwRc;
|
|
|
|
} // IMixerMessageId()
|
|
|
|
|
|
//==========================================================================;
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//==========================================================================;
|
|
|
|
/*--------------------------------------------------------------------------;
|
|
*
|
|
* @doc EXTERNAL MIXER SDK API
|
|
*
|
|
* @api UINT | mixerGetNumDevs | The <f mixerGetNumDevs> function retrieves
|
|
* the number of audio mixer devices present in the system.
|
|
*
|
|
* @rdesc Returns the number of audio mixer devices present in the system.
|
|
* If no audio mixer devices are available, zero is returned.
|
|
*
|
|
* @xref <f mixerGetDevCaps>, <f mixerOpen>
|
|
*
|
|
**/
|
|
|
|
UINT APIENTRY mixerGetNumDevs(
|
|
void
|
|
)
|
|
{
|
|
UINT cDevs;
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
EnterNumDevs("mixerGetNumDevs");
|
|
cDevs = guTotalMixerDevs;
|
|
LeaveNumDevs("mixerGetNumDevs");
|
|
|
|
return cDevs;
|
|
} // mixerGetNumDevs()
|
|
|
|
|
|
/*--------------------------------------------------------------------------;
|
|
*
|
|
* @doc EXTERNAL MIXER SDK STRUCTURE
|
|
*
|
|
* @types MIXERCAPS | The <t MIXERCAPS> structure describes the capabilities
|
|
* of a mixer device.
|
|
*
|
|
* @field WORD | wMid | Specifies a manufacturer identifier for the mixer
|
|
* device driver. Manufacturer identifiers are defined in Appendix B,
|
|
* <lq>Manufacturer ID and Product ID Lists.<rq>
|
|
*
|
|
* @field WORD | wPid | Specifies a product identifier for the mixer device
|
|
* driver. Product identifiers are defined in Appendix B,
|
|
* <lq>Manufacturer ID and Product ID Lists.<rq>
|
|
*
|
|
* @field MMVERSION | vDriverVersion | Specifies the version number of the
|
|
* mixer device driver. The high-order byte is the major version
|
|
* number, and the low-order byte is the minor version number.
|
|
*
|
|
* @field char | szPname[MAXPNAMELEN] | Specifies the name of the product.
|
|
* If the mixer device driver supports multiple cards, this string must
|
|
* uniquely and easily identify (potentially to a user) this specific
|
|
* card. For example, szPname = <lq>Sound Card Mixer, I/O address 200<rq>
|
|
* would uniquely identify (to the user) this particular card as a
|
|
* Sound Card Mixer for the physical card based at I/O address 200. If
|
|
* only one device is installed, it is recommended that only the base
|
|
* name be returned. For example, szPname should be <lq>Sound Card Mixer<rq>
|
|
* if only one device is present.
|
|
*
|
|
* @field DWORD | fdwSupport | Specifies various support information for
|
|
* the mixer device driver. No extended support bits are currently
|
|
* defined.
|
|
*
|
|
* @field DWORD | cDestinations | The number of audio mixer line destinations
|
|
* available through the mixer. All mixer devices must support at least
|
|
* one destination line, so this member can never be zero. Destination
|
|
* indexes used in the <e MIXERLINE.dwDestination> member of the
|
|
* <t MIXERLINE> structure range from zero to the value specified in the
|
|
* <e MIXERCAPS.cDestinations> member minus one.
|
|
*
|
|
* @tagname tMIXERCAPS
|
|
*
|
|
* @othertype MIXERCAPS FAR * | LPMIXERCAPS | A pointer to a <t MIXERCAPS>
|
|
* structure.
|
|
*
|
|
* @othertype MIXERCAPS * | PMIXERCAPS | A pointer to a <t MIXERCAPS>
|
|
* structure.
|
|
*
|
|
* @xref <f mixerGetDevCaps>, <f mixerOpen>, <f mixerGetLineInfo>
|
|
*
|
|
**/
|
|
|
|
/*--------------------------------------------------------------------------;
|
|
*
|
|
* @doc EXTERNAL MIXER SDK API
|
|
*
|
|
* @api MMRESULT | mixerGetDevCaps | The <f mixerGetDevCaps> function
|
|
* queries a specified audio mixer device to determine its capabilities.
|
|
*
|
|
* @parm UINT | uMxId | Identifies the audio mixer device with either
|
|
* an audio mixer device identifier or a handle to an opened audio mixer
|
|
* device.
|
|
*
|
|
* @parm LPMIXERCAPS | pmxcaps | Pointer to a <t MIXERCAPS> structure that
|
|
* receives information about the capabilities of the device.
|
|
*
|
|
* @parm UINT | cbmxcaps | Specifies the size, in bytes, of the <t MIXERCAPS>
|
|
* structure.
|
|
*
|
|
* @rdesc The return value is zero if the function is successful. Otherwise,
|
|
* it returns a non-zero error number. Possible error returns include
|
|
* the following:
|
|
*
|
|
* @flag <c MMSYSERR_BADDEVICEID> | The specified device identifier is
|
|
* out of range.
|
|
*
|
|
* @flag <c MMSYSERR_INVALHANDLE> | The audio mixer device handle passed
|
|
* is invalid.
|
|
*
|
|
* @flag <c MMSYSERR_INVALPARAM> | One or more arguments passed is
|
|
* invalid.
|
|
*
|
|
* @comm Use the <f mixerGetNumDevs> function to determine the number of
|
|
* audio mixer devices present in the system. The device identifier
|
|
* specified by <p uMxId> varies from zero to one less than the number
|
|
* of mixer devices present.
|
|
*
|
|
* Only <p cbmxcaps> bytes (or less) of information is copied to the
|
|
* location pointed to by <p pmxcaps>. If <p cbmxcaps> is zero, nothing
|
|
* is copied, and the function returns success.
|
|
*
|
|
* This function also accepts an audio mixer device handle returned by
|
|
* the <f mixerOpen> function as the <p uMxId> argument. The calling
|
|
* application should cast the <c HMIXER> handle to a UINT.
|
|
*
|
|
* @xref <f mixerGetNumDevs>, <t MIXERCAPS>, <f mixerOpen>
|
|
*
|
|
**/
|
|
|
|
MMRESULT APIENTRY mixerGetDevCapsA(
|
|
UINT_PTR uMxId,
|
|
LPMIXERCAPSA pmxcapsA,
|
|
UINT cbmxcaps
|
|
)
|
|
{
|
|
MIXERCAPS2W mxcaps2W;
|
|
MIXERCAPS2A mxcaps2A;
|
|
MMRESULT mmr;
|
|
|
|
if (0 == cbmxcaps)
|
|
return (MMSYSERR_NOERROR);
|
|
|
|
V_WPOINTER(pmxcapsA, cbmxcaps, MMSYSERR_INVALPARAM);
|
|
|
|
memset(&mxcaps2W, 0, sizeof(mxcaps2W));
|
|
|
|
mmr = mixerGetDevCaps(uMxId, (LPMIXERCAPSW)&mxcaps2W, sizeof(mxcaps2W));
|
|
|
|
if (mmr != MMSYSERR_NOERROR) {
|
|
return mmr;
|
|
}
|
|
|
|
//
|
|
// Copy the structure back as cleanly as possible. This would
|
|
// Be a little easier if all the strings were at the end of structures.
|
|
// Things would be a LOT more sensible if they could ONLY ask for the
|
|
// whole structure (then we could copy the result direct to the
|
|
// caller's memory).
|
|
//
|
|
// Because of all this it's easiest to get the whole UNICODE structure,
|
|
// massage it into an ASCII stucture then (for the 0.001% of such apps)
|
|
// copy back the part they actually asked for. The definition of the
|
|
// API means that, far from these apps going faster, everyone goes slow.
|
|
//
|
|
|
|
Iwcstombs(mxcaps2A.szPname, mxcaps2W.szPname, MAXPNAMELEN);
|
|
mxcaps2A.wMid = mxcaps2W.wMid;
|
|
mxcaps2A.wPid = mxcaps2W.wPid;
|
|
mxcaps2A.vDriverVersion = mxcaps2W.vDriverVersion;
|
|
mxcaps2A.fdwSupport = mxcaps2W.fdwSupport;
|
|
mxcaps2A.cDestinations = mxcaps2W.cDestinations;
|
|
mxcaps2A.ManufacturerGuid = mxcaps2W.ManufacturerGuid;
|
|
mxcaps2A.ProductGuid = mxcaps2W.ProductGuid;
|
|
mxcaps2A.NameGuid = mxcaps2W.NameGuid;
|
|
|
|
CopyMemory((PVOID)pmxcapsA, &mxcaps2A, min(sizeof(mxcaps2A), cbmxcaps));
|
|
|
|
return mmr;
|
|
|
|
} // mixerGetDevCapsA()
|
|
|
|
MMRESULT APIENTRY mixerGetDevCaps(
|
|
UINT_PTR uMxId,
|
|
LPMIXERCAPS pmxcaps,
|
|
UINT cbmxcaps
|
|
)
|
|
{
|
|
DWORD_PTR dwParam1, dwParam2;
|
|
MDEVICECAPSEX mdCaps;
|
|
PCWSTR DevInterface;
|
|
MMRESULT mmr;
|
|
|
|
if (0 == cbmxcaps)
|
|
return (MMSYSERR_NOERROR);
|
|
|
|
V_WPOINTER(pmxcaps, cbmxcaps, MMSYSERR_INVALPARAM);
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
DevInterface = mixerReferenceDevInterfaceById(uMxId);
|
|
dwParam2 = (DWORD_PTR)DevInterface;
|
|
|
|
if (0 == dwParam2)
|
|
{
|
|
dwParam1 = (DWORD_PTR)pmxcaps;
|
|
dwParam2 = (DWORD)cbmxcaps;
|
|
}
|
|
else
|
|
{
|
|
mdCaps.cbSize = (DWORD)cbmxcaps;
|
|
mdCaps.pCaps = pmxcaps;
|
|
dwParam1 = (DWORD_PTR)&mdCaps;
|
|
}
|
|
|
|
AcquireHandleListResourceShared();
|
|
|
|
if ((uMxId >= guTotalMixerDevs) && !BAD_HANDLE((HMIXER)uMxId, TYPE_MIXER))
|
|
{
|
|
mmr = (MMRESULT)IMixerMessageHandle((HMIXER)uMxId,
|
|
MXDM_GETDEVCAPS,
|
|
dwParam1,
|
|
dwParam2);
|
|
}
|
|
else
|
|
{
|
|
ReleaseHandleListResource();
|
|
mmr = (MMRESULT)IMixerMessageId((UINT)uMxId,
|
|
MXDM_GETDEVCAPS,
|
|
(DWORD_PTR)dwParam1,
|
|
(DWORD_PTR)dwParam2);
|
|
}
|
|
|
|
if (DevInterface) wdmDevInterfaceDec(DevInterface);
|
|
|
|
return (mmr);
|
|
|
|
} // mixerGetDevCaps()
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------;
|
|
*
|
|
* @doc EXTERNAL MIXER SDK API
|
|
*
|
|
* @api MMRESULT | mixerGetID | The <f mixerGetID> function gets the device
|
|
* identifier for an audio mixer device that corresponds to audio mixer
|
|
* object handle <p hmxobj>.
|
|
*
|
|
* @parm <c HMIXEROBJ> | hmxobj | Identifies the audio mixer object handle
|
|
* to map to an audio mixer device identifier.
|
|
*
|
|
* @parm UINT FAR * | puMxId | Points to a UINT-sized variable that will
|
|
* receive the audio mixer device identifier. If no mixer device is
|
|
* available for the <p hmxobj> object, then '-1' is placed in this
|
|
* location (an error code of <c MMSYSERR_NODRIVER> is also returned).
|
|
*
|
|
* @parm DWORD | fdwId | Specifies flags for how to map the audio mixer
|
|
* object <p hmxobj>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_MIXER> | Specifies that <p hmxobj> is an audio
|
|
* mixer device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f mixerGetNumDevs>. This flag is
|
|
* optional.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HMIXER> | Specifies that <p hmxobj> is a mixer
|
|
* device handle returned by <f mixerOpen>. This flag is optional.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_WAVEOUT> | Specifies that <p hmxobj> is a
|
|
* waveform output device identifier in the range of zero to one less
|
|
* than the number of devices returned by <f waveOutGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HWAVEOUT> | Specifies that <p hmxobj> is a
|
|
* waveform output handle returned by <f waveOutOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_WAVEIN> | Specifies that <p hmxobj> is a
|
|
* waveform input device identifier in the range of zero to one less
|
|
* than the number of devices returned by <f waveInGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HWAVEIN> | Specifies that <p hmxobj> is a
|
|
* waveform input handle returned by <f midiInOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_MIDIOUT> | Specifies that <p hmxobj> is a MIDI
|
|
* output device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f midiOutGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HMIDIOUT> | Specifies that <p hmxobj> is a
|
|
* MIDI output handle returned by <f midiOutOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_MIDIIN> | Specifies that <p hmxobj> is a MIDI
|
|
* input device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f midiInGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HMIDIIN> | Specifies that <p hmxobj> is a MIDI
|
|
* input handle returned by <f midiInOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_AUX> | Specifies that <p hmxobj> is an
|
|
* auxiliary device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f auxGetNumDevs>.
|
|
*
|
|
* @rdesc The return value is zero if the function is successful. Otherwise,
|
|
* it returns a non-zero error number. Possible error returns include
|
|
* the following:
|
|
*
|
|
* @flag <c MMSYSERR_BADDEVICEID> | The <p hmxobj> argument specifies an
|
|
* invalid device identifier.
|
|
*
|
|
* @flag <c MMSYSERR_INVALHANDLE> | The <p hmxobj> argument specifies an
|
|
* invalid handle.
|
|
*
|
|
* @flag <c MMSYSERR_INVALFLAG> | One or more flags are invalid.
|
|
*
|
|
* @flag <c MMSYSERR_INVALPARAM> | One or more arguments passed is
|
|
* invalid.
|
|
*
|
|
* @flag <c MMSYSERR_NODRIVER> | No audio mixer device is available for
|
|
* the object specified by <p hmxobj>. Note that the location referenced
|
|
* by <p puMxId> will also contain the value '-1'.
|
|
*
|
|
* @comm Use the <f mixerGetID> function to determine what audio mixer
|
|
* device (if any) is responsible for performing mixing functions on a
|
|
* media device. For example, an application can use <f mixerGetID> to
|
|
* get the mixer device identifier responsible for setting the volume
|
|
* on a waveform output handle. Or the application may want to display
|
|
* a peak meter for waveform input device.
|
|
*
|
|
* @xref <f mixerGetNumDevs>, <f mixerGetDevCaps>, <f mixerOpen>
|
|
*
|
|
**/
|
|
MMRESULT APIENTRY mixerGetID(
|
|
HMIXEROBJ hmxobj,
|
|
UINT FAR *puMxId,
|
|
DWORD fdwId
|
|
)
|
|
{
|
|
ClientUpdatePnpInfo();
|
|
|
|
return IMixerGetID( hmxobj, (PUINT)puMxId, NULL, fdwId );
|
|
} // mixerGetID()
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// MMRESULT IMixerGetID
|
|
//
|
|
// Description:
|
|
//
|
|
//
|
|
// Arguments:
|
|
// HMIXEROBJ hmxobj:
|
|
//
|
|
// UINT FAR *puMxId:
|
|
//
|
|
// DWORD fdwId:
|
|
//
|
|
// Return (MMRESULT):
|
|
//
|
|
// History:
|
|
// 06/27/93 cjp [curtisp]
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
MMRESULT IMixerGetID(
|
|
HMIXEROBJ hmxobj,
|
|
PUINT puMxId,
|
|
LPMIXERLINE pmxl,
|
|
DWORD fdwId
|
|
)
|
|
{
|
|
MMRESULT mmr;
|
|
MIXERLINE mxl;
|
|
UINT u;
|
|
|
|
V_DFLAGS(fdwId, MIXER_GETIDF_VALID, IMixerGetID, MMSYSERR_INVALFLAG);
|
|
V_WPOINTER(puMxId, sizeof(UINT), MMSYSERR_INVALPARAM);
|
|
|
|
|
|
//
|
|
// set to '-1' which would be the mixer mapper (if there was one)
|
|
// this way we will definitely fail any calls made on this id if
|
|
// this function fails and the caller doesn't check his return value.
|
|
//
|
|
*puMxId = (UINT)-1;
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
switch (MIXER_OBJECTF_TYPEMASK & fdwId)
|
|
{
|
|
case MIXER_OBJECTF_MIXER:
|
|
case MIXER_OBJECTF_HMIXER:
|
|
{
|
|
mmr = (fdwId & MIXER_OBJECTF_HANDLE) ? MMSYSERR_INVALHANDLE : MMSYSERR_BADDEVICEID;
|
|
|
|
if ((UINT_PTR)hmxobj >= guTotalMixerDevs)
|
|
{
|
|
V_HANDLE_ACQ(hmxobj, TYPE_MIXER, mmr);
|
|
*puMxId = ((PMIXERDEV)hmxobj)->uDeviceID;
|
|
ReleaseHandleListResource();
|
|
} else {
|
|
*puMxId = PtrToUint(hmxobj);
|
|
}
|
|
return (MMSYSERR_NOERROR);
|
|
}
|
|
|
|
case MIXER_OBJECTF_HWAVEOUT:
|
|
{
|
|
UINT uId;
|
|
DWORD dwId;
|
|
|
|
mmr = waveOutGetID((HWAVEOUT)hmxobj, &uId);
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
{
|
|
return (MMSYSERR_INVALHANDLE);
|
|
}
|
|
|
|
if (WAVE_MAPPER == uId)
|
|
{
|
|
mmr = (MMRESULT)waveOutMessage((HWAVEOUT)hmxobj,
|
|
WODM_MAPPER_STATUS,
|
|
WAVEOUT_MAPPER_STATUS_DEVICE,
|
|
(DWORD_PTR)(LPVOID)&dwId);
|
|
|
|
if (MMSYSERR_NOERROR == mmr)
|
|
{
|
|
uId = (UINT)dwId;
|
|
}
|
|
}
|
|
|
|
hmxobj = (HMIXEROBJ)(UINT_PTR)uId;
|
|
}
|
|
|
|
case MIXER_OBJECTF_WAVEOUT:
|
|
{
|
|
WAVEOUTCAPS woc;
|
|
|
|
mmr = waveOutGetDevCaps((UINT_PTR)hmxobj, &woc, sizeof(woc));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (MMSYSERR_BADDEVICEID);
|
|
|
|
woc.szPname[SIZEOF(woc.szPname) - 1] = '\0';
|
|
|
|
mxl.Target.dwType = MIXERLINE_TARGETTYPE_WAVEOUT;
|
|
mxl.Target.dwDeviceID = PtrToUlong(hmxobj);
|
|
mxl.Target.wMid = woc.wMid;
|
|
mxl.Target.wPid = woc.wPid;
|
|
mxl.Target.vDriverVersion = woc.vDriverVersion;
|
|
lstrcpy(mxl.Target.szPname, woc.szPname);
|
|
break;
|
|
}
|
|
|
|
|
|
case MIXER_OBJECTF_HWAVEIN:
|
|
{
|
|
UINT uId;
|
|
DWORD dwId;
|
|
|
|
mmr = waveInGetID((HWAVEIN)hmxobj, &uId);
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
{
|
|
return (MMSYSERR_INVALHANDLE);
|
|
}
|
|
|
|
if (WAVE_MAPPER == uId)
|
|
{
|
|
mmr = (MMRESULT)waveInMessage((HWAVEIN)hmxobj,
|
|
WIDM_MAPPER_STATUS,
|
|
WAVEIN_MAPPER_STATUS_DEVICE,
|
|
(DWORD_PTR)(LPVOID)&dwId);
|
|
|
|
if (MMSYSERR_NOERROR == mmr)
|
|
{
|
|
uId = (UINT)dwId;
|
|
}
|
|
}
|
|
|
|
hmxobj = (HMIXEROBJ)(UINT_PTR)uId;
|
|
}
|
|
|
|
case MIXER_OBJECTF_WAVEIN:
|
|
{
|
|
WAVEINCAPS wic;
|
|
|
|
mmr = waveInGetDevCaps((UINT_PTR)hmxobj, &wic, sizeof(wic));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (MMSYSERR_BADDEVICEID);
|
|
|
|
wic.szPname[SIZEOF(wic.szPname) - 1] = '\0';
|
|
|
|
mxl.Target.dwType = MIXERLINE_TARGETTYPE_WAVEIN;
|
|
mxl.Target.dwDeviceID = PtrToUlong(hmxobj);
|
|
mxl.Target.wMid = wic.wMid;
|
|
mxl.Target.wPid = wic.wPid;
|
|
mxl.Target.vDriverVersion = wic.vDriverVersion;
|
|
lstrcpy(mxl.Target.szPname, wic.szPname);
|
|
break;
|
|
}
|
|
|
|
|
|
case MIXER_OBJECTF_HMIDIOUT:
|
|
mmr = midiOutGetID((HMIDIOUT)hmxobj, (UINT FAR *)&hmxobj);
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (MMSYSERR_INVALHANDLE);
|
|
|
|
case MIXER_OBJECTF_MIDIOUT:
|
|
{
|
|
MIDIOUTCAPS moc;
|
|
|
|
mmr = midiOutGetDevCaps((UINT_PTR)hmxobj, &moc, sizeof(moc));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (MMSYSERR_BADDEVICEID);
|
|
|
|
moc.szPname[SIZEOF(moc.szPname) - 1] = '\0';
|
|
|
|
mxl.Target.dwType = MIXERLINE_TARGETTYPE_MIDIOUT;
|
|
mxl.Target.dwDeviceID = PtrToUlong(hmxobj);
|
|
mxl.Target.wMid = moc.wMid;
|
|
mxl.Target.wPid = moc.wPid;
|
|
mxl.Target.vDriverVersion = moc.vDriverVersion;
|
|
lstrcpy(mxl.Target.szPname, moc.szPname);
|
|
break;
|
|
}
|
|
|
|
|
|
case MIXER_OBJECTF_HMIDIIN:
|
|
mmr = midiInGetID((HMIDIIN)hmxobj, (UINT FAR *)&hmxobj);
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (MMSYSERR_INVALHANDLE);
|
|
|
|
case MIXER_OBJECTF_MIDIIN:
|
|
{
|
|
MIDIINCAPS mic;
|
|
|
|
mmr = midiInGetDevCaps((UINT_PTR)hmxobj, &mic, sizeof(mic));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (MMSYSERR_BADDEVICEID);
|
|
|
|
mic.szPname[SIZEOF(mic.szPname) - 1] = '\0';
|
|
|
|
mxl.Target.dwType = MIXERLINE_TARGETTYPE_MIDIIN;
|
|
mxl.Target.dwDeviceID = PtrToUlong(hmxobj);
|
|
mxl.Target.wMid = mic.wMid;
|
|
mxl.Target.wPid = mic.wPid;
|
|
mxl.Target.vDriverVersion = mic.vDriverVersion;
|
|
lstrcpy(mxl.Target.szPname, mic.szPname);
|
|
break;
|
|
}
|
|
|
|
|
|
case MIXER_OBJECTF_AUX:
|
|
{
|
|
AUXCAPS ac;
|
|
|
|
mmr = auxGetDevCaps((UINT_PTR)hmxobj, &ac, sizeof(ac));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (MMSYSERR_BADDEVICEID);
|
|
|
|
ac.szPname[SIZEOF(ac.szPname) - 1] = '\0';
|
|
|
|
mxl.Target.dwType = MIXERLINE_TARGETTYPE_AUX;
|
|
mxl.Target.dwDeviceID = PtrToUlong(hmxobj);
|
|
mxl.Target.wMid = ac.wMid;
|
|
mxl.Target.wPid = ac.wPid;
|
|
mxl.Target.vDriverVersion = ac.vDriverVersion;
|
|
lstrcpy(mxl.Target.szPname, ac.szPname);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
DebugErr1(DBF_ERROR,
|
|
"mixerGetID: unknown mixer object flag (%.08lXh).",
|
|
MIXER_OBJECTF_TYPEMASK & fdwId);
|
|
return (MMSYSERR_INVALFLAG);
|
|
}
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
mxl.cbStruct = sizeof(mxl);
|
|
mxl.dwDestination = (DWORD)-1L;
|
|
mxl.dwSource = (DWORD)-1L;
|
|
mxl.dwLineID = (DWORD)-1L;
|
|
mxl.fdwLine = 0;
|
|
mxl.dwUser = 0;
|
|
mxl.dwComponentType = (DWORD)-1L;
|
|
mxl.cChannels = 0;
|
|
mxl.cConnections = 0;
|
|
mxl.cControls = 0;
|
|
mxl.szShortName[0] = '\0';
|
|
mxl.szName[0] = '\0';
|
|
|
|
|
|
for (u = 0; u < guTotalMixerDevs; u++)
|
|
{
|
|
mmr = (MMRESULT)IMixerMessageId(u,
|
|
MXDM_GETLINEINFO,
|
|
(DWORD_PTR)(LPVOID)&mxl,
|
|
MIXER_GETLINEINFOF_TARGETTYPE);
|
|
|
|
if (MMSYSERR_NOERROR == mmr)
|
|
{
|
|
*puMxId = u;
|
|
|
|
if (NULL != pmxl)
|
|
{
|
|
DWORD cbStruct;
|
|
|
|
cbStruct = pmxl->cbStruct;
|
|
|
|
CopyMemory(pmxl, &mxl, (UINT)cbStruct);
|
|
|
|
pmxl->cbStruct = cbStruct;
|
|
}
|
|
|
|
return (mmr);
|
|
}
|
|
}
|
|
|
|
return (MMSYSERR_NODRIVER);
|
|
} // IMixerGetID()
|
|
|
|
|
|
/*--------------------------------------------------------------------------;
|
|
*
|
|
* @doc EXTERNAL MIXER SDK API
|
|
*
|
|
* @api MMRESULT | mixerOpen | The <f mixerOpen> function opens a specified
|
|
* audio mixer device for use. An application must open a mixer device
|
|
* if it wishes to receive notifications of mixer line and control
|
|
* changes. This function also ensures that the device will not be
|
|
* removed until the application closes the handle.
|
|
*
|
|
* @parm LPHMIXER | phmx | Points to a variable that will receive a handle
|
|
* that identifies the opened audio mixer device. Use this handle to
|
|
* identify the device when calling other audio mixer functions. This
|
|
* argument may not be NULL. If an application wishes to query for
|
|
* audio mixer support on a media device, the <f mixerGetID> function
|
|
* may be used.
|
|
*
|
|
* @parm UINT | uMxId | Identifies the audio mixer device to open. Use a
|
|
* valid device identifier or any <c HMIXEROBJ> (see <f mixerGetID> for
|
|
* a description of mixer object handles). Note that there is currently
|
|
* no 'mapper' for audio mixer devices, so a mixer device identifier of
|
|
* '-1' is not valid.
|
|
*
|
|
* @parm DWORD | dwCallback | Specifies a handle to a window called when the
|
|
* state of an audio mixer line and/or control associated with the
|
|
* device being opened is changed. Specify zero for this argument
|
|
* if no callback mechanism is to be used.
|
|
*
|
|
* @parm DWORD | dwInstance | This parameter is currently not used and
|
|
* should be set to zero.
|
|
*
|
|
* @parm DWORD | fdwOpen | Specifies flags for opening the device.
|
|
*
|
|
* @flag CALLBACK_WINDOW | If this flag is specified, <p dwCallback> is
|
|
* assumed to be a window handle.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_MIXER> | Specifies that <p uMxId> is an audio
|
|
* mixer device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f mixerGetNumDevs>. This flag is
|
|
* optional.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HMIXER> | Specifies that <p uMxId> is a mixer
|
|
* device handle returned by <f mixerOpen>. This flag is optional.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_WAVEOUT> | Specifies that <p uMxId> is a
|
|
* waveform output device identifier in the range of zero to one less
|
|
* than the number of devices returned by <f waveOutGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HWAVEOUT> | Specifies that <p uMxId> is a
|
|
* waveform output handle returned by <f waveOutOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_WAVEIN> | Specifies that <p uMxId> is a
|
|
* waveform input device identifier in the range of zero to one less
|
|
* than the number of devices returned by <f waveInGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HWAVEIN> | Specifies that <p uMxId> is a
|
|
* waveform input handle returned by <f midiInOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_MIDIOUT> | Specifies that <p uMxId> is a MIDI
|
|
* output device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f midiOutGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HMIDIOUT> | Specifies that <p uMxId> is a
|
|
* MIDI output handle returned by <f midiOutOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_MIDIIN> | Specifies that <p uMxId> is a MIDI
|
|
* input device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f midiInGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HMIDIIN> | Specifies that <p uMxId> is a MIDI
|
|
* input handle returned by <f midiInOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_AUX> | Specifies that <p uMxId> is an
|
|
* auxiliary device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f auxGetNumDevs>.
|
|
*
|
|
* @rdesc The return value is zero if the function is successful. Otherwise,
|
|
* it returns a non-zero error number. Possible error returns include
|
|
* the following:
|
|
*
|
|
* @flag <c MMSYSERR_BADDEVICEID> | The <p uMxId> argument specifies an
|
|
* invalid device identifier.
|
|
*
|
|
* @flag <c MMSYSERR_INVALHANDLE> | The <p uMxId> argument specifies an
|
|
* invalid handle.
|
|
*
|
|
* @flag <c MMSYSERR_INVALFLAG> | One or more flags are invalid.
|
|
*
|
|
* @flag <c MMSYSERR_INVALPARAM> | One or more arguments passed is
|
|
* invalid.
|
|
*
|
|
* @flag <c MMSYSERR_NODRIVER> | No audio mixer device is available for
|
|
* the object specified by <p uMxId>. Note that the location referenced
|
|
* by <p uMxId> will also contain the value '-1'.
|
|
*
|
|
* @flag <c MMSYSERR_ALLOCATED> | The specified resource is already
|
|
* allocated by the maximum number of clients possible.
|
|
*
|
|
* @flag <c MMSYSERR_NOMEM> | Unable to allocate resources.
|
|
*
|
|
* @comm Use the <f mixerGetNumDevs> function to determine the number of
|
|
* audio mixer devices present in the system. The device identifier
|
|
* specified by <p uMxId> varies from zero to one less than the number
|
|
* of devices present.
|
|
*
|
|
* If a window is chosen to receive callback information, the following
|
|
* messages are sent to the window procedure function to indicate when
|
|
* a line or control state changes: <m MM_MIXM_LINE_CHANGE>,
|
|
* <m MM_MIXM_CONTROL_CHANGE>. <p wParam> is the handle to the mixer
|
|
* device. <p lParam> is the line identifier for <m MM_MIXM_LINE_CHANGE>
|
|
* or the control identifier for <m MM_MIXM_CONTROL_CHANGE> that
|
|
* changed state.
|
|
*
|
|
* @xref <f mixerClose>, <f mixerGetNumDevs>, <f mixerGetID>,
|
|
* <f mixerGetLineInfo>
|
|
*
|
|
**/
|
|
|
|
MMRESULT APIENTRY mixerOpen(
|
|
LPHMIXER phmx,
|
|
UINT uMxId,
|
|
DWORD_PTR dwCallback,
|
|
DWORD_PTR dwInstance,
|
|
DWORD fdwOpen
|
|
)
|
|
{
|
|
MMRESULT mmr;
|
|
PMIXERDRV pmxdrv;
|
|
UINT port;
|
|
PMIXERDEV pmxdev;
|
|
PMIXERDEV pmxdevRunList;
|
|
MIXEROPENDESC mxod;
|
|
DWORD_PTR dwDrvUser;
|
|
|
|
//
|
|
//
|
|
//
|
|
V_WPOINTER(phmx, sizeof(HMIXER), MMSYSERR_INVALPARAM);
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
*phmx = NULL;
|
|
|
|
//
|
|
// Don't allow callback functions - they're not useful and they
|
|
// cause headaches. Specifically for Windows NT the only way
|
|
// to cause an asynchronous callback to 16-bit land from a 32-bit DLL
|
|
// is to cause an interrupt but we don't want to require mixer stuff
|
|
// to be locked down to allow for this.
|
|
//
|
|
|
|
if ((fdwOpen & CALLBACK_TYPEMASK) == CALLBACK_FUNCTION)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerOpen: CALLBACK_FUNCTION is not supported");
|
|
return MMSYSERR_INVALFLAG;
|
|
}
|
|
|
|
V_DCALLBACK(dwCallback, HIWORD(fdwOpen & CALLBACK_TYPEMASK), MMSYSERR_INVALPARAM);
|
|
V_DFLAGS(fdwOpen, MIXER_OPENF_VALID, mixerOpen, MMSYSERR_INVALFLAG);
|
|
|
|
mmr = IMixerGetID((HMIXEROBJ)(UINT_PTR)uMxId, &uMxId, NULL, (MIXER_OBJECTF_TYPEMASK & fdwOpen));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (mmr);
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
mmr = mixerReferenceDriverById(uMxId, &pmxdrv, &port);
|
|
if (mmr)
|
|
{
|
|
return mmr;
|
|
}
|
|
|
|
#ifdef MIXER_MAPPER
|
|
//
|
|
// Default Mixer Mapper:
|
|
//
|
|
// If a mixer mapper is installed as a separate DLL then all mixer
|
|
// mapper messages are routed to it. If no mixer mapper is installed,
|
|
// simply loop through the mixer devices looking for a match.
|
|
//
|
|
if ((MIXER_MAPPER == uMxId) && (NULL == pmxdrv->drvMessage))
|
|
{
|
|
for (uMxId = 0; uMxId < guTotalMixerDevs; uMxId++)
|
|
{
|
|
// try to open it
|
|
if (MMSYSERR_NOERROR == mmr)
|
|
break;
|
|
|
|
}
|
|
|
|
mregDecUsagePtr(pmxdrv);
|
|
return (mmr);
|
|
}
|
|
#endif
|
|
|
|
|
|
//
|
|
// Get some memory for the dev structure
|
|
//
|
|
pmxdev = (PMIXERDEV)NewHandle(TYPE_MIXER, pmxdrv->cookie, sizeof(MIXERDEV));
|
|
if (NULL == pmxdev)
|
|
{
|
|
mregDecUsagePtr(pmxdrv);
|
|
return (MMSYSERR_NOMEM);
|
|
}
|
|
|
|
ENTER_MM_HANDLE(pmxdev);
|
|
SetHandleFlag(pmxdev, MMHANDLE_BUSY);
|
|
ReleaseHandleListResource();
|
|
|
|
//
|
|
// initialize our open instance struct for the client
|
|
//
|
|
pmxdev->uHandleType = TYPE_MIXER;
|
|
pmxdev->pmxdrv = pmxdrv;
|
|
pmxdev->wDevice = port;
|
|
pmxdev->uDeviceID = uMxId;
|
|
pmxdev->fdwHandle = 0;
|
|
|
|
//
|
|
// save the client's callback info
|
|
//
|
|
pmxdev->dwCallback = dwCallback;
|
|
pmxdev->dwInstance = dwInstance;
|
|
pmxdev->fdwOpen = fdwOpen;
|
|
|
|
MIXMGR_ENTER;
|
|
|
|
//
|
|
// Check to see if we already have this device open
|
|
//
|
|
for (pmxdevRunList = gpMixerDevHeader; pmxdevRunList; pmxdevRunList = pmxdevRunList->pmxdevNext)
|
|
{
|
|
if (pmxdevRunList->pmxdrv != pmxdrv) continue;
|
|
if (pmxdevRunList->wDevice != port) continue;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Have we found a match?
|
|
//
|
|
if (NULL != pmxdevRunList)
|
|
{
|
|
//
|
|
// Set the driver's dwUser to the value we got before.
|
|
//
|
|
pmxdev->dwDrvUser = pmxdevRunList->dwDrvUser;
|
|
|
|
//
|
|
// We have a match, add the caller to the devlist chain (next in
|
|
// line AFTER the one we just found).
|
|
//
|
|
pmxdev->pmxdevNext = pmxdevRunList->pmxdevNext;
|
|
pmxdevRunList->pmxdevNext = pmxdev;
|
|
|
|
ClearHandleFlag(pmxdev, MMHANDLE_BUSY);
|
|
|
|
MIXMGR_LEAVE;
|
|
LEAVE_MM_HANDLE(pmxdev);
|
|
|
|
//
|
|
// Tell the caller the good news
|
|
//
|
|
*phmx = (HMIXER)pmxdev;
|
|
|
|
//
|
|
// All done. Note we don't dec usage on pmxdrv.
|
|
//
|
|
return (MMSYSERR_NOERROR);
|
|
}
|
|
|
|
//
|
|
// If we get here, no one has the device currently open. Let's
|
|
// go open it, then.
|
|
//
|
|
|
|
//
|
|
// Load up our local MIXEROPENDESC struct
|
|
//
|
|
|
|
mxod.hmx = (HMIXER)pmxdev;
|
|
mxod.pReserved0 = (LPVOID)NULL;
|
|
mxod.dwCallback = (DWORD_PTR)MixerCallbackFunc;
|
|
mxod.dwInstance = (DWORD_PTR)uMxId;
|
|
mxod.dnDevNode = (DWORD_PTR)pmxdev->pmxdrv->cookie;
|
|
|
|
EnterCriticalSection(&pmxdrv->MixerCritSec);
|
|
|
|
mmr = (MMRESULT)((*(pmxdrv->drvMessage))(port,
|
|
MXDM_OPEN,
|
|
(DWORD_PTR)(LPDWORD)&dwDrvUser,
|
|
(DWORD_PTR)(LPVOID)&mxod,
|
|
CALLBACK_FUNCTION));
|
|
|
|
LeaveCriticalSection(&pmxdrv->MixerCritSec);
|
|
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
{
|
|
// Should we do this after the MIXMGR_LEAVE???
|
|
LEAVE_MM_HANDLE(pmxdev);
|
|
MIXMGR_LEAVE;
|
|
FreeHandle((HMIXER)pmxdev);
|
|
}
|
|
else
|
|
{
|
|
MIXERCAPS mxcaps;
|
|
DWORD_PTR dwParam1, dwParam2;
|
|
MDEVICECAPSEX mdCaps;
|
|
|
|
mregIncUsagePtr(pmxdrv);
|
|
|
|
dwParam2 = (DWORD_PTR)pmxdev->pmxdrv->cookie;
|
|
|
|
if (0 == dwParam2)
|
|
{
|
|
dwParam1 = (DWORD_PTR)&mxcaps;
|
|
dwParam2 = (DWORD)sizeof(mxcaps);
|
|
}
|
|
else
|
|
{
|
|
mdCaps.cbSize = (DWORD)sizeof(mxcaps);
|
|
mdCaps.pCaps = &mxcaps;
|
|
dwParam1 = (DWORD_PTR)&mdCaps;
|
|
}
|
|
|
|
// Calling manually since we don't have the HandleList resource...
|
|
EnterCriticalSection(&pmxdrv->MixerCritSec);
|
|
(*(pmxdrv->drvMessage))(port, MXDM_GETDEVCAPS, dwDrvUser, dwParam1, dwParam2);
|
|
LeaveCriticalSection(&pmxdrv->MixerCritSec);
|
|
|
|
//
|
|
// cache some stuff for parameter validation
|
|
//
|
|
pmxdev->fdwSupport = mxcaps.fdwSupport;
|
|
pmxdev->cDestinations = mxcaps.cDestinations;
|
|
pmxdev->dwDrvUser = dwDrvUser;
|
|
*phmx = (HMIXER)pmxdev;
|
|
|
|
//
|
|
// Put this new device into the devlist chain.
|
|
//
|
|
|
|
pmxdev->pmxdevNext = gpMixerDevHeader;
|
|
gpMixerDevHeader = pmxdev;
|
|
|
|
ClearHandleFlag(pmxdev, MMHANDLE_BUSY);
|
|
LEAVE_MM_HANDLE(pmxdev);
|
|
MIXMGR_LEAVE;
|
|
}
|
|
|
|
mregDecUsagePtr(pmxdrv);
|
|
|
|
return (mmr);
|
|
|
|
} // mixerOpen()
|
|
|
|
|
|
/*--------------------------------------------------------------------------;
|
|
*
|
|
* @doc EXTERNAL MIXER SDK API
|
|
*
|
|
* @api MMRESULT | mixerClose | The <f mixerClose> function closes the
|
|
* specified audio mixer device. An application must close all mixer
|
|
* handles before exiting (or when the application is finished using
|
|
* the device).
|
|
*
|
|
* @parm <c HMIXER> | hmx | Specifies a handle to the audio mixer device.
|
|
* This handle must have been returned successfully by <f mixerOpen>. If
|
|
* <f mixerClose> is successful, <p hmx> is no longer valid.
|
|
*
|
|
* @rdesc Returns zero if the function was successful. Otherwise, it returns
|
|
* a non-zero error number. Possible error returns are:
|
|
*
|
|
* @flag <c MMSYSERR_INVALHANDLE> | Specified device handle is invalid.
|
|
*
|
|
* @xref <f mixerOpen>
|
|
*
|
|
**/
|
|
|
|
MMRESULT APIENTRY mixerClose(
|
|
HMIXER hmx
|
|
)
|
|
{
|
|
MMRESULT mmr;
|
|
PMIXERDEV pmxdev;
|
|
PMIXERDRV pmxdrv;
|
|
BOOL closemixerdriver;
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
V_HANDLE_ACQ(hmx, TYPE_MIXER, MMSYSERR_INVALHANDLE);
|
|
|
|
ENTER_MM_HANDLE(hmx);
|
|
ReleaseHandleListResource();
|
|
|
|
if (IsHandleDeserted(hmx))
|
|
{
|
|
// This handle has been deserted. Let's just free it.
|
|
|
|
LEAVE_MM_HANDLE(hmx);
|
|
FreeHandle(hmx);
|
|
return MMSYSERR_NOERROR;
|
|
}
|
|
|
|
//
|
|
// remove the mixer handle from the linked list
|
|
//
|
|
// BUGBUG: We're removing the driver from the list BEFORE we know if
|
|
// the close is successful (for the last handle).
|
|
//
|
|
|
|
MIXMGR_ENTER;
|
|
|
|
pmxdev = (PMIXERDEV)hmx;
|
|
pmxdrv = pmxdev->pmxdrv;
|
|
|
|
if (pmxdev == gpMixerDevHeader)
|
|
{
|
|
gpMixerDevHeader = pmxdev->pmxdevNext;
|
|
}
|
|
else
|
|
{
|
|
PMIXERDEV pmxdevT;
|
|
|
|
for (pmxdevT = gpMixerDevHeader;
|
|
pmxdevT && (pmxdevT->pmxdevNext != pmxdev);
|
|
pmxdevT = pmxdevT->pmxdevNext)
|
|
;
|
|
|
|
if (NULL == pmxdevT)
|
|
{
|
|
DebugErr1(DBF_ERROR,
|
|
"mixerClose: invalid mixer handle (%.04Xh).",
|
|
hmx);
|
|
|
|
MIXMGR_LEAVE;
|
|
LEAVE_MM_HANDLE(hmx);
|
|
|
|
return (MMSYSERR_INVALHANDLE);
|
|
}
|
|
|
|
pmxdevT->pmxdevNext = pmxdev->pmxdevNext;
|
|
}
|
|
|
|
//
|
|
// see if this is the last handle on this open instance
|
|
//
|
|
closemixerdriver = TRUE;
|
|
if (gpMixerDevHeader)
|
|
{
|
|
PMIXERDEV pmxdevT;
|
|
for (pmxdevT = gpMixerDevHeader; pmxdevT; pmxdevT = pmxdevT->pmxdevNext)
|
|
{
|
|
if (pmxdevT->pmxdrv != pmxdev->pmxdrv) continue;
|
|
if (pmxdevT->wDevice != pmxdev->wDevice) continue;
|
|
closemixerdriver = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
MIXMGR_LEAVE;
|
|
|
|
// handle should be marked as "busy" even if we don't send the driver
|
|
// message.
|
|
SetHandleFlag(hmx, MMHANDLE_BUSY);
|
|
|
|
//
|
|
// if last open instance, then close it
|
|
//
|
|
mmr = MMSYSERR_NOERROR;
|
|
|
|
if (closemixerdriver)
|
|
{
|
|
EnterCriticalSection(&pmxdrv->MixerCritSec);
|
|
mmr = (MMRESULT)(*(pmxdrv->drvMessage))(pmxdev->wDevice, MXDM_CLOSE, pmxdev->dwDrvUser, 0L, 0L);
|
|
LeaveCriticalSection(&pmxdrv->MixerCritSec);
|
|
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
{
|
|
// Should we put the handle back in the list???
|
|
ClearHandleFlag(hmx, MMHANDLE_BUSY);
|
|
}
|
|
}
|
|
|
|
LEAVE_MM_HANDLE(hmx);
|
|
mregDecUsagePtr(pmxdev->pmxdrv);
|
|
|
|
if (MMSYSERR_NOERROR == mmr)
|
|
{
|
|
//
|
|
// we're done with the memory block. now free the memory and return.
|
|
//
|
|
FreeHandle(hmx);
|
|
}
|
|
|
|
return (mmr);
|
|
} // mixerClose()
|
|
|
|
|
|
/*--------------------------------------------------------------------------;
|
|
*
|
|
* @doc EXTERNAL MIXER SDK API
|
|
*
|
|
* @api DWORD | mixerMessage | The <f mixerMessage> function sends a user
|
|
* defined audio mixer driver message directly to a mixer driver.
|
|
*
|
|
* @parm <c HMIXER> | hmx | Specifies a handle to an open instance of a
|
|
* mixer device. This handle is returned by <f mixerOpen>.
|
|
*
|
|
* @parm UINT | uMsg | Specifies the user defined mixer driver message to
|
|
* send to the mixer driver. This message must be above or equal to
|
|
* the <m MXDM_USER> message.
|
|
*
|
|
* @parm DWORD | dwParam1 | Contains the first argument associated with the
|
|
* message being sent.
|
|
*
|
|
* @parm DWORD | dwParam2 | Contains the second argument associated with the
|
|
* message being sent.
|
|
*
|
|
* @rdesc The return value is specific to the user defined mixer driver
|
|
* message <p uMsg> sent. However, the following return values are
|
|
* possible:
|
|
*
|
|
* @flag <c MMSYSERR_INVALHANDLE> | Specified device handle is invalid.
|
|
*
|
|
* @flag <c MMSYSERR_INVALPARAM> | <p uMsg> is not in the <m MXDM_USER>
|
|
* range.
|
|
*
|
|
* @flag <c MMSYSERR_NOTSUPPORTED> | The mixer device did not process
|
|
* the message.
|
|
*
|
|
* @comm The <f mixerMessage> function is provided to allow audio mixer
|
|
* driver specific messages to be sent to a mixer device. The messages
|
|
* that may be sent through this function must be above or equal to the
|
|
* <m MXDM_USER> message.
|
|
*
|
|
* User defined messages must only be sent to a mixer driver that
|
|
* specifically supports the messages. The caller should verify that
|
|
* the mixer driver is in fact the correct driver by getting the
|
|
* mixer capabilities and checking the <e MIXERCAPS.wMid>,
|
|
* <e MIXERCAPS.wPid>, <e MIXERCAPS.vDriverVersion> and
|
|
* <e MIXERCAPS.szPname> members of the <t MIXERCAPS> structure.
|
|
*
|
|
* It is important for an application to verify all members specified
|
|
* above due to many driver writers releasing drivers with improper
|
|
* or unregistered manufacturer and product identifiers.
|
|
*
|
|
* Never send user defined messages to an unknown audio mixer driver.
|
|
*
|
|
* @xref <f mixerOpen>, <f mixerGetDevCaps>
|
|
*
|
|
**/
|
|
|
|
DWORD APIENTRY mixerMessage(
|
|
HMIXER hmx,
|
|
UINT uMsg,
|
|
DWORD_PTR dwParam1,
|
|
DWORD_PTR dwParam2
|
|
)
|
|
{
|
|
DWORD dw;
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
AcquireHandleListResourceShared();
|
|
|
|
if (BAD_HANDLE(hmx, TYPE_MIXER))
|
|
{
|
|
ReleaseHandleListResource();
|
|
return IMixerMessageId (PtrToUint(hmx), uMsg, dwParam1, dwParam2);
|
|
}
|
|
|
|
//
|
|
// don't allow any non-user range messages through this API
|
|
//
|
|
if (MXDM_USER > uMsg)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerMessage: message must be in MXDM_USER range--what's this (%u)?", uMsg);
|
|
ReleaseHandleListResource();
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
|
|
dw = IMixerMessageHandle(hmx, uMsg, dwParam1, dwParam2);
|
|
|
|
return (dw);
|
|
|
|
} // mixerMessage()
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// BOOL IMixerIsValidComponentType
|
|
//
|
|
// Description:
|
|
//
|
|
//
|
|
// Arguments:
|
|
// DWORD dwComponentType:
|
|
//
|
|
// UINT uSrcDst:
|
|
//
|
|
// Return (BOOL):
|
|
//
|
|
// History:
|
|
// 10/06/93 cjp [curtisp]
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
BOOL IMixerIsValidComponentType
|
|
(
|
|
DWORD dwComponentType,
|
|
DWORD fdwLine
|
|
)
|
|
{
|
|
|
|
if (0 == (MIXERLINE_LINEF_SOURCE & fdwLine))
|
|
{
|
|
if (dwComponentType > MIXERLINE_COMPONENTTYPE_DST_LAST)
|
|
return (FALSE);
|
|
|
|
return (TRUE);
|
|
}
|
|
else
|
|
{
|
|
if (dwComponentType < MIXERLINE_COMPONENTTYPE_SRC_FIRST)
|
|
return (FALSE);
|
|
|
|
if (dwComponentType > MIXERLINE_COMPONENTTYPE_SRC_LAST)
|
|
return (FALSE);
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
} // IMixerIsValidComponentType()
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------;
|
|
*
|
|
* @doc EXTERNAL MIXER SDK STRUCTURE
|
|
*
|
|
* @types MIXERLINE | The <t MIXERLINE> structure describes the state
|
|
* and metrics of an audio mixer device line.
|
|
*
|
|
* @syntaxex
|
|
* typedef struct tMIXERLINE
|
|
* {
|
|
* DWORD cbStruct;
|
|
* DWORD dwDestination;
|
|
* DWORD dwSource;
|
|
* DWORD dwLineID;
|
|
* DWORD fdwLine;
|
|
* DWORD dwUser;
|
|
* DWORD dwComponentType;
|
|
* DWORD cChannels;
|
|
* DWORD cConnections;
|
|
* DWORD cControls;
|
|
* char szShortName[MIXER_SHORT_NAME_CHARS];
|
|
* char szName[MIXER_LONG_NAME_CHARS];
|
|
* struct
|
|
* {
|
|
* DWORD dwType;
|
|
* DWORD dwDeviceID;
|
|
* WORD wMid;
|
|
* WORD wPid;
|
|
* MMVERSION vDriverVersion;
|
|
* char szPname[MAXPNAMELEN];
|
|
* } Target;
|
|
* } MIXERLINE;
|
|
*
|
|
* @field DWORD | cbStruct | Specifies the size, in bytes, of the
|
|
* <t MIXERLINE> structure. This member must be initialized before
|
|
* calling the <f mixerGetLineInfo> function. The size specified in this
|
|
* member must be large enough to contain the base <t MIXERLINE>
|
|
* structure. When the <f mixerGetLineInfo> function returns, this
|
|
* member contains the actual size of the information returned. The
|
|
* returned information will never exceed the requested size.
|
|
*
|
|
* @field DWORD | dwDestination | Specifies the destination line index.
|
|
* This member ranges from zero to one less than the value specified
|
|
* in the <e MIXERCAPS.cDestinations> member of the <t MIXERCAPS>
|
|
* structure retrieved by the <f mixerGetDevCaps> function. When the
|
|
* <f mixerGetLineInfo> function is called with the
|
|
* <c MIXER_GETLINEINFOF_DESTINATION> flag specified, the details for
|
|
* the destination line are returned. Note that the
|
|
* <e MIXERLINE.dwSource> member must be set to zero in this case. When
|
|
* called with the <c MIXER_GETLINEINFOF_SOURCE> flag specified, the
|
|
* details for the source given by the <e MIXERLINE.dwSource> member
|
|
* associated with the <e MIXERLINE.dwDestination> member are returned.
|
|
*
|
|
* @field DWORD | dwSource | Specifies the source line index for the source
|
|
* line associated with the <e MIXERLINE.dwDestination> member. That
|
|
* is, this member specifies the nth source line associated with the
|
|
* specified destination line. This member is not used for destination
|
|
* lines and must be set to zero when <c MIXER_GETLINEINFOF_DESTINATION>
|
|
* is specified for <f mixerGetLineInfo>. When the
|
|
* <c MIXER_GETLINEINFOF_SOURCE> flag is specified, this member ranges
|
|
* from zero to one less than the value specified in the
|
|
* <e MIXERLINE.cConnections> of the <t MIXERLINE> structure for the
|
|
* destination line given in the <e MIXERLINE.dwDestination> member.
|
|
*
|
|
* @field DWORD | dwLineID | Specifies an audio mixer defined identifier
|
|
* that uniquely refers to the line described by the <t MIXERLINE>
|
|
* structure. This identifier is unique only to a single mixer device
|
|
* and may be of any format that the mixer device wishes. An application
|
|
* should only use this identifier as an abstract handle. No two
|
|
* lines for a single mixer device will have the same line identifier
|
|
* under any circumstances.
|
|
*
|
|
* @field DWORD | fdwLine | Specifies status and support flags for the
|
|
* audio mixer line. This member is always returned to the application
|
|
* and requires no initialization.
|
|
*
|
|
* @flag <c MIXERLINE_LINEF_SOURCE> | Specifies that this audio mixer
|
|
* line is a source line associated with a single destination line. If
|
|
* this flag is not set, then this line is a destination line associated
|
|
* with zero or more source lines.
|
|
*
|
|
* @flag <c MIXERLINE_LINEF_DISCONNECTED> | Specifies that this audio
|
|
* mixer line is disconnected. A disconnected line's associated controls
|
|
* can still be modified but the changes will have no effect until the
|
|
* line becomes connected. An application may want to modify its
|
|
* behavior if a mixer line is disconnected.
|
|
*
|
|
* @flag <c MIXERLINE_LINEF_ACTIVE> | Specifies that this audio mixer
|
|
* line is active. An active line specifies that a signal is (probably)
|
|
* passing through the line. For example, if a waveform output device
|
|
* is not in use by an application, then the line associated with that
|
|
* device would not be active (the <c MIXERLINE_LINEF_ACTIVE> flag would
|
|
* not be set). If the waveform output device is opened, then the
|
|
* the line is considered active and the <c MIXERLINE_LINEF_ACTIVE> flag
|
|
* will be set. Note that a 'paused' or 'starved' waveform output device
|
|
* is still considered active. In other words, if the waveform output
|
|
* device is opened by an application regardless of whether data is
|
|
* being played, the associated line is considered active. If a line
|
|
* cannot be strictly defined as 'active' verses 'inactive', then the
|
|
* audio mixer device will always set the <c MIXERLINE_LINEF_ACTIVE>
|
|
* flag. An example of where this information can be used by an
|
|
* application is displaying a 'peak meter.' Peak meters are polled
|
|
* meters. An application may want to disable its polling timer while
|
|
* the line is inactive to improve system performance. Note that the
|
|
* <c MIXERLINE_LINEF_ACTIVE> flag is also affected by the status of
|
|
* the mixer line's mute control. Muted mixer lines are never active.
|
|
*
|
|
* @field DWORD | dwUser | Specifies 32-bits of audio mixer device defined
|
|
* instance data for the line. This member is intended for custom
|
|
* audio mixer applications designed specifically for the mixer device
|
|
* returning this information. An application that is not specifically
|
|
* tailored to understand this member should simply ignore this data.
|
|
*
|
|
* @field DWORD | dwComponentType | Specifies the component type for this
|
|
* line. An application may use this information to display tailored
|
|
* graphics or search for a particular component. If an application
|
|
* does not know about a component type, then this member should be
|
|
* ignored. Currently, this member may be one of the following values:
|
|
*
|
|
* @flag <c MIXERLINE_COMPONENTTYPE_DST_UNDEFINED> | Specifies that the
|
|
* line is a destination that cannot be defined by one of the standard
|
|
* component types. An audio mixer device is required to use this
|
|
* component type for line component types that have not been defined
|
|
* by Microsoft.
|
|
*
|
|
* @flag <c MIXERLINE_COMPONENTTYPE_DST_DIGITAL> | Specifies that the
|
|
* line is a digital destination (for example, digital input to a DAT
|
|
* or CD Audio Disc).
|
|
*
|
|
* @flag <c MIXERLINE_COMPONENTTYPE_DST_LINE> | Specifies that the line
|
|
* is a line level destination (for example, line level input from
|
|
* a CD Audio Disc) that will be the final recording source for the
|
|
* ADC. Most audio cards for the PC provide some sort of gain for the
|
|
* recording source line, so the mixer device will use the
|
|
* <c MIXERLINE_COMPONENTTYPE_DST_WAVEIN> type.
|
|
*
|
|
* @flag <c MIXERLINE_COMPONENTTYPE_DST_MONITOR> | Specifies that the
|
|
* line is a destination used for a monitor.
|
|
*
|
|
* @flag <c MIXERLINE_COMPONENTTYPE_DST_SPEAKERS> | Specifies that the
|
|
* line is an adjustable (gain and/or attenuation) destination intended
|
|
* to drive speakers. This is the normal component type for the audio
|
|
* output of most audio cards for the PC.
|
|
*
|
|
* @flag <c MIXERLINE_COMPONENTTYPE_DST_HEADPHONES> | Specifies that the
|
|
* line is an adjustable (gain and/or attenuation) destination intended
|
|
* to driver headphones. Most audio cards use the same destination
|
|
* line for speakers and headphones--in which case the mixer device
|
|
* will simply use the <c MIXERLINE_COMPONENTTYPE_DST_SPEAKERS> type.
|
|
*
|
|
* @flag <c MIXERLINE_COMPONENTTYPE_DST_TELEPHONE> | Specifies that the
|
|
* line is a destination that will be routed to the telephone line.
|
|
*
|
|
* @flag <c MIXERLINE_COMPONENTTYPE_DST_WAVEIN> | Specifies that the
|
|
* line is a destination that will be the final recording source for the
|
|
* waveform input (ADC). This line will normally provide some sort of
|
|
* gain or attenuation. This is the normal component type for the
|
|
* recording line of most audio cards for the PC.
|
|
*
|
|
* @flag <c MIXERLINE_COMPONENTTYPE_DST_VOICEIN> | Specifies that the
|
|
* line is a destination that will be the final recording source for
|
|
* voice input. This component type is exactly like
|
|
* <c MIXERLINE_COMPONENTTYPE_DST_WAVEIN> but is intended specifically
|
|
* for settings used during voice recording/recognition. This line
|
|
* is entirely optional for a mixer device to support--many mixer
|
|
* devices may only provide <c MIXERLINE_COMPONENTTYPE_DST_WAVEIN>.
|
|
*
|
|
*
|
|
* @flag <c MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED> | Specifies that the
|
|
* line is a source that cannot be defined by one of the standard
|
|
* component types. An audio mixer device is required to use this
|
|
* component type for line component types that have not been defined
|
|
* by Microsoft.
|
|
*
|
|
* @flag <c MIXERLINE_COMPONENTTYPE_SRC_DIGITAL> | Specifies that the
|
|
* line is a digital source (for example, digital output from a DAT or
|
|
* CD Audio Disc).
|
|
*
|
|
* @flag <c MIXERLINE_COMPONENTTYPE_SRC_LINE> | Specifies that the line
|
|
* is a line level source (for example, line level input from
|
|
* an external stereo) that will be used as a, perhaps, optional source
|
|
* for recording. Most audio cards for the PC provide some sort of gain
|
|
* for the recording source line, so the mixer device will use the
|
|
* <c MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY> type.
|
|
*
|
|
* @flag <c MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE> | Specifies that the
|
|
* line is a microphone recording source. Most audio cards for the
|
|
* PC provide at least two types of recording sources: an auxiliary
|
|
* line and microphone input. A microphone line normally provides
|
|
* some sort of gain. Audio cards that use a single input for use
|
|
* with a microphone or auxiliary line should use the
|
|
* <c MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE> component type.
|
|
*
|
|
* @flag <c MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER> | Specifies that
|
|
* the line is a source originating from the output of an internal
|
|
* synthesizer. Most audio cards for the PC provide some sort of
|
|
* MIDI synthesizer (for example, an Ad Lib compatible or OPL/3 FM
|
|
* synthesizer).
|
|
*
|
|
* @flag <c MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC> | Specifies that
|
|
* the line is a source originating from the output of an internal audio
|
|
* compact disc. This component type is provided for those audio cards
|
|
* that provide a source line solely intended to be connected to an
|
|
* audio compact disc (or CD-ROM playing a Redbook Audio CD).
|
|
*
|
|
* @flag <c MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE> | Specifies that the
|
|
* line is a source originating from an incoming telephone line.
|
|
*
|
|
* @flag <c MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER> | Specifies that the
|
|
* line is a source originating from the PC speaker. Several audio cards
|
|
* for the PC provide the ability to mix what would normally be played
|
|
* on the internal speaker with the output of an audio card. The
|
|
* ability to use this output as a source for recording has also been
|
|
* exploited by some audio cards.
|
|
*
|
|
* @flag <c MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT> | Specifies that the
|
|
* line is a source originating from the waveform output (DAC). Most
|
|
* cards for the PC provide this component type as a source to the
|
|
* <c MIXERLINE_COMPONENTTYPE_DST_SPEAKERS> destination. Some cards will
|
|
* also allow this source to be routed to the
|
|
* <c MIXERLINE_COMPONENTTYPE_DST_WAVEIN> destination.
|
|
*
|
|
* @flag <c MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY> | Specifies that the
|
|
* line is a source originating from the auxiliary line. This line type
|
|
* is intended as a source with gain or attenuation that can be routed
|
|
* to the <c MIXERLINE_COMPONENTTYPE_DST_SPEAKERS> destination and/or
|
|
* recorded from through the <c MIXERLINE_COMPONENTTYPE_DST_WAVEIN>
|
|
* destination.
|
|
*
|
|
* @flag <c MIXERLINE_COMPONENTTYPE_SRC_ANALOG> | Specifies that the
|
|
* line is a source originating from one or more lines. This line type
|
|
* is intended for audio mixers that can mix multiple lines into a
|
|
* single source for that can be routed to the
|
|
* <c MIXERLINE_COMPONENTTYPE_DST_SPEAKERS> destination and/or
|
|
* recorded from through the <c MIXERLINE_COMPONENTTYPE_DST_WAVEIN>
|
|
* destination.
|
|
*
|
|
* @field DWORD | cChannels | Specifies the maximum number of separate
|
|
* channels that can be manipulated independantly for the line. Most
|
|
* of the modern audio cards for the PC are stereo devices, so this
|
|
* member will be two. Channel one is assumed to be the left channel;
|
|
* channel two is assumed to be the right channel. Note that a
|
|
* multi-channel line may have one or more uniform controls (controls
|
|
* that affect all channels of a line uniformly) associated with it.
|
|
* An example of a uniform control is a Mute that mutes all channels
|
|
* of a line simultaneously. A line must have at least one channel--
|
|
* this member will never be zero.
|
|
*
|
|
* @field DWORD | cConnections | Specifies the number of connections that
|
|
* are associated with the line. Currently, this member is used only
|
|
* for destination lines and specifies the number of source lines
|
|
* that are associated with it. This number may be zero. For source
|
|
* lines, this member is always zero.
|
|
*
|
|
* @field DWORD | cControls | Specifies the number of controls associated
|
|
* with the line. This value may be zero. If no controls are associated
|
|
* with the line, then the line is probably (but not always) just a
|
|
* source that may be selected in a MUX or Mixer but allows no
|
|
* manipulation of the signal. For example, a digital source may have
|
|
* this attribute.
|
|
*
|
|
* @field char | szShortName[<c MIXER_SHORT_NAME_CHARS>] | Specifies a short
|
|
* string that describes the <e MIXERLINE.dwLineID> audio mixer line.
|
|
* This description is appropriate for using as a displayable label for
|
|
* the line that can fit in small spaces.
|
|
*
|
|
* @field char | szName[<c MIXER_LONG_NAME_CHARS>] | Specifies a string
|
|
* that describes the <e MIXERLINE.dwLineID> audio mixer line. This
|
|
* description is appropriate for using as a displayable description
|
|
* for the line that is not limited by screen space.
|
|
*
|
|
* @field struct | Target | Contains the target media information.
|
|
*
|
|
* @field2 DWORD | dwType | Specifies the target media device type
|
|
* associated with the audio mixer line described in the <t MIXERLINE>
|
|
* structure. An application must ignore target information for media
|
|
* device types that it does not understand. Currently, this member may
|
|
* be one of the following:
|
|
*
|
|
* @flag <c MIXERLINE_TARGETTYPE_UNDEFINED> | Specifies that the line
|
|
* described by this <t MIXERLINE> structure is not strictly bound
|
|
* to a defined media type. All remaining <e MIXERLINE.Target> structure
|
|
* members of the <t MIXERLINE> structure should be ignored. Note that
|
|
* an application may not use the <c MIXERLINE_TARGETTYPE_UNDEFINED>
|
|
* target type when calling the <f mixerGetLineInfo> function with the
|
|
* <c MIXER_GETLINEINFOF_TARGETTYPE> flag.
|
|
*
|
|
* @flag <c MIXERLINE_TARGETTYPE_WAVEOUT> | Specifies that the line
|
|
* described by this <t MIXERLINE> structure is strictly bound to
|
|
* the waveform output device detailed in the remaining members of
|
|
* the <e MIXERLINE.Target> structure member of the <t MIXERLINE>
|
|
* structure.
|
|
*
|
|
* @flag <c MIXERLINE_TARGETTYPE_WAVEIN> | Specifies that the line
|
|
* described by this <t MIXERLINE> structure is strictly bound to
|
|
* the waveform input device detailed in the remaining members of
|
|
* the <e MIXERLINE.Target> structure member of the <t MIXERLINE>
|
|
* structure.
|
|
*
|
|
* @flag <c MIXERLINE_TARGETTYPE_MIDIOUT> | Specifies that the line
|
|
* described by this <t MIXERLINE> structure is strictly bound to
|
|
* the MIDI output device detailed in the remaining members of
|
|
* the <e MIXERLINE.Target> structure member of the <t MIXERLINE>
|
|
* structure.
|
|
*
|
|
* @flag <c MIXERLINE_TARGETTYPE_MIDIIN> | Specifies that the line
|
|
* described by this <t MIXERLINE> structure is strictly bound to
|
|
* the MIDI input device detailed in the remaining members of
|
|
* the <e MIXERLINE.Target> structure member of the <t MIXERLINE>
|
|
* structure.
|
|
*
|
|
* @flag <c MIXERLINE_TARGETTYPE_AUX> | Specifies that the line
|
|
* described by this <t MIXERLINE> structure is strictly bound to
|
|
* the auxiliary device detailed in the remaining members of
|
|
* the <e MIXERLINE.Target> structure member of the <t MIXERLINE>
|
|
* structure.
|
|
*
|
|
* @field2 DWORD | dwDeviceID | In the case of the
|
|
* <e MIXERLINE.dwType> member being a target type other than
|
|
* <c MIXERLINE_TARGETTYPE_UNDEFINED>, this member is the current device
|
|
* identifier of the target media device. This identifier is identical
|
|
* to the current media device index of the associated media device.
|
|
* Note that when calling the <f mixerGetLineInfo> function with
|
|
* the <c MIXER_GETLINEINFOF_TARGETTYPE> flag, this member is ignored on
|
|
* input and will be returned to the caller by the audio mixer manager.
|
|
*
|
|
* @field2 WORD | wMid | In the case of the <e MIXERLINE.dwType>
|
|
* member being a target type other than <c MIXERLINE_TARGETTYPE_UNDEFINED>,
|
|
* this member is the manufacturer identifier of the target media device.
|
|
* This identifier is identical to the wMid member of the associated
|
|
* media device capabilities structure.
|
|
*
|
|
* @field WORD | wPid | In the case of the <e MIXERLINE.dwType>
|
|
* member being a target type other than <c MIXERLINE_TARGETTYPE_UNDEFINED>,
|
|
* this member is the product identifier of the target media device.
|
|
* This identifier is identical to the wPid member of the associated
|
|
* media device capabilities structure.
|
|
*
|
|
* @field2 MMVERSION | vDriverVersion | In the case of the
|
|
* <e MIXERLINE.dwType> member being a target type other than
|
|
* <c MIXERLINE_TARGETTYPE_UNDEFINED>, this member is the driver version
|
|
* of the target media device. This version is identical to the
|
|
* vDriverVersion member of the associated media device capabilities
|
|
* structure.
|
|
*
|
|
* @field char | szPname[MAXPNAMELEN] | In the case of the
|
|
* <e MIXERLINE.dwType> member being a target type other than
|
|
* <c MIXERLINE_TARGETTYPE_UNDEFINED>, this member is the product
|
|
* name of the target media device. This name is identical to the
|
|
* szPname member of the associated media device capabilities structure.
|
|
*
|
|
* @tagname tMIXERLINE
|
|
*
|
|
* @othertype MIXERLINE FAR * | LPMIXERLINE | A pointer to a <t MIXERLINE>
|
|
* structure.
|
|
*
|
|
* @othertype MIXERLINE * | PMIXERLINE | A pointer to a <t MIXERLINE>
|
|
* structure.
|
|
*
|
|
* @xref <f mixerGetLineInfo>, <f mixerGetDevCaps>
|
|
*
|
|
**/
|
|
|
|
/*--------------------------------------------------------------------------;
|
|
*
|
|
* @doc EXTERNAL MIXER SDK API
|
|
*
|
|
* @api MMRESULT | mixerGetLineInfo | The <f mixerGetLineInfo> function
|
|
* retrieves information about a specified audio mixer devices 'line'.
|
|
*
|
|
* @parm <c HMIXEROBJ> | hmxobj | Specifies a handle to the audio mixer
|
|
* device object to get line information from.
|
|
*
|
|
* @parm LPMIXERLINE | pmxl | Points to a <t MIXERLINE> structure. This
|
|
* structure is filled with information about the mixer line for the
|
|
* audio mixer device. See the comments for each query flag passed
|
|
* through <p fdwInfo> for details on what members of the <t MIXERLINE>
|
|
* structure must be initialized before calling <f mixerGetLineInfo>.
|
|
* Note that in all cases, <e MIXERLINE.cbStruct> must be initialized
|
|
* to be the size, in bytes, of the <t MIXERLINE> structure.
|
|
*
|
|
* @parm DWORD | fdwInfo | Specifies flags for getting information on a
|
|
* mixer line.
|
|
*
|
|
* @flag <c MIXER_GETLINEINFOF_DESTINATION> | If this flag is specified,
|
|
* <p pmxl> is to receive information on the destination line
|
|
* specified by the <e MIXERLINE.dwDestination> member of the
|
|
* <t MIXERLINE> structure. This index ranges from zero to one less
|
|
* than <e MIXERCAPS.cDestinations> of the <t MIXERCAPS> structure.
|
|
* All remaining structure members except <e MIXERLINE.cbStruct> require
|
|
* no further initialization.
|
|
*
|
|
* @flag <c MIXER_GETLINEINFOF_SOURCE> | If this flag is specified,
|
|
* <p pmxl> is to receive information on the source line specified by
|
|
* the <e MIXERLINE.dwDestination> and <e MIXERLINE.dwSource> members
|
|
* of the <t MIXERLINE> structure. The index specified by
|
|
* <e MIXERLINE.dwDestination> ranges from zero to one less than
|
|
* <e MIXERCAPS.cDestinations> of the <t MIXERCAPS> structure. The
|
|
* index specified by for <e MIXERLINE.dwSource> ranges from
|
|
* zero to one less than the <e MIXERLINE.cConnections> member of the
|
|
* <t MIXERLINE> structure returned for the <e MIXERLINE.dwDestination>
|
|
* line. All remaining structure members except <e MIXERLINE.cbStruct>
|
|
* require no further initialization.
|
|
*
|
|
* @flag <c MIXER_GETLINEINFOF_LINEID> | If this flag is specified,
|
|
* <p pmxl> is to receive information on the line specified by the
|
|
* <e MIXERLINE.dwLineID> member of the <t MIXERLINE> structure. This
|
|
* is usually used to retrieve updated information on a line's state.
|
|
* All remaining structure members except <e MIXERLINE.cbStruct> require
|
|
* no further initialization.
|
|
*
|
|
* @flag <c MIXER_GETLINEINFOF_COMPONENTTYPE> | If this flag is
|
|
* specified, <p pmxl> is to receive information on the first line of
|
|
* the type specified in the <e MIXERLINE.dwComponentType> member of the
|
|
* <t MIXERLINE> structure. This is used to retrieve information
|
|
* on a line that is of a specific component type (for example, an
|
|
* application could specify <c MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE>
|
|
* to retrieve information on the first Microphone input associated
|
|
* with the specified <p hmxobj>). All remaining structure members
|
|
* except <e MIXERLINE.cbStruct> require no further initialization.
|
|
*
|
|
* @flag <c MIXER_GETLINEINFOF_TARGETTYPE> | If this flag is specified,
|
|
* <p pmxl> is to receive information on the line that is for the
|
|
* <e MIXERLINE.dwType> of the <t MIXERLINE> structure. This is
|
|
* used to retrieve information on a line that handles the target
|
|
* type (<c MIXERLINE_TARGETTYPE_WAVEOUT> for example). An application
|
|
* must initialize <e MIXERLINE.dwType>, <e MIXERLINE.wMid>,
|
|
* <e MIXERLINE.wPid>, <e MIXERLINE.vDriverVersion> and
|
|
* <e MIXERLINE.szPname> of the <t MIXERLINE> structure before
|
|
* calling <f mixerGetLineInfo>. All of these values can be retrieved
|
|
* from the device capabilities structures for all media devices. All
|
|
* remaining structure members except <e MIXERLINE.cbStruct> require
|
|
* no further initialization.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_MIXER> | Specifies that <p hmxobj> is an audio
|
|
* mixer device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f mixerGetNumDevs>. This flag is
|
|
* optional.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HMIXER> | Specifies that <p hmxobj> is a mixer
|
|
* device handle returned by <f mixerOpen>. This flag is optional.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_WAVEOUT> | Specifies that <p hmxobj> is a
|
|
* waveform output device identifier in the range of zero to one less
|
|
* than the number of devices returned by <f waveOutGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HWAVEOUT> | Specifies that <p hmxobj> is a
|
|
* waveform output handle returned by <f waveOutOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_WAVEIN> | Specifies that <p hmxobj> is a
|
|
* waveform input device identifier in the range of zero to one less
|
|
* than the number of devices returned by <f waveInGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HWAVEIN> | Specifies that <p hmxobj> is a
|
|
* waveform input handle returned by <f midiInOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_MIDIOUT> | Specifies that <p hmxobj> is a MIDI
|
|
* output device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f midiOutGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HMIDIOUT> | Specifies that <p hmxobj> is a
|
|
* MIDI output handle returned by <f midiOutOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_MIDIIN> | Specifies that <p hmxobj> is a MIDI
|
|
* input device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f midiInGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HMIDIIN> | Specifies that <p hmxobj> is a MIDI
|
|
* input handle returned by <f midiInOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_AUX> | Specifies that <p hmxobj> is an
|
|
* auxiliary device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f auxGetNumDevs>.
|
|
*
|
|
* @rdesc The return value is zero if the function is successful. Otherwise,
|
|
* it returns a non-zero error number. Possible error returns include
|
|
* the following:
|
|
*
|
|
* @flag <c MMSYSERR_BADDEVICEID> | The <p hmxobj> argument specifies an
|
|
* invalid device identifier.
|
|
*
|
|
* @flag <c MMSYSERR_INVALHANDLE> | The <p hmxobj> argument specifies an
|
|
* invalid handle.
|
|
*
|
|
* @flag <c MMSYSERR_INVALFLAG> | One or more flags are invalid.
|
|
*
|
|
* @flag <c MMSYSERR_INVALPARAM> | One or more arguments passed is
|
|
* invalid.
|
|
*
|
|
* @flag <c MMSYSERR_NODRIVER> | No audio mixer device is available for
|
|
* the object specified by <p hmxobj>.
|
|
*
|
|
* @flag <c MIXERR_INVALLINE> | The audio mixer device line reference is
|
|
* invalid.
|
|
*
|
|
* @xref <t MIXERLINE>, <f mixerOpen>, <f mixerGetDevCaps>, <t MIXERCAPS>,
|
|
* <f mixerGetLineControls>
|
|
*
|
|
**/
|
|
|
|
MMRESULT APIENTRY mixerGetLineInfoA(
|
|
HMIXEROBJ hmxobj,
|
|
LPMIXERLINEA pmxlA,
|
|
DWORD fdwInfo
|
|
)
|
|
{
|
|
MIXERLINEW mxlW;
|
|
MMRESULT mmr;
|
|
|
|
//
|
|
// Validate the mixer line info pointer
|
|
//
|
|
|
|
V_WPOINTER(pmxlA, sizeof(DWORD), MMSYSERR_INVALPARAM);
|
|
if (pmxlA->cbStruct < sizeof(MIXERLINEA)) {
|
|
return MMSYSERR_INVALPARAM;
|
|
}
|
|
V_WPOINTER(pmxlA, pmxlA->cbStruct, MMSYSERR_INVALPARAM);
|
|
|
|
//
|
|
// Call the UNICODE version to get the full set of data
|
|
//
|
|
|
|
CopyMemory((PVOID)&mxlW, (PVOID)pmxlA, FIELD_OFFSET(MIXERLINE, cChannels));
|
|
mxlW.cbStruct = sizeof(mxlW);
|
|
|
|
//
|
|
// If target stuff wanted we must set the target data
|
|
//
|
|
|
|
if ((fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) ==
|
|
MIXER_GETLINEINFOF_TARGETTYPE) {
|
|
CopyMemory((PVOID)&mxlW.Target.dwType, (PVOID)&pmxlA->Target.dwType,
|
|
FIELD_OFFSET(MIXERLINE, Target.szPname[0]) -
|
|
FIELD_OFFSET(MIXERLINE, Target.dwType));
|
|
|
|
Imbstowcs(mxlW.Target.szPname, pmxlA->Target.szPname, MAXPNAMELEN);
|
|
}
|
|
|
|
//
|
|
// Set the relevant values
|
|
//
|
|
|
|
mmr = mixerGetLineInfo(hmxobj, &mxlW, fdwInfo);
|
|
|
|
if (mmr != MMSYSERR_NOERROR) {
|
|
return mmr;
|
|
}
|
|
|
|
//
|
|
// Massage the return data to ASCII
|
|
//
|
|
|
|
ConvertMIXERLINEWToMIXERLINEA(pmxlA, &mxlW);
|
|
|
|
return mmr;
|
|
} // mixerGetLineInfoA()
|
|
|
|
MMRESULT APIENTRY mixerGetLineInfo(
|
|
HMIXEROBJ hmxobj,
|
|
LPMIXERLINE pmxl,
|
|
DWORD fdwInfo
|
|
)
|
|
{
|
|
DWORD fdwMxObjType;
|
|
MMRESULT mmr;
|
|
PMIXERDEV pmxdev;
|
|
// UINT cb;
|
|
UINT uMxId;
|
|
BOOL fSourceLine, fResource;
|
|
|
|
V_DFLAGS(fdwInfo, MIXER_GETLINEINFOF_VALID, mixerGetLineInfo, MMSYSERR_INVALFLAG);
|
|
V_WPOINTER(pmxl, sizeof(DWORD), MMSYSERR_INVALPARAM);
|
|
if (sizeof(MIXERLINE) > pmxl->cbStruct)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetLineInfo: structure size too small or cbStruct not initialized (%lu).", pmxl->cbStruct);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
V_WPOINTER(pmxl, pmxl->cbStruct, MMSYSERR_INVALPARAM);
|
|
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
//
|
|
//
|
|
//
|
|
fSourceLine = FALSE;
|
|
switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK)
|
|
{
|
|
case MIXER_GETLINEINFOF_DESTINATION:
|
|
pmxl->dwSource = (DWORD)-1L;
|
|
pmxl->dwLineID = (DWORD)-1L;
|
|
pmxl->dwComponentType = (DWORD)-1L;
|
|
break;
|
|
|
|
case MIXER_GETLINEINFOF_SOURCE:
|
|
fSourceLine = TRUE;
|
|
pmxl->dwLineID = (DWORD)-1L;
|
|
pmxl->dwComponentType = (DWORD)-1L;
|
|
break;
|
|
|
|
case MIXER_GETLINEINFOF_LINEID:
|
|
pmxl->dwSource = (DWORD)-1L;
|
|
pmxl->dwDestination = (DWORD)-1L;
|
|
pmxl->dwComponentType = (DWORD)-1L;
|
|
break;
|
|
|
|
case MIXER_GETLINEINFOF_COMPONENTTYPE:
|
|
pmxl->dwSource = (DWORD)-1L;
|
|
pmxl->dwDestination = (DWORD)-1L;
|
|
pmxl->dwLineID = (DWORD)-1L;
|
|
|
|
if (!IMixerIsValidComponentType(pmxl->dwComponentType, 0) &&
|
|
!IMixerIsValidComponentType(pmxl->dwComponentType, MIXERLINE_LINEF_SOURCE))
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetLineInfo: invalid dwComponentType (%lu).", pmxl->dwComponentType);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
break;
|
|
|
|
case MIXER_GETLINEINFOF_TARGETTYPE:
|
|
pmxl->dwSource = (DWORD)-1L;
|
|
pmxl->dwDestination = (DWORD)-1L;
|
|
pmxl->dwLineID = (DWORD)-1L;
|
|
pmxl->dwComponentType = (DWORD)-1L;
|
|
|
|
if (MIXERLINE_TARGETTYPE_AUX < pmxl->Target.dwType)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetLineInfo: invalid Target.dwType (%lu).", pmxl->Target.dwType);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
DebugErr1(DBF_ERROR, "mixerGetLineInfo: invalid query flag (%.08lXh).",
|
|
fdwInfo & MIXER_GETLINEINFOF_QUERYMASK);
|
|
return (MMSYSERR_INVALFLAG);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
fdwMxObjType = (MIXER_OBJECTF_TYPEMASK & fdwInfo);
|
|
|
|
fResource = FALSE;
|
|
|
|
AcquireHandleListResourceShared();
|
|
|
|
// Checking for the type of mixer object. If it is a non-mixer type
|
|
// calling IMixerMesssageID (called by IMixerGetID) with the shared
|
|
// resource will deadlock.
|
|
if ((MIXER_OBJECTF_MIXER == fdwMxObjType) ||
|
|
(MIXER_OBJECTF_HMIXER == fdwMxObjType))
|
|
{
|
|
if (BAD_HANDLE(hmxobj, TYPE_MIXER))
|
|
{
|
|
ReleaseHandleListResource();
|
|
}
|
|
else
|
|
{
|
|
fResource = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ReleaseHandleListResource();
|
|
}
|
|
|
|
mmr = IMixerGetID(hmxobj, &uMxId, pmxl, fdwMxObjType);
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
{
|
|
dprintf(( "!IMixerGetLineInfo: IMixerGetID() failed!" ));
|
|
if (fResource)
|
|
ReleaseHandleListResource();
|
|
return (mmr);
|
|
}
|
|
|
|
if ((MIXER_OBJECTF_MIXER == fdwMxObjType) ||
|
|
(MIXER_OBJECTF_HMIXER == fdwMxObjType))
|
|
{
|
|
//
|
|
// if a mixer device id was passed, then null hmx so we use the
|
|
// correct message sender below
|
|
//
|
|
if ((UINT_PTR)hmxobj == uMxId)
|
|
hmxobj = NULL;
|
|
}
|
|
else
|
|
{
|
|
return (MMSYSERR_NOERROR);
|
|
}
|
|
|
|
|
|
//
|
|
// clear all fields before calling driver
|
|
//
|
|
if (NULL != hmxobj)
|
|
{
|
|
//
|
|
//
|
|
//
|
|
pmxdev = (PMIXERDEV)hmxobj;
|
|
#if 0
|
|
if (pmxdev->cDestinations <= pmxl->dwDestination)
|
|
{
|
|
ReleaseHandleListResource();
|
|
DebugErr1(DBF_ERROR, "mixerGetLineInfo: invalid destination index (%lu).", pmxl->dwDestination);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
#endif
|
|
|
|
mmr = (MMRESULT)IMixerMessageHandle((HMIXER)hmxobj,
|
|
MXDM_GETLINEINFO,
|
|
(DWORD_PTR)(LPVOID)pmxl,
|
|
fdwInfo);
|
|
}
|
|
else
|
|
{
|
|
#pragma message("----IMixerGetLineInfo: dwDestination not validated for ID's!!")
|
|
mmr = (MMRESULT)IMixerMessageId(uMxId,
|
|
MXDM_GETLINEINFO,
|
|
(DWORD_PTR)(LPVOID)pmxl,
|
|
fdwInfo);
|
|
}
|
|
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
return (mmr);
|
|
|
|
#pragma message("----IMixerGetLineInfo: should validate mixer driver didn't hose us!")
|
|
|
|
|
|
//
|
|
// validate the driver's returned stuff...
|
|
//
|
|
//
|
|
if (sizeof(MIXERLINE) != pmxl->cbStruct)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetLineInfo: buggy driver returned invalid cbStruct (%lu).", pmxl->cbStruct);
|
|
pmxl->cbStruct = sizeof(MIXERLINE);
|
|
}
|
|
|
|
if ((DWORD)-1L == pmxl->dwDestination)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetLineInfo: buggy driver failed to init dwDestination member.");
|
|
}
|
|
if (fSourceLine)
|
|
{
|
|
if (0 == (MIXERLINE_LINEF_SOURCE & pmxl->fdwLine))
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetLineInfo: buggy driver failed to set MIXERLINE_LINEF_SOURCE.");
|
|
pmxl->fdwLine |= MIXERLINE_LINEF_SOURCE;
|
|
}
|
|
|
|
if ((DWORD)-1L == pmxl->dwSource)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetLineInfo: buggy driver failed to init dwSource member.");
|
|
}
|
|
}
|
|
if ((DWORD)-1L == pmxl->dwLineID)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetLineInfo: buggy driver failed to init dwLineID member.");
|
|
}
|
|
if (pmxl->fdwLine & ~0x80008001L)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetLineInfo: buggy driver set reserved line flags (%.08lXh)!", pmxl->fdwLine);
|
|
pmxl->fdwLine &= 0x80008001L;
|
|
}
|
|
if (!IMixerIsValidComponentType(pmxl->dwComponentType, pmxl->fdwLine))
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetLineInfo: buggy driver returned invalid dwComponentType (%.08lXh).", pmxl->dwComponentType);
|
|
pmxl->dwComponentType = MIXERLINE_TARGETTYPE_UNDEFINED;
|
|
}
|
|
if (0 == pmxl->cChannels)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetLineInfo: buggy driver returned zero channels?!?");
|
|
pmxl->cChannels = 1;
|
|
}
|
|
if (fSourceLine)
|
|
{
|
|
if (0 != pmxl->cConnections)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetLineInfo: buggy driver returned non-zero connections on source?!?");
|
|
pmxl->cConnections = 0;
|
|
}
|
|
}
|
|
|
|
pmxl->szShortName[SIZEOF(pmxl->szShortName) - 1] = '\0';
|
|
pmxl->szName[SIZEOF(pmxl->szName) - 1] = '\0';
|
|
|
|
|
|
//
|
|
// Does this really need to be done if TARGETTYPE was requested?
|
|
//
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
if (MIXERLINE_TARGETTYPE_UNDEFINED != pmxl->Target.dwType)
|
|
{
|
|
UINT u;
|
|
|
|
pmxl->Target.dwDeviceID = (DWORD)-1L;
|
|
|
|
|
|
//
|
|
// we have a wMid, wPid and szPname (supposedly) of type dwType
|
|
// so let's go find it...
|
|
//
|
|
switch (pmxl->Target.dwType)
|
|
{
|
|
case MIXERLINE_TARGETTYPE_WAVEOUT:
|
|
u = waveOutGetNumDevs();
|
|
while (u--)
|
|
{
|
|
WAVEOUTCAPS woc;
|
|
|
|
mmr = waveOutGetDevCaps(u, &woc, sizeof(woc));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
continue;
|
|
|
|
woc.szPname[SIZEOF(woc.szPname) - 1] = '\0';
|
|
|
|
if (woc.wMid != pmxl->Target.wMid)
|
|
continue;
|
|
|
|
if (woc.wPid != pmxl->Target.wPid)
|
|
continue;
|
|
|
|
if (woc.vDriverVersion != pmxl->Target.vDriverVersion)
|
|
continue;
|
|
|
|
if (lstrcmp(woc.szPname, pmxl->Target.szPname))
|
|
continue;
|
|
|
|
pmxl->Target.dwDeviceID = u;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case MIXERLINE_TARGETTYPE_WAVEIN:
|
|
u = waveInGetNumDevs();
|
|
while (u--)
|
|
{
|
|
WAVEINCAPS wic;
|
|
|
|
mmr = waveInGetDevCaps(u, &wic, sizeof(wic));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
continue;
|
|
|
|
wic.szPname[SIZEOF(wic.szPname) - 1] = '\0';
|
|
|
|
if (wic.wMid != pmxl->Target.wMid)
|
|
continue;
|
|
|
|
if (wic.wPid != pmxl->Target.wPid)
|
|
continue;
|
|
|
|
if (wic.vDriverVersion != pmxl->Target.vDriverVersion)
|
|
continue;
|
|
|
|
if (lstrcmp(wic.szPname, pmxl->Target.szPname))
|
|
continue;
|
|
|
|
pmxl->Target.dwDeviceID = u;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case MIXERLINE_TARGETTYPE_MIDIOUT:
|
|
u = midiOutGetNumDevs();
|
|
while (u--)
|
|
{
|
|
MIDIOUTCAPS moc;
|
|
|
|
mmr = midiOutGetDevCaps(u, &moc, sizeof(moc));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
continue;
|
|
|
|
moc.szPname[SIZEOF(moc.szPname) - 1] = '\0';
|
|
|
|
if (moc.wMid != pmxl->Target.wMid)
|
|
continue;
|
|
|
|
if (moc.wPid != pmxl->Target.wPid)
|
|
continue;
|
|
|
|
if (moc.vDriverVersion != pmxl->Target.vDriverVersion)
|
|
continue;
|
|
|
|
if (lstrcmp(moc.szPname, pmxl->Target.szPname))
|
|
continue;
|
|
|
|
pmxl->Target.dwDeviceID = u;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case MIXERLINE_TARGETTYPE_MIDIIN:
|
|
u = midiInGetNumDevs();
|
|
while (u--)
|
|
{
|
|
MIDIINCAPS mic;
|
|
|
|
mmr = midiInGetDevCaps(u, &mic, sizeof(mic));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
continue;
|
|
|
|
mic.szPname[SIZEOF(mic.szPname) - 1] = '\0';
|
|
|
|
if (mic.wMid != pmxl->Target.wMid)
|
|
continue;
|
|
|
|
if (mic.wPid != pmxl->Target.wPid)
|
|
continue;
|
|
|
|
if (mic.vDriverVersion != pmxl->Target.vDriverVersion)
|
|
continue;
|
|
|
|
if (lstrcmp(mic.szPname, pmxl->Target.szPname))
|
|
continue;
|
|
|
|
pmxl->Target.dwDeviceID = u;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case MIXERLINE_TARGETTYPE_AUX:
|
|
u = auxGetNumDevs();
|
|
while (u--)
|
|
{
|
|
AUXCAPS ac;
|
|
|
|
mmr = auxGetDevCaps(u, &ac, sizeof(ac));
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
continue;
|
|
|
|
ac.szPname[SIZEOF(ac.szPname) - 1] = '\0';
|
|
|
|
if (ac.wMid != pmxl->Target.wMid)
|
|
continue;
|
|
|
|
if (ac.wPid != pmxl->Target.wPid)
|
|
continue;
|
|
|
|
if (ac.vDriverVersion != pmxl->Target.vDriverVersion)
|
|
continue;
|
|
|
|
if (lstrcmp(ac.szPname, pmxl->Target.szPname))
|
|
continue;
|
|
|
|
pmxl->Target.dwDeviceID = u;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
pmxl->Target.dwType = MIXERLINE_TARGETTYPE_UNDEFINED;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
return (mmr);
|
|
|
|
} // mixerGetLineInfo()
|
|
|
|
|
|
//
|
|
// Abstract converting the complex mixerline structure
|
|
//
|
|
void ConvertMIXERLINEWToMIXERLINEA(
|
|
PMIXERLINEA pmxlA,
|
|
PMIXERLINEW pmxlW
|
|
)
|
|
{
|
|
//
|
|
// Don't copy cbStruct
|
|
//
|
|
|
|
CopyMemory((PVOID)((PBYTE)pmxlA + sizeof(DWORD)),
|
|
(PVOID)((PBYTE)pmxlW + sizeof(DWORD)),
|
|
FIELD_OFFSET(MIXERLINEA, szShortName[0]) - sizeof(DWORD));
|
|
|
|
Iwcstombs(pmxlA->szShortName, pmxlW->szShortName,
|
|
sizeof(pmxlA->szShortName));
|
|
Iwcstombs(pmxlA->szName, pmxlW->szName,
|
|
sizeof(pmxlA->szName));
|
|
|
|
CopyMemory((PVOID)&pmxlA->Target, (PVOID)&pmxlW->Target,
|
|
FIELD_OFFSET(MIXERLINEA, Target.szPname[0]) -
|
|
FIELD_OFFSET(MIXERLINEA, Target.dwType));
|
|
|
|
Iwcstombs(pmxlA->Target.szPname, pmxlW->Target.szPname,
|
|
sizeof(pmxlA->Target.szPname));
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------;
|
|
*
|
|
* @doc EXTERNAL MIXER SDK STRUCTURE
|
|
*
|
|
* @types MIXERCONTROL | The <t MIXERCONTROL> structure describes the state
|
|
* and metrics of a single control for an audio mixer line.
|
|
*
|
|
* @syntaxex
|
|
* typedef struct tMIXERCONTROL
|
|
* {
|
|
* DWORD cbStruct;
|
|
* DWORD dwControlID;
|
|
* DWORD dwControlType;
|
|
* DWORD fdwControl;
|
|
* DWORD cMultipleItems;
|
|
* char szShortName[MIXER_SHORT_NAME_CHARS];
|
|
* char szName[MIXER_LONG_NAME_CHARS];
|
|
* union
|
|
* {
|
|
* struct
|
|
* {
|
|
* LONG lMinimum;
|
|
* LONG lMaximum;
|
|
* };
|
|
* struct
|
|
* {
|
|
* DWORD dwMinimum;
|
|
* DWORD dwMaximum;
|
|
* };
|
|
* DWORD dwReserved[6];
|
|
* } Bounds;
|
|
* union
|
|
* {
|
|
* DWORD cSteps;
|
|
* DWORD cbCustomData;
|
|
* DWORD dwReserved[6];
|
|
* } Metrics;
|
|
* } MIXERCONTROL;
|
|
*
|
|
* @field DWORD | cbStruct | Specifies the size, in bytes, of the
|
|
* <t MIXERCONTROL> structure. Since the <t MIXERCONTROL> structure
|
|
* is only passed as a receiving buffer referenced and described by
|
|
* the <t MIXERLINECONTROLS> structure passed to the
|
|
* <f mixerGetLineControls> function, it is not necessary for the
|
|
* calling application to initialize this member (or any other members
|
|
* of this structure). When the <f mixerGetLineControls> function
|
|
* returns, this member contains the actual size of the information
|
|
* returned by the mixer device. The returned information will never
|
|
* exceed the requested size and will never be smaller than the
|
|
* base <t MIXERCONTROL> structure.
|
|
*
|
|
* @field DWORD | dwControlID | Specifies an audio mixer defined identifier
|
|
* that uniquely refers to the control described by the <t MIXERCONTROL>
|
|
* structure. This identifier is unique only to a single mixer device
|
|
* and may be of any format that the mixer device wishes. An application
|
|
* should only use this identifier as an abstract handle. No two
|
|
* controls for a single mixer device will have the same control
|
|
* identifier under any circumstances.
|
|
*
|
|
* @field DWORD | dwControlType | Specifies the control type for this
|
|
* control. An application must use this information to display the
|
|
* appropriate control for input from the user. An application may
|
|
* also wish to display tailored graphics based on the control type or
|
|
* search for a particular control type on a specific line. If an
|
|
* application does not know about a control type, then this control
|
|
* must be ignored. There are currently seven different control type
|
|
* classifications.
|
|
*
|
|
* The control type class <cl MIXERCONTROL_CT_CLASS_CUSTOM> consists of
|
|
* the following standard control types.
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_CUSTOM><nl>
|
|
*
|
|
* The control type class <cl MIXERCONTROL_CT_CLASS_METER> consists of
|
|
* the following standard control types.
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_BOOLEANMETER><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_SIGNEDMETER><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_PEAKMETER><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER><nl>
|
|
*
|
|
* The control type class <cl MIXERCONTROL_CT_CLASS_SWITCH> consists of
|
|
* the following standard control types.
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_BUTTON><nl>
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_BOOLEAN><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_ONOFF><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_MUTE><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_MONO><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_LOUDNESS><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_STEREOENH><nl>
|
|
*
|
|
* The control type class <cl MIXERCONTROL_CT_CLASS_NUMBER> consists of
|
|
* the following standard control types.
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_SIGNED><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_DECIBELS><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_UNSIGNED><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_PERCENT><nl>
|
|
*
|
|
* The control type class <cl MIXERCONTROL_CT_CLASS_SLIDER> consists of
|
|
* the following standard control types.
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_SLIDER><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_PAN><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_QSOUNDPAN><nl>
|
|
*
|
|
* The control type class <cl MIXERCONTROL_CT_CLASS_FADER> consists of
|
|
* the following standard control types.
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_FADER><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_VOLUME><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_BASS><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_TREBLE><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_EQUALIZER><nl>
|
|
*
|
|
* The control type class <cl MIXERCONTROL_CT_CLASS_TIME> consists of
|
|
* the following standard control types.
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_MICROTIME><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_MILLITIME><nl>
|
|
*
|
|
* The control type class <cl MIXERCONTROL_CT_CLASS_LIST> consists of
|
|
* the following standard control types.
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_SINGLESELECT><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_MUX><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_MIXER><nl>
|
|
*
|
|
* @field DWORD | fdwControl | Specifies status and support flags for the
|
|
* audio mixer line control.
|
|
*
|
|
* @flag <c MIXERCONTROL_CONTROLF_UNIFORM> | Specifies that the control
|
|
* acts on all channels of a multi-channel line in a uniform fashion.
|
|
* For example, a Mute control that mutes both channels of a stereo
|
|
* line would set this flag. Most MUX and Mixer controls will also
|
|
* specify the <c MIXERCONTROL_CONTROLF_UNIFORM> flag.
|
|
*
|
|
* @flag <c MIXERCONTROL_CONTROLF_MULTIPLE> | Specifies that the control
|
|
* has two or more settings per channel. An example of a control
|
|
* that requires the multiple flag is an equalizer--each frequency
|
|
* band can be set to different values. Note that an equalizer that
|
|
* affects both channels of a stereo line in a uniform fashion will
|
|
* also set the <c MIXERCONTROL_CONTROLF_UNIFORM> flag.
|
|
*
|
|
* @flag <c MIXERCONTROL_CONTROLF_DISABLED> | Specifies that the control
|
|
* is disabled (perhaps due to other settings for the mixer hardware)
|
|
* and cannot be used. An application can read current settings from
|
|
* a disabled control, but cannot apply settings.
|
|
*
|
|
* @field DWORD | cMultipleItems | Specifies the number of items per
|
|
* channel that a <c MIXERCONTROL_CONTROLF_MULTIPLE> control contains.
|
|
* This number will always be two or greater for multiple item
|
|
* controls. If the control is not a multiple item control, this
|
|
* member will be zero and should be ignored.
|
|
*
|
|
* @field char | szShortName[<c MIXER_SHORT_NAME_CHARS>] | Specifies a short
|
|
* string that describes the <e MIXERCONTROL.dwControlID> audio mixer
|
|
* line control. This description is appropriate for using as a
|
|
* displayable label for the control that can fit in small spaces.
|
|
*
|
|
* @field char | szName[<c MIXER_LONG_NAME_CHARS>] | Specifies a string
|
|
* that describes the <e MIXERCONTROL.dwControlID> audio mixer line
|
|
* control. This description is appropriate for using as a displayable
|
|
* description for the control that is not limited by screen space.
|
|
*
|
|
* @field union | Bounds | Contains the union of boundary types.
|
|
*
|
|
* @field2 DWORD | dwMinimum | Specifies the minimum unsigned value
|
|
* for a control that has an unsigned boundary nature. Refer to the
|
|
* description for each control type to determine if this member is
|
|
* appropriate for the control. This member overlaps with the
|
|
* <e MIXERCONTROL.lMinimum> member and cannot be used in
|
|
* conjunction with that member.
|
|
*
|
|
* @field2 DWORD | dwMaximum | Specifies the maximum unsigned value
|
|
* for a control that has an unsigned boundary nature. Refer to the
|
|
* description for each control type to determine if this member is
|
|
* appropriate for the control. This member overlaps with the
|
|
* <e MIXERCONTROL.lMaximum> member and cannot be used in
|
|
* conjunction with that member.
|
|
*
|
|
* @field2 DWORD | lMinimum | Specifies the minimum signed value
|
|
* for a control that has a signed boundary nature. Refer to the
|
|
* description for each control type to determine if this member is
|
|
* appropriate for the control. This member overlaps with the
|
|
* <e MIXERCONTROL.dwMinimum> member and cannot be used in
|
|
* conjunction with that member.
|
|
*
|
|
* @field2 DWORD | lMaximum | Specifies the maximum signed value
|
|
* for a control that has a signed boundary nature. Refer to the
|
|
* description for each control type to determine if this member is
|
|
* appropriate for the control. This member overlaps with the
|
|
* <e MIXERCONTROL.dwMaximum> member and cannot be used in
|
|
* conjunction with that member.
|
|
*
|
|
* @field union | Metrics | Contains the union of boundary metrics.
|
|
*
|
|
* @field2 DWORD | cSteps | Specifies the number of discrete
|
|
* ranges within the specified <e MIXERCONTROL.Bounds> for a control.
|
|
* Refer to the description for each control type to determine if this
|
|
* member is appropriate for the control. This member overlaps with the
|
|
* other members of the <e MIXERCONTROL.Metrics> structure member and
|
|
* cannot be used in conjunction with those members.
|
|
*
|
|
* @field2 DWORD | cbCustomData | Specifies the size, in bytes,
|
|
* required to hold the state of a custom control type. This member
|
|
* is only appropriate for the <c MIXERCONTROL_CONTROLTYPE_CUSTOM>
|
|
* control type. See the description for custom control types for more
|
|
* information on the use of this member.
|
|
*
|
|
* @tagname tMIXERCONTROL
|
|
*
|
|
* @othertype MIXERCONTROL FAR * | LPMIXERCONTROL | A pointer to a
|
|
* <t MIXERCONTROL> structure.
|
|
*
|
|
* @othertype MIXERCONTROL * | PMIXERCONTROL | A pointer to a
|
|
* <t MIXERCONTROL> structure.
|
|
*
|
|
* @xref <t MIXERLINECONTROLS>, <f mixerGetLineControls>, <f mixerGetLineInfo>,
|
|
* <f mixerGetControlDetails>, <f mixerSetControlDetails>,
|
|
* <t MIXERCONTROLDETAILS>
|
|
*
|
|
**/
|
|
|
|
/*--------------------------------------------------------------------------;
|
|
*
|
|
* @doc EXTERNAL MIXER SDK STRUCTURE
|
|
*
|
|
* @types MIXERLINECONTROLS | The <t MIXERLINECONTROLS> structure references
|
|
* what controls to retrieve information on from an audio mixer line.
|
|
*
|
|
* @field DWORD | cbStruct | Specifies the size, in bytes, of the
|
|
* <t MIXERLINECONTROLS> structure. This member must be initialized
|
|
* before calling the <f mixerGetLineControls> function. The size
|
|
* specified in this member must be large enough to contain the base
|
|
* <t MIXERLINECONTROLS> structure. When the <f mixerGetLineControls>
|
|
* function returns, this member contains the actual size of the
|
|
* information returned. The returned information will never exceed
|
|
* the requested size and will never be smaller than the base
|
|
* <t MIXERLINECONTROLS> structure.
|
|
*
|
|
* @field DWORD | dwLineID | Specifies the line identifier to retrieve
|
|
* one or all controls for. This member is not used if the
|
|
* <c MIXER_GETLINECONTROLSF_ONEBYID> flag is specified for the
|
|
* <f mixerGetLineControls> function--but the mixer device will return
|
|
* this member in this case. The <e MIXERLINECONTROLS.dwControlID>
|
|
* and <e MIXERLINECONTROLS.dwControlType> members are not used when
|
|
* <c MIXER_GETLINECONTROLSF_ALL> is specified.
|
|
*
|
|
* @field DWORD | dwControlID | Specifies the control identifier of the
|
|
* control desired. This member is used with the
|
|
* <c MIXER_GETLINECONTROLSF_ONEBYID> flag for <f mixerGetLineControls>
|
|
* to retrieve the control information of the specified control.
|
|
* Note that the <e MIXERLINECONTROLS.dwLineID> member of the
|
|
* <t MIXERLINECONTROLS> structure will be returned by the mixer device
|
|
* and is not required as an input parameter. This member overlaps with
|
|
* the <e MIXERLINECONTROLS.dwControlType> member and cannot be used in
|
|
* conjunction with the <c MIXER_GETLINECONTROLSF_ONEBYTYPE> query type.
|
|
*
|
|
* @field DWORD | dwControlType | Specifies the control type of the
|
|
* control desired. This member is used with the
|
|
* <c MIXER_GETLINECONTROLSF_ONEBYTYPE> flag for <f mixerGetLineControls>
|
|
* to retrieve the first control of the specified type on the line
|
|
* specified by the <e MIXERLINECONTROLS.dwLineID> member of the
|
|
* <t MIXERLINECONTROLS> structure. This member overlaps with the
|
|
* <e MIXERLINECONTROLS.dwControlID> member and cannot be used in
|
|
* conjunction with the <c MIXER_GETLINECONTROLSF_ONEBYID> query type.
|
|
*
|
|
* @field DWORD | cControls | Specifies the number of <t MIXERCONTROL>
|
|
* structure elements to retrieve. This member must be initialized by
|
|
* the application before calling the <f mixerGetLineControls> function.
|
|
* This member may only be one (if <c MIXER_GETLINECONTROLSF_ONEBYID> or
|
|
* <c MIXER_GETLINECONTROLSF_ONEBYTYPE> is specified) or the value
|
|
* returned in the <e MIXERLINE.cControls> member of the <t MIXERLINE>
|
|
* structure returned for a line. This member cannot be zero. If a
|
|
* line specifies that it has no controls, then <f mixerGetLineControls>
|
|
* should not be called.
|
|
*
|
|
* @field DWORD | cbmxctrl | Specifies the size, in bytes, of a single
|
|
* <t MIXERCONTROL> structure. This must be at least large enough
|
|
* to hold the base <t MIXERCONTROL> structure. The total size, in
|
|
* bytes, required for the buffer pointed to by <e MIXERLINECONTROLS.pamxctrl>
|
|
* member is the product of the <e MIXERLINECONTROLS.cbmxctrl> and
|
|
* <e MIXERLINECONTROLS.cControls> members of the <t MIXERLINECONTROLS>
|
|
* structure.
|
|
*
|
|
* @field LPMIXERCONTROL | pamxctrl | Points to one or more <t MIXERCONTROL>
|
|
* structures to receive the details on the requested audio mixer line
|
|
* controls. This member may never be NULL and must be initialized before
|
|
* calling the <f mixerGetLineControls> function. Each element of the
|
|
* array of controls must be at least large enough to hold a base
|
|
* <t MIXERCONTROL> structure. The <e MIXERLINECONTROLS.cbmxctrl> member
|
|
* must specify the size, in bytes, of each element in this array. No
|
|
* initialization of the buffer pointed to by this member needs to be
|
|
* initialized by the application. All members will be filled in by
|
|
* the mixer device (including the <e MIXERCONTROL.cbStruct> member
|
|
* of each <t MIXERCONTROL> structure) upon returning successfully to
|
|
* the application.
|
|
*
|
|
* @tagname tMIXERLINECONTROLS
|
|
*
|
|
* @othertype MIXERLINECONTROLS FAR * | LPMIXERLINECONTROLS | A pointer to a
|
|
* <t MIXERLINECONTROLS> structure.
|
|
*
|
|
* @othertype MIXERLINECONTROLS * | PMIXERLINECONTROLS | A pointer to a
|
|
* <t MIXERLINECONTROLS> structure.
|
|
*
|
|
* @xref <t MIXERCONTROL>, <f mixerGetLineControls>, <f mixerGetLineInfo>,
|
|
* <f mixerGetControlDetails>, <f mixerSetControlDetails>
|
|
*
|
|
**/
|
|
|
|
/*--------------------------------------------------------------------------;
|
|
*
|
|
* @doc EXTERNAL MIXER SDK API
|
|
*
|
|
* @api MMRESULT | mixerGetLineControls | The <f mixerGetLineControls>
|
|
* function is used to retrieve one or more controls associated with
|
|
* an audio mixer device line.
|
|
*
|
|
* @parm <c HMIXEROBJ> | hmxobj | Specifies a handle to the audio mixer
|
|
* device object to get line control information from.
|
|
*
|
|
* @parm LPMIXERLINECONTROLS | pmxlc | Points to a <t MIXERLINECONTROLS>
|
|
* structure. This structure is used to reference one or more
|
|
* <t MIXERCONTROL> structures to be filled with information about the
|
|
* controls associated with a mixer line.
|
|
* See the comments for each query flag passed through <p fdwControls>
|
|
* for details on what members of the <t MIXERLINECONTROLS> structure
|
|
* that must be initialized. Note that in all cases, the
|
|
* <e MIXERLINECONTROLS.cbStruct> member of the <t MIXERLINECONTROLS>
|
|
* structure must be initialized to be the size, in bytes, of the
|
|
* <t MIXERLINECONTROLS> structure.
|
|
*
|
|
* @parm DWORD | fdwControls | Specifies flags for getting information on
|
|
* one or more control associated with a mixer line.
|
|
*
|
|
* @flag <c MIXER_GETLINECONTROLSF_ALL> | If this flag is specified,
|
|
* <p pmxlc> references a list of <t MIXERCONTROL> structures that
|
|
* will receive information on all controls associated with the
|
|
* line identified by the <e MIXERLINECONTROLS.dwLineID> member of
|
|
* the <t MIXERLINECONTROLS> structure. <e MIXERLINECONTROLS.cControls>
|
|
* must be initialized to the number of controls associated with the
|
|
* line. This number is retrieved from the <e MIXERLINE.cControls>
|
|
* member of the <t MIXERLINE> structure returned by the
|
|
* <f mixerGetLineInfo> function. <e MIXERLINECONTROLS.cbmxctrl> must
|
|
* be initialized to the size, in bytes, of a single <t MIXERCONTROL>
|
|
* structure. <e MIXERLINECONTROLS.pamxctrl> must point to
|
|
* the first <t MIXERCONTROL> structure to be filled in. Both the
|
|
* <e MIXERLINECONTROLS.dwControlID> and <e MIXERLINECONTROLS.dwControlType>
|
|
* members are ignored for this query.
|
|
*
|
|
* @flag <c MIXER_GETLINECONTROLSF_ONEBYID> | If this flag is specified,
|
|
* <p pmxlc> references a single <t MIXERCONTROL> structure that
|
|
* will receive information on the control identified by the
|
|
* <e MIXERLINECONTROLS.dwControlID> member of the <t MIXERLINECONTROLS>
|
|
* structure. <e MIXERLINECONTROLS.cControls> must be initialized to one.
|
|
* <e MIXERLINECONTROLS.cbmxctrl> must be initialized to the size, in
|
|
* bytes, of a single <t MIXERCONTROL> structure.
|
|
* <e MIXERLINECONTROLS.pamxctrl> must point to a <t MIXERCONTROL>
|
|
* structure to be filled in. Both the <e MIXERLINECONTROLS.dwLineID>
|
|
* and <e MIXERLINECONTROLS.dwControlType> members are ignored for this
|
|
* query. This query is usually used to refresh a control after
|
|
* receiving a <m MM_MIXM_CONTROL_CHANGE> control change notification
|
|
* message by the user-specified callback (see <f mixerOpen>).
|
|
*
|
|
* @flag <c MIXER_GETLINECONTROLSF_ONEBYTYPE> | If this flag is specified,
|
|
* <p pmxlc> references a single <t MIXERCONTROL> structure that
|
|
* will receive information on the fist control associated with the
|
|
* line identified by <e MIXERLINECONTROLS.dwLineID> of the type
|
|
* specified in the <e MIXERLINECONTROLS.dwControlType> member of the
|
|
* <t MIXERLINECONTROLS> structure.
|
|
* <e MIXERLINECONTROLS.cControls> must be
|
|
* initialized to one. <e MIXERLINECONTROLS.cbmxctrl> must be initialized
|
|
* to the size, in bytes, of a single <t MIXERCONTROL> structure.
|
|
* <e MIXERLINECONTROLS.pamxctrl> must point to a <t MIXERCONTROL>
|
|
* structure to be filled in. The <e MIXERLINECONTROLS.dwControlID>
|
|
* member is ignored for this query. This query can be used by an
|
|
* application to get information on single control associated with
|
|
* a line. For example, an application may only want to use a peak
|
|
* meter from a waveform output line.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_MIXER> | Specifies that <p hmxobj> is an audio
|
|
* mixer device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f mixerGetNumDevs>. This flag is
|
|
* optional.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HMIXER> | Specifies that <p hmxobj> is a mixer
|
|
* device handle returned by <f mixerOpen>. This flag is optional.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_WAVEOUT> | Specifies that <p hmxobj> is a
|
|
* waveform output device identifier in the range of zero to one less
|
|
* than the number of devices returned by <f waveOutGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HWAVEOUT> | Specifies that <p hmxobj> is a
|
|
* waveform output handle returned by <f waveOutOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_WAVEIN> | Specifies that <p hmxobj> is a
|
|
* waveform input device identifier in the range of zero to one less
|
|
* than the number of devices returned by <f waveInGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HWAVEIN> | Specifies that <p hmxobj> is a
|
|
* waveform input handle returned by <f midiInOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_MIDIOUT> | Specifies that <p hmxobj> is a MIDI
|
|
* output device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f midiOutGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HMIDIOUT> | Specifies that <p hmxobj> is a
|
|
* MIDI output handle returned by <f midiOutOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_MIDIIN> | Specifies that <p hmxobj> is a MIDI
|
|
* input device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f midiInGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HMIDIIN> | Specifies that <p hmxobj> is a MIDI
|
|
* input handle returned by <f midiInOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_AUX> | Specifies that <p hmxobj> is an
|
|
* auxiliary device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f auxGetNumDevs>.
|
|
*
|
|
* @rdesc The return value is zero if the function is successful. Otherwise,
|
|
* it returns a non-zero error number. Possible error returns include
|
|
* the following:
|
|
*
|
|
* @flag <c MMSYSERR_BADDEVICEID> | The <p hmxobj> argument specifies an
|
|
* invalid device identifier.
|
|
*
|
|
* @flag <c MMSYSERR_INVALHANDLE> | The <p hmxobj> argument specifies an
|
|
* invalid handle.
|
|
*
|
|
* @flag <c MMSYSERR_INVALFLAG> | One or more flags are invalid.
|
|
*
|
|
* @flag <c MMSYSERR_INVALPARAM> | One or more arguments passed is
|
|
* invalid.
|
|
*
|
|
* @flag <c MMSYSERR_NODRIVER> | No audio mixer device is available for
|
|
* the object specified by <p hmxobj>.
|
|
*
|
|
* @flag <c MIXERR_INVALLINE> | The audio mixer device line reference is
|
|
* invalid.
|
|
*
|
|
* @flag <c MIXERR_INVALCONTROL> | The control reference is invalid.
|
|
*
|
|
* @xref <t MIXERLINECONTROLS>, <t MIXERCONTROL>, <f mixerGetLineInfo>,
|
|
* <f mixerOpen>, <f mixerGetControlDetails>, <f mixerSetControlDetails>
|
|
*
|
|
**/
|
|
|
|
MMRESULT APIENTRY mixerGetLineControlsA(
|
|
HMIXEROBJ hmxobj,
|
|
LPMIXERLINECONTROLSA pmxlcA,
|
|
DWORD fdwControls
|
|
)
|
|
{
|
|
MIXERLINECONTROLSW mxlcW;
|
|
MMRESULT mmr;
|
|
DWORD cControls;
|
|
|
|
V_WPOINTER(pmxlcA, sizeof(DWORD), MMSYSERR_INVALPARAM);
|
|
V_WPOINTER(pmxlcA, (UINT)pmxlcA->cbStruct, MMSYSERR_INVALPARAM);
|
|
if (sizeof(MIXERLINECONTROLSA) > pmxlcA->cbStruct) {
|
|
DebugErr1(DBF_ERROR, "mixerGetLineControls: structure size too small or cbStruct not initialized (%lu).", pmxlcA->cbStruct);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
//
|
|
// Set up a MIXERCONTROLW structure and allocate space for the
|
|
// returned data
|
|
//
|
|
|
|
CopyMemory((PVOID)&mxlcW, (PVOID)pmxlcA,
|
|
FIELD_OFFSET(MIXERLINECONTROLSA, pamxctrl));
|
|
mxlcW.cbmxctrl = mxlcW.cbmxctrl + sizeof(MIXERCONTROLW) -
|
|
sizeof(MIXERCONTROLA);
|
|
|
|
//
|
|
// Work out how many controls (what a mess - why isn't the count
|
|
// ALWAYS required)!
|
|
//
|
|
|
|
switch (MIXER_GETLINECONTROLSF_QUERYMASK & fdwControls)
|
|
{
|
|
case MIXER_GETLINECONTROLSF_ONEBYID:
|
|
case MIXER_GETLINECONTROLSF_ONEBYTYPE:
|
|
cControls = 1;
|
|
break;
|
|
|
|
default:
|
|
cControls = mxlcW.cControls;
|
|
break;
|
|
}
|
|
|
|
if (cControls != 0) {
|
|
mxlcW.pamxctrl = (LPMIXERCONTROLW)
|
|
LocalAlloc(LPTR, cControls * mxlcW.cbmxctrl);
|
|
|
|
if (mxlcW.pamxctrl == NULL) {
|
|
return MMSYSERR_NOMEM;
|
|
}
|
|
|
|
} else {
|
|
mxlcW.pamxctrl = NULL;
|
|
}
|
|
|
|
//
|
|
// Call the real function
|
|
//
|
|
|
|
mmr = mixerGetLineControls(hmxobj, &mxlcW, fdwControls);
|
|
|
|
if (mmr != MMSYSERR_NOERROR) {
|
|
if (mxlcW.pamxctrl != NULL) {
|
|
LocalFree((HLOCAL)mxlcW.pamxctrl);
|
|
}
|
|
return mmr;
|
|
}
|
|
|
|
//
|
|
// The INPUT line id can be changed !!
|
|
//
|
|
|
|
pmxlcA->dwLineID = mxlcW.dwLineID;
|
|
|
|
//
|
|
// The control id can be changed !!
|
|
//
|
|
|
|
pmxlcA->dwControlID = mxlcW.dwControlID;
|
|
|
|
|
|
//
|
|
// Copy and massage the data back for the application
|
|
//
|
|
|
|
{
|
|
UINT i;
|
|
LPMIXERCONTROLA pamxctrlA;
|
|
LPMIXERCONTROLW pamxctrlW;
|
|
|
|
for (i = 0, pamxctrlA = pmxlcA->pamxctrl, pamxctrlW = mxlcW.pamxctrl;
|
|
i < cControls;
|
|
i++,
|
|
*(LPBYTE *)&pamxctrlA += pmxlcA->cbmxctrl,
|
|
*(LPBYTE *)&pamxctrlW += mxlcW.cbmxctrl
|
|
) {
|
|
|
|
|
|
CopyMemory((PVOID)pamxctrlA,
|
|
(PVOID)pamxctrlW,
|
|
FIELD_OFFSET(MIXERCONTROLA, szShortName[0]));
|
|
|
|
/*
|
|
** Set the size
|
|
*/
|
|
|
|
pamxctrlA->cbStruct = sizeof(MIXERCONTROLA);
|
|
|
|
Iwcstombs(pamxctrlA->szShortName,
|
|
pamxctrlW->szShortName,
|
|
sizeof(pamxctrlA->szShortName));
|
|
Iwcstombs(pamxctrlA->szName,
|
|
pamxctrlW->szName,
|
|
sizeof(pamxctrlA->szName));
|
|
|
|
CopyMemory((PVOID)((PBYTE)pamxctrlA +
|
|
FIELD_OFFSET(MIXERCONTROLA, Bounds.lMinimum)),
|
|
(PVOID)((PBYTE)pamxctrlW +
|
|
FIELD_OFFSET(MIXERCONTROLW, Bounds.lMinimum)),
|
|
sizeof(MIXERCONTROLW) -
|
|
FIELD_OFFSET(MIXERCONTROLW, Bounds.lMinimum));
|
|
|
|
}
|
|
}
|
|
|
|
if (mxlcW.pamxctrl != NULL) {
|
|
LocalFree((HLOCAL)mxlcW.pamxctrl);
|
|
}
|
|
return mmr;
|
|
|
|
} // mixerGetLineControlsA()
|
|
|
|
MMRESULT APIENTRY mixerGetLineControls(
|
|
HMIXEROBJ hmxobj,
|
|
LPMIXERLINECONTROLS pmxlc,
|
|
DWORD fdwControls
|
|
)
|
|
{
|
|
DWORD fdwMxObjType;
|
|
UINT uMxId;
|
|
BOOL fResource;
|
|
MMRESULT mmr;
|
|
|
|
V_DFLAGS(fdwControls, MIXER_GETLINECONTROLSF_VALID, mixerGetLineControls, MMSYSERR_INVALFLAG);
|
|
V_WPOINTER(pmxlc, sizeof(DWORD), MMSYSERR_INVALPARAM);
|
|
|
|
//
|
|
// the structure header for MIXERLINECONTROLS must be at least the
|
|
// minimum size
|
|
//
|
|
if (sizeof(MIXERLINECONTROLS) > pmxlc->cbStruct)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetLineControls: structure size too small or cbStruct not initialized (%lu).", pmxlc->cbStruct);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
V_WPOINTER(pmxlc, pmxlc->cbStruct, MMSYSERR_INVALPARAM);
|
|
|
|
if (sizeof(MIXERCONTROL) > pmxlc->cbmxctrl)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetLineControls: structure size too small or cbmxctrl not initialized (%lu).", pmxlc->cbmxctrl);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
//
|
|
//
|
|
//
|
|
switch (MIXER_GETLINECONTROLSF_QUERYMASK & fdwControls)
|
|
{
|
|
case MIXER_GETLINECONTROLSF_ALL:
|
|
if (0 == pmxlc->cControls)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetLineControls: cControls cannot be zero.");
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
|
|
pmxlc->dwControlID = (DWORD)-1L;
|
|
break;
|
|
|
|
case MIXER_GETLINECONTROLSF_ONEBYID:
|
|
pmxlc->dwLineID = (DWORD)-1L;
|
|
|
|
// -- fall through --
|
|
|
|
case MIXER_GETLINECONTROLSF_ONEBYTYPE:
|
|
pmxlc->cControls = (DWORD)1;
|
|
break;
|
|
|
|
default:
|
|
DebugErr1(DBF_ERROR, "mixerGetLineControls: invalid query flags (%.08lXh).",
|
|
MIXER_GETLINECONTROLSF_QUERYMASK & fdwControls);
|
|
return (MMSYSERR_INVALFLAG);
|
|
}
|
|
|
|
V_WPOINTER(pmxlc->pamxctrl, pmxlc->cControls * pmxlc->cbmxctrl, MMSYSERR_INVALPARAM);
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
fdwMxObjType = (MIXER_OBJECTF_TYPEMASK & fdwControls);
|
|
|
|
fResource = FALSE;
|
|
|
|
AcquireHandleListResourceShared();
|
|
|
|
// Checking for the type of mixer object. If it is a non-mixer type
|
|
// calling IMixerMesssageID (called by IMixerGetID) with the shared
|
|
// resource will deadlock.
|
|
if ((MIXER_OBJECTF_MIXER == fdwMxObjType) ||
|
|
(MIXER_OBJECTF_HMIXER == fdwMxObjType))
|
|
{
|
|
if (BAD_HANDLE(hmxobj, TYPE_MIXER))
|
|
{
|
|
ReleaseHandleListResource();
|
|
}
|
|
else
|
|
{
|
|
fResource = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ReleaseHandleListResource();
|
|
}
|
|
|
|
mmr = IMixerGetID(hmxobj, &uMxId, NULL, fdwMxObjType);
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
{
|
|
if (fResource)
|
|
ReleaseHandleListResource();
|
|
return (mmr);
|
|
}
|
|
|
|
if ((MIXER_OBJECTF_MIXER == fdwMxObjType) ||
|
|
(MIXER_OBJECTF_HMIXER == fdwMxObjType))
|
|
{
|
|
//
|
|
// if a mixer device id was passed, then null hmx so we use the
|
|
// correct message sender below
|
|
//
|
|
if ((UINT_PTR)hmxobj == uMxId)
|
|
hmxobj = NULL;
|
|
}
|
|
else
|
|
{
|
|
hmxobj = NULL;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
if (NULL != hmxobj)
|
|
{
|
|
mmr = (MMRESULT)IMixerMessageHandle((HMIXER)hmxobj,
|
|
MXDM_GETLINECONTROLS,
|
|
(DWORD_PTR)pmxlc,
|
|
fdwControls);
|
|
}
|
|
else
|
|
{
|
|
mmr = (MMRESULT)IMixerMessageId(uMxId,
|
|
MXDM_GETLINECONTROLS,
|
|
(DWORD_PTR)pmxlc,
|
|
fdwControls);
|
|
}
|
|
|
|
return (mmr);
|
|
} // mixerGetLineControls()
|
|
|
|
|
|
/*--------------------------------------------------------------------------;
|
|
*
|
|
* @doc EXTERNAL MIXER SDK STRUCTURE
|
|
*
|
|
* @types MIXERCONTROLDETAILS_LISTTEXT | The <t MIXERCONTROLDETAILS_LISTTEXT>
|
|
* structure is used to get list text, label text, and/or band range
|
|
* information for multiple item controls. This structure is only used
|
|
* in conjunction with the <c MIXER_GETCONTROLDETAILSF_LISTTEXT> flag
|
|
* on the <f mixerGetControlDetails> function.
|
|
*
|
|
* @field DWORD | dwParam1 | Specifies the first 32 bit control type
|
|
* specific value. Refer to the description of the multiple item control
|
|
* type for information on what this value represents for the given
|
|
* control.
|
|
*
|
|
* @field DWORD | dwParam1 | Specifies the second 32 bit control type
|
|
* specific value. Refer to the description of the multiple item control
|
|
* type for information on what this value represents for the given
|
|
* control.
|
|
*
|
|
* @field char | szName[<c MIXER_LONG_NAME_CHARS>] | Specifies a name that
|
|
* describes a single item in a multiple item control. This text can
|
|
* be used as a label or item text depending on the specific control
|
|
* type.
|
|
*
|
|
* @comm The following standard control types use the
|
|
* <t MIXERCONTROLDETAILS_LISTTEXT> structure for getting the item text
|
|
* descriptions on multiple item controls:
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_EQUALIZER><nl>
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_SINGLESELECT><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_MUX><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_MIXER><nl>
|
|
*
|
|
* @tagname tMIXERCONTROLDETAILS_LISTTEXT
|
|
*
|
|
* @othertype MIXERCONTROLDETAILS_LISTTEXT FAR * | LPMIXERCONTROLDETAILS_LISTTEXT |
|
|
* A pointer to a <t MIXERCONTROLDETAILS_LISTTEXT> structure.
|
|
*
|
|
* @othertype MIXERCONTROLDETAILS_LISTTEXT * | PMIXERCONTROLDETAILS_LISTTEXT |
|
|
* A pointer to a <t MIXERCONTROLDETAILS_LISTTEXT> structure.
|
|
*
|
|
* @xref <t MIXERCONTROLDETAILS_UNSIGNED>, <t MIXERCONTROLDETAILS_SIGNED>,
|
|
* <t MIXERCONTROLDETAILS_BOOLEAN>, <f mixerGetControlDetails>,
|
|
* <f mixerSetControlDetails>, <t MIXERCONTROL>
|
|
*
|
|
**/
|
|
|
|
/*--------------------------------------------------------------------------;
|
|
*
|
|
* @doc EXTERNAL MIXER SDK STRUCTURE
|
|
*
|
|
* @types MIXERCONTROLDETAILS_BOOLEAN | The <t MIXERCONTROLDETAILS_BOOLEAN>
|
|
* structure is used to get and set Boolean type control details for
|
|
* an audio mixer control. Refer to the control type description for
|
|
* the desired control to determine what details structure to use.
|
|
*
|
|
* @field LONG | fValue | Specifies the Boolean value for a single item
|
|
* or channel. This value is assumed to zero for a 'FALSE' state (for
|
|
* example, off or disabled). This value is assumed to be non-zero
|
|
* for a 'TRUE' state (for example, on or enabled).
|
|
*
|
|
* @comm The following standard control types use the
|
|
* <t MIXERCONTROLDETAILS_BOOLEAN> structure for getting and setting
|
|
* details:
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_BOOLEANMETER><nl>
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_BUTTON><nl>
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_BOOLEAN><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_ONOFF><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_MUTE><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_MONO><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_LOUDNESS><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_STEREOENH><nl>
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_SINGLESELECT><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_MUX><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_MIXER><nl>
|
|
*
|
|
* @tagname tMIXERCONTROLDETAILS_BOOLEAN
|
|
*
|
|
* @othertype MIXERCONTROLDETAILS_BOOLEAN FAR * | LPMIXERCONTROLDETAILS_BOOLEAN |
|
|
* A pointer to a <t MIXERCONTROLDETAILS_BOOLEAN> structure.
|
|
*
|
|
* @othertype MIXERCONTROLDETAILS_BOOLEAN * | PMIXERCONTROLDETAILS_BOOLEAN |
|
|
* A pointer to a <t MIXERCONTROLDETAILS_BOOLEAN> structure.
|
|
*
|
|
* @xref <t MIXERCONTROLDETAILS_UNSIGNED>, <t MIXERCONTROLDETAILS_SIGNED>,
|
|
* <t MIXERCONTROLDETAILS_LISTTEXT>, <f mixerGetControlDetails>,
|
|
* <f mixerSetControlDetails>, <t MIXERCONTROL>
|
|
*
|
|
**/
|
|
|
|
/*--------------------------------------------------------------------------;
|
|
*
|
|
* @doc EXTERNAL MIXER SDK STRUCTURE
|
|
*
|
|
* @types MIXERCONTROLDETAILS_SIGNED | The <t MIXERCONTROLDETAILS_SIGNED>
|
|
* structure is used to get and set signed type control details for
|
|
* an audio mixer control. Refer to the control type description for
|
|
* the desired control to determine what details structure to use.
|
|
*
|
|
* @field LONG | lValue | Specifies a signed integer value for a single
|
|
* item or channel. This value must be inclusively within the bounds
|
|
* given in the <e MIXERCONTROL.Bounds> structure member of the
|
|
* <t MIXERCONTROL> structure for signed integer controls.
|
|
*
|
|
* @comm The following standard control types use the
|
|
* <t MIXERCONTROLDETAILS_SIGNED> structure for getting and setting
|
|
* details:
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_SIGNEDMETER><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_PEAKMETER><nl>
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_SIGNED><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_DECIBELS><nl>
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_SLIDER><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_PAN><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_QSOUNDPAN><nl>
|
|
*
|
|
* @tagname tMIXERCONTROLDETAILS_SIGNED
|
|
*
|
|
* @othertype MIXERCONTROLDETAILS_SIGNED FAR * | LPMIXERCONTROLDETAILS_SIGNED |
|
|
* A pointer to a <t MIXERCONTROLDETAILS_SIGNED> structure.
|
|
*
|
|
* @othertype MIXERCONTROLDETAILS_SIGNED * | PMIXERCONTROLDETAILS_SIGNED |
|
|
* A pointer to a <t MIXERCONTROLDETAILS_SIGNED> structure.
|
|
*
|
|
* @xref <t MIXERCONTROLDETAILS_UNSIGNED>, <t MIXERCONTROLDETAILS_BOOLEAN>,
|
|
* <t MIXERCONTROLDETAILS_LISTTEXT>, <f mixerGetControlDetails>,
|
|
* <f mixerSetControlDetails>, <t MIXERCONTROL>
|
|
*
|
|
**/
|
|
|
|
/*--------------------------------------------------------------------------;
|
|
*
|
|
* @doc EXTERNAL MIXER SDK STRUCTURE
|
|
*
|
|
* @types MIXERCONTROLDETAILS_UNSIGNED | The <t MIXERCONTROLDETAILS_UNSIGNED>
|
|
* structure is used to get and set unsigned type control details for
|
|
* an audio mixer control. Refer to the control type description for
|
|
* the desired control to determine what details structure to use.
|
|
*
|
|
* @field DWORD | dwValue | Specifies an unsigned integer value for a single
|
|
* item or channel. This value must be inclusively within the bounds
|
|
* given in the <e MIXERCONTROL.Bounds> structure member of the
|
|
* <t MIXERCONTROL> structure for unsigned integer controls.
|
|
*
|
|
* @comm The following standard control types use the
|
|
* <t MIXERCONTROLDETAILS_UNSIGNED> structure for getting and setting
|
|
* details:
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_UNSIGNEDMETER><nl>
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_UNSIGNED><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_PERCENT><nl>
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_FADER><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_VOLUME><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_BASS><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_TREBLE><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_EQUALIZER><nl>
|
|
*
|
|
* <c MIXERCONTROL_CONTROLTYPE_MICROTIME><nl>
|
|
* <c MIXERCONTROL_CONTROLTYPE_MILLITIME><nl>
|
|
*
|
|
* @tagname tMIXERCONTROLDETAILS_UNSIGNED
|
|
*
|
|
* @othertype MIXERCONTROLDETAILS_UNSIGNED FAR * | LPMIXERCONTROLDETAILS_UNSIGNED |
|
|
* A pointer to a <t MIXERCONTROLDETAILS_UNSIGNED> structure.
|
|
*
|
|
* @othertype MIXERCONTROLDETAILS_UNSIGNED * | PMIXERCONTROLDETAILS_UNSIGNED |
|
|
* A pointer to a <t MIXERCONTROLDETAILS_UNSIGNED> structure.
|
|
*
|
|
* @xref <t MIXERCONTROLDETAILS_SIGNED>, <t MIXERCONTROLDETAILS_BOOLEAN>,
|
|
* <t MIXERCONTROLDETAILS_LISTTEXT>, <f mixerGetControlDetails>,
|
|
* <f mixerSetControlDetails>, <t MIXERCONTROL>
|
|
*
|
|
**/
|
|
|
|
|
|
/*--------------------------------------------------------------------------;
|
|
*
|
|
* @doc EXTERNAL MIXER SDK STRUCTURE
|
|
*
|
|
* @types MIXERCONTROLDETAILS | The <t MIXERCONTROLDETAILS> structure
|
|
* references control detail structures to retrieve or set state
|
|
* information of an audio mixer control. All members of this structure
|
|
* must be initialized before calling the <f mixerGetControlDetails>
|
|
* and <f mixerSetControlDetails> functions.
|
|
*
|
|
* @field DWORD | cbStruct | Specifies the size, in bytes, of the
|
|
* <t MIXERCONTROLDETAILS> structure. This member must be initialized
|
|
* before calling the <f mixerGetControlDetails> and
|
|
* <f mixerSetControlDetails> functions. The size specified in this
|
|
* member must be large enough to contain the base
|
|
* <t MIXERCONTROLDETAILS> structure. When the <f mixerGetControlDetails>
|
|
* function returns, this member contains the actual size of the
|
|
* information returned. The returned information will never exceed
|
|
* the requested size and will never be smaller than the base
|
|
* <t MIXERCONTROLDETAILS> structure.
|
|
*
|
|
* @field DWORD | dwControlID | Specifies the control identifier to get or
|
|
* set details on. This member must always be initialized before calling
|
|
* the <f mixerGetControlDetails> and <f mixerSetControlDetails>
|
|
* functions.
|
|
*
|
|
* @field DWORD | cChannels | Specifies the number of channels to get or
|
|
* set details for. This member can be one of the following values for a
|
|
* control.
|
|
*
|
|
* 1. If the details for the control are expected on all channels for
|
|
* a line, then this member must be equal the <e MIXERLINE.cChannels>
|
|
* member of the <t MIXERLINE> structure.
|
|
*
|
|
* 2. If the control is a <c MIXERCONTROL_CONTROLF_UNIFORM> control, then
|
|
* this member must be set to one.
|
|
*
|
|
* 3. If the control is not uniform, but the application wishes to
|
|
* get and set all channels as if they were uniform, then this member
|
|
* should be set to one.
|
|
*
|
|
* 4. If the control is a <c MIXERCONTROL_CONTROLTYPE_CUSTOM> control,
|
|
* then this member must be zero.
|
|
*
|
|
* An application is not allowed to specify any value that comes
|
|
* between one and the number of channels for the line. For example,
|
|
* specifying two or three for a four channel line is not valid.
|
|
* This member can never be zero for non-custom control types.
|
|
*
|
|
* @field DWORD | cMultipleItems | Specifies the number of multiple items
|
|
* per channel to get or set details for. This member can be one of
|
|
* the following values for a control.
|
|
*
|
|
* 1. If the control is not a <c MIXERCONTROL_CONTROLF_MULTIPLE> control,
|
|
* then this member must be zero.
|
|
*
|
|
* 2. If the control is a <c MIXERCONTROL_CONTROLF_MULTIPLE> control,
|
|
* then this member must be equal to the <e MIXERCONTROL.cMultipleItems>
|
|
* member of the <t MIXERCONTROL> structure.
|
|
*
|
|
* 3. If the control is a <c MIXERCONTROL_CONTROLTYPE_CUSTOM> control,
|
|
* then this member must be zero unless the
|
|
* <c MIXER_SETCONTROLDETAILSF_CUSTOM> flag is specified for the
|
|
* <f mixerSetControlDetails> function. In this case, the
|
|
* <e MIXERCONTROLDETAILS.cMultipleItems> member overlaps with the
|
|
* <e MIXERCONTROLDETAILS.hwndOwner> member and is therefore the value
|
|
* of the window handle.
|
|
*
|
|
* An application is not allowed to specify any value other than the
|
|
* value specified in the <e MIXERCONTROL.cMultipleItems> member of
|
|
* the <t MIXERCONTROL> structure for a <c MIXERCONTROL_CONTROLF_MULTIPLE>
|
|
* control.
|
|
*
|
|
* @field DWORD | cbDetails | Specifies the size, in bytes, of a single
|
|
* details structure. This size must be the exact size of the correct
|
|
* details structure. There are currently four different details
|
|
* structures:
|
|
*
|
|
* @flag <t MIXERCONTROLDETAILS_UNSIGNED> | Defines an unsigned
|
|
* value for a mixer line control.
|
|
*
|
|
* @flag <t MIXERCONTROLDETAILS_SIGNED> | Defines an signed
|
|
* value for a mixer line control.
|
|
*
|
|
* @flag <t MIXERCONTROLDETAILS_BOOLEAN> | Defines a Boolean
|
|
* value for a mixer line control.
|
|
*
|
|
* @flag <t MIXERCONTROLDETAILS_LISTTEXT> | Defines a list text
|
|
* buffer for a mixer line control.
|
|
*
|
|
* Refer to the description of the control type for information on what
|
|
* details structure is appropriate for a specific control.
|
|
*
|
|
* If the control is a <c MIXERCONTROL_CONTROLTYPE_CUSTOM> control,
|
|
* then this member must be equal to the <e MIXERCONTROL.cbCustomData>
|
|
* member of the <t MIXERCONTROL> structure.
|
|
*
|
|
* @field LPVOID | paDetails | Points to an array of one or more details
|
|
* structures to get or set details for the specified control in. The
|
|
* required size for this buffer is computed as follows:
|
|
*
|
|
* 1. For controls that are not <c MIXERCONTROL_CONTROLF_MULTIPLE> types,
|
|
* the size of this buffer is the product of the
|
|
* <e MIXERCONTROLDETAILS.cChannels> and <e MIXERCONTROLDETAILS.cbDetails>
|
|
* members of the <t MIXERCONTROLDETAILS> structure.
|
|
*
|
|
* 2. For controls that are <c MIXERCONTROL_CONTROLF_MULTIPLE> types,
|
|
* the size of this buffer is the product of the
|
|
* <e MIXERCONTROLDETAILS.cChannels>, <e MIXERCONTROLDETAILS.cMultipleItems>
|
|
* and <e MIXERCONTROLDETAILS.cbDetails> members of the
|
|
* <t MIXERCONTROLDETAILS> structure.
|
|
*
|
|
* The layout of the details elements in this array are as follows:
|
|
*
|
|
* 1. For controls that are not <c MIXERCONTROL_CONTROLF_MULTIPLE> types,
|
|
* each element index is equivalent to the zero based channel that it
|
|
* affects. That is, <e MIXERCONTROLDETAILS.paDetails>[0] is for the
|
|
* left channel, <e MIXERCONTROLDETAILS.paDetails>[1] is for the
|
|
* right channel.
|
|
*
|
|
* 2. For controls that are <c MIXERCONTROL_CONTROLF_MULTIPLE> types,
|
|
* the array can be thought of as a two dimensional array that is
|
|
* 'channel major'. That is, all multiple items for the left channel
|
|
* are given, then all multiple items for the right channel, etc.
|
|
*
|
|
* If the control is a <c MIXERCONTROL_CONTROLTYPE_CUSTOM> control,
|
|
* then this member must point to a buffer that is at least large
|
|
* enough to hold the size, in bytes, specified by the
|
|
* <e MIXERCONTROL.cbCustomData> member of the <t MIXERCONTROL>
|
|
* structure.
|
|
*
|
|
* @tagname tMIXERCONTROLDETAILS
|
|
*
|
|
* @othertype MIXERCONTROLDETAILS FAR * | LPMIXERCONTROLDETAILS | A pointer
|
|
* to a <t MIXERCONTROLDETAILS> structure.
|
|
*
|
|
* @othertype MIXERCONTROLDETAILS * | PMIXERCONTROLDETAILS | A pointer
|
|
* to a <t MIXERCONTROLDETAILS> structure.
|
|
*
|
|
* @ex So the following example shows how to address a single item in a
|
|
* multiple item control for using the <t MIXERCONTROLDETAILS_SIGNED>
|
|
* details structure. |
|
|
* {
|
|
* MIXERCONTROLDETAILS mxcd;
|
|
* PMIXERCONTROLDETAILS_SIGNED pamxcd_s;
|
|
* PMIXERCONTROLDETAILS_SIGNED pmxcd_s;
|
|
*
|
|
* //
|
|
* // 'mxcd' is assumed to be a valid MIXERCONTROLDETAILS
|
|
* // structure.
|
|
* //
|
|
* // 'channel' is assumed to be a valid channel ranging from zero
|
|
* // to one less than the number of channels available for the
|
|
* // signed control.
|
|
* //
|
|
* // 'item' is assumed to be a valid item index ranging from zero
|
|
* // to one less than the number of 'multiple items' stored in
|
|
* // the variable called 'cMultipleItems'.
|
|
* //
|
|
* pamxcd_s = (PMIXERCONTROLDETAILS_SIGNED)mxcd.paDetails;
|
|
* pmxcd_s = &pamxcd_s[(channel * cMultipleItems) + item];
|
|
* }
|
|
*
|
|
* @xref <f mixerGetLineControls>, <f mixerGetControlDetails>,
|
|
* <f mixerSetControlDetails>, <t MIXERCONTROL>
|
|
*
|
|
**/
|
|
|
|
/*--------------------------------------------------------------------------;
|
|
*
|
|
* @doc EXTERNAL MIXER SDK API
|
|
*
|
|
* @api MMRESULT | mixerGetControlDetails | The <f mixerGetControlDetails>
|
|
* function is used to retrieve details on a single control associated
|
|
* with an audio mixer device line.
|
|
*
|
|
* @parm <c HMIXEROBJ> | hmxobj | Specifies a handle to the audio mixer
|
|
* device object to get control details for.
|
|
*
|
|
* @parm LPMIXERCONTROLDETAILS | pmxcd | Points to a <t MIXERCONTROLDETAILS>
|
|
* structure. This structure is used to reference control detail
|
|
* structures to be filled with state information about the control.
|
|
* See the comments for each query flag passed through <p fdwDetails>
|
|
* for details on what members of the <t MIXERCONTROLDETAILS> structure
|
|
* must be initialized before calling the <f mixerGetControlDetails>
|
|
* function. Note that in all cases, the <e MIXERCONTROLDETAILS.cbStruct>
|
|
* member of the <t MIXERCONTROLDETAILS> structure must be initialized
|
|
* to be the size, in bytes, of the <t MIXERCONTROLDETAILS> structure.
|
|
*
|
|
* @parm DWORD | fdwDetails | Specifies flags for getting details on
|
|
* a control.
|
|
*
|
|
* @flag <c MIXER_GETCONTROLDETAILSF_VALUE> | If this flag is specified,
|
|
* the application is interested in getting the current value(s) for a
|
|
* control. The <e MIXERCONTROLDETAILS.paDetails> member of the
|
|
* <t MIXERCONTROLDETAILS> points to one or more details structures of
|
|
* the correct type for the control type. Refer to the description of the
|
|
* <t MIXERCONTROLDETAILS> structure for information on what each member
|
|
* of this structure must be initialized before calling the
|
|
* <f mixerGetControlDetails> function.
|
|
*
|
|
* @flag <c MIXER_GETCONTROLDETAILSF_LISTTEXT> | If this flag is specified,
|
|
* the <e MIXERCONTROLDETAILS.paDetails> member of the <t MIXERCONTROLDETAILS>
|
|
* structure points to one or more <t MIXERCONTROLDETAILS_LISTTEXT>
|
|
* structures to receive text labels for multiple item controls. Note
|
|
* that an application must get all list text items for a multiple item
|
|
* control at once. Refer to the description of the <t MIXERCONTROLDETAILS>
|
|
* structure for information on what each member of this structure must
|
|
* be initialized before calling the <f mixerGetControlDetails> function.
|
|
* This flag cannot be used with <c MIXERCONTROL_CONTROLTYPE_CUSTOM>
|
|
* controls.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_MIXER> | Specifies that <p hmxobj> is an audio
|
|
* mixer device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f mixerGetNumDevs>. This flag is
|
|
* optional.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HMIXER> | Specifies that <p hmxobj> is a mixer
|
|
* device handle returned by <f mixerOpen>. This flag is optional.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_WAVEOUT> | Specifies that <p hmxobj> is a
|
|
* waveform output device identifier in the range of zero to one less
|
|
* than the number of devices returned by <f waveOutGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HWAVEOUT> | Specifies that <p hmxobj> is a
|
|
* waveform output handle returned by <f waveOutOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_WAVEIN> | Specifies that <p hmxobj> is a
|
|
* waveform input device identifier in the range of zero to one less
|
|
* than the number of devices returned by <f waveInGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HWAVEIN> | Specifies that <p hmxobj> is a
|
|
* waveform input handle returned by <f midiInOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_MIDIOUT> | Specifies that <p hmxobj> is a MIDI
|
|
* output device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f midiOutGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HMIDIOUT> | Specifies that <p hmxobj> is a
|
|
* MIDI output handle returned by <f midiOutOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_MIDIIN> | Specifies that <p hmxobj> is a MIDI
|
|
* input device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f midiInGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HMIDIIN> | Specifies that <p hmxobj> is a MIDI
|
|
* input handle returned by <f midiInOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_AUX> | Specifies that <p hmxobj> is an
|
|
* auxiliary device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f auxGetNumDevs>.
|
|
*
|
|
* @rdesc The return value is zero if the function is successful. Otherwise,
|
|
* it returns a non-zero error number. Possible error returns include
|
|
* the following:
|
|
*
|
|
* @flag <c MMSYSERR_BADDEVICEID> | The <p hmxobj> argument specifies an
|
|
* invalid device identifier.
|
|
*
|
|
* @flag <c MMSYSERR_INVALHANDLE> | The <p hmxobj> argument specifies an
|
|
* invalid handle.
|
|
*
|
|
* @flag <c MMSYSERR_INVALFLAG> | One or more flags are invalid.
|
|
*
|
|
* @flag <c MMSYSERR_INVALPARAM> | One or more arguments passed is
|
|
* invalid.
|
|
*
|
|
* @flag <c MMSYSERR_NODRIVER> | No audio mixer device is available for
|
|
* the object specified by <p hmxobj>.
|
|
*
|
|
* @flag <c MIXERR_INVALCONTROL> | The control reference is invalid.
|
|
*
|
|
* @xref <t MIXERCONTROLDETAILS>, <t MIXERCONTROL>, <f mixerGetLineControls>,
|
|
* <f mixerOpen>, <f mixerSetControlDetails>
|
|
*
|
|
**/
|
|
|
|
MMRESULT APIENTRY mixerGetControlDetailsA(
|
|
HMIXEROBJ hmxobj,
|
|
LPMIXERCONTROLDETAILS pmxcd,
|
|
DWORD fdwDetails
|
|
)
|
|
{
|
|
MIXERCONTROLDETAILS mxcd;
|
|
MMRESULT mmr;
|
|
int cDetails;
|
|
|
|
//
|
|
// Everything is OK unless it's MIXER_GETCONTROLDETAILSF_LISTTEXT
|
|
//
|
|
|
|
if ((MIXER_GETCONTROLDETAILSF_QUERYMASK & fdwDetails) !=
|
|
MIXER_GETCONTROLDETAILSF_LISTTEXT) {
|
|
return mixerGetControlDetails(hmxobj, pmxcd, fdwDetails);
|
|
}
|
|
|
|
V_WPOINTER(pmxcd, sizeof(DWORD), MMSYSERR_INVALPARAM);
|
|
|
|
//
|
|
// the structure header for MIXERCONTROLDETAILS must be at least the
|
|
// minimum size
|
|
//
|
|
if (sizeof(MIXERCONTROLDETAILS) > pmxcd->cbStruct)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetControlDetails: structure size too small or cbStruct not initialized (%lu).", pmxcd->cbStruct);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
V_WPOINTER(pmxcd, pmxcd->cbStruct, MMSYSERR_INVALPARAM);
|
|
|
|
if (sizeof(MIXERCONTROLDETAILS_LISTTEXTA) < pmxcd->cbDetails) {
|
|
DebugErr1(DBF_ERROR, "mixerGetControlDetails: structure size too small or cbDetails not initialized for _LISTTEXT (%lu).", pmxcd->cbDetails);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
//
|
|
// Allocate space for the return structure.
|
|
//
|
|
|
|
mxcd = *pmxcd;
|
|
cDetails = pmxcd->cChannels * pmxcd->cMultipleItems;
|
|
|
|
mxcd.paDetails =
|
|
(PVOID)LocalAlloc(LPTR, cDetails *
|
|
sizeof(MIXERCONTROLDETAILS_LISTTEXTW));
|
|
|
|
mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXTW);
|
|
|
|
if (mxcd.paDetails == NULL) {
|
|
return MMSYSERR_NOMEM;
|
|
}
|
|
|
|
|
|
//
|
|
// Call the UNICODE version
|
|
//
|
|
|
|
mmr = mixerGetControlDetails(hmxobj, &mxcd, fdwDetails);
|
|
|
|
if (mmr != MMSYSERR_NOERROR) {
|
|
LocalFree((HLOCAL)(mxcd.paDetails));
|
|
return mmr;
|
|
}
|
|
|
|
//
|
|
// Copy the return data back
|
|
//
|
|
|
|
{
|
|
int i;
|
|
PMIXERCONTROLDETAILS_LISTTEXTW pDetailsW;
|
|
PMIXERCONTROLDETAILS_LISTTEXTA pDetailsA;
|
|
|
|
for (i = 0,
|
|
pDetailsW = (PMIXERCONTROLDETAILS_LISTTEXTW)mxcd.paDetails,
|
|
pDetailsA = (PMIXERCONTROLDETAILS_LISTTEXTA)pmxcd->paDetails;
|
|
|
|
i < cDetails;
|
|
|
|
i++,
|
|
pDetailsW++,
|
|
*(LPBYTE *)&pDetailsA += pmxcd->cbDetails)
|
|
{
|
|
pDetailsA->dwParam1 = pDetailsW->dwParam1;
|
|
pDetailsA->dwParam2 = pDetailsW->dwParam2;
|
|
Iwcstombs(pDetailsA->szName, pDetailsW->szName,
|
|
sizeof(pDetailsA->szName));
|
|
}
|
|
}
|
|
|
|
LocalFree((HLOCAL)mxcd.paDetails);
|
|
|
|
return mmr;
|
|
|
|
} // mixerGetControlDetailsA()
|
|
|
|
MMRESULT APIENTRY mixerGetControlDetails(
|
|
HMIXEROBJ hmxobj,
|
|
LPMIXERCONTROLDETAILS pmxcd,
|
|
DWORD fdwDetails
|
|
)
|
|
{
|
|
DWORD fdwMxObjType;
|
|
MMRESULT mmr;
|
|
UINT uMxId;
|
|
UINT cDetails;
|
|
BOOL fResource;
|
|
|
|
V_DFLAGS(fdwDetails, MIXER_GETCONTROLDETAILSF_VALID, mixerGetControlDetails, MMSYSERR_INVALFLAG);
|
|
V_WPOINTER(pmxcd, sizeof(DWORD), MMSYSERR_INVALPARAM);
|
|
|
|
//
|
|
// the structure header for MIXERCONTROLDETAILS must be at least the
|
|
// minimum size
|
|
//
|
|
if (sizeof(MIXERCONTROLDETAILS) > pmxcd->cbStruct)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetControlDetails: structure size too small or cbStruct not initialized (%lu).", pmxcd->cbStruct);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
V_WPOINTER(pmxcd, pmxcd->cbStruct, MMSYSERR_INVALPARAM);
|
|
|
|
|
|
switch (MIXER_GETCONTROLDETAILSF_QUERYMASK & fdwDetails)
|
|
{
|
|
case MIXER_GETCONTROLDETAILSF_VALUE:
|
|
//
|
|
// if both cChannels and cMultipleItems are zero, it is a
|
|
// custom control
|
|
//
|
|
if ((0 == pmxcd->cChannels) && (0 == pmxcd->cMultipleItems))
|
|
{
|
|
if (0 == pmxcd->cbDetails)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetControlDetails: cbDetails cannot be zero.");
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
V_WPOINTER(pmxcd->paDetails, pmxcd->cbDetails, MMSYSERR_INVALPARAM);
|
|
|
|
}
|
|
else
|
|
{
|
|
if (0 == pmxcd->cChannels)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetControlDetails: cChannels for _VALUE cannot be zero.");
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
|
|
if (pmxcd->cbDetails < sizeof(MIXERCONTROLDETAILS_SIGNED))
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetControlDetails: structure size too small or cbDetails not initialized (%lu).", pmxcd->cbDetails);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
cDetails = (UINT)pmxcd->cChannels;
|
|
if (0 != pmxcd->cMultipleItems)
|
|
{
|
|
cDetails *= (UINT)pmxcd->cMultipleItems;
|
|
}
|
|
|
|
V_WPOINTER(pmxcd->paDetails, cDetails * pmxcd->cbDetails, MMSYSERR_INVALPARAM);
|
|
}
|
|
break;
|
|
|
|
case MIXER_GETCONTROLDETAILSF_LISTTEXT:
|
|
if (0 == pmxcd->cChannels)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetControlDetails: cChannels for _LISTTEXT cannot be zero.");
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
if (2 > pmxcd->cMultipleItems)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerGetControlDetails: cMultipleItems for _LISTTEXT must be 2 or greater.");
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
if (pmxcd->cbDetails < sizeof(MIXERCONTROLDETAILS_LISTTEXT))
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerGetControlDetails: structure size too small or cbDetails not initialized (%lu).", pmxcd->cbDetails);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
cDetails = (UINT)pmxcd->cChannels * (UINT)pmxcd->cMultipleItems;
|
|
V_WPOINTER(pmxcd->paDetails, cDetails * pmxcd->cbDetails, MMSYSERR_INVALPARAM);
|
|
break;
|
|
|
|
default:
|
|
DebugErr1(DBF_ERROR, "mixerGetControlDetails: invalid query flags (%.08lXh).",
|
|
MIXER_GETCONTROLDETAILSF_QUERYMASK & fdwDetails);
|
|
return (MMSYSERR_INVALFLAG);
|
|
}
|
|
|
|
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
//
|
|
//
|
|
//
|
|
fdwMxObjType = (MIXER_OBJECTF_TYPEMASK & fdwDetails);
|
|
|
|
fResource = FALSE;
|
|
|
|
AcquireHandleListResourceShared();
|
|
|
|
// Checking for the type of mixer object. If it is a non-mixer type
|
|
// calling IMixerMesssageID (called by IMixerGetID) with the shared
|
|
// resource will deadlock.
|
|
if ((MIXER_OBJECTF_MIXER == fdwMxObjType) ||
|
|
(MIXER_OBJECTF_HMIXER == fdwMxObjType))
|
|
{
|
|
if (BAD_HANDLE(hmxobj, TYPE_MIXER))
|
|
{
|
|
ReleaseHandleListResource();
|
|
}
|
|
else
|
|
{
|
|
fResource = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ReleaseHandleListResource();
|
|
}
|
|
|
|
mmr = IMixerGetID(hmxobj, &uMxId, NULL, fdwMxObjType);
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
{
|
|
if (fResource)
|
|
ReleaseHandleListResource();
|
|
return (mmr);
|
|
}
|
|
|
|
if ((MIXER_OBJECTF_MIXER == fdwMxObjType) ||
|
|
(MIXER_OBJECTF_HMIXER == fdwMxObjType))
|
|
{
|
|
//
|
|
// if a mixer device id was passed, then null hmx so we use the
|
|
// correct message sender below
|
|
//
|
|
if ((UINT_PTR)hmxobj == uMxId)
|
|
hmxobj = NULL;
|
|
}
|
|
else
|
|
{
|
|
hmxobj = NULL;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
if (NULL != hmxobj)
|
|
{
|
|
mmr = (MMRESULT)IMixerMessageHandle((HMIXER)hmxobj,
|
|
MXDM_GETCONTROLDETAILS,
|
|
(DWORD_PTR)pmxcd,
|
|
fdwDetails);
|
|
}
|
|
else
|
|
{
|
|
mmr = (MMRESULT)IMixerMessageId(uMxId,
|
|
MXDM_GETCONTROLDETAILS,
|
|
(DWORD_PTR)pmxcd,
|
|
fdwDetails);
|
|
}
|
|
|
|
return (mmr);
|
|
} // mixerGetControlDetails()
|
|
|
|
|
|
/*--------------------------------------------------------------------------;
|
|
*
|
|
* @doc EXTERNAL MIXER SDK API
|
|
*
|
|
* @api MMRESULT | mixerSetControlDetails | The <f mixerSetControlDetails>
|
|
* function is used to set details on a single control associated
|
|
* with an audio mixer device line.
|
|
*
|
|
* @parm <c HMIXEROBJ> | hmxobj | Specifies a handle to the audio mixer
|
|
* device object to set control details for.
|
|
*
|
|
* @parm LPMIXERCONTROLDETAILS | pmxcd | Points to a <t MIXERCONTROLDETAILS>
|
|
* structure. This structure is used to reference control detail
|
|
* structures to that contain the desired state for the control.
|
|
* See the description for the <t MIXERCONTROLDETAILS> structure
|
|
* to determine what members of this structure must be initialized
|
|
* before calling the <f mixerSetControlDetails> function. Note that
|
|
* in all cases, the <e MIXERCONTROLDETAILS.cbStruct> member of the
|
|
* <t MIXERCONTROLDETAILS> structure must be initialized
|
|
* to be the size, in bytes, of the <t MIXERCONTROLDETAILS> structure.
|
|
*
|
|
* @parm DWORD | fdwDetails | Specifies flags for setting details for
|
|
* a control.
|
|
*
|
|
* @flag <c MIXER_SETCONTROLDETAILSF_VALUE> | If this flag is specified,
|
|
* the application is interested in setting the current value(s) for a
|
|
* control. The <e MIXERCONTROLDETAILS.paDetails> member of the
|
|
* <t MIXERCONTROLDETAILS> points to one or more details structures of
|
|
* the correct type for the control type. Refer to the description of the
|
|
* <t MIXERCONTROLDETAILS> structure for information on what each member
|
|
* of this structure must be initialized before calling the
|
|
* <f mixerSetControlDetails> function.
|
|
*
|
|
* @flag <c MIXER_SETCONTROLDETAILSF_CUSTOM> | If this flag is specified,
|
|
* the application is asking the mixer device to display a custom
|
|
* dialog for the specified custom mixer control. The handle for the
|
|
* owning window is specified in the <e MIXERCONTROLDETAILS.hwndOwner>
|
|
* member (this handle may, validly, be NULL). The mixer device will
|
|
* gather the required information from the user and return the data
|
|
* in the specified buffer. This data may then be saved by the
|
|
* application and later set back to the same state using the
|
|
* <c MIXER_SETCONTROLDETAILSF_VALUE> flag. If an application only
|
|
* needs to get the current state of a custom mixer control without
|
|
* displaying a dialog, then the <f mixerGetControlDetails> function
|
|
* can be used with the <c MIXER_GETCONTROLDETAILSF_VALUE> flag.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_MIXER> | Specifies that <p hmxobj> is an audio
|
|
* mixer device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f mixerGetNumDevs>. This flag is
|
|
* optional.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HMIXER> | Specifies that <p hmxobj> is a mixer
|
|
* device handle returned by <f mixerOpen>. This flag is optional.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_WAVEOUT> | Specifies that <p hmxobj> is a
|
|
* waveform output device identifier in the range of zero to one less
|
|
* than the number of devices returned by <f waveOutGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HWAVEOUT> | Specifies that <p hmxobj> is a
|
|
* waveform output handle returned by <f waveOutOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_WAVEIN> | Specifies that <p hmxobj> is a
|
|
* waveform input device identifier in the range of zero to one less
|
|
* than the number of devices returned by <f waveInGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HWAVEIN> | Specifies that <p hmxobj> is a
|
|
* waveform input handle returned by <f midiInOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_MIDIOUT> | Specifies that <p hmxobj> is a MIDI
|
|
* output device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f midiOutGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HMIDIOUT> | Specifies that <p hmxobj> is a
|
|
* MIDI output handle returned by <f midiOutOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_MIDIIN> | Specifies that <p hmxobj> is a MIDI
|
|
* input device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f midiInGetNumDevs>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_HMIDIIN> | Specifies that <p hmxobj> is a MIDI
|
|
* input handle returned by <f midiInOpen>.
|
|
*
|
|
* @flag <c MIXER_OBJECTF_AUX> | Specifies that <p hmxobj> is an
|
|
* auxiliary device identifier in the range of zero to one less than the
|
|
* number of devices returned by <f auxGetNumDevs>.
|
|
*
|
|
* @rdesc The return value is zero if the function is successful. Otherwise,
|
|
* it returns a non-zero error number. Possible error returns include
|
|
* the following:
|
|
*
|
|
* @flag <c MMSYSERR_BADDEVICEID> | The <p hmxobj> argument specifies an
|
|
* invalid device identifier.
|
|
*
|
|
* @flag <c MMSYSERR_INVALHANDLE> | The <p hmxobj> argument specifies an
|
|
* invalid handle.
|
|
*
|
|
* @flag <c MMSYSERR_INVALFLAG> | One or more flags are invalid.
|
|
*
|
|
* @flag <c MMSYSERR_INVALPARAM> | One or more arguments passed is
|
|
* invalid.
|
|
*
|
|
* @flag <c MMSYSERR_NODRIVER> | No audio mixer device is available for
|
|
* the object specified by <p hmxobj>.
|
|
*
|
|
* @flag <c MIXERR_INVALCONTROL> | The control reference is invalid.
|
|
*
|
|
* @xref <t MIXERCONTROLDETAILS>, <t MIXERCONTROL>, <f mixerGetLineControls>,
|
|
* <f mixerOpen>, <f mixerGetControlDetails>
|
|
*
|
|
**/
|
|
|
|
MMRESULT APIENTRY mixerSetControlDetails(
|
|
HMIXEROBJ hmxobj,
|
|
LPMIXERCONTROLDETAILS pmxcd,
|
|
DWORD fdwDetails
|
|
)
|
|
{
|
|
DWORD fdwMxObjType;
|
|
MMRESULT mmr;
|
|
UINT uMxId;
|
|
UINT cDetails;
|
|
BOOL fResource;
|
|
|
|
V_DFLAGS(fdwDetails, MIXER_SETCONTROLDETAILSF_VALID, mixerSetControlDetails, MMSYSERR_INVALFLAG);
|
|
V_WPOINTER(pmxcd, sizeof(DWORD), MMSYSERR_INVALPARAM);
|
|
|
|
//
|
|
// the structure header for MIXERCONTROLDETAILS must be at least the
|
|
// minimum size
|
|
//
|
|
if (sizeof(MIXERCONTROLDETAILS) > pmxcd->cbStruct)
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerSetControlDetails: structure size too small or cbStruct not initialized (%lu).", pmxcd->cbStruct);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
V_WPOINTER(pmxcd, pmxcd->cbStruct, MMSYSERR_INVALPARAM);
|
|
|
|
|
|
|
|
switch (MIXER_SETCONTROLDETAILSF_QUERYMASK & fdwDetails)
|
|
{
|
|
case MIXER_SETCONTROLDETAILSF_VALUE:
|
|
//
|
|
// cChannels is zero for custom controls
|
|
//
|
|
if (0 == pmxcd->cChannels)
|
|
{
|
|
if (0 == pmxcd->cbDetails)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerSetControlDetails: cbDetails cannot be zero.");
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
V_WPOINTER(pmxcd->paDetails, pmxcd->cbDetails, MMSYSERR_INVALPARAM);
|
|
|
|
//
|
|
//
|
|
//
|
|
if (0 != pmxcd->cMultipleItems)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerSetControlDetails: cMultipleItems must be zero for custom controls.");
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pmxcd->cbDetails < sizeof(MIXERCONTROLDETAILS_SIGNED))
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerSetControlDetails: structure size too small or cbDetails not initialized (%lu).", pmxcd->cbDetails);
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
cDetails = (UINT)pmxcd->cChannels;
|
|
|
|
//
|
|
//
|
|
//
|
|
if (0 != pmxcd->cMultipleItems)
|
|
{
|
|
cDetails *= (UINT)(pmxcd->cMultipleItems);
|
|
}
|
|
|
|
V_WPOINTER(pmxcd->paDetails, cDetails * pmxcd->cbDetails, MMSYSERR_INVALPARAM);
|
|
}
|
|
break;
|
|
|
|
case MIXER_SETCONTROLDETAILSF_CUSTOM:
|
|
if (0 == pmxcd->cbDetails)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerSetControlDetails: cbDetails cannot be zero for custom controls.");
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
if (0 != pmxcd->cChannels)
|
|
{
|
|
DebugErr(DBF_ERROR, "mixerSetControlDetails: cChannels must be zero for custom controls.");
|
|
return (MMSYSERR_INVALPARAM);
|
|
}
|
|
|
|
V_WPOINTER(pmxcd->paDetails, pmxcd->cbDetails, MMSYSERR_INVALPARAM);
|
|
|
|
//
|
|
//
|
|
//
|
|
if ((NULL != pmxcd->hwndOwner) && !IsWindow(pmxcd->hwndOwner))
|
|
{
|
|
DebugErr1(DBF_ERROR, "mixerSetControlDetails: hwndOwner must be a valid window handle (%.04Xh).", pmxcd->hwndOwner);
|
|
return (MMSYSERR_INVALHANDLE);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
DebugErr1(DBF_ERROR, "mixerSetControlDetails: invalid query flags (%.08lXh).",
|
|
MIXER_SETCONTROLDETAILSF_QUERYMASK & fdwDetails);
|
|
return (MMSYSERR_INVALFLAG);
|
|
}
|
|
|
|
|
|
ClientUpdatePnpInfo();
|
|
|
|
//
|
|
//
|
|
//
|
|
fdwMxObjType = (MIXER_OBJECTF_TYPEMASK & fdwDetails);
|
|
|
|
fResource = FALSE;
|
|
|
|
AcquireHandleListResourceShared();
|
|
|
|
// Checking for the type of mixer object. If it is a non-mixer type
|
|
// calling IMixerMesssageID (called by IMixerGetID) with the shared
|
|
// resource will deadlock.
|
|
if ((MIXER_OBJECTF_MIXER == fdwMxObjType) ||
|
|
(MIXER_OBJECTF_HMIXER == fdwMxObjType))
|
|
{
|
|
if (BAD_HANDLE(hmxobj, TYPE_MIXER))
|
|
{
|
|
ReleaseHandleListResource();
|
|
}
|
|
else
|
|
{
|
|
fResource = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ReleaseHandleListResource();
|
|
}
|
|
|
|
mmr = IMixerGetID(hmxobj, &uMxId, NULL, fdwMxObjType);
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
{
|
|
if (fResource)
|
|
ReleaseHandleListResource();
|
|
return (mmr);
|
|
}
|
|
|
|
if ((MIXER_OBJECTF_MIXER == fdwMxObjType) ||
|
|
(MIXER_OBJECTF_HMIXER == fdwMxObjType))
|
|
{
|
|
//
|
|
// if a mixer device id was passed, then null hmx so we use the
|
|
// correct message sender below
|
|
//
|
|
if ((UINT_PTR)hmxobj == uMxId)
|
|
hmxobj = NULL;
|
|
}
|
|
else
|
|
{
|
|
hmxobj = NULL;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
if (NULL != hmxobj)
|
|
{
|
|
mmr = (MMRESULT)IMixerMessageHandle((HMIXER)hmxobj,
|
|
MXDM_SETCONTROLDETAILS,
|
|
(DWORD_PTR)pmxcd,
|
|
fdwDetails);
|
|
}
|
|
else
|
|
{
|
|
mmr = (MMRESULT)IMixerMessageId(uMxId,
|
|
MXDM_SETCONTROLDETAILS,
|
|
(DWORD_PTR)pmxcd,
|
|
fdwDetails);
|
|
}
|
|
|
|
return (mmr);
|
|
} // mixerSetControlDetails()
|
|
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// MMRESULT mixerDesertHandle
|
|
//
|
|
// Description:
|
|
// Cleans up the mixer handle and marks it as deserted.
|
|
//
|
|
// Arguments:
|
|
// HMIXER hmx: Mixer handle.
|
|
//
|
|
// Return (MMRESULT): Error code.
|
|
//
|
|
// History:
|
|
// 01/25/99 Fwong Adding Pnp Support.
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
MMRESULT mixerDesertHandle
|
|
(
|
|
HMIXER hmx
|
|
)
|
|
{
|
|
MMRESULT mmr;
|
|
PMIXERDEV pmxdev;
|
|
PMIXERDEV pmxdevT;
|
|
PMIXERDRV pmxdrv;
|
|
BOOL fClose;
|
|
|
|
V_HANDLE_ACQ(hmx, TYPE_MIXER, MMSYSERR_INVALHANDLE);
|
|
|
|
ENTER_MM_HANDLE(hmx);
|
|
ReleaseHandleListResource();
|
|
|
|
if (IsHandleDeserted(hmx))
|
|
{
|
|
// Handle has already been deserted...
|
|
LEAVE_MM_HANDLE(hmx);
|
|
return (MMSYSERR_NOERROR);
|
|
}
|
|
|
|
// Marking handle as deserted
|
|
SetHandleFlag(hmx, MMHANDLE_DESERTED);
|
|
|
|
//
|
|
// remove the mixer handle from the linked list
|
|
//
|
|
|
|
MIXMGR_ENTER;
|
|
|
|
pmxdev = (PMIXERDEV)hmx;
|
|
pmxdrv = pmxdev->pmxdrv;
|
|
|
|
if (pmxdev == gpMixerDevHeader)
|
|
{
|
|
gpMixerDevHeader = pmxdev->pmxdevNext;
|
|
}
|
|
else
|
|
{
|
|
for (pmxdevT = gpMixerDevHeader;
|
|
pmxdevT && (pmxdevT->pmxdevNext != pmxdev);
|
|
pmxdevT = pmxdevT->pmxdevNext)
|
|
;
|
|
|
|
if (NULL == pmxdevT)
|
|
{
|
|
DebugErr1(DBF_ERROR,
|
|
"mixerDesertHandle: invalid mixer handle (%.04Xh).",
|
|
hmx);
|
|
|
|
MIXMGR_LEAVE;
|
|
LEAVE_MM_HANDLE(hmx);
|
|
|
|
return (MMSYSERR_INVALHANDLE);
|
|
}
|
|
|
|
pmxdevT->pmxdevNext = pmxdev->pmxdevNext;
|
|
}
|
|
|
|
//
|
|
// see if this is the last handle on this open instance
|
|
//
|
|
fClose = TRUE;
|
|
if (gpMixerDevHeader)
|
|
{
|
|
PMIXERDEV pmxdevT2;
|
|
for (pmxdevT2 = gpMixerDevHeader; pmxdevT2; pmxdevT2 = pmxdevT2->pmxdevNext)
|
|
{
|
|
if (pmxdevT2->pmxdrv != pmxdev->pmxdrv) continue;
|
|
if (pmxdevT2->wDevice != pmxdev->wDevice) continue;
|
|
fClose = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
MIXMGR_LEAVE;
|
|
|
|
if (fClose)
|
|
{
|
|
EnterCriticalSection(&pmxdev->pmxdrv->MixerCritSec);
|
|
mmr = (*(pmxdrv->drvMessage))(pmxdev->wDevice, MXDM_CLOSE, pmxdev->dwDrvUser, 0L, 0L);
|
|
LeaveCriticalSection(&pmxdev->pmxdrv->MixerCritSec);
|
|
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
{
|
|
// Close message failed.
|
|
// Should we put the handle back in the list???
|
|
LEAVE_MM_HANDLE(hmx);
|
|
return mmr;
|
|
}
|
|
}
|
|
|
|
LEAVE_MM_HANDLE(hmx);
|
|
|
|
mregDecUsage(PTtoH(HMD, pmxdev->pmxdrv));
|
|
|
|
return MMSYSERR_NOERROR;
|
|
} // mixerDesertHandle()
|
|
|