[svn-commits] file: branch file/t38insanity r89204 - in /team/file/t38insanity: apps/ chann...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Nov 12 18:31:30 CST 2007


Author: file
Date: Mon Nov 12 18:31:29 2007
New Revision: 89204

URL: http://svn.digium.com/view/asterisk?view=rev&rev=89204
Log:
Add in some T.38 work. This turns T.38 requesting/rejecting/accepting into control frames so that if an application wanted to it could step in the middle and handle things. Right now this works with my Sipura and is able to fall back to ULAW.

Modified:
    team/file/t38insanity/apps/app_dial.c
    team/file/t38insanity/channels/chan_sip.c
    team/file/t38insanity/include/asterisk/frame.h
    team/file/t38insanity/main/channel.c
    team/file/t38insanity/main/rtp.c

Modified: team/file/t38insanity/apps/app_dial.c
URL: http://svn.digium.com/view/asterisk/team/file/t38insanity/apps/app_dial.c?view=diff&rev=89204&r1=89203&r2=89204
==============================================================================
--- team/file/t38insanity/apps/app_dial.c (original)
+++ team/file/t38insanity/apps/app_dial.c Mon Nov 12 18:31:29 2007
@@ -724,6 +724,18 @@
 					ast_verb(3, "Call on %s left from hold\n", c->name);
 					ast_indicate(in, AST_CONTROL_UNHOLD);
 					break;
+				case AST_CONTROL_T38_REQUEST:
+					ast_verb(3, "%s requested T.38 capabilities, passing it to %s\n", c->name, in->name);
+					ast_indicate(in, AST_CONTROL_T38_REQUEST);
+					break;
+				case AST_CONTROL_T38_REJECT:
+					ast_verb(3, "%s rejected T.38 request, passing it to %s\n", c->name, in->name);
+					ast_indicate(in, AST_CONTROL_T38_REJECT);
+					break;
+				case AST_CONTROL_T38_ACCEPT:
+					ast_verb(3, "%s accepted T.38 request, passing it to %s\n", c->name, in->name);
+					ast_indicate(in, AST_CONTROL_T38_ACCEPT);
+					break;
 				case AST_CONTROL_OFFHOOK:
 				case AST_CONTROL_FLASH:
 					/* Ignore going off hook and flash */
@@ -813,7 +825,10 @@
 			if (single && (f->frametype == AST_FRAME_CONTROL) && 
 				((f->subclass == AST_CONTROL_HOLD) || 
 				 (f->subclass == AST_CONTROL_UNHOLD) || 
-				 (f->subclass == AST_CONTROL_VIDUPDATE))) {
+				 (f->subclass == AST_CONTROL_VIDUPDATE) ||
+				 (f->subclass == AST_CONTROL_T38_REQUEST) ||
+				 (f->subclass == AST_CONTROL_T38_REJECT) ||
+				 (f->subclass == AST_CONTROL_T38_ACCEPT))) {
 				ast_verb(3, "%s requested special control %d, passing it to %s\n", in->name, f->subclass, outgoing->chan->name);
 				ast_indicate_data(outgoing->chan, f->subclass, f->data, f->datalen);
 			}

Modified: team/file/t38insanity/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/file/t38insanity/channels/chan_sip.c?view=diff&rev=89204&r1=89203&r2=89204
==============================================================================
--- team/file/t38insanity/channels/chan_sip.c (original)
+++ team/file/t38insanity/channels/chan_sip.c Mon Nov 12 18:31:29 2007
@@ -1783,7 +1783,6 @@
 static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p, int *faxdetect);
 
 /*------ T38 Support --------- */
-static int sip_handle_t38_reinvite(struct ast_channel *chan, struct sip_pvt *pvt, int reinvite); 
 static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans);
 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);
@@ -4498,6 +4497,21 @@
 			/* ast_rtcp_send_h261fur(p->vrtp); */
 		} else
 			res = -1;
+		break;
+	case AST_CONTROL_T38_REQUEST:
+		/* If we have T38 support enabled send out a T.38 reinvite, otherwise reject this */
+		if (p->udptl)
+			transmit_reinvite_with_sdp(p, TRUE);
+		else
+			ast_queue_control(p->owner, AST_CONTROL_T38_REJECT);
+		break;
+	case AST_CONTROL_T38_REJECT:
+		/* Reject the T.38 offer coming in */
+		ast_log(LOG_NOTICE, "Dude reject the offer\n");
+		break;
+	case AST_CONTROL_T38_ACCEPT:
+		/* The other side has accepted our T.38 request, thus we ourselves can push back T.38 */
+		ast_log(LOG_NOTICE, "Accept T.38 on %s\n", ast->name);
 		break;
 	case -1:
 		res = -1;
@@ -13133,7 +13147,6 @@
 	int res = 0;
 	int xmitres = 0;
 	int reinvite = (p->owner && p->owner->_state == AST_STATE_UP);
-	struct ast_channel *bridgepeer = NULL;
 	
 	if (reinvite)
 		ast_debug(4, "SIP response %d to RE-invite on %s call %s\n", resp, outgoing ? "outgoing" : "incoming", p->callid);
@@ -13244,49 +13257,8 @@
 			/* Save Record-Route for any later requests we make on this dialogue */
 			build_route(p, req, 1);
 		}
-		
-		if (p->owner && (p->owner->_state == AST_STATE_UP) && (bridgepeer = ast_bridged_channel(p->owner))) { /* if this is a re-invite */
-			struct sip_pvt *bridgepvt = NULL;
-
-			if (!bridgepeer->tech) {
-				ast_log(LOG_WARNING, "Ooooh.. no tech!  That's REALLY bad\n");
-				break;
-			}
-			if (IS_SIP_TECH(bridgepeer->tech)) {
-				bridgepvt = (struct sip_pvt*)(bridgepeer->tech_pvt);
-				if (bridgepvt->udptl) {
-					if (p->t38.state == T38_PEER_REINVITE) {
-						sip_handle_t38_reinvite(bridgepeer, p, 0);
-						ast_rtp_set_rtptimers_onhold(p->rtp);
-						if (p->vrtp)
-							ast_rtp_set_rtptimers_onhold(p->vrtp);	/* Turn off RTP timers while we send fax */
-					} else if (p->t38.state == T38_DISABLED && bridgepeer && (bridgepvt->t38.state == T38_ENABLED)) {
-						ast_log(LOG_WARNING, "RTP re-invite after T38 session not handled yet !\n");
-						/* Insted of this we should somehow re-invite the other side of the bridge to RTP */
-						/* XXXX Should we really destroy this session here, without any response at all??? */
-						sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
-					}
-				} else {
-					ast_debug(2, "Strange... The other side of the bridge does not have a udptl struct\n");
-					sip_pvt_lock(bridgepvt);
-					bridgepvt->t38.state = T38_DISABLED;
-					sip_pvt_unlock(bridgepvt);
-					ast_debug(1,"T38 state changed to %d on channel %s\n", bridgepvt->t38.state, bridgepeer->tech->type);
-					p->t38.state = T38_DISABLED;
-					ast_debug(2,"T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
-				}
-			} else {
-				/* Other side is not a SIP channel */
-				ast_debug(2, "Strange... The other side of the bridge is not a SIP channel\n");
-				p->t38.state = T38_DISABLED;
-				ast_debug(2,"T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
-			}
-		}
-		if ((p->t38.state == T38_LOCAL_REINVITE) || (p->t38.state == T38_LOCAL_DIRECT)) {
-			/* If there was T38 reinvite and we are supposed to answer with 200 OK than this should set us to T38 negotiated mode */
-			p->t38.state = T38_ENABLED;
-			ast_debug(1, "T38 changed state to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
-		}
+
+		/* Check for T.38 stuff */
 
 		if (!req->ignore && p->owner) {
 			if (!reinvite) {
@@ -13376,24 +13348,12 @@
 		break;
 	case 488: /* Not acceptable here */
 		xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
+		/* If this was a reinvite to T.38, reject things and return to audio */
 		if (reinvite && p->udptl) {
-			/* If this is a T.38 call, we should go back to 
-			   audio. If this is an audio call - something went
-			   terribly wrong since we don't renegotiate codecs,
-			   only IP/port .
-			*/
-			p->t38.state = T38_DISABLED;
-			/* Try to reset RTP timers */
-			ast_rtp_set_rtptimers_onhold(p->rtp);
-			ast_log(LOG_ERROR, "Got error on T.38 re-invite. Bad configuration. Peer needs to have T.38 disabled.\n");
-
-			/*! \bug Is there any way we can go back to the audio call on both
-			   sides here? 
-			*/
-			/* While figuring that out, hangup the call */
-			if (p->owner && !req->ignore)
-				ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
-			p->needdestroy = 1;
+			/* Send back a T.38 reject frame */
+			ast_queue_control(p->owner, AST_CONTROL_T38_REJECT);
+			/* Set it up with audio now */
+			transmit_reinvite_with_sdp(p, FALSE);
 		} else {
 			/* We can't set up this call, so give up */
 			if (p->owner && !req->ignore)
@@ -15073,82 +15033,15 @@
 
 			transmit_response(p, "100 Trying", req);
 
+			/* See if the remote side has performed a reinvite to T38, if so accept it and request that the other side setup T38 */
 			if (p->t38.state == T38_PEER_REINVITE) {
-				struct ast_channel *bridgepeer = NULL;
-				struct sip_pvt *bridgepvt = NULL;
-				
-				if ((bridgepeer = ast_bridged_channel(p->owner))) {
-					/* We have a bridge, and this is re-invite to switchover to T38 so we send re-invite with T38 SDP, to other side of bridge*/
-					/*! XXX: we should also check here does the other side supports t38 at all !!! XXX */
-					if (IS_SIP_TECH(bridgepeer->tech)) {
-						bridgepvt = (struct sip_pvt*)bridgepeer->tech_pvt;
-						if (bridgepvt->t38.state == T38_DISABLED) {
-							if (bridgepvt->udptl) { /* If everything is OK with other side's udptl struct */
-								/* Send re-invite to the bridged channel */
-								sip_handle_t38_reinvite(bridgepeer, p, 1);
-							} else { /* Something is wrong with peers udptl struct */
-								ast_log(LOG_WARNING, "Strange... The other side of the bridge don't have udptl struct\n");
-								sip_pvt_lock(bridgepvt);
-								bridgepvt->t38.state = T38_DISABLED;
-								sip_pvt_unlock(bridgepvt);
-								ast_debug(2,"T38 state changed to %d on channel %s\n", bridgepvt->t38.state, bridgepeer->name);
-								if (req->ignore)
-									transmit_response(p, "488 Not acceptable here", req);
-								else
-									transmit_response_reliable(p, "488 Not acceptable here", req);
-							
-							}
-						} else {
-							/* The other side is already setup for T.38 most likely so we need to acknowledge this too */
-							transmit_response_with_t38_sdp(p, "200 OK", req, XMIT_CRITICAL);
-							p->t38.state = T38_ENABLED;
-							ast_debug(1, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
-						}
-					} else {
-						/* Other side is not a SIP channel */
-						if (req->ignore)
-							transmit_response(p, "488 Not acceptable here", req);
-						else
-							transmit_response_reliable(p, "488 Not acceptable here", req);
-						p->t38.state = T38_DISABLED;
-						ast_debug(2,"T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
-
-						if (!p->lastinvite) /* Only destroy if this is *not* a re-invite */
-							sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
-					}
-				} else {
-					/* we are not bridged in a call */
-					transmit_response_with_t38_sdp(p, "200 OK", req, XMIT_CRITICAL);
-					p->t38.state = T38_ENABLED;
-					ast_debug(1,"T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
-				}
-			} else if (p->t38.state == T38_DISABLED) { /* Channel doesn't have T38 offered or enabled */
-				int sendok = TRUE;
-
-				/* If we are bridged to a channel that has T38 enabled than this is a case of RTP re-invite after T38 session */
-				/* so handle it here (re-invite other party to RTP) */
-				struct ast_channel *bridgepeer = NULL;
-				struct sip_pvt *bridgepvt = NULL;
-				if ((bridgepeer = ast_bridged_channel(p->owner))) {
-					if (IS_SIP_TECH(bridgepeer->tech)) {
-						bridgepvt = (struct sip_pvt*)bridgepeer->tech_pvt;
-						/* Does the bridged peer have T38 ? */
-						if (bridgepvt->t38.state == T38_ENABLED) {
-							ast_log(LOG_WARNING, "RTP re-invite after T38 session not handled yet !\n");
-							/* Insted of this we should somehow re-invite the other side of the bridge to RTP */
-							if (req->ignore)
-								transmit_response(p, "488 Not Acceptable Here (unsupported)", req);
-							else
-								transmit_response_reliable(p, "488 Not Acceptable Here (unsupported)", req);
-							sendok = FALSE;
-						} 
-						/* No bridged peer with T38 enabled*/
-					}
-				} 
-				/* Respond to normal re-invite */
-				if (sendok)
-					/* If this is not a re-invite or something to ignore - it's critical */
-					transmit_response_with_sdp(p, "200 OK", req, (reinvite || req->ignore) ?  XMIT_UNRELIABLE : XMIT_CRITICAL);
+				/* Queue up a control frame for the other side to know we want T38 */
+				ast_queue_control(p->owner, AST_CONTROL_T38_REQUEST);
+				/* If the other side does not respond in a reasonable amount of time reject this reinvite */
+				ast_log(LOG_NOTICE, "Requesting that the other side switch to T.38\n");
+			} else {
+				/* If this is not a re-invite or something to ignore - it's critical */
+				transmit_response_with_sdp(p, "200 OK", req, (reinvite || req->ignore) ?  XMIT_UNRELIABLE : XMIT_CRITICAL);
 			}
 			p->invitestate = INV_TERMINATED;
 			break;
@@ -18493,85 +18386,6 @@
 	return 0;
 }
 
-/*! \brief Handle T38 reinvite 
-	\todo Make sure we don't destroy the call if we can't handle the re-invite. 
-	Nothing should be changed until we have processed the SDP and know that we
-	can handle it.
-*/
-static int sip_handle_t38_reinvite(struct ast_channel *chan, struct sip_pvt *pvt, int reinvite)
-{
-	struct sip_pvt *p;
-	int flag = 0;
-	
-	p = chan->tech_pvt;
-	if (!p || !pvt->udptl)
-		return -1;
-	
-	/* Setup everything on the other side like offered/responded from first side */
-	sip_pvt_lock(p);
-
-	/*! \todo check if this is not set earlier when setting up the PVT. If not
-		maybe it should move there. */
-	p->t38.jointcapability = p->t38.peercapability = pvt->t38.jointcapability;
-
-	ast_udptl_set_far_max_datagram(p->udptl, ast_udptl_get_local_max_datagram(pvt->udptl));
-	ast_udptl_set_local_max_datagram(p->udptl, ast_udptl_get_local_max_datagram(pvt->udptl));
-	ast_udptl_set_error_correction_scheme(p->udptl, ast_udptl_get_error_correction_scheme(pvt->udptl));
-	
-	if (reinvite) {		/* If we are handling sending re-invite to the other side of the bridge */
-		/*! \note The SIP_CAN_REINVITE flag is for RTP media redirects,
-			not really T38 re-invites which are different. In this
-			case it's used properly, to see if we can reinvite over
-			NAT 
-		*/
-		if (ast_test_flag(&p->flags[0], SIP_CAN_REINVITE) && ast_test_flag(&pvt->flags[0], SIP_CAN_REINVITE)) {
-			ast_udptl_get_peer(pvt->udptl, &p->udptlredirip);
-			flag =1;
-		} else {
-			memset(&p->udptlredirip, 0, sizeof(p->udptlredirip));
-		}
-		if (!ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
-			if (!p->pendinginvite) {
-				if (flag)
-					ast_debug(3, "Sending reinvite on SIP '%s' - It's UDPTL soon redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(p->udptlredirip.sin_addr), ntohs(p->udptlredirip.sin_port));
-				else
-					ast_debug(3, "Sending reinvite on SIP '%s' - It's UDPTL soon redirected to us (IP %s)\n", p->callid, ast_inet_ntoa(p->ourip.sin_addr));
-				transmit_reinvite_with_sdp(p, TRUE);
-			} else if (!ast_test_flag(&p->flags[0], SIP_PENDINGBYE)) {
-				if (flag)
-					ast_debug(3, "Deferring reinvite on SIP '%s' - It's UDPTL will be redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(p->udptlredirip.sin_addr), ntohs(p->udptlredirip.sin_port));
-				else
-					ast_debug(3, "Deferring reinvite on SIP '%s' - It's UDPTL will be redirected to us (IP %s)\n", p->callid, ast_inet_ntoa(p->ourip.sin_addr));
-				ast_set_flag(&p->flags[0], SIP_NEEDREINVITE);
-			}
-		}
-		/* Reset lastrtprx timer */
-		p->lastrtprx = p->lastrtptx = time(NULL);
-		sip_pvt_unlock(p);
-		return 0;
-	} else {	/* If we are handling sending 200 OK to the other side of the bridge */
-		if (ast_test_flag(&p->flags[0], SIP_CAN_REINVITE) && ast_test_flag(&pvt->flags[0], SIP_CAN_REINVITE)) {
-			ast_udptl_get_peer(pvt->udptl, &p->udptlredirip);
-			flag = 1;
-		} else {
-			memset(&p->udptlredirip, 0, sizeof(p->udptlredirip));
-		}
-		if (flag)
-			ast_debug(3, "Responding 200 OK on SIP '%s' - It's UDPTL soon redirected to IP %s:%d\n", p->callid, ast_inet_ntoa(p->udptlredirip.sin_addr), ntohs(p->udptlredirip.sin_port));
-		else
-			ast_debug(3, "Responding 200 OK on SIP '%s' - It's UDPTL soon redirected to us (IP %s)\n", p->callid, ast_inet_ntoa(p->ourip.sin_addr));
-		pvt->t38.state = T38_ENABLED;
-		p->t38.state = T38_ENABLED;
-		ast_debug(2, "T38 changed state to %d on channel %s\n", pvt->t38.state, pvt->owner ? pvt->owner->name : "<none>");
-		ast_debug(2, "T38 changed state to %d on channel %s\n", p->t38.state, chan ? chan->name : "<none>");
-		transmit_response_with_t38_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
-		p->lastrtprx = p->lastrtptx = time(NULL);
-		sip_pvt_unlock(p);
-		return 0;
-	}
-}
-
-
 /*! \brief Returns null if we can't reinvite audio (part of RTP interface) */
 static enum ast_rtp_get_result sip_get_rtp_peer(struct ast_channel *chan, struct ast_rtp **rtp)
 {

Modified: team/file/t38insanity/include/asterisk/frame.h
URL: http://svn.digium.com/view/asterisk/team/file/t38insanity/include/asterisk/frame.h?view=diff&rev=89204&r1=89203&r2=89204
==============================================================================
--- team/file/t38insanity/include/asterisk/frame.h (original)
+++ team/file/t38insanity/include/asterisk/frame.h Mon Nov 12 18:31:29 2007
@@ -285,6 +285,9 @@
 	AST_CONTROL_HOLD = 16,		/*!< Indicate call is placed on hold */
 	AST_CONTROL_UNHOLD = 17,	/*!< Indicate call is left from hold */
 	AST_CONTROL_VIDUPDATE = 18,	/*!< Indicate video frame update */
+	AST_CONTROL_T38_REQUEST = 19,   /*!< Request a T.38 session */
+	AST_CONTROL_T38_REJECT = 20,    /*!< Reject a T.38 session */
+	AST_CONTROL_T38_ACCEPT = 21,    /*!< Accept a T.38 session */
 };
 
 #define AST_SMOOTHER_FLAG_G729		(1 << 0)

Modified: team/file/t38insanity/main/channel.c
URL: http://svn.digium.com/view/asterisk/team/file/t38insanity/main/channel.c?view=diff&rev=89204&r1=89203&r2=89204
==============================================================================
--- team/file/t38insanity/main/channel.c (original)
+++ team/file/t38insanity/main/channel.c Mon Nov 12 18:31:29 2007
@@ -1540,7 +1540,7 @@
 
 int ast_answer(struct ast_channel *chan)
 {
-	return __ast_answer(chan, 500);
+	return __ast_answer(chan, 0);
 }
 
 void ast_deactivate_generator(struct ast_channel *chan)
@@ -2508,6 +2508,7 @@
 		chan->generator->digit(chan, f->subclass);
 
 	ast_channel_unlock(chan);
+
 	return f;
 }
 
@@ -3964,6 +3965,9 @@
 			case AST_CONTROL_HOLD:
 			case AST_CONTROL_UNHOLD:
 			case AST_CONTROL_VIDUPDATE:
+			case AST_CONTROL_T38_REQUEST:
+			case AST_CONTROL_T38_REJECT:
+			case AST_CONTROL_T38_ACCEPT:
 				ast_indicate_data(other, f->subclass, f->data, f->datalen);
 				break;
 			default:

Modified: team/file/t38insanity/main/rtp.c
URL: http://svn.digium.com/view/asterisk/team/file/t38insanity/main/rtp.c?view=diff&rev=89204&r1=89203&r2=89204
==============================================================================
--- team/file/t38insanity/main/rtp.c (original)
+++ team/file/t38insanity/main/rtp.c Mon Nov 12 18:31:29 2007
@@ -3327,7 +3327,10 @@
 		} else if ((fr->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
 			if ((fr->subclass == AST_CONTROL_HOLD) ||
 			    (fr->subclass == AST_CONTROL_UNHOLD) ||
-			    (fr->subclass == AST_CONTROL_VIDUPDATE)) {
+			    (fr->subclass == AST_CONTROL_VIDUPDATE) ||
+			    (fr->subclass == AST_CONTROL_T38_REQUEST) ||
+			    (fr->subclass == AST_CONTROL_T38_REJECT) ||
+			    (fr->subclass == AST_CONTROL_T38_ACCEPT)) {
 				if (fr->subclass == AST_CONTROL_HOLD) {
 					/* If we someone went on hold we want the other side to reinvite back to us */
 					if (who == c0)
@@ -3561,7 +3564,10 @@
 		} else if ((fr->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
 			if ((fr->subclass == AST_CONTROL_HOLD) ||
 			    (fr->subclass == AST_CONTROL_UNHOLD) ||
-			    (fr->subclass == AST_CONTROL_VIDUPDATE)) {
+			    (fr->subclass == AST_CONTROL_VIDUPDATE) ||
+			    (fr->subclass == AST_CONTROL_T38_REQUEST) ||
+			    (fr->subclass == AST_CONTROL_T38_REJECT) ||
+			    (fr->subclass == AST_CONTROL_T38_ACCEPT)) {
 				/* If we are going on hold, then break callback mode and P2P bridging */
 				if (fr->subclass == AST_CONTROL_HOLD) {
 					if (p0_callback)




More information about the svn-commits mailing list