[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