? doc/api Index: channels/chan_sip.c =================================================================== RCS file: /usr/cvsroot/asterisk/channels/chan_sip.c,v retrieving revision 1.292.2.19 diff -u -r1.292.2.19 chan_sip.c --- channels/chan_sip.c 15 Mar 2004 09:14:36 -0000 1.292.2.19 +++ channels/chan_sip.c 17 Mar 2004 01:45:13 -0000 @@ -74,6 +74,7 @@ #define SIP_DTMF_RFC2833 (1 << 0) #define SIP_DTMF_INBAND (1 << 1) #define SIP_DTMF_INFO (1 << 2) +#define SIP_DTMF_NOTIFY (1 << 3) static int max_expiry = DEFAULT_MAX_EXPIRY; static int default_expiry = DEFAULT_DEFAULT_EXPIRY; @@ -103,6 +104,7 @@ #define SIP_MAX_PACKET 1500 /* Also from RFC 2543, should sub headers tho */ #define ALLOWED_METHODS "INVITE, ACK, CANCEL, OPTIONS, BYE, REFER" +#define NOTIFY_RESP ";method=\"NOTIFY;Event=telephone-event;Duration=2000\"" static char context[AST_MAX_EXTENSION] = "default"; @@ -1387,6 +1389,7 @@ if (p && p->rtp && (p->dtmfmode & SIP_DTMF_RFC2833)) { ast_rtp_senddigit(p->rtp, digit); } + /* XXX dtmfmode & SIP_DTMF_NOTIFY */ /* If in-band DTMF is desired, send that */ if (p->dtmfmode & SIP_DTMF_INBAND) return -1; @@ -2405,7 +2408,13 @@ copy_header(resp, req, "Call-ID"); copy_header(resp, req, "CSeq"); add_header(resp, "User-Agent", "Asterisk PBX"); - add_header(resp, "Allow", ALLOWED_METHODS); + if (p->dtmfmode == SIP_DTMF_NOTIFY) { + add_header(resp, "Allow", ALLOWED_METHODS ", NOTIFY"); + add_header(resp, "Call-Info", NOTIFY_RESP); + add_header(resp, "Allow-events", "telephone-event"); + } else + add_header(resp, "Allow", ALLOWED_METHODS); + if (p->expiry) { /* For registration responses, we also need expiry and contact info */ @@ -2853,7 +2862,12 @@ snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", inet_ntoa(p->ourip), ourport, p->branch); reqprep(&req, p, "INVITE", 0); } - add_header(&req, "Allow", ALLOWED_METHODS); + if (p->dtmfmode == SIP_DTMF_NOTIFY) { + add_header(&req, "Allow", ALLOWED_METHODS ", NOTIFY"); + add_header(&req, "Call-Info", NOTIFY_RESP); + add_header(&req, "Allow-events", "telephone-event"); + } else + add_header(&req, "Allow", ALLOWED_METHODS); add_sdp(&req, p, rtp, vrtp); /* Use this as the basis */ copy_request(&p->initreq, &req); @@ -2987,7 +3001,12 @@ { add_header(&req, "Alert-info",distinctive_ring); } - add_header(&req, "Allow", ALLOWED_METHODS); +#if DTMF_NOTIFY_SEND + if (p->dtmfmode == SIP_DTMF_NOTIFY) + add_header(&req, "Allow", ALLOWED_METHODS ", NOTIFY"); + else +#endif + add_header(&req, "Allow", ALLOWED_METHODS); if (sdp) { add_sdp(&req, p, NULL, NULL); } else { @@ -4571,6 +4590,44 @@ return RESULT_SUCCESS; } +static void receive_notify(struct sip_pvt *p, struct sip_request *req) +{ + unsigned char *ptr; + unsigned int event; + char resp = 0; + struct ast_frame f; + int len; + + len = 4; /* XXX is it safe to presume this is always 4 bytes? */ + ptr = req->data + (req->len - len); + + if (p->owner) { + if (ptr[1] & 0x80) { + if (sipdebug) + ast_verbose("NOTIFY DTMF stop received: '%d'\n", ptr[0]); + return; + } + if (sipdebug) + ast_verbose("NOTIFY DTMF start received: '%d'\n", ptr[0]); + event = ptr[0]; + if (event < 10) { + resp = '0' + event; + } else if (event < 11) { + resp = '*'; + } else if (event < 12) { + resp = '#'; + } else if (event < 16) { + resp = 'A' + (event - 12); + } + memset(&f, 0, sizeof(f)); + f.frametype = AST_FRAME_DTMF; + f.subclass = resp; + f.offset = 0; + f.data = NULL; + f.datalen = 0; + ast_queue_frame(p->owner, &f, 0); + } +} static void receive_info(struct sip_pvt *p, struct sip_request *req) { char buf[1024] = ""; @@ -5580,7 +5637,7 @@ } } else if (!strcasecmp(cmd, "INFO")) { if (sipdebug) - ast_verbose("Receiving DTMF!\n"); + ast_verbose("Receiving INFO DTMF!\n"); receive_info(p, req); transmit_response(p, "200 OK", req); } else if (!strcasecmp(cmd, "REGISTER")) { @@ -5613,6 +5670,11 @@ } else { handle_response(p, respid, e + len, req,ignore); } + } else if (!strcasecmp(cmd, "NOTIFY")) { + if (sipdebug) + ast_verbose("Receiving NOTIFY DTMF!\n"); + receive_notify(p, req); + transmit_response(p, "200 OK", req); } else { transmit_response_with_allow(p, "405 Method Not Allowed", req); ast_log(LOG_NOTICE, "Unknown SIP command '%s' from '%s'\n", @@ -6061,6 +6123,8 @@ user->dtmfmode = SIP_DTMF_RFC2833; else if (!strcasecmp(v->value, "info")) user->dtmfmode = SIP_DTMF_INFO; + else if (!strcasecmp(v->value, "notify")) + user->dtmfmode = SIP_DTMF_NOTIFY; else { ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value); user->dtmfmode = SIP_DTMF_RFC2833; @@ -6228,6 +6292,8 @@ peer->dtmfmode = SIP_DTMF_RFC2833; else if (!strcasecmp(v->value, "info")) peer->dtmfmode = SIP_DTMF_INFO; + else if (!strcasecmp(v->value, "notify")) + peer->dtmfmode = SIP_DTMF_NOTIFY; else { ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value); peer->dtmfmode = SIP_DTMF_RFC2833; @@ -6376,6 +6442,8 @@ globaldtmfmode = SIP_DTMF_RFC2833; else if (!strcasecmp(v->value, "info")) globaldtmfmode = SIP_DTMF_INFO; + else if (!strcasecmp(v->value, "notify")) + globaldtmfmode = SIP_DTMF_NOTIFY; else { ast_log(LOG_WARNING, "Unknown dtmf mode '%s', using rfc2833\n", v->value); globaldtmfmode = SIP_DTMF_RFC2833; @@ -6625,7 +6693,7 @@ } static char *synopsis_dtmfmode = "Change the dtmfmode for a SIP call"; -static char *descrip_dtmfmode = "SIPDtmfMode(inband|info|rfc2833): Changes the dtmfmode for a SIP call\n"; +static char *descrip_dtmfmode = "SIPDtmfMode(inband|info|rfc2833|notify): Changes the dtmfmode for a SIP call\n"; static char *app_dtmfmode = "SIPDtmfMode"; static int sip_dtmfmode(struct ast_channel *chan, void *data) { @@ -6647,6 +6715,8 @@ p->dtmfmode = SIP_DTMF_RFC2833; else if (!strcasecmp(mode,"inband")) p->dtmfmode = SIP_DTMF_INBAND; + else if (!strcasecmp(mode,"notify")) + p->dtmfmode = SIP_DTMF_NOTIFY; else ast_log(LOG_WARNING, "I don't know about this dtmf mode: %s\n",mode); return 0;