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

A-Teilnehmer Signalisierung bei Attended-Transfer[gelöst]

Dieses Thema im Forum "Asterisk Allgemein" wurde erstellt von Heldenhaft, 10 Okt. 2008.

  1. Heldenhaft

    Heldenhaft Neuer User

    Registriert seit:
    24 Nov. 2004
    Beiträge:
    104
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    #1 Heldenhaft, 10 Okt. 2008
    Zuletzt bearbeitet: 15 Okt. 2008
    Hallo,
    ich hab eine Lösung für die A-Teilnehmer Signalisierung bei Attended-Transfer und anderen Situationen (z.B. Pickup) gebastelt. Das ganze ist eine Mischung aus verschiedenen Patches die ich im Netz gefunden habe. Leider bin ich mir insbesondere bei den Aastra Patch nicht sicher in wie weit ich Asterisk aus den Tritt bringe.

    Das ganze funktioniert nur für Snom und Aastra-Telefone.
    Beide Telefone unterstützen spezielle SIP-Messages innerhalb eines SIP-Dialogs um die CallerId während eines Gespräches zu aktualisiern. Snom nutzt einfach ein SIP-Notify und bei Aastra muss man leider ein ReInvite durchführen.

    Im Asterisk habe ich nun einen Patch eingebaut der die Channel-Struktur um Markierungsfelder erweitert, die festhalten das diese Channels gebridged werden sollen. Wenn zwei Channels gebridged werden wird ein User-“Tranfer“-Event geworfen. Über einen Manager-Dienst kann man dann auf den bestehenden Channels ein Kommando ausführen (z.B. sip aastra_callerid_update channel Name Number). Das geht natürlich auch jederzeit auf der Konsole.

    Leider bin ich mir nicht sicher ob Asterisk, insbesondere bei den Aastras (ReInvite), nicht durcheinander kommt, weil der notwendige Reinvite vielleicht die Seq-Nummern verwürfelt :)?!

    Die Patches habe ich gegen Asterisk 1.2.30 erzeugt.

    channel.h
    Code:
    --- include/asterisk/channel.h	2006-11-07 19:22:01.000000000 +0100
    +++ ../asterisk-1.2.30.2/include/asterisk/channel.h	2008-10-02 18:38:22.000000000 +0200
    @@ -372,7 +372,13 @@
     	/* Channel monitoring */
     	struct ast_channel_monitor *monitor;
     
    -	/*! Track the read/written samples for monitor use */
    +	/* Play xfersound */
    +	int xfersound;
    +
    +	/* dtmfOff */
    +	int dtmfOff;
    +
    +        /*! Track the read/written samples for monitor use */
     	unsigned long insmpl;
     	unsigned long outsmpl;
    

    channel.c
    Code:
    --- channel.c	2007-07-05 16:19:14.000000000 +0200
    +++ ../asterisk-1.2.30.2/channel.c	2008-10-02 18:38:22.000000000 +0200
    @@ -3339,6 +3339,45 @@
     	check = ast_autoservice_stop(peer);
     }
     
    +static void checkAndActivateDtmf (struct ast_channel * channel)
    +{
    +        char* channelName = pbx_builtin_getvar_helper (channel, "dtmfChannelName");
    +        char* dtmfOff = pbx_builtin_getvar_helper (channel, "dtmfOff");
    +           
    +        // SIP-account1000&SIP/account1001
    +
    +        if (channelName != NULL && dtmfOff != NULL)
    +        {
    +            // SIP/account2323-345834754897	   
    +            char* pos = index (channel->name, '-');
    +	    if (pos != NULL)
    +	    {
    +
    +	       char buf[(pos - channel->name) + 1];
    +	       strncpy (buf, channel->name, pos - channel->name);
    +	       buf[pos - channel->name] = 0;
    +	       
    +	       if (strstr (channelName, buf) != NULL)
    +	       {
    +		  if (strcmp (dtmfOff, "true") == 0)
    +		  {
    +		       channel->dtmfOff = 1;
    +		  }
    +	       }
    +	       
    +	    }
    +        }
    +        else
    +        {
    +	   if (dtmfOff != NULL)
    +	   {
    +	       channel->dtmfOff = 1;
    +	   }
    +	}
    +}
    +
    +
    +
     static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct ast_channel *c1,
     						 struct ast_bridge_config *config, struct ast_frame **fo,
     						 struct ast_channel **rc, struct timeval bridge_end)
    @@ -3354,6 +3393,7 @@
     	int watch_c1_dtmf;
     	void *pvt0, *pvt1;
     	int to;
    +	int xfersoundplayed=0;
     	
     	cs[0] = c0;
     	cs[1] = c1;
    @@ -3363,8 +3403,24 @@
     	o1nativeformats = c1->nativeformats;
     	watch_c0_dtmf = config->flags & AST_BRIDGE_DTMF_CHANNEL_0;
     	watch_c1_dtmf = config->flags & AST_BRIDGE_DTMF_CHANNEL_1;
    +   
    +        checkAndActivateDtmf (c0);
    +        checkAndActivateDtmf (c1);
    +   
    +	if ((c1->xfersound || c0->xfersound) && !xfersoundplayed) {
    +	   if (strcmp (c1->tech->type, "SIP") == 0)
    +	     {
    +		manager_event(EVENT_FLAG_USER, "usereventtransfer", 
    +			      "Channel: %s\r\nUniqueid: %s\r\ndst: %s\r\ncallerIdNum: %s\r\ncallerIdName: %s\r\n",
    +			      c0->name, c0->uniqueid, c1->name, c0->cid.cid_num, c0->cid.cid_name);
    +
    +		bridge_playfile (c1,c0,"xferbeep",c1->language);
    +		xfersoundplayed=1;
    +	      }
    +      	}
     
    -	for (;;) {
    +   
    +        for (;;) {
     		if ((c0->tech_pvt != pvt0) || (c1->tech_pvt != pvt1) ||
     		    (o0nativeformats != c0->nativeformats) ||
     		    (o1nativeformats != c1->nativeformats)) {
    @@ -3417,6 +3473,7 @@
     				break;
     			}
     		}
    +	
     		if ((f->frametype == AST_FRAME_VOICE) ||
     		    (f->frametype == AST_FRAME_DTMF) ||
     		    (f->frametype == AST_FRAME_VIDEO) || 
    
    chan_sip
    Code:
    --- channels/chan_sip.c	2008-06-03 21:30:02.000000000 +0200
    +++ ../asterisk-1.2.30.2/channels/chan_sip.c	2008-10-02 18:38:22.000000000 +0200
    @@ -333,6 +333,9 @@
     static char default_context[AST_MAX_CONTEXT] = DEFAULT_CONTEXT;
     static char default_subscribecontext[AST_MAX_CONTEXT];
     
    +#define REDIRECT_CONTEXT "default"
    +static char redirect_context[AST_MAX_CONTEXT] = REDIRECT_CONTEXT;
    +
     #define DEFAULT_VMEXTEN "asterisk"
     static char global_vmexten[AST_MAX_EXTENSION] = DEFAULT_VMEXTEN;
     
    @@ -667,6 +670,7 @@
     	char lastmsg[256];			/*!< Last Message sent/received */
     	int amaflags;				/*!< AMA Flags */
     	int pendinginvite;			/*!< Any pending invite */
    +	int xfersound;				/*!< Play beep on attend transfer */
     #ifdef OSP_SUPPORT
     	int osphandle;				/*!< OSP Handle for call */
     	time_t ospstart;			/*!< OSP Start time */
    @@ -2591,7 +2595,7 @@
     		ast_setstate(ast, AST_STATE_UP);
     		if (option_debug)
     			ast_log(LOG_DEBUG, "sip_answer(%s)\n", ast->name);
    -		res = transmit_response_with_sdp(p, "200 OK", &p->initreq, 2);
    +		res = transmit_response_with_sdp(p, "200 OK", &p->initreq, 1);
     	}
     	ast_mutex_unlock(&p->lock);
     	return res;
    @@ -2677,18 +2681,26 @@
     	struct sip_pvt *p = ast->tech_pvt;
     	int res = 0;
     	ast_mutex_lock(&p->lock);
    -	switch (ast_test_flag(p, SIP_DTMF)) {
    -	case SIP_DTMF_INFO:
    +        if (ast->dtmfOff != 1)
    +        {
    + 	   ast_log(LOG_DEBUG, "************ Send sip digit\n");
    +	   switch (ast_test_flag(p, SIP_DTMF)) {
    +	    case SIP_DTMF_INFO:
     		transmit_info_with_digit(p, digit);
     		break;
    -	case SIP_DTMF_RFC2833:
    +	    case SIP_DTMF_RFC2833:
     		if (p->rtp)
     			ast_rtp_senddigit(p->rtp, digit);
     		break;
    -	case SIP_DTMF_INBAND:
    +	    case SIP_DTMF_INBAND:
     		res = -1;
     		break;
    +	   }
     	}
    +        else
    +      	   ast_log(LOG_DEBUG, "********** Dont Send sip digit\n");
    +
    +   
     	ast_mutex_unlock(&p->lock);
     	return res;
     }
    @@ -5210,6 +5222,7 @@
     	enum state { NOTIFY_OPEN, NOTIFY_INUSE, NOTIFY_CLOSED } local_state = NOTIFY_OPEN;
     	char *pidfstate = "--";
     	char *pidfnote= "Ready";
    +	struct sip_pvt *np = NULL;
     
     	memset(from, 0, sizeof(from));
     	memset(to, 0, sizeof(to));
    @@ -5346,11 +5359,38 @@
     	case DIALOG_INFO_XML: /* SNOM subscribes in this format */
     		ast_build_string(&t, &maxbytes, "<?xml version=\"1.0\"?>\n");
     		ast_build_string(&t, &maxbytes, "<dialog-info xmlns=\"urn:ietf:params:xml:ns:dialog-info\" version=\"%d\" state=\"%s\" entity=\"%s\">\n", p->dialogver++, full ? "full":"partial", mto);
    -		if ((state & AST_EXTENSION_RINGING) && global_notifyringing)
    -			ast_build_string(&t, &maxbytes, "<dialog id=\"%s\" direction=\"recipient\">\n", p->exten);
    -		else
    +
    +		if (!ast_strlen_zero(hint)) {
    +			/* check if the device is ringing and if so get the callid to enable pickup functionality (e.g. for snom phones) */
    +			if ((state & AST_EXTENSION_RINGING)) {
    +				struct ast_channel *chan = NULL;
    +				int hintlen = strlen(hint);
    +
    +				while ((chan = ast_channel_walk_locked(chan)) != NULL) {
    +					if (chan->_state == AST_STATE_RINGING && !strncasecmp(chan->name, "SIP", 3) && chan->tech_pvt && !strncasecmp(chan->name, hint, hintlen)) {
    +						char iabuf[INET_ADDRSTRLEN];
    +
    +						np = chan->tech_pvt;
    +						ast_build_string(&t, &maxbytes, "<dialog id=\"%s\" direction=\"recipient\" call-id=\"%s\" local-tag=\"as%08x\" remote-tag=\"%s\">\n", p->exten, np->callid, (unsigned int)np->tag, np->theirtag);
    +						ast_build_string(&t, &maxbytes, "<state>%s</state>\n", statestring);
    +						ast_build_string(&t, &maxbytes, "<local><identity display=\"%s\">%s</identity><target uri=\"%s\"/></local>\n", p->exten, mto, mfrom);
    +						ast_build_string(&t, &maxbytes, "<remote><identity display=\"%s\">%s@%s</identity><target uri=\"%s\"/></remote>\n", np->fromname, np->fromuser, ((!ast_strlen_zero(np->fromdomain)) ? np->fromdomain : ast_inet_ntoa(iabuf, sizeof(iabuf), np->ourip)), mto);
    +
    +						if (option_debug > 1)
    +							ast_log(LOG_NOTICE, "Transmitting CallID in NOTIFY message - DialogID: %s  CallID: %s\n", p->exten, np->callid);
    +
    +						ast_mutex_unlock(&chan->lock);
    +						break;
    +					}
    +					ast_mutex_unlock(&chan->lock);
    +				}
    +			}
    +		}
    +
    +		if (!np) {
     			ast_build_string(&t, &maxbytes, "<dialog id=\"%s\">\n", p->exten);
    -		ast_build_string(&t, &maxbytes, "<state>%s</state>\n", statestring);
    +			ast_build_string(&t, &maxbytes, "<state>%s</state>\n", statestring);
    +		}
     		ast_build_string(&t, &maxbytes, "</dialog>\n</dialog-info>\n");
     		break;
     	case NONE:
    @@ -9732,7 +9772,10 @@
     			s += 4;
     		ast_log(LOG_DEBUG, "Found 302 Redirect to extension '%s'\n", s);
     		if (p->owner)
    +	        {
    +			ast_copy_string(p->owner->context, redirect_context, sizeof(p->owner->context));
     			ast_copy_string(p->owner->call_forward, s, sizeof(p->owner->call_forward));
    +		}
     	}
     }
     
    @@ -10557,7 +10600,11 @@
     			peerb->cdr = peerc->cdr;
     		}
     		peerc->cdr = NULL;
    -		
    +
    +		if ((p1->xfersound || p2->xfersound) && peerd != NULL) {
    +			peerd->xfersound=1;
    +		}
    +	   
     		if (ast_channel_masquerade(peerb, peerc)) {
     			ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", peerb->name, peerc->name);
     			res = -1;
    @@ -10893,6 +10940,11 @@
     		if (!ignore) {
     			if (p->refer_call) {
     				ast_log(LOG_DEBUG,"202 Accepted (supervised)\n");
    +				
    +				ast_log(LOG_DEBUG,"supervised/attended transfer. Setting sip_pvt flags\n");
    +				p->refer_call->xfersound=1;
    +				p->xfersound=1;
    +
     				attempt_transfer(p, p->refer_call);
     				if (p->refer_call->owner)
     					ast_mutex_unlock(&p->refer_call->owner->lock);
    @@ -12847,7 +12899,9 @@
     		}
     
     		/* Create the interface list */
    -		if (!strcasecmp(v->name, "context")) {
    +		if (!strcasecmp(v->name, "redirectcontext")) {
    +			ast_copy_string(redirect_context, v->value, sizeof(redirect_context));
    +		} else if (!strcasecmp(v->name, "context")) {
     			ast_copy_string(default_context, v->value, sizeof(default_context));
     		} else if (!strcasecmp(v->name, "realm")) {
     			ast_copy_string(global_realm, v->value, sizeof(global_realm));
    @@ -13586,9 +13640,144 @@
     	return sip_reload(0, 0, NULL);
     }
     
    +
    +static struct sip_pvt * search_channel (char *channelId)
    +{
    +   struct ast_channel *c;
    +   const char *cid=NULL;
    +   struct sip_pvt *p;
    +
    +   c = ast_channel_walk_locked(NULL);
    +   while(c) 
    +   {
    +      if (!strncasecmp(channelId, c->name, strlen(channelId))) 
    +      {
    +	 break;
    +      }
    +	
    +      ast_mutex_unlock(&c->lock);
    +      c = ast_channel_walk_locked(c);
    +   }
    +   
    +   if (c) 
    +   {
    +      ast_mutex_unlock(&c->lock);
    +      cid=pbx_builtin_getvar_helper(c,"PickupCallId");
    +      if (cid == NULL)
    +      {
    +	 cid=pbx_builtin_getvar_helper(c,"SIPCALLID");
    +      }
    +   }
    +
    +   if (cid) 
    +   {
    +      ast_mutex_lock(&iflock);
    +      p = iflist;
    +      while(p) 
    +      {
    +	 if (!strcasecmp(p->callid, cid)) 
    +	 {
    +	    ast_mutex_unlock(&iflock);
    +	    return p;
    +	 }
    +	 p = p->next;
    +      }
    +    }
    +   ast_mutex_unlock(&iflock);
    +   return NULL;
    +}
    +
    +
    +/*aastra */
    +static int sip_aastra_callerid_update (int fd, int argc, char *argv[])
    +{
    +       char *channelId;
    +       struct sip_pvt *p;
    +       char *newname, *newnumber;
    +       char buf[512];
    +       char callerId[512];
    +
    +       if (argc < 5)
    +         return RESULT_SHOWUSAGE;
    +
    +       channelId=argv[2];
    +       newname=argv[3];
    +       newnumber=argv[4];
    +
    +       p = search_channel (channelId);
    +       if (p != NULL)
    +       {
    +	  ast_mutex_lock(&p->lock);
    +	  
    +	  struct sip_request req;
    +	
    +	  if (ast_test_flag(p, SIP_REINVITE_UPDATE))
    +	    reqprep(&req, p, SIP_UPDATE, 0, 1);
    +	  else 
    +	    reqprep(&req, p, SIP_INVITE, 0, 1);
    +
    +	  sprintf(callerId, "\"%s\"<sip:%s@%s>",newname, newnumber, ast_inet_ntoa(buf, sizeof(buf), p->ourip));
    +	  add_header(&req, "P-Asserted-Identity", callerId);
    +	  add_header(&req, "Allow", ALLOWED_METHODS);
    +	  if (sipdebug)
    +	    add_header(&req, "X-asterisk-info", "SIP re-invite (RTP bridge)");
    +
    +	  ast_rtp_offered_from_local(p->rtp, 1);
    +	  add_sdp(&req, p);
    +
    +	  copy_request(&p->initreq, &req);
    +	  parse_request(&p->initreq);
    +	  if (sip_debug_test_pvt(p))
    +	    ast_verbose("%d headers, %d lines\n", p->initreq.headers, p->initreq.lines);
    +	  p->lastinvite = p->ocseq;
    +	  ast_set_flag(p, SIP_OUTGOING);
    +	  send_request(p, &req, 1, p->ocseq);
    +	  ast_mutex_unlock(&p->lock);
    +       }       
    +  return RESULT_SUCCESS;
    +}
    +
    +static int sip_snom_callerid_update (int fd, int argc, char *argv[])
    +{
    +       char *channelId;
    +       struct sip_pvt *p;
    +       char *newname, *newnumber;
    +       char buf[512];
    +
    +       if (argc < 5)
    +         return RESULT_SHOWUSAGE;
    +
    +
    +       channelId=argv[2];
    +       newname=argv[3];
    +       newnumber=argv[4];
    +
    +       p = search_channel (channelId);
    +       if (p != NULL)
    +       {
    +	  struct sip_request req;
    +	  char from[512];
    +	  char to[512];
    +	
    +	  sprintf(from, "From: \"%s\" <sip:%s@%s>\r\n", newname, newnumber, ast_inet_ntoa(buf, sizeof(buf), p->ourip));
    +	  sprintf(to, "To:  \"%s\" <sip:%s@%s>\r\n", newname, newnumber, ast_inet_ntoa(buf, sizeof(buf), p->ourip));
    +
    +	  reqprep(&req, p, SIP_INFO, 0, 1);
    +
    +	  add_header_contentLength(&req, (strlen(from) + strlen(to)) );
    +	  add_header(&req, "Content-Type", "message/sipfrag");
    +	  add_line(&req, from);
    +	  add_line(&req, to);
    +	  return send_request(p, &req, 1, p->ocseq);
    +       }
    +  return RESULT_SUCCESS;
    +}
    +
     static struct ast_cli_entry  my_clis[] = {
     	{ { "sip", "notify", NULL }, sip_notify, "Send a notify packet to a SIP peer", notify_usage, complete_sipnotify },
     	{ { "sip", "show", "objects", NULL }, sip_show_objects, "Show all SIP object allocations", show_objects_usage },
    +        { { "sip", "aastra-callerid-update", NULL }, sip_aastra_callerid_update, "Send a reinvite to update the callerid for a aastra device", "sip aastra-callerid-update <channel> <newname> <newnumber>"},
    +        { { "sip", "snom-callerid-update", NULL }, sip_snom_callerid_update, "Send a notify to update the callerid for a snom device", "sip snom-callerid-update <channel> <newname> <newnumber>"},
     	{ { "sip", "show", "users", NULL }, sip_show_users, "Show defined SIP users", show_users_usage },
     	{ { "sip", "show", "user", NULL }, sip_show_user, "Show details on specific SIP user", show_user_usage, complete_sip_show_user },
     	{ { "sip", "show", "subscriptions", NULL }, sip_show_subscriptions, "Show active SIP subscriptions", show_subscriptions_usage},
    
     
  2. Heldenhaft

    Heldenhaft Neuer User

    Registriert seit:
    24 Nov. 2004
    Beiträge:
    104
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Keine Antworten? Überhaupt nichts? Ist das nicht ein Feature was jeder haben möchte?

    Geht das bei euch auch ohne Probleme oder löst Ihr das Problem anders?
     
  3. magic911

    magic911 Neuer User

    Registriert seit:
    19 Feb. 2006
    Beiträge:
    99
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Für mich sind es Features die ich brauche. Komme allerdings erst in der kommenden Woche zum testen.

    Gruß Magic911
     
  4. jwm@gmx.at

    jwm@gmx.at Neuer User

    Registriert seit:
    20 Jan. 2006
    Beiträge:
    118
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Hallo!

    Ja, das wäre genau was ich brauche (zumindest für die Snom Phones).
    Aber ich habe leider nicht wirklich viel Erfahrung wie man einen solchen Patch einspielt.

    Hannes
     
  5. Heldenhaft

    Heldenhaft Neuer User

    Registriert seit:
    24 Nov. 2004
    Beiträge:
    104
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Der Patch alleine hiflt dir noch nicht wirklich weiter. Du brauchst auch noch eine Manager-API-Applikation die das ganze verwaltet. Ich denke der Aufwand ist zu hoch - vielleicht gibt es ja noch eine andere Lösung?
     
  6. hmdanman

    hmdanman Neuer User

    Registriert seit:
    19 Apr. 2006
    Beiträge:
    7
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    calleridupdated

    Hallo Leute!

    Ich habe einen Dienst programmiert welcher die aktiven Gespräche Analysiert und bei einem Transfer den CallerID über die Funktion sip_snom_callerid_update umdreht.

    Falls Interesse besteht, würde ich diesen gerne veröffentlichen.

    Leider funktioniert das CallerID Update nicht beim holen eines Gespräches mit *8. Ich habe bemerkt, dass im chan_sip die SIPCALLID mit einem ungültigen Channel überschrieben wird und deshalb das sip_snom_callerid_update das Notify nicht mehr ans snom schicken kann.

    Ich verwende noch asterisk 1.2.30.2

    Danke für die Hilfe
     
  7. Heldenhaft

    Heldenhaft Neuer User

    Registriert seit:
    24 Nov. 2004
    Beiträge:
    104
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Hi,
    ich habe es bei ausgehenden Gesprächen bisher leider auch nicht geschafft. Hatte aber immer vermutet, dass es einfach an den Endgeräten liegt. Auf die SIPCALLERID bin ich noch nicht gekommen. Hast du schon eine Lösung?
     
  8. hmdanman

    hmdanman Neuer User

    Registriert seit:
    19 Apr. 2006
    Beiträge:
    7
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Hallo Heldenhaft!

    Ja, ich habe den Code so modifiziert damit zusätzlich die Variable PickupCallID nur dann gesetzt wird, wenn in der SIPCALLERID "sip:" drin steht. Somit wird in der Unterfunktion search_channels die Richtige Channel-Nummer gefunden und das CallerIDUpdate funktioniert auch bei Pickups.
     
  9. Heldenhaft

    Heldenhaft Neuer User

    Registriert seit:
    24 Nov. 2004
    Beiträge:
    104
    Zustimmungen:
    0
    Punkte für Erfolge:
    0
    Hi,
    bei Pickups hat es bei mir auch schon geklappt. Allerdings konnte ich in der "Ring"-Phase bei normalen ausgehenden Gesprächen die CallerId nicht ändern. Das hat immer erst funktioniert, wenn das Gespräch angenommen worden ist. Ich vermute mal, dass es während der Rufphase bei dir auch nicht klappt. Ist leider noch ein kleines Manko, da einige Kollegen gerne den gewählten Namen im Display sehen würden.