My interest for TAPI was prompted when I decided to develop «home» applications that would provide my computer with dialing, callerID and answering machine capabilities. I decided to develop a TAPI application myself. As a result, in this series of four articles, I will review the basics of TAPI, devise a component, develop the recording and playback capabilities for the modem and develop an In-process automation server called gtroTelServer that would provide the required capabilities to calling applications. This first article introduces the TAPI capabilities that will be used [the other three articles are in preparation].
The idea of using computers to communicate is not new. Using a telephone line as a communication medium between computers is not exactly a space-age concept either. Fast dedicated computers have had controlled telephone switches for quite some time, and modems are now one of the most common PC peripherals.
Telephony is a technology that integrates computers with the telephone network. With telephony, people can use their computers to take advantage of a wide range of sophisticated communications features and services over a telephone line. Historically, it has been associated with proprietary enterprise solutions such as IVRs and PBX switches. This equipment is expensive, and is commonly supplied by the vendor with proprietary software to drive it. Relatively inexpensive telephony peripherals have been available for some time, but the software to drive them has also been hardware-specific.
Most home telephone connections in the world are of the type POTS, or Plain Old Telephone Service. Most POTS calls are transmitted digitally except while in the local loop the part of the telephone network between the telephone and the telephone company's central switching office. The scope of this article is limited to POTS and its objective is to develop basic understanding that can be used by ordinary users using a standard PC equipped with a voice modem and running under relatively new versions of Windows (I use Windows Vista Home Premium, SP-1).
What is TAPI?
TAPI is an acronym for the Telephony Application Programming Interface. It lets programmers develop applications that provide personal telephony to users. Microsoft designed it to offer an alternative to hardware-dependent telephony solutions. It is an abstraction software that inserts itself between custom applications and the hardware. Its goal is to present both software and hardware vendors with a consistent, device-independent programming model. With TAPI, applications need not know anything about the underlying hardware.
Versions of TAPI
It has evolved with the consecutive versions of Windows. It was introduced in 1993 as the result of joint development by Microsoft and Intel. The first publicly available version of TAPI was version 1.3, which was released as a patch on top of Microsoft Windows 3.1 (no longer supported),. The first version on Windows 95 was TAPI 1.4. It had support for 32-bit applications.TAPI 2.0 was introduced with Windows NT 4.0. It was the first version on the Windows NT platform. It made a significant step forward by supporting ACD and PBX-specific functionality. In 1997, Microsoft released TAPI 2.1. This version of TAPI was available as a downloadable update and was the first version to be supported on both the Microsoft Windows 95 and Windows NT/2000 platforms.TAPI 3.0 was released in 1999 together with Windows 2000. This version enables IP telephony (VoIP) by providing simple and generic methods for making connections between two (using H.323) or more (using IP Multicast) computers and now also offers the ability to access any media streams involved in the connection. Windows XP included both TAPI 3.1 and TAPI 2.2. TAPI 3.1 supports the Microsoft Component Object Model and provides a set of COM objects to application programmers. This version uses File Terminals which allow applications to record streaming data to a file and play this recorded data back to a stream.
For the programmer, the primary advantage of TAPI is that Microsoft has committed to providing the TAPI model as part of the basic operating system for all future versions of Windows. It can be used in four levels of complexity:
- Assisted Telephony -The simplest form of TAPI service.
- Basic Telephony - Provides basic in- and outbound telephony services for a single-line phone.
- Supplemental Telephony - Provides advanced telephone services such as hold, park, conference, and so on, to single and multiline phones.
- Extended Telephony - Provides a direct interface between Windows programs and vendor-specific TAPI services.
The last three levels are often referred to as full telephony.
TAPI conceptual objects
TAPI is an abstraction of the hardware and software used in telephony. In order to be device-independant, TAPI uses four types of telephony conceptual objects: LineApp, Line, Phone, and Call.
- LineApp - LineApp is the mother of all TAPI conceptual objects. It doesn't have a corresponding physical entity: it is a handle on TAPI. Each LineApp represents a distinct TAPI session. A LineApp is created when the lineInitialize() (TAPI 1,4) or lineInitializeEx() (TAPI 2.0 and later) API function is called, and destroyed when lineShutdown() is called. A process can create multiple LineApps if necessary. The LineApp owns all other TAPI concepts; the ownership is exclusive and not transferable. Each instance of LineApp is identified by its LineApp handle.
- Line - The Line object corresponds to the telephony line presented by the service provider. Sometimes this is the telephone line, but often TAPI Line does not correspond to an actual line. A TAPI Line is a logical representation of a device that functions as a method of conveyance for a telephony media stream.
- Phone - The Phone object is a logical representation of the terminal equipment. As in the physical telephony world, Phone objects can be used without calls.
- Call - A Call object can be created by either TAPI or a TSP. Typically, the application creates or receives calls. Each Call is identified by a Call handle.
Basic Telephony
The Basic Telephony service model has several API calls for handling and fulfilling service requests. These calls can be collected into logical groups
- line-handling API functions handle the initialization and opening and closing of TAPI lines.
- Line settings and status API functions handle the reading and writing of various parameter values that control the behavior of the line device.
- Outbound and inbound calls API functions handle the details of placing an outbound voice or data call and answering an inbound voice or data call.
The following table shows the Basic Telephony API calls, sorted by functional group, along with a short description of their use.
Function Group | API Call | Description |
---|---|---|
Line-handling | lineInitialize | Initializes the Telephony API line abstraction for use by the invoking application. |
lineShutdown | Shuts down the application's use of the Telephony API line. | |
lineNegotiateAPIVersion | Allows an application to negotiate an API version to use. | |
lineOpen | Opens a specified line device for providing subsequent monitoring and/or control of the line. | |
lineClose | Closes a specified opened line device. | |
lineDrop | Disconnects a call, or abandons a call attempt in progress. | |
lineDeallocateCall | De-allocates the specified call handle. | |
Line settings and status | lineGetDevCaps | Returns the capabilities of a given line device. |
lineGetDevConfig | Returns the configuration of a media stream device. | |
lineGetlineDevStatus | Returns the current status of the specified open line device. | |
lineSetDevConfig | Sets the configuration of the specified media stream device. | |
lineSetStatusMessages | Specifies the status changes for which the application wants to be notified. | |
lineGetStatusMessages | Returns the application's current line and address status message settings. | |
lineGetID | Retrieves a device ID associated with the specified open line, address, or call. | |
lineSetNumRings | Indicates the number of rings after which inbound calls are to be answered. | |
lineGetNumRings | This function returns the minimum number of rings requested with lineSetNumRings. | |
lineGetIcon | Allows an application to retrieve an icon for display to the user. | |
lineConfigDialog | Causes the provider of the specified line device to display a dialog that allows the user to configure parameters related to the line device. | |
Inbound and outbound calls | lineMakeCall | Makes an outbound call and returns a call handle for it. |
lineDial | Dials calls | |
lineAnswer | Answers an inbound call. |
Along with the extensive API set for Basic Telephony, the TAPI model defines several data structures that are used to pass information between TAPI and the requesting application. The layout of the structures contains variable as well as fixed data. This allows the API set to contain information of indeterminate length without prior knowledge of the contents of the structure.
Most Windows APIs are primarily concerned with what goes on inside your computer, but TAPI is designed to interface with external, noncomputer devices that can be highly dissimilar and unpredictable. Here, we will deal with basic telephony as well as with simple hardware and software: a modem and a telephony service provider (Unimodem/5). I will describe them in the forthcoming sections.
Modems
A modem (MOdulator DEModulator) is a device that enables a computer to transmit data over telephone or cable lines. As computer information is stored digitally, whereas information transmitted over a telephone line is analog, a modem converts between the two forms. Traditionally, they are connected to a serial port. They may be internal or external
A voice modem is a modem that is capable of playing and recording audio over a telephone line. While almost all modems are capable of doing data and fax, a growing number have voice capabilities. Modern voice modems are powerful telephony devices capable of advanced features like voice interaction, call transfers, and outbound dialing. For most users, a high quality voice modem and advanced telephony software will allow them to create a professional communications solution.
TAPI Service Provider (TSP)
The term "service provider" is nothing more than a fancy name for a driver. A TAPI service provider (TSP) is a driver that allows TAPI applications to communicate with different types of TAPI hardware. It translates TAPI functions into commands that the hardware can understand, and translates events from the hardware into data that the TAPI application can understand. Because different telephony hardware can support different kinds of features, different TSP's can support different TAPI functions.
On PCs, the voice drivers are interfaced with Windows through the Unimodem TSP, Windows' universal modem voice drivers. Audio devices (or Wave Devices) for the voice modem are usually provided by the manufacturer.
Unimodem is the default TSP used by Windows. Unimodem comes in a few different flavors:
- Unimodem - used by Windows 95 initial release and NT4. This TSP is data only, voice is not supported.
- Unimodem/V - used by Windows 95 OSR2, 98 and ME. This is a data and voice TSP. The /V stands for Voice, not a Roman numeral 5.
- Unimodem/5 - used by Windows 2000, XP and Vista. This is a data and voice TSP. The /5 is for Windows version 5, not the Arabic numeral V.
Most modem vendors support Unimodem/5 with most of their voice modems. Such support is provided with an information file (*.inf) that contains the information that tells Unimodem/5 how to interact with the modem
As a telephony service provider, Unimodem has severe restrictions:
- Due to the half-duplex capabilities of voice modems regarding media streaming via PC you can only use "wave/in" or "wave/out" device at the same time. This is a system wide restriction, i.e. any application or service having one of the modem's wave devices opened prevents any other application from opening it too.
- Modems driven by Unimodem.TSP only support 8 kHz, 16-bit, mono, WAVE_FORMAT_PCM wave format.
In the preceeding sections, I have provided basics of TAPI. For more on TAPI, the reader is referred to the Microsoft Windows Telephony API TAPI Programmer's Reference. More can be obtained from the FAQs by Bruce Pennypacker, Andreas Marshall, Grant Schenck and Michael Dunn.
How it works
In terms of the process involved, working with telephony is similar to working with many other computer technologies, including multimedia. First you must establish a connection with the hardware through its driver(s). You accomplish this task by initializing TAPI.
- The application must call the lineInitialize() (TAPI 1.4) lineInitializeEx() (TAPI 2.0 and later) function that take several parameters that involves
-
- defining the instance handle of the calling application;
- selecting an event notification mechanism (callback function, event handle or IO Completion Port);
- defining the address of a callback function if the callback function event notification mechanism is selected;
- defining the the highest TAPI version it is designed to support;
- a handle for TAPI that is used for most subsequent calls to TAPI function;
- the number of line devices available to the application;
- Using this parameter the application must enumerate each of the device detected by TAPI;
- For each line device found by TAPI, the application must use the lineNegociateAPIVersion() API call and obtain the TAPI version it supports.
- During this process, the capabilities of each line device is scrutinized and the selection of the modem is performed.
TAPI Versioning
The TAPI Version refers to the revision history of the API calling and parameter-passing conventions. As TAPI evolved, new API functions were added, new events and messages were added, and modifications were made to existing standards. Each such revision has been given a version number. To assure backward compatibility, operating systems ship with binaries that support a certain range of TAPI versions
Handling TAPI messages
Up to now, TAPI has been initialized and we have chosen to have a callback function to process TAPI messages. The available line devices have been enumerated and the modem selected as the active line device. We now need to figure out how to handle the messages.
TAPI is strongly event-driven and TAPI function calls are frequently asynchronous. When an API function requests that a certain action be performed, the request is passed to TAPI, TAPI passes it down to the TSP, the request is queued, and the API function returns. Later when the operation is completed, the application is notified.
The Callback function
The Callback function is used by TAPI to inform an application about various events that happen during the TAPI session. First of all, the good news is that you can leave the callback function empty in case you do not intend to use any TAPI handles during session lifetime. This function is declared as follows and must be a procedure that is external to any class:
procedure CallBackProc(hDevice, dwMessage, dwInstance, dwParam1, dwParam2, dwParam3 : DWORD); stdcall;
The first parameter is a handle either of a line device or a call on which TAPI is informing your application. More interesting parameters are the dwParam(s) parameters. They describe the fired message and its specific data. You can find a complete list of TAPI messages in the SDK documentation with a detailed description of each message parameter.
Additionally, the callback function must be a global procedure, not a class member (method). The problem in substituting a callback function by a class member is that Windows does not understand either C++ class member functions or Delphi's methods which carry "this" and "self" as a first hidden parameter.
Types of messages
All of these messages are sent to the application through the message notification mechanism that the application specified in lineInitializeEx(). The message always contains a handle to the relevant telephony object (phone, line, or call), which the application can use to determine the message type. The structure of the messages presented hereunder follows very closely the structure used in the TapiCallback() method presented above.
Line related messages
In the type of line related messages, hDevice contains a handle to the line.
- LINE_APPNEWCALL: sent whenever the application is spontaneously given a handle to a new call TAPI version 2.0 or later). Because the message includes the new call handle and the line handle of the line on which the call exists, the application can readily create a new call object in the correct context. The LINE_APPNEWCALL message is always immediately followed by a LINE_CALLSTATE message indicating the initial state of the call.
- LINE_LINEDEVSTATE: sent when the state of a line device has changed.
- LINE_ADDRESSSTATE: sent when the status of an address changes on a line that is currently open by the application.
- LINE_CLOSE: sent when the specified line device has been forcibly closed.
Call related messages
For the following messages, the hDevice parameter contains a handle to the call
- LINE_CALLINFO: sent when the call information about the specified call has changed.
- LINE_CALLSTATE: sent when the status of the specified call has changed. Typically, several such messages are received during the lifetime of a call. Applications are notified of new incoming calls with this message; the new call is in the offering state.
- LINE_GATHERDIGITS: This message is sent when the current buffered digit-gathering request has terminated or is canceled.
- LINE_GENERATE: sent to notify the application that the current digit or tone generation has terminated.
- LINE_MONITORDIGIT: sent when a digit is detected;
- LINE_MONITORMEDIA: sent when a change in the call's media mode is detected.
Other messages
- LINE_CREATE: sent to inform the application of the creation of a new line device.
- LINE_REMOVE: sent to inform an application of the removal (deletion from the system) of a line device.
- LINE_REPLY: sent to report the results of function calls that completed asynchronously.
- LINE_REQUEST: sent to report the arrival of a new request from another application.
Opening a line
After having obtained the capabilities of a line and have developed a callback procedure responding to TAPI messages, an application must open a line device before it can access telephony functions on that line. We obtain a handle to a capable telephone line with a call to the lineOpen() API function:
function lineOpen(hLineApp: HLINEAPP; dwDeviceID: DWORD; lphLine: PHLine;
dwAPIVersion, dwExtVersion, dwCallbackInstance, dwPrivileges,
dwMediaModes: DWORD; lpCallParams: PLineCallParams): Longint; stdcall;
This function that requires many inputs from the application: the TAPI Application handle hLineApp obtained from lineInitialize(), the identification of the device dwDeviceId, the dwAPIVersion received from lineNegotiateAPIVersion(), the line call priviledge and the media mode selected by the application. The parameters marked as pointers return
- lphLine, a pointer to an HLINE handle, which is then loaded with the handle representing the opened line device. We will use this handle to identify the device when invoking other functions on the open line device; and
- lpCallParams, a pointer to a structure of type TLINECALLPARAMS. This pointer is only used if LINEMAPPER is used; otherwise lpCallParams is ignored. It describes the call parameter that the line device should be able to provide.
In TAPI, a line is an abstraction, a device-independent representation of a physical line device, such as a modem. It can contain one or more identical communications channels (used for signaling and/or information) between the application and the switch or network. Because channels belonging to a single line have identical capabilities, they are interchangeable. In many cases (as with POTS), a service provider will model a line as having only one channel. Other technologies, like ISDN, offer more channels, and the service provider should treat them accordingly. Here, we deal with POTS.
The function lineOpen() can be invoked in one of two ways:
- A specific line device is selected by means of its line-device ID (the parameter dwDeviceID). The lineOpen request will open the specified line device. Applications interested in handling inbound calls typically use specific line devices because the application has been notified which line is carrying or is expected to carry the inbound call. When a line device has been opened successfully, the application is returned a handle representing the open line.
- The application can specify that it wants to use any line device that has certain properties. In this case, the application uses the value LINEMAPPER instead of a specific line-device ID as a parameter for lineOpen. The application also specifies which properties it needs on the call in parameters to lineOpen(). The function opens any available line device that supports the specified call parameters. This attempt, of course, may fail. If successful, the caller can determine the line-device ID by calling lineGetID, specifying the handle (lphLine) to the open line device returned by lineOpen.
The ability of an application to deal with inbound and outbound calls on a line is determined by the value used for the and the dwPrivilegesdwMediaModes parameters of the lineOpen() function. With this function, the application indicates its interest in monitoring calls or receiving ownership of inbound calls of one or more specific media modes, or of any (unspecified) media mode.
Call privileges
Ownership of a call is a type of privilege. Applications obtain owner or monitor privilege to new incoming calls by specifying the desired privilege as a parameter of lineOpen(). The privilege with which a line is opened remains in effect for subsequent calls used by that application on that line. An application always has owner privileges on calls it creates. When the application opens a line to place calls (as opposed to taking inbound calls) it invokes lineOpen() with the privilege LINECALLPRIVILEGE_NONE, which insulates the application from incoming calls while allowing outgoing calls. The other privileges used with the lineOpe() function are only for incoming calls.
- LINECALLPRIVILEGE_MONITOR - The application has monitor privileges to the call. These privileges allow the application to monitor state changes and query information and status about the call.
- LINECALLPRIVILEGE_OWNER - The application has owner privileges to the call. These privileges allow the application to manipulate the call in ways that affect the state of the call.
When a call handle is first provided to an application or whenever call privileges of that application are modified, the LINE_CALLSTATE message is sent to the application. When an application hands off a call, and if the receiving application does not already have a handle with owner privileges, then this message informs the application about its new privileges to the call. In this test bed, opening a line for monitoring inbound calls is done using LINECALLPRIVILEGE_MONITOR orLINECALLPRIVILEGE_OWNER for the call privilege.
Bearer Mode
The bearer mode corresponds to the quality of transmission requested from the network for establishing a call. It is important to keep the concept of bearer mode separate from that of media type. As an example, the analog telephone network provides only a 3.1 kHz voice-grade bearer mode but calls using it can support media types such as voice, fax, or data modem.
Media modes
The media mode is the form in which data is transmitted on a line. The four main types of media mode are voice, speech, fax, and data. The interest of an application for calls of given media modes is notified with the dwMediaModes parameter of lineOpen(). An inbound call of a certain media mode is given to the application that has opened the line device for that particular media mode. A single application may specify multiple flags simultaneously to handle multiple media modes. Alternatively, an application that wants to handle calls for which the actual media mode present has not yet been determined would turn on the unknown media bit as a parameter of lineOpen().
Handling calls
Once TAPI has been initialized and a line opened, the event-driven TAPI waits for a call to occur. Such call may be outbound or inbound.
- Outbound calls - Once the application has opened the line device, it places the call with lineMakeCall(), specifying the address (phone number and area code) in the lpszDestAddress parameter and the media mode in the lpCallParams parameter. This function returns a positive "request ID" if the function is completed asynchronously, or a negative error number if an error has occurred. Negative return values describe specific error states. Later, when the function has successfully set up the call, the application receives a lineMakeCall()LINE_REPLY message.
- Inbound calls - When the line has been opened with call priviledges of "LINECALLPRIVILEDGE_MONITOR or LINECALLPRIOVILEDGE, inbound call can be monitored. When a call occurs, several events are triggered sequentially:
-
- LINE_APPNEWCALL with a valid call handle and owner privilege,
- LINE_CALLSTATE with LINECALLSTATE_OFFERING,
- LINE_CALLINFO with LINECALLINFOSTATE_CALLERID,
- A second LINE_CALLINFO with LINECALLINFOSTATE_CALLERID,
- ... other messages
Ending calls and leaving TAPI
When a call is finished, the application receives a LINE_CALLSTATE message, which informs it that the state of a line device has changed: a remote disconnect has occurred. The application disconnects the call at the local end (it "goes on-hook") with lineDrop(). Alternatively, the application itself may choose to end the call by invoking lineDrop() before receiving the remote-disconnect message.
Here are the steps that might be used to end a call, close the line, and leave TAPI:
- The application calls lineDrop(), which places the call in the IDLE state. The call still exists, and the application still has its handle. Now the application can examine the call-information record, if desired.
- The application calls lineDeallocateCall() to release the call handle for the finished call. The call no longer exists.
- If the application expects no more calls on the line, it uses lineClose() to close the line. At this point, there will be no more incoming or outgoing calls on that line.
- The application invokes lineShutdown() to end the use of TAPI's functions for the current session.
Conclusion
That is about all that is needed to understand the design and implementation of the TgtroCallerID component that will be discussed in the second article of this series (not available yet).The scope of this article has been restricted on purpose to the simplest part of TAPI: POTS. TAPI is much more than what is covered here. TAPI also lets you make connections over other types of networks. More advanced kinds of data transmission methods are being developed, refined, and installed.
References
Much of this page has been retrieved from the references listed hereunder. Indebtness is hereby acknowledged.
- Telephony Application Programming Interface from Wikiperia.
- TAPI Quick Reference by Jialong He;
- TAPI 3.1 Overview from MSDN;
- "For the Telephony API, Press 1; For Unimodem, Press 2; or Stay on the Line" by Hiroo Umeno (Microsoft System Journal, April 1998);