[svn-commits] oej: branch oej/realtimetext-t140 r48260 - in /team/oej/realtimetext-t140: ./...

svn-commits at lists.digium.com svn-commits at lists.digium.com
Tue Dec 5 04:20:22 MST 2006


Author: oej
Date: Tue Dec  5 05:20:22 2006
New Revision: 48260

URL: http://svn.digium.com/view/asterisk?view=rev&rev=48260
Log:
Update to trunk, add line to CHANGES

Removed:
    team/oej/realtimetext-t140/main/coef_in.h
    team/oej/realtimetext-t140/main/coef_out.h
Modified:
    team/oej/realtimetext-t140/   (props changed)
    team/oej/realtimetext-t140/.cleancount
    team/oej/realtimetext-t140/CHANGES
    team/oej/realtimetext-t140/Makefile
    team/oej/realtimetext-t140/agi/Makefile
    team/oej/realtimetext-t140/apps/app_dial.c
    team/oej/realtimetext-t140/apps/app_sms.c
    team/oej/realtimetext-t140/apps/app_voicemail.c
    team/oej/realtimetext-t140/channels/chan_sip.c
    team/oej/realtimetext-t140/configs/extensions.conf.sample
    team/oej/realtimetext-t140/configs/sip.conf.sample
    team/oej/realtimetext-t140/configs/voicemail.conf.sample
    team/oej/realtimetext-t140/configure
    team/oej/realtimetext-t140/configure.ac
    team/oej/realtimetext-t140/doc/snmp.txt
    team/oej/realtimetext-t140/include/asterisk/frame.h
    team/oej/realtimetext-t140/include/asterisk/rtp.h
    team/oej/realtimetext-t140/include/asterisk/threadstorage.h
    team/oej/realtimetext-t140/main/callerid.c
    team/oej/realtimetext-t140/main/channel.c
    team/oej/realtimetext-t140/main/cli.c
    team/oej/realtimetext-t140/main/frame.c
    team/oej/realtimetext-t140/main/fskmodem.c
    team/oej/realtimetext-t140/main/rtp.c
    team/oej/realtimetext-t140/main/tdd.c
    team/oej/realtimetext-t140/makeopts.in
    team/oej/realtimetext-t140/sounds/Makefile

Propchange: team/oej/realtimetext-t140/
------------------------------------------------------------------------------
Binary property 'branch-1.4-blocked' - no diff available.

Propchange: team/oej/realtimetext-t140/
------------------------------------------------------------------------------
Binary property 'branch-1.4-merged' - no diff available.

Propchange: team/oej/realtimetext-t140/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Tue Dec  5 05:20:22 2006
@@ -1,1 +1,1 @@
-/trunk:1-48172
+/trunk:1-48259

Modified: team/oej/realtimetext-t140/.cleancount
URL: http://svn.digium.com/view/asterisk/team/oej/realtimetext-t140/.cleancount?view=diff&rev=48260&r1=48259&r2=48260
==============================================================================
--- team/oej/realtimetext-t140/.cleancount (original)
+++ team/oej/realtimetext-t140/.cleancount Tue Dec  5 05:20:22 2006
@@ -1,1 +1,1 @@
-26
+27

Modified: team/oej/realtimetext-t140/CHANGES
URL: http://svn.digium.com/view/asterisk/team/oej/realtimetext-t140/CHANGES?view=diff&rev=48260&r1=48259&r2=48260
==============================================================================
--- team/oej/realtimetext-t140/CHANGES (original)
+++ team/oej/realtimetext-t140/CHANGES Tue Dec  5 05:20:22 2006
@@ -63,3 +63,4 @@
      does not count paused queue members as unavailable.
   * Added maxfiles option to options section of asterisk.conf which allows you to specify
      what Asterisk should set as the maximum number of open files when it loads.
+  * Added support for T.140 realtime text in SIP/RTP

Modified: team/oej/realtimetext-t140/Makefile
URL: http://svn.digium.com/view/asterisk/team/oej/realtimetext-t140/Makefile?view=diff&rev=48260&r1=48259&r2=48260
==============================================================================
--- team/oej/realtimetext-t140/Makefile (original)
+++ team/oej/realtimetext-t140/Makefile Tue Dec  5 05:20:22 2006
@@ -57,6 +57,7 @@
 export PROC
 export SOLINK
 export STRIP
+export DOWNLOAD
 
 # even though we could use '-include makeopts' here, use a wildcard
 # lookup anyway, so that make won't try to build makeopts if it doesn't
@@ -273,14 +274,14 @@
 	@echo " + Asterisk has successfully been built, and +"  
 	@echo " + can be installed by running:              +"
 	@echo " +                                           +"
-	@echo " +               make install                +"  
+	@echo " +               $(MAKE) install                +"  
 	@echo " +-------------------------------------------+"  
 
 _all: cleantest $(SUBDIRS)
 
 makeopts: configure
 	@echo "****"
-	@echo "**** The configure script must be executed before running 'make'."
+	@echo "**** The configure script must be executed before running '$(MAKE)'."
 	@echo "****"
 	@exit 1
 

Modified: team/oej/realtimetext-t140/agi/Makefile
URL: http://svn.digium.com/view/asterisk/team/oej/realtimetext-t140/agi/Makefile?view=diff&rev=48260&r1=48259&r2=48260
==============================================================================
--- team/oej/realtimetext-t140/agi/Makefile (original)
+++ team/oej/realtimetext-t140/agi/Makefile Tue Dec  5 05:20:22 2006
@@ -21,7 +21,7 @@
 
 include $(ASTTOPDIR)/Makefile.rules
 
-all: #$(AGIS)
+all: $(AGIS)
 
 strcompat.c: ../main/strcompat.c
 	@cp $< $@

Modified: team/oej/realtimetext-t140/apps/app_dial.c
URL: http://svn.digium.com/view/asterisk/team/oej/realtimetext-t140/apps/app_dial.c?view=diff&rev=48260&r1=48259&r2=48260
==============================================================================
--- team/oej/realtimetext-t140/apps/app_dial.c (original)
+++ team/oej/realtimetext-t140/apps/app_dial.c Tue Dec  5 05:20:22 2006
@@ -1430,6 +1430,7 @@
 		if (ast_test_flag(outgoing, OPT_MUSICBACK)) {
 			moh = 1;
 			ast_moh_start(chan, opt_args[OPT_ARG_MUSICBACK], NULL);
+			ast_indicate(chan, AST_CONTROL_PROGRESS);
 		} else if (ast_test_flag(outgoing, OPT_RINGBACK)) {
 			ast_indicate(chan, AST_CONTROL_RINGING);
 			sentringing++;

Modified: team/oej/realtimetext-t140/apps/app_sms.c
URL: http://svn.digium.com/view/asterisk/team/oej/realtimetext-t140/apps/app_sms.c?view=diff&rev=48260&r1=48259&r2=48260
==============================================================================
--- team/oej/realtimetext-t140/apps/app_sms.c (original)
+++ team/oej/realtimetext-t140/apps/app_sms.c Tue Dec  5 05:20:22 2006
@@ -119,59 +119,59 @@
 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 };
 
-#define SMSLEN 160              /* max SMS length */
+#define SMSLEN 160              /*!< max SMS length */
 
 typedef struct sms_s
 {
-	unsigned char hangup;        /* we are done... */
-	unsigned char err;           /* set for any errors */
-	unsigned char smsc:1;        /* we are SMSC */
-	unsigned char rx:1;          /* this is a received message */
-	char queue[30];              /* queue name */
-	char oa[20];                 /* originating address */
-	char da[20];                 /* destination address */
-	time_t scts;                 /* time stamp, UTC */
-	unsigned char pid;           /* protocol ID */
-	unsigned char dcs;           /* data coding scheme */
-	short mr;                    /* message reference - actually a byte, but usde -1 for not set */
-	int udl;                     /* user data length */
-	int udhl;                    /* user data header length */
-	unsigned char srr:1;         /* Status Report request */
-	unsigned char udhi:1;        /* User Data Header required, even if length 0 */
-	unsigned char rp:1;          /* Reply Path */
-	unsigned int vp;             /* validity period in minutes, 0 for not set */
-	unsigned short ud[SMSLEN];   /* user data (message), UCS-2 coded */
-	unsigned char udh[SMSLEN];   /* user data header */
-	char cli[20];                /* caller ID */
-	unsigned char ophase;        /* phase (0-79) for 0 and 1 frequencies (1300Hz and 2100Hz) */
-	unsigned char ophasep;       /* phase (0-79) for 1200 bps */
-	unsigned char obyte;         /* byte being sent */
-	unsigned int opause;         /* silent pause before sending (in sample periods) */
-	unsigned char obitp;         /* bit in byte */
-	unsigned char osync;         /* sync bits to send */
-	unsigned char obytep;        /* byte in data */
-	unsigned char obyten;        /* bytes in data */
-	unsigned char omsg[256];     /* data buffer (out) */
-	unsigned char imsg[200];     /* data buffer (in) */
+	unsigned char hangup;        /*!< we are done... */
+	unsigned char err;           /*!< set for any errors */
+	unsigned char smsc:1;        /*!< we are SMSC */
+	unsigned char rx:1;          /*!< this is a received message */
+	char queue[30];              /*!< queue name */
+	char oa[20];                 /*!< originating address */
+	char da[20];                 /*!< destination address */
+	time_t scts;                 /*!< time stamp, UTC */
+	unsigned char pid;           /*!< protocol ID */
+	unsigned char dcs;           /*!< data coding scheme */
+	short mr;                    /*!< message reference - actually a byte, but usde -1 for not set */
+	int udl;                     /*!< user data length */
+	int udhl;                    /*!< user data header length */
+	unsigned char srr:1;         /*!< Status Report request */
+	unsigned char udhi:1;        /*!< User Data Header required, even if length 0 */
+	unsigned char rp:1;          /*!< Reply Path */
+	unsigned int vp;             /*!< validity period in minutes, 0 for not set */
+	unsigned short ud[SMSLEN];   /*!< user data (message), UCS-2 coded */
+	unsigned char udh[SMSLEN];   /*!< user data header */
+	char cli[20];                /*!< caller ID */
+	unsigned char ophase;        /*!< phase (0-79) for 0 and 1 frequencies (1300Hz and 2100Hz) */
+	unsigned char ophasep;       /*!< phase (0-79) for 1200 bps */
+	unsigned char obyte;         /*!< byte being sent */
+	unsigned int opause;         /*!< silent pause before sending (in sample periods) */
+	unsigned char obitp;         /*!< bit in byte */
+	unsigned char osync;         /*!< sync bits to send */
+	unsigned char obytep;        /*!< byte in data */
+	unsigned char obyten;        /*!< bytes in data */
+	unsigned char omsg[256];     /*!< data buffer (out) */
+	unsigned char imsg[200];     /*!< data buffer (in) */
 	signed long long ims0,
 		imc0,
 		ims1,
-		imc1;                      /* magnitude averages sin/cos 0/1 */
+		imc1;                      /*!< magnitude averages sin/cos 0/1 */
 	unsigned int idle;
-	unsigned short imag;         /* signal level */
+	unsigned short imag;         /*!< signal level */
 	unsigned char ips0,
 		ips1,
 		ipc0,
-		ipc1;                      /* phase sin/cos 0/1 */
-	unsigned char ibitl;         /* last bit */
-	unsigned char ibitc;         /* bit run length count */
-	unsigned char iphasep;       /* bit phase (0-79) for 1200 bps */
-	unsigned char ibitn;         /* bit number in byte being received */
-	unsigned char ibytev;        /* byte value being received */
-	unsigned char ibytep;        /* byte pointer in messafe */
-	unsigned char ibytec;        /* byte checksum for message */
-	unsigned char ierr;          /* error flag */
-	unsigned char ibith;         /* history of last bits */
+		ipc1;                      /*!< phase sin/cos 0/1 */
+	unsigned char ibitl;         /*!< last bit */
+	unsigned char ibitc;         /*!< bit run length count */
+	unsigned char iphasep;       /*!< bit phase (0-79) for 1200 bps */
+	unsigned char ibitn;         /*!< bit number in byte being received */
+	unsigned char ibytev;        /*!< byte value being received */
+	unsigned char ibytep;        /*!< byte pointer in messafe */
+	unsigned char ibytec;        /*!< byte checksum for message */
+	unsigned char ierr;          /*!< error flag */
+	unsigned char ibith;         /*!< history of last bits */
 	unsigned char ibitt;         /* total of 1's in last 3 bites */
 	/* more to go here */
 } sms_t;

Modified: team/oej/realtimetext-t140/apps/app_voicemail.c
URL: http://svn.digium.com/view/asterisk/team/oej/realtimetext-t140/apps/app_voicemail.c?view=diff&rev=48260&r1=48259&r2=48260
==============================================================================
--- team/oej/realtimetext-t140/apps/app_voicemail.c (original)
+++ team/oej/realtimetext-t140/apps/app_voicemail.c Tue Dec  5 05:20:22 2006
@@ -142,6 +142,7 @@
 /* Don't modify these here; set your umask at runtime instead */
 #define	VOICEMAIL_DIR_MODE	0777
 #define	VOICEMAIL_FILE_MODE	0666
+#define	CHUNKSIZE	65536
 
 #define VOICEMAIL_CONFIG "voicemail.conf"
 #define ASTERISK_USERNAME "asterisk"
@@ -1099,6 +1100,7 @@
 				goto yuck;
 			}
 			if (!strcasecmp(coltitle, "recording")) {
+				off_t offset;
 				res = SQLGetData(stmt, x + 1, SQL_BINARY, NULL, 0, &colsize2);
 				fdlen = colsize2;
 				if (fd > -1) {
@@ -1109,24 +1111,27 @@
 						fd = -1;
 						continue;
 					}
-					if (fd > -1) {
-						if ((fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == -1) {
+					/* Read out in small chunks */
+					for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
+						/* +1 because SQLGetData likes null-terminating binary data */
+						if ((fdm = mmap(NULL, CHUNKSIZE + 1, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == (void *)-1) {
 							ast_log(LOG_WARNING, "Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
 							SQLFreeHandle(SQL_HANDLE_STMT, stmt);
 							ast_odbc_release_obj(obj);
 							goto yuck;
+						} else {
+							res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE + 1, NULL);
+							munmap(fdm, 0);
+							if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+								ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
+								unlink(full_fn);
+								SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+								ast_odbc_release_obj(obj);
+								goto yuck;
+							}
 						}
 					}
-				}
-				if (fdm) {
-					memset(fdm, 0, fdlen);
-					res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, fdlen, &colsize2);
-					if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-						ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
-						SQLFreeHandle (SQL_HANDLE_STMT, stmt);
-						ast_odbc_release_obj(obj);
-						goto yuck;
-					}
+					truncate(full_fn, fdlen);
 				}
 			} else {
 				res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
@@ -1147,8 +1152,6 @@
 yuck:	
 	if (f)
 		fclose(f);
-	if (fdm)
-		munmap(fdm, fdlen);
 	if (fd > -1)
 		close(fd);
 	return x - 1;
@@ -8003,6 +8006,8 @@
 				if (option_verbose > 2)
 					ast_verbose(VERBOSE_PREFIX_3 "Saving message as is\n");
 				ast_stream_and_wait(chan, "vm-msgsaved", "");
+				STORE(recordfile, vmu->mailbox, vmu->context, -1, chan, vmu, fmt, duration, vms);
+				DISPOSE(recordfile, -1);
 				cmd = 't';
 				return res;
 			}

Modified: team/oej/realtimetext-t140/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/oej/realtimetext-t140/channels/chan_sip.c?view=diff&rev=48260&r1=48259&r2=48260
==============================================================================
--- team/oej/realtimetext-t140/channels/chan_sip.c (original)
+++ team/oej/realtimetext-t140/channels/chan_sip.c Tue Dec  5 05:20:22 2006
@@ -242,15 +242,15 @@
 	\note this is for the INVITE that sets up the dialog
 */
 enum invitestates {
-	INV_NONE = 0,	/*!< No state at all, maybe not an INVITE dialog */
-	INV_CALLING,	/*!< Invite sent, no answer */
-	INV_PROCEEDING,	/*!< We got 1xx message */
-	INV_EARLY_MEDIA, /*!< We got 18x message with to-tag back */
-	INV_COMPLETED,	/*!< Got final response with error. Wait for ACK, then CONFIRMED */
-	INV_CONFIRMED,	/*!< Confirmed response - we've got an ack (Incoming calls only) */
-	INV_TERMINATED,	/*!< Transaction done - either successful (AST_STATE_UP) or failed, but done 
-				The only way out of this is a BYE from one side */
-	INV_CANCELLED	/*!< Transaction cancelled by client or server in non-terminated state */
+	INV_NONE = 0,	        /*!< No state at all, maybe not an INVITE dialog */
+	INV_CALLING = 1,	/*!< Invite sent, no answer */
+	INV_PROCEEDING = 2,	/*!< We got/sent 1xx message */
+	INV_EARLY_MEDIA = 3,    /*!< We got 18x message with to-tag back */
+	INV_COMPLETED = 4,	/*!< Got final response with error. Wait for ACK, then CONFIRMED */
+	INV_CONFIRMED = 5,	/*!< Confirmed response - we've got an ack (Incoming calls only) */
+	INV_TERMINATED = 6,	/*!< Transaction done - either successful (AST_STATE_UP) or failed, but done 
+				     The only way out of this is a BYE from one side */
+	INV_CANCELLED = 7,	/*!< Transaction cancelled by client or server in non-terminated state */
 };
 
 /* Do _NOT_ make any changes to this enum, or the array following it;
@@ -961,8 +961,6 @@
 	time_t lastrtprx;			/*!< Last RTP received */
 	time_t lastrtptx;			/*!< Last RTP sent */
 	int rtptimeout;				/*!< RTP timeout time */
-	int rtpholdtimeout;			/*!< RTP timeout when on hold */
-	int rtpkeepalive;			/*!< Send RTP packets for keepalive */
 	struct sockaddr_in recv;		/*!< Received as */
 	struct in_addr ourip;			/*!< Our IP */
 	struct ast_channel *owner;		/*!< Who owns us (if we have an owner) */
@@ -1661,6 +1659,14 @@
 		ast_verbose("Initreq: %d headers, %d lines\n", p->initreq.headers, p->initreq.lines);
 }
 
+/*! \brief Encapsulate setting of SIP_ALREADYGONE to be able to trace it with debugging */
+static void sip_alreadygone(struct sip_pvt *dialog)
+{
+	if (option_debug > 2)
+		ast_log(LOG_DEBUG, "Setting SIP_ALREADYGONE on dialog %s\n", dialog->callid);
+	ast_set_flag(&dialog->flags[0], SIP_ALREADYGONE);
+}
+
 
 /*! \brief returns true if 'name' (with optional trailing whitespace)
  * matches the sip method 'id'.
@@ -1939,7 +1945,7 @@
 			sip_pvt_lock(pkt->owner);
 		}
 		if (pkt->owner->owner) {
-			ast_set_flag(&pkt->owner->flags[0], SIP_ALREADYGONE);
+			sip_alreadygone(pkt->owner);
 			ast_log(LOG_WARNING, "Hanging up call %s - no reply to our critical packet.\n", pkt->owner->callid);
 			ast_queue_hangup(pkt->owner->owner);
 			ast_channel_unlock(pkt->owner->owner);
@@ -2726,17 +2732,21 @@
 	if (dialog->rtp) {
 		ast_rtp_setdtmf(dialog->rtp, ast_test_flag(&dialog->flags[0], SIP_DTMF) != SIP_DTMF_INFO);
 		ast_rtp_setdtmfcompensate(dialog->rtp, ast_test_flag(&dialog->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
+		ast_rtp_set_rtptimeout(dialog->rtp, peer->rtptimeout);
+		ast_rtp_set_rtpholdtimeout(dialog->rtp, peer->rtpholdtimeout);
+		ast_rtp_set_rtpkeepalive(dialog->rtp, peer->rtpkeepalive);
+		/* Set Frame packetization */
+		ast_rtp_codec_setpref(dialog->rtp, &dialog->prefs);
+		dialog->autoframing = peer->autoframing;
 	}
 	if (dialog->vrtp) {
 		ast_rtp_setdtmf(dialog->vrtp, 0);
 		ast_rtp_setdtmfcompensate(dialog->vrtp, 0);
-	}
-
-	/* Set Frame packetization */
-	if (dialog->rtp) {
-		ast_rtp_codec_setpref(dialog->rtp, &dialog->prefs);
-		dialog->autoframing = peer->autoframing;
-	}
+		ast_rtp_set_rtptimeout(dialog->vrtp, peer->rtptimeout);
+		ast_rtp_set_rtpholdtimeout(dialog->vrtp, peer->rtpholdtimeout);
+		ast_rtp_set_rtpkeepalive(dialog->vrtp, peer->rtpkeepalive);
+	}
+
 	ast_string_field_set(dialog, peername, peer->username);
 	ast_string_field_set(dialog, authname, peer->username);
 	ast_string_field_set(dialog, username, peer->username);
@@ -2774,8 +2784,6 @@
 		dialog->noncodeccapability &= ~AST_RTP_DTMF;
 	ast_string_field_set(dialog, context, peer->context);
 	dialog->rtptimeout = peer->rtptimeout;
-	dialog->rtpholdtimeout = peer->rtpholdtimeout;
-	dialog->rtpkeepalive = peer->rtpkeepalive;
 	if (peer->call_limit)
 		ast_set_flag(&dialog->flags[0], SIP_CALL_LIMIT);
 	dialog->maxcallbitrate = peer->maxcallbitrate;
@@ -3099,9 +3107,9 @@
 
 	/* Check the list of users only for incoming calls */
 	if (global_limitonpeers == FALSE && !outgoing && (u = find_user(name, 1)))  {
-			inuse = &u->inUse;
-			call_limit = &u->call_limit;
-			inringing = NULL;
+		inuse = &u->inUse;
+		call_limit = &u->call_limit;
+		inringing = NULL;
 	} else if ( (p = find_peer(ast_strlen_zero(fup->peername) ? name : fup->peername, NULL, 1) ) ) { /* Try to find peer */
 		inuse = &p->inUse;
 		call_limit = &p->call_limit;
@@ -3405,7 +3413,7 @@
 		return 0;
 	}
 	/* If the call is not UP, we need to send CANCEL instead of BYE */
-	if (ast->_state == AST_STATE_RING || ast->_state == AST_STATE_RINGING) {
+	if (p->invitestate < INV_COMPLETED) {
 		needcancel = TRUE;
 		if (option_debug > 3)
 			ast_log(LOG_DEBUG, "Hanging up channel in state %s (not UP)\n", ast_state2str(ast->_state));
@@ -3426,7 +3434,7 @@
 	*/
 	if (ast_test_flag(&p->flags[0], SIP_ALREADYGONE))
 		needdestroy = 1;	/* Set destroy flag at end of this function */
-	else
+	else if (p->invitestate != INV_CALLING)
 		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
 
 	/* Start the process if it's not already started */
@@ -3488,6 +3496,7 @@
 				   but we can't send one while we have "INVITE" outstanding. */
 				ast_set_flag(&p->flags[0], SIP_PENDINGBYE);	
 				ast_clear_flag(&p->flags[0], SIP_NEEDREINVITE);	
+				sip_cancel_destroy(p);
 			}
 		}
 	}
@@ -3605,15 +3614,12 @@
 	case AST_FRAME_MODEM:
 		if (p) {
 			sip_pvt_lock(p);
-			if (p->udptl) {
-				if ((ast->_state != AST_STATE_UP) &&
-					!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) && 
-				    !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
-					transmit_response_with_t38_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE);
-					ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);
-				}
+			/* UDPTL requires two-way communication, so early media is not needed here.
+				we simply forget the frames if we get modem frames before the bridge is up.
+				Fax will re-transmit.
+			*/
+			if (p->udptl && ast->_state != AST_STATE_UP) 
 				res = ast_udptl_write(p->udptl, frame);
-			}
 			sip_pvt_unlock(p);
 		}
 		break;
@@ -3740,6 +3746,7 @@
 	switch(condition) {
 	case AST_CONTROL_RINGING:
 		if (ast->_state == AST_STATE_RING) {
+			p->invitestate = INV_EARLY_MEDIA;
 			if (!ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) ||
 			    (ast_test_flag(&p->flags[0], SIP_PROG_INBAND) == SIP_PROG_INBAND_NEVER)) {				
 				/* Send 180 ringing if out-of-band seems reasonable */
@@ -3756,7 +3763,8 @@
 	case AST_CONTROL_BUSY:
 		if (ast->_state != AST_STATE_UP) {
 			transmit_response(p, "486 Busy Here", &p->initreq);
-			ast_set_flag(&p->flags[0], SIP_ALREADYGONE);	
+			p->invitestate = INV_TERMINATED;
+			sip_alreadygone(p);
 			ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
 			break;
 		}
@@ -3765,7 +3773,8 @@
 	case AST_CONTROL_CONGESTION:
 		if (ast->_state != AST_STATE_UP) {
 			transmit_response(p, "503 Service Unavailable", &p->initreq);
-			ast_set_flag(&p->flags[0], SIP_ALREADYGONE);	
+			p->invitestate = INV_TERMINATED;
+			sip_alreadygone(p);
 			ast_softhangup_nolock(ast, AST_SOFTHANGUP_DEV);
 			break;
 		}
@@ -3776,6 +3785,7 @@
 		    !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
 		    !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
 			transmit_response(p, "100 Trying", &p->initreq);
+			p->invitestate = INV_PROCEEDING;  
 			break;
 		}
 		res = -1;
@@ -3784,6 +3794,7 @@
 		if ((ast->_state != AST_STATE_UP) &&
 		    !ast_test_flag(&p->flags[0], SIP_PROGRESS_SENT) &&
 		    !ast_test_flag(&p->flags[0], SIP_OUTGOING)) {
+			p->invitestate = INV_EARLY_MEDIA;
 			transmit_response_with_sdp(p, "183 Session Progress", &p->initreq, XMIT_UNRELIABLE);
 			ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT);	
 			break;
@@ -4302,16 +4313,19 @@
 		ast_rtp_setdtmf(p->rtp, ast_test_flag(&p->flags[0], SIP_DTMF) != SIP_DTMF_INFO);
 		ast_rtp_setdtmfcompensate(p->rtp, ast_test_flag(&p->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
 		ast_rtp_settos(p->rtp, global_tos_audio);
+		ast_rtp_set_rtptimeout(p->rtp, global_rtptimeout);
+		ast_rtp_set_rtpholdtimeout(p->rtp, global_rtpholdtimeout);
+		ast_rtp_set_rtpkeepalive(p->rtp, global_rtpkeepalive);
 		if (p->vrtp) {
 			ast_rtp_settos(p->vrtp, global_tos_video);
 			ast_rtp_setdtmf(p->vrtp, 0);
 			ast_rtp_setdtmfcompensate(p->vrtp, 0);
+			ast_rtp_set_rtptimeout(p->vrtp, global_rtptimeout);
+			ast_rtp_set_rtpholdtimeout(p->vrtp, global_rtpholdtimeout);
+			ast_rtp_set_rtpkeepalive(p->vrtp, global_rtpkeepalive);
 		}
 		if (p->udptl)
 			ast_udptl_settos(p->udptl, global_tos_audio);
-		p->rtptimeout = global_rtptimeout;
-		p->rtpholdtimeout = global_rtpholdtimeout;
-		p->rtpkeepalive = global_rtpkeepalive;
 		p->maxcallbitrate = default_maxcallbitrate;
 	}
 
@@ -10430,6 +10444,7 @@
 	ast_cli(fd, "  T1 minimum:             %d\n", global_t1min);
 	ast_cli(fd, "  Relax DTMF:             %s\n", global_relaxdtmf ? "Yes" : "No");
 	ast_cli(fd, "  Compact SIP headers:    %s\n", compactheaders ? "Yes" : "No");
+	ast_cli(fd, "  RTP Keepalive:          %d %s\n", global_rtpkeepalive, global_rtpkeepalive ? "" : "(Disabled)" );
 	ast_cli(fd, "  RTP Timeout:            %d %s\n", global_rtptimeout, global_rtptimeout ? "" : "(Disabled)" );
 	ast_cli(fd, "  RTP Hold Timeout:       %d %s\n", global_rtpholdtimeout, global_rtpholdtimeout ? "" : "(Disabled)");
 	ast_cli(fd, "  MWI NOTIFY mime type:   %s\n", default_notifymime);
@@ -11826,6 +11841,9 @@
 				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-inivte after T38 session not handled yet !\n");
 						/* Insted of this we should somehow re-invite the other side of the bridge to RTP */
@@ -11892,7 +11910,7 @@
 			if (p->authtries == MAX_AUTHTRIES || do_proxy_auth(p, req, resp, SIP_INVITE, 1)) {
 				ast_log(LOG_NOTICE, "Failed to authenticate on INVITE to '%s'\n", get_header(&p->initreq, "From"));
 				ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);	
-				ast_set_flag(&p->flags[0], SIP_ALREADYGONE);	
+				sip_alreadygone(p);
 				if (p->owner)
 					ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
 			}
@@ -11906,20 +11924,23 @@
 		if (!ast_test_flag(req, SIP_PKT_IGNORE) && p->owner)
 			ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
 		ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);	
-		ast_set_flag(&p->flags[0], SIP_ALREADYGONE);	
+		sip_alreadygone(p);
 		break;
 
 	case 404: /* Not found */
 		transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
 		if (p->owner && !ast_test_flag(req, SIP_PKT_IGNORE))
 			ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
-		ast_set_flag(&p->flags[0], SIP_ALREADYGONE);	
+		sip_alreadygone(p);
 		break;
 
 	case 481: /* Call leg does not exist */
-		/* Could be REFER or INVITE */
+		/* Could be REFER caused INVITE with replaces */
 		ast_log(LOG_WARNING, "Re-invite to non-existing call leg on other UA. SIP dialog '%s'. Giving up.\n", p->callid);
 		transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
+		if (p->owner)
+			ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
+		sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
 		break;
 
 	case 491: /* Pending */
@@ -11972,7 +11993,16 @@
 			ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
 		}
 		break;
-
+	case 481: /* Call leg does not exist */
+
+		/* A transfer with Replaces did not work */
+		/* OEJ: We should Set flag, cancel the REFER, go back
+		to original call - but right now we can't */
+		ast_log(LOG_WARNING, "Remote host can't match REFER request to call '%s'. Giving up.\n", p->callid);
+		if (p->owner)
+			ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
+		ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
+		break;
 
 	case 500:   /* Server error */
 	case 501:   /* Method not implemented */
@@ -12330,21 +12360,9 @@
 			break;
 		case 481: /* Call leg does not exist */
 			if (sipmethod == SIP_INVITE) {
-				/* First we ACK */
-				transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
-				if (option_debug)
-					ast_log(LOG_DEBUG, "Got 481 on Invite. Assuming INVITE with REPLACEs failed to '%s'\n", get_header(&p->initreq, "From"));
-				if (owner)
-					ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
-				sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
+				handle_response_invite(p, resp, rest, req, seqno);
 			} else if (sipmethod == SIP_REFER) {
-				/* A transfer with Replaces did not work */
-				/* OEJ: We should Set flag, cancel the REFER, go back
-				to original call - but right now we can't */
-				ast_log(LOG_WARNING, "Remote host can't match request %s to call '%s'. Giving up.\n", sip_methods[sipmethod].text, p->callid);
-				if (owner)
-					ast_queue_control(p->owner, AST_CONTROL_CONGESTION);
-				ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);
+				handle_response_refer(p, resp, rest, req, seqno);
 			} else if (sipmethod == SIP_BYE) {
 				/* The other side has no transaction to bye,
 				just assume it's all right then */
@@ -12386,7 +12404,6 @@
 				/* Fatal response */
 				if ((option_verbose > 2) && (resp != 487))
 					ast_verbose(VERBOSE_PREFIX_3 "Got SIP response %d \"%s\" back from %s\n", resp, rest, ast_inet_ntoa(p->sa.sin_addr));
-				ast_set_flag(&p->flags[0], SIP_ALREADYGONE);	
 	
 				stop_media_flows(p); /* Immediately stop RTP, VRTP and UDPTL as applicable */
 
@@ -12445,7 +12462,7 @@
 				/* ACK on invite */
 				if (sipmethod == SIP_INVITE) 
 					transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, FALSE);
-				ast_set_flag(&p->flags[0], SIP_ALREADYGONE);	
+				sip_alreadygone(p);
 				if (!p->owner)
 					ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);	
 			} else if ((resp >= 100) && (resp < 200)) {
@@ -13534,7 +13551,7 @@
 						transmit_response(p, "503 Unavailable", req);	/* OEJ - Right answer? */
 					else
 						transmit_response_reliable(p, "503 Unavailable", req);
-					ast_set_flag(&p->flags[0], SIP_ALREADYGONE);	
+					sip_alreadygone(p);
 					/* Unlock locks so ast_hangup can do its magic */
 					sip_pvt_unlock(p);
 					c->hangupcause = AST_CAUSE_CALL_REJECTED;
@@ -13858,7 +13875,7 @@
 		transmit_response(p, "603 Declined (No dialog)", req);
 		if (!ast_test_flag(req, SIP_PKT_IGNORE)) {
 			append_history(p, "Xfer", "Refer failed. Outside of dialog.");
-			ast_set_flag(&p->flags[0], SIP_ALREADYGONE);	
+			sip_alreadygone(p);
 			ast_set_flag(&p->flags[0], SIP_NEEDDESTROY);	
 		}
 		return 0;
@@ -14117,7 +14134,7 @@
 {
 		
 	check_via(p, req);
-	ast_set_flag(&p->flags[0], SIP_ALREADYGONE);	
+	sip_alreadygone(p);
 	p->invitestate = INV_CANCELLED;
 	
 	if (p->owner && p->owner->_state == AST_STATE_UP) {
@@ -14160,7 +14177,7 @@
 	if (sipdebug && option_debug)
 		ast_log(LOG_DEBUG, "Initializing initreq for method %s - callid %s\n", sip_methods[req->method].text, p->callid);
 	check_via(p, req);
-	ast_set_flag(&p->flags[0], SIP_ALREADYGONE);	
+	sip_alreadygone(p);
 
 	/* Get RTCP quality before end of call */
 	if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY) || p->owner) {
@@ -14915,52 +14932,66 @@
 
 
 /*! \brief helper function for the monitoring thread */
-static void check_rtp_timeout(struct sip_pvt *sip, time_t t)
-{
-	if (sip->rtp && sip->owner &&
-	    (sip->owner->_state == AST_STATE_UP) &&
-	    !sip->redirip.sin_addr.s_addr) {
-		if (sip->lastrtptx &&
-		    sip->rtpkeepalive &&
-		    (t > sip->lastrtptx + sip->rtpkeepalive)) {
-			/* Need to send an empty RTP packet */
-			sip->lastrtptx = time(NULL);
-			ast_rtp_sendcng(sip->rtp, 0);
-		}
-		if (sip->lastrtprx &&
-		    (sip->rtptimeout || sip->rtpholdtimeout) &&
-		    (t > sip->lastrtprx + sip->rtptimeout)) {
-			/* Might be a timeout now -- see if we're on hold */
-			struct sockaddr_in sin;
-			ast_rtp_get_peer(sip->rtp, &sin);
-			if (sin.sin_addr.s_addr || 
-			    (sip->rtpholdtimeout && 
-			     (t > sip->lastrtprx + sip->rtpholdtimeout))) {
-				/* Needs a hangup */
-				if (sip->rtptimeout) {
-					while (sip->owner && ast_channel_trylock(sip->owner)) {
-						sip_pvt_unlock(sip);
-						usleep(1);
-						sip_pvt_lock(sip);
-					}
-					if (sip->owner) {
-						if (!(ast_rtp_get_bridged(sip->rtp))) {
-							ast_log(LOG_NOTICE,
-								"Disconnecting call '%s' for lack of RTP activity in %ld seconds\n",
-								sip->owner->name,
-								(long) (t - sip->lastrtprx));
-							/* Issue a softhangup */
-							ast_softhangup_nolock(sip->owner, AST_SOFTHANGUP_DEV);
-						} else
-							ast_log(LOG_NOTICE, "'%s' will not be disconnected in %ld seconds because it is directly bridged to another RTP stream\n", sip->owner->name, (long) (t - sip->lastrtprx));
-						ast_channel_unlock(sip->owner);
-						/* forget the timeouts for this call, since a hangup
-						   has already been requested and we don't want to
-						   repeatedly request hangups
-						*/
-						sip->rtptimeout = 0;
-						sip->rtpholdtimeout = 0;
-					}
+static void check_rtp_timeout(struct sip_pvt *dialog, time_t t)
+{
+	/* If we have no RTP or no active owner, no need to check timers */
+	if (!dialog->rtp || !dialog->owner)
+		return;
+	/* If the call is not in UP state or redirected outside Asterisk, no need to check timers */
+	if (dialog->owner->_state != AST_STATE_UP || dialog->redirip.sin_addr.s_addr)
+		return;
+
+	/* If we have no timers set, return now */
+	if (ast_rtp_get_rtpkeepalive(dialog->rtp) == 0 || (ast_rtp_get_rtptimeout(dialog->rtp) == 0 && ast_rtp_get_rtpholdtimeout(dialog->rtp) == 0))
+		return;
+
+	/* Check AUDIO RTP keepalives */
+	if (dialog->lastrtptx && ast_rtp_get_rtpkeepalive(dialog->rtp) &&
+		    (t > dialog->lastrtptx + ast_rtp_get_rtpkeepalive(dialog->rtp))) {
+		/* Need to send an empty RTP packet */
+		dialog->lastrtptx = time(NULL);
+		ast_rtp_sendcng(dialog->rtp, 0);
+	}
+
+	/*! \todo Check video RTP keepalives
+
+		Do we need to move the lastrtptx to the RTP structure to have one for audio and one
+		for video? It really does belong to the RTP structure.
+	*/
+
+	/* Check AUDIO RTP timers */
+	if (dialog->lastrtprx && (ast_rtp_get_rtptimeout(dialog->rtp) || ast_rtp_get_rtpholdtimeout(dialog->rtp)) &&
+		    (t > dialog->lastrtprx + ast_rtp_get_rtptimeout(dialog->rtp))) {
+
+		/* Might be a timeout now -- see if we're on hold */
+		struct sockaddr_in sin;
+		ast_rtp_get_peer(dialog->rtp, &sin);
+		if (sin.sin_addr.s_addr || (ast_rtp_get_rtpholdtimeout(dialog->rtp) &&
+		     (t > dialog->lastrtprx + ast_rtp_get_rtpholdtimeout(dialog->rtp)))) {
+			/* Needs a hangup */
+			if (dialog->rtptimeout) {
+				while (dialog->owner && ast_channel_trylock(dialog->owner)) {
+					sip_pvt_unlock(dialog);
+					usleep(1);
+					sip_pvt_lock(dialog);
+				}
+				if (!(ast_rtp_get_bridged(dialog->rtp))) {
+					ast_log(LOG_NOTICE, "Disconnecting call '%s' for lack of RTP activity in %ld seconds\n",
+						dialog->owner->name, (long) (t - dialog->lastrtprx));
+					/* Issue a softhangup */
+					ast_softhangup_nolock(dialog->owner, AST_SOFTHANGUP_DEV);
+				} else
+					ast_log(LOG_NOTICE, "'%s' will not be disconnected in %ld seconds because it is directly bridged to another RTP stream\n", dialog->owner->name, (long) (t - dialog->lastrtprx));
+				ast_channel_unlock(dialog->owner);
+				/* forget the timeouts for this call, since a hangup
+				   has already been requested and we don't want to
+				   repeatedly request hangups
+				*/
+				ast_rtp_set_rtptimeout(dialog->rtp, 0);
+				ast_rtp_set_rtpholdtimeout(dialog->rtp, 0);
+				if (dialog->vrtp) {
+					ast_rtp_set_rtptimeout(dialog->vrtp, 0);
+					ast_rtp_set_rtpholdtimeout(dialog->vrtp, 0);
 				}
 			}
 		}
@@ -14974,7 +15005,7 @@
 static void *do_monitor(void *data)
 {
 	int res;
-	struct sip_pvt *sip;
+	struct sip_pvt *dialog;
 	struct sip_peer *peer = NULL;
 	time_t t;
 	int fastrestart = FALSE;
@@ -15002,6 +15033,7 @@
 			if (sipsock > -1)
 				sipsock_read_id = ast_io_change(io, sipsock_read_id, sipsock, NULL, 0, NULL);
 		}
+
 		/* Check for dialogs needing to be killed */
 		dialoglist_lock();
 restartsearch:		
@@ -15010,18 +15042,20 @@
 		   of time since the last time we did it (when MWI is being sent, we can
 		   get back to this point every millisecond or less)
 		*/
-		for (sip = dialoglist; !fastrestart && sip; sip = sip->next) {
-			sip_pvt_lock(sip);
+		for (dialog = dialoglist; !fastrestart && dialog; dialog = dialog->next) {
+			sip_pvt_lock(dialog);
 			/* Check RTP timeouts and kill calls if we have a timeout set and do not get RTP */
-			check_rtp_timeout(sip, t);
+			check_rtp_timeout(dialog, t);
 			/* If we have sessions that needs to be destroyed, do it now */
-			if (ast_test_flag(&sip->flags[0], SIP_NEEDDESTROY) && !sip->packets &&
-			    !sip->owner) {
-				sip_pvt_unlock(sip);
-				__sip_destroy(sip, TRUE, FALSE);
+			/* Check if we have outstanding requests not responsed to or an active call
+				- if that's the case, wait with destruction */
+			if (ast_test_flag(&dialog->flags[0], SIP_NEEDDESTROY) && !dialog->packets &&
+			    !dialog->owner) {
+				sip_pvt_unlock(dialog);
+				__sip_destroy(dialog, TRUE, FALSE);
 				goto restartsearch;
 			}
-			sip_pvt_unlock(sip);
+			sip_pvt_unlock(dialog);
 		}
 		dialoglist_unlock();
 
@@ -15030,7 +15064,8 @@
 		res = ast_sched_wait(sched);
 		if ((res < 0) || (res > 1000))
 			res = 1000;
-		/* If we might need to send more mailboxes, don't wait long at all.*/
+
+		/* If we might need to send more mailbox notifications, don't wait long at all.*/
 		if (fastrestart)
 			res = 1;
 		res = ast_io_wait(io, res);
@@ -16268,10 +16303,10 @@
 			compactheaders = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "notifymimetype")) {
 			ast_copy_string(default_notifymime, v->value, sizeof(default_notifymime));
+		} else if (!strcasecmp(v->name, "limitonpeers")) {
+			global_limitonpeers = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "notifyringing")) {
 			global_notifyringing = ast_true(v->value);
-		} else if (!strcasecmp(v->name, "limitpeersonly")) {
-			global_limitonpeers = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "notifyhold")) {
 			global_notifyhold = ast_true(v->value);
 		} else if (!strcasecmp(v->name, "alwaysauthreject")) {

Modified: team/oej/realtimetext-t140/configs/extensions.conf.sample
URL: http://svn.digium.com/view/asterisk/team/oej/realtimetext-t140/configs/extensions.conf.sample?view=diff&rev=48260&r1=48259&r2=48260
==============================================================================
--- team/oej/realtimetext-t140/configs/extensions.conf.sample (original)
+++ team/oej/realtimetext-t140/configs/extensions.conf.sample Tue Dec  5 05:20:22 2006
@@ -167,7 +167,7 @@
 ;
 ; List canonical entries here
 ;
-;exten => 12564286000,1,Macro(std-exten,6000,IAX2/foo)
+;exten => 12564286000,1,Macro(stdexten,6000,IAX2/foo)
 ;exten => _125642860XX,1,Dial(IAX2/otherbox/${EXTEN:7})
 
 [dundi-e164-customers]

Modified: team/oej/realtimetext-t140/configs/sip.conf.sample
URL: http://svn.digium.com/view/asterisk/team/oej/realtimetext-t140/configs/sip.conf.sample?view=diff&rev=48260&r1=48259&r2=48260
==============================================================================
--- team/oej/realtimetext-t140/configs/sip.conf.sample (original)
+++ team/oej/realtimetext-t140/configs/sip.conf.sample Tue Dec  5 05:20:22 2006
@@ -95,12 +95,6 @@
 ;language=en			; Default language setting for all users/peers
 				; This may also be set for individual users/peers
 ;relaxdtmf=yes			; Relax dtmf handling
-;rtptimeout=60			; Terminate call if 60 seconds of no RTP or RTCP activity
-				; when we're not on hold. This is to be able to hangup
-				; a call in the case of a phone disappearing from the net,
-				; like a powerloss or grandma tripping over a cable.
-;rtpholdtimeout=300		; Terminate call if 300 seconds of no RTP or RTCP activity
-				; when we're on hold (must be > rtptimeout)
 ;trustrpid = no			; If Remote-Party-ID should be trusted
 ;sendrpid = yes			; If Remote-Party-ID should be sent
 ;progressinband=never		; If we should generate in-band ringing always
@@ -162,6 +156,21 @@
 ;
 ;regcontext=sipregistrations
 ;
+;--------------------------- RTP timers ----------------------------------------------------
+; These timers are currently used for both audio and video streams. The RTP timeouts
+; are only applied to the audio channel.
+; The settings are settable in the global section as well as per device
+;
+;rtptimeout=60			; Terminate call if 60 seconds of no RTP or RTCP activity
+				; on the audio channel

[... 1206 lines stripped ...]


More information about the svn-commits mailing list