Programmable Telephone Gateway

The gateway consists of an RTP gateway and a call processor.

Call Processor

The call processor program has two functions:

  1. answer any SIP calls and optionally make other SIP calls
  2. answer POTS phone calls.

The call processor combines Tcl and C. The basic event loop is Tcl, but parsing and other functions are implemented in C.

It answers the analog phone line via the Teltone interface box. The Teltone interface has a serial port and line-level audio input and output ports that connect it to the workstation. The program is a single C/Tcl-based event-driven program that triggers events based on strings received through the serial port, such as phone ringing or hang-up, as well as other events. A CPL program is invoked for each incoming call.

To simplify retransmission of requests, SIP is handled by a separate process that communicates via a bidirectional pipe with the CPL process. The CPL process sends commands such as INVITE or BYE, the process returns final status responses or INVITE or BYE (for incoming calls). (Is this necessary? Could probably handle timing within CPL module.)

The call processing language (CPL) is a Tcl-based language for processing incoming phone, ISDN and SIP calls.

For packet telephony and voice mail, RTSP requests should be supported directly (rtsp setup, rtsp play, rtsp pause, rtsp teardown).

Events

The following events can occur. Some events generate local variables that are visible only inside the event handler. Variables marked with (*) are only set for SIP calls. The device is either phone or. inet (for Internet). [Use callid instead for several concurrent SIP calls?]
name of event description of event SIP? phone? local variables implementation note
- (initial state) phone rings or SIP invitation arrives x x $callid (phone: locally generated), $from (SIP From: header; phone: if caller id available), $to (SIP To: header; phone: ISDN extension) $media (list from SDP description) $subject (*), $priority (*), $organization (*)  
busy outgoing call found busy callee x x retry-after  
ringing Outgoing call is ringing at the other side. x x    
declined Our outgoing call was answered, but the callee doesn't want to talk. to use x - $reason (*)  
answered [device] Our outgoing call was accepted. The variables describe where audio is to be sent. x x $host (*) $port (*)  
disconnected [device] Caller hung up. x x   SIP: received BYE or pmm BYE.
dtmf digit The given DTMF digit was dialed. If no digit is given, any digit will do. x x $digit  
timeout ms Timeout after the given number of milliseconds. x x    

Commands

Events marked with (*) apply to SIP only.
command SIP phone description events triggered implementation note
dial URL x x Dial (if telephone) or invite (if SIP URL). busy, answered; declined (*) Issues SIP INVITE command. User is responsible for handling time-out.
answer x x Answer the call (i.e., "pick up the phone").   SIP: send a "200 OK" response.
decline reason x - Decline the incoming call for the reason given.   SIP: Send 6xx response.
forward destination x - Decline call and tell caller to call the given number instead.   SIP: Send 301 "Moved temporarily" response.
connected x - Acknowledge call acceptance.   SIP: Send CONNECTED request to callee.
connect address port [ttl] x x Connect the workstation audio input/output to the network address given.   This is signaled via pmm to the RTP gateway.
disconnect [address port] x x Disconnect the workstation audio input/output to the network address given. If no address is given, disconnect phone.   This is signaled via pmm to the RTP gateway.
play file x x Play audio file to currently connected system(s).   pmm command to RTP gateway.
speak words x x Converts text to speech and hands it to the device.   pmm command to text-to-speech program.
play -stop x x Stop playing audio file.   pmm command to RTP gateway.
record file x x Record audio data from currently connected system.   pmm command to RTP gateway.
record -stop x x Record audio data from currently connected system.   pmm command to RTP gateway.
goto state [arg1 ...] x x Transition to the state named, with the given arguments.   internal command.

Implementation

The CPL program is parsed into the "entry" commands (the ones outside on) and a number of event handlers, one for each on command. Thus, each state is a list of Tcl "programs". The parsing may be done via Tcl.

The C program maintains a global state variable that is set by the goto command.

A number of generic file/socket event handlers always exist, independent of the state. Currently, these are:

When entering a state, the C program installs the event handlers requested and then executes (via eval) the entry statements. The exact mechanism of installing the event handlers depend on the event. Example implementation: for the DTMF handler, a pointer to the respective digit-specific Tcl handler is copied to a global Tcl array, which is accessed by the generic DTMF event handler. When a digit is recognized, the DTMF handler checks the array and does an eval on the entry, if found.

RTP gateway

This daemon program takes audio input from the workstation audio interface and generates RTP packets to one or more addresses. Similarly, it takes incoming audio packets and plays them to an audio interface. This program is NeVoT, but without a Tk user interface.

NeVoT is remote-controlled through a multicast interface (pmm).

NeVoT is also capable of recording audio to a file and playing back audio from a file.

The gateway needs to be enhanced to be able to detect DTMF ("touch tones") and indicate reception of DTMF back through pmm.

CPL syntax

States have the following generic syntax:

state S {arg1 arg2} {
  Tcl
  on E { Tcl }
  on E { Tcl }
}

Here, S is the name of the state, E the name of an event and Tcl can be any Tcl code.

Example

The following example answers a phone, plays a welcome message and then allows the user to connect to another announcement or access a gateway to the Internet.
# number dialed
set number ""

# Initial state as phone rings

state initial { } {
  # pick up phone through command
  # ignored if we have already picked up
  answer

  # play outgoing message
  play -loop "welcome.au"

  on disconnected {
    play -stop
  }

  # If user presses "1", this message is interrupted
  on dtmf 1 {
    play -stop
    goto sales
  }

  # If user presses "2", go to recording
  on dtmf 0 {
    play -stop
    goto record_message
  }
}

# This is the sales menu; can be interrupted any time
state sales {
  play "sales.au"
  on dtmf 0 {
    goto initial
  }  
  on dtmf 2 {
    goto record_message
  }
}

# Record message until user hangs up or presses key
state record_message {
  on disconnected phone {
    goto 
  }
  on dtmf * {
  }
}

# Connect user to Internet by having him "type out" names via the keypad
state dial {
  on dtmf # {
    goto connect_internet $number
  }
  on dtmf * {
    set number "$number$digit"
  }
}

# Try connecting to SIP address.
state connect_internet {number} {
  dial sip://${number}@gateway.cs.columbia.edu

  on ringing {
    goto ringing $number
  }
  on timeout 30 {
    goto connect_internet $number
  }
}

state ringing {number} {
  on busy {
    speak "The number you have dialed, $number, is busy."
    speak "Please try again later."
    disconnect
    exit
  }
  on decline {
    speak "The number you have dialed, $number, refuses your call."
    disconnect
    exit
  }
  on answered {
    connected
    connect $host $port
    goto icall $host $port
  }
}

# Gatewayed phone call is in progress. User can press # to be connected
# to a different number.
state icall {host port} {
  on disconnected {
    # disconnect the other side
    disconnect $host $port
    exit
  }
  on dtmf # {
    goto initial
  }
}

Last modified: 1997-08-23 by Henning Schulzrinne