Figure 6 MYTAPI_.C
#include "comdial.h"
#include "resource.h"
extern HWND hTTYWnd;
/////////////////////////////////////////////////////////////////////
// telephonyInitialize - mega function to retrieve all
// configuration information needed for telephony, plus
// initialize TAPI and open the line.
////////////////////////////////////////////////////////////////////
int telephonyInitialize(HWND hWnd, HINSTANCE hInst, PMYTAPI mytapi)
{
LONG lrc;
int i;
LINEEXTENSIONID extensions;
// initialize application use of TAPI
while (lineInitialize(&mytapi->hTAPI, hInst,
mytapi->CallbackProc = (LINECALLBACK)MakeProcInstance((FARPROC)LineCallBackProc,
hInst),
"TAPIProcess", &mytapi->dwNumLines) ==
LINEERR_REINIT) {
Sleep (5); // sleep for five seconds
if (MessageBox(hWnd, "Telephony system is reinitializing - Click" \
" Cancel to abort", "Error", MB_RETRYCANCEL) ==IDCANCEL)
goto error;
} // end while (TAPI reinitializing)
// bool indicates lineInitialize called successfully
mytapi->bInitialized = TRUE;
// check every logical line for one that support modem data
for (i=0; (unsigned)i<mytapi->dwNumLines; i++) {
// negotiate version of TAPI to use
lrc = lineNegotiateAPIVersion(mytapi->hTAPI, i, WIN95TAPIVERSION,
WIN95TAPIVERSION, &mytapi->dwVersionToUse,
&extensions);
if (lrc)
continue;
// get line device caps
lrc = mylineGetDevCaps (mytapi);
if (lrc)
goto error;
// check that the line supports answering machines
if (mytapi->pLinedevcaps->dwMediaModes & LINEMEDIAMODE_AUTOMATEDVOICE) {
mytapi->dwLine = i;
break;
}
}
return 0;
error:
// error! clean up and return error code
telephonyShutdown(mytapi);
return lrc;
}
/////////////////////////////////////////////////////////////////////
// telephonyOpen - open the telephone line device
//
////////////////////////////////////////////////////////////////////
int telephonyOpen(HWND hWnd, HINSTANCE hInst, PMYTAPI mytapi)
{
LONG lrc;
// open the line device
lrc = lineOpen(mytapi->hTAPI, mytapi->dwLine, &mytapi->hLine,
mytapi->dwVersionToUse, 0, (DWORD)mytapi,
LINECALLPRIVILEGE_OWNER,
LINEMEDIAMODE_AUTOMATEDVOICE,
NULL);
if (lrc)
goto error;
// bool indicates lineOpen called successfully
mytapi->bLineopen = TRUE;
// get the telephony icon and make it ours
myDrawTAPIIcon(hWnd, mytapi);
// receive all possible status messages for the
// line device and address
lineSetStatusMessages(mytapi->hLine,
mytapi->pLinedevcaps->dwLineStates,
0);
// set ring count for the no-message waiting situation
lineSetNumRings (mytapi->hLine, 0, RINGCNT);
lineGetNumRings(mytapi->hLine, 0, &mytapi->nRingCnt);
// success
return 0;
error:
// error! clean up and return error code
telephonyShutdown(mytapi);
return lrc;
} // end procedure (telephony initialize)
·
·
·
/////////////////////////////////////////////////////////////////////
// mylineGetWaveID - get wave handle
////////////////////////////////////////////////////////////////////
LONG mylineGetWaveID (DWORD dwSelect, LPSTR waveDev, PMYTAPI mytapi)
{
DWORD dwWaveDev;
VARSTRING *vs;
LONG lrc;
DWORD dwSize;
// allocate memory for structure
vs = (VARSTRING *) calloc (1, sizeof(VARSTRING));
// set structure size
vs->dwTotalSize = sizeof(VARSTRING);
do {
// get information into structure
if (dwSelect == LINECALLSELECT_LINE)
lrc = lineGetID(mytapi->hLine, 0L, NULL, dwSelect, vs,
waveDev);
if (dwSelect == LINECALLSELECT_CALL)
lrc = lineGetID(mytapi->hLine, 0L, mytapi->hCall, dwSelect,
vs, waveDev);
// bomb out if error
if (lrc) {
free (vs);
return -1;
}
// reallocate and try again
if (vs->dwTotalSize < vs->dwNeededSize) {
dwSize = vs->dwNeededSize;
free (vs);
vs = (VARSTRING *) calloc(1, dwSize);
vs->dwTotalSize = dwSize;
continue;
} /* end if (need more space) */
break; /* success */
} while (TRUE);
// copy wave id
dwWaveDev = (DWORD) *((DWORD *)((LPSTR)vs + vs->dwStringOffset));
free (vs);
return dwWaveDev;
} /* end function (mylineGetWaveID) */
/////////////////////////////////////////////////////////////////////
// mylineGetDevCaps - get LINEDEVCAPS structure
////////////////////////////////////////////////////////////////////
LONG mylineGetDevCaps( PMYTAPI mytapi)
{
LONG lrc;
DWORD dwsize;
// if space already allocated for structure, free it up
if (mytapi->bLinedevcapsalloced) {
free (mytapi->pLinedevcaps);
mytapi->bLinedevcapsalloced = FALSE;
}
// allocate memory for structure
mytapi->pLinedevcaps = (LINEDEVCAPS *) calloc(1, sizeof(LINEDEVCAPS));
if (!mytapi->pLinedevcaps)
return LINEERR_NOMEM;
mytapi->bLinedevcapsalloced = TRUE;
// set structure size
mytapi->pLinedevcaps->dwTotalSize = sizeof(LINEDEVCAPS);
do {
// get information into structure
lrc = lineGetDevCaps(mytapi->hTAPI, mytapi->dwLine,
mytapi->dwVersionToUse,
0, mytapi->pLinedevcaps);
// bomb out if error
if (lrc) {
free (mytapi->pLinedevcaps);
mytapi->bLinedevcapsalloced = FALSE;
return lrc;
}
dwsize = mytapi->pLinedevcaps->dwNeededSize;
// reallocate and try again
if (mytapi->pLinedevcaps->dwTotalSize < dwsize) {
free (mytapi->pLinedevcaps);
mytapi->bLinedevcapsalloced = FALSE;
mytapi->pLinedevcaps = (LINEDEVCAPS *) calloc(1, dwsize);
if (!mytapi->pLinedevcaps)
return LINEERR_NOMEM;
mytapi->bLinedevcapsalloced = TRUE;
mytapi->pLinedevcaps->dwTotalSize = dwsize;
continue;
}
break;
} while (TRUE);
return lrc;
}
/////////////////////////////////////////////////////////////////////
// mylineGetCallStatus - get LINECALLSTATUS structure
////////////////////////////////////////////////////////////////////
LONG mylineGetCallStatus( PMYTAPI mytapi)
{
LONG lrc;
DWORD dwsize;
// if space already allocated for structure, free it up
if (mytapi->bLinecallstatusalloced) {
free (mytapi->pLinecallstatus);
mytapi->bLinecallstatusalloced = FALSE;
}
// allocate memory for structure
mytapi->pLinecallstatus = (LINECALLSTATUS *) calloc(1,
sizeof(LINECALLSTATUS));
if (!mytapi->pLinecallstatus)
return LINEERR_NOMEM;
mytapi->bLinecallstatusalloced = TRUE;
// set structure size
mytapi->pLinecallstatus->dwTotalSize = sizeof(LINECALLSTATUS);
do {
// get information into structure
lrc = lineGetCallStatus(mytapi->hCall, mytapi->pLinecallstatus);
// bomb out if error
if (lrc) {
free (mytapi->pLinecallstatus);
mytapi->bLinecallstatusalloced = FALSE;
return lrc;
}
// reallocate and try again
dwsize = mytapi->pLinecallstatus->dwNeededSize;
if (mytapi->pLinecallstatus->dwTotalSize < dwsize) {
free (mytapi->pLinecallstatus);
mytapi->bLinecallstatusalloced = FALSE;
mytapi->pLinecallstatus = (LINECALLSTATUS *) calloc(1, dwsize);
if (!mytapi->pLinecallstatus)
return LINEERR_NOMEM;
mytapi->bLinecallstatusalloced = TRUE;
mytapi->pLinecallstatus->dwTotalSize = dwsize;
continue;
}
break;
} while (TRUE);
return lrc;
}
/////////////////////////////////////////////////////////////////////
// telephonyShutdown - mega functions to close line, shut down
// telephony, close modem handle, restore serial device
// configuration, and free up various allocated structures.
////////////////////////////////////////////////////////////////////
void telephonyShutdown( PMYTAPI mytapi)
{
// close line if open
if (mytapi->bLineopen)
lineClose(mytapi->hLine);
// shutdown tapi if initialized
if (mytapi->bInitialized)
lineShutdown(mytapi->hTAPI);
// free up various structures if allocated
if (mytapi->bLinedevcapsalloced)
free (mytapi->pLinedevcaps);
if (mytapi->bLinedevstatusalloced)
free (mytapi->pLinedevstatus);
if (mytapi->bLinecallinfoalloced)
free(mytapi->pLinecallinfo);
if (mytapi->bLinecallstatusalloced)
free(mytapi->pLinecallstatus);
// set flags to indicate that the structures are no longer
// allocated
mytapi->bLinedevcapsalloced = FALSE;
mytapi->bLinedevstatusalloced = FALSE;
mytapi->bLineopen = FALSE;
mytapi->bInitialized = FALSE;
mytapi->bLinecallinfoalloced = FALSE;
mytapi->bLinecallstatusalloced = FALSE;
mytapi->bWaitForCall = FALSE;
} // end function (telephonyShutdown)
/////////////////////////////////////////////////////////////////////
// LineCallBackProc - message function for TAPI events
////////////////////////////////////////////////////////////////////
/* callback function */
void FAR PASCAL LineCallBackProc(DWORD dwDevice,DWORD dwMessage,
DWORD dwInstance,DWORD dwParam1,
DWORD dwParam2,DWORD dwParam3)
{
LONG lrc;
PMYTAPI mytapi = (PMYTAPI)dwInstance;
switch (dwMessage) {
case LINE_CALLSTATE:
processCallState (mytapi, dwDevice, dwParam1, dwParam3);
break;
case LINE_CLOSE:
break;
case LINE_LINEDEVSTATE:
switch (dwParam1) {
case LINEDEVSTATE_RINGING:
mytapi->nRings = dwParam3;
if (mytapi->bWaitForCall && mytapi->nRings == mytapi->nRingCnt) {
// answer incoming calls
lrc = lineAnswer(mytapi->hCall,NULL,0);
if (!(lrc >0 )) {
ProcessTAPIError(lrc);
myMessageBox("Error answering call");
}
mytapi->nRings = 0;
}
break;
}
break;
case LINE_MONITORDIGITS:
switch (dwParam2) {
case LINEDIGITMODE_DTMF:
{
char name[30];
if (mytapi->iPlayState == PLAYSTATE_IDLE) {
if (LOBYTE(dwParam1) == '1') {
if (mytapi->h_waveout =playSound
(mytapi->dwWaveOutID,"pw.wav", hTTYWnd)) {
mytapi->iPlayState = PLAYSTATE_PASSWORD;
}
} else if (LOBYTE(dwParam1) == '2') {
if (mytapi->h_waveout =playSound (1,"msg-1.wav",
hTTYWnd)) {
mytapi->iPlayState = PLAYSTATE_RECORD;
recordMessage (mytapi->dwWaveInID);
}
}
} else if (mytapi->iPlayState == PLAYSTATE_PASSWORD) {
if (LOBYTE(dwParam1) ==
mytapi->szPassword[mytapi->inx])
mytapi->inx++;
else
mytapi->inx = 0;
if (!mytapi->szPassword[mytapi->inx]) {
/* successful password */
// begin playing messages
mytapi->inx = 0;
if (mytapi->nMsgCnt > 0) {
mytapi->nPlayCnt = 0;
wsprintf(name, "msg-%d.wav",
mytapi->nPlayCnt);
if (mytapi->h_waveout =playSound
(mytapi->dwWaveOutID,name, hTTYWnd))
mytapi->iPlayState =PLAYSTATE_PLAYBACK;
} else {
mytapi->h_waveout =playSound
(mytapi->dwWaveOutID,
"nomsg.wav", hTTYWnd);
}
}
}
break;
}
case LINEDIGITMODE_DTMFEND:
break;
default:
break;
} //end switch
break;
case LINE_MONITORTONE:
break;
case LINE_REPLY:
if (dwParam2 < 0)
ProcessTAPIError (dwParam2);
default:
break;
} //end switch
return;
} /* LineCallBackProc */
·
·
·
/////////////////////////////////////////////////////////////////////
// myMessageBox - easy message box function
////////////////////////////////////////////////////////////////////
void myMessageBox (LPSTR s)
{
MessageBox (NULL, "Error", s, MB_OK);
}
/////////////////////////////////////////////////////////////////////
// processCallState
////////////////////////////////////////////////////////////////////
void processCallState (PMYTAPI mytapi, DWORD dwDevice, DWORD dwState,
DWORD dwPrivilege)
{
LONG lrc;
HMENU hMenu;
switch (dwPrivilege) {
case LINECALLPRIVILEGE_MONITOR:
break;
case LINECALLPRIVILEGE_OWNER:
// update local call information
mylineGetCallStatus(mytapi);
// update menus
hMenu = GetMenu(hTTYWnd);
// answer call
if (mytapi->pLinecallstatus->dwCallFeatures &
LINECALLFEATURE_ANSWER)
EnableMenuItem( hMenu, IDM_ANSWER, MF_ENABLED | MF_BYCOMMAND );
else
EnableMenuItem( hMenu, IDM_ANSWER, MF_GRAYED | MF_DISABLED |
MF_BYCOMMAND ) ;
// save call handle and get device ids
if (mytapi->hCall != (HCALL)dwDevice) {
mytapi->hCall = (HCALL)dwDevice;
mytapi->dwWaveInID = mylineGetWaveID(LINECALLSELECT_CALL,
"wave/in", mytapi);
mytapi->dwWaveOutID = mylineGetWaveID(LINECALLSELECT_CALL,
"wave/out", mytapi);
}
break;
default:
break;
} //end switch
switch (dwState) {
case LINECALLSTATE_IDLE:
// deallocate call resources
lineDeallocateCall (mytapi->hCall);
mytapi->hCall = NULL;
break;
·
·
·
case LINECALLSTATE_CONNECTED:
mytapi->h_waveout =playSound (mytapi->dwWaveOutID,"greeting.wav",
hTTYWnd);
mytapi->iPlayState = PLAYSTATE_IDLE;
mytapi->inx = 0;
lrc = lineMonitorDigits(mytapi->hCall, LINEDIGITMODE_DTMF);
break;
default:
break;
} //end switch
return;
}
Figure 8 Handling MM_WOM_DONE
case MM_WOM_DONE:
/* Unprepare the header */
waveOutUnprepareHeader((HWAVEOUT)wParam,(LPWAVEHDR)lParam,
sizeof(WAVEHDR));
waveOutClose((HWAVEOUT)wParam); /* close wave device */
free (((LPWAVEHDR)lParam)->lpData); /* free the wave data */
free ((LPWAVEHDR)lParam); /* free the header */
if (mytapi.iPlayState == PLAYSTATE_PLAYBACK) {
if (mytapi.nPlayCnt < mytapi.nMsgCnt) {
mytapi.nPlayCnt++;
wsprintf (name, "msg-%d.wav", mytapi.nPlayCnt);
mytapi.h_waveout=playSound (mytapi.dwWaveOutID, name,
hTTYWnd);
} else {
mytapi.iPlayState = PLAYSTATE_IDLE;
mytapi.inx = 0;
mytapi.nPlayCnt = 0;
}
}
break;
Figure 9 Handling LINE_CALLSTATE
case LINE_CALLSTATE:
// (all cases of dwParam1)
switch (dwParam3) {
case LINECALLPRIVILEGE_MONITOR:
break; // I don't have privilege to answer
case LINECALLPRIVILEGE_OWNER:
// update local call information, menus
.
.
.
// save call handle and get device ids
if (mytapi.hCall != (HCALL)dwDevice) {
mytapi.hCall = (HCALL)dwDevice;
mytapi.dwWaveInID =
mylineGetWaveID(LINECALLSELECT_CALL, "wave/in");
mytapi.dwWaveOutID =
mylineGetWaveID(LINECALLSELECT_CALL, "wave/out");
}
break;
default:
break;
} //end switch
Figure 10 Cleaning Up After Recording
case MM_WIM_DATA:
waveInUnprepareHeader (mytapi.h_wavein, (LPWAVEHDR)lParam,
sizeof(WAVEHDR));
waveInClose (mytapi.h_wavein); /* close wave device */
/* drop the call */
if (mytapi.hCall) {
if ((lrc = lineDrop (mytapi.hCall, NULL, 0)) < 0) {
ProcessTAPIError (lrc);
MessageBox (hTTYWnd, "Error dropping call", "", MB_OK);
}
}
mytapi.nMsgCnt++;
wsprintf (name, "msg-%d.wav", mytapi.nMsgCnt);
saveMessage (name, (LPWAVEHDR)lParam); /* save the message */
/* free 60s message buffer */
GlobalFree ((HANDLE)((LPWAVEHDR)lParam)->dwUser);
// set ring count for the message-waiting situation to implement
// toll saver feature
lineSetNumRings (mytapi.hLine, 0, max(0, RINGCNT-2));
lineGetNumRings (mytapi.hLine, 0, &mytapi.nRingCnt);
mytapi.iPlayState = PLAYSTATE_IDLE;
mytapi.iPlaySubState = PLAYSUBSTATE_PASSWORD0;
break;