Basic Line Services

Line API Initialization and Shutdown

An application that wants to use the line device abstractions in the Telephony API must first initialize its usage of the line API by calling lineInitialize. In this operation, the application provides its application callback function to the API and specifies whether it wants to be called back in interrupt handler context or in application thread context. Although the interrupt handler context provides faster response, the highly constrained interrupt environment severely limits what the callback function can perform. Conversely, the callback in the app's thread requires that the interrupt handler first activate the app's thread, which is then forced to invoke its callback. While this is a higher latency mechanism, it does allow the callback to operate without any of the interrupt context restrictions. Since telephony events do not typically require "immediate" response, application developers are strongly discouraged from selecting the interrupt context callback option.

The lineInitialize function returns two pieces of information to the application: an application handle and the number of line devices. The application handle represents the application's usage of the Telephony API. API functions that use line or call handles (see further) do not require the application handle, as this handle is derived from the specified line, phone, or call handle.

The second piece of information returned by lineInitialize is the number of line devices available to the application via the API. Line devices are identified by their device identifier (device ID). Valid device IDs range from zero to the number of line devices - 1. For example, if lineInitialize reports that there are two line devices in a system, then valid line device IDs are zero and 1.

Once an application is finished using the line abstraction of the Telephony API, it invokes lineShutdown passing its application handle to shutdown its usage of the API. This allows the API to free any resources assigned to this application.

lineInitialize

Initializes the Telephony API line abstraction for use by the invoking application.

lineShutdown

Shuts down the application's use of the line Telephony API.

Both lineInitialize and lineShutdown operate fully synchronously; i.e., these functions either return a success or failure indication; they never return an asynchronous Request ID.

Lines

A line device can represent a pool of homogeneous resources (i.e., channels) that are used to establish calls. The Telephony API in a client PC typically provides access to one or more line devices.

All line devices support at least the basic telephony services. If the application is interested in using supplementary and/or extended telephony services, then the application must first determine the exact capabilities of the line device. Telephony capability vary with configuration (e.g., client versus client/server), hardware, service provider software, and the telephone network. Applications should make no assumptions as to what telephony capabilities are available beyond just basic telephony services. An application determines a line's device capabilities via lineGetDevCaps.

lineGetDevCaps

Returns the supplementary and extended capabilities of a given line device as a data structure of type LINEDEVCAPS.

Here are some examples of how a service provider might model various configurations:

Example 1 - A single POTS line in the phone-centric or PC-centric connection models would most straightforwardly be modeled as a single line device with one channel.

Example 2 - A single BRI-ISDN line in the phone-centric or PC-centric models. The service provider has a number of options as to how it may want to model this. Some are described below.

Model the BRI line as a single line device with a pool of two channels allowing both channels to be combined for establishing 128 kbps calls.

Model each B-channel as a separate line device and disallow both channels to be combined into a single 128 kbps channel.

Model the BRI connection as two separate line devices, each drawing up to 2 channels from a shared pool of 2 B-channels.

Model as three line devices, one for each B-channel, and one for the combination. Clearly in the latter two models, resources may be assigned to different line devices at different times.

Example 3 - In client/server systems a pool of telephone ports attached to a server may be shared among multiple client PCs via a local area network. The pool may be administered to assign a maximum number of line devices (quota) to each client workstation. It is not unusual for the sum of all quotas to exceed the total number of lines. Furthermore, a given client with quota equal to 2 may be satisfied by using ports 1 and 2 at one time and ports 7 and 11 at a later time. The service provider for the pool may model this arrangement by providing each client workstation access to two line devices. This implies that the (fixed) device IDs for each client are zero and 1. If later the application calls lineGetDevCaps for device zero and again for device 1, it should be able to assume that the device capabilities for each of these devices will be constant, since that is the Windows device model. For server based devices that are pooled as described in the example above, this only holds for line devices that have identical device capabilities.

Example 4 - Switch-to-host link.

To provide personal telephony to each desktop, the service provider could model the PBX line paired with the PC as a single line device with one channel. Each client PC would have one line device available.

Model each third party station as a separate line device. This enables the application to control calls on other stations. This solution requires that the application open each line it wants manipulate or monitor, which may be fine if only a small number of lines is of interest, but may generate a lot of overhead if a large number or lines is involved.

Model the set of all third party stations as a single line device with one address (e.g., phone number) assigned to it per station. Only a single device is to be opened, providing monitoring and control of all addresses on the line (i.e., all stations). To originate a call on any of these stations, the application only needs to specify the station's address to the operation that makes the call. No extra open operations are required. This modeling does imply that all stations have the same line device capabilities, although their address capabilities could be different.

Note that all of the examples discussed are simply different ways that a service provider may choose to implement the mapping of line device behavior onto some physical realization.

An application is notified about changes in the status of a line device via the LINE_LINEDEVSTATE callback message. The application can control line status items for which it wants to be notified via the function lineSetStatusMessages. It can determine the complete status of a line device by calling lineGetLineDevStatus.

lineGetLineDevStatus

Returns current status of the specified open line device via a structure of type LINEDEVSTATUS.

LINE_LINEDEVSTATE

Sent to the application to notify it about changes in the line status. This message indicates which status item has changed.

lineSetStatusMessages

Select the line and address (see further) for which the app wants to receive status change notification messages. The messages controlled by this operation are LINE_LINEDEVSTATE and LINE_ADDRESSSTATE.

lineGetStatusMessages

Return the app's current line and address status message settings requested via lineSetStatusMessages.

Addresses

Each line device is assigned one or more addresses. Think of an address as corresponding to a telephone directory number assigned to the line device. The API presents a model where address assignments to line devices are static and will not change until reconfigured at the switch or network. LineGetDevCaps for a line device returns the number of addresses assigned to the line. Individual addresses are assigned Address IDs, which are numbers in the range zero to the number of addresses on the line minus one. An address ID is only meaningful in the context of a given line device, so an address is named as the tuple consisting of line and address ID. As described later, a line can be named by its device ID or handle.

The network or switch can configure address-to-line assignments in several ways. Usually, one of the addresses assigned to a line will be that line's primary address. A line's primary address is able to uniquely identify the line device, although the address may also be assigned to other lines as a non-primary address. Address configurations recognized by the Telephony API include:

Private. The address is assigned to one line device only. An inbound call for this address is only offered at one line device.

In contrast, a bridged address is assigned to more than one line device. Depending on the switch vendor different terminology may be used such as: multiple appearance directory number (MADN), bridged appearance, shared appearance. An incoming call on a bridged address will be offered on all lines associated with the address. Different variations arise from the associated behavior when using such a bridged address.

Bridged-Exclusive. Connecting one of the bridged lines to a remote party will cause the address to appear "in use" to all other parties that are part of the bridge.

Bridged-New. Connecting one of the bridged lines to a remote party still allows the other lines to use the address. However, a new call appearance is allocated to the second line.

Bridged-Shared. If one line is connected to a remote party, other bridged lines that use the address will enter into a multi-party conference call on the existing call.

Monitored. The line provides an indication of the busy or idle status of the address, but the line cannot use the address for answering or making calls.

As is the case with line devices, the addresses assigned to a line device may have different capabilities. Switching features and authorization may be different for different addresses. An app must call lineGetAddressCaps to determine the exact capabilities of each address.

lineGetAddressCaps

Returns the telephony capabilities of an address as a data structure of type LINEADDRESSCAPS.

The API's device query capability, status and event reporting mechanisms provide the application with the necessary information required to manage the different bridged address arrangements. For example, the app will be able to determine if a call has been answered by a bridged station by tracking the status changes and call state event changes on the address (see further).

An application is notified about changes in the status of an address via the LINE_ADDRESSSTATE callback message. The application can control the address status items for which it wants to be notified via the function lineSetStatusMessages. It can determine the complete status of an address device by calling lineGetAddressStatus.

lineGetAddressStatus

Returns current status of a specified address via a structure of type LINEADDRESSSTATUS.

LINE_ADDRESSSTATE

Message sent to the application to notify it about changes in the address status.

Addresses on a line device are normally identified via their address ID. When making calls, the API allows alternate address selections for the originating address, such as its address in dialable format or even service provider-specific naming mechanisms (for example by using API extensions based on switch-assigned station IDs). The function lineGetAddressID provides for the mapping of the alternate address format back to the address ID used by other operations in the API.

lineGetAddressID

Retrieves the address ID of an address specified using an alternate format.

Opening and Closing Line Devices

After having obtained the capabilities of a line device, an application must open the line device before it can access telephony functions on that line. When a line device has been opened successfully, the app is returned a handle representing the open line. A line device can be opened in different modes, thus providing a structured way of sharing the line device, as detailed later.

lineOpen

Opens a specified line device for providing subsequent monitoring and/or control of the line.

lineClose

Closes a specified opened line device.

A line device can be specified to lineOpen in one of two ways:

A specific line device is selected by means of its line device ID. The lineOpen request will open the specified line device. Applications interested in handling inbound calls will typically use specific line devices.

The app can specify that it wants to use any line device that has certain properties. The indication LINE_MAPPER is used instead of a specific line device ID. The properties are specified by means of the call parameters that the application intends to use. The API will open any available line device that supports the specified call parameters. This, of course, may fail. If successful, the caller can determine the line device ID by calling lineGetID on the handle to the open line device returned by lineOpen.

An application that has successfully opened a line device is always allowed the app to make an outbound call on the opened line device (unless all of its addresses are of the monitored type, or the line only supports inbound calls).

An application opens a line device for the purpose of handling inbound calls and/or making outbound calls, or for monitoring call activities on the line for logging purposes. The handling of inbound calls is tied to the media mode of the call. By opening a line device, the app registers interest in inbound calls of one or more media modes. An inbound call of a certain media mode is given to the application that opened the line device for the corresponding media mode. An application that wants to handle calls of unknown media mode can simply use the media mode unknown to lineOpen.

In addition to the media mode, the application can specify the call privileges it wants to the calls provided to it. This is how an application specifies whether it wants to monitor or own calls. For an inbound call, only one application is selected as the owner, although all applications with monitor interest in the call will be notified about the incoming call as well.

When multiple simultaneous opens are requested for the same media mode by different applications, the conflict is resolved by using a priority scheme. The call with owner privileges (see further) is dispatched to the application with the highest priority for the given media mode. The application's priorities are established by a mechanism that is outside of the API itself and is configured by the user, for example via a control panel applet. The description of such an applet is outside the scope of the Telephony API. In essence, the applet would allow the user to assign relative priorities to the modules (the applications and DLLs) that use the Telephony API. The resulting configuration information is stored away in a standard place and format (TELEPHON.INI) where it can be accessed by the Telephony DLL.

The "[HandoffPriorities]" section of TELEPHON.INI specifies the priority of applications to handle incoming calls and call handoffs of particular media types. When the call is handed off, The Telephony DLL will check the applications that have the line open to determine which of them expressed interest in calls of the current media mode (specified by the provider or application handing off the call). If more than one application has the line open and is interested in calls of the current media mode, the Telephony DLL will check the priorities specified in this section to determine which application will get the call (with the highest priority being assigned to the first listed application under that media type, and proceeding in the order listed). If none of the open, interested applications is listed in the current media mode entry in this section (or if there is no entry for that media mode), then the application to receive the call handoff is arbitrary (with preference given to the application which currently owns the call, in case it is handing off only as a courtesy). There is no direct association between these media modes and particular media stream APIs; it is up to the application to know which API is used to access a particular media stream.

For example:

[HandoffPriorities]

unknown=answmach.exe,phonemgr.exe

interactivevoice=phonemgr.exe

automatedvoice=voicefax.dll,answmach.exe

G3fax=faxbox.exe,voicefax.dll

In concept, for each media mode, the Telephony DLL can be thought of as maintaining an ordered list (ordered by priority) of the modules that have opened the line device for that media mode. An inbound call of a certain media mode is dispatched to the module at the head of the media mode's module list. If, for whatever reason, that module closes the line device, then the module is removed from the list, possibly causing another module to become the new head of the list.

An unclassified and unanswered incoming call is first sent to the highest priority module that opened the line device for the unknown media mode. If there is no such application, the Telephony DLL performs media mode determination. If such an application exists, it should typically answer the call and, if it later determines that the call has a media mode it does not manage, the application should handoff the call specifying the new media mode of the call as a parameter. If the line is currently open by an application for that media mode, then the Telephony API will handoff ownership of the call to that application. See the section on Multi Application Considerations for details.

When a single module handles more than one media mode, and after processing the call in one mode, the media mode changes (e.g., from voice to fax), then the module is expected to first handoff its call handle before starting its fax processing. Modules that behave in this manner offer the user a finer grain control of call dispatching than modules that don't.

Assume for example that the user has an integrated application that manages unknown, voice, and fax media modes and that allows the user to interactively screen all inbound calls. For each inbound call, the user could be told whom the call is from, whether it is a live person attempting to talk, or a fax trying to send a fax. Depending on the situation, the user is then given the option to either answer the call interactively (interactive voice) or take a voice message (automated voice), or if it is a fax call (fax), to receive the fax or reject it. Since the application has the line open for unknown media mode, all inbound calls will be dispatched to it by the Telephony DLL. Later the user decides that he really likes the call screening facility of this application, but would like received faxes to show up in his email inbox. If the application never hands off the call, faxes will continue to show up in the application's mailbox instead. However, if the application were to handoff the call after the user indicates he wants to receive the fax, the user can grant highest priority to the fax module that has access to the email inbox. When the integrated application hands off the fax call, the Telephony DLL implementation passes ownership of the call to the email module. Note that if the integrated application were assigned highest priority for fax, ownership of the call would automatically be given back to the integrated application.

Referring back to the TELEPHON.INI example above, assume that the answmach application, the voicefax application and the faxbox application are running and have opened the line device for the corresponding media modes. When a call comes in, answmach will receive ownership of the call. Assume that the call initially carries voice. The answmach hands off the call specifying automated voice as the call's new media mode. Ownership of the call is passed to the voicefax module, which processes the call while in automated voice media mode. Next, the call transitions to fax mode (user wants to send or receive a fax over the same call). Voicefax hands off the call specifying fax as the media mode. Ownership of the call is passed to the faxbox application.

While the examples above were geared toward inbound call processing, the handoff mechanism works equally well for combining different media modes handled by independent applications into a single outbound call. For example, a call starts out as an interactive voice call. At the end of the conversation, the user decides to send a fax over the same call. The application that owned the interactive voice call can now handoff the call, specifying the G3fax media mode. This will pass ownership of the call to the fax application, where the user can then initiate the fax send on the existing call.

Version Compatibility

Over time, different versions may exist for the Telephony DLL, applications, and service providers for a line or phone. New versions may define new features, new fields to data structures and bit fields, etc. Version numbers therefore indicate how to interpret various data structures.

To allow optimal mixing and matching of different versions of applications, versions of the Telephony DLL itself, and versions service providers by different vendors, the API provides a simple version negotiation mechanism for applications. There are two different versions that need to be agreed on by the app, the Telephony DLL and the service provider for each line device. One is the version number for the basic and supplementary Telephony API and is referred to as the API version, the other is the version for the provider-specific extensions, if any, and is referred to as the Extension version. The format of the data structures and data types used by the API's basic and supplementary features is defined by the API version, while the Extension version determines the format of data structures defined by the vendor-specific extensions.

Version negotiation proceeds in two phases. In the first phase the API version number is negotiated, in the second phase the Extension version is negotiated. If the application does not use any API extensions then it simply skips the second phase and extensions are not activated by the service provider. If the application does want to use extensions, but the service provider's extensions are not recognized by the application (i.e., wrong vendor), then the app should skip the negotiation for Extension version as well. Otherwise, the app uses a second phase to negotiate the device-specific Extension version to use.

Version negotiation is tied to the determination of a line's capabilities (lineGetDevCaps). During the first phase, the application indicates it wants to negotiate the API version number and provides the API version range it is compatible with. The Telephony DLL in turn negotiates with the line's service provider to determine which API version range it currently supports. The DLL next selects a version number (typically, although not necessarily, the highest version number) in the overlapping version range that app, DLL and service provider are able to deal with. This number is returned to the application, together with the line's device capabilities for that version, and the Extension ID which defines the extensions available from that line's service provider.

If the app understands the extensions identified by the Extension ID and decides to use them, then a second negotiation phase is performed. Again, the application queries the line's device capabilities by calling lineGetDevCaps again. This time specifying the already agreed upon API version and the extension version range it supports. The Telephony DLL passes this information on to the service provider for the line. The service provider checks the API version and the extension version range against its own, and selects the appropriate extension version number. An updated form of the device capabilities for the line is returned which contains: the selected API version number, the extension ID and selected extension version number, the line's device capabilities consistent with the API version, as well as the line's device-specific capabilities consistent with the Extension version. Both version numbers are specified when the application opens the line. At that point, the app, DLL and service provider are committed to use the agreed upon versions. If device-specific extension are not to be used, then the Extension version should be specified as zero.

Note that in an environment where multiple applications open the same line device, the first application to open the line device may very well select the versions for all future applications that want to use the line. Similarly, an application that opens multiple line devices may find it easier to operate all line devices under the same API version number.

Address Formats

Addresses assigned to a line device in the API are typically selected via their address ID. Each address ID corresponds to a directory number via which the address is known to entities that want to make calls to it. Also, making outbound calls typically requires that a directory number be supplied to identify the called party.

Many users like to dial people, fax machines, bulletin boards, etc. by selecting their names from an address book. The actual directory number that is to be dialed depends on the geographical location of the user and the connectivity of the specific line device. For example, a PC may have access to two lines. One could be connected to a PBX while another could be connected to the central office. When making a call to the same party, different numbers (i.e., a different prefix; dial '9' to get out) will have to be used. The user may have a portable PC or notebook and and should not have to change the entries in the address book simply because they operate in a different telephony environment. Rather, the user would like a way of telling the computer about his current location and the line device he wants to make calls on, leaving the address book unchanged, and instead have dialing take care of the differences transparently.

Related to this is the handling of international call progress. The call progress tones involved in making a call may include all tones in the path from the originating switch to the remote party's switch. Call progress tone tables typically vary from country to country. To make call progress work internationally, the service provider needs to know what call progress to use when making an outbound call.

To deal with directory numbers, the API defines two common formats. One is the canonical address format, the other is the dialable number format.

The canonical address format is intended to be a universally constant directory number, it is the directory number one would like to store in the address book, and never change.

A canonical address is an ASCII string with the following structure:

+ CountryCode Delimiter AreaCode Delimiter SubscriberNumber
$
BillingInfo | Subaddress ^ Name CRLF ...

where

+ is ASCII Hex(2B); it indicates that the number that follows it uses the canonical format.

CountryCode

is a variable sized string containing digits 0-9. The CountryCode is delimited by the following Delimiter. It identifies the country in which the address is located.

Delimiter

is any character except 0-9 + $ | ^ CRLF. It is used to delimit the end of the CountryCode part and the beginning of the AreaCode, and the AreaCode and SubscriberNumber parts of an address.

AreaCode

is a variable sized string containing digits 0-9, delimited by the next Delimiter. AreaCode is the area code part of the address.

SubscriberNumber

is a variable sized string containing digits 0-9 as well as delimiters, but excluding + $ | ^ CRLF. Delimiters embedded in the SubscriberNumber are ignored.

$

is ASCII Hex(24), and is optional. If present, the information following it up to the next + $ | ^ CRLF, or the end of the canonical address string is used as billing information.

BillingInfo

is a variable sized string containing digits and delimiters excluding + $ | ^ CRLF. This information carries billing or charging information, such as a credit card number. Billing information is not changed by address translation.

|

is ASCII Hex(7C), and is optional. If present, the information following it up to the next + $ | ^ CRLF, or the end of the canonical address string is treated as subaddress information (e.g., ISDN subaddress, other).

Subaddress

is a variable sized string containing a subaddress. The string is delimited by + $ | ^ CRLF or the end of the address string. When dialing, subaddress information is passed to the remote party. It can be an ISDN subaddress, and email address, etc.

^

is ASCII Hex(5E), and is optional. If present, the information following it up to the next + $ | ^ CRLF or the end of the canonical address string is treated as an ISDN name.

Name

is a variable sized string treated as name information. Name is delimited by + $ | ^ CRLF or the end of the canonical address string. When dialing, name information is passed to the remote party.

CRLF

is ASCII Hex(0D) followed by ASCII Hex (0A), and is optional. If present, it indicates that another canonical number is following this one. It is used to separate multiple canonical addresses as part of a single address string (inverse multiplexing).

The dialable address format describes a number that can be dialed on the given line. A dialable address contains part addressing information and is part navigational in nature. A dialable address is an ASCII string with the following structure:
DialableNumber $ BillingInfo | Subaddress ^ Name CRLF ... ;

where

DialableNumber

digits and delimiters 0-9 A-D * # , ! W w P p T t @ ; delimited by $ | ^ CRLF or the end of the dialable address string.

Where

0-9 A-D * #

are the ASCII characters corresponding to the DTMF and/or pulse digits.

!

is ASCII Hex(21). It indicates that a flash is to be inserted in the dial string.

P p

is ASCII Hex(50) or Hex(70). It indicates that pulse dialing is to be used for the digits following it.

T t

is ASCII Hex(54) or Hex(74). It indicates that tone (DTMF) dialing is to be used for the digits following it.

,

is ASCII Hex(27). It indicates that dialing is to be paused. The duration of a pause is device specific and can be retrieved from the line's device capabilities. Multiple commas can be used to provider longer pauses.

W w

is ASCII Hex(57) or Hex(77). An uppercase or lowercase W indicates that dialing should proceed only after dialtone has been detected.

@

is ASCII Hex(40). It indicates that dialing is to "wait for quiet answer" before dialing the remainder of the dialable address. This means to wait for at least one ringback tone followed by several seconds of silence.

$

is ASCII Hex(24), and is optional. It indicates that dialing the billing information is to wait for a "billing signal" (e.g., a credit card bong tone). If present, the information following it up to the next + $ | ^ CRLF, or the end of the dialable address string is used as billing information.

BillingInfo

is a variable sized string containing digits and delimiters excluding + $ | ^ CRLF. This information carries billing or charging information, such as a credit card number. Billing information is not changed by address translation.

|

is ASCII Hex(7C), and is optional. If present, the information following it up to the next + $ | ^ CRLF, or the end of the dialable address string is treated as subaddress information (e.g., ISDN subaddress, other).

Subaddress

is a variable sized string containing a subaddress. The string is delimited by + $ | ^ CRLF or the end of the address string. When dialing, subaddress information is passed to the remote party. It can be an ISDN subaddress, and email address, etc.

^

is ASCII Hex(5E), and is optional. If present, the information following it up to the next + $ | ^ CRLF or the end of the dialable address string is treated as an ISDN name.

Name

is a variable sized string treated as name information. Name is delimited by + $ | ^ CRLF or the end of the dialable address string. When dialing, name information is passed to the remote party.

CRLF

is ASCII Hex(0D) followed by ASCII Hex (0A), and is optional. If present, it indicates that another dialable number is following this one. It is used to separate multiple canonical addresses as part of a single address string (inverse multiplexing).

;

is ASCII Hex(3B). If placed at the end of a dialable address string, it indicates that the address information is incomplete and more address information will be provided later.


The Telephony API provides an address translation service via lineTranslateAddress.

lineTranslateAddress

Translates between an address in canonical format and an address in dialable format.

The address translation service does not performing any dialing. An application can use it to display the number that would have been dialed on the screen to the user for verification, or from the country code and area code it can compute the wall clock time at the destination address.

The application specifies the line device and a canonical address and the lineTranslateAddress returns the dialable number and country code. The line device provides part of the translation context. Geographical location is part of configuration of the telephony service provider and is provided through a control applet provided as part of the Developer Kit. This is outside the scope of the Telephony API. BillingInfo, Subaddress and Name, if present, are unmodified by the translation. Alphabetic characters as in 1-800-FOR-TAPI are not translated due to different standardizations in different countries.

Note that an app is not limited to using dialable addresses that were returned by lineTranslateAddress. It is free to fabricate its own dialable numbers if it knows what it wants dialed.

Calls

Unlike line devices and addresses, calls are dynamic. A call or call appearance represents a connection between two (or more) addresses. One address is the originating address (the caller), which is the address from which the call originated; the other is the destination address (the called), which identifies the remote end point or station with which the originator wishes to communicate. At any given time, zero, one, or more calls can exist on a single address. A familiar example where multiple calls exist on single address is call waiting: while having a conversation with one party, a subscriber with call waiting is alerted when another party tries to call. The subscriber can flash his phone to answer the second caller, which automatically places the first party on hold. The user can toggle between the two parties by flashing. In this example, the subscriber has two calls existing on one address on his line. Since the human user at the telephone handset can only be talking to one remote party at a time, in this example, only one call is active per line at any point in time; the telephone switch keeps the other calls on hold. With a line able to model pools of channels, multiple active calls may exist on a call at any one time, depending on the configuration

The Telephony API identifies a specific call by means of a call handle, and the Telephony DLL assigns call handles as required. A different handle exists per call per application. An application can obtain call handles in a number of well defined ways. Certain API functions create new calls and return the handle for the call to the application. Other times, call handles may be provided unsolicited in callbacks made from the Telephony DLL to the application. This is the case with inbound calls.

As mentioned, call handles are per app per call. Different applications with handles to the same telephone call will have different handles. The scope of a call handle is therefore limited to one application only. Although applications use call handles to identify calls to the API, a phone call may also be assigned a unique call ID by the service provider that allows the call to be tracked across call transfers. Whether or not a service provider assigns call IDs to calls is a device capability.

The call privileges of an app for a call are maintained within the Telephony DLL; they are not a property of an app's handle for the call. An app can test call handles for equality.

Finally, apps must dispose of their call handle when they are through using it. Resources are allocated dynamically for each call for each app that is given a handle for this call, these resources are not automatically deallocated when the call is cleared since the app may still find it useful to extract information from the call (e.g., for logging purposes).

Call States and Events

Strictly speaking, a connection is not fully established until both parties are communicating, but there are, in fact, several stages involved in establishing and clearing a call. Events occur on a call that cause the call to transition through several call states as it comes into existence, is used to exchange information, and terminates. Call state transitions result from both solicited and unsolicited events. A solicited event is one caused by the application controlling the call (e.g., by invoking operations in the API), while the switch, the telephone network, or the actions of the remote party cause unsolicited events. Note that operations on line devices, addresses, and calls may require the line, address, or call upon which they operate to be in certain specific states.

Whenever a call changes state, the API reports the new state in a callback to the application. The programming model the application developer should follow is not one that preassumes a rigid call state machine, but one where the application should react to the events reported to the application. In other words, call state notification does not report transitions that, depending on the current state of the call (known to the application), may force a transition to another state (computed by the application). Instead the notification simply tells the application what the call's new state is.

Some of the Telephony API defined call states and events are exclusive to inbound or outbound call processing, while others occur in both cases. Several of these call states provide additional information that may be of use to the application. For example, the busy state signifies that a call cannot be completed because a resource between the originator and the destination is unavailable. Information supplied with the busy state includes station busy or trunk busy. Station busy indicates that the destination's station was busy (e.g., phone is offhook); trunk busy means a circuit in the switch or network was busy. Call states defined by the Telephony API are listed below.

idle - This corresponds to the "null" state; no activity exists on the call (no call really exists).

offering (inbound) - The switch informs the PC of the arrival of a new incoming call. Note that the offering state is different from having the phone or PC ring. When a call is offered, the PC is not necessarily instructed to alert the user. Let's look at a real life example. An incoming call on a shared call appearance will be offered to all stations that share the appearance; however, typically only the station that has the appearance as its primary address will be instructed to ring. If that station does not answer after some amount of time, the bridging stations may be instructed to ring as well.

accepted (inbound) - An application has accepted an offering call. In ISDN, this has the side effect of initiating the alerting of the user at both the caller's side and the called party side. An offering call can always be answered without first being accepted.

dialtone (outbound) - The call is receiving a dial tone from the switch. The presence of a dial tone indicates that the switch is ready to receive a dialable number. Additional information includes:

normal dialtone - The "normal" everyday dial tone. This is most often a continuous tone.

special dialtone - A special dial tone is often used to signal certain conditions such as message-waiting. This is usually an interrupted dial tone.

dialing (outbound) - The originator is dialing digits on the call. The dialed digits are collected by the switch.

proceeding (outbound) - The call is proceeding through the network. This occurs after dialing is complete and prior to the call reaching the dialed party via ringback, busy, or answer.

special info (outbound) - The call is receiving a special information signal. A special information signal precedes a prerecorded announcement indicating why a call cannot be competed.

no circuit - A no circuit or emergency announcement.

customer irregularity - This typically means that the dialed number is not correct.

reorder - A reorder or equipment irregularity announcement.

busy (outbound) - The call is receiving a busy signal. Busy indicates that some resource is not available and the call cannot be normally completed at this time. Additional information consists of:

station busy - The station at the other end is off-hook (station busy).

trunk busy - The network is congested. This usually uses a fast busy.

ringback (outbound) - The station to be called has been reached and the destination's switch is generating a ring tone back to the PC. A ringback means that the destination address is being alerted to the call.

connected (inbound and outbound) - Information is being exchanged over the call.

on hold (inbound and outbound) - The call is currently held by the switch. This frees up the physical line, and allows another call to use the line.

conferenced (inbound and outbound) - The call is a member of a conference call and is logically in the connected state (to the conference bridge). A call in the conferenced state refers to a conference call (in the connected, onHold, ... state).

on hold pending conference (inbound and outbound) - This conference call is currently on hold and waiting for the user to add another party.

on hold pending transfer (inbound and outbound) - The call is on hold in preparation of being transferred.

disconnected (inbound and outbound) - The call has been disconnected by the remote party.

unknown (inbound and outbound) - The call exists, but its state is currently unknown. This may be the result of poor call progress detection.

Although, under normal circumstances, an outbound call is likely to transition from idle to connected via a number of intermediate states (dial tone, dialing, proceeding, ringback) other paths are often possible. For example, the ringback state may be skipped; a hot phone or non dialed phone may transition directly from idle to connected, etc.

An application should always process call state event notifications. Call state transitions valid for one switch or configuration may be invalid for another. For example, consider a line from the switch that via a simple Y-connector physically terminates both at the PC and at a separate phone set, creating a party line configuration between the PC and the phone set. The PC termination and, therefore, the application using the Telephony API, may have no knowledge about the activities on the line handled by the phone set; i.e., the line may be in use without the service provider being aware of this. An application that wants to make an outbound call will succeed in allocating a call appearance from the API, but really ends up sharing in the active call on the line. Blindly sending a DTMF dial string without checking for dialtone first may not result in intended (or polite) behavior.

LINE_CALLSTATE

Sent to an application to notify it about changes in a call's state.

lineGetCallInfo

Returns mostly constant information about a call as a data structure of type LINECALLINFO.

lineGetCallStatus

Returns complete call status information for the specified call as a data structure of type LINECALLSTATUS.

The call information data structure maintained for each call contains an application-specific field that applications can read and write. This field is not interpreted by the API. Apps can use it to "tag" calls in application-specific ways. Writing the field such that the change becomes visible to other applications requires that the application use lineSetAppSpecific.

lineSetAppSpecific

Sets the application specific field of a call's information structure.

Making Calls

To make an outbound call, the application must have opened the line device. The standard way to make the call is then for the application to invoke lineMakeCall specifying the line handle and a dialable destination address. The request first obtains a call appearance on an address on the line, waits for dialtone, and dials the specified address. If successful, a handle to a call with owner privileges is returned to the application. Optionally, the application can specify the address on the line where it wants the call to originate. This can be done by specifying the address ID, or by using the corresponding directory number. The latter may be useful in configurations where it is more practical to identify the originating address by its directory number than by its address ID. If special call setup parameters are to be taken into consideration, then the application must supply additional information to lineMakeCall. Call setup parameters are required when requesting a special bearer mode, a call's bandwidth, a call's expected media mode, user-to-user information (ISDN), secure the call, block sending of caller ID to the called party, automatically take the phone offhook at the originator and/or the called party, etc.

The application can also use lineMakeCall just to only allocate a call appearance (or partially dial) and then explicitly perform (or complete) dialing by using lineDial. When the number provided is incomplete, dialing the digits may be delayed by placing a ';' (semicolon) at the end of the number.

lineMakeCall

Makes an outbound call and returns a call handle for the new call.

lineDial

Dials (parts of one or more) dialable addresses. Use this operation in all situations where you need to send address information to the switch on an existing call; such as dialing the address of a party to transfer a call to, etc.

Once dialing is complete, call progress information is provided to the application via the LINE_CALLSTATE callback. This enables the application to track whether or not the call is reaching the called party.

The dialable number format allows multiple destination addresses to be supplied at once. This may be useful if the service provider provides some form of inverse multiplexing by setting up calls to each of the specified destinations and then managing the information stream as a single high-bandwidth media stream. The app perceives this as a single call, as it will only receive a single call handle representing the aggregate of all the individual phone calls. It is also possible to support inverse multiplexing at the application level. Then the app would set up a series of individual calls and synchronize their media streams.

Inbound Call Notification

After an application has opened a line device registering a media mode and a privilege other than none, the application can be notified when a call arrives providing the call handle to the application. An application is informed of all call state events via the LINE_CALLSTATE callback message. This message provides both the call handle, the call state, and the application's privilege to the call. This is, therefore, also the message that informs an application about calls it has never seen before. For an unanswered inbound call, the call state will be offering. The application can then invoke lineGetCallInfo to find out information about the call. The fact that a call is offered may not necessarily imply the user is being alerted. A separate LINE_LINEDEVSTATE callback is made with a ringing indication to provide this information to the application.

Call information includes (among other things):

bearer mode, rate - This is the bearer mode (voice, data) and data rate (in bps) of the call.

media mode - The current media mode of the call. Unknown if this information is unknown.

call origin - Indicates whether the call originated from an internal caller, an external caller, or unknown.

reason for the call - Describes "why" the call is occurring. Possible reasons are: direct call, transferred from another number, busy-forwarded from another number, unconditionally forwarded from another number, the call was picked up from another number, a call completion request, or a callback reminder. Unknown if this information is not known.

caller-ID - Identifies the originating party of the call. This can be in a variety of (name or number) formats, determined by what the switch or network provides.

called-ID - Identifies the party originally dialed by the caller.

connected-ID - Identifies the party that is actually connected to. This may be different from the called party if the call was diverted.

redirection-ID - Identifies to the caller the number towards which diversion was invoked.

redirecting-ID - Identifies to the diverted-to user the party from which diversion was invoked.

user-to-user information - User-to-user information sent by the remote station (ISDN).

Note that depending on the telephony environment, not all information about a call may be available at the time the call is initially offered. For example, if caller ID is provided by the network between the first and second ring, caller-ID will be unknown at the time the call is first offered. When it becomes known shorty thereafter, a LINE_CALLINFO callback message will notify the application about the change in party ID information of the call.

If a new call arrives while another call already exists on the line or address, then similar notification and call information is supplied following the same mechanism as for any incoming call. If an app does not want any interference for a call from the switch or phone network, then it should secure the call. Securing a call can be done at the time the call is made via a parameter to lineMakeCall, or later on when the call already exists via lineSecureCall. The call will be secure until the call is disconnected. Securing a call may be useful for example when it is feared that certain network tones (e.g., call waiting) could destroy a call's media stream (e.g., fax).

lineSecureCall

Secures an existing call from interference by other events.

Answering Inbound Calls

Once a call has been offered to an application, and the application is an owner of the call, then the app may answer the call via lineAnswer.

lineAnswer

Answers an offering call.

Once a call has been answered, its call state will typically transition to connected and information can be exchanged over the call.

Toll Saver Support

Since an inbound call can only be answered once, a mechanism is provided by the API to allow independent applications to indicate the maximum number of rings that should be allowed to pass before an inbound call should be answered. This mechanism allows the implementation of a toll saver feature in this type of an environment. Toll saver typically answers an inbound call after a fewer number of rings if a certain user-definable condition holds true; for example, the user has high-priority messages waiting. If the condition is false, then the user's call is not answered after a small number of rings, allowing the user to hang up and avoid being charged for the call. The module that answers the call can query the number of rings prior to answering each call. This number will be the minimum of all ring counts set by all applications. Note that this feature does not in itself answer the call; it is informational only. The operations provided by the API to support toll saver function are lineSetNumRings and lineGetNumRings. If no requests have been made to lineSetNumRings, then the value 0xFFFFFFFF is returned by lineGetNumRings.

lineSetNumRings

An application that opens a line device in any mode can indicate after how many rings it wants inbound calls answered. Certain conditions known only to the application may affect the number of rings allowing the implementation of an overall toll saver feature. Note that this operation does not answer any calls. It is only informational in nature.

lineGetNumRings

This function returns the minimum number of rings requested via lineSetNumRings. This value is of use to the module (application, DLL, or API implementation) that actually decides when to answer each call. As conditions that influence the number of rings may change dynamically, it should be called frequently (if not prior to the answering of each call). This function is intended to support the implementation of toll saver style features. Note that this operation does not answer any calls. It is only informational in nature.

Any application that has opened a line device can make outbound calls on the line. Note that a successful open of a line device does not automatically guarantee the lineMakeCall request will succeed. The actual synchronization point for an application being able to allocate the line resources necessary to make an outbound call is whether or not the application can successfully allocate an available call appearance. If calls exists on the line that are controlled by other applications, then these calls would have to be on hold and would typically be forced to remain on hold until the application either places its call on hold or drops the call.

All applications that have opened a line device in any mode are notified about certain general status and events occurring on the line device or its addresses. These include the line being taken out of service, the line going back in service, the line being under maintenance, an address becoming in use or going idle, a successful open or close operation being executed on the line device.

After an application is finished using a line device, it should close the device by calling lineClose on the line device handle.

After the device has been closed, the application's handle for the line device is no longer valid. A LINE_LINEDEVSTATE message is sent to the other applications to inform them about the state change on the line. Note that in certain environments, it may be desirable for a line device that is currently open by an application to be forcibly reclaimed (possibly by the use of some control applet) from the application's control. This feature prevents a single (e.g., misbehaved) application or user from monopolizing a line resource. When this occurs, an application will receive a LINE_CLOSE message for the open line device that was forcibly closed.

Setting a Terminal for Phone Conversations

The user's PC may have access to multiple devices, selectable by the user, and used to conduct interactive voice conversations. First, there is the phone device itself, complete with lamps, buttons, display, ringer, and voice I/O device (handset, speakerphone, headset). The user's PC may also have a separate voice I/O device (e.g., headset, or mic/speaker combination attached to a sound card) for use with phone conversations. The Telephony API enables the user to select where he wants the information routed that the switch sends over the line, address, or call. The switch normally expects this to be one of its phone sets, and sends ring requests, lamp events (for stimulus phones), display data, and voice data as appropriate. The phone in turn sends hookswitch events, button press events (for stimulus phones), and voice data back to the switch. Note that the line portion of the Telephony API makes lamp events, display events, and ring events available, either as functional return codes to the various operations in the API, or as unsolicited functional call status messages sent to the application callback. The Telephony API implementation is responsible for mapping between the functional API level and the underlying stimulus or functional messages used by the telephony network. In functional telephony environments, the API functions are mapped to the functional protocol.

Via the lineSetTerminal function, the application can control the routing of different low-level events exchanged between the switch and the station; it can also decide not to route some of these low-level events to a device. The routing of the different classes of events can be individually controlled. For example, the media stream of a call (e.g., voice) can be sent to any transducer device if the service provider/hardware is capable of doing so. Ring events from the switch to the phone can mapped into a visual alert on the PC's screen or they can be routed to a phone device. Lamp events and display events can be ignored or routed to a phone device (which will appear to behave as a normal phone set). Finally, button presses at a phone device may or may not be passed on to the line. In any case, this routing of low-level signals from the line does not affect the operation of the line API portion which always maps the low-level events to their functional equivalent. Consult a line's device capabilities to detemine the terminals it has available.

lineSetTerminal

Specifies the terminal device to which the specified line, address events or call media stream events are routed. Separate terminals can be specified for each event class. Event classes include: lamps, buttons, display, ringer, hookswitch, and media stream.

An example will help illustrate how to use this operation. Assume initially that the application suppresses the routing of all events, and the user selects a headset as his current I/O device. An incoming call will send a LINE_CALLSTATE message and a LINE_LINEDEVSTATE message with the ringing indication. Since routing of all events is suppressed, ring events are not routed to the phone, so ringing of the phone is suppressed. Instead the application notifies the user by means of a pop-up dialog box and a system beep in the headset. The user decides to answer the call. Since his current I/O device is the headset, the telephony application will invoke lineSetTerminal on the incoming call to route the call's media to the headset and answer the call. The application may also invoke lineSetTerminal to route lamp and display information events to the phone set to have the phone behave as usual.

As a second example, assume an incoming call is alerting at the user's PC. Instead of selecting the answer option with the mouse, the user decides to just pick up the phone's handset to answer the call. The offhook status at the phone (see further) sends a callback message to the application. The application can interpret this as a request by the user to select the phone handset to conduct the conversation. The application invokes lineSetTerminal to route the voice data on the call to the phone set.

Call Drop

To terminate a call or a call attempt, the application can use lineDrop on the call. This has the effect of hanging up on that call and making it possible to make another call.

If the remote party disconnects a call, the application will receive a LINE_CALLSTATE message with a call state of disconnected. To clear the call, the application must also drop the call by invoking lineDrop on the call.

A call handle remains valid after a call has been dropped. This enables the application to still call operations such as lineGetCallInfo to retrieve information about a call (for example, for logging purposes). Each application with a handle for the call must eventually deallocate its call handle to free any memory resources allocated for the app for the call. The application deallocates its call handle by calling lineHandoff specifying a target media mode as none and a call privilege as none.

lineDrop

Disconnects a call, or abandons a call attempt in progress.

Call Handle Manipulation

When an application makes a call, the app is returned a handle to the call with owner privileges. When the app is notified about an inbound call it is provided a handle to a call with either owner privileges or monitor privileges, depending on the privileges requested at line open.

An application's call handle and associated privileges remain valid until the application takes some explicit action. After a call reverts to the idle state, the application is still allowed to read the call's information structure and status. After the application decides it has no more use for the call, it should deallocate its handle. It does this by invoking lineHandoff using the call handle. Note that the Telephony DLL allocates memory for each call for each app with a handle for the call. Service providers will likely allocate memory to hold call information as well. Deallocation of an application's call handle allows the Telephony DLL and the service provider to reclaim any memory resources allocated to the call. An application's handle for a call becomes void after a successful deallocate. An attempt by an application to deallocate a call handle for a non-idle call for which it is the only owner will fail. The application should either first handoff ownership or clear the call by dropping it, which places the call into the idle state, and then deallocate its handle.

Note that the use of lineHandoff for deallocating a call is really just one usage of this operation. As its name suggests, lineHandoff allows an application with a valid call handle to handoff call ownership privileges to other applications. The application selects the target application by means of the media mode it wants the call's media stream to carry next. The app can either select one of the specific media modes, the unknown media mode (treat the call again as an unclassified call), or the media mode none. LineHandoff also allows the app to specify the call privileges to the call it wants to end up with after a successful handoff. This can be owner, monitor, or none. A privilege of none is used if the app wants to deallocate its call handle after the handoff. A media mode of none is used if the application just wants to change its privileges to the call without performing any handoff.

The application that is the target of the handoff will be notified via a LINE_CALLSTATE message that contains the call handle, the call state, and the application's privilege (owner) for the call.

Besides gaining call handles by being the target of a successful handoff or being selected for handling incoming calls, an application can always request handles with specified privileges to calls on a line, an address, or calls related to a call. This is performed by lineGetCalls.

lineHandoff

Hands off call ownership and/or changes an app's privileges to a call.

lineGetCalls

Acquires call handles to calls on a line, address, or calls related to a given call. The app determines the call privileges it wants to have for the returned calls.