📄 mixfunc.cpp
字号:
case MIXER_GETCONTROLDETAILSF_VALUE:
MIXMSG1("mix_handle_GETCONTROLDETAILS: MIXER_GETCONTROLDETAILSF_VALUE: control %d",
pControlDetails->dwControlID);
{
DWORD dwRet;
switch(g_Controls[pControlDetails->dwControlID].dwControlType)
{
case MIXERCONTROL_CONTROLTYPE_MUX:
case MIXERCONTROL_CONTROLTYPE_MUTE:
{
MIXERCONTROLDETAILS_BOOLEAN *pDetails = (MIXERCONTROLDETAILS_BOOLEAN *)
MapPtrToProcess(pControlDetails->paDetails, GetCallerProcess());
if (!pDetails || pControlDetails->cbDetails < sizeof(MIXERCONTROLDETAILS_BOOLEAN))
{
MIXERRMSG2("mix_handle_GETCONTROLDETAILS: Bad parms: pointer: 0x%8.8x, size %d",
pDetails, pControlDetails->cbDetails);
goto badparms;
}
if (IsBadWritePtr((LPVOID)pDetails, sizeof(MIXERCONTROLDETAILS_BOOLEAN)))
{
MIXERRMSG("mix_handle_GETCONTROLDETAILS: Bad pointer");
goto badparms;
}
if (g_Controls[pControlDetails->dwControlID].dwControlType == MIXERCONTROL_CONTROLTYPE_MUX)
{
DWORD fValue;
dwRet = GetMuxValue(pDriverContext, pControlDetails->dwControlID, &fValue);
pDetails->fValue = fValue;
}
else // mute
{
int fValue;
dwRet = GetMixerMute(pDriverContext, pControlDetails->dwControlID, &fValue);
pDetails->fValue = fValue;
}
}
break;
case MIXERCONTROL_CONTROLTYPE_VOLUME:
{
MIXERCONTROLDETAILS_UNSIGNED *pDetails = (MIXERCONTROLDETAILS_UNSIGNED *)
MapPtrToProcess(pControlDetails->paDetails, GetCallerProcess());
// for UNIFORM controls (in our case, MUTE and MUX), there needs be only one
// MIXERCONTROLDETAILS_xxx structure; for non uniform controls
// we need one structure for each channel
if (!pDetails || pControlDetails->cbDetails < sizeof(MIXERCONTROLDETAILS_UNSIGNED))
goto badparms;
if (IsBadWritePtr((LPVOID)pDetails, pControlDetails->cChannels * pControlDetails->cbDetails))
{
MIXERRMSG("mix_handle_GETCONTROLDETAILS: Bad pointer");
goto badparms;
}
dwRet = GetMixerVolume(pDriverContext,
pControlDetails->dwControlID,
&(pDetails[LEFT_CHANNEL].dwValue), &(pDetails[RIGHT_CHANNEL].dwValue));
// scale values (if scaling window handle set; see scalevol.h for details)
}
break;
case MIXERCONTROL_CONTROLTYPE_UNSIGNED: // only one of that type: the ZV port sample rate
{
MIXERCONTROLDETAILS_UNSIGNED *pDetails = (MIXERCONTROLDETAILS_UNSIGNED *)
MapPtrToProcess(pControlDetails->paDetails, GetCallerProcess());
if (!pDetails || pControlDetails->cbDetails < sizeof(MIXERCONTROLDETAILS_UNSIGNED))
goto badparms;
if (IsBadWritePtr((LPVOID)pDetails, sizeof(MIXERCONTROLDETAILS_UNSIGNED)))
{
MIXERRMSG("mix_handle_GETCONTROLDETAILS: Bad pointer");
goto badparms;
}
dwRet = GetUnsignedValue(pDriverContext,
pControlDetails->dwControlID,
&(pDetails->dwValue));
}
break;
default:
MIXERRMSG1("mix_handle_GETCONTROLDETAILS: Bad control type: %d",
g_Controls[pControlDetails->dwControlID].dwControlType);
ASSERT(FALSE);
}
}
break;
case MIXER_GETCONTROLDETAILSF_LISTTEXT:
MIXMSG1("mix_handle_GETCONTROLDETAILS: MIXER_GETCONTROLDETAILSF_LISTTEXT: control %d",
pControlDetails->dwControlID);
switch(g_Controls[pControlDetails->dwControlID].dwControlType)
{
case MIXERCONTROL_CONTROLTYPE_MUX:
{
int i;
MIXERCONTROLDETAILS_LISTTEXT *pDetails = (MIXERCONTROLDETAILS_LISTTEXT *)
MapPtrToProcess(pControlDetails->paDetails, GetCallerProcess());
if (!pDetails || pControlDetails->cbDetails < sizeof(MIXERCONTROLDETAILS_LISTTEXT))
goto badparms;
if (IsBadWritePtr(pDetails->szName, MIXER_LONG_NAME_CHARS))
{
MIXERRMSG("mix_handle_GETCONTROLDETAILS: Bad pointer");
goto badparms;
}
// get the current mux'ed line ID and name
for (i = 0; i < MAX_MULTIPLEXERS; i++)
{
if (g_Multiplexers[i].dwMuxID == pControlDetails->dwControlID)
{
DWORD dwValue;
LPMIXERLINE pTempLine;
dwRet = GetMuxValue(pDriverContext, pControlDetails->dwControlID, &dwValue);
if (NO_ERROR != dwRet)
{
SetLastError(dwRet);
return MIXERR_INVALCONTROL; // not supported or another error
}
pDetails->dwParam1 = g_Multiplexers[i].muxedLines[dwValue];
pTempLine = FindMixerLine(pDetails->dwParam1);
if (!pTempLine)
{
MIXERRMSG1("mix_handle_GETCONTROLDETAILS: Bad line ID: %d", pDetails->dwParam1);
return MIXERR_INVALLINE;
}
_tcscpy(pDetails->szName, pTempLine->szName);
break;
}
}
ASSERT(i < MAX_MULTIPLEXERS);
}
break;
default: // can't do MIXER_GETCONTROLDETAILSF_LISTTEXT on volume or mute controls
goto badparms;
}
break;
default:
return MMSYSERR_INVALFLAG;
}
if (dwRet != NO_ERROR)
{
SetLastError(dwRet);
return MMSYSERR_NODRIVER;
}
return MMSYSERR_NOERROR;
badparms:
MIXERRMSG("Bad parameters in mix_handle_GETCONTROLDETAILS");
SetLastError(ERROR_INVALID_PARAMETER);
return MMSYSERR_INVALPARAM;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function:
mix_handle_SETCONTROLDETAILS
Description:
Sets a control's value
Arguments:
PMIXER_CONTEXT pMixer : pointer to the mixer context structure
DWORD dwUser : returned by the app (not used)
DWORD dwParam1 : pointer to the MIXERCONTROLDETAILS structure describing the control
DWORD dwParam2 : flags that describe the value to be set
Return Value: DWORD
-------------------------------------------------------------------*/
DWORD mix_handle_SETCONTROLDETAILS(PMIXER_CONTEXT pMixer, DWORD dwUser, DWORD dwParam1, DWORD dwParam2)
{
// this is where the real work is!
LPMIXERCONTROLDETAILS pControlDetails = (LPMIXERCONTROLDETAILS) MapPtrToProcess((PVOID)dwParam1, GetCallerProcess());
PDRIVER_CONTEXT pDriverContext = g_pDriverContext;
ASSERT(pMixer && pDriverContext);
if (!pControlDetails)
goto badparms;
if (pControlDetails->cbStruct < sizeof(MIXERCONTROLDETAILS))
goto badparms;
if (pControlDetails->dwControlID >= MAX_CONTROLS)
{
MIXERRMSG1("mix_handle_SETCONTROLDETAILS: Bad control ID: %d", pControlDetails->dwControlID);
return MIXERR_INVALCONTROL;
}
switch (dwParam2 & MIXER_SETCONTROLDETAILSF_QUERYMASK )
{
case MIXER_SETCONTROLDETAILSF_VALUE:
{
DWORD dwRet;
switch(g_Controls[pControlDetails->dwControlID].dwControlType)
{
case MIXERCONTROL_CONTROLTYPE_MUX:
case MIXERCONTROL_CONTROLTYPE_MUTE:
{
MIXERCONTROLDETAILS_BOOLEAN *pDetails = (MIXERCONTROLDETAILS_BOOLEAN *)
MapPtrToProcess(pControlDetails->paDetails, GetCallerProcess());
if (!pDetails || pControlDetails->cbDetails < sizeof(MIXERCONTROLDETAILS_BOOLEAN))
goto badparms;
if (g_Controls[pControlDetails->dwControlID].dwControlType == MIXERCONTROL_CONTROLTYPE_MUX)
{
dwRet = SetMuxValue(pDriverContext,
pControlDetails->dwControlID,
pDetails->fValue);
}
else // mute
{
dwRet = SetMixerMute(pDriverContext,
pControlDetails->dwControlID,
pDetails->fValue);
}
}
break;
case MIXERCONTROL_CONTROLTYPE_VOLUME:
{
MIXERCONTROLDETAILS_UNSIGNED *pDetails = (MIXERCONTROLDETAILS_UNSIGNED *)
MapPtrToProcess(pControlDetails->paDetails, GetCallerProcess());
// for UNIFORM controls (in our case, MUTE and MUX), there needs be only one
// MIXERCONTROLDETAILS_xxx structure; for non uniform controls
// we need one structure for each channel
if (!pDetails ||
pControlDetails->cbDetails < sizeof(MIXERCONTROLDETAILS_UNSIGNED))
goto badparms;
if (IsBadWritePtr((LPVOID)pDetails, pControlDetails->cChannels * pControlDetails->cbDetails))
{
MIXERRMSG("error: Bad pointer in mix_handle_SETCONTROLDETAILS");
goto badparms;
}
if (pControlDetails->cChannels == 1)
pDetails[RIGHT_CHANNEL].dwValue = pDetails[LEFT_CHANNEL].dwValue;
if (pDetails[LEFT_CHANNEL].dwValue > MAX_ATTENUATION ||
pDetails[RIGHT_CHANNEL].dwValue > MAX_ATTENUATION)
goto badparms;
dwRet = SetMixerVolume(pDriverContext,
pControlDetails->dwControlID,
pDetails[LEFT_CHANNEL].dwValue, pDetails[RIGHT_CHANNEL].dwValue);
}
break;
case MIXERCONTROL_CONTROLTYPE_UNSIGNED:
{
MIXERCONTROLDETAILS_UNSIGNED *pDetails = (MIXERCONTROLDETAILS_UNSIGNED *)
MapPtrToProcess(pControlDetails->paDetails, GetCallerProcess());
if (!pDetails || pControlDetails->cbDetails < sizeof(MIXERCONTROLDETAILS_UNSIGNED))
goto badparms;
dwRet = SetUnsignedValue(pDriverContext,
pControlDetails->dwControlID,
pDetails->dwValue);
}
break;
default:
MIXERRMSG2("mix_handle_SETCONTROLDETAILS: Control %d, unknown type: 0x%8.8x", pControlDetails->dwControlID,
g_Controls[pControlDetails->dwControlID].dwControlType);
dwRet = ERROR_NOT_SUPPORTED;
}
if (dwRet != NO_ERROR)
{
SetLastError(dwRet);
return MMSYSERR_NODRIVER;
}
}
break;
default:
return MMSYSERR_INVALFLAG;
}
// all seems ok; call registered callbacks (if any)
{
PMIXER_CONTEXT pMix = pDriverContext->pMixerContextList;
CALLBACKINFO cbi;
DWORD dwOldPermissions = SetProcPermissions(0xFFFFFFFF);
while (pMix)
{
if (pMix->pfnMixerCallback)
{
cbi.hProc = (PVOID) pMix->hProcess;
cbi.pfn = (FARPROC) pMix->pfnMixerCallback;
cbi.pvArg0 = (PVOID) pMix; // the first parameter is here
__try
{
PerformCallBack(&cbi, MM_MIXM_CONTROL_CHANGE, pMix->dwInstance, pControlDetails->dwControlID, 0);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
MIXERRMSG("Callback error!");
}
}
pMix = pMix->pNext;
}
SetProcPermissions(dwOldPermissions );
}
return MMSYSERR_NOERROR;
badparms:
MIXERRMSG("Bad parameters in mix_handle_GETCONTROLDETAILS");
SetLastError(ERROR_INVALID_PARAMETER);
return MMSYSERR_INVALPARAM;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function:
CopyControlStruct
Description:
Arguments:
PMIXERCONTROL pMixerControl :
int iIndex :
Return Value: void
-------------------------------------------------------------------*/
void CopyControlStruct(PMIXERCONTROL pMixerControl, int iIndex)
{
pMixerControl->cbStruct = sizeof(MIXERCONTROL);
pMixerControl->dwControlID = iIndex;
// pMixerControl->dwControlType = g_Controls[iIndex].dwControlType & (MIXERCONTROL_CT_SUBCLASS_MASK | MIXERCONTROL_CT_CLASS_MASK);
pMixerControl->dwControlType = g_Controls[iIndex].dwControlType;
// the volume controls act separately on the two channels (i.e., you can have different volumes on left and right)
// the mute and mux are uniform: they act the same on both channels
pMixerControl->fdwControl = (MIXERCONTROL_CONTROLTYPE_VOLUME == g_Controls[iIndex].dwControlType)?
0:
MIXERCONTROL_CONTROLF_UNIFORM;
pMixerControl->cMultipleItems = 0;
_tcscpy(pMixerControl->szShortName, g_Controls[iIndex].szShortName);
_tcscpy(pMixerControl->szName, g_Controls[iIndex].szName);
// pMixerControl->Bounds.dwMinimum = g_Controls[iIndex].dwMinimum;
// pMixerControl->Bounds.dwMaximum = g_Controls[iIndex].dwMaximum;
// [CC - 7/23/1999 ] see comments in csmix.h
pMixerControl->Bounds.dwMinimum = 0;
pMixerControl->Bounds.dwMaximum = MAX_ATTENUATION;
pMixerControl->Metrics.cSteps = MAX_ATTENUATION;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function:
mix_FreeMixer
Description:
Frees a mixer device context and removes it from the contexts list
Arguments:
PMIXER_CONTEXT pMixer : pointer to the mixer context structure
Return Value: BOOL
-------------------------------------------------------------------*/
BOOL mix_FreeMixer(PMIXER_CONTEXT pMixer)
{
BOOL retval = TRUE;
PMIXER_CONTEXT pTemp, pPrev = NULL;
LockMixerList();
pTemp = g_pDriverContext->pMixerContextList;
while(pTemp)
{
if (pTemp == pMixer)
break;
pPrev = pTemp;
pTemp = pTemp->pNext;
}
if (NULL == pTemp)
{ // the device wasn't found in the list
RETAILMSG( 1, (TEXT("Error: mix_FreeMixer: bad Open Handle 0x%08x\r\n"), pMixer) );
SetLastError( ERROR_INVALID_HANDLE );
retval = FALSE;
}
else
{ // device found, pTemp points to it, and pPrev points to the previous one in the list
// unless it's the first one, in which case pPrev is null
if (pPrev)
pPrev->pNext = pTemp->pNext;
else
g_pDriverContext->pMixerContextList = pTemp->pNext;
LocalFree(pTemp);
}
UnlockMixerList();
return retval;
}
#if 0
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Function:
ScaleValues
Description:
Scales the values to be transmitted to the hardware
Currently calls the GI tv application to do the work;
this may change in the future
Arguments:
PMIXER_CONTEXT pMixer : the driver context
DWORD dwControlIndex : the index in the g_Controls array of the control to be scaled
DWORD *pdwLeft : the
DWORD *pdwRight :
UMSG bDirectConversion :
Return Value: void
-------------------------------------------------------------------*/
void ScaleValues(PMIXER_CONTEXT pMixer, DWORD dwControlIndex,
DWORD *pdwLeft, DWORD *pdwRight, BOOL bDirectConversion)
{
// is scaling to be done for all channels? It makes sense for TV audio, but not for others
/*
if (dwControlIndex != 0)
return;
*/
if (IsWindow(pDriverContext->hHookWnd))
{
DWORD dwVal = SendMessage(pDriverContext->hHookWnd, // the window of the GI tv app
bDirectConversion?
WM_SCALEDIRECT: // convert from application data to hardware data
WM_SCALEINVERSE, // convert from hardware to app data
MAKELONG(g_Controls[dwControlIndex].dwMinimum,
g_Controls[dwControlIndex].dwMaximum), // minimum and maximum values the hardware accepts for the control
MAKELONG(*pdwRight, *pdwLeft)); // values to be scaled
// check the received values against the bounds
if (GET_LEFT_CHANNEL(dwVal) >= min(g_Controls[dwControlIndex].dwMinimum,
g_Controls[dwControlIndex].dwMaximum) &&
GET_LEFT_CHANNEL(dwVal) <= max(g_Controls[dwControlIndex].dwMinimum,
g_Controls[dwControlIndex].dwMaximum) &&
GET_RIGHT_CHANNEL(dwVal) >= min(g_Controls[dwControlIndex].dwMinimum,
g_Controls[dwControlIndex].dwMaximum) &&
GET_RIGHT_CHANNEL(dwVal) <= max(g_Controls[dwControlIndex].dwMinimum,
g_Controls[dwControlIndex].dwMaximum))
{ // Ok, set those values
*pdwRight = GET_RIGHT_CHANNEL(dwVal);
*pdwLeft = GET_LEFT_CHANNEL(dwVal);
RETAILMSG(1, (TEXT("ScaleValues: Got scaled values: (%d, %d)\r\n"),
*pdwLeft,
*pdwRight));
}
else
{ // received values are bad, ignore them
RETAILMSG(1, (TEXT("ScaleValues: Got bad scaled values: (%d, %d)\r\n"),
GET_LEFT_CHANNEL(dwVal),
GET_RIGHT_CHANNEL(dwVal)));
}
}
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -