///////////////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 1998 Active Voice Corporation. All Rights Reserved. // // Active Agent(r) and Unified Communications(tm) are trademarks of Active Voice Corporation. // // Other brand and product names used herein are trademarks of their respective owners. // // The entire program and user interface including the structure, sequence, selection, // and arrangement of the dialog, the exclusively "yes" and "no" choices represented // by "1" and "2," and each dialog message are protected by copyrights registered in // the United States and by international treaties. // // Protected by one or more of the following United States patents: 5,070,526, 5,488,650, // 5,434,906, 5,581,604, 5,533,102, 5,568,540, 5,625,676, 5,651,054. // // Active Voice Corporation // Seattle, Washington // USA // ///////////////////////////////////////////////////////////////////////////////////////// //// // wavmixer.c - wav mixer functions //// #include "winlocal.h" #include #include "wavmixer.h" #include "calc.h" #include "mem.h" #include "trace.h" //// // private definitions //// // wavmixer control struct // typedef struct WAVMIXER { DWORD dwVersion; HINSTANCE hInst; HTASK hTask; HMIXER hMixer; UINT nLastError; DWORD dwFlags; } WAVMIXER, FAR *LPWAVMIXER; #define VOLUME_MINLEVEL 0 #define VOLUME_MAXLEVEL 100 #define VOLUME_POSITIONS (VOLUME_MAXLEVEL - VOLUME_MINLEVEL) #define WAVMIXER_SUPPORTSVOLUME 0x00000001 #define WAVMIXER_GETVOLUME 0x00000002 #define WAVMIXER_SETVOLUME 0x00000004 #define LEVEL_MINLEVEL 0 #define LEVEL_MAXLEVEL 100 #define LEVEL_POSITIONS (LEVEL_MAXLEVEL - LEVEL_MINLEVEL) #define WAVMIXER_SUPPORTSLEVEL 0x00000001 #define WAVMIXER_GETLEVEL 0x00000002 // helper functions // static int WINAPI WavMixerVolume(HWAVMIXER hWavMixer, LPINT lpnLevel, DWORD dwFlags); static int WINAPI WavMixerLevel(HWAVMIXER hWavMixer, LPINT lpnLevel, DWORD dwFlags); static LPWAVMIXER WavMixerGetPtr(HWAVMIXER hWavMixer); static HWAVMIXER WavMixerGetHandle(LPWAVMIXER lpWavMixer); //// // public functions //// // WavMixerInit - initialize wav mixer device // (i) must be WAVMIXER_VERSION // (i) instance handle of calling module // (i) device id or handle, as specified by // (i) reserved; must be 0; // (i) reserved; must be 0; // (i) control flags // WAVMIXER_HWAVEIN contains an HWAVEIN // WAVMIXER_HWAVEOUT contains an HWAVEOUT // WAVMIXER_WAVEIN contains a wav input device id // WAVMIXER_WAVEOUT contains a wav output device id // return handle (NULL if error) // HWAVMIXER WINAPI WavMixerInit(DWORD dwVersion, HINSTANCE hInst, LPARAM lParam, DWORD dwReserved1, DWORD dwReserved2, DWORD dwFlags) { BOOL fSuccess = TRUE; LPWAVMIXER lpWavMixer = NULL; if (dwVersion != WAVMIXER_VERSION) fSuccess = TraceFALSE(NULL); else if (hInst == NULL) fSuccess = TraceFALSE(NULL); else if ((lpWavMixer = (LPWAVMIXER) MemAlloc(NULL, sizeof(WAVMIXER), 0)) == NULL) fSuccess = TraceFALSE(NULL); else { UINT uMxId = (UINT) lParam; DWORD fdwOpen = 0; UINT nLastError; lpWavMixer->dwVersion = dwVersion; lpWavMixer->hInst = hInst; lpWavMixer->hTask = GetCurrentTask(); lpWavMixer->hMixer = NULL; lpWavMixer->nLastError = 0; lpWavMixer->dwFlags = dwFlags; if (dwFlags & WAVMIXER_HWAVEIN) fdwOpen |= MIXER_OBJECTF_HWAVEIN; if (dwFlags & WAVMIXER_HWAVEOUT) fdwOpen |= MIXER_OBJECTF_HWAVEOUT; if (dwFlags & WAVMIXER_WAVEIN) fdwOpen |= MIXER_OBJECTF_WAVEIN; if (dwFlags & WAVMIXER_WAVEOUT) fdwOpen |= MIXER_OBJECTF_WAVEOUT; // open the mixer device // if ((nLastError = mixerOpen(&lpWavMixer->hMixer, uMxId, 0L, 0L, fdwOpen)) != MMSYSERR_NOERROR) { fSuccess = TraceFALSE(NULL); TracePrintf_1(NULL, 5, TEXT("mixerOpen failed (%u)\n"), (unsigned) nLastError); } } if (!fSuccess) { WavMixerTerm(WavMixerGetHandle(lpWavMixer)); lpWavMixer = NULL; } return fSuccess ? WavMixerGetHandle(lpWavMixer) : NULL; } // WavMixerTerm - shut down wave mixer device // (i) handle returned from WavMixerInit // return 0 if success // int WINAPI WavMixerTerm(HWAVMIXER hWavMixer) { BOOL fSuccess = TRUE; LPWAVMIXER lpWavMixer; if ((lpWavMixer = WavMixerGetPtr(hWavMixer)) == NULL) fSuccess = TraceFALSE(NULL); else { if (lpWavMixer->hMixer != NULL) { UINT nLastError; if ((nLastError = mixerClose(lpWavMixer->hMixer)) != MMSYSERR_NOERROR) { fSuccess = TraceFALSE(NULL); TracePrintf_1(NULL, 5, TEXT("mixerClose failed (%u)\n"), (unsigned) nLastError); } else lpWavMixer->hMixer = NULL; } if ((lpWavMixer = MemFree(NULL, lpWavMixer)) != NULL) fSuccess = TraceFALSE(NULL); } return fSuccess ? 0 : -1; } // WavMixerSupportsVolume - return TRUE if device supports volume control // (i) handle returned from WavMixerInit // (i) control flags // 0 reserved; must be zero // return TRUE if device supports volume control // BOOL WINAPI WavMixerSupportsVolume(HWAVMIXER hWavMixer, DWORD dwFlags) { if (WavMixerVolume(hWavMixer, NULL, WAVMIXER_SUPPORTSVOLUME) != 0) return FALSE; else return TRUE; } // WavMixerGetVolume - get current volume level // (i) handle returned from WavMixerInit // (i) control flags // 0 reserved; must be zero // return volume level (0 minimum through 100 maximum, -1 if error) // int WINAPI WavMixerGetVolume(HWAVMIXER hWavMixer, DWORD dwFlags) { BOOL fSuccess = TRUE; int nLevel; if (WavMixerVolume(hWavMixer, &nLevel, WAVMIXER_GETVOLUME) != 0) fSuccess = TraceFALSE(NULL); return fSuccess ? nLevel : -1; } // WavMixerSetVolume - set current volume level // (i) handle returned from WavMixerInit // (i) volume level // 0 minimum volume // 100 maximum volume // (i) control flags // 0 reserved; must be zero // return new volume level (0 minimum through 100 maximum, -1 if error) // int WINAPI WavMixerSetVolume(HWAVMIXER hWavMixer, int nLevel, DWORD dwFlags) { BOOL fSuccess = TRUE; if (WavMixerVolume(hWavMixer, &nLevel, WAVMIXER_SETVOLUME) != 0) fSuccess = TraceFALSE(NULL); return fSuccess ? nLevel : -1; } static int WINAPI WavMixerVolume(HWAVMIXER hWavMixer, LPINT lpnLevel, DWORD dwFlags) { BOOL fSuccess = TRUE; LPWAVMIXER lpWavMixer; LPMIXERCONTROL lpmxc = NULL; // // We have to initialize local variable // UINT nLastError; MIXERLINE mxlDst; MIXERLINE mxlSrc; BOOL fWaveIn = FALSE; if ((lpWavMixer = WavMixerGetPtr(hWavMixer)) == NULL) fSuccess = TraceFALSE(NULL); else if ((lpmxc = (LPMIXERCONTROL) MemAlloc(NULL, sizeof(MIXERCONTROL), 0)) == NULL) fSuccess = TraceFALSE(NULL); // get info for the destination line // if (fSuccess) { if ((lpWavMixer->dwFlags & WAVMIXER_WAVEIN) || (lpWavMixer->dwFlags & WAVMIXER_HWAVEIN)) fWaveIn = TRUE; mxlDst.cbStruct = sizeof(mxlDst); mxlDst.dwComponentType = fWaveIn ? MIXERLINE_COMPONENTTYPE_DST_WAVEIN : MIXERLINE_COMPONENTTYPE_DST_SPEAKERS; if ((nLastError = mixerGetLineInfo((HMIXEROBJ) lpWavMixer->hMixer, &mxlDst, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE)) != MMSYSERR_NOERROR) { fSuccess = TraceFALSE(NULL); TracePrintf_1(NULL, 5, TEXT("mixerGetLineInfo failed (%u)\n"), (unsigned) nLastError); } } // find appropriate source line connected to this destination line // if (fSuccess) { DWORD dwSource; for (dwSource = 0; fSuccess && dwSource < mxlDst.cConnections; ++dwSource) { mxlSrc.cbStruct = sizeof(mxlSrc); mxlSrc.dwSource = dwSource; mxlSrc.dwDestination = mxlDst.dwDestination; if ((nLastError = mixerGetLineInfo((HMIXEROBJ) lpWavMixer->hMixer, &mxlSrc, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_SOURCE)) != MMSYSERR_NOERROR) { fSuccess = TraceFALSE(NULL); TracePrintf_1(NULL, 5, TEXT("mixerGetLineInfo failed (%u)\n"), (unsigned) nLastError); } else if (mxlSrc.dwComponentType == (DWORD) (fWaveIn ? MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE : MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT)) { // source line found // break; } } if (dwSource == mxlDst.cConnections) { // unable to find source line // fSuccess = TraceFALSE(NULL); } } // find volume control, if any, of the appropriate line // if (fSuccess) { MIXERLINECONTROLS mxlc; mxlc.cbStruct = sizeof(mxlc); mxlc.dwLineID = (fWaveIn ? mxlSrc.dwLineID : mxlDst.dwLineID); mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME; mxlc.cControls = 1; mxlc.cbmxctrl = sizeof(MIXERCONTROL); mxlc.pamxctrl = lpmxc; if ((nLastError = mixerGetLineControls((HMIXEROBJ) lpWavMixer->hMixer, &mxlc, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE)) != MMSYSERR_NOERROR) { fSuccess = TraceFALSE(NULL); TracePrintf_1(NULL, 5, TEXT("mixerGetLineControls failed (%u)\n"), (unsigned) nLastError); } } // get and/or set current volume level // if (fSuccess && ((dwFlags & WAVMIXER_GETVOLUME) || (dwFlags & WAVMIXER_SETVOLUME))) { LPMIXERCONTROLDETAILS_UNSIGNED lpmxcdu = NULL; MIXERCONTROLDETAILS mxcd; DWORD cChannels = mxlSrc.cChannels; DWORD dwVolume; int nLevel; if (lpmxc->fdwControl & MIXERCONTROL_CONTROLF_UNIFORM) cChannels = 1; if ((lpmxcdu = (LPMIXERCONTROLDETAILS_UNSIGNED) MemAlloc(NULL, cChannels * sizeof(MIXERCONTROLDETAILS_UNSIGNED), 0)) == NULL) { fSuccess = TraceFALSE(NULL); } else { mxcd.cbStruct = sizeof(mxcd); mxcd.dwControlID = lpmxc->dwControlID; mxcd.cChannels = cChannels; mxcd.hwndOwner = (HWND) NULL; mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); mxcd.paDetails = (LPVOID) lpmxcdu; if ((nLastError = mixerGetControlDetails((HMIXEROBJ) lpWavMixer->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE)) != MMSYSERR_NOERROR) { fSuccess = TraceFALSE(NULL); TracePrintf_1(NULL, 5, TEXT("mixerGetControlDetails failed (%u)\n"), (unsigned) nLastError); } else dwVolume = lpmxcdu[0].dwValue; } if (fSuccess && (dwFlags & WAVMIXER_SETVOLUME)) { if (lpnLevel != NULL) nLevel = *lpnLevel; // convert signed level (0 - 100) to unsigned volume (0 - 65535) // dwVolume = nLevel * (0xFFFF / VOLUME_POSITIONS); lpmxcdu[0].dwValue = lpmxcdu[cChannels - 1].dwValue = dwVolume; TracePrintf_2(NULL, 5, TEXT("WavMixerSetVolume() = %d, 0x%08lX\n"), (int) nLevel, (unsigned long) dwVolume); if ((nLastError = mixerSetControlDetails((HMIXEROBJ) lpWavMixer->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_SETCONTROLDETAILSF_VALUE)) != MMSYSERR_NOERROR) { fSuccess = TraceFALSE(NULL); TracePrintf_1(NULL, 5, TEXT("mixerSetControlDetails failed (%u)\n"), (unsigned) nLastError); } #if 1 // save new volume to pass back // else if ((nLastError = mixerGetControlDetails((HMIXEROBJ) lpWavMixer->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE)) != MMSYSERR_NOERROR) { fSuccess = TraceFALSE(NULL); TracePrintf_1(NULL, 5, TEXT("mixerGetControlDetails failed (%u)\n"), (unsigned) nLastError); } else dwVolume = lpmxcdu[0].dwValue; #endif } if (fSuccess && #if 1 ((dwFlags & WAVMIXER_GETVOLUME) || (dwFlags & WAVMIXER_SETVOLUME))) #else (dwFlags & WAVMIXER_GETVOLUME)) #endif { // convert unsigned volume (0 - 65535) to signed level (0 - 100) // nLevel = LOWORD(dwVolume) / (0xFFFF / VOLUME_POSITIONS); if (lpnLevel != NULL) *lpnLevel = nLevel; TracePrintf_2(NULL, 5, TEXT("WavMixerGetVolume() = %d, 0x%08lX\n"), (int) nLevel, (unsigned long) dwVolume); } if (lpmxcdu != NULL && (lpmxcdu = MemFree(NULL, lpmxcdu)) != NULL) fSuccess = TraceFALSE(NULL); } // clean up // if (lpmxc != NULL && (lpmxc = MemFree(NULL, lpmxc)) != NULL) fSuccess = TraceFALSE(NULL); if (hWavMixer != NULL && lpWavMixer != NULL) lpWavMixer->nLastError = nLastError; return fSuccess ? 0 : -1; } // WavMixerSupportsLevel - return TRUE if device supports peak meter level // (i) handle returned from WavMixerInit // (i) control flags // 0 reserved; must be zero // return TRUE if device supports peak meter level // BOOL WINAPI WavMixerSupportsLevel(HWAVMIXER hWavMixer, DWORD dwFlags) { if (WavMixerLevel(hWavMixer, NULL, WAVMIXER_SUPPORTSLEVEL) != 0) return FALSE; else return TRUE; } // WavMixerGetLevel - get current peak meter level // (i) handle returned from WavMixerInit // (i) control flags // 0 reserved; must be zero // return peak meter level (0 minimum through 100 maximum, -1 if error) // int WINAPI WavMixerGetLevel(HWAVMIXER hWavMixer, DWORD dwFlags) { BOOL fSuccess = TRUE; int nLevel; if (WavMixerLevel(hWavMixer, &nLevel, WAVMIXER_GETLEVEL) != 0) fSuccess = TraceFALSE(NULL); return fSuccess ? nLevel : -1; } static int WINAPI WavMixerLevel(HWAVMIXER hWavMixer, LPINT lpnLevel, DWORD dwFlags) { BOOL fSuccess = TRUE; LPWAVMIXER lpWavMixer; LPMIXERCONTROL lpmxc = NULL; // // Initialize local variable // UINT nLastError = 0; MIXERLINE mxlDst; MIXERLINE mxlSrc; BOOL fWaveIn = FALSE; if ((lpWavMixer = WavMixerGetPtr(hWavMixer)) == NULL) fSuccess = TraceFALSE(NULL); else if ((lpmxc = (LPMIXERCONTROL) MemAlloc(NULL, sizeof(MIXERCONTROL), 0)) == NULL) fSuccess = TraceFALSE(NULL); // get info for the destination line // if (fSuccess) { if ((lpWavMixer->dwFlags & WAVMIXER_WAVEIN) || (lpWavMixer->dwFlags & WAVMIXER_HWAVEIN)) fWaveIn = TRUE; mxlDst.cbStruct = sizeof(mxlDst); mxlDst.dwComponentType = fWaveIn ? MIXERLINE_COMPONENTTYPE_DST_WAVEIN : MIXERLINE_COMPONENTTYPE_DST_SPEAKERS; if ((nLastError = mixerGetLineInfo((HMIXEROBJ) lpWavMixer->hMixer, &mxlDst, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_COMPONENTTYPE)) != MMSYSERR_NOERROR) { fSuccess = TraceFALSE(NULL); TracePrintf_1(NULL, 5, TEXT("mixerGetLineInfo failed (%u)\n"), (unsigned) nLastError); } } // find appropriate source line connected to this destination line // if (fSuccess) { DWORD dwSource; for (dwSource = 0; fSuccess && dwSource < mxlDst.cConnections; ++dwSource) { mxlSrc.cbStruct = sizeof(mxlSrc); mxlSrc.dwSource = dwSource; mxlSrc.dwDestination = mxlDst.dwDestination; if ((nLastError = mixerGetLineInfo((HMIXEROBJ) lpWavMixer->hMixer, &mxlSrc, MIXER_OBJECTF_HMIXER | MIXER_GETLINEINFOF_SOURCE)) != MMSYSERR_NOERROR) { fSuccess = TraceFALSE(NULL); TracePrintf_1(NULL, 5, TEXT("mixerGetLineInfo failed (%u)\n"), (unsigned) nLastError); } else if (mxlSrc.dwComponentType == (DWORD) (fWaveIn ? MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE : MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT)) { // source line found // break; } } if (dwSource == mxlDst.cConnections) { // unable to find source line // fSuccess = TraceFALSE(NULL); } } // find peak meter control, if any, of the appropriate line // if (fSuccess) { MIXERLINECONTROLS mxlc; mxlc.cbStruct = sizeof(mxlc); mxlc.dwLineID = (fWaveIn ? mxlDst.dwLineID : mxlSrc.dwLineID); mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_PEAKMETER; mxlc.cControls = 1; mxlc.cbmxctrl = sizeof(MIXERCONTROL); mxlc.pamxctrl = lpmxc; if ((nLastError = mixerGetLineControls((HMIXEROBJ) lpWavMixer->hMixer, &mxlc, MIXER_OBJECTF_HMIXER | MIXER_GETLINECONTROLSF_ONEBYTYPE)) != MMSYSERR_NOERROR) { fSuccess = TraceFALSE(NULL); TracePrintf_1(NULL, 5, TEXT("mixerGetLineControls failed (%u)\n"), (unsigned) nLastError); } } // get current peak meter level // if (fSuccess && (dwFlags & WAVMIXER_GETLEVEL)) { LPMIXERCONTROLDETAILS_SIGNED lpmxcds = NULL; MIXERCONTROLDETAILS mxcd; DWORD cChannels = mxlDst.cChannels; DWORD dwLevel; int nLevel; if (lpmxc->fdwControl & MIXERCONTROL_CONTROLF_UNIFORM) cChannels = 1; if ((lpmxcds = (LPMIXERCONTROLDETAILS_SIGNED) MemAlloc(NULL, cChannels * sizeof(MIXERCONTROLDETAILS_SIGNED), 0)) == NULL) { fSuccess = TraceFALSE(NULL); } else { mxcd.cbStruct = sizeof(mxcd); mxcd.dwControlID = lpmxc->dwControlID; mxcd.cChannels = cChannels; mxcd.hwndOwner = (HWND) NULL; mxcd.cbDetails = sizeof(MIXERCONTROLDETAILS_SIGNED); mxcd.paDetails = (LPVOID) lpmxcds; if ((nLastError = mixerGetControlDetails((HMIXEROBJ) lpWavMixer->hMixer, &mxcd, MIXER_OBJECTF_HMIXER | MIXER_GETCONTROLDETAILSF_VALUE)) != MMSYSERR_NOERROR) { fSuccess = TraceFALSE(NULL); TracePrintf_1(NULL, 5, TEXT("mixerGetControlDetails failed (%u)\n"), (unsigned) nLastError); } else { // convert signed level to unsigned level // dwLevel = lpmxcds[0].lValue - 0; // lpmxc->Bounds.lMinimum; dwLevel *= 2; } } // convert unsigned level (0 - 65535) to signed level (0 - 100) // nLevel = LOWORD(dwLevel) / (0xFFFF / LEVEL_POSITIONS); if (lpnLevel != NULL) *lpnLevel = nLevel; // // We have to verify lpmxcds pointer // TracePrintf_3(NULL, 5, TEXT("WavMixerGetLevel() = %d, %ld, 0x%08lX\n"), (int) nLevel, lpmxcds ? lpmxcds[0].lValue : 0, (unsigned long) dwLevel); if (lpmxcds != NULL && (lpmxcds = MemFree(NULL, lpmxcds)) != NULL) fSuccess = TraceFALSE(NULL); } // clean up // if (lpmxc != NULL && (lpmxc = MemFree(NULL, lpmxc)) != NULL) fSuccess = TraceFALSE(NULL); if (hWavMixer != NULL && lpWavMixer != NULL) lpWavMixer->nLastError = nLastError; return fSuccess ? 0 : -1; } //// // helper functions //// // WavMixerGetPtr - verify that wavmixer handle is valid, // (i) handle returned from WavMixerInit // return corresponding wavmixer pointer (NULL if error) // static LPWAVMIXER WavMixerGetPtr(HWAVMIXER hWavMixer) { BOOL fSuccess = TRUE; LPWAVMIXER lpWavMixer; if ((lpWavMixer = (LPWAVMIXER) hWavMixer) == NULL) fSuccess = TraceFALSE(NULL); else if (IsBadWritePtr(lpWavMixer, sizeof(WAVMIXER))) fSuccess = TraceFALSE(NULL); #ifdef CHECKTASK // make sure current task owns the wavmixer handle // else if (lpWavMixer->hTask != GetCurrentTask()) fSuccess = TraceFALSE(NULL); #endif return fSuccess ? lpWavMixer : NULL; } // WavMixerGetHandle - verify that wavmixer pointer is valid, // (i) pointer to WAVMIXER struct // return corresponding wavmixer handle (NULL if error) // static HWAVMIXER WavMixerGetHandle(LPWAVMIXER lpWavMixer) { BOOL fSuccess = TRUE; // // we have to initialize local variable // HWAVMIXER hWavMixer = NULL; if ((hWavMixer = (HWAVMIXER) lpWavMixer) == NULL) fSuccess = TraceFALSE(NULL); return fSuccess ? hWavMixer : NULL; }