Dial Option M

P.Hoffmann

Neuer User
Mitglied seit
1 Feb 2009
Beiträge
179
Punkte für Reaktionen
0
Punkte
0
Hallo,

sobald eine Verbindung -hergestellt durch Dial - besteht, soll der Macro XY aufgerufen werden. Das klappt auch ohne Probleme. Leider bleibt bei dem Telefon welches irgendwo anruft der Channel die ganze Zeit unbeantwortet, auch wenn die Verbindung schon besteht bzw. der Anruf auf der anderen Seite angenommen wurde.

Der Macro selbst beinhaltet einen Aufruf zu einem AGI-Script.

Das Problem besteht darin, dass der AGI Script so lange läuft, wie das Gespräch selbst. Asterisk wartet aber leider erst, bis der Script durch ist.

Auch eine Ausführung mit Dial funktioniert nicht. Beispiel:

exten => 100,1,Dial(SIP/100&Local/s@xy)

[xy]
exten => s,1,agi(xy.php)

Hier läuft aber der Script aber nur in der Klingelzeit. Er soll aber NUR während des Gesprächs laufen.
Hat jemand einen Tipp?
 
Zuletzt bearbeitet:
Ich verstehe noch nicht richtig:

Du startest ein AGI-Skript:
Variante 1: aus einem Makro heraus (Dial-Option M).
Variante 2: aus einem anderen Kontext heraus ([xy]).

Problem ist immer, dass Asterisk erst weitermacht, wenn das Skript fertig ist.

Was ist denn der Soll-Zustand? Das AGI-Skript soll während des Gesprächs - und zwar nur während des Gesprächs - laufen? Möglicherweise bist Du dann mit einem system-Aufruf, der das Skript in den Hintergrund schickt, besser bedient. Halt: wie bekommt dann das Skript das Gesprächsende mit? Ein zweiter Gedanke:

Mittlerweile bin ich soweit, dass ich schon sehr deutlich für eine Art universeller "Middleware" plädiere, wie foschi sie schonmal hier skizziert hat. Damit fängst Du z.B. Anfang und Ende eines Gesprächs außerhalb des Asterisk ab und machst beliebige System-Aktionen: Skripte, Nachrichte usw. usf. Diese "Middleware" zu schreiben ist aber Knochenarbeit.

Nebenfrage: was soll denn Dein Skript tun? Die Gesprächskosten anzeigen? - reine Neugier.
 
Hallo anhalter42,

Ich verstehe noch nicht richtig:

Du startest ein AGI-Skript:
Variante 1: aus einem Makro heraus (Dial-Option M).
Variante 2: aus einem anderen Kontext heraus ([xy]).

1. AGI Script "dial.php" wird gestartet
2. AGI Script "dial.php" ruft Dial mit Optiom M für den Macro auf
3. Im Macro wird "Abrechnung.php" gestartet. Alle 60 Sekunden wird ein Eintrag in der Datenbank gemacht. Es wird z.B. bei einem Festnetz Gespräch -1ct vom Guthaben abgezogen.

Was ist denn der Soll-Zustand? Das AGI-Skript soll während des Gesprächs - und zwar nur während des Gesprächs - laufen? Möglicherweise bist Du dann mit einem system-Aufruf, der das Skript in den Hintergrund schickt, besser bedient.
Der AGI-Script soll starten sobald auf der anderen Seite das Gespräch angenommen wurde und stoppen wenn der Kanel aufgelegt wird.
An system() habe ich auch schon gedacht.

Halt: wie bekommt dann das Skript das Gesprächsende mit?
Gibt es in Asterisk eine Möglichkeit die Prozess-ID des durch System() gestarteten Scripts abzurufen? Diese schreib man sich in eine Variable und führt am Ende des Gesprächs, also nach AGI(dial.php), System(kill ...) aus.

...
Nebenfrage: was soll denn Dein Skript tun? Die Gesprächskosten anzeigen? - reine Neugier.

Siehe oben (Guthaben Abrechnung).
 
Gibt es in Asterisk eine Möglichkeit die Prozess-ID des durch System() gestarteten Scripts abzurufen? Diese schreib man sich in eine Variable und führt am Ende des Gesprächs, also nach AGI(dial.php), System(kill ...) aus.

Jein.

Der Trick, der mir dazu einfällt, wäre in etwa wie folgt:

Du rufst ein AGI über system auf und schickst es in den Hintergrund (siehe anhalter42). Dieses AGI stellt seine eigene ProzessID fest (entsprechend AGI-Sprache) und schreibt diese in ein File (das für Asterisk lesbar ist). Dieses File bekommt als Filenamen die Channel-ID oder aber die UNIQU_ID des CDR (in jedem Fall irgendetwas, was einen eindeutigen Bezug zum Asterisk-CallChannel herstellt).

Das Skript läuft jetzt vor sich hin und tut, was Du willst.

Wird jetzt der Call beendet, springst Du in die h-Extension (damit das immer klappt, den Dial-Befehl ggf. mit Option g ausstatten)
Dort startest Du wieder ein AGI bzw. einen system-Call. Gegenstand ist hier: Lies das CHANNEL- bzw. UNIQUEID-Skript und kille den Prozess, dessen ID sich darin befindet.

Das ist nicht besonders elegant, könnte aber theoretisch funktionieren.

Die andere Alternative hat anhalter42 angerissen - Eine Middleware, die letztlich über Manager-Events getriggert wird und abhängig vom Event bestimmte Transaktionen ausführt. Auf diesem Prinzip basiert zum Beispiel das Flash Operator Panel. So etwas zu bauen ist aber dann wirklich nicht trivial.
 
Die andere Alternative hat anhalter42 angerissen - Eine Middleware, die letztlich über Manager-Events getriggert wird und abhängig vom Event bestimmte Transaktionen ausführt. Auf diesem Prinzip basiert zum Beispiel das Flash Operator Panel. So etwas zu bauen ist aber dann wirklich nicht trivial.

Kannst du mir ein Beispiel, geschrieben in PHP hierzu schicken?

Ich habe selbst noch keine Erfahrung mit dem Asterisk Manager.

Eine Überlegung von mir wäre, das vor jeder Abrechnung bzw. vor jedem Datenbank Eintrag des Scripts geprüft wird, ob der Channel noch verfügbar ist.
Der Channel-Name selbst wird als Argument mit übergeben.

Code:
<?php

function Channel($id)
{
// Prüfen ob Channel $id noch verfügbar ist, wenn ja 'true' zurückgeben
}

while(true)
{
   if(Channel($argv[1])))
   {
      //Datenbank Eintrag
   }
   else
   {
      break;
   }
}
?>
 
Zuletzt bearbeitet:
Du warst zu schnell. Für die Überwachung über Events hab' ich keine Idee, das steht erst irgendwann in unbestimmter Zukunft auf der ToDo-List.

Aber: Alternative Idee zu Deinem fachlichen Problem:

Wenn es um Prepaid-Billing geht und wir mal kurz unterstellen, dass immer der Tarif gelten soll, der zu Gesprächsbeginn galt (also keine Tarifumschaltung innerhalb eines Gesprächs), dann kann man das auch ohne "mitlaufendes" AGI lösen, wenn man darauf verzichten kann, das Guthaben "during call" aktuell zu halten, d.h. der Update in der DB erfolgt erst nach Call-Hangup auf Basis der billsecs. Folgendes Prinzip:

1. Ermittle aktuellen Guthabenstand des Teilnehmers
2. Ermittle Preis je Takt und Taktung für das Anrufziel
3. Ermittle aus 1 und 2 die maximale Anrufdauer bis zu einem Guthabenstand von 0 (oder einem beliebig anderen positiven Betrag) in Millisekunden
4. Dial mit Option L(<Ergebnis aus 3.>).

Damit erreichst Du, dass keiner länger telefonieren kann, als er Guthaben hat und das ganze ohne ein mitlaufendes AGI. Beim Schreiben des CDRs (entweder über Trigger in der DB oder per AGI in der h-Extension) machst Du dann ein Guthabenupdate.
Die L-Option hat noch ein paar mehr Parameter, die Du optional verwenden kannst.

Vielleicht löst das ja schon Dein fachliches Problem. Eine Middlewarelösung ist wie gesagt recht elegent (selbst Tarifumschaltung im Gespräch ginge), aber ich fürchte, das wird keiner einfach so irgendwo liegen haben, es sei denn foschi hat da erfolgreich etwas gebaut und kann & will es zur Verfügung stellen.
 
Der Benutzer hat aber evtl. mehrere Channel gleichzeitig offen. Mehrere Verbindungen bestehen gleichzeitig. Von daher muss das Guthaben immer aktuell gehalten werden über einen Script welcher auch bei Bedarf sofort mit einem Hangup() einwirken kann.

Edit:
Anscheinend gibt es für das Abfragen von Channels im Asterisk Manager keinen Befehl.
Code:
*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

Als Dial-Plan Application gibt es aber ChanIsAvail(). Evtl. könnte man sich eine Funktion bauen, welche ChanIsAvail irgendwie über ein Call-File aufruft ........ Das ist aber auch nicht sehr elegant.
 
Zuletzt bearbeitet:
Shit, dann brauchst Du das ganze natürlich Realtime und "during call", mein Vorschlag klappt nur bei einem Sprachkanal.

Wie gesagt, Du kannst die "Frickellösung" ausprobieren, ansonsten kannst Du nur versuchen, Dich durch den Code z.B. von Flash Operator Panel zu qälen und zu schauen, wie da die AMI-Events abgegriffen werden. Dem Channel dann ggf. ein Hangup zu senden, ist dabei denke ich die einfachste Übung.
Du brauchst ja dann zudem eine Variante, die einerseits in einer Zeitschleife arbeitet und einmal je Charging-Intervall (Takt) ein Update ausführt, andererseits musst Du auf Channel-Events reagieren (Hangup) und Du musst gleichzeitig alle Verbindungen eines Kunden tracken um ggf. alle Channel zu terminieren. (Das würde auch der Frickelvorschlag so nicht ohne weiteres leisten)
Wenn Du dann noch Warnungen einspielen willst (so nach dem Motto: Sie haben noch 15 Sekunden Gesprächszeit), wird es noch aufwändiger.

Lange Rede, kurzer Sinn: Dafür hab' ich out of the box nicht wirklich eine funktionierende Idee, das ist dann schon ein richtiges Projekt, das wir hier aufmachen können, wenn sich genug Sponsoren finden ...

Edit:
Mit einer Middleware würdest Du vom AMI Events geschickt bekommen für die im Asterisk ablaufenden Aktionen. Dial und Hangup senden auch solche Events mitsamt den Variablen dazu (wie Channel). Du selbst kannst dann Kommandos absetzen (siehe Deine Liste), also unter anderem auch Hangup.
 
Das klingt doch wieder ganz anders. Das würde ich evtl. so angehen:

Das Ganze sollte datenbankbasiert laufen: bei Gesprächsbeginn machst Du einen Eintrag mit Zeitstempel in eine Datenbank (wer? channelid? startzeit?).
Bei Gepsrächsende löschst Du diesen Eintrag wieder.

In einer anderen Tabelle hast Du die Guthaben: wer? wieviel?. Auf Deinem System läuft ständig ein Prozess, der nachsieht, ob noch Guthaben da ist. Wenn nix mehr da ist, löst er mittels `asterisk -rx 'Hangup'` (oder so ähnlich, musst Du mal probieren) das sofortige Hangup für alle bestehenden Channels des Nutzers aus.

Im Wählplan setzt Du also lediglich Zeitstempel oder löschst sie. Der Rest passiert außenrum und greift nur bei Bedarf - wenn auch zugegebenermaßen recht hart - ein.
 
@anhalter42

Das könnte so gehen, wenn man jedem Channel die Ratinggrößen mitgibt.

Sobald dann Calls eingetragen sind, geht ein Serverprozess hin und "überwacht die Einträge", wobei in dem entsprechenden Billingintervall (je Channel) das Gesamtguthaben aktualisiert wird. Erreicht das 0, werden alle Channels des Nutzers getrennt (wie vorgeschlagen oder über AMI-Event).
 
@anhalter42:

Angenommen, der Benutzer startet 10 Gespräche gleichzeitig. Diese Laufen doch dann solange wie er möchte, oder? Erst nach dem Gespräch erfolgt ja die Abrechnung. Genau das soll ja verhindert werden. Bitte endschultige wenn ich was falsch verstanden habe.

Edit:
Sei denn, man setzt ein Limit. Aber das ist ja auch nicht die "beste" Lösung.

@abw1oim:

Im Prinzip brauchen wir nur eine Lösung, welche nachschaut auf Channel XY noch verhanden ist. Natürlich eine, welche außerhalb eines AGI-Scripts aufgerufen werden kann. Bei System() ist die Kooperation nicht mehr da.
 
Bitte diesen Beitrag löschen, habe versehentlich zweimal auf Speichern geklickt.
 
@P.Hoffmann

siehe mein letztes Post. Der Gedanke von anhalter42 ist durchaus für Dein Szenario machbar auch bei n Gesprächen gleichzeitig. Es geht ja darum, dass ein entsprechender Serverprozess alle Einträge überwacht und im entsprechenden Intervall das Guthaben aktualisiert und bei 0 dann eben alle Channels, die zum Account gehören, terminiert. Das sollte machbar sein, das einzige, was Du bauen müsstest, wäre ein Serverprozess, der die Einträge überwacht und je Eintrag einen Timer (= Billingintervall) aufsetzt, der dann halt nach jedem Timerintervall ein Update des Guthabeens macht und ggf. (dann aber alle Channel des Teilnehmers) terminiert.
 
Auf Deinem System läuft ständig ein Prozess, der nachsieht, ob noch Guthaben da ist. Wenn nix mehr da ist, löst er mittels `asterisk -rx 'Hangup'` (oder so ähnlich, musst Du mal probieren) das sofortige Hangup für alle bestehenden Channels des Nutzers aus.

... und wie braucht man das Guthaben auf? Welches Script rechnet z.B. je Minute immer 1ct minus? Auch dieser ?
 
So, ich habe das Problem jetzt mit dem System()-Befehl gelößt.
Allerdings wird die PID durch 'Abrechnung-Start.php' von 'Abrechnung.php' per AGI in eine Asterisk Variable geschrieben, und nicht in eine Datei.
Zum Ende des Gespräches führt Asterisk System(kill ${PID}) aus. Diese Lösung funktioniert wunderbar und ist Sekunden genau, auch bei unterschiedlichen Taktungen.
Falls das Guthaben aufgebraucht ist, wird ein SoftHangup() eingesetzt.
 
Zuletzt bearbeitet:
Kostenlos!

Statistik des Forums

Themen
248,854
Beiträge
2,302,939
Mitglieder
378,504
Neuestes Mitglied
Hallo61Hallo