Chapter 28

Using TAPI to Handle Incoming Calls


CONTENTS


Now that you know how to use TAPI services to handle outbound calling, it's time to create an example of handling inbound calls. In this chapter, you'll learn how to use the TAPILINE control that ships with the book to create a simple Visual Basic program that will wait for an incoming call and notify you with "ring." You can then pick up an attached receiver to accept the call. If you have a speaker phone card in your workstation, you can simply click a button on the screen and begin to talk.

Before you can accept incoming calls, you need to open an available line device with parameters that tell TAPI you plan to use the line for incoming calls. This chapter will show you how to select a valid line device and how to use the lineOpen method to prepare TAPI to respond to inbound calls.

In order to respond to and accept incoming calls, you need to know how to interpret a new set of TAPI messages. These messages are sent to the TapiCallBack event of the TAPILINE control. In this chapter, you'll learn which messages are used to monitor inbound calls and how to write Visual Basic code that responds to each message.

Finally, you'll learn how to end inbound calls properly, including how to respond when the caller on the other line hangs up unexpectedly. When you finish the project in this chapter, you'll know how to write telephone answering routines for all your Visual Basic and VBA-language programs.

Process Flow for Inbound Calls

Before you start to code the example, it's important to go over the basics of how to use TAPI services to handle inbound calls. The process is not very complex, but it can be tricky because you need to write a program that can wait for a telephone event and then respond accordingly. Since the program is designed to wait for a call, it is the telephone that really controls the program flow.

There are a total of six basic steps to using TAPI to process inbound calls (see Figure 28.1). Several of these steps are pretty much the same as those used to handle outbound calls.

Figure 28.1 : The process flow for handling inbound call

The six steps are

This process can best be illustrated using a typical voice call between two people. Let's assume you need to create a Visual Basic program that will answer incoming calls and route them to a telephone handset or speakerphone. You'll want to allow the user to start TAPI, wait for a call, accept any inbound calls, and, at the end of a conversation, end the call and wait for another one.

Starting TAPI services on the workstation requires initializing the TAPI driver (lineInitialize), verifying the current TAPI API version (lineNegotiateAPIVersion), and collecting information on all the available TAPI devices on the workstation (lineGetDevCaps). Then you must select one of the line devices that is capable of handling inbound calls and open it for inbound handling (lineOpen). By opening the device in this way, you are telling TAPI that you want to be told whenever an inbound call shows up on the line.

At this point, all you need to do is wait for TAPI to tell you when a call appears on the selected line. When it does, your program will receive a message (through the TapiCallBack event) telling you that a call is being "offered" to you. If you decide to accept the call, you can retrieve the handle to the call and answer (using the lineAnswer method). Once this is done, your program can pass the call to the user and wait until the conversation is completed.

There are basically two ways a phone conversation ends: Either you hang up or the person (machine) on the other end hangs up. In the first case, you can use the lineDrop and lineClose methods to end the call. If, however, the other party hangs up (possibly unexpectedly), the line is automatically closed by TAPI. However, you still need to release your program's hold on the call handle (using lineDeallocateCall). In either case, performing lineClose or lineDeallocateCall will prepare the line device for receiving additional inbound calls.

There are two main points to keep in mind when building applications to accept inbound calls. First, after you open the device using parameters that inform TAPI that you want to be notified of any inbound calls, you need to watch for (and respond to) TAPI messages that occur when a call appears. The second main point is that once a call is accepted and in progress, your program needs to watch for (and respond to) TAPI messages that indicate the call has ended. In other words, your inbound call handler has two main jobs:

The rest of this chapter shows you how to use the TAPILINE control and Visual Basic to create a program that performs all the tasks necessary for handling inbound voice calls.

Note
The example in this chapter assumes your workstation has a modem or telephony card that is capable of handling voice calls. If your modem is able to handle only data calls, you can still build the project described here. However, you will be able to complete only data modem calls, not voice calls.

The TAPIANS Project

The rest of this chapter is devoted to building a Visual Basic application that handles inbound calls. You need to write code that will handle initializing and opening an inbound line device, and code that will respond to TAPI messages regarding calls appearing on the line. Along with the code you write, you'll need to use the TAPILINE control and the Visual Basic TAPI library files that are on the CD-ROM that ships with this book.

Note
For more information on the TAPILINE control and the TAPI library files, see Chapter 26, "TAPI Tools-Using the TAPILINE Control."

Finally, you'll need to design an input form that allows users to start the TAPI call monitor, accept offered calls, and hang up completed calls.

When you are done with this example, you'll have a handful of TAPI answering routines that you can use in all your Visual Basic or VBA-compatible programs.

Creating the TAPIANS Form

First, you need to lay out a Visual Basic form with four command buttons, one list box, and one multiline text box. This form will be used to start TAPI services and accept and end calls on the selected line. Refer to Table 28.1 and Figure 28.2 when building the TAPIANS form.

Figure 28.2 : Laying out the TAPIANS form

Table 28.1. Controls for the TAPIANS form.
ControlProperty Setting
VB.Form Name frmTapiAns
 Caption "Form1"
 Height 3525
 Left 1245
 Top 1215
 Width 6750
VB.TextBox Name txtStatus
 BackColor &H00C0C0C0&
 Height 1635
 Left 1500
 MultiLine -1 'True
 ScrollBars 3 'Both
 TabIndex 5
 Top 1320
 Width 4995
VB.ListBox Name lstLines
 Height 1035
 Left 1500
 TabIndex 4
 Top 120
 Width 3195
VB.CommandButton Name cmdButton
 Caption "E&xit"
 Height 495
 Index 3
 Left 120
 TabIndex 3
 Top 1920
 Width 1215
VB.CommandButton Name cmdButton
 Caption "&Hang Up"
 Height 495
 Index 2
 Left 120
 TabIndex 2
 Top 1320
 Width 1215
VB.CommandButton Name cmdButton
 Caption "&Answer Call"
 Height 495
 Index 1
 Left 120
 TabIndex 1
 Top 720
 Width 1215
VB.CommandButton Name cmdButton
 Caption "&Start"
 Height 495
 Index 0
 Left 120
 TabIndex 0
 Top 120
 Width 1215
VB.Image Name Image1
 Height 1035
 Left 4800
 Stretch -1 'True
 Top 180
 Width 1695
MCI.MMControl Name MMControl1
 Height 330
 Left 180
 TabIndex 6
 Top 2460
 Visible 0 'False
 Width 3540
TapilineLib.Tapiline Name Tapiline1
 Left 600
 Top 2820

There are a few things that you need to keep in mind when building this form. First, be sure to add the TAPILINE control to your project (Tools | Custom Controls) before you start building the form. Also notice that you need to add the MCI Multimedia control to the form. You'll use that control to produce the sound of a ringing telephone whenever a call appears on the monitored line. Notice that the MCI control has its Visible property set to FALSE. There is also an Image control on the form. You'll load an image of a multiline telephone into this control at run-time. Be sure to set the Stretch property of the Image control to TRUE. Finally, by now you should recognize the control array used with the command buttons. Be sure to add the first button, set its values (including the Index value), and then use Edit | Copy and Edit | Paste to add all the buttons in the control array.

When you are finished building the form, save it as TAPIANS.FRM and save the project as TAPIANS.VBP before you go on to the next section.

Coding the TAPIANS Form

There are a handful of code routines you need to add to the TAPIANS form. But, before you add code to the form, you need to add two BAS modules to the project (File | Add File). These modules can be found on the CD-ROM that ships with this book. The first is the TAPILINE.BAS module. This module contains all the TAPI constants, structures, and helper APIs needed to support the TAPILINE control. The second BAS module you need to add to the project is the TAPICALL.BAS module. This routine contains several helper functions and subroutines for decoding TAPI messages. There are also several general routines in this module to handle typical TAPI operations for Visual Basic programs

.

Tip
The easiest way to add the TAPICALL and TAPILINE modules to your project is to first copy them into the project directory, and then use the File | Add File menu option to place them into your project. You probably have more than one copy of these routines on your hard disk. You used them in Chapter 26, "TAPI Tools-Using the TAPILINE Control." If you can't find them on your hard disk, you can find them on the CD-ROM that ships with this book.

Coding the Form_Load and Form_Unload Events

The first code to add to the project is the code for the Form_Load event. This code calls several support routines and handles general initialization controls. Add the code shown in Listing 28.1 to the Form_Load event of the form.


Listing 28.1. Coding the Form_Load event.
Private Sub Form_Load()
    '
    ClearHandles ' start clean
    TapiStart ' init tapi & get version
    TapiGetDevCaps ' get device names
    MCIStart ' init multimedia control
    '
    Me.Left = (Screen.Width - Me.Width) / 2
    Me.Top = (Screen.Height - Me.Height) / 2
    '
    Me.Caption = "TAPI Answer Demo"
    Me.Image1.Picture = LoadPicture(App.Path & "\phone.wmf")
    txtStatus.Text = ""
    '
    cmdButton(1).Enabled = False
    cmdButton(2).Enabled = False
    '
End Sub

The code in the Form_Load event calls for support routines to set up TAPI and the MCI control. The rest of the code centers the form and sets properties for the form and various controls on the form.

Listing 28.2 shows the code for the Form_Unload event. This code makes sure that TAPI services are properly closed down before exiting the program. Add this code to the TAPIANS form.


Listing 28.2. Adding code to the Form_Unload event.
Private Sub Form_Unload(Cancel As Integer)
    '
    ' close up shop
    '
    Tapiline1.LineDrop "", 0 ' drop active call
    Tapiline1.LineClose ' close open line
    Tapiline1.LineShutdown ' uninit TAPI
    '
End Sub

Nothing complex here. The only item to note is the inclusion of the two parameters for the lineDrop method. These parameters are used only when passing user information on ISDN lines. Since this program assumes you'll be using voice-grade telephone lines, the values are left empty.

Adding the TAPIANS Support Routines

There are just a few support routines needed for the TAPIANS project. These routines handle the initialization of TAPI and multimedia services for the workstation. You'll also add a routine to clear out TAPI pointers at the start of the project and the end of a call.

First, you need a routine to handle the initial startup of TAPI services for the workstation. This routine should start TAPI, get a count of all the available line devices, and confirm the API version of the devices. The code in Listing 28.3 shows you how to do this. Add a new sub-routine called TAPIStart on the form (use Insert | Procedure), and enter the code shown in Listing 28.3.


Listing 28.3. Adding the TAPIStart procedure.
Public Sub TapiStart()
    '
    ' start tapi and get lines
    '
    Dim x As Integer
    Dim lRtn As Long
    '
    lRtn = Tapiline1.LineInitialize(App.EXEName)
    If lRtn < 0 Then
        MsgBox "Unable to Start TAPI!", vbCritical
        Unload Me
    End If
    '
    For x = 0 To Tapiline1.NumDevices - 1
        Tapiline1.LineNegotiateAPIVersion x, &H10000, &H10004
    Next x
    '
End Sub

You've seen most of this before. Notice that the lRtn value is checked after attempting to start TAPI. You'll see that the test is for a value less than zero. Several TAPI functions return positive values instead of zero when they are successful. However, error values are always less than zero. You'll also notice the hexadecimal values &H10000 (decimal 65536) and &H10004 (decimal 65540) as parameters in the lineNegotiateAPIVersion method. These are the minimum (1.0) and maximum (1.4) API versions supported by the TAPILINE control. Notice also that the numDevices property of the TAPILINE control is set to the total number of recognized line devices for the workstation. You'll use this value to collect information on all the registered line devices.

Next, you need to add a routine to get the capabilities of all the line devices you discovered in the TAPIStart routine. You'll use the numDevices property just mentioned above. Listing 28.4 shows the new routine TapiGetDevCaps. This routine fills a list box with the names of all the registered devices. With this list, the user can select the device most appropriate for voice calls. Add the code in Listing 28.4 to your form.


Listing 28.4. Adding the TapiGetDevCaps routine.
Public Sub TapiGetDevCaps()
    '
    ' load device names into list box
    '
    Dim a As Long
    Dim b As LINEDEVCAPS
    Dim c As String * 2048
    Dim x As Integer
    '
    For x = 0 To Tapiline1.NumDevices - 1
        ' make the call to get dev caps
        a = Tapiline1.LineGetDevCaps(x)
        If a < 0 Then
            lstLines.AddItem "<<<ERROR>>> DevCaps..." & LineErr(a)
        Else
            LineDevCapsFunc TAPI_READ, b, c
            c = Clean(c)
            lstLines.AddItem GetOffset(Len(b) + 4, b.dwLineNameOffset, Âb.dwLineNameSize, c)
        End If
    Next x
    '
End Sub

You can see that after calling the lineGetDevCaps method of the TAPILINE control, you need to call the lineDevCapsFunc API function to retrieve the data in the LINEDEVCAPS structure. This data is filled in by TAPI when you use the lineGetDevCaps method. This routine uses the GetOffset helper function (from the TAPICALLS library) to pull out the line device name and insert it into the list control on the form.

Since this project will use a WAV file to signal a ringing phone, you'll need to add some code to initialize the MCI Multimedia control to handle WAV output. Add a new subroutine called MCIStart and enter the code shown in Listing 28.5.


Listing 28.5. Adding the MCIStart routine.
Public Sub MCIStart()
    '
    ' init MCI control for ringing phone
    '
    MMControl1.Notify = False
    MMControl1.Wait = True
    MMControl1.Shareable = False
    MMControl1.DeviceType = "WaveAudio"
    MMControl1.filename = App.Path & "\ringin.wav"
    MMControl1.Command = "Open"
    '
End Sub

Not too much to comment on here, either. Just note that the control accesses the RINGIN.WAV file. This should be placed in your application directory. It is included on the CD-ROM that accompanies this book. If you have it stored in another location, be sure to modify the code in Listing 28.5 to point to the proper folder.

The last support routine you need to add to the project is one that clears TAPILINE control properties related to a completed call. You'll use this routine at the very beginning of the program (for initialization) and at the end of each call (for cleanup). Add a new subroutine called ClearHandles and enter the code shown in Listing 28.6.


Listing 28.6. Adding the ClearHandles routine.
Public Sub ClearHandles()
    '
    ' set all control handles to zero
    '
    Tapiline1.LineHandle = 0
    Tapiline1.HandleToCall = 0
    Tapiline1.AddressID = 0
    '
End Sub

These properties are all set when a call is accepted on a line device. Once a call is ended, you need to clear these properties in preparation for the next call.

Save the form (TAPIANS.FRM) and project (TAPIANS.VBP) before continuing.

Adding the TapiCallBack Event Code

The next code you need to add to the project relates to detecting and responding to TAPI messages (TapiCallBack). The TapiCallBack event of the TAPILINE control receives all messages generated by the TAPI system. As mentioned in earlier chapters, there are several different messages, each with their own set of accompanying parameters

.

Note
For more information on TAPI messages, their use, and meaning, refer to Chapter 23, "TAPI Architecture."

In this example, you need to keep track of only two messages:

The LINE_CALLSTATE message is sent whenever the state of the selected line has changed. This program will watch for messages that indicate there is a new call on the line (dwParam1 = LINECALLSTATE_OFFERED) or when the party on the other end of the line closed the call unexpectedly (dwParam1 = LINECALLSTATE_IDLE). The LINE_CLOSE message is sent whenever the user ends the call normally.

You can monitor the message activity by adding code to the TapiCallBack event that checks each message sent by TAPI. This is done using a SELECT CASE structure to compare the incoming message to a list of messages for which you are waiting. The code in Listing 28.7 shows how this is done. Add this code to the TapiCallBack event.


Listing 28.7. Adding code to the TapiCallBack event.
Private Sub Tapiline1_TapiCallBack(ByVal hDevice As Long, ByVal dwMessage As Long, ÂByVal dwInstance As Long, ByVal dwParam1 As Long, ByVal dwParam2 As Long, ByVal ÂdwParam3 As Long)
    '
    ' handle TAPI messages
    '
    Dim cMsg As String
    '
    ' handle call actions
    Select Case dwMessage
        Case LINE_CALLSTATE ' state of call on line changed
            Select Case dwParam1
                Case LINECALLSTATE_OFFERING ' get call handle
                    Tapiline1.HandleToCall = hDevice ' update handle to call
                    MMControl1.Command = "play" ' ring me!
                Case LINECALLSTATE_IDLE ' they hung up on me!
                    Tapiline1.LineDeallocateCall ' dump pointer
                    Tapiline1.HandleToCall = 0 ' clear property
                    AddText txtStatus, "LineDeallocate Successful"
            End Select
        Case LINE_CLOSE ' line was closed
            cmdButton_Click 2 ' force hangup
    End Select
    '
    ' report status to user
    cMsg = TapiCallBackHandler(hDevice, dwMessage, dwInstance, dwParam1, dwParam2, ÂdwParam3)
    AddText txtStatus, cMsg
    '
End Sub

The code in Listing 28.7 shows the SELECT CASE structure monitoring two messages-LINE_CALLSTATE and LINE_CLOSE. When the LINE_CALLSTATE message appears, additional checking is performed to determine the exact state of the call. If a new call is appearing on the line (LINECALLSTATE_OFFERING), the program updates the HandleToCall property and then rings the workstation to tell the user a call is coming in.

If the call state has changed to completed (LINECALLSTATE_IDLE), the routine releases memory allocated to the call and clears the HandleToCall property in preparation for the next incoming call.

When the LINE_CLOSE message appears, that means the user has completed the call. The code here makes a call to the cmdButton array that will act as if the user pressed the HangUp button (you'll code that in just a moment).

You'll also notice that the routine contains calls to the TapiCallBackHandler function. This function interprets the TAPI message and creates a text string that can be shown to the user to indicate the progress of the call.

Coding the cmdButton Array

The last code you need to add will handle the user's actions on the command buttons. There are four possible actions that the user can select:

Listing 28.8 shows the complete code for the cmdButton_Click event.


Listing 28.8. The code for the cmdButton_Click event.
Private Sub cmdButton_Click(Index As Integer)
    '
    ' open a line for monitoring
    '
    Dim lRtn As Long
    Dim lPrivilege As Long
    Dim lMediaMode As Long
    '
    ' check for start up selection only
    If Index = 0 Then
        If lstLines.ListIndex = -1 Then
            MsgBox "Select a line first!", vbInformation
            Exit Sub
        End If
    End If
    '
    ' set line parameters
    lPrivilege = LINECALLPRIVILEGE_OWNER + LINECALLPRIVILEGE_MONITOR
    lMediaMode = LINEMEDIAMODE_INTERACTIVEVOICE
    '
    ' react to user selection
    Select Case Index
        Case 0 ' start looking
            lRtn = Tapiline1.LineOpen(lstLines.ListIndex, 0, lPrivilege, ÂlMediaMode)
            If lRtn < 0 Then
                AddText txtStatus, "<<LineOpen ERROR>> " & LineErr(lRtn)
            Else
                AddText txtStatus, "LineOpen Successful"
                AddText txtStatus, "Waiting for an incoming call..."
                '
                cmdButton(0).Enabled = False
                cmdButton(1).Enabled = True
                cmdButton(2).Enabled = True
                '
            End If
        Case 1 ' answer call
            lRtn = Tapiline1.LineAnswer("", 0) ' only needed for ISDN
            If (lRtn < 0) Then
                AddText txtStatus, "<<LineAnswer ERROR>> " & LineErr(lRtn)
            Else
                AddText txtStatus, "LineAnswer Successful"
            End If
        Case 2 ' disconnect call
            Tapiline1.LineDrop "", 0 ' no parms unless ISDN!
            Tapiline1.LineClose
            '
            cmdButton(0).Enabled = True
            cmdButton(1).Enabled = False
            cmdButton(2).Enabled = False
            '
            ClearHandles ' clean up control handles
            AddText txtStatus, "Line Dropped and Closed"
        Case 3 ' exit program
            Unload Me
    End Select
    '
End Sub

There's a lot going on in this code section, so it is worth reviewing in greater detail.

First, if the user has pressed the Start button, the code checks to make sure a line device has been selected from the list box. If no line device was selected, the user gets an error message, and the code exits the procedure (see Listing 28.9).


Listing 28.9. Checking for a selected line device.
' check for start up selection only
    If Index = 0 Then
        If lstLines.ListIndex = -1 Then
            MsgBox "Select a line first!", vbInformation
            Exit Sub
        End If
    End If

If the user has selected a valid device and pressed the Start button, the routine attempts to open the selected line device for interactive voice services with owner and monitor privileges.

Note
The privilege values tell TAPI that the program wants to "own" any incoming calls. But, if for some reason this workstation cannot own the calls, at least it wants to be able to "see" (monitor) them. This is the standard privilege profile for incoming calls.

If an error occurs when attempting to open the line, an error message is delivered to the text box. If the line is opened successfully, the appropriate message is sent to the text box, and the Answer and HangUp buttons are enabled while the Start button is disabled (see Listing 28.10).


Listing 28.10. Opening a line for incoming calls.
' set line parameters
    lPrivilege = LINECALLPRIVILEGE_OWNER + LINECALLPRIVILEGE_MONITOR
    lMediaMode = LINEMEDIAMODE_INTERACTIVEVOICE
    '
    ' react to user selection
    Select Case Index
        Case 0 ' start looking
            lRtn = Tapiline1.LineOpen(lstLines.ListIndex, 0, lPrivilege, ÂMediaMode)
            If lRtn < 0 Then
                AddText txtStatus, "<<LineOpen ERROR>> " & LineErr(lRtn)
            Else
                AddText txtStatus, "LineOpen Successful"
                AddText txtStatus, "Waiting for an incoming call..."
                '
                cmdButton(0).Enabled = False
                cmdButton(1).Enabled = True
                cmdButton(2).Enabled = True
                '
            End If

Once the line is opened, the user will receive a notice (the sound of a ringing phone) when a call appears on the line. The user can press the Answer button to accept the call. Listing 28.11 shows the code that calls the LineAnswer method to accept a call.


Listing 28.11. Accepting an incoming call.
Case 1 ' answer call
            lRtn = Tapiline1.LineAnswer("", 0) ' only needed for ISDN
            If (lRtn < 0) Then
                AddText txtStatus, "<<LineAnswer ERROR>> " & LineErr(lRtn)
            Else
                AddText txtStatus, "LineAnswer Successful"
            End If

This code is quite simple, but it hides a very important aspect of accepting an incoming call. The lineAnswer method assumes that you already have the HandleToCall property set to point to the call handle provided by TAPI. However, this property is not automatically set for you. Since you may not want to accept a given call, TAPI supplies you with only the call handle. This is done as part of the LINE_CALLSTATE message. Check out the code in Listing 28.7 to see where the HandleToCall property is set for you.

The last bit of code in the cmdButton_Click event that needs some attention is the code that handles the HangUp button. This button is pressed to close out an active call. When a user decides to end a call, both the lineClose and lineDrop methods should be invoked to clear resources. It is also a good idea to clear any handle properties that relate to the previous call. Listing 28.12 shows the HangUp code in detail.


Listing 28.12. Ending a TAPI call.
Case 2 ' disconnect call
            Tapiline1.LineDrop "", 0 ' no parms unless ISDN!
            Tapiline1.LineClose
            '
            cmdButton(0).Enabled = True
            cmdButton(1).Enabled = False
            cmdButton(2).Enabled = False
            '
            ClearHandles ' clean up control handles
            AddText txtStatus, "Line Dropped and Closed"

That completes the coding of the TAPIANS project. Be sure to save the form (TAPIANS.FRM) and the project (TAPIANS.VBP) before you continue. In the next section, you'll test the TAPIANS project to make sure it is working properly.

Testing TAPIANS

Now that you have completed the TAPIANS project, you're ready to test it out. To do this, you'll need a workstation configuration that includes either a built-in TAPI-compliant speakerphone or a standard telephone handset connected to the "out" jack of a voice-capable modem. Figure 28.3 shows an example of how you can arrange a standard voice-data modem and telephone handset to handle inbound TAPI calls.

Figure 28.3 : Example hardware arrangement for handling incoming calls

Note
If you do not have a voice-capable modem or telephony card, you can still test this project. You'll need to change the MONITORMEDIA_ mode from INTERACTIVEVOICE to DATAMODEM. This will set up your application to accept data modem calls. When the call is answered, TAPI will immediately begin sending data handshaking signals to the party at the other end of the phone.

In order to fully test the project, you'll need to answer an incoming phone call. If you are working from a home or office that has multiple phone lines, you can simply set up the TAPIANS program to monitor a line and call that line from another phone in the same building.

If you are working where you have only one line for both incoming and outgoing calls, you'll need to arrange for assistance from a friend. After running the TAPIANS project and pressing the Start button, call a friend and ask him or her to call you back at the same number that TAPIANS is monitoring.

Tip
You can purchase from office and telephone equipment suppliers devices that will simulate an incoming call on the line. These devices cost very little and are handy if you want to take your TAPI software to demonstrations, shows, or other events where you cannot rely on access to active telephone lines.

Once you have your test call lined up, you can run the TAPIANS project and begin testing.

The first thing you'll see is a list of all the line devices that TAPI recognizes on your workstation. Scroll through the list and select the one that will be able to handle the media mode for your test call (voice-data modem). Once you highlight the line device, you can press the Start button to tell TAPI to begin monitoring the line device for incoming calls. You should receive a message in the status box that tells you that TAPI services were started and that the program is waiting for a call (see Figure 28.4).

Figure 28.4 : TAPIANS is waiting for an incoming call

Now you need to get TAPIANS to see an incoming call appear on the line. If you have another phone line available to you, use it to call the phone line that TAPI is monitoring. If you don't have multiple phone lines, now is the time to call one of your friends to ask him or her to call the TAPI-monitored line.

Note
If you are using a call simulator, you can just flip the switch that sends a "tip-and-ring" signal along the line. This will tell TAPI a call is coming in.

When a call appears on the line, TAPI sends a LINE_CALLSTATE message with a dwParam1 equal to LINECALLSTATE_OFFERING. This tells your program that a new call is being offered to you for acceptance. At this point, the TAPIANS program will copy the hDevice value passed in the LINE_CALLSTATE message into the HandleToCall property of the TAPILINE control. This prepares the control to answer the offered call.

When the user presses the Answer button, TAPIANS invokes the lineAnswer method. If this function call is successful, TAPI returns three messages in quick succession. First, TAPI sends a LINE_REPLY message back to TAPIANS. This message is sent by TAPI whenever an asynchronous TAPI service request is completed. This message is not important for this application and can be disregarded.

Note
LINE_REPLY messages are useful for applications that deal in multiple phone lines. Since there are several possible asynchronous activities that can occur during TAPI services, keeping track of the RequestID is important. Since this application is working with only a single phone line, it is not so important to keep track of the RequestID value.

The next message TAPI returns is a LINE_CALLSTATE message with a dwParam1 equal to LINECALLSTATE_AccEPTED. This message tells TAPIANS that the lineAnswer method was successful. Finally, TAPI will return a message of LINE_CALLSTATE with a dwParam1 set to LINECALLSTATE_CONNECTED. This message indicates that the telephone call has been successfully connected. You can now pick up the telephone handset and talk to the person at the other end of the line (or to yourself, depending on how you placed the call!).

This set of messages and responses from your Visual Basic program happens quite quickly. Figure 28.5 shows how the messages appear in a typical call appearance.

Figure 28.5 : Viewing call progress for an incoming call

When you are ready to end the telephone call, you press the HangUp button on the TAPIANS dialog box. This will cause the program to drop the call and close the line. You'll get a short message telling you the line was closed successfully.

That's all there is to it. You now have a functional Visual Basic program that can see calls coming in on the line and give users the chance to answer those calls using a Visual Basic program.

Summary

In this chapter, you learned how to use the TAPILINE control to create a Visual Basic application that can monitor a telephone line for incoming calls and allow users to answer those calls. In the process, you learned about the six steps needed to handle inbound calls using TAPI services:

You also learned the importance of the LINE_CALLSTATE message sent by TAPI whenever a new call appears on the line and when an active call becomes idle (the other party hangs up). You learned how to write code in the TapiCallBack event of the TAPILINE control to watch for and respond to LINE_CALLSTATE messages.

Finally, you learned the importance of getting the call handle from the LINECALLSTATE_OFFERING message and placing this value into the HandleToCall property of the TAPILINE control. This must be done before you can invoke the lineAnswer method to accept the incoming call.

In the next chapter, you'll combine the skills you learned here with the techniques you learned in Chapter 26 for placing outbound calls to build a "virtual phone" for your pc. This application will allow users to place outbound calls and accept inbound calls.