.titleBar { margin-bottom: 5px!important; }

[Frage] SIP-Peer rausfinden, welcher ein gespräch angenommen hat?

Dieses Thema im Forum "Asterisk Skripte" wurde erstellt von Nizzmo, 12 Okt. 2011.

  1. Nizzmo

    Nizzmo Neuer User

    Registriert seit:
    26 Nov. 2006
    Beiträge:
    36
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    hallo,

    ist es irgendwie (auf einfachem weg) möglich, den sip peer rauszufinden, welcher ein gespräch angenommen hat? es geht darum wenn mehrere telefone gleichzeitig klingeln, dass ich gerne wissen möchte wer des telefonat angenommen hat, um diesem user spezielle infos zukommen zu lassen.
    theoretisch würde es über ein grep-script, welches die asterisk-logfiles auswertetet funktionieren, aber das ist natürlich eine unschöne und performance-lastige lösung, welche ich ungern verwenden würde.

    grüße,
    markus
     
  2. ViennaAustria

    ViennaAustria Neuer User

    Registriert seit:
    11 Okt. 2005
    Beiträge:
    177
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Ort:
    Wien
    Wann willst Du diese Information haben?

    • noch Während des Gesprächs bzw. beim Abheben? Das ist saukompliziert!
    • oder irgendwann nachher für Statistiken? Dafür ist grep/awk/Datenbank/... ein wirklich gutes Werkzeug. Einfach die CDRs auswerten (als Textfile oder mittels Datenbank).
    Für live Informationen musst Du zwei Fälle berücksichtigen:

    1. wie findet man heraus, welcher Teilnehmer bei einem mehrfach-Dial abgehoben hat? Also Dial(SIP/11&SIP/12&SIP/13&SIP/provider/0664...)
    2. wie findet man heraus, dass möglicherweise gar keiner der angerufenen Teilnehmer abgehoben hat, sondern sich jemand anderer das Gespräch mit *8 bzw. Pickup() geholt hat?
    Für beides habe ich mir was durch-überlegt, was tatsächlich auch funktioniert. Es ist aber "ne Wissenschaft". Vor allem ärgert mich, dass es doch nicht sooo kompliziert sein müsste. Ich fürchte, mit fehlt hier das nötige Wissen für eine elegante und einfache Lösung.

    Wenn hier Asterisk-Gurus mitlesen, würde ich das sehr gerne gemeinsam durch-diskutieren.
     
  3. Nizzmo

    Nizzmo Neuer User

    Registriert seit:
    26 Nov. 2006
    Beiträge:
    36
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    du sprichst genau des an, was ich mir auch schon seit ein paar tage überlege und leider bisher keine lösung gefunden habe...

    ich möchte die lösung während des gesprächs haben!

    mein ziel ist folgendes:
    kunde ruft an und ich gleiche die nummer mit unserem crm ab. falls es die nummer in unserem crm gibt, bekommt der mitarbeiter der das gespräch angenommen hat eine xmpp-message mit dem firmennamen und einem link zum crm, wo er sofort auf die kundendaten zurückgreifen kann.

    dieses kleine projekt hab ich an einen azubi (fiae) abgegeben, welcher das als sein ihk-abschluss-projekt verwenden will. nur bei der jetzigen problemstellung gehen mir lösungsvorschläge aus. also wenn man irgendwas "drum-herum" programmieren muss, dass es funktioniert sollte des für ihn auch kein problem darstellen, mir reicht der richtige ansatz :)
     
  4. ViennaAustria

    ViennaAustria Neuer User

    Registriert seit:
    11 Okt. 2005
    Beiträge:
    177
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Ort:
    Wien
    Also ich hab in meinen gesendeten e-Mails gekramt und August 2008 tatsächlich dasjenige gefunden, in dem ich meine diesbezüglichen Erkenntnisse an die Kollegen geschickt habe. Das betrifft also Asterisk 1.4. Schauen wir mal, ob wir diese 3 Jahre alte Info gemeinsam verstehen können... :)

    Es ging darum, wass wir in unserem alten ISDN IVR System mittels Jabber Statusmeldungen verschickt haben, um den Kollegen zu sagen

    1. wer ruft gerade an?
    2. wer hat sich das Gespräch geholt?
    3. das Gespräch wurde gerade beendet
    Das mussten wir auf Asterisk abbilden und ich weiss noch, dass es viiiiel Bastelei badurfte, das zu realisieren (in unserem ISDN IVR System war das alles trivial).



    ----- Schnipp -----



    Hallo!

    Ich habe es geschafft, alle Statusänderungen eines Calls in einem Asterisk IVR System in Echtzeit zu erfassen; also

    • WANN ein Gespräch reinkommt
    • WANN WER dieses Gespräch entgegengenommen hat
    • WANN WER wieder aufgelegt hat
    Die Meldung eingehender Calls ist trivial: "just call JabberPhone", wenn das IVR System anstartet.

    Die abgehoben/aufgelegt Meldungen sind kitzlig, zumal der Dialplan verstirbt, wenn der Anrufer zuerst auflegt! Legt im Gegensatz der Angerufene zuerst auf, könnte man dies ja noch durch weitere Arbeitsschritte erfassen, wenn man das Dial Kommando entsprechend präpariert...

    Ich habe mir also das Konzept unserer 105500x Umleitungen zugrundegelegt und verwende als gemeinsame Wissensdatenbank statt Postgres die Asterisk DB, weil man die aus AEL und AGI direkt und schnell bedienen kann.

    Geht ein Call an mehrere Apparate (z.B. Ringruf oder Snom+Handy), dann erzeugt man vorher für jeden ausgehenden Call einen Datensatz in der DB mit einer Callnummer. Dazu verwendet man z.B. einen laufend inkremetierten Wert in der DB a la Postgres "serial" oder eine globale Variable oder eine UUID sonstiger Quelle. Pro Call muss man
    ivrAVALON/call/<nr>/cli
    ivrAVALON/call/<nr>/cld
    definieren. Zusätzlich kann man
    ivrAVALON/call/<nr>/delay
    ivrAVALON/call/<nr>/timeout
    auch noch ausfüllen, wenn man eine Startverzögerung haben möchte und/oder eine limitierte Rufdauer. Dann startet man die Calls gleichzeitig per
    Dial(LOCAL/##1&LOCAL/##2&LOCAL/##3);
    wenn beispielsweise Datensätze für Callnummern 1, 2 und 3 erzeugt wurden:
    ivrAVALON/call/1/cli = 01522341018
    ivrAVALON/call/1/cld = 11

    ivrAVALON/call/2/cli = 01522341018
    ivrAVALON/call/2/cld = 19
    ivrAVALON/call/2/delay = 10

    ivrAVALON/call/3/cli = 01522341018
    ivrAVALON/call/3/cld = 01999309511
    ivrAVALON/call/3/timeout = 25​
    Damit wird dreimal gleichzeitig die Routingextension
    _##. => {
    Wait(${DB(ivrAVALON/call/${EXTEN:2}/delay)});
    Set(cld=${DB(ivrAVALON/call/${EXTEN:2}/cld)});
    Set(timeout=${DB(ivrAVALON/call/${EXTEN:2}/timeout)});
    Set(DB(ivrAVALON/channel/${CHANNEL})=${EXTEN:2});
    if ( "${cld:0:1}" = "0" ) {
    Dial(SIP/selfnet/${cld},${timeout},M(jabberphone^${EXTEN:2})tw);
    } else {
    Dial(SIP/${cld},${timeout},M(jabberphone^${EXTEN:2})tw);
    };
    Hangup();
    } ​
    aufgerufen. Diese baut den Call zu einer lokalen SIP Extension oder zum Festnetz auf (je nachdem, ob die CLD mit Null beginnt oder nicht) und merkt sich die jeweilige Callnummer (1, 2 oder 3 im Beispiel) über die ChannelID (z.B. "SIP/selfnet-08154711") in
    ivrAVALON/channel/<channelid>
    sozusagen als Reverse-Mapping für später. Wird eine Verbindung hergestellt, startet der
    macro jabberphone( ext ) {
    Set(DB(ivrAVALON/call/${ext}/pickedup)=1);
    NoOp(inform jabberphone that ${DB(ivrAVALON/call/${ext}/cld)} picked up the call from ${DB(ivrAVALON/call/${ext}/cli)});
    }; ​
    kurz an. Der vermerkt einerseits, dass der Call abgehoben wurde und schickt andererseits die heiss ersehnte Meldung an den JabberPhone, wer (CLD z.B. 19) welches Gespräch (CLI z.B: 01522341018) gerade eben abgehoben hat. Im Moment des Abhebens einer dieser Verbindungen werden alle anderen parallelen Calls vom ursprünglichen Dial(LOCAL/##1&...) aufgelegt.

    Beim Auflegen (mit oder ohne zuvor hergestellter Verbindung) läuft die Asterisk aber gottseidank noch durch die
    h => {
    Set(ext=${DB(ivrAVALON/channel/${CHANNEL})});
    if("${DB(ivrAVALON/call/${ext}/pickedup)}"="1") {
    NoOp(inform jabberphone that ${DB(ivrAVALON/call/${ext}/cld)} hung up the call from ${DB(ivrAVALON/call/${ext}/cli)});
    };
    DBdeltree(ivrAVALON/call/${ext});
    DBdel(ivrAVALON/channel/${CHANNEL});
    }; ​
    Extension, die einerseits die Asterisk DB aufräumt und zweitens, wenn es eine Verbindung gab, dem JabberPhone meldet wer (CLD) welches Gespräch (CLI) soeben aufgelegt hat. Nachdem aber in der "h" Extension verlässlich eigenlich nur mehr die ursprüngliche ChannelID zur Verfügung steht (siehe auch "Use with great care" auf http://www.voip-info.org/wiki/view/Asterisk+h+extension), habe ich diese als Wiedererkennungszeichen eingesetzt - das "Reverse Mapping" von zuvor.

    Ergebnis: Abheben und Auflegen werden in Echtzeit vermeldet und nach Abschluss des Calls sind alle Datenbankeinträge wieder weggeräumt - egal, ob abgehoben wurde oder welche Seite das Gespräch beendet hat.

    Möchte man in den JabberPhone Meldungen weitere Daten anzeigen (Namen von Quelle und Ziel, Handle für die JabberPhone Verbindung, ...), kann man diese ja nach Belieben in weitere
    ivrAVALON/call/<nr>/xxx
    Datensätze einfüllen, da bei Gesprächsabschluss der gesamte Teilbaum ivrAVALON/call/<nr> weggeräumt wird.

    Ich bin stolz auf mich! :-D

    ToDo:

    1. Implementierung der Kommunikation zu JabberPhone
    2. Implementierung eines "thread-safe" Zählers für die Erzeugung einer eindeutigen Callnummer, auch wenn mehrere eingehende Gespräche gleichzeitig verteilt werden
    Hier vermute ich jedoch keine besonderen Probleme mehr...

    servus,
    Thomas
     
  5. Nizzmo

    Nizzmo Neuer User

    Registriert seit:
    26 Nov. 2006
    Beiträge:
    36
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    hey, super - vielen vielen dank!
    ich werd mir des morgen mal genauer ansehen bzw. testen und dann meine erkenntnisse dazu hier posten! :)
    ich wünsch dir noch einen schönen abend.
     
  6. rentier-s

    rentier-s Guest

    AMI spuckt alles mögliche an Informationen aus, da ist auch das Link-Event dabei. Man muss nur mit einem Daemon auf die entsprechende Nachricht von AMI warten und diese dann entsprechend verarbeiten.

    Alternativ könnte man beim Dial mittels U-Flag eine Routine aufrufen, die ein AGI startet, das per AMI abfrägt mit welchem Channel gebridged wurde und dann die Nachricht an den Mitarbeiter verschickt.
     
  7. ViennaAustria

    ViennaAustria Neuer User

    Registriert seit:
    11 Okt. 2005
    Beiträge:
    177
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Ort:
    Wien
    Die Idee mit AMI ist gut. Allerdings für unser Jabber Interface problematisch, weil

    1. muss man einen Dämon laufen haben, der mit einer Socketverbindung ("Telnet") im Manegement Intarfece mit liest und mit den anderen Teilen des Systems kommuniziert. Das ist grundsätzlich aufwändiger und daher fehleranfälliger (Dämon tot, Asterisk Tot und Dämon reconnected nicht, ...), als eine Lösung im Diaplan. [kann trotzdem besser sein! das zeigt sich i.r.l.]
    2. muss man sich einen Weg überlegen, wie ich dem AMI bzw. dem mitlesenden Dämon erkläre, welche Nachricht er in den Jabber schreiben soll, wenn zwei Kanäle verbunden werden. Der AMI Event liefert ja nur Channel IDs und Unique IDs. Aus denen muss man erkennen, welcher der gleichzeitig läutenden Calls verbunden wurde (Kunde 1, Kunde 2, ...) und daraus die gewünschte Nachricht erzeugen "A/19 Peter Silie (0815/4711) - Benjamin @99".
    Das ist aber in jedem Fall näher anzusehen! :rock:
     
  8. rentier-s

    rentier-s Guest

    Asterisk würde auf jeden Fall unbeirrt weiterlaufen, auch wenn der Daemon den Geist aufgibt. Wobei mir nicht viel einfällt, was einen solchen Daemon aus der Ruhe bringen könnte. Und selbst wenn, ist er leicht per cron alle paar Minuten überprüft und ggf. neu gestartet.

    Wie gesagt, alternativ könnte man der per Dialplan aufrufen. Die Routine von U wird ausgeführt, sobald der Anruf angenommen wird. Den Channel des Anrufers kennt man, damit kann man per AGI+AMI abfragen wohin dieser gebridged wurde.

    Die Events aus AMI sind, finde ich, recht gut lesbar. Mit
    Code:
    Event: Link
    Channel1: SIP/101-3f3f
    Channel2: Zap/2-1
    
    weiß ich zB. genau, meine SIP-Nst 101 ist jetzt mit der externen Nr. 2 verbunden. Das ist mit regulären Audrücken ruckzuck ausgewertet.
    Was ich aus dem Stegreif nicht zu sagen vermag ist, ob die Reichenfolge der Channels immer richtig ist, also ob man abgehend von ankommend unterscheiden kann. Aber dazu könnte man schlimmsten Falls die Channel-Informationen auslesen und anhand des Contextes unterscheiden.
     
  9. ViennaAustria

    ViennaAustria Neuer User

    Registriert seit:
    11 Okt. 2005
    Beiträge:
    177
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Ort:
    Wien
    Alleine schon, dass ICH ihn programmiert habe... ;)

    Nja. Wir verbinden nicht nur zu lokalen nebenstellen, sondern auch zu Mobiltelefonen und Anschlüssen an anderen Telefonanlagen. Das wird man aber sicher in den Griff bekommen. Wir wollen aber viel mehr als nur Caller und Callee anzeigen, wie z.B.

    • welche Mitarbeiter sind denn überhaupt per Jabber zu benachrichtigen?
    • wohin hat der Anrufer ursprünglich gewählt? Nebenstelle, Ringruf, welche Firma (sind mehrere bei uns) bzw. welche Hotline-Nummer
    • wer ist der Anrufer (Identifikation über CLI - Datenbank)?
    • wer (Mitarbeiter) hat wo (Büro, Home-Office, Handy, Kunde, ...) abgehoben?
    Das muss man dem AMI-Lese-Dämon schicken (die ersten drei Punkte stehen ja schon fest, bevor es zu läuten beginnt = können vom Dialplan kommen und als Parameter übermittelt werden) bzw. muss er aus der Management Nachricht auslesen und "verstehen", um die Daten des Abhebenden zu ermitteln - also Datenbankzugriff.

    Ich speichere solche temporären Informationen gerne in der Asterisk DB. Die ist simpel und schnell genug für sowas. Allerdings kann ich sie von Aussen nicht direkt manipulieren, was bei einem Dämon die Sache nicht einfacher macht (ja, klar: "asterisk -rx database put..." Aufruf). Kann man das Asterisk /var/lib/asterisk/astdb File irgendwie direkt lesen/manipulieren? Angeblich soll das Berkley DB sein. Mit den Tools, die z.B. die Sendmail DBs /etc/mail/*.db manipulieren können ist es mir jedenfalls nicht gelungen.
     
  10. abw1oim

    abw1oim Aktives Mitglied

    Registriert seit:
    26 März 2007
    Beiträge:
    951
    Zustimmungen:
    3
    Punkte für Erfolge:
    18
    Ort:
    Bonn
    Hier mal noch ein alternativer Ansatz für Gruppencalls inclusive pickup (ab Asterisk 1.8):

    Code:
    // Beispielkontext für eingehende Anrufe mit Gruppenruf
    context inbound { 
            _X.   = > {
                         Set(ToDial=SIP/100&SIP/101);
                         Dial(${ToDial},,U(cdrupdate));
                         }
    }
    
    context cdrupdate {
    
    	s	=>	{
    			Set(LOCAL(pickup)=1);
    			Set(LOCAL(max)=${FIELDQTY(MASTER_CHANNEL(ToDial),&)});
    			for (LOCAL(i)=1;${i}<=${max};LOCAL(i)=$[${i}+1]) {
    				Set(LOCAL(chan)=${CUT(CUT(MASTER_CHANNEL(ToDial),&,${i}),/,2)});
    				if (${chan}=${CHANNEL(peername)}) {
    					Set(LOCAL(pickup)=0);
    					Set(LOCAL(i)=$[${max}+1]);
    				}
    			}
    			if (${pickup}=1) {
    				Set(MASTER_CHANNEL(ispickup)=1);
    			} else {
    				Set(MASTER_CHANNEL(ispickup)=0);
    			}
    			Set(MASTER_CHANNEL(dstnumber_final)=${CHANNEL(peername)});
    			if (${CHANNEL(channeltype)}=SIP) {
    				Set(MASTER_CHANNEL(dstname_final)=${SIPPEER(${CHANNEL(peername)},callerid_name)});
    			} else {
    				Set(MASTER_CHANNEL(dstname_final)=${IAXPEER(${CHANNEL(peername)},callerid_name)});
    			}
    			Return;
    			}
    }
    
    Zur Erklärung: Der Dial-Befehl wird for dem Bridge (Verbinden) des Anrufs zum Teilnehmer die Subroutine cdrupdate aufrufen. Innerhalb dieser wird die Variable ToDial des ursprünglichen Channels (MASTER_CHANNEL) ausgewertet und mit den Variablen des neu aufgebauten Channels verglichen. Gibt es einen Match, handelt es sich nicht um einen Pickup, aandernfalls schon.
    Beispielhaft wird hier neben der Pickup-Info sowohl ddie CALLERID(num) (dstnumber_final) als auch die CALLERID(name) (dstname_final) des 2. Channels neben der Pickupinfo als Variablen an den MASTER_CHANNEL übergeben. Darüber ist es auch möglich, entsprechende CDR-Variablen (die liegen im er im ursprünglichen MASTER_CHANNEL) zu setzen.
     
  11. rentier-s

    rentier-s Guest

    @ViennaAustria

    Der Daemon schaut bei einem Link-Event nach, ob einer der beiden Channels in der "zu benachrichtigen" Datenbank vorkommt. Fall ja, besorgt er sich für den anderen Channel weitere Informationen:

    Code:
    Event: Status
    Channel: SIP/102-efe4
    CallerID: "Test Client" <102>
    Account:
    State: Up
    Context: sipclients
    Extension: 102
    Priority: 1
    Seconds: 16
    Link: SIP/102-cbcf
    Uniqueid: 1113857632.4
    ActionID: blah
    Über den Context weiß man, von wo nach wo der Anruf ging, über die Extension was der Anrufer gewählt hat. CallerID steht auch drin. Wenn Du weitere Informationen möchtest, kannst Du diese am Anfang des Dialplans als Channel-Variable setzen und nachher ebenfalls per AMI auslesen. Sogar ganz ohne AstDB.

    Ich meine, mir ist es egal, wie Ihr das macht. Ich sage nur, dass das was Du hier zu zerreden versuchst, doch relativ einfach funktioniert (sofern man die Schnittstelle kennt ;-)). Wenn Du das nicht möchtest, Deine Sache, dem TE möge es eine Hilfe sein (oder auch nicht).