Opening a LineThe TAPI lineOpen function opens a line device ready for making a call. The line device identifier and the negotiated TAPI version are passed to the function, which returns a line device handle (Table 11.5).
Listing 11.3a shows the first part of the function MakeCall that negotiates the TAPI version number and calls lineOpen to obtain a HLINE handle through which the call will be made. Listing 11.3a Function MakeCall Opening a lineHLINE g_hLine = NULL; HCALL g_hCall = NULL; void MakeCall(DWORD dwLineId, LPTSTR szPhoneNumber) { DWORD dwTAPIVersion, dwReturn; LPLINETRANSLATEOUTPUT lpTransOutput = NULL; DWORD dwSizeOfTransOut = sizeof (LINETRANSLATEOUTPUT); TCHAR szDialablePhoneNum[TAPIMAXDESTADDRESSSIZE + 1]; cout _T("Dialing: ") szPhoneNumber endl; dwTAPIVersion = NegotiateTAPIVersion(dwLineId); if(dwTAPIVersion == 0) return; if (dwReturn = lineOpen( g_hLineApp, // Usage handle for TAPI dwLineId, // Cannot use the LINEMAPPER value &g_hLine, // Line handle dwTAPIVersion, // API version number 0, // Must set to zero for Windows CE 0, // No data passed back // Can only make an outgoing call LINECALLPRIVILEGE_NONE, 0, // Media mode NULL)) // Must set to NULL for Windows CE { cout _T("Could not open line: ") dwReturn; return; } // Remainder of program follows. Translating a Telephone NumberTelephone numbers are usually stored in canonical format, and this may include the international dial-in number and area code. Canonical format telephone numbers must first be translated to a dialable format before making the call. This translation takes into account the configured current location of the user and determines if a local, long distance, or international call needs to be made. It is important to call lineTranslateAddress even if you have a correctly formatted telephone number for the current location. Some line devices place a "P" or "T" before the telephone number to indicate pulse or tone dialing when translating the number, and without this the call will fail. The function lineTranslateAddress (Table 11.6) is passed the TAPI usage handle, device line identifier, a negotiated TAPI version, and the phone number to be translated. The code in Listing 11.3b is a continuation of the MakeCall function started in Listing 11.3a. The LINETRANSLATEOUTPUT is another structure that has variable size depending on the amount of information appended after the structure as defined in tapi.h. The LINETRANSLATEOUTPUT structure lpTransOutput must be allocated to a sufficient size to receive the translated telephone number. In the first iteration of the "do" loop, the allocation is made to the size of LINETRANSLATEOUTPUT, with the dwTotalSize member being set to this size. On returning from calling lineTranslateAddress the dwNeededSize member will contain the actual required size of the LINETRANSLATEOUPUT structure. If this is greater than the size provided, the structure is reallocated and the function lineTranslateAddress called again.
Listing 11.3b Function MakeCall Translating phone number// Function MakeCall continued // Call translate address before dialing. do { // Allocate memory for lpTransOutput. if (!(lpTransOutput = (LPLINETRANSLATEOUTPUT) LocalAlloc(LPTR, dwSizeOfTransOut))) return; lpTransOutput->dwTotalSize = dwSizeOfTransOut; if (dwReturn = lineTranslateAddress ( g_hLineApp, // Usage handle for TAPI dwLineId, // Line device identifier dwTAPIVersion, // Highest TAPI version szPhoneNumber, // Address to be translated 0, // Must be 0 for Windows CE 0, // No associated operations lpTransOutput)) // Translated address { LocalFree(lpTransOutput); return; } if (lpTransOutput->dwNeededSize <= lpTransOutput->dwTotalSize) break; else { dwSizeOfTransOut = lpTransOutput->dwNeededSize; LocalFree (lpTransOutput); lpTransOutput = NULL; } } while (TRUE); // Save the translated phone number for dialing. wcscpy(szDialablePhoneNum, (LPTSTR) ((LPBYTE) lpTransOutput + lpTransOutput->dwDialableStringOffset)); cout _T("Translated Number: ") szDialablePhoneNum endl; // Remainder of program follows. Once a successful call to lineTranslateAddress has been made, the dwDialableStringOffset member is used to locate the translated telephone number at the end of the lpTransOutput structure. The telephone number is copied into the string buffer szDialablePhoneNum. wcscpy(szDialablePhoneNum, (LPTSTR) ((LPBYTE) lpTransOutput + lpTransOutput->dwDialableStringOffset)); Now that a translated telephone number has been obtained, the call can be made. Notice that a telephone number is translated using the line device identifier and not a handle to an open line device. This means that the telephone numbers can be translated without first opening the line device. Making the CallThe function lineMakeCall (Table 11.7) makes a call through a handle to an opened line device using a translated telephone number. The function returns a handle to the call in a HCALL variable. The call is made asynchronously that is, lineMakeCall will return before the dialing has completed. An application can monitor the various stages of making the call (such as dialing and then making the connection) through the callback function set when TAPI was initialized with a call to lineInitialize. The structure of this callback function is described in the next section. You should note that the callback function is called using the same thread that is used to initialize TAPI. If this is the same thread used to call lineMakeCall, take care in blocking the thread you might end up blocking the calls to the callback function as well.
Listing 11.3c Function MakeCall Dialing the number// Make the phone call. dwReturn = lineMakeCall( g_hLine, // handle to open line &g_hCall, // return handle to call szDialablePhoneNum, // phone number to dial 0, // default country code NULL); // call parameters if(dwReturn < 0) cout _T("Could not make call") dwReturn endl; else if(dwReturn >= 0) cout _T("Dialing asynchronously") endl; } void Listing11_3() { DWORD dwNumLines; if(!(dwNumLines = InitializeTAPI())) return; // insert telephone number here in place of xxxxxx MakeCall(6, _T("xxxxxx ")); } The code in Listing 11.3c completes the code in MakeCall. A function call is made to lineMakeCall to call the number and receive back a handle to the new call in g_hCall. Line Callback FunctionAn application initializing TAPI with lineInitialize should provide a callback function like that shown in Listing 11.3d. The function is passed a device handle and message type in dwMsg. When making a call, the dwMsg value will contain the value LINE_CALLSTATE, and these are generally the only messages an application making straightforward calls using TAPI will be interested in. When the dwMsg variable has the value LINE_CALLSTATE, the dwParam1 parameter contains a reason code for the notification, such as LINECALLSTATE_DIALING. These constants are defined in tapi.h. The most important reason code is LINECALLSTATE_CONNECTED once this has been received an application can start sending and receiving data through the connection. Listing 11.3d lineCallbackFuncVOID FAR PASCAL lineCallbackFunc(DWORD hDevice, DWORD dwMsg, DWORD dwCallbackInstance, DWORD dwParam1, DWORD dwParam2, DWORD dwParam3) { // only interested in LINE_CALLSTATE messages if(dwMsg != LINE_CALLSTATE) return; cout _T("LINE_CALLSTATE: "); // dwParam1 is the specific LINE_CALLSTATE // change occurring switch (dwParam1) { case LINECALLSTATE_IDLE: cout _T("Idle"); break; case LINECALLSTATE_DIALTONE: cout _T("Dial tone"); break; case LINECALLSTATE_DIALING: cout _T("Dialing"); break; case LINECALLSTATE_PROCEEDING: cout _T("Dialing has completed"); break; case LINECALLSTATE_RINGBACK: cout _T("Ring back"); break; case LINECALLSTATE_CONNECTED: cout _T("Connected"); break; case LINECALLSTATE_BUSY: cout _T("Busy"); break; case LINECALLSTATE_DISCONNECTED: switch (dwParam2) { case LINEDISCONNECTMODE_NORMAL: cout _T("Normal disconnect"); break; case LINEDISCONNECTMODE_UNKNOWN: cout _T("Unknown reason"); break; case LINEDISCONNECTMODE_REJECT: cout _T("Remote Party rejected"); break; case LINEDISCONNECTMODE_BUSY: cout _T("Remote busy"); break; default: cout _T("Disconnect: Other reason") dwParam2; break; Listing11_4(); // close call and line } break; default: cout _T("Other notification") dwParam1; } cout endl; } The reason code LINECALLSTATE_DISCONNECTED is sent when a call is terminated, and the dwParam2 parameter contains a reason code for the disconnection. A common disconnect code is LINEDISCONNECTMODE_BUSY, indicating that the telephone number being called is engaged. In the event of a LINECALLSTATE_DISCONNECTED reason code being received, an application should close the relevant TAPI handles associated with the call. In Listing 11.3d this is done by calling the function Listing11_4, as described in the next section. Shutting Down a CallYour application or the party being called can terminate a call. To drop a call, your application should call the lineDrop function to drop the call, and then lineDeallocateCall to free any resources associated with the call and close the HCALL handle (Listing 11.4). At this point, the open line device can be used to make another call, or lineClose can be called to close the HLINE handle. Listing 11.4 Shutting down a callvoid Listing11_4() { lineDrop(g_hCall, // call to drop NULL, // no data to be sent on drop 0); // length of data to be sent lineDeallocateCall(g_hCall); g_hCall = NULL; lineClose(g_hLine); g_hLine = NULL; ShutdownTAPI(); } In the event of the call being terminated by the other party, the call-back function will receive a LINECALLSTATE_DISCONNECTED notification as described in the previous section.
|