Making a Call with TAPI

Once a device's capabilities have been determined, TAPI functions can be used to make, maintain, and terminate a call. The steps required are the following:

  • Open a device line using the function lineOpen.

  • Translate the telephone number from canonical form (including international dial-in number and area code) to a dialable form (taking into account the user's current location).

  • Call lineMakeCall to make the call that connects asynchronously.

  • Provide a lineCallbackFunc function to receive notifications.

  • Close the call by calling lineDrop, lineDeallocateCall and lineClose.

Opening a Line

The 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).

Table 11.5. lineOpen—Opens a line device ready for making a call
lineOpen
HLINEAPP hLineAppHLINEAPP handle returned from calling lineInitialize.
DWORD dwDeviceIDLine device identifier to negotiate version for. Between 0 and dwNum-Lines1 returned from lineInitialize.
LPHLINE lphLinePointer to an HLINE variable that receives a handle to the open line device.
DWORD dwAPIVersionNegotiated TAPI version number returned from lineNegotiateAPI-Version.
DWORD dwExtVersionUnsupported, pass as zero.
DWORD dwCallbackInstanceApplication-defined value passed to the lineCallbackFunc function with notification messages.
DWORD dwPrivilegesIncoming call privileges. Pass LINECALLPRIVILEGE_NONE if incoming calls are not required or supported.
DWORD dwMediaModesMedia modes supported by application when receiving calls. Pass 0 if incoming calls are not supported.
LPLINECALLPARAMS const lpCallParamsCALLPARAMS structure specifying how the call should be made. Passing NULL specifies that a default call will be made.
LONG Return ValueZero for success, or a LINERR_ value indicating an error. These errors are defined in tapi.h.

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 line
HLINE 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 Number

Telephone 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.

Table 11.6. lineTranslateAddress—Translates a phone number from canonical to dialable form
lineTranslateAddress
HLINEAPP hLineAppHLINEAPP handle returned from calling lineInitialize.
DWORD dwDeviceIDLine device identifier to negotiate version for. Between 0 and dwNumLines1 returned from lineInitialize.
DWORD dwAPIVersionNegotiated TAPI version number returned from lineNegotiate-APIVersion.
LPCTSTR lpszAddressInTelephone number to be translated.
DWORD dwCardUnsupported, pass as zero.
DWORD dwTranslateOptionsTranslate options constants. Examples are
LINETRANSLATEOPTION_CANCELCALLWAITING to cancel call waiting.
LINETRANSLATEOPTION_FORCELOCAL to force a local call.
LPLINETRANSLATEOUTPUT lpTranslateOutputPointer to a LINETRANSLATEOUTPUT structure to receive the translated telephone number.
LONG Return ValueZero for success, or a LINERR_ value indicating an error. These errors are defined in tapi.h.

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 Call

The 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.

Table 11.7. lineMakeCall—Dials the specified number through an open line device
lineMakeCall
HLINE hLineHandle to an open line obtained by calling lineOpen.
LPHCALL lphCallPointer to an HCALL variable in which the call handle is returned.
LPCTSTR lpszDestAddressTelephone number to be dialed.
DWORD dwCountryCodeCountry code to use, or 0 for the default.
LPLINECALLPARAMS const lpCallParamsLINECALLPARAMS structure specifying how the call is to be made. If NULL, a default call is made.
LONG Return ValueZero for success, or a LINERR_ value indicating an error. These errors are defined in tapi.h.

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 Function

An 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_CONNECTEDonce this has been received an application can start sending and receiving data through the connection.

Listing 11.3d. lineCallbackFunc
VOID 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 Call

Your 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 call
void 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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.70.255