Es gibt verschiedene Möglichkeiten, eine Asterisk-Telefonanlage von extern (also z.B. von anderen Programmen) aus zu steuern.
Die einfachste Möglichkeit, mit Asterisk von außen zu kommunizieren,
ist der Aufruf des Programmes asterisk mit den
Parametern -rx
und danach dem CLI-Befehl. So kann
man jeden beliebigen CLI-Befehl von der Shell aus ausführen.
Wenn man sich den Dialplan für die Extension
23
im Context
[meine-telefone]
anschauen will, kann man dies
mit der Eingabe asterisk -rx "show dialplan
23@meine-telefone" erreichen:
root@molokai:~>asterisk -rx "show dialplan 23@meine-telefone" [ Context 'meine-telefone' created by 'pbx_config' ] '23' => 1. Wait(1) [pbx_config] 2. Answer() [pbx_config] 3. Playback(hello-world) [pbx_config] 4. Wait(1) [pbx_config] 5. Hangup() [pbx_config] -= 1 extension (5 priorities) in 1 context. =- root@molokai:~>
Call Files lassen sich am ehesten mit Batch-Dateien vergleichen. Sie
werden ins Verzeichnis /var/spool/asterisk/outgoing/
verschoben und dort dann von Asterisk abgearbeitet.
Wichtig | |
---|---|
Ein mv (move) ist im Dateisystem ein atomarer Vorgang und deshalb für Call Files ideal geeignet. Bei einem cp (copy) wird dagegen die Datei Zeile für Zeile kopiert. Es kann also vorkommen, dass ein halbfertig kopiertes Call File von Asterisk bereits abgearbeitet wird. |
Der ganze Mechanismus lässt sich anhand eines Beispiels besser erklären. Nehmen wir an, dass an einer Asterisk-Anlage ein SIP-Telefon mit der Nummer 2000 angemeldet ist. Weiterhin haben wir im Dialplan die folgende Extension eingetragen:
[call-file-test] exten => 10,1,Answer() exten => 10,n,Wait(1) exten => 10,n,Playback(hello-world) exten => 10,n,Wait(1) exten => 10,n,Hangup()
Jetzt generieren wir im Verzeichnis /tmp/
die
Datei ein-test.call
mit folgendem
Inhalt:
Channel: SIP/2000 MaxRetries: 2 RetryTime: 60 WaitTime: 30 Context: call-file-test Extension: 10
Danach verschieben wir diese Datei mit mv /tmp/ein-test.call /var/spool/asterisk/outgoing/
root@molokai:~>mv /tmp/ein-test.call /var/spool/asterisk/outgoing/
Jetzt passiert Folgendes:
- Asterisk überprüft ständig, ob sich im Verzeichnis
/var/spool/asterisk/outgoing/
ein Call File befindet, und arbeitet dieses ab, sobald es da ist. - Asterisk öffnet eine Verbindung zum Telefon
SIP/2000
. Wenn das Telefon besetzt sein oder nicht rangehen sollte, dann versucht Asterisk das gleiche noch zwei Mal (sieheMaxRetries
). - Geht der Benutzer des Telefons 2000 ran, dann startet
Asterisk im Context
[call-file-test]
die Abarbeitung der Extension10
. Es wird also der Sprachbausteinhello-world
abgespielt.
Im Call File können folgende Parameter angegeben werden:
Channel: <channel>
- Der zu benutzende Channel. Dabei gilt die gleiche
Syntax wie beim
Dial()
-Befehl (siehe „Dial()
“). Callerid: <callerid>
- Die zu benutzende Caller-ID.
WaitTime: <number>
- Die Anzahl an Sekunden, die das System auf die Annahme des Anrufs warten soll. Wird der Wert nicht angegeben, dann ist der Default 45 Sekunden.
MaxRetries: <number>
- Die Anzahl der weiteren Wählversuche (falls besetzt oder nicht erreichbar). Wird dieser Parameter nicht angegeben, ist der Defaultwert 0 (es wird also nur einmal versucht, den Channel aufzubauen).
RetryTime: <number>
- Die Anzahl an Sekunden, die bis zum nächsten Wählversuch gewartet wird. Wird dieser Parameter nicht angegeben, ist der Defaultwert 300 Sekunden.
Account: <account>
- Der Abrechnungscode für Ihr CDR-System.
Context: <context>
- Der Zielcontext.
Extension: <exten>
- Die Zielextension, die bei Erfolg aufgerufen wird.
Priority: <priority>
- Die Zielpriorität. Wenn nicht angegeben, dann ist der Defaultwert 1.
Setvar: <var=value>
- Mit
Setvar:
können beliebig viele Channelvariablen definiert werden. Archive: <yes|no>
Normalerweise werden Call Files nach der Abarbeitung direkt gelöscht. Ist
Archive: yes
gesetzt, werden die Call Files aber stattdessen ins Verzeichnis/var/spool/asterisk/outgoing_done/
verschoben. Dabei wird Asterisk noch eine Zeile zum Call File hinzufügen. Diese beschreibt das Ergebnis des Call Files und sieht so aus:Status: <Expired|Completed|Failed>
Beim Aufruf eines Call Files vergleicht Asterisk die Zeit der letzten Änderung der Datei mit der aktuellen Uhrzeit. Liegt dieser Eintrag in der Zukunft, wird das Call File noch nicht abgearbeitet. So kann man leicht Call Files zeitgesteuert abarbeiten.
Nehmen wir an, ein Hotel möchte über Asterisk ein einfaches Weckrufsystem erstellen. Kunden sollen einen Weckruf über die Servicerufnummer *77* aktivieren können. Nach der *77* soll das genaue Datum und die Weckuhrzeit gewählt werden.
[hotel-intern] exten => _*77*XXXXXXXXXXXX,1,Answer() exten => _*77*XXXXXXXXXXXX,n,Set(Jahr=${EXTEN:4:4}) exten => _*77*XXXXXXXXXXXX,n,Set(Monat=${EXTEN:8:2}) exten => _*77*XXXXXXXXXXXX,n,Set(Tag=${EXTEN:10:2}) exten => _*77*XXXXXXXXXXXX,n,Set(Stunden=${EXTEN:12:2}) exten => _*77*XXXXXXXXXXXX,n,Set(Minuten=${EXTEN:14:2}) exten => _*77*XXXXXXXXXXXX,n,NoOp(Weckruf soll fuer die Rufnummer ${CALLERID(num)} soll um ${Stunden}:${Minuten} Uhr am ${Tag}.${Monat}.${Jahr} erfolgen.) exten => _*77*XXXXXXXXXXXX,n,System(echo -e "Channel: SIP/${CALLERID(num)}\\nContext: Weckruf\\nExtension: 23" > /tmp/${UNIQUEID}.call) exten => _*77*XXXXXXXXXXXX,n,System(touch -t ${Jahr}${Monat}${Tag}${Stunden}${Minuten} /tmp/${UNIQUEID}.call) exten => _*77*XXXXXXXXXXXX,n,System(mv /tmp/${UNIQUEID}.call /var/spool/asterisk/outgoing/) exten => _*77*XXXXXXXXXXXX,n,Playback(rqsted-wakeup-for) exten => _*77*XXXXXXXXXXXX,n,SayNumber(${Stunden}) exten => _*77*XXXXXXXXXXXX,n,SayNumber(${Minuten}) exten => _*77*XXXXXXXXXXXX,n,Playback(digits/oclock) exten => _*77*XXXXXXXXXXXX,n,Hangup() [Weckruf] exten => 23,1,Answer() exten => 23,n,Wait(1) exten => 23,n,Playback(this-is-yr-wakeup-call) exten => 23,n,Wait(1) exten => 23,n,Hangup()
Das Manager-Interface aktiviert man, indem man in der
manager.conf
im Abschnitt [general]
den
Parameter enabled=yes
setzt.
Achtung | |
---|---|
Das sollte man nie auf einem Server mit öffentlichem Zugang machen, außer man schützt sich zusätzlich durch iptables, ipfw oder eine andere Firewall oder einen SSH-Tunnel! |
Ganz unten legen wir uns einen Benutzereintrag mit dem Namen
admin
an:
[admin] secret = geheim deny = 0.0.0.0/0.0.0.0 permit = 127.0.0.1/255.255.255.255 read = all,system,call,log,verbose,command,agent,user,config write = all,system,call,log,verbose,command,agent,user,config
Die
Optionen nach read
und write
geben an, für
welche Befehlsklassen wir dem User Rechte geben.[127]
Achtung | |
---|---|
Diese großzügige Rechtevergabe dient nur zum Testen! Mit dem
Recht |
Nach einem Restart von Asterisk können wir uns auf Port 5038 mit dem AMI verbinden, was wir auf der Shell mit telnet[128]ausprobieren:
$
telnet 127.0.0.1 5038
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Asterisk Call Manager/1.0
Man kann hier von Hand Befehle (die meist aus mehreren Zeilen bestehen) eintippen, z.B.:
Action: Login ActionID: 1 Username: admin Secret: geheim
Anmerkung | |
---|---|
Alle Befehls-Pakete werden durch zwei Returns abgeschlossen. |
Antwort:
Response: Success ActionID: 1 Message: Authentication accepted
Die primäre Verwendung liegt aber ganz klar im automatisierten Zugriff durch Skripte.
Anmerkung | |
---|---|
Die Manager-API ist nicht unbedingt dafür berühmt, viele gleichzeitige Verbindungen handhaben zu können (auch wenn sich das in der Version 1.4 stark verbessert hat). In so einer Last-Situation könnte man über den Einsatz eines speziellen Proxys wie den „Simple Asterisk Manager Proxy“[129] (ein Perl-Skript) nachdenken, der viele Verbindungen entgegennimmt und zu einer bündelt - für die zugreifenden Skripte völlig transparent. Für die folgenden „Spielereien“ ist das aber unnötig. |
Nach erfolgreicher Authentifizierung können in beiden Richtung
Pakete gesendet werden. Die Art des Pakets wird immer von der ersten Zeile
darin bestimmt. Der Client sendet Action
-Pakete, der Server
antwortet mit Response
oder kann auch von sich aus
Event
-Pakete schicken. Die Reihenfolge der Zeilen in einem
Paket ist ansonsten aber irrelevant. Zeilen werden durch CR LF[130] beendet, das ganze Paket durch ein weiteres CR LF.
Normalerweise sendet der Client in jeder Action
ein
ActionID
-Feld mit beliebigem, möglichst eindeutigem,
Inhalt[131], das der Server so in seine Response
übernimmt,
damit sich die Antworten bei Überschneidungen zuordnen lassen.
Der Server sendet Event
-Pakete, um den Client über
verschiedene Ereignisse zu informieren. Es gibt auch Ereignisse, die von
einer Action
des Clients ausgelöst werden. Dann sendet der
Server ein Response: Follows
gefolgt von den Events (die dann
ebenfalls die ActionID
beinhalten) und ein abschließendes
Event (normalerweise
Aktionsname
Complete).
Wenn Ihr Client keine Events benötigt, kann er direkt im ersten
Authentifizierungs-Paket den Parameter Events: off
senden, um
dann nur Antworten auf von ihm gesendete Actions zu erhalten.
Die Liste der verfügbaren Befehle erhält man im
CLI mit show manager commands
(bzw. manager show commands), Informationen über einen
Befehl mit show manager command
Befehlsname
(bzw. manager
show command Befehlsname
):
mos-eisley*CLI> manager show commands Action Privilege Synopsis ------ --------- -------- AbsoluteTimeout call,all Set Absolute Timeout AgentCallbackLo agent,all Sets an agent as logged in by callback AgentLogoff agent,all Sets an agent as no longer logged in Agents agent,all Lists agents and their status ChangeMonitor call,all Change monitoring filename of a channel Command command,all Execute Asterisk CLI Command DBGet system,all Get DB Entry DBPut system,all Put DB Entry Events <none> Control Event Flow ExtensionState call,all Check Extension Status GetConfig config,all Retrieve configuration Getvar call,all Gets a Channel Variable Hangup call,all Hangup Channel IAXnetstats <none> Show IAX Netstats IAXpeers <none> List IAX Peers ListCommands <none> List available manager commands Logoff <none> Logoff Manager MailboxCount call,all Check Mailbox Message Count MailboxStatus call,all Check Mailbox Monitor call,all Monitor a channel Originate call,all Originate Call Park call,all Park a channel ParkedCalls <none> List parked calls PauseMonitor call,all Pause monitoring of a channel Ping <none> Keepalive command PlayDTMF call,all Play DTMF signal on a specific channel. QueueAdd agent,all Add interface to queue. QueuePause agent,all Makes a queue member temporarily unavailable QueueRemove agent,all Remove interface from queue. Queues <none> Queues QueueStatus <none> Queue Status Redirect call,all Redirect (transfer) a call SetCDRUserField call,all Set the CDR UserField Setvar call,all Set Channel Variable SIPpeers system,all List SIP peers (text format) SIPshowpeer system,all Show SIP peer (text format) Status call,all Lists channel status StopMonitor call,all Stop monitoring a channel UnpauseMonitor call,all Unpause monitoring of a channel UpdateConfig config,all Update basic configuration UserEvent user,all Send an arbitrary event WaitEvent <none> Wait for an event to occur
Diese
Befehle sind fast immer gleichlautend mit einer entsprechenden
Dialplan-Applikation - neu ist vor allem die Action
Originate
, mit der man einen ausgehenden Anruf veranlassen
kann, und Command
, was einen Befehl direkt auf dem CLI
ausführt. Da wir unserem User admin
alle Rechte gegeben haben
(s.o.), darf er alle Befehle ausführen. Wie man einen Befehl benutzt,
erfährt man so:
mos-eisley*CLI> manager show command Command Action: Command Synopsis: Execute Asterisk CLI Command Privilege: command,a Description: Run a CLI command. Variables: (Names marked with * are required) *Command: Asterisk CLI command to run ActionID: Optional Action id for message matching.
Die von Asterisk verschickten Events sind bisher so gut wie undokumentiert. Auf http://www.voip-info.org/wiki/view/asterisk+manager+events findet sich eine zusammengestellte Liste mit spärlichen Hinweisen. Ein paar Erklärungen kann man auf http://asterisk-java.sourceforge.net/apidocs/net/sf/asterisk/manager/event/package-frame.html nachlesen[132].
Nehmen wir an, wir wollten über das Manager-Interface die Anzahl der Nachrichten in einer Voicemailbox abfragen. Diese einfache Aufgabe lässt sich leicht mit einem Skript für expect lösen.
Folgendes Expect-Skript verbindet sich mit dem AMI, loggt sich ein und gibt schließlich die Anzahl der neuen und alten Nachrichten in der angegebenen Mailbox aus:
#!/usr/bin/expect # # Aufruf: ./vmcount.exp 1234@default # der Benutzer-Zugang wie in manager.conf eingerichtet: set username "admin" set secret "geheim" set host "127.0.0.1" set port "5038" if {[llength $argv] != 1} { send_user "Fehler: Geben Sie eine Mailbox an!\n" exit 1 } # erstes Argument ist die abzufragende Mailbox: set mailbox [lindex $argv 0] send_user "Mailbox: $mailbox\n" # Durchschleifen von stdout zum User abschalten: log_user 0 # Verbindung zum AMI öffnen: spawn telnet $host $port # für den Fall, daß telnet abbricht weil keine Verbindung # hergestellt werden kann: expect_before eof { send_user "Fehler beim Verbinden.\n" exit 1 } # auf die Zeichenfolge "Manager" warten und bei Erfolg # ein Login-Paket senden: # expect "Manager" { send_user "Verbunden.\n" send "Action: Login\nUsername: $username\nSecret: $secret\n\n" # Beachten Sie, daß telnet Zeilenumbrüche (\n) automatisch # in CR LF (\r\n) umwandelt. Man darf hier also nicht \r\n # angeben. } # Login erfolgreich?: # expect { -re "Response:\\s*Error" { send_user "Login fehlgeschlagen.\n" exit 1 } -re "Response:\\s*Success" { send_user "Eingeloggt.\n" # Anzahl der Mailbox-Nachrichten abfragen: send "Action: MailboxCount\nMailbox: $mailbox\n\n" } } expect { -re "Response:\\s*Error" { send_user "Abfragen der Mailbox fehlgeschlagen.\n" exit 1 } -re "Response:\\s*Success" {} } expect { -re "NewMessages:\\s*(\[\\d]*)" { send_user "Neue Nachrichten: $expect_out(1,string)\n" } } expect { -re "OldMessages:\\s*(\[\\d]*)" { send_user "Alte Nachrichten: $expect_out(1,string)\n" } } # Ausloggen - nicht unbedingt nötig, aber sauber: send "Action: Logoff\n\n"
Wir speichern das Skript als vmcount.exp
und setzen es mit chmod a+x vmcount.exp auf
ausführbar.
Aufruf:
$ ./vmcount.exp 123@default Mailbox: 123@default Verbunden. Eingeloggt. Neue Nachrichten: 0 Alte Nachrichten: 0
Vorweg gesagt: Erwarten Sie nicht zu viel von diesem kleinen Exkurs. StarAstAPI ist noch verbesserungsfähig. :-)
Für das Manager-Interface gibt es mittlerweile mehr oder weniger gute APIs in verschiedenen Programmiersprachen (PHP, Perl, Python, Ruby etc.), die natürlich hier nicht alle getestet werden konnten[134]. Sollte die API für Ihre Lieblingssprache nicht laufen, können Sie das Problem sicher lösen - bis hierher haben sowieso nur Leute gelesen, die schon mal programmiert haben. :-)
Wir testen hier ganz kurz die StarAstAPI[135] in PHP, die ein PHP 5 voraussetzt[136], das mit --enable-sockets
kompiliert
wurde.[137] Leider findet man in den StarAstAPI-Dateien noch die seit
Jahren veralteten „short open tags“ (<?
),
ersetzen Sie diese ggf. durch die korrekte Syntax
(<?php
). Der API liegen 4 Demo-Skripte bei:
sLogin.php
versucht nur, sich einzuloggen[138], sCommand.php
führt den CLI-Befehl
reload
aus, sDial.php
versucht eine
Verbindung mit SIP/120 und sEvents.php
empfängt
Events. Wenn wir gleichzeitig mit asterisk -vvvr die
CLI beobachten und mit php -q sLogin.php eine
Verbindung zum AMI öffnen[139], sehen wir im CLI:
mos-eisley*CLI> == Parsing '/etc/asterisk/manager.conf': Found [Jan 26 20:08:09] NOTICE[10352]: manager.c:961 authenticate: 127.0.0.1 tried to authenticate with nonexistent user 'mark' == Connect attempt from '127.0.0.1' unable to authenticate mos-eisley*CLI>
Es hat also wegen des falschen Users nicht funktioniert, trotzdem meldet das Demo-Skript:
$ php -q sLogin.php Login Sucessful
und danach das Response-Paket:
Response: Error ActionID: 1 Message: Authentication failed
StarAstAPI arbeitet also nicht ganz sauber, kann aber sicher ohne allzu großen Aufwand verbessert werden. Wenn wir php -q sEvents.php aufrufen - jetzt mit dem richtigen User - sehen wir im CLI:
mos-eisley*CLI> == Parsing '/etc/asterisk/manager.conf': Found == Manager 'admin' logged on from 127.0.0.1 mos-eisley*CLI>
Testhalber führen wir im CLI ein
reload
aus, was sich in diesen Events in der Ausgabe des
PHP-Skripts widerspiegelt:
Event: Reload Privilege: system,all Message: Reload Requested Event: ChannelReload Privilege: system,all Channel: SIP ReloadReason: RELOAD (Channel module reload) Registry_Count: 0 Peer_Count: 0 User_Count: 0
Lassen Sie sich was einfallen! Schreiben Sie ein kleines Skript, das all Ihre Freunde anruft - natürlich mitten in der Nacht!
So könnten wir das Beispiel aus „Beispiel: Anzahl der Mailbox-Nachrichten mit Expect abfragen“ in PHP mit der StarAstAPI lösen:
#!/usr/bin/php -q <?php # der Parameter -q dient dazu, bei einem CGI-PHP die Ausgabe der # Header abzuschalten if ($argc != 2) { echo "Fehler: Geben Sie eine Mailbox an!\n"; exit(1); } # das erste Argument nach dem Programmnamen ist die Mailbox: $mailbox = $argv[1]; echo "Mailbox: $mailbox\n\n"; # StarAstAPI einbinden: require_once './StarAstAPI/StarAstAPI.php'; # verbinden und einloggen: # $ami = new AstClientConnection(); if ($ami->Login( 'admin', 'geheim', '127.0.0.1', 5038 )) { $rp = $ami->GetResponse('1'); //echo $rp->ToString(); } else { exit(1); } # folgendes Paket senden: # Action: MailboxCount # Mailbox: $mailbox # ActionID: 2 # $data = new AstPacketData; $data->AddKVPair( 'Action' , 'MailboxCount' ); $data->AddKVPair( 'Mailbox' , $mailbox ); $data->AddKVPair( 'ActionID', '2' ); $packet = new AstPacket; $packet->SetAstPacketType( 'Action' ); $packet->SetAstPacketData( $data ); $ami->SendPacket( $packet ); # Antwort-Paket mit ActionID 2 lesen: # $rPacket = $ami->GetResponse('2'); //echo $rp->ToString(); $rData = $rPacket->GetAstPacketData(); $r = $rData->GetAll(); echo "Neue Nachrichten: ", (int)trim($r['NewMessages:']), "\n"; echo "Alte Nachrichten: ", (int)trim($r['OldMessages:']), "\n"; echo "\n"; # Ausloggen - nicht unbedingt nötig, aber sauber: # $ami->Logoff(); # allerdings ist die Funktion der StarAstAPI nicht gerade schön. # sie tut dies: #echo "Logoff Called from somewhere ..."; #socket_close($this->mSocket); echo "\n"; ?>
Wir speichern das Skript als
vmcount.php
und setzen es mit chmod a+x
vmcount.exp auf ausführbar.
Aufruf:
$ ./vmcount.php 123@default Mailbox: 123123123 Neue Nachrichten: 0 Alte Nachrichten: 0 Logoff Called from somewhere ...
Seit Version 1.4 bringt Asterisk einen kleinen Webserver mit, AJAM genannt, über den man per HTTP auf das Asterisk Manager Interface (AMI) zugreifen kann. Die Bezeichnung „AJAM“ ist eindeutig von „AJAX“[140] (Asynchronous JavaScript and XML) abgeleitet.
Zur Einrichtung sind die Schritte wie in Abschnitt 3, „Das Manager-Interface (AMI)“ Voraussetzung, zusätzlich stellt man in
der manager.conf
im Abschnitt [general]
den Parameter webenabled
auf yes
ein. Beachten
Sie auch den Parameter httptimeout
, der festlegt, nach
welcher Inaktivität (in Sekunden) man im Web-Interface automatisch
ausgeloggt wird. Um dann den Webserver zu aktivieren, setzt man in der
http.conf
folgende Einstellungen:
[general] enabled=yes enablestatic=yes bindaddr=127.0.0.1 bindport=8088 prefix=asterisk
enablestatic
muss man nur dann
aktivieren, wenn der AJAM auch als Webserver für statische Dateien im
Verzeichnis /var/lib/asterisk/static-http/
fungieren
soll. Normalerweise stellt man das auf no
, es ist aber
Voraussetzung für die Asterisk-AJAM-Demo („AJAM Demo“).
Restart nicht vergessen!
Achtung | |
---|---|
Nach meiner Einschätzung ist es in den seltensten Fällen
empfehlenswert, andere Web-Applikationen, also solche, die
ausschließlich für den Administrator zugänglich sind, direkt auf die
AJAM-Schnittstelle zugreifen zu lassen, und das ist wohl auch nicht so
gedacht, denn dazu lassen sich die Rechte mit |
Wir betrachten wieder die aus „Beispiel: Anzahl der Mailbox-Nachrichten mit Expect abfragen“ und „Beispiel: Anzahl der Mailbox-Nachrichten mit PHP abfragen“ bekannte einfache Aufgabe, also die Anzahl der Nachrichten auf einer Mailbox abzufragen. Der AJAM bietet hier folgende Möglichkeiten:
Unter der URL
http://localhost:8088/asterisk/manager
wartet das Manager-Interface auf unsere Anfragen. Dabei werden die Felder eines Pakets als Parameter an die URL gehängt. Probieren Sie die folgenden beiden Adressen im Webbrowser aus:
http://localhost:8088/asterisk/manager?action=Login&username=admin&secret=geheim
http://localhost:8088/asterisk/manager?action=MailboxCount&mailbox=123
Die Antwort erfolgt jeweils als HTML-Seite, ist also für den Zugriff durch Skripte denkbar ungeeignet.
Man kann in der URL manager
durch
rawman
ersetzen, dann erfolgt die Antwort als Plain-Text.
Zum Einloggen und Abfragen der Mailbox-Nachrichten
also:
http://localhost:8088/asterisk/rawman?action=Login&username=admin&secret=geheim
Response: Success Message: Authentication accepted
http://localhost:8088/asterisk/rawman?action=MailboxCount&mailbox=123
Response: Success Message: Mailbox Message Count Mailbox: 123 NewMessages: 0 OldMessages: 0
http://localhost:8088/asterisk/rawman?action=Logoff
Response: Goodbye Message: Thanks for all the fish.
Diese Text-Ausgabe kann man also gut in automatisierten Skripten verwenden.
Will man stattdessen lieber XML, dann ruft man mxml
auf. Die XML-Ausgabe ist hier zur leichteren Lesbarkeit formatiert
dargestellt, der AJAM macht keine Zeilenumbrüche innerhalb der Tags.
Einen korrekten XML-Parser würde das aber auch so wie hier dargestellt
nicht stören.
http://localhost:8088/asterisk/mxml?action=Login&username=admin&secret=geheim
<ajax-response> <response type='object' id='unknown'> <generic response='Success' message='Authentication accepted' /> </response> </ajax-response>
http://localhost:8088/asterisk/mxml?action=MailboxCount&mailbox=123
<ajax-response> <response type='object' id='unknown'> <generic response='Success' message='Mailbox Message Count' mailbox='123' newmessages='0' oldmessages='0' /> </response> </ajax-response>
http://localhost:8088/asterisk/mxml?action=Logoff
<ajax-response> <response type='object' id='unknown'> <generic response='Goodbye' message='Thanks for all the fish.' /> </response> </ajax-response>
Bei AJAX-Anwendungen - das erkennt man leicht am Namen
„Asynchronous JavaScript and XML“ - ist XML das übliche
Format, obwohl es wegen seiner aufgeblähten Struktur vielfach
kritisiert wird. Für AJAX können aber auch andere Formate wie
JSON[141] zum Einsatz kommen. JSON (JavaScript Object Notation)
ist - der Name verrät es - besonders gut für JavaScript-Anwendungen
geeignet, da die Datenstruktur hier nativ mit eval()
in
ein Objekt umgewandelt werden kann und wenig Overhead hat. Es
existieren aber auch zahlreiche Implementierungen für PHP, Perl etc.
Eine Ausgabe in JSON fehlt dem AJAM bisher jedoch leider. Man könnte
aber beispielsweise die Plain-Text-Ausgabe clientseitig in JSON
umwandeln, wenn einem das leichter fällt oder wenn es sich besser in
vorhandene JS-Libs inegrieren lässt. Hier der Ansatz als
Idee:
// angenommen in responseText ist der empfangene Antwort-Text // gespeichert, was wir hier nur simulieren: var responseText = 'Response: Success\n' +'Message: Mailbox Message Count\n' +'Mailbox: 123\n' +'NewMessages: 0\n' +'OldMessages: 0\n'; // einfache Anführungszeichen escapen: responseText = responseText.replace( /\'/g, "\\'" ); // Felder quoten: responseText = responseText.replace( /^([a-z\d]*):\s*(.*)/gmi, "'$1':'$2'," ); // in Objekt umwandeln: eval('var packet = {'+ responseText +'}'); // jetzt kann man wie bei jedem Objekt so auf die Felder zugreifen: alert( packet['NewMessages'] ); // gibt "0" aus
Für Zugriffe von AJAX-Anwendungen auf den AJAM ist der Ping-Befehl besonders hilfreich, der dazu dient, die Verbindung und Authentifizierung offenzuhalten.
http://localhost:8088/asterisk/rawman?action=Ping
Response: Pong
Unter der URL
http://localhost:8088/asterisk/static/ajamdemo.html
ist
eine kleine Beispiel-Anwendung mitgeliefert, die den Zugriff per AJAX
demonstriert. Sie verwendet die äußerst praktische JavaScript-Library
Prototype[142] für die AJAX-Zugriffe und zeigt mit der Action
Status
die momentan aktiven Kanäle an. Sie können die
AJAM-Demo als Basis für eigene AJAX-Anwendungen heranziehen.
Der Webserver von Asterisk ist sehr minimalistisch und ersetzt
keinesfalls einen „richtigen“ Server wie den Apache, der
auch PHP-Skripte ausführt etc. Um beides zu vereinen, könnte man z.B.
in der httpd.conf
des Apache an der
entsprechenden Stelle den Eintrag
ProxyPass /ajam http://localhost:8088/asterisk
verwenden,
um für alle Zugriffe auf den URL-Pfad /ajam
nur als Proxy
zu fungieren und die Anfragen zum AJAM durchzuschleusen.
[127] Welche Rechte-Klassen man zum Ausführen eines Befehls haben muss, erfährt man im CLI mit show manager commands bzw. manager show commands.
[128] Hier kommt nur das Tool telnet zum Einsatz. Das hat nichts mit dem Telnet-Protokoll oder Port zu tun.
[130] Carriage Return (ASCII 13 dezimal) und Line Feed (ASCII 10 dezimal)
[131] Hier bietet sich etwa der Name des Skripts, ein Timestamp und
eine fortlaufende Nummer für jede Action an, z.B.
testskript.php-1169405408-1.
[132] Nicht verwirren lassen, das ist eigentlich eine Java-Dokumentation.
[134] Beispiele mit Anmerkungen auf http://www.voip-info.org/wiki/view/Asterisk+manager+Examples
[136] Die API lässt sich aber relativ leicht auf PHP 4 umschreiben, obwohl der Code recht unübersichtlich und schlecht formatiert ist. Im Zweifelsfall einfach immer die Parse-Errors beheben. :-)
[137] Auf der Shell erfährt man mit php -m, welche Module einkompiliert sind.
[138] Wenn Sie nach der Anleitung oben vorgegangen sind, müssen Sie natürlich jeweils den Benutzernamen und das Passwort entsprechend anpassen.
[139] Hier absichtlich mit falschem User/Passwort.
Version 1.2, November 2002
Neue Version verfügbar
Sie betrachten gerade die alte Version des Buches (Version 1.0). Wir empfehlen Ihnen für Asterisk 1.4 und 1.6 die neue Version des Buches.
Asterisk-Tag 2008
Lernen Sie Mark Spencer (den Erfinder von Asterisk) kennen! Viele Vorträge, Case-Studies und Workshops rund um das Thema VoIP. Asterisk-Tag.org