[asterisk-commits] pcadach: branch pcadach/chan_h323_exts r39499 - in /team/pcadach/chan_h323_ex...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Wed Aug 9 19:30:54 MST 2006


Author: pcadach
Date: Wed Aug  9 21:30:53 2006
New Revision: 39499

URL: http://svn.digium.com/view/asterisk?rev=39499&view=rev
Log:
Changes to revision 10761 with all modifications.

Added:
    team/pcadach/chan_h323_exts/channels/h323/ast_t38.cpp   (with props)
    team/pcadach/chan_h323_exts/channels/h323/ast_t38.h   (with props)
    team/pcadach/chan_h323_exts/channels/h323/ast_video.cpp   (with props)
    team/pcadach/chan_h323_exts/channels/h323/ast_video.h   (with props)
Modified:
    team/pcadach/chan_h323_exts/Makefile
    team/pcadach/chan_h323_exts/apps/Makefile
    team/pcadach/chan_h323_exts/apps/app_voicemail.c
    team/pcadach/chan_h323_exts/channel.c
    team/pcadach/chan_h323_exts/channels/chan_h323.c
    team/pcadach/chan_h323_exts/channels/chan_iax2.c
    team/pcadach/chan_h323_exts/channels/chan_sip.c
    team/pcadach/chan_h323_exts/channels/h323/Makefile
    team/pcadach/chan_h323_exts/channels/h323/ast_h323.cpp
    team/pcadach/chan_h323_exts/channels/h323/ast_h323.h
    team/pcadach/chan_h323_exts/channels/h323/chan_h323.h
    team/pcadach/chan_h323_exts/codecs/Makefile
    team/pcadach/chan_h323_exts/configs/sip.conf.sample
    team/pcadach/chan_h323_exts/frame.c
    team/pcadach/chan_h323_exts/include/asterisk/channel.h
    team/pcadach/chan_h323_exts/rtp.c
    team/pcadach/chan_h323_exts/udptl.c

Modified: team/pcadach/chan_h323_exts/Makefile
URL: http://svn.digium.com/view/asterisk/team/pcadach/chan_h323_exts/Makefile?rev=39499&r1=39498&r2=39499&view=diff
==============================================================================
--- team/pcadach/chan_h323_exts/Makefile (original)
+++ team/pcadach/chan_h323_exts/Makefile Wed Aug  9 21:30:53 2006
@@ -53,7 +53,7 @@
 endif
 
 #Overwite config files on "make samples"
-OVERWRITE=y
+OVERWRITE=n
 
 #Include debug and macro symbols in the executables (-g) and profiling info (-pg)
 DEBUG=-g3 #-pg
@@ -79,7 +79,7 @@
 WITH_SMDI = 1
 
 # Optional debugging parameters
-DEBUG_THREADS = #-DDUMP_SCHEDULER #-DDEBUG_SCHEDULER #-DDEBUG_THREADS #-DDO_CRASH #-DDETECT_DEADLOCKS
+DEBUG_THREADS = -DDEBUG_THREADS -DDO_CRASH -DDETECT_DEADLOCKS
 
 # Uncomment next one to enable ast_frame tracing (for debugging)
 TRACE_FRAMES = #-DTRACE_FRAMES

Modified: team/pcadach/chan_h323_exts/apps/Makefile
URL: http://svn.digium.com/view/asterisk/team/pcadach/chan_h323_exts/apps/Makefile?rev=39499&r1=39498&r2=39499&view=diff
==============================================================================
--- team/pcadach/chan_h323_exts/apps/Makefile (original)
+++ team/pcadach/chan_h323_exts/apps/Makefile Wed Aug  9 21:30:53 2006
@@ -30,6 +30,10 @@
 
 ifeq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/osp/osp.h $(CROSS_COMPILE_TARGET)/usr/include/osp/osp.h),)
   MODS:=$(filter-out app_osplookup.so,$(MODS))
+endif
+
+ifneq ($(wildcard $(CROSS_COMPILE_TARGET)/usr/local/include/spandsp.h $(CROSS_COMPILE_TARGET)/usr/include/spandsp.h),)
+APPS+=app_rxfax.so app_txfax.so
 endif
 
 ifneq ($(shell if [[ 0x`$(CROSS_COMPILE_BIN)curl-config --vernum` -ge 0x70907 ]]; then echo "OK" ; fi),)
@@ -86,6 +90,12 @@
 app_curl.so: app_curl.o
 	$(CC) $(SOLINK) -o $@ ${CYGSOLINK} $< ${CYGSOLIB} $(CURLLIBS)
 
+app_rxfax.so : app_rxfax.o
+	$(CC) $(SOLINK) -o $@ $< -lspandsp -ltiff
+
+app_txfax.so : app_txfax.o
+	$(CC) $(SOLINK) -o $@ $< -lspandsp -ltiff
+
 look:	look.c
 	$(CC) -pipe -O6 -g look.c -o look -lncurses
 

Modified: team/pcadach/chan_h323_exts/apps/app_voicemail.c
URL: http://svn.digium.com/view/asterisk/team/pcadach/chan_h323_exts/apps/app_voicemail.c?rev=39499&r1=39498&r2=39499&view=diff
==============================================================================
--- team/pcadach/chan_h323_exts/apps/app_voicemail.c (original)
+++ team/pcadach/chan_h323_exts/apps/app_voicemail.c Wed Aug  9 21:30:53 2006
@@ -4499,6 +4499,79 @@
 	return res;
 }
 
+static int get_lastdigits(int num)
+{
+	num %= 100;
+	return (num < 20) ? num : num % 10;
+}
+
+static int vm_intro_ru(struct ast_channel *chan,struct vm_state *vms)
+{
+	int res;
+	int lastnum;
+	int dcnum;
+
+	res = ast_play_and_wait(chan, "vm-youhave");
+	if (!res && vms->newmessages) {
+		lastnum = get_lastdigits(vms->newmessages);
+		dcnum = vms->newmessages - lastnum;
+		if (dcnum)
+			res = say_and_wait(chan, dcnum, chan->language);
+		if (!res && lastnum) {
+			if (lastnum == 1) 
+				res = ast_play_and_wait(chan, "digits/ru/odno");
+			else
+				res = say_and_wait(chan, lastnum, chan->language);
+		}
+
+		if (!res)
+			res = ast_play_and_wait(chan, (lastnum == 1) ? "vm-novoe" : "vm-novyh");
+
+		if (!res && vms->oldmessages)
+			res = ast_play_and_wait(chan, "vm-and");
+	}
+
+	if (!res && vms->oldmessages) {
+		lastnum = get_lastdigits(vms->oldmessages);
+		dcnum = vms->newmessages - lastnum;
+		if (dcnum)
+			res = say_and_wait(chan, dcnum, chan->language);
+		if (!res && lastnum) {
+			if (lastnum == 1) 
+				res = ast_play_and_wait(chan, "digits/ru/odno");
+			else
+				res = say_and_wait(chan, lastnum, chan->language);
+		}
+
+		if (!res)
+			res = ast_play_and_wait(chan, (lastnum == 1) ? "vm-staroe" : "vm-staryh");
+	}
+
+	if (!res && !vms->newmessages && !vms->oldmessages) {
+		lastnum = 0;
+		res = ast_play_and_wait(chan, "vm-no");
+	}
+
+	if (!res) {
+		switch(lastnum) {
+		case 1:
+			res = ast_play_and_wait(chan, "vm-soobshenie");
+			break;
+		case 2:
+		case 3:
+		case 4:
+			res = ast_play_and_wait(chan, "vm-soobsheniya");
+			break;
+		default:
+			res = ast_play_and_wait(chan, "vm-soobsheniy");
+			break;
+		}
+	}
+
+	return res;
+}
+
+
 static int vm_intro(struct ast_channel *chan,struct vm_state *vms)
 {
 	/* Play voicemail intro - syntax is different for different languages */
@@ -4522,6 +4595,8 @@
 		return vm_intro_se(chan, vms);
 	} else if (!strcasecmp(chan->language, "no")) {	/* NORWEGIAN syntax */
 		return vm_intro_no(chan, vms);
+	} else if (!strcasecmp(chan->language, "ru")) {   /* RUSSIAN syntax */
+		return vm_intro_ru(chan, vms);
 	} else {					/* Default to ENGLISH */
 		return vm_intro_en(chan, vms);
 	}

Modified: team/pcadach/chan_h323_exts/channel.c
URL: http://svn.digium.com/view/asterisk/team/pcadach/chan_h323_exts/channel.c?rev=39499&r1=39498&r2=39499&view=diff
==============================================================================
--- team/pcadach/chan_h323_exts/channel.c (original)
+++ team/pcadach/chan_h323_exts/channel.c Wed Aug  9 21:30:53 2006
@@ -333,7 +333,7 @@
 	shutting_down = 1;
 	if (hangup) {
 		AST_LIST_LOCK(&channels);
-		AST_LIST_TRAVERSE(&channels, c, list)
+		AST_LIST_TRAVERSE(&channels, c, chan_list)
 			ast_softhangup(c, AST_SOFTHANGUP_SHUTDOWN);
 		AST_LIST_UNLOCK(&channels);
 	}
@@ -345,7 +345,7 @@
 	struct ast_channel *c;
 	int cnt = 0;
 	AST_LIST_LOCK(&channels);
-	AST_LIST_TRAVERSE(&channels, c, list)
+	AST_LIST_TRAVERSE(&channels, c, chan_list)
 		cnt++;
 	AST_LIST_UNLOCK(&channels);
 	return cnt;
@@ -682,7 +682,7 @@
 	tmp->tech = &null_tech;
 
 	AST_LIST_LOCK(&channels);
-	AST_LIST_INSERT_HEAD(&channels, tmp, list);
+	AST_LIST_INSERT_HEAD(&channels, tmp, chan_list);
 	AST_LIST_UNLOCK(&channels);
 	return tmp;
 }
@@ -816,7 +816,7 @@
 
 	for (retries = 0; retries < 10; retries++) {
 		AST_LIST_LOCK(&channels);
-		AST_LIST_TRAVERSE(&channels, c, list) {
+		AST_LIST_TRAVERSE(&channels, c, chan_list) {
 			if (!prev) {
 				/* want head of list */
 				if (!name && !exten)
@@ -845,7 +845,7 @@
 						break;
 				}
 			} else if (c == prev) { /* found, return c->next */
-				c = AST_LIST_NEXT(c, list);
+				c = AST_LIST_NEXT(c, chan_list);
 				break;
 			}
 		}
@@ -952,7 +952,7 @@
 	headp=&chan->varshead;
 	
 	AST_LIST_LOCK(&channels);
-	AST_LIST_REMOVE(&channels, chan, list);
+	AST_LIST_REMOVE(&channels, chan, chan_list);
 	/* Lock and unlock the channel just to be sure nobody
 	   has it locked still */
 	ast_mutex_lock(&chan->lock);
@@ -2144,7 +2144,7 @@
 
 	if (chan->tech->send_digit)
 		res = chan->tech->send_digit(chan, digit);
-	if (!(chan->tech->send_digit && chan->tech->send_digit_begin) ||
+	if (/*!(chan->tech->send_digit && chan->tech->send_digit_begin) ||*/
 	    res) {
 		/*
 		 * Device does not support DTMF tones, lets fake
@@ -2293,6 +2293,14 @@
 		else
 			res = 0;
 		break;
+#ifdef T38_SUPPORT
+	case AST_FRAME_MODEM:
+		if (chan->tech->write)
+			res = chan->tech->write(chan, fr);
+		else
+			res = 0;
+		break;
+#endif
 	case AST_FRAME_VOICE:
 		if (chan->tech->write) {
 			/* Bypass translator if we're writing format in the raw write format.  This
@@ -3305,12 +3313,14 @@
 			}
 			continue;
 		}
+		if (option_verbose > 3)
+			ast_verbose(VERBOSE_PREFIX_4 "Reading frame from channel %s fdno %d\n", who->name, who->fdno);
 		f = ast_read(who);
 		if (!f) {
 			*fo = NULL;
 			*rc = who;
 			res = AST_BRIDGE_COMPLETE;
-			ast_log(LOG_DEBUG, "Didn't get a frame from channel: %s\n",who->name);
+			ast_log(LOG_DEBUG, "Didn't get a frame from channel: %s, fdno=%d\n",who->name, who->fdno);
 			break;
 		}
 

Modified: team/pcadach/chan_h323_exts/channels/chan_h323.c
URL: http://svn.digium.com/view/asterisk/team/pcadach/chan_h323_exts/channels/chan_h323.c?rev=39499&r1=39498&r2=39499&view=diff
==============================================================================
--- team/pcadach/chan_h323_exts/channels/chan_h323.c (original)
+++ team/pcadach/chan_h323_exts/channels/chan_h323.c Wed Aug  9 21:30:53 2006
@@ -73,11 +73,15 @@
 #include "asterisk/sched.h"
 #include "asterisk/io.h"
 #include "asterisk/rtp.h"
+#ifdef T38_SUPPORT
+#include "asterisk/udptl.h"
+#endif
 #include "asterisk/acl.h"
 #include "asterisk/callerid.h"
 #include "asterisk/cli.h"
 #include "asterisk/dsp.h"
 #include "asterisk/causes.h"
+#include "asterisk/stringfields.h"
 #ifdef __cplusplus
 }
 #endif
@@ -96,17 +100,22 @@
 rfc2833_cb on_set_rfc2833_payload;
 hangup_cb on_hangup;
 setcapabilities_cb on_setcapabilities;
+setpeercapabilities_cb on_setpeercapabilities;
+stop_rtp_cb on_stop_rtp_channel;
+on_udptl_cb on_external_udptl_create;
+start_udptl_cb on_start_udptl_channel;
 
 /* global debug flag */
 int h323debug;
 
 /** Variables required by Asterisk */
-static const char type[] = "H323";
 static const char desc[] = "The NuFone Network's Open H.323 Channel Driver";
 static const char tdesc[] = "The NuFone Network's Open H.323 Channel Driver";
 static const char config[] = "h323.conf";
 static char default_context[AST_MAX_CONTEXT] = "default";
 static struct sockaddr_in bindaddr;
+
+#define GLOBAL_CAPABILITY (AST_FORMAT_G723_1 | AST_FORMAT_GSM | AST_FORMAT_ULAW | AST_FORMAT_ALAW | AST_FORMAT_G729A | AST_FORMAT_H261)
 
 /** H.323 configuration values */
 static int h323_signalling_port = 1720;
@@ -134,6 +143,11 @@
 	struct sockaddr_in sa;                  		/* Our peer */
 	struct sockaddr_in redirip; 			        /* Where our RTP should be going if not to us */
 	int nonCodecCapability;					/* non-audio capability */
+#ifdef T38_SUPPORT
+//	struct t38properties t38;
+	struct sockaddr_in udptlredirip;
+	struct ast_udptl *udptl;
+#endif
 	int outgoing;						/* Outgoing or incoming call? */
 	char exten[AST_MAX_EXTENSION];				/* Requested extension */
 	char context[AST_MAX_CONTEXT];				/* Context where to start */
@@ -143,12 +157,22 @@
 	char rdnis[80];						/* Referring DNIS, if available */
 	int amaflags;						/* AMA Flags */
 	struct ast_rtp *rtp;					/* RTP Session */
+#ifdef VIDEO_SUPPORT
+	struct ast_rtp *vrtp;
+#endif
 	struct ast_dsp *vad;					/* Used for in-band DTMF detection */
 	int nativeformats;					/* Codec formats supported by a channel */
 	int needhangup;						/* Send hangup when Asterisk is ready */
 	int hangupcause;					/* Hangup cause from OpenH323 layer */
 	int newstate;						/* Pending state change */
 	int newcontrol;						/* Pending control to send */
+	int pref_codec;						/* Preferred codec */
+	int peercapability;					/* Capabilities learned from peer */
+	int jointcapability;				/* Common capabilities for local and remote side */
+	int rtp_tx_enabled;					/* While RTP tx is enabled */
+	int vrtp_tx_enabled;
+	struct sockaddr_in rtp_tx_addr;
+	struct sockaddr_in vrtp_tx_addr;
 	struct oh323_pvt *next;				/* Next channel in list */
 } *iflist = NULL;
 
@@ -206,9 +230,9 @@
 static int oh323_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
 
 static const struct ast_channel_tech oh323_tech = {
-	.type = type,
+	.type = "H323",
 	.description = tdesc,
-	.capabilities = AST_FORMAT_ULAW,
+	.capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1),
 	.properties = AST_CHAN_TP_WANTSJITTER,
 	.requester = oh323_request,
 	.send_digit = oh323_digit,
@@ -217,10 +241,11 @@
 	.answer = oh323_answer,
 	.read = oh323_read,
 	.write = oh323_write,
+	.write_video = oh323_write,
 	.indicate = oh323_indicate,
 	.fixup = oh323_fixup,
 	/* disable, for now */
-#if 0
+#if 1
 	.bridge = ast_rtp_bridge,
 #endif
 };
@@ -306,6 +331,18 @@
 		ast_rtp_destroy(pvt->rtp);
 	}
 	
+#ifdef VIDEO_SUPPORT
+	if (pvt->vrtp) {
+		ast_rtp_destroy(pvt->vrtp);
+	}
+#endif
+	
+#ifdef T38_SUPPORT
+	if (pvt->udptl) {
+		ast_udptl_destroy(pvt->udptl);
+	}
+#endif
+	
 	/* Free dsp used for in-band DTMF detection */
 	if (pvt->vad) {
 		ast_dsp_free(pvt->vad);
@@ -360,7 +397,7 @@
 		return -1;
 	}
 	ast_mutex_lock(&pvt->lock);
-	if (pvt->rtp && (pvt->options.dtmfmode & H323_DTMF_RFC2833)) {
+	if (pvt->rtp && (pvt->options.dtmfmode & H323_DTMF_RFC2833) && pvt->rtp_tx_enabled) {
 		/* out-of-band DTMF */
 		if (h323debug) {
 			ast_log(LOG_DEBUG, "Sending out-of-band digit %c on %s\n", digit, c->name);
@@ -496,7 +533,7 @@
 	if (c->hangupcause) {
 		q931cause = c->hangupcause;
 	} else {
-		char *cause = pbx_builtin_getvar_helper(c, "DIALSTATUS");
+		const char *cause = pbx_builtin_getvar_helper(c, "DIALSTATUS");
 		if (cause) {
 			if (!strcmp(cause, "CONGESTION")) {
 				q931cause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
@@ -539,18 +576,48 @@
 	return 0;
 }
 
-static struct ast_frame *oh323_rtp_read(struct oh323_pvt *pvt)
+#ifdef T38_SUPPORT
+static struct ast_frame *oh323_rtp_read(struct ast_channel *chan, struct oh323_pvt *pvt, int *faxdetect)
+#else
+static struct ast_frame *oh323_rtp_read(struct ast_channel *chan, struct oh323_pvt *pvt)
+#endif
 {
 	/* Retrieve audio/etc from channel.  Assumes pvt->lock is already held. */
 	struct ast_frame *f;
 
+#if 0
 	/* Only apply it for the first packet, we just need the correct ip/port */
 	if (pvt->options.nat) {
 		ast_rtp_setnat(pvt->rtp, pvt->options.nat);
 		pvt->options.nat = 0;
 	}
-
-	f = ast_rtp_read(pvt->rtp);
+#endif
+
+	switch(chan->fdno) {
+	case 0:
+		f = ast_rtp_read(pvt->rtp);
+		break;
+	case 1:
+		f = ast_rtcp_read(pvt->rtp);
+		break;
+#ifdef VIDEO_SUPPORT
+	case 2:
+		f = ast_rtp_read(pvt->vrtp);
+		break;
+	case 3:
+		f = ast_rtcp_read(pvt->vrtp);
+		break;
+#endif
+#ifdef T38_SUPPORT
+	case 4:
+		f = ast_udptl_read(pvt->udptl);
+		break;
+#endif
+	default:
+		f = &ast_null_frame;
+		break;
+	}
+
 	/* Don't send RFC2833 if we're not supposed to */
 	if (f && (f->frametype == AST_FRAME_DTMF) && !(pvt->options.dtmfmode & H323_DTMF_RFC2833)) {
 		return &ast_null_frame;
@@ -580,7 +647,15 @@
 				else
 					ast_log(LOG_NOTICE, "Unable to process inband DTMF while channel is locked\n");
 				if (f &&(f->frametype == AST_FRAME_DTMF)) {
-					ast_log(LOG_DEBUG, "Received in-band digit %c.\n", f->subclass);
+#ifdef T38_SUPPORT
+					if (f->subclass == 'f') {
+						if (option_debug) 
+							ast_log(LOG_DEBUG, "Fax CNG detected on %s\n", chan->name);
+						*faxdetect = 1;
+					}
+#endif
+					if (option_debug)
+						ast_log(LOG_DEBUG, "Received in-band digit %c.\n", f->subclass);
 				}
 			}
 		}
@@ -592,10 +667,24 @@
 {
 	struct ast_frame *fr;
 	struct oh323_pvt *pvt = (struct oh323_pvt *)c->tech_pvt;
+#ifdef T38_SUPPORT
+	int faxdetected = 0;
+#endif
 	ast_mutex_lock(&pvt->lock);
 	__oh323_update_info(c, pvt);
-	fr = oh323_rtp_read(pvt);
+#ifdef T38_SUPPORT
+	fr = oh323_rtp_read(c, pvt, &faxdetected);
+#else
+	fr = oh323_rtp_read(c, pvt);
+#endif
 	ast_mutex_unlock(&pvt->lock);
+#ifdef T38_SUPPORT
+#if 0
+	if (faxdetected) {
+		oh323_mode_change();
+	}
+#endif
+#endif
 	return fr;
 }
 
@@ -603,28 +692,58 @@
 {
 	struct oh323_pvt *pvt = (struct oh323_pvt *) c->tech_pvt;
 	int res = 0;
-	if (frame->frametype != AST_FRAME_VOICE) {
-		if (frame->frametype == AST_FRAME_IMAGE) {
-			return 0;
-		} else {
-			ast_log(LOG_WARNING, "Can't send %d type frames with H323 write\n", frame->frametype);
-			return 0;
-		}
-	} else {
+
+	switch (frame->frametype) {
+	case AST_FRAME_IMAGE:
+		return 0;
+#ifdef T38_SUPPORT
+	case AST_FRAME_MODEM:
+		if (pvt) {
+			ast_mutex_lock(&pvt->lock);
+			if (pvt->udptl) {
+				res = ast_udptl_write(pvt->udptl, frame);
+			}
+			__oh323_update_info(c, pvt);
+			ast_mutex_unlock(&pvt->lock);
+		}
+		break;
+#endif
+	case AST_FRAME_VOICE:
 		if (!(frame->subclass & c->nativeformats)) {
 			ast_log(LOG_WARNING, "Asked to transmit frame type %d, while native formats is %d (read/write = %d/%d)\n",
 				frame->subclass, c->nativeformats, c->readformat, c->writeformat);
 			return 0;
 		}
-	}
-	if (pvt) {
-		ast_mutex_lock(&pvt->lock);
-		if (pvt->rtp) {
-			res =  ast_rtp_write(pvt->rtp, frame);
-		}
-		__oh323_update_info(c, pvt);
-		ast_mutex_unlock(&pvt->lock);
-	}
+		if (pvt) {
+			ast_mutex_lock(&pvt->lock);
+			if (pvt->rtp && pvt->rtp_tx_enabled) {
+				res =  ast_rtp_write(pvt->rtp, frame);
+			}
+//			else if (h323debug)
+//				ast_log(LOG_DEBUG, "RTP TX is disabled for %s\n", c->name);
+			__oh323_update_info(c, pvt);
+			ast_mutex_unlock(&pvt->lock);
+		}
+		break;
+#ifdef VIDEO_SUPPORT
+	case AST_FRAME_VIDEO:
+		if (pvt) {
+			ast_mutex_lock(&pvt->lock);
+			if (pvt->vrtp && pvt->rtp_tx_enabled) {
+				res =  ast_rtp_write(pvt->vrtp, frame);
+			}
+			else if (h323debug)
+				ast_log(LOG_DEBUG, "VRTP TX is disabled for %s\n", c->name);
+			__oh323_update_info(c, pvt);
+			ast_mutex_unlock(&pvt->lock);
+		}
+		break;
+#endif
+	default:
+		ast_log(LOG_WARNING, "Can't send %d type frames with H.323 write\n", frame->frametype);
+		break;
+	}
+	
 	return res;
 }
 
@@ -639,7 +758,7 @@
 	ast_mutex_unlock(&pvt->lock);
 
 	if (h323debug)
-		ast_log(LOG_DEBUG, "OH323: Indicating %d on %s\n", condition, token);
+		ast_log(LOG_DEBUG, "OH323: Indicating %d on %s, native format=%d, read format=%d, write format=%d\n", condition, token, c->nativeformats, c->readformat, c->writeformat);
 
 	switch(condition) {
 	case AST_CONTROL_RINGING:
@@ -735,15 +854,28 @@
 	ast_mutex_lock(&pvt->lock);
 	if (ch) {
 		ch->tech = &oh323_tech;
-		snprintf(ch->name, sizeof(ch->name), "H323/%s", host);
-		ch->nativeformats = pvt->options.capability;
-		if (!ch->nativeformats) {
-			ch->nativeformats = global_options.capability;
-		}
+		ast_string_field_build(ch, name, "H323/%s", host);
+		if (!(fmt = pvt->jointcapability) && !(fmt = pvt->options.capability))
+			fmt = global_options.capability;
+		ch->nativeformats = ast_codec_choose(&pvt->options.prefs, fmt, 1)/* | (pvt->jointcapability & AST_FORMAT_VIDEO_MASK)*/;
 		pvt->nativeformats = ch->nativeformats;
 		fmt = ast_best_codec(ch->nativeformats);
+#if 0
 		ch->type = type;
+#endif
 		ch->fds[0] = ast_rtp_fd(pvt->rtp);
+		ch->fds[1] = ast_rtcp_fd(pvt->rtp);
+#ifdef VIDEO_SUPPORT
+		if (pvt->vrtp) {
+			ch->fds[2] = ast_rtp_fd(pvt->vrtp);
+			ch->fds[3] = ast_rtcp_fd(pvt->vrtp);
+		}
+#endif
+#ifdef T38_SUPPORT
+		if (pvt->udptl) {
+			ch->fds[4] = ast_udptl_fd(pvt->udptl);
+		}
+#endif
 		if (state == AST_STATE_RING) {
 			ch->rings = 1;
 		}
@@ -765,7 +897,7 @@
 		strncpy(ch->exten, pvt->exten, sizeof(ch->exten) - 1);		
 		ch->priority = 1;
 		if (!ast_strlen_zero(pvt->accountcode)) {
-			strncpy(ch->accountcode, pvt->accountcode, sizeof(ch->accountcode) - 1);
+			ast_string_field_set(ch, accountcode, pvt->accountcode);
 		}
 		if (pvt->amaflags) {
 			ch->amaflags = pvt->amaflags;
@@ -810,13 +942,29 @@
 		return NULL;
 	}
 	memset(pvt, 0, sizeof(struct oh323_pvt));
+	memset(&pvt->rtp_tx_addr, 0xff, sizeof(pvt->rtp_tx_addr));
 	pvt->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0,bindaddr.sin_addr);
+#ifdef VIDEO_SUPPORT
+	memset(&pvt->vrtp_tx_addr, 0xff, sizeof(pvt->vrtp_tx_addr));
+	pvt->vrtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
+#endif
+#ifdef T38_SUPPORT
+	pvt->udptl = ast_udptl_new_with_bindaddr(sched, io, 9, bindaddr.sin_addr);
+#endif
 	if (!pvt->rtp) {
 		ast_log(LOG_WARNING, "Unable to create RTP session: %s\n", strerror(errno));
 		free(pvt);
 		return NULL;
 	}
 	ast_rtp_settos(pvt->rtp, tos);
+#ifdef VIDEO_SUPPORT
+	if (pvt->vrtp)
+		ast_rtp_settos(pvt->vrtp, tos);
+#endif
+#ifdef T38_SUPPORT
+	if (pvt->udptl)
+		ast_udptl_settos(pvt->udptl, tos);
+#endif
 	ast_mutex_init(&pvt->lock);
 	/* Ensure the call token is allocated */
 	if ((pvt->cd).call_token == NULL) {
@@ -829,6 +977,7 @@
 	memset((char *)(pvt->cd).call_token, 0, 128);
 	pvt->cd.call_reference = callid;
 	memcpy(&pvt->options, &global_options, sizeof(pvt->options));
+	pvt->jointcapability = pvt->options.capability;
 	if (pvt->options.dtmfmode & H323_DTMF_RFC2833) {
 		pvt->nonCodecCapability |= AST_RTP_DTMF;
 	} else {
@@ -969,10 +1118,23 @@
 	if (p) {
 		found++;
 		memcpy(&pvt->options, &p->options, sizeof(pvt->options));
+		pvt->jointcapability = pvt->options.capability;
 		if (pvt->rtp) {
 			ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", pvt->options.nat);
 			ast_rtp_setnat(pvt->rtp, pvt->options.nat);
 		}
+#ifdef VIDEO_SUPPORT
+		if (pvt->vrtp) {
+			ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", pvt->options.nat);
+			ast_rtp_setnat(pvt->vrtp, pvt->options.nat);
+		}
+#endif
+#ifdef T38_SUPPORT
+		if (pvt->udptl) {
+			ast_log(LOG_DEBUG, "Setting NAT on UDPTL to %d\n", pvt->options.nat);
+			ast_udptl_setnat(pvt->udptl, pvt->options.nat);
+		}
+#endif
 		if (pvt->options.dtmfmode) {
 			if (pvt->options.dtmfmode & H323_DTMF_RFC2833) {
 				pvt->nonCodecCapability |= AST_RTP_DTMF;
@@ -996,6 +1158,7 @@
 		hp = ast_gethostbyname(hostn, &ahp);
 		if (hp) {
 			memcpy(&pvt->options, &global_options, sizeof(pvt->options));
+			pvt->jointcapability = pvt->options.capability;
 			memcpy(&pvt->sa.sin_addr, hp->h_addr, sizeof(pvt->sa.sin_addr));
 			pvt->sa.sin_port = htons(portno);
 			return 0;	
@@ -1057,10 +1220,23 @@
 	}
 	else {
 		memcpy(&pvt->options, &global_options, sizeof(pvt->options));
+		pvt->jointcapability = pvt->options.capability;
 		if (pvt->rtp) {
 			ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", pvt->options.nat);
 			ast_rtp_setnat(pvt->rtp, pvt->options.nat);
 		}
+#ifdef VIDEO_SUPPORT
+		if (pvt->vrtp) {
+			ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", pvt->options.nat);
+			ast_rtp_setnat(pvt->vrtp, pvt->options.nat);
+		}
+#endif
+#ifdef T38_SUPPORT
+		if (pvt->udptl) {
+			ast_log(LOG_DEBUG, "Setting NAT on UDPTL to %d\n", pvt->options.nat);
+			ast_udptl_setnat(pvt->udptl, pvt->options.nat);
+		}
+#endif
 		if (pvt->options.dtmfmode) {
 			if (pvt->options.dtmfmode & H323_DTMF_RFC2833) {
 				pvt->nonCodecCapability |= AST_RTP_DTMF;
@@ -1077,6 +1253,7 @@
 	ast_mutex_unlock(&caplock);
 
 	ast_mutex_lock(&pvt->lock);
+	pvt->pref_codec = format;
 	tmpc = __oh323_new(pvt, AST_STATE_DOWN, tmp1);
 	ast_mutex_unlock(&pvt->lock);
 	if (!tmpc) {
@@ -1137,11 +1314,12 @@
   *
   * Returns the local RTP information
   */
-struct rtp_info *external_rtp_create(unsigned call_reference, const char * token)
+struct rtp_info *external_rtp_create(unsigned call_reference, const char * token, int datatype)
 {	
 	struct oh323_pvt *pvt;
 	struct sockaddr_in us;
 	struct rtp_info *info;
+	struct ast_rtp *rtp;
 
 	info = (struct rtp_info *)malloc(sizeof(struct rtp_info));
 	if (!info) {
@@ -1155,7 +1333,21 @@
 		return NULL;
 	}
 	/* figure out our local RTP port and tell the H.323 stack about it */
-	ast_rtp_get_us(pvt->rtp, &us);
+	rtp = (struct ast_rtp *)NULL;
+	switch(datatype) {
+	case 1:
+		rtp = pvt->rtp;
+		break;
+	case 2:
+		rtp = pvt->vrtp;
+		break;
+	}
+	if (!rtp) {
+		free(info);
+		ast_log(LOG_ERROR, "RTP information for call %s(%d) isn't available for datatype %d\n", token, call_reference, datatype);
+		return NULL;
+	}
+	ast_rtp_get_us(rtp, &us);
 	ast_mutex_unlock(&pvt->lock);
 
 	ast_inet_ntoa(info->addr, sizeof(info->addr), us.sin_addr);
@@ -1178,11 +1370,12 @@
   *
   * Returns nothing 
   */
-void setup_rtp_connection(unsigned call_reference, const char *remoteIp, int remotePort, const char *token, int pt)
+void setup_rtp_connection(unsigned call_reference, const char *remoteIp, int remotePort, const char *token, int pt, int direction, int bridging_enabled, int datatype)
 {
 	struct oh323_pvt *pvt;
 	struct sockaddr_in them;
 	struct rtpPayloadType rtptype;
+	struct ast_rtp *rtp;
 
 	if (h323debug)
 		ast_log(LOG_DEBUG, "Setting up RTP connection for %s\n", token);
@@ -1190,42 +1383,145 @@
 	/* Find the call or allocate a private structure if call not found */
 	pvt = find_call_locked(call_reference, token); 
 	if (!pvt) {
-		ast_log(LOG_ERROR, "Something is wrong: rtp\n");
+		ast_log(LOG_ERROR, "Something is wrong: cannot find call %s(%d) for RTP information\n", token, call_reference);
 		return;
 	}
 	if (pvt->alreadygone) {
 		ast_mutex_unlock(&pvt->lock);
 		return;
 	}
-	rtptype = ast_rtp_lookup_pt(pvt->rtp, pt);
-	pvt->nativeformats = rtptype.code;
-	if (pvt->owner && !ast_mutex_trylock(&pvt->owner->lock)) {
-		pvt->owner->nativeformats = pvt->nativeformats;
-		ast_set_read_format(pvt->owner, pvt->owner->readformat);
-		ast_set_write_format(pvt->owner, pvt->owner->writeformat);
-		if (pvt->options.progress_audio)
-			ast_queue_control(pvt->owner, AST_CONTROL_PROGRESS);
-		ast_mutex_unlock(&pvt->owner->lock);
-	}
-	else {
-		if (pvt->options.progress_audio)
-			pvt->newcontrol = AST_CONTROL_PROGRESS;
+	switch(datatype) {
+	case 1:
+		rtp = pvt->rtp;
+		break;
+	case 2:
+		rtp = pvt->vrtp;
+		break;
+	}
+	if (!rtp) {
+		ast_log(LOG_ERROR, "No RTP info for call %s(%d) available for datatype %d\n", token, call_reference, datatype);
+		return;
+	}
+	ast_rtp_set_m_type(rtp, pt);
+	rtptype = ast_rtp_lookup_pt(rtp, pt);
+	if (rtp == pvt->rtp) {
+		pvt->nativeformats = rtptype.code;
 		if (h323debug)
-			ast_log(LOG_DEBUG, "RTP connection preparation for %s is pending...\n", token);
-	}
-
+			ast_log(LOG_DEBUG, "RTP payload is %d, codec is %d\n", pt, pvt->nativeformats);
+		if (pvt->owner && !ast_mutex_trylock(&pvt->owner->lock)) {
+			pvt->owner->nativeformats = pvt->nativeformats;
+			ast_set_read_format(pvt->owner, pvt->owner->readformat);
+			ast_set_write_format(pvt->owner, pvt->owner->writeformat);
+			if (pvt->options.progress_audio)
+				ast_queue_control(pvt->owner, AST_CONTROL_PROGRESS);
+			else {
+				/* Kick Asterisk core to process bridging */
+				ast_queue_frame(pvt->owner, &ast_null_frame);
+			}
+			ast_mutex_unlock(&pvt->owner->lock);
+		}
+		else {
+			if (pvt->options.progress_audio)
+				pvt->newcontrol = AST_CONTROL_PROGRESS;
+			if (h323debug)
+				ast_log(LOG_DEBUG, "RTP connection preparation for %s is pending...\n", token);
+		}
+	}
+
+	if (direction) {
+		if (!bridging_enabled) {
+			if (h323debug)
+				ast_log(LOG_DEBUG, "Enabling RTP TX for %s\n", token);
+			switch(datatype) {
+			case 1:
+				pvt->rtp_tx_enabled = 1;
+				break;
+			case 2:
+				pvt->vrtp_tx_enabled = 1;
+				break;
+			}
+		} else {
+			if (h323debug)
+				ast_log(LOG_DEBUG, "RTP TX for %s is disabled while in native bridge mode\n", token);
+			switch(datatype) {
+			case 1:
+				pvt->rtp_tx_enabled = 0;
+				break;
+			case 2:
+				pvt->vrtp_tx_enabled = 0;
+				break;
+			}
+		}
+	}
+	
 	them.sin_family = AF_INET;
 	/* only works for IPv4 */
-	them.sin_addr.s_addr = inet_addr(remoteIp); 
+	them.sin_addr.s_addr = inet_addr(remoteIp);
 	them.sin_port = htons(remotePort);
-	ast_rtp_set_peer(pvt->rtp, &them);
-
+
+	/* Update peer address with information from TX direction only */
+	if (direction) {
+		if (!them.sin_addr.s_addr && !them.sin_port) {
+			switch(datatype) {
+			case 1:
+				memcpy(&them, &pvt->rtp_tx_addr, sizeof(them));
+				break;
+			case 2:
+				memcpy(&them, &pvt->vrtp_tx_addr, sizeof(them));
+				break;
+			}
+		}
+		ast_rtp_set_peer(rtp, &them);
+	}
+	switch(datatype) {
+	case 1:
+		memcpy(&pvt->rtp_tx_addr, &them, sizeof(them));
+		break;
+	case 2:
+		memcpy(&pvt->vrtp_tx_addr, &them, sizeof(them));
+		break;
+	}
 	ast_mutex_unlock(&pvt->lock);
 
 	if (h323debug)
 		ast_log(LOG_DEBUG, "RTP connection prepared for %s\n", token);
 
 	return;
+}
+
+void shutdown_rtp_connection(unsigned call_reference, const char *token, int direction, int datatype)
+{
+	struct oh323_pvt *pvt;
+
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Shutting down RTP connection for %s\n", token);
+
+	/* Find the call or allocate a private structure if call not found */
+	pvt = find_call_locked(call_reference, token); 
+	if (!pvt) {
+		ast_log(LOG_ERROR, "Something is wrong: Cannot find connection %s(%d) for RTP shutdown of datatype %d\n", token, call_reference, datatype);
+		return;
+	}
+	if (pvt->alreadygone) {
+		ast_mutex_unlock(&pvt->lock);
+		return;
+	}
+	if (direction) {
+		if (h323debug)
+			ast_log(LOG_DEBUG, "Stopping RTP TX for %s\n", token);
+		switch(datatype) {
+		case 1:
+			pvt->rtp_tx_enabled = 0;
+			memset(&pvt->rtp_tx_addr, 0xff, sizeof(pvt->rtp_tx_addr));
+			break;
+		case 2:
+			pvt->vrtp_tx_enabled = 0;
+			memset(&pvt->vrtp_tx_addr, 0xff, sizeof(pvt->vrtp_tx_addr));
+			break;
+		}
+	}
+	
+	ast_mutex_unlock(&pvt->lock);
 }
 
 /**  
@@ -1234,7 +1530,6 @@
   */
 void connection_made(unsigned call_reference, const char *token)
 {
-	struct ast_channel *c = NULL;
 	struct oh323_pvt *pvt;
 
 	if (h323debug)
@@ -1306,6 +1601,7 @@
 	/* Populate the call details in the private structure */
 	memcpy(&pvt->cd, cd, sizeof(pvt->cd));
 	memcpy(&pvt->options, &global_options, sizeof(pvt->options));
+	pvt->jointcapability = pvt->options.capability;
 
 	if (h323debug) {
 		ast_verbose(VERBOSE_PREFIX_3 "Setting up Call\n");
@@ -1314,6 +1610,7 @@
 		ast_verbose(VERBOSE_PREFIX_3 "\tCalling party number:  [%s]\n", pvt->cd.call_source_e164);
 		ast_verbose(VERBOSE_PREFIX_3 "\tCalled party name:  [%s]\n", pvt->cd.call_dest_alias);
 		ast_verbose(VERBOSE_PREFIX_3 "\tCalled party number:  [%s]\n", pvt->cd.call_dest_e164);
+		ast_verbose(VERBOSE_PREFIX_3 "\tCalling party IP: [%s]\n", pvt->cd.sourceIp);
 	}
 
 	/* Decide if we are allowing Gatekeeper routed calls*/
@@ -1341,7 +1638,7 @@
 				strncpy(pvt->exten, cd->call_dest_alias, sizeof(pvt->exten) - 1);
 			}
 			if (ast_strlen_zero(default_context)) {
-				ast_log(LOG_ERROR, "Call from '%s' rejected due to no default context\n", pvt->cd.call_source_aliases);
+				ast_log(LOG_ERROR, "Call from '%s'@%s rejected due to no default context\n", pvt->cd.call_source_aliases, pvt->cd.sourceIp);
 				return NULL;
 			}
 			strncpy(pvt->context, default_context, sizeof(pvt->context) - 1);
@@ -1370,6 +1667,7 @@
 			}
 			strncpy(pvt->context, user->context, sizeof(pvt->context) - 1);
 			memcpy(&pvt->options, &user->options, sizeof(pvt->options));
+			pvt->jointcapability = pvt->options.capability;
 			if (!ast_strlen_zero(pvt->cd.call_dest_e164)) {
 				strncpy(pvt->exten, cd->call_dest_e164, sizeof(pvt->exten) - 1);
 			} else {
@@ -1436,7 +1734,6 @@
   */
 void chan_ringing(unsigned call_reference, const char *token)
 {
-	struct ast_channel *c = NULL;
 	struct oh323_pvt *pvt;
 
 	if (h323debug)
@@ -1479,7 +1776,7 @@
 			break;
 #if 1
 #ifdef DEBUG_THREADS
-		ast_log(LOG_NOTICE, "Avoiding H.323 destory deadlock on %s, locked at %ld/%d by %s (%s:%d)\n", call_token, pvt->owner->lock.thread, pvt->owner->lock.reentrancy, pvt->owner->lock.func, pvt->owner->lock.file, pvt->owner->lock.lineno);
+		ast_log(LOG_NOTICE, "Avoiding H.323 destory deadlock on %s, locked at %ld/%d by %s (%s:%d)\n", call_token, pvt->owner->lock.thread[0], pvt->owner->lock.reentrancy, pvt->owner->lock.func[0], pvt->owner->lock.file[0], pvt->owner->lock.lineno[0]);
 #else
 		ast_log(LOG_NOTICE, "Avoiding H.323 destory deadlock on %s\n", call_token);
 #endif
@@ -1554,21 +1851,39 @@
 		ast_log(LOG_DEBUG, "DTMF payload on %s set to %d\n", token, payload);
 }
 
-static void set_local_capabilities(unsigned call_reference, const char *token)
+static void set_peer_capabilities(unsigned call_reference, const char *token, int capabilities)
 {
 	struct oh323_pvt *pvt;
-	int capability, dtmfmode;
 
 	if (h323debug)
-		ast_log(LOG_DEBUG, "Setting capabilities for connection %s\n", token);
+		ast_log(LOG_DEBUG, "Got remote capabilities for connection %s\n", token);
 
 	pvt = find_call_locked(call_reference, token);
 	if (!pvt)
 		return;
-	capability = pvt->options.capability;
+	pvt->peercapability = capabilities;
+	pvt->jointcapability = pvt->options.capability & capabilities;
+	ast_mutex_unlock(&pvt->lock);
+}
+
+static void set_local_capabilities(unsigned call_reference, const char *token)
+{
+	struct oh323_pvt *pvt;
+	int capability, dtmfmode, pref_codec;
+	struct ast_codec_pref prefs;
+
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Setting capabilities for connection %s\n", token);
+
+	pvt = find_call_locked(call_reference, token);
+	if (!pvt)
+		return;
+	capability = (pvt->jointcapability) ? pvt->jointcapability : pvt->options.capability;
 	dtmfmode = pvt->options.dtmfmode;
+	prefs = pvt->options.prefs;
+	pref_codec = pvt->pref_codec;
 	ast_mutex_unlock(&pvt->lock);
-	h323_set_capabilities(token, capability, dtmfmode);
+	h323_set_capabilities(token, capability, dtmfmode, &prefs, pref_codec);
 
 	if (h323debug)
 		ast_log(LOG_DEBUG, "Capabilities for connection %s is set\n", token);
@@ -1791,21 +2106,12 @@
 
 static int update_common_options(struct ast_variable *v, struct call_options *options)
 {
-	unsigned int format;
 	int tmp;
 
 	if (!strcasecmp(v->name, "allow")) {
-		format = ast_getformatbyname(v->value);
-		if (format < 1) 
-			ast_log(LOG_WARNING, "Cannot allow unknown format '%s'\n", v->value);
-		else
-			options->capability |= format;
+		ast_parse_allow_disallow(&options->prefs, &options->capability, v->value, 1);
 	} else if (!strcasecmp(v->name, "disallow")) {
-		format = ast_getformatbyname(v->value);
-		if (format < 1) 
-			ast_log(LOG_WARNING, "Cannot disallow unknown format '%s'\n", v->value);
-		else
-			options->capability &= ~format;
+		ast_parse_allow_disallow(&options->prefs, &options->capability, v->value, 0);
 	} else if (!strcasecmp(v->name, "dtmfmode")) {
 		if (!strcasecmp(v->value, "inband")) {
 			options->dtmfmode = H323_DTMF_INBAND;
@@ -2026,7 +2332,7 @@
 	memset(&global_options, 0, sizeof(global_options));
 	global_options.dtmfcodec = 101;
 	global_options.dtmfmode = H323_DTMF_RFC2833;
-	global_options.capability = ~0;	/* All capabilities */
+	global_options.capability = GLOBAL_CAPABILITY;	/* All capabilities */
 	global_options.bridge = 1;		/* Do native bridging by default */
 	v = ast_variable_browse(cfg, "general");
 	while(v) {
@@ -2246,7 +2552,7 @@
 {
 	struct oh323_pvt *pvt;
 	pvt = (struct oh323_pvt *) chan->tech_pvt;
-	if (pvt && pvt->rtp && pvt->options.bridge) {
+	if (pvt && pvt->rtp && pvt->options.bridge && h323_bridge_capable(pvt->cd.call_token)) {
 		return pvt->rtp;
 	}
 	return NULL;
@@ -2257,6 +2563,7 @@
 	return NULL;
 }
 
+#if 0
 static char *convertcap(int cap)
 {
 	switch (cap) {
@@ -2281,38 +2588,202 @@
 		return NULL;
 	}
 }
-
-static int oh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs)
+#endif
+
+static int oh323_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active)
 {
 	/* XXX Deal with Video */
 	struct oh323_pvt *pvt;
 	struct sockaddr_in them;
-	struct sockaddr_in us;
-	char *mode;
-	char iabuf[INET_ADDRSTRLEN];
+//	char iabuf[INET_ADDRSTRLEN];
 
 	if (!rtp) {
 		return 0;
 	}
 
-	mode = convertcap(chan->writeformat); 
 	pvt = (struct oh323_pvt *) chan->tech_pvt;
 	if (!pvt) {
 		ast_log(LOG_ERROR, "No Private Structure, this is bad\n");
 		return -1;
 	}
-	ast_rtp_get_peer(rtp, &them);	
-	ast_rtp_get_us(rtp, &us);
-	h323_native_bridge(pvt->cd.call_token, ast_inet_ntoa(iabuf, sizeof(iabuf), them.sin_addr), mode);
-	return 0;
+	if (rtp)
+		ast_rtp_get_peer(rtp, &them);
+	else
+		memset(&them, 0, sizeof(them));
+	if (h323debug) {
+		char s1[1024];
+		char s2[1024];
+		char s3[1024];
+		ast_log(LOG_DEBUG, "H.323 bridge capabilities is %s, peer is %s, joint is %s\n",
+			ast_getformatname_multiple(s1, sizeof(s1), codecs),
+			ast_getformatname_multiple(s2, sizeof(s3), pvt->peercapability),
+			ast_getformatname_multiple(s3, sizeof(s3), pvt->jointcapability));
+	}
+	return h323_native_bridge(pvt->cd.call_token, them, codecs & pvt->jointcapability);
+}
+
+static int oh323_get_codec(struct ast_channel *chan)
+{
+	struct oh323_pvt *pvt = chan->tech_pvt;
+	int capability;
+	if (!pvt)
+		return 0;
+	capability = pvt->peercapability ? pvt->peercapability : pvt->jointcapability;
+	if (h323debug) {
+		char s1[1024];
+		char s2[1024];
+		ast_log(LOG_DEBUG, "H.323 peer capabilities is %s, joint capabilities is %s\n",
+			ast_getformatname_multiple(s1, sizeof(s1), pvt->peercapability),
+			ast_getformatname_multiple(s2, sizeof(s2), pvt->jointcapability));
+	}
+	return capability;
 }
 
 static struct ast_rtp_protocol oh323_rtp = {
-	.type = type,
+	.type = "H323",
 	.get_rtp_info = oh323_get_rtp_peer,
 	.get_vrtp_info = oh323_get_vrtp_peer,
-	.set_rtp_peer=  oh323_set_rtp_peer,
+	.set_rtp_peer = oh323_set_rtp_peer,
+	.get_codec = oh323_get_codec,
 };
+
+#ifdef T38_SUPPORT
+static struct ast_udptl *oh323_get_udptl_peer(struct ast_channel *chan)
+{
+	struct oh323_pvt *pvt;
+	struct ast_udptl *udptl = NULL;
+	
+	pvt = chan->tech_pvt;
+	if (!pvt)
+		return NULL;
+	
+	ast_mutex_lock(&pvt->lock);
+	if (pvt->udptl)
+		udptl = pvt->udptl;
+	ast_mutex_unlock(&pvt->lock);
+	return udptl;
+}
+
+static int oh323_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl)
+{
+	struct oh323_pvt *pvt;
+	
+	pvt = chan->tech_pvt;
+	if (!pvt)
+		return -1;
+	
+	ast_mutex_lock(&pvt->lock);
+	if (udptl)
+		ast_udptl_get_peer(udptl, &pvt->udptlredirip);
+	else
+		memset(&pvt->udptlredirip, 0, sizeof(pvt->udptlredirip));
+
+	/* Switch UDPTL to different source here */
+
+	return -1;
+}
+
+static struct ast_udptl_protocol oh323_udptl = {
+	type: "H.323",
+	get_udptl_info: oh323_get_udptl_peer,
+	set_udptl_peer: oh323_set_udptl_peer,
+};
+#endif
+
+struct rtp_info *external_udptl_create(unsigned call_reference, const char * token)
+{	
+	struct oh323_pvt *pvt;
+	struct sockaddr_in us;
+	struct rtp_info *info;
+
+	info = (struct rtp_info *)malloc(sizeof(struct rtp_info));
+	if (!info) {
+		ast_log(LOG_ERROR, "Unable to allocated info structure, this is very bad\n");
+		return NULL;
+	}
+	pvt = find_call_locked(call_reference, token); 
+	if (!pvt) {
+		free(info);
+		ast_log(LOG_ERROR, "Unable to find call %s(%d)\n", token, call_reference);
+		return NULL;
+	}
+	/* figure out our local RTP port and tell the H.323 stack about it */
+	ast_udptl_get_us(pvt->udptl, &us);
+	ast_mutex_unlock(&pvt->lock);
+
+	ast_inet_ntoa(info->addr, sizeof(info->addr), us.sin_addr);
+	info->port = ntohs(us.sin_port);
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Sending UDPTL 'US' %s:%d\n", info->addr, info->port);
+	return info;
+}
+
+void setup_udptl_connection(unsigned call_reference, const char *remoteIp, int remotePort, const char *token, int direction)
+{
+	struct oh323_pvt *pvt;
+	struct sockaddr_in them;
+
+	if (h323debug)
+		ast_log(LOG_DEBUG, "Setting up UDPTL connection for %s\n", token);
+
+	/* Find the call or allocate a private structure if call not found */
+	pvt = find_call_locked(call_reference, token); 
+	if (!pvt) {
+		ast_log(LOG_ERROR, "Something is wrong: udptl\n");
+		return;
+	}
+	if (pvt->alreadygone) {
+		ast_mutex_unlock(&pvt->lock);
+		return;
+	}
+
+	them.sin_family = AF_INET;
+	/* only works for IPv4 */
+	them.sin_addr.s_addr = inet_addr(remoteIp);
+	them.sin_port = htons(remotePort);
+
+	/* Update peer address with information from TX direction only */
+	if (direction) {
+//		if (!them.sin_addr.s_addr && !them.sin_port)

[... 4619 lines stripped ...]


More information about the asterisk-commits mailing list