[asterisk-commits] oej: branch oej/tdd-sip r89063 - in /team/oej/tdd-sip: channels/ main/
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue Nov 6 15:15:50 CST 2007
Author: oej
Date: Tue Nov 6 15:15:49 2007
New Revision: 89063
URL: http://svn.digium.com/view/asterisk?view=rev&rev=89063
Log:
Implementing TDD in sip
Modified:
team/oej/tdd-sip/channels/chan_sip.c
team/oej/tdd-sip/main/channel.c
Modified: team/oej/tdd-sip/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/oej/tdd-sip/channels/chan_sip.c?view=diff&rev=89063&r1=89062&r2=89063
==============================================================================
--- team/oej/tdd-sip/channels/chan_sip.c (original)
+++ team/oej/tdd-sip/channels/chan_sip.c Tue Nov 6 15:15:49 2007
@@ -144,7 +144,7 @@
#include "asterisk/translate.h"
#include "asterisk/version.h"
#include "asterisk/event.h"
-
+#include "asterisk/tdd.h"
#ifndef FALSE
#define FALSE 0
#endif
@@ -207,6 +207,9 @@
#define SIP_MAX_PACKET 4096 /*!< Also from RFC 3261 (2543), should sub headers tho */
#define INITIAL_CSEQ 101 /*!< our initial sip sequence number */
+
+#define END_SILENCE_LEN 400 /*!< TTY silence length */
+#define ASCII_BYTES_PER_CHAR 80 /*!< TTY bytes of sound data per character */
/*! \brief Global jitterbuffer configuration - by default, jb is disabled */
static struct ast_jb_conf default_jbconf =
@@ -1122,8 +1125,22 @@
struct sip_invite_param *options; /*!< Options for INVITE */
int autoframing; /*!< The number of Asters we group in a Pyroflax
before strolling to the Grokyzpå
- (A bit unsure of this, please correct if
- you know more) */
+ (A bit unsure of this, please correct if you know more) */
+
+
+ struct tdd_state *tdd; /*!< TDD state */
+ unsigned int didtdd:1;
+ unsigned int tddIsSending;
+#define TDDREADBUFLEN 160 /* uLaw=>160 samples/frame */
+ short tddbuffer[AST_FRIENDLY_OFFSET/2 + TDDREADBUFLEN]; /* TDD read buffer */
+ unsigned char* ttytonebuf;
+ int ttytonebufend;
+#define TTYCHARBUFLENGTH 2048
+ char ttycharbuf[TTYCHARBUFLENGTH];
+ int ttycharbuflen;
+ int ttyhasholdtone;
+ int vcoMode;
+ int ttysched;
};
/*! Max entires in the history list for a sip_pvt */
@@ -1789,6 +1806,12 @@
static struct ast_udptl *sip_get_udptl_peer(struct ast_channel *chan);
static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl);
+/*--------TTY support ----------*/
+enum ast_bridge_result sip_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
+int tty_write_cb(void* data);
+static int sip_setoption(struct ast_channel *chan, int option, void* data, int datalen);
+
+
/*! \brief Definition of this channel for PBX channel registration */
static const struct ast_channel_tech sip_tech = {
.type = "SIP",
@@ -1810,10 +1833,11 @@
.fixup = sip_fixup, /* called with chan locked */
.send_digit_begin = sip_senddigit_begin, /* called with chan unlocked */
.send_digit_end = sip_senddigit_end,
- .bridge = ast_rtp_bridge, /* XXX chan unlocked ? */
+ .bridge = sip_bridge, /* XXX chan unlocked ? */
.early_bridge = ast_rtp_early_bridge,
.send_text = sip_sendtext, /* called with chan locked */
.func_channel_read = acf_channel_read,
+ .setoption = sip_setoption,
};
/*! \brief This version of the sip channel tech has no send_digit_begin
@@ -4060,6 +4084,12 @@
sip_pvt_unlock(p);
return 0;
}
+
+ /* Disable TDD mode */
+ int x=0;
+ ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
+ p->didtdd=0;
+
/* If the call is not UP, we need to send CANCEL instead of BYE */
/* In case of re-invites, the call might be UP even though we have an incomplete invite transaction */
if (p->invitestate < INV_COMPLETED && p->owner->_state != AST_STATE_UP) {
@@ -4217,6 +4247,8 @@
return res;
}
+int holdend = 0;
+
/*! \brief Send frame to media channel (rtp) */
static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
{
@@ -4248,7 +4280,10 @@
ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
}
p->lastrtptx = time(NULL);
- res = ast_rtp_write(p->rtp, frame);
+ if(!p->tdd) // || (p->tdd && p->vcoMode)){
+ res = ast_rtp_write(p->rtp, frame);
+ else if(p->vcoMode)
+ res = ast_rtp_write(p->rtp, frame);
}
sip_pvt_unlock(p);
}
@@ -4273,7 +4308,40 @@
case AST_FRAME_TEXT:
if (p) {
sip_pvt_lock(p);
- if (p->trtp) {
+ if(p->tdd) { /* force TDD mode instead of T140 if TDD is on */
+ unsigned char *intext=frame->data;
+ int textlen=frame->datalen;
+ int i;
+
+ for(i=0; i<textlen; i++) {
+ if(intext[i]==0x1b && (textlen-i)>=2 && intext[i+1]==0x61) {
+ // ESC 0061 = T140 INT = mode change
+ ast_log(LOG_DEBUG,"TDD: Switching VCO Mode\n");
+ p->vcoMode=(p->vcoMode)?0:1;
+ }
+ ast_log(LOG_DEBUG,"Recvd char: %c(%X)\n",intext[i],intext[i]);
+
+ if(intext[i]==0xef && ((textlen-i) >= 3) ) {
+ if(intext[i+1]==0xbb && intext[i+2]==0xbf) {
+ // UTF8 synch char, do not display!
+ i+=2;
+ ast_log(LOG_DEBUG,"SYNCH CHAR RECEIVED!\n");
+ }
+ }
+ else if(intext[i]==0xe2 && ((textlen-i) >= 3) ) {
+ if(intext[i+1]==0x80 && intext[i+2]==0xa8) {
+ // UTF8 RET = E2 80 A8
+ p->ttycharbuf[p->ttycharbuflen++]='\n';
+ ast_log(LOG_DEBUG,"RET CHAR RECEIVED!\n");
+ i+=2;
+ }
+ }
+ else if(isprint(intext[i])) // TODO: a better check
+ p->ttycharbuf[p->ttycharbuflen++]=intext[i];
+ else p->ttycharbuf[p->ttycharbuflen++]='?';
+ }
+ }
+ else if (p->trtp) {
/* Activate text early media */
if ((ast->_state != AST_STATE_UP) &&
!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
@@ -4680,6 +4748,8 @@
manager_event(EVENT_FLAG_SYSTEM, "ChannelUpdate",
"Channel: %s\r\nUniqueid: %s\r\nChanneltype: %s\r\nSIPcallid: %s\r\nSIPfullcontact: %s\r\n",
tmp->name, tmp->uniqueid, "SIP", i->callid, i->fullcontact);
+
+ i->tdd = NULL;
return tmp;
}
@@ -4830,6 +4900,26 @@
switch(ast->fdno) {
case 0:
f = ast_rtp_read(p->rtp); /* RTP Audio */
+ /* If TDD mode is on, try to read TDD signals */
+ if (p->tdd && !p->tddIsSending) {
+ int c;
+ c = tdd_feed(p->tdd,f->data,f->datalen);
+ if (c < 0) {
+ ast_log(LOG_DEBUG,"tdd_feed failed\n"); /* do not do anything */
+ break;
+ }
+ if (c) { /* if a char to return - change the frame! */
+ f->subclass = AST_FORMAT_T140;
+ f->frametype = AST_FRAME_TEXT;
+ f->mallocd = 0;
+ f->offset = AST_FRIENDLY_OFFSET;
+ f->data = p->tddbuffer + AST_FRIENDLY_OFFSET;
+ f->datalen = 1;
+ *((char *) f->data) = c;
+ ast_log(LOG_DEBUG,"TTY:Baudot was able to decipher character: %c from channel %s\n",c,ast->name);
+
+ }
+ }
break;
case 1:
f = ast_rtcp_read(p->rtp); /* RTCP Control Channel */
@@ -4842,16 +4932,15 @@
break;
case 4:
f = ast_rtp_read(p->trtp); /* RTP Text */
- if (sipdebug_text) {
- int i;
- unsigned char* arr = f->data;
- for (i=0; i < f->datalen; i++)
- ast_verbose("%c", (arr[i] > ' ' && arr[i] < '}') ? arr[i] : '.');
- ast_verbose(" -> ");
- for (i=0; i < f->datalen; i++)
- ast_verbose("%02X ", arr[i]);
- ast_verbose("\n");
- }
+ int i;
+ unsigned char* arr = f->data;
+ ast_log(LOG_DEBUG,"Text received from channel %s:",ast->name);
+ for (i=0; i < f->datalen; i++)
+ ast_verbose("%c", (arr[i] > ' ' && arr[i] < '}') ? arr[i] : '.');
+ ast_verbose(" -> ");
+ for (i=0; i < f->datalen; i++)
+ ast_verbose("%02X ", arr[i]);
+ ast_verbose("\n");
break;
case 5:
f = ast_udptl_read(p->udptl); /* UDPTL for T.38 */
@@ -4881,7 +4970,7 @@
}
if (f && (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
- f = ast_dsp_process(p->owner, p->vad, f);
+ f = ast_dsp_process(p->owner, p->vad, f);
if (f && f->frametype == AST_FRAME_DTMF) {
if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_UDPTL) && f->subclass == 'f') {
ast_debug(1, "Fax CNG detected on %s\n", ast->name);
@@ -4903,6 +4992,7 @@
int faxdetected = FALSE;
sip_pvt_lock(p);
+
fr = sip_rtp_read(ast, p, &faxdetected);
p->lastrtprx = time(NULL);
@@ -5093,6 +5183,9 @@
p->t38.jointcapability = p->t38.capability;
}
ast_string_field_set(p, context, default_context);
+
+ p->tdd=NULL;
+ p->tddIsSending=0;
/* Add to active dialog list */
dialoglist_lock();
@@ -8804,8 +8897,10 @@
/* Save SIP options profile */
peer->sipoptions = pvt->sipoptions;
- if (!ast_strlen_zero(curi) && ast_strlen_zero(peer->username))
+ if (!ast_strlen_zero(curi)) /* Overwrite the default username from config at registration */
ast_copy_string(peer->username, curi, sizeof(peer->username));
+ else
+ peer->username[0] = '\0';
if (peer->expire > -1) {
ast_sched_del(sched, peer->expire);
@@ -13036,12 +13131,10 @@
static void parse_moved_contact(struct sip_pvt *p, struct sip_request *req)
{
char tmp[BUFSIZ];
- char *s, *e, *t;
+ char *s, *e;
char *domain;
ast_copy_string(tmp, get_header(req, "Contact"), sizeof(tmp));
- if ((t = strchr(tmp, ',')))
- *t = '\0';
s = remove_uri_parameters(get_in_brackets(tmp));
if (ast_test_flag(&p->flags[0], SIP_PROMISCREDIR)) {
if (!strncasecmp(s, "sip:", 4))
@@ -18962,6 +19055,140 @@
return CLI_SUCCESS;
}
+int tty_write_cb(void* data) {
+ struct sip_pvt *p=(struct sip_pvt*)data;
+ int ttysamples=176, packetsamples=160;
+// 1.6 kbytes for 200ms ulaw audio
+#define HOLDTONELEN 1600
+ int tonebufcharend = p->ttytonebufend;
+
+ if(p->ttyhasholdtone==1)
+ tonebufcharend -= HOLDTONELEN;
+ if(tonebufcharend<0)
+ tonebufcharend=0;
+ if (tonebufcharend <= ttysamples ) {
+ if (p->ttycharbuflen > 0) {
+ char texttogen[2];
+
+ texttogen[0]=p->ttycharbuf[0];
+ texttogen[1]='\0';
+ int len = tdd_generate(p->tdd, p->ttytonebuf+tonebufcharend+1, texttogen);
+ if (len < 1)
+ ast_log(LOG_DEBUG,"tdd_generate failed!\n");
+ tonebufcharend += len;
+ p->ttytonebufend = tonebufcharend;
+ p->ttycharbuflen -= 1;
+ memmove(p->ttycharbuf,p->ttycharbuf+1,p->ttycharbuflen);
+ ast_log(LOG_DEBUG,"tty text send callback. charbuf:%s\ncharbuf size:%d, tonebuf size:%d\n",p->ttycharbuf,p->ttycharbuflen,p->ttytonebufend);
+ p->ttyhasholdtone=0;
+
+ if (p->ttycharbuflen == 0) {
+ // Put in hold tone
+ tdd_gen_holdtone(p->ttytonebuf + tonebufcharend);
+ p->ttytonebufend += HOLDTONELEN;
+ p->ttyhasholdtone = 1;
+ }
+ }
+ }
+ if (p->ttytonebufend>0) {
+ int readsize;
+ if (p->ttytonebufend < packetsamples)
+ readsize = p->ttytonebufend;
+ else
+ readsize=packetsamples;
+ if(readsize>0) {
+ struct ast_frame wf = {
+ .frametype = AST_FRAME_VOICE,
+ .subclass = AST_FORMAT_ULAW,
+ .offset = AST_FRIENDLY_OFFSET,
+ .data = p->ttytonebuf + AST_FRIENDLY_OFFSET,
+ .src = __FUNCTION__,
+ .datalen = readsize,
+ .samples = readsize,
+ };
+ ast_rtp_write(p->rtp,&wf);
+ memmove(p->ttytonebuf,p->ttytonebuf+readsize,p->ttytonebufend - readsize);
+ p->ttytonebufend -= readsize;
+ if(p->ttytonebufend==0) ast_log(LOG_DEBUG,"Tone buffer empty!");
+ }
+ }
+ return 1;
+}
+
+/*! \brief Sets options, currently only for TDD support */
+static int sip_setoption(struct ast_channel *chan, int option, void* data, int datalen)
+{
+ char *cp;
+ struct sip_pvt *p = chan->tech_pvt;
+
+
+ /* all supported options require data */
+ if (!data || (datalen < 1)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (option==AST_OPTION_TDD) {
+
+ cp = (char *) data;
+ if (!*cp) { /* turn it off */
+ ast_debug(1, "Set option TDD MODE, value: OFF(0) on %s\n",chan->name);
+ if (p->tdd)
+ tdd_free(p->tdd);
+ p->tdd = 0;
+ p->didtdd=0;
+ memset( p->ttycharbuf,'\0',TTYCHARBUFLENGTH-1);
+
+ return 0;
+ }
+
+ ast_debug(1, "Set option TDD MODE, value: ON on %s\n", chan->name);
+
+ /* Add T140 to channel's format list */
+ if(p->owner) {
+ p->owner->nativeformats |= AST_FORMAT_T140;
+ }
+
+ /* turn it on */
+ if (!p->didtdd) { /* if havent done it yet */
+ p->didtdd=1;
+
+ p->ttytonebuf=ast_malloc(1024*TDD_BYTES_PER_CHAR);
+ p->ttytonebufend=0;
+ memset(p->ttycharbuf,'\0',TTYCHARBUFLENGTH-1);
+ p->ttycharbuf[0]='\0';
+ p->ttyhasholdtone=0;
+ p->vcoMode=0;
+
+ ast_sched_add(sched, 20, tty_write_cb, p);
+ }
+ if (!p->tdd) { /* if we dont have one yet */
+ p->tdd = tdd_new(); /* allocate one */
+ }
+
+ }
+ return 0;
+}
+
+/*! \brief SIP Bridge - either low-level RTP bridge or core depending on whether TDD is used or not */
+enum ast_bridge_result sip_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
+{
+
+ struct sip_pvt *p0 = (struct sip_pvt *) c0->tech_pvt;
+ struct sip_pvt *p1 = (struct sip_pvt *) c1->tech_pvt;
+
+ if( p0->tdd || p1->tdd ) {
+ ast_debug(3, "SIP Bridge: TDD mode is on, so use core bridge.\n");
+ return AST_BRIDGE_FAILED_NOWARN;
+ } else
+ return ast_rtp_bridge(c0, c1, flags, fo, rc, timeoutms);
+}
+
+
+
+
+
+
/*! \brief Part of Asterisk module interface */
static int reload(void)
{
Modified: team/oej/tdd-sip/main/channel.c
URL: http://svn.digium.com/view/asterisk/team/oej/tdd-sip/main/channel.c?view=diff&rev=89063&r1=89062&r2=89063
==============================================================================
--- team/oej/tdd-sip/main/channel.c (original)
+++ team/oej/tdd-sip/main/channel.c Tue Nov 6 15:15:49 2007
@@ -2813,15 +2813,18 @@
ast_channel_lock(chan);
CHECK_BLOCKING(chan);
break;
- case AST_FRAME_TEXT:
- if (fr->subclass == AST_FORMAT_T140) {
- res = (chan->tech->write_text == NULL) ? 0 :
- chan->tech->write_text(chan, fr);
- } else {
- res = (chan->tech->send_text == NULL) ? 0 :
- chan->tech->send_text(chan, (char *) fr->data);
- }
- break;
+ case AST_FRAME_TEXT:
+ if (fr->subclass == AST_FORMAT_T140) {
+
+ res = (chan->tech->write_text == NULL) ? 0 :
+ chan->tech->write_text(chan, fr);
+ }
+ else {
+ res = (chan->tech->send_text == NULL) ? 0 :
+ chan->tech->send_text(chan, (char *) fr->data);
+ }
+
+ break;
case AST_FRAME_HTML:
res = (chan->tech->send_html == NULL) ? 0 :
chan->tech->send_html(chan, fr->subclass, (char *) fr->data, fr->datalen);
More information about the asterisk-commits
mailing list