- Mitglied seit
- 24 Nov 2004
- Beiträge
- 104
- Punkte für Reaktionen
- 0
- Punkte
- 0
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
channel.c
chan_sip
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},
Zuletzt bearbeitet: