7. Beispielanwendungen

In diesem Kapitel sollen anhand einiger Beispiel die Möglichkeiten von CPL gezeigt werden. Die Beispiele orientieren sich an der gegenwärtigen Implementierung, d.h. die Möglichkeiten, die sich durch den Einsatz eines Tcl-Interpreters ergeben sind hier nicht berücksichtigt.


7.1. Einfacher Anrufbeantworter

Das folgende CPL-Skript realisiert einen trivialen Anrufbeantworter: Nach Eingang eines Anrufes startet das Skript im Anweisungsblock der Definition. Dort wird nach einem Eintrag ins Logfile der Anruf mittels entgegengenommen. Anschließend wird eine Ansage abgespielt, gefolgt von einem kurzen 1,3 kHz Ton. Nach dem Starten eines Timers wird der eingehende Audiostrom in der Datei icm.au maximal 1 Minute lang aufgezeichnet. Bei Ablauf des Timers wird die Verbindung beendet (), anschließend terminiert das Skript ().

state IncomingCall {

    on enter {
      log "$sysDate $sysTime: incoming call from $sysCallingParty\n"
      accept
      exec "iAuCat Welcome.au"       # play outgoing message
      exec "iAuTone 1300 100 50"     # generate 1.3 kHz tone for 100 ms
      timer recTimer local 00:01:00  # allow 1 minute recording time
      audiorec "icm.au"              # record incoming msg
      }
    on timer recTimer {
      hangup
      exit
    }
}
Soll der Anrufbeantworter erst nach 10 Sekunden aktiviert werden, damit der Anruf beispielsweise an einem anderen Telefon entgegengenommen werden kann, so wäre das Beispiel wie folgt abzuändern:

state IncomingCall {

    on enter {
      timer pickupDelay local 00:00:10
    }
    on timer pickupDelay {
      log "$sysDate $sysTime: incoming call from $sysCallingParty\n"
      accept
      exec "iAuCat Welcome.au"       # play outgoing message
      exec "iAuTone 300 100 50"      # generate 1.3 kHz tone for 100 ms
      timer recTimer local 00:01:00  # allow 1 minute recording time
      audiorec "icm.au"              # record incoming msg
      }
    on timer recTimer {
      hangup
      exit
    }
}
Die -Anweisung, die den Anruf entgegennimmt, wird hier also um 10 Sekunden verzögert. Wurde (an einem Mehrgeräteanschluß) der Anruf an einem anderen Apparat angenommen, so wird ein Disconnect-Event ausgelöst, durch das das Skript terminiert wird.


7.2. Teilnahme an einem RTP-Strom

Das folgende Beispiel beschreibt eine State-Machine bestehend aus vier Zuständen, mit der der Benutzer an einem RTP-Datenstrom teilnehmen kann. Nach Eingabe von IP-Adresse und UDP-Portnummer wird er mittels mit dem RTP-Audiostrom verbunden. An diesem Beispiel werden u.a. der Gebrauch der -Anweisung sowie die Fehlerbehandlung mittels sysStatus deutlich.

state Welcome {

    on enter {
      accept
      exec "sun5/iAuCat ounds/GutenTag.au"  # greeting message
      if { $sysStatus != 0 } {
        exec "sun5/iAuCat sounds/Fehler.au" # error message
        hangup
        exit
      }
      enter GetIPaddr
    }
}

state GetIPaddr {

    on enter {
      exec "sun5/iAuCat sounds/ip.au"
      timer t1 local 00:00:20               # allow 20 sec for IP addr.
    }
    on dtmf "D'*'D'*'D'*'D'#'" {
      cvt ip $sysDtmf "DTMF2IP"             # convert DTMF into IP addr.
      if { $sysStatus != 0 } {
        exec "sun5/iAuCat sounds/ipErr.au"
        enter GetIPaddr }
      else {
        enter GetPortNo
      }
    }
    on timer t1 {
      exec "sun5/iAuCat sounds/Eingeschlafen.au"
      enter GetIPaddr
    }
}

state GetPortNo {

    on enter {
      exec "sun5/iAuCat sounds/PortNr.au"
      timer t1 local 0:0:05 }               # allow 5 sec. for input
    on dtmf "ddddd" {
      set port $sysDtmf
      if {$port < 1024} {
        exec "sun5/iAuCat sounds/IllPortNo.au"
        enter GetPortNo
      }
      if {$port > 65535} {
        exec "sun5/iAuCat sounds/IllPortNo.au"
        enter GetPortNo
      }
      enter ListenToMbone }
    on timer t1 {
      exec "sun5/iAuCat sounds/Eingeschlafen.au"
      enter GetPortNo
    }
}

state ListenToMbone {

    on enter {
      exec "sun5/iAuCat sounds/BeendenMit.au"
      redirect "rtp://$ip:$port"
      if { $sysStatus != 0 } {
        exec "sun5/iAuCat sounds/Fehler.au" # error message
        hangup
        exit
      }
    }
    on dtmf "#" {
      enter Welcome
    }
}
Zur Veranschaulichung ist die State-Machine in Abbildung [pic-sm1] grafisch dargestellt. Die in der folgenden Beschreibung in Klammern gesetzten Zahlen entsprechen den in der Abbildung schwarz hinterlegten Event-Nummern. Nach dem Abspielen einer Begrüßungsnachricht im Startzustand Welcome wird der Zustand GetIPaddr betreten (2), wo der Benutzer zur Eingabe einer IP-Adresse in Dotted-Decimal-Notation aufgefordert wird, deren Eingabe er mit der \#-Taste abschließen muß. Für die Eingabe bleiben ihm 20 s Zeit, danach (2a) wird eine Fehlermeldung ausgegeben und der Zustand erneut betreten, d.h. Eingabeaufforderung und Timerstart werden wiederholt. Nach Erkennung der Eingabe wird diese mit umgewandelt und der Zustand GetPortNo zur Eingabe der Portnummer betreten (3). Diese wird als fünfstellige Zahl erwartet (). Nach Erkennung der Portnummer wird der Zustand ListenToMbone betreten (4), in dem der Anrufer mittels mit der gewünschten Audiokonferenz verbunden wird.

Finite-State-Machine for the MBONE example

Die Konferenzteilnahme kann mit Hilfe der \#-Taste beendet werden (6), ohne gleichzeitig die Telefonverbindung zu beenden. Vielmehr gelangt der Anrufer wieder in den Ausgangszustand zurück.


7.3. Erweiterter Anrufbeantworter

Im folgenden Beispiel wird ein erweiterter Anrufbeantworter realisiert. Hier kann der Anrufer durch Eingabe einer Geheimnummer aufgezeichnete Nachrichten abhören. Ungeduldige Anrufer, die wiederum in Besitz einer Geheimnummer sind, können sich mit der gewünschten Person sofort verbinden lassen ().

# ans.cpl   --  "Enhanced" answering machine
#
# (c) 1997 F. Oertel
#

state Welcome {

    on enter {
      set myPIN 4711
      set sysTrace 1
      accept
      if { $sysTime < "17:00:00" } {
        exec "sun5/iAuCat sounds/GutenTag.au" }     # greeting message
      else {
        exec "sun5/iAuCat sounds/GutenAbend.au" }   # greeting message
      enter Selection
    }
}

state Selection {

    on enter {
      exec "sun5/iAuCat sounds/Inhalt.au"   # tell user the menu
      timer t local 0:0:08                  # allow 8 secs for input
    }
    on dtmf "1" { enter RecordMessage       }
    on dtmf "2" { enter PlayMessages        }
    on dtmf "3" { enter Redirect            }
    on dtmf "#" { exit                      }
    on timer t {
      exec "sun5/iAuCat sounds/Eingeschlafen.au"
      enter Selection
    }
}

state RecordMessage {

    on enter {
      exec "sun5/iAuCat sounds/Sprechen.au"
      exec "sun5/iTone 1350 200 60"         # beep
      timer icm local 00:01:00              # allow 1 min for icm
      audiorec "icm/i$sysCalls.au"
    }
    on dtmf "#" {                           # terminate recording
      enter Selection }
    on timer icm {
      exec "sun5/iAuCat sounds/Genug.au"    # "thank you for ..."
      exit
    }
}

state PlayMessages {

    on enter {
      AskForPIN
    }
    on dtmf "4711" {                        # we've got a PIN!
      exec "sun5/iAuCat icm/*.au"           # play all recorded messages
     enter Selection
    }
    on timer pin {
      exec "sun5/iAuCat sounds/Eingeschlafen.au"
      enter Selection
    }
}

state Redirect {

    on enter {
      AskForPIN
    }
    on dtmf 4711 {
      timer pin stop
      redirect "phone://35"                 # redirect to my handy
      enter Selection
    }
    on dtmf "#" {
      enter Selection
    }
    on timer pin {
      exec "sun5/iAuCat sounds/Eingeschlafen.au"
      enter Selection
    }
}

proc AskForPIN {

    exec "sun5/iAuCat sounds/PIN.au"
    timer pin local 0:0:6                   # wait 6 secs for PIN
}

Dieses Beispiel zeigt u.a. den Einsatz von Prozeduren. In AskForPIN werden ein Audiofile abgespielt sowie ein Timer gestartet. Da die Prozedur aus den Zuständen Redirect und PlayMessages aufgerufen wird, gilt der Timer jeweils lokal in diesen Zuständen.


7.4. Preiswertes Telefonieren

Ein Dienstanbieter kann teure Auslandsgespräche oder ähnliches zum Ortstarif anbieten: Der Anrufer ruft zunächst den Dienstanbieter an, legitimiert sich durch eine Geheimzahl (oder auch nicht) und wählt dann die gewünschte Nummer, mit der er dann per verbunden wird. Folgendes Programm realisiert diesen Dienst (ohne Anruferlegitimation):

state Welcome {

    on enter {
      accept
      exec "sun5/iAuCat sounds/GutenTag.au"
      timer DialTimeout local 0:00:20
    }
    on dtmf "D'#'" {
      timer DialTimeout stop
      timer ConnectTimeout local 00:30:00
      redirect "phone://$sysDtmf"
    }
    on timer DialTimeout {
      exec "sun5/iAuCat sounds/att.au"
      exit
    }
}
Nach der Ansage hat der Benutzer 20 s lang Zeit eine beliebige Nummer einzugeben. Nachdem er die Eingabe mit der \#-Taste beendet hat, wird er sofort mit der gewünschten Nummer verbunden. Die Verbindungsdauer wird durch den Timer ConnectTimeout auf 30 Minuten begrenzt. Zu beachten ist, daß während des Gespräches eine weitere Nummer eingegeben und mit \# quittiert werden kann. Das hierbei erneut ausgelöste DTMF-Event beendet die aktuelle Umleitung automatisch, so daß der zweite B-Kanal für das erneute sofort wieder zur Verfügung steht. Wichtig ist hier außerdem den Timer für die Nummerneingabe zu beenden, da sonst nach Ablauf der 20 s die Verbindung beendet wird.
File was created Wed Feb 26 18:31:47 1997 by tex2html