# ITX Programmer's Guide

The ITX Project

May 4, 1999

## Contents

- Contents
- Introduction
- If You Want to Use ITX ...
- Data Exchange
- Signaling
  - Obtaining a Signaling Object
  - Dialing Out
  - Incoming Calls
  - Signaling and the Other Components
  - How ITX Signaling Works
- Directory Services
- The Gateway
  - Implementation Details
- About Events, Exceptions, Properties, and Statistics
  - Events
  - Exceptions
  - Statistics
  - About Connection Properties
- Examples
  - Minimal ITX Program
  - ITX Program That Rings a Telephone
  - Registry Dumper
  - PhoneRecorder
  - Network Client

# Introduction

Telephony applications move sound across the telephone network and the internet. The ITX API (Application Programming Interface) allows telephony connections to be established between any combination of computers and telephones.

When sound is being transmitted over the Internet, it is generally transferred as UDP traffic. We use RTP (Real Time Protocol) packets to handle this traffic. This protocol helps with synchronizing send and receive buffers, timestamping and sequence numbering.

Sound on the telephone lines, however, is transmitted as sound samples (8-bit samples, Pulse Code Modulation), generally multiplexed into a TDMA (Time Division Multiple Access) flow and transferred at 64kbps.

Besides the data plane just described, telephony applications also involve a control plane. The control plane, or ``signaling'', is what sets up, monitors and tears down calls. DTMF (Dual-Toned Multiple Frequency) tones are also handled in the control plane.

To move sound between the PSTN (Public Switched Telephone Network) and the Internet, we use PC adapter cards that move voice data between the telephone network and the Internet. A networked computer that contains one or more of these cards is called a ``Gateway''. In the ITX system, the Gateway has been designed such that the programmer do not have to worry about whether the program is talking to a desktop PC or a Gateway.

If you have your own PBX (Public Branch Exchange), you can acquire a JTAPI (Java Telephony API) package for controlling it. In this case, the Gateway can send control requests to the PBX, and the PBX can be used to set up and tear down calls. In this way you can take advantage of any additional functionality that the PBX provides.

Finally, you need a way to look up telephone numbers and email addresses. The ITX system allows any backend database to be plugged in and used, in this release, we provide an implementation based on BIND. The application programmer uses the Directory Service API to look up addresses for users. Users register with the Directory Service, allowing them to be located by other users. The implementation of the backend database is transparent to the application programmer or user.

This overview has described the four main components of the ITX API:

- Data Exchange (implemented in the `cnrg.itx.datax Java package)`
- Signaling (implemented in the `cnrg.itx.signal Java package)`
- Gateway (implemented in the `cnrg.itx.gtwy Java package)`
- Directory Service (implemented `cnrg.itx.ds Java package)`

The rest of this Guide explains how you, programming in Java, can use the `cnrg.itx` telephony package to create your own internet-telephony applications. Please refer to the JavaDoc for more detail; it can be found at http://www.cs.cornell.edu/cnrg/telephony/JavaDocs.

# If You Want to Use ITX ...

If you are a faculty, staff or student at Cornell:

- You can use the demonstration ITX telephony system running in the System Lab in Upson 331. Get yourself registered in the ITX database (how?)
- To contact ITX entities by telephone, just call up extension 45522 or 45523 and then punch in the 5 digit extension number of the entity you are trying to reach. Not much is implemented for this approach yet, though.
- To write an application that can interact with the internet and the telephone network, you need to write a Java program. This Guide, plus our JavaDoc at `http://www.cs.cornell.edu/cnrg/telephony/JavaDocs` will tell you what you need to know. You must run your application on a computer that is inside the CS firewall.

Otherwise:

- You can install ITX on your own system. In order to interface with ``real'' telephones, you will need a card that accepts a telephone line and that has drivers that can call out on these lines, get input on these lines, and the like. Our demonstration system uses a Dialogic D41/EPCI card; its lines are connected to a PBX which sits in the System Lab; and this PBX is connected to the campus PBX.
- If all you are interested in is doing computer to computer telephony using microphones and speakers, then just omit (or don't use) the `cnrg.itx.gtwy` package. [TBD: move `cnrg.itx.signal.pbx` to `cnrg.itx.gtwy.pbx`]
- The ITX system is programmed in Java with JNI to some lower-level C code. The directory server (BIND) runs in Unix and the rest of the system runs in NT. Our gateway must run on an NT machine. The rest of the system would run on other Java platforms if the Directory CStub and the Jaudio instructions were re-platformed.
- To run an ITX application, you need to have at least the directory server running (see the operations manual). To handle actual telephones, you must also have a gateway and PBX servers running.
- The application must have access to a file, `resolv.conf`, located by default in your working directory (details later in the guide).
- Your $PATH should include `jaudio.dll` and `CStub.dll`

# Data Exchange

In telephony applications, ``data'' refers to sound, whether encoded as PCM samples and sent over wires, or stored as PCM samples in an audio file, or traveling over the internet as UDP packets that contain the samples.

ITX's data exchange package (`cnrg.itx.datax`) is used by the programmer to record, play and transfer sound. The basic object in this package is the Connection. A Connection consists of two channels, an input channel (this brings sound to the application) and the output channel (which carries sound from the application).

The channels contain devices. Each channel has a source device and zero or more destination device. (A common setup has a channel connected to a source and one destination.) The current ITX package contains implementations for the following devices:

Destination Devices

- NetworkDestination - used to send sound data across the internet
- SpeakerDestination - used to play sound to the speaker attached to the computer
- StreamDestination - used to send sound to a Java Stream.

Source Devices

- MicrophoneSource - used to record sound from a microphone
- NetworkSource - used to receive sound from the internet (usually from a corresponding Network Destination)
- StreamSource - used to read in sound from a Java Stream

Example: Suppose you want to set up a connection that uses your computer's microphone as input, and a file as output. Of course, there are already tools for generating audio files, but here's how you can use ITX to record your own:

          Channel c = new Channel();
          c.setSource ( new MicrophoneSource(c));
          FileOutputStream fos = new FileOutputStream ("mumble.raw");
          c.addDestination ( new StreamDestination ( fos ) );

This application is inherently ``half-duplex'': there is only one uni-directional channel with the microphone as a source and the file as a destination. A ``full-duplex'' application would have two channels, each with a source and destination.

To conclude the example, the application sets up a half-duplex connection as follows:

          AudioConnection ac = new AudioConnection ( c, null );
          ac.open();

After a certain period of time, or after the application determines that the connection is no longer needed, it closes the connection:

    ac.close();

The only kind of connection supported by ITX is the AudioConnection (appropriate enough for a telephony system).

For data transfer over the internet, a forward error correction is done at the network layer. Buffering is also done at the NetworkSource to remove jitter due to network delays.

Like all ITX components, Data Exchange can be used together or independently of the other components

# Signaling

Signaling provides the control layer for the ITX application. Signaling provides services to the programmers such as registrations, call setup, call termination, as well as keepalives. It is built as a distributed component without a central server.

All applications that wish to use signaling must either implement cnrg.itx.SignalingObserver, or extend cnrg.itx.AbstractSignalingObserver.

In addition, the application may also choose to implement cnrg.itx.SignalConnectionObserver in order to made non-block call setups.

The DesktopSignaling object is an application's primary control plane interface. This object is used to register the user with the Directory Service, to dial other applications, and to tell the application if it has an incoming call. We will discuss each in turn.

# Obtaining a Signaling Object

To obtain a signaling component, you instantiate a DesktogbpSignaling object, giving it parameters to authenticate your application with the database, and a handle to your application so that it can call your handler routines when certain signaling events occur. Here is the simplest DesktopSignaling constructor:

    import cnrg.itx.signal.*;
    public class myFirstITXApp extends AbstractSignalingObserver {
           :
       DesktopSignaling signal = new DesktopSignaling ( this, "userid", "password" )
           :
    }

Passing ``this'' as a handle tells our DesktopSignaling who its SignalObserver is. The functions in the SignalObserver are called by DesktopSignaling to notify it of events, such as call invitations and hangups. The next two arguments are Strings which are authenticated against the database of currently registered ITX users. In addition, the current location (IP address and port number) of this application is registered.

In the present version of ITX, DesktopSignaling locates the Directory Server (the only centralized server in the ITX system) by reading a file called `resolv.conf`, by default from your current working directory. The contents of this file says where the directory server is running, e.g.

       1 nameserver 128.84.223.58
       2 nameserver 128.84.223.59
       3 ...

These are the ip addresses of the primary and secondary BIND servers.

If your `resolv.conf` file is in a different directory, you can use a variant of the DesktopSignaling constructor to say where it is:

       // tell signaling where the directory server's config file is
       DesktopSignaling signal = new DesktopSignaling
          ( this, "id", "pass", "my custom telephony application ",
           "c:\\net\\reconfig.ini");

Note that this variant also lets you give a name to your application, which is entered as a descriptive tag in the directory's database.

Since the DesktopSignaling registers your current location in the database, you should remove this when finishing. Do this by invoking your DesktopSignaling's

    logout()

method.

# Dialing Out

Suppose your application wants to call somebody on a telephone, or maybe it wants to contact another application (Voice Mail, for example), or just wants to call a person, contacting them wherever they may be located. This is done by your DesktopSignaling's `Dial()` method. This method takes a String object that says who or what you want to call. If it is a telephone, you might put in a string like `5551212`, which would dial a telephone number. If you want to dial an user in the system, you may also give the userid of the user.

The Dial method sends a call invitation to the other party; if the invitation is accepted, Dial sets up a SignalConnection (which is a AudioConnection as described in the previous section with control information added to it). If the invitation is refused, an appropriate Exception is thrown.

By default, a full-duplex connection is set up. One channel goes from the microphone on your computer to the internet address of the entity you called (if your application is dialing a telephone, the internet address is that of a Gateway machine to place the call). The other channel comes in from the network (from whatever or whomever you called) and goes to the speakers on your computer.

If you don't like this setup for your input and output channels, then you can override them in the dial call.

Here are two examples (``signal'' is the DesktopSignaling object):

       // Example 1: default is to use microphone and speakers
       SignalConnection flow1 = signal.Dial ( "user@itx.org" );
           :
       // Example 2: over-ride the defaults for a half-duplex connection
       Channel cOut = new Channel();
       cOut.setSource(new Microphone(cOut));
       cOut.addDestination(new NetworkDestination())
       SignalConnection flow2 = signal.Dial ("5551212", null, cOut);

The first example will send a dial invitation to user@itx.org trying each location in the list of places at which he is currently callable, until the call is picked up or the list is exhausted. His current locations are listed in the ITX Directory, and might include a roaming location.

The second example dials a telephone number and will send sound to the telephone but will not receive data.

If the application decides that it wants to hangup a call, it can call its DesktopSignaling's Hangup method:

       // signal is our DesktopSignaling
       // con is the SignalConnection we were using
       signal.Hangup ( con );

# Incoming Calls

Taking incoming calls starts with the application's SignalingObserver handler methods. These methods include:

- `onInvite(InviteSignalEvent)` - a peer application is asking you to answer (``inviting'', in telephony jargon). Your application can accept, reject, or say you are busy.
- `onStartCall(SignalConnection sc)` - a peer application has confirmed your accept, and call setup is complete. The application should use the Connection inside of the SignalConnection to do data exchange, after opening it.
- `onAbortCall(AbortSignalEvent)` - the peer application has aborted the invitation made to you (perhaps after learning that your are running on a computer with no speakers; see the section on PropertyCollections). The event object contains the reason for the abort.

There are a few other SignalingObserver methods that your application might wish to implement. These are

- `onHangup(HangupSignalEvent)` - the peer application has hung up. This would normally come during an established call.
- `onDTMF(DTMFSignalEvent)` - the peer application has sent you a DTMF tone. Details are in the event object.

# Signal and Interaction with other ITX components

There are certain variations available to the ITX applications programmer concerning the interaction between your control layer and the directory and the data layer. At minimum, the application need never make direct calls on the directory or on the data layer, because your DesktopSignaling will do this for you. Thus the most basic ITX application is layered as follows:

# How ITX Signaling Works

ITX signaling protocol is based on the SIP call initiation protocol. Users are addressed by email-like addresses. The first step in a 3-way session setup is when the caller sends an INVITE signal to the callee. The invitation contains enough information to describe the caller and what media types and formats will be accepted in the call.

The callee then decides whether or not to ACCEPT. If so, then the packet that goes back to the caller contains the callee's part of a data connection (which media properties are supported, etc.). Finally, the caller completes the packet with its properties and sends a CONFIRM back to the callee.

Once the 3-way handshake is complete, both sides then open their data connection and the call proceeds.If at any time, the 3-way handshake times out, the call is torn down and the application is informed through the onAbortCall() event handler.

For example if the caller never receives an ACCEPT (which actually could also be a busy or reject as well as an accept), the Dial function completes and throws an InviteTimeOutException. Likewise, if the callee sends an ACCEPT packet back to the caller but never gets an ACK, it times out and tears down the half-way built connections.

# Directory Service

A Directory Service client is encapsulated within each DesktopSignaling object. This client communicates with the directory server, to look up names and locations, to authenticate an user with the server, to add and delete entries, and so on. The actual directory server used by the ITX project is BIND from Berkeley; by overriding the DSComm class, one can interface with other databases

The directory service client is instantiated by your application's DesktopSignaling object. An application can get its DirectoryService object from its DesktopSignaling:

       DesktopSignaling signal;  // our DesktopSignaling
       DirectoryService ds;      // our directory client
           :
       ds = signal.getDirectory();

Now the application can use the directory through any DirectoryService public methods. It should be pointed out that there are levels of privilege associated with the directory. Applications and users have the lowest level of access, and can manipulate only those database entries associated with their username. The access level for a user or application is determined when the entry is first added to the database by the database administrator.

When Directory Service is instantiated, the current location of the user and application is added to the directory so that other applications/users/telephones can find the user.

One simple ITX application might be a program that allows people to update their personal profile to specify new telephone numbers where she or he can be reached. This sample application would register on the user's behalf (collecting the userid and password via a dialogue box, say), and then call `registerLocation()` and `unregisterLocation()` as the user wishes.

One convenient method is ``dumpAllUsers'' which lists all the users registered with ITX.

Given a userid, you can look up their ITX extension number, at least for the users that are ``listed'', using the ``getExtension'' method:

       // ds is my DirectoryService.  How can I contact bob@cornell.edu?
       Digits extension = ds.getExtension(new UserID("bob@cornell.edu"));

(Digits is a class in the `cnrg.itx.ds` package.)

The application might want to look up its own information, registered in the database by your DesktopSignaling component when you constructed it. This information includes your extension or userid or whatever. In fact, if your application is invoking any method that requires a UserID object, one way of coming up with one is as follows:

       // signal is my DesktopSignaling - who did I register as?
       UserID me = (signal.getDirectory()).getID();

See the DirectoryService JavaDoc page for other methods you can use. Some other objects in the `cnrg.itx.ds` package that programmers should be familiar with include these: UserID, Location, and Digits.

A Location contains the information about a participant in the ITX system. For example, `SignalEvent.InvitePacket.getSenderLoc()` returns the Location of the person who started a call. From the Location you can get its type (whether it is a telephone, ip address or user id), whether or not that Location can be directly dialed, and so on.

The UserID object encapsulates the name of an user. Location.getUID() returns the caller's name; DesktopSignaling.getDirectory().getID() returns the name that this application was logged in with.

# The Gateway

ITX telephony applications that wish to include real telephones located in the telephone network use the `cnrg.itx.gtwy` package to relay sound data between the internet and the telephone network.

The way the gateway package is integrated with ITX is as follows: when launched, the Gateway Manager runs as a peer application with its own signaling, data, and directory clients, just like any other ITX application. The difference is that when it gets an invitation from another application, that invitation is asking for a real telephone number. The Gateway's implementation of the Dial method is to place a call from one of its telephone lines to some other telephone.

For example, suppose my application wants to call a telephone number. When directory services is asked to look up that number, it realizes it is a telephone because (1) it is not in the database, and (2) it is all digits. In this case, it returns to my application the list of all the locations (IP and port) of running gateways.

Similarly, using a real telephone, one might dial the gateway, and then punch in the extension of an application or user on the network that one wants to call. The gateway will then set up a datapath between the line you are calling on and a socket that leads to the indicated application, which could be some user's desktop telephone application.

Gateway code (unlike control, data, and directory) is not bound with ITX applications; it runs as a server and as a peer application. The name of the server is Gateway. Only one Gateway per machine is permitted, because a set of telephone lines can only be controlled by a single manager.

A gateway may or may not be associated with a PBX. If your group has control over a PBX, or part of a PBX (as we do in the ITX project), then you can have the gateway use the PBX to place and receive calls. In our case, the gateway passes all invitations to a telephone on to the PBX Server (PBXSignalingServer), which then dials the telephone and reports back whether the telephone line was picked up or not. In addition, it hangs up the call when asked to do so, and reports back to the gateway if the remote telephone hangs up.

The gateway also allows you to use a real telephone to send sound to an application running on another computer. The steps involved are:

1.
  Pick up the telephone and call a number on some gateway.
2.
  The gateway answers the call, playing a recorded message to the caller. In the case of the CUTel Demo, the message asks you to punch in an extension number, followed by a pound sign.
3.
  The gateway then makes a Dial to the user at that extension. As a result, the gateway's DesktopSignaling component sends the invite on to the current Location of that user (presumably an application running on a computer somewhere).
4.
  When the user or application accepts, the gateway opens up a data channel from the oncoming call to the Network, and the call commences.

All sound data between the Gateway and another application passes over the network, in UDP packets, using RTP. Accordingly any data sources or destinations that involve a telephone will use a NetworkSource or NetworkDestination device.

Sound data between the Gateway and the telephone is 8-bit sound samples multiplexed together and transmitted at 64 Kbps. The Gateway executes all the logic for converting between the one and the other.

# Implementation Details

None of the information in this section is needed by the ITX programmer, but it may be of interest anyway.

The gateway server, Gateway, is coded in Java with JNI calls to the low-level Dialogic system library, written in C. The Dialogic library handles such things as initializing the telephone lines and playing sound bytes to the telephone.

The Gateway instantiates a SignalInterface object, which in turn instantiates a standard ITX DesktopSignaling object (which in turn registers the gateway with directory service). The SignalInterface is the part of the gateway that implements the SignalingObserver interface.

The SignalInterface object also communicates with a PBX server.The PBX runs entirely under the control of a gateway and does not directly communicate with any other application.

The PBX server is coded entirely in Java, does not handle any data, and uses JTAPI (Java Telephony API) to control the PBX. Using JTAPI, the PBX can set up outgoing telephone calls to anywhere. (Incoming telephone calls go through the PBX machine, but not through the PBX server. The call goes directly to one of the lines on the gateway.)

Users of the `cnrg.itx` package will have to implement their own Gateway if they use a different telephony card. However, the DesktopSignaling component, programmed entirely in Java, should work as is. The PBX server should also work as is, because your PBX vendor should be able to supply you with a JTAPI implementation for their machine.

# About Events, Exceptions, Properties, and Statistics

The ITX system extensively uses an event model. Events are passed to handlers, so that the handlers can take appropriate action. Exceptions are thrown in case of unexpected events. Properties are roughly media capabilities, and are part of every connection. Statistics can be generated for all data transfers.

# Events

Each ITX application is a SignalingObserver. Hence, events are used to convey information to the application's event handlers. For example, your onInvite handler is passed an InviteSignalEvent, which contains all the information about who is asking for you to pick up a call.

Most event objects have methods defined on them for extracting bits of information. For example, the AbortSignalEvent has the following methods:

- getAbortReason() - returns the String containing explaining why the invite was aborted.
- getConnection() - returns the data Connection that had been setup between you and the party that is aborting the invite.

If your application extends the AbstractSignalingObserver, all of the default event handlers might be acceptable. (None of these handlers do anything at all.) In this case, you do not need to put any of the handlers into your application. But if you want to do something special on onInvite, etc., then you must override the corresponding handler.

All of the SignalEvents (AbortSignalEvent, DTMFSignalEvent, HangupSignalEvent, and InviteSignalEvent) contain the InvitePacket that was used to initiate the call. `getInvitePacket()` can be used to retrieve the InvitePacket, and all of the information inside. There are many public methods that can be called on an InvitePacket.

# Exceptions

If unexpected things happen during the course of ITX execution, then Exception objects are created and thrown. There are a wide variety of specific Exceptions, all of which inherit from Java's Exception class. You may choose to field individual Exceptions, or just Exception in general. In any case, the `toString()` method is defined on the Exception which gives more information about why the ITX Exception was thrown.

Once a call has been set up, each party to the call has a SignalConnection object, which contains basically all the information relating to a call. In particular you can use the `getProperties()` method to extract the PropertiesCollection from the SignalConnection. The Properties Collection is the set of device properties available to a call.

The NetworkProperty allows you to get the IP address and port of a network device's data port. Properties also include features of the encoded data stream, such as packet size and encoding method.

# Statistics

Does your application want to know how much sound data is flowing, or ineed whether any sound is flowing at all? The Stats object (in the `cnrg.itx.datax` package) does the trick.

Sources, Destinations, Channels, and Connections all implement the Statistics interface, meaning that they keep a count of bytes transmitted or whatever. The `Statistics.getStatistics()` method returns a printable Stats object, for example:

       System.out.println ( myNetworkSource.getStatistics() );

With some effort, an application could also parse the object to extract, say, the number of bytes that have been sent. An application could also use the Statistics interface to collect its own statistics.

# Examples

In the examples below, it is assumed that your CLASSPATH has the `itx.jar` archive somewhere in it, that you have a `resolv.conf` file in your working directory, that your PATH includes the directory containing `DSComm.dll` and `jaudio.dll`, and that the Gateway, PBX Server, and Directory Server are all up and running.

# Minimal ITX Program

The minimal ITX application makes and takes no calls, sends and receives no data, but the location of its signaling component is registered in the directory for the duration of the run:

    import cnrg.itx.signal.*;
    public class Minimal extends AbstractSignalingObserver {
       public static void main (String[] args) {
          Minimal me = new Minimal();
       }
       public Minimal() {     // register and then unregister
          try {
             DesktopSignaling sig = new DesktopSignaling (this, "guest", "guest");
             sig.logout();
          } catch (Exception e) {
             System.out.println("Couldn't get authenticated");
          }
       }
    }

In a real application you'll probably want to have the unregister far apart from the constructor. This means you would store ``sig'' as a local variable, and have a logout method that invokes `sig.logout()`.

# ITX Program That Rings a Telephone

The next most minimal ITX program runs entirely in the control plane, and does not send or receive any sound data. However, it does use signaling to register with the database, ring a telephone, and unregister with the database. Edit the preceding example to add the following code between constructing a DesktopSignaling and logging out:

         :
       // Make 2545454 ring
       try {
          SignalConnection con = sig.Dial ("2545454",null,null);
          :
          sig.Hangup ( con );
       } catch ( ConnectException e ) {}
         :

# PhoneRecorder

If you don't have a microphone on your computer, you can still use your telephone to record voice data. The following application will write incoming sound data into an output file:

    import java.io.*; // for OutputStream

    import cnrg.itx.signal.*;  // for DesktopSignaling
    import cnrg.itx.signal.SignalEvent.*;
    import cnrg.itx.datax.devices.*;  // for AudioConnection, etc.
    import cnrg.itx.datax.*;          // for Channel

    public class PhoneRecorder extends AbstractSignalingObserver {

       private DesktopSignaling myDS = null;
       private FileOutputStream ourFile = null;
       private NetworkSource source = null;
       private StreamDestination dest = null;

       // Default constructor gets a DesktopSignaling object
       public PhoneRecorder () {
          [ myDS = new DesktopSignaling ( this, "PhoneRecorder", ... ) ]
       }

       // Main entry point is here
       public static void main ( String[] args ) {
          PhoneRecorder me = new PhoneRecorder();
       }

       // SignalingObserver method - invoked when someone calls this app
       public void onInvite (InviteSignalEvent ise) {
          Connection c = null;            // our AudioConnection
          Channel in = new Channel();     // This will be telephone to file

          // Open a FileOutputStream, which is the file to which sound is written
          try { ourFile = new FileOutputStream ( getName() );
          } catch ( Exception e ) {
    	 System.out.println ("Could not open an output file because" + e);
    	 System.exit( 0 );
          }

          // Set up a half-duplex AudioConnection and open it
          try {
    	 source = new NetworkSource(in, Channel.SAMPLE_SIZE);
    	 dest = new StreamDestination(ourFile);
    	 // our in channel is NetworkSource -> StreamDestination
             in.setSource ( source );    in.addDestination ( dest );
    	 // our connection has only an in channel (half-duplex)
             c = new AudioConnection ( in, null );     c.open();
          } catch ( Exception e ) {
    	 System.out.println ("Could not open data connection because" + e);
    	 System.exit( 0 );
          }

          // If we get to here, we have an open data connection
          ise.accept( c );  // set the accept flag in the invitation

          // Exit back to DesktopSignaling, which will return the
          // Accepted invitation back to the Gateway

       }

       // This method is invoked by DesktopSignaling when the caller hangs up.
       public void onHangup(HangupSignalEvent hse) {
          try {
             ourFile.flush();
             ourFile.close();
          } catch ( Exception e ) {}
          System.out.println ( source.getStatistics() );
          System.out.println ( dest.getStatistics() );
          myDS.logout();
       }

       // +++++++++++  Private methods +++++++++++++++++=

       // Generate a file name to capture the data
       private String getName () {
          return "file1";   // Substitute your own here
       }
    }

# Network Client

The previous example illustrated a simple half-duplex application. A full duplex connection between two application is illustrated by the following example, which is the client side. The server side is left to the imagination.

    package cnrg.itx.datax.devices;

    import cnrg.itx.datax.*;
    import java.io.*;
    import java.net.*;

    /**
     * This class tests audio streaming over the network.  This sample routine
     * uses a NetworkSource * and SpeakerDestination to play audio originating
     * from a NetworkServer.  Note that in creating the various destinations
     * and sources, the remote source/destination sample size MUST equal the
     * local source/destination sample size.
     */
    public class NetworkClient
    {
      public static int PORT = 7777;

      public static void main(String []args)
      {
        try
        {

          // Input channel, source, and destination
          Channel inChannel = new Channel();
          NetworkSource inSource = new NetworkSource(inChannel,
                     PORT,
                        Channel.SAMPLE_SIZE);
          SpeakerDestination inDest = new SpeakerDestination();

          // Set input channel
          inChannel.setSource(inSource);
          inChannel.addDestination(inDest);

          // Start destination
          inChannel.open();

          // Let the audio file play...
          System.out.println("Playing audio from the network...");
        }
        catch (Exception e)
        {
          System.out.println(e.getMessage());
        }
      }
    }

# Appendix A: ITX Package Hierarchy

Here is a list of the classes that are useful to the ITX applications programmer, and (TBD) some of their methods.

                             Hierarchy For ITX Packages

    Class Hierarchy

       o class java.lang.Object
            o class cnrg.itx.signal.client.AbstractSignalingObserver (implements
              cnrg.itx.signal.client.SignalingObserver)
            o class cnrg.itx.datax.Channel (implements
              cnrg.itx.datax.Properties, cnrg.itx.datax.Statistics)
            o class cnrg.itx.signal.client.DesktopSignaling
            o class cnrg.itx.ds.client.Digits (implements java.io.Serializable)
            o class cnrg.itx.ds.client.DirectoryService
            o class cnrg.itx.ds.client.Location (implements
              java.io.Serializable)
            o class cnrg.itx.datax.devices.MicrophoneSource (implements
              java.lang.Runnable, cnrg.itx.datax.Source)
            o class cnrg.itx.datax.devices.NetworkDestination (implements
              cnrg.itx.datax.Destination)
            o class cnrg.itx.datax.devices.NetworkProperty (implements
              cnrg.itx.datax.Property)
            o class cnrg.itx.datax.devices.NetworkSource (implements
              java.lang.Runnable, cnrg.itx.datax.Source)
            o class java.util.Observable
                 o class cnrg.itx.datax.Connection (implements
                   cnrg.itx.datax.Properties, java.lang.Runnable,
                   cnrg.itx.datax.Statistics)
                      o class cnrg.itx.datax.AudioConnection
            o class cnrg.itx.datax.PropertiesCollection (implements
              java.io.Serializable)
            o class cnrg.itx.signal.client.SignalConnection
            o class cnrg.itx.signal.SignalEvent.SignalEvent (implements
              java.io.Serializable)
                 o class cnrg.itx.signal.SignalEvent.AbortSignalEvent
                 o class cnrg.itx.signal.SignalEvent.AliveSignalEvent
                 o class cnrg.itx.signal.SignalEvent.DTMFSignalEvent
                 o class cnrg.itx.signal.SignalEvent.HangupSignalEvent
                 o class cnrg.itx.signal.SignalEvent.InviteSignalEvent
            o class cnrg.itx.signal.SigPacket (implements java.io.Serializable)
                 o class cnrg.itx.signal.InvitePacket (implements
                   java.io.Serializable)
            o class cnrg.itx.datax.devices.SpeakerDestination (implements
              cnrg.itx.datax.Destination)
            o class cnrg.itx.signal.SignalEvent.StartCallSignalEvent
            o class cnrg.itx.datax.Stats
            o class cnrg.itx.datax.devices.StreamDestination (implements
              cnrg.itx.datax.Destination)
            o class cnrg.itx.datax.devices.StreamSource (implements
              java.lang.Runnable, cnrg.itx.datax.Source)
            o class java.lang.Throwable (implements java.io.Serializable)
                 o class java.lang.Exception
                      o class cnrg.itx.datax.DataException
                           o class cnrg.itx.datax.DuplicateDestinationException
                           o class cnrg.itx.datax.jaudio.JAudioException
                      o class cnrg.itx.ds.client.DirectoryServiceException
                           o class cnrg.itx.ds.client.AccessDeniedException
                           o class cnrg.itx.ds.client.AuthenticationException
                           o class
                             cnrg.itx.ds.client.RecordAlreadyExistsException
                           o class cnrg.itx.ds.client.RecordNotFoundException
                      o class cnrg.itx.gtwy.GatewayException
                      o class cnrg.itx.ITXException
                           o class
                             cnrg.itx.signal.client.DesktopSignalingException
                                o class cnrg.itx.signal.client.ConnectException
                                     o class
                                       cnrg.itx.signal.client.ConnectFailedToOpenSocketException
                                     o class
                                       cnrg.itx.signal.client.ConnectNullObjectSentException
                                     o class
                                       cnrg.itx.signal.client.ConnectNullSocketException
                                o class
                                  cnrg.itx.signal.client.DesktopSignalingServerException
                                o class cnrg.itx.signal.client.InviteException
                                     o class
                                       cnrg.itx.signal.client.InviteBusyException
                                     o class
                                       cnrg.itx.signal.client.InviteIncompatibleException
                                     o class
                                       cnrg.itx.signal.client.InviteInvalidException
                                     o class
                                       cnrg.itx.signal.client.InviteRejectException
                                     o class
                                       cnrg.itx.signal.client.InviteTimeoutException
                           o class cnrg.itx.signal.pbx.DialingException
                           o class cnrg.itx.signal.pbx.PBXSignalingException
                      o class cnrg.itx.signal.client.SigPacketHandlerException
            o class cnrg.itx.ds.client.UserID (implements java.io.Serializable)
            o class cnrg.itx.ds.client.UserProperty

    Interface Hierarchy

       o interface cnrg.itx.datax.Properties
            o interface cnrg.itx.datax.Destination(also extends
              cnrg.itx.datax.Statistics)
            o interface cnrg.itx.datax.Source(also extends
              cnrg.itx.datax.Statistics)
       o interface java.io.Serializable
            o interface cnrg.itx.datax.Property
       o interface cnrg.itx.signal.SignalID
       o interface cnrg.itx.signal.client.SignalingObserver
       o interface cnrg.itx.datax.Statistics
            o interface cnrg.itx.datax.Destination(also extends
              cnrg.itx.datax.Properties)
            o interface cnrg.itx.datax.Source(also extends
              cnrg.itx.datax.Properties)

# About this document ...

ITX Programmer's Guide

This document was generated using the LaTeX2`HTML` translator Version 98.1p1 release (March 2nd, 1998)

Copyright © 1993, 1994, 1995, 1996, 1997, Nikos Drakos, Computer Based Learning Unit, University of Leeds.

The command line arguments were:
latex2html `-local_icons -split 2 Guide`.

The translation was initiated by Donna Bergmark on 1999-04-15

Subsections

- Contents
- Introduction
- If You Want to Use ITX ...
- Data Exchange
- Signaling
  - Obtaining a Signaling Object
  - Dialing Out
  - Incoming Calls
  - Signaling and the Other Components
  - How ITX Signaling Works
- Directory Services
- The Gateway
  - Implementation Details
- About Events, Exceptions, Properties, and Statistics
  - Events
  - Exceptions
  - Statistics
  - About Connection Properties
- Examples
  - Minimal ITX Program
  - ITX Program That Rings a Telephone
  - Registry Dumper
  - PhoneRecorder
  - Network Client
- Appendix A: ITX Package Hierarchy
- About this document ...