Beispiele in verschiedenen Programmiersprachen

Ein AGI-Skript ist ein gewöhnliches ausführbares Programm, das Asterisk aus dem Dialplan heraus startet, per stdin/stdout mit ihm spricht und sich beim Beenden wieder abmeldet. Es ist fast egal, welche Programmiersprache Sie dafür benutzen — hier ein paar pragmatische Beispiele.

Das Skript wird aus der extensions.conf heraus aufgerufen:

exten => 1234,1,Answer()
 same => n,AGI(mein-skript.sh)
 same => n,Hangup()

Asterisk sucht AGI-Skripte in /var/lib/asterisk/agi-bin/. Die Datei muss dem Asterisk-User lesbar und ausführbar sein.

Bash

Für einfache Aufgaben ist Bash völlig ausreichend — das AGI-Protokoll ist zeilenbasiertes ASCII.

#!/bin/bash
# /var/lib/asterisk/agi-bin/hello.sh

# Variablen vom Kanal einlesen (die Asterisk vor dem ersten Kommando schickt)
while read line && [ -n "$line" ]; do
    case "$line" in
        agi_callerid:*) CALLERID="${line#*: }" ;;
    esac
done

# Ein Kommando senden
echo "EXEC Playback hello-world"
read answer

# Eine Variable setzen
echo "SET VARIABLE AUFRUFER $CALLERID"
read answer

exit 0

Python

Für mehr als ein paar Zeilen ist Python angenehmer. Es gibt mehrere AGI-Wrapper; hier ein Minimal-Beispiel ohne Abhängigkeit:

#!/usr/bin/env python3
# /var/lib/asterisk/agi-bin/hello.py

import sys

# Initial-Variablen lesen
vars = {}
while True:
    line = sys.stdin.readline().strip()
    if not line:
        break
    key, _, value = line.partition(":")
    vars[key.strip()] = value.strip()

def agi(cmd):
    print(cmd, flush=True)
    return sys.stdin.readline().strip()

agi('VERBOSE "Hallo aus Python!" 3')
agi('STREAM FILE hello-world ""')
agi('SET VARIABLE PY_DONE 1')

Für größere Projekte lohnt sich die Bibliothek pyst2 oder asterisk-agi-python.

Node.js

// /var/lib/asterisk/agi-bin/hello.js
// npm install agi-node
const { Runner } = require('agi-node');
const runner = new Runner();

runner.addContext('default', async (channel) => {
  await channel.streamFile('hello-world');
  await channel.setVariable('NODE_DONE', '1');
});

runner.start(3000);

Der Node-Handler läuft als FastAGI-Server — das heißt, Asterisk öffnet eine TCP-Verbindung zu Ihrem Service statt pro Anruf einen neuen Prozess zu starten. Im Dialplan:

exten => 1234,1,AGI(agi://127.0.0.1:3000/default)

FastAGI ist für produktive Anwendungen fast immer die bessere Wahl: kein Process-Fork pro Anruf, keine Kaltstart-Latenz.

Andere Programmiersprachen

Für so gut wie jede Sprache existiert ein AGI-Wrapper:

  • Rubyruby-agi, historisch auch Adhearsion (auch wenn letzteres als Framework kaum noch aktiv gepflegt wird).

  • PHPphpagi (https://github.com/welltime/phpagi), war lange Zeit populär, ist aber eher historisch.

  • Goagi-go (https://github.com/zaf/agi).

  • PerlAsterisk::AGI (CPAN); zum Historisieren in vielen alten Installationen noch im Einsatz.

Für komplexere externe Logik empfehlen wir heute allerdings den Umstieg auf ARI: asynchrone Event-Verarbeitung, HTTP/REST-API, WebSocket, viele gleichzeitige Calls pro Prozess.