diff --git a/libs/freetdm/mod_freetdm/Makefile.in b/libs/freetdm/mod_freetdm/Makefile.in
index ceea0dfbba..33ca03b440 100644
--- a/libs/freetdm/mod_freetdm/Makefile.in
+++ b/libs/freetdm/mod_freetdm/Makefile.in
@@ -4,6 +4,7 @@ BASE=../../..
 FT_DIR=..
 VERBOSE=1
 FTLA=$(FT_DIR)/libfreetdm.la
+LOCAL_OBJS=tdm.o
 LOCAL_CFLAGS=-I$(FT_DIR)/src/include -I$(FT_DIR)/src/isdn/include $(FT_CFLAGS)
 LOCAL_LDFLAGS=-L$(FT_DIR) -lfreetdm 
 include $(BASE)/build/modmake.rules
diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c
index 89524f0eca..63abc9f284 100755
--- a/libs/freetdm/mod_freetdm/mod_freetdm.c
+++ b/libs/freetdm/mod_freetdm/mod_freetdm.c
@@ -873,7 +873,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
 	if (!tech_pvt->ftdmchan) {
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "no ftdmchan set in channel %s!\n", name);
 		return SWITCH_STATUS_FALSE;
-	} 
+	}
 
 	span_id = ftdm_channel_get_span_id(tech_pvt->ftdmchan);
 	chan_id = ftdm_channel_get_id(tech_pvt->ftdmchan);
@@ -906,7 +906,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
 	ftdm_channel_wait(tech_pvt->ftdmchan, &wflags, ftdm_channel_get_io_interval(tech_pvt->ftdmchan) * 10);
 	
 	if (!(wflags & FTDM_WRITE)) {
-		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Dropping frame! (write note ready) in channel %s device %d:%d!\n", name, span_id, chan_id);
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Dropping frame! (write not ready) in channel %s device %d:%d!\n", name, span_id, chan_id);
 		return SWITCH_STATUS_SUCCESS;
 	}
 
diff --git a/libs/freetdm/mod_freetdm/tdm.c b/libs/freetdm/mod_freetdm/tdm.c
new file mode 100644
index 0000000000..935411867b
--- /dev/null
+++ b/libs/freetdm/mod_freetdm/tdm.c
@@ -0,0 +1,413 @@
+/* 
+* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
+*
+* Version: MPL 1.1
+*
+* The contents of this file are subject to the Mozilla Public License Version
+* 1.1 (the "License"); you may not use this file except in compliance with
+* the License. You may obtain a copy of the License at
+* http://www.mozilla.org/MPL/
+*
+* Software distributed under the License is distributed on an "AS IS" basis,
+* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+* for the specific language governing rights and limitations under the
+* License.
+*
+* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+*
+* The Initial Developer of the Original Code is
+* Anthony Minessale II <anthm@freeswitch.org>
+* Portions created by the Initial Developer are Copyright (C)
+* the Initial Developer. All Rights Reserved.
+*
+* Contributor(s):
+* 
+* Mathieu Rene <mrene@avgs.ca>
+*
+* tdm.c -- FreeTDM Controllable Channel Module
+*
+*/
+
+#include <switch.h>
+#include "freetdm.h"
+
+void ctdm_init(switch_loadable_module_interface_t *module_interface);
+
+/* Parameters */
+
+#define kSPAN_ID "span"
+#define kCHAN_ID "chan"
+
+static struct {
+    switch_memory_pool_t *pool;
+    switch_endpoint_interface_t *endpoint_interface;
+} ctdm;
+
+typedef struct {
+    int span_id;
+    int chan_id;
+    ftdm_channel_t *ftdm_channel;
+    switch_core_session_t *session;
+    switch_codec_t read_codec, write_codec;
+    switch_frame_t read_frame;
+} ctdm_private_t;
+
+static switch_status_t channel_on_init(switch_core_session_t *session);
+static switch_status_t channel_on_destroy(switch_core_session_t *session);
+static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
+													switch_caller_profile_t *outbound_profile,
+													switch_core_session_t **new_session, 
+													switch_memory_pool_t **pool,
+													switch_originate_flag_t flags, switch_call_cause_t *cancel_cause);
+static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
+static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
+static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg);
+static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf);
+
+switch_state_handler_table_t ctdm_state_handlers = {
+	.on_init = channel_on_init,
+	.on_destroy = channel_on_destroy
+};
+
+switch_io_routines_t ctdm_io_routines = {
+    .send_dtmf = channel_send_dtmf,
+	.outgoing_channel = channel_outgoing_channel,
+	.read_frame = channel_read_frame,
+	.write_frame = channel_write_frame,
+	.receive_message = channel_receive_message
+};
+
+void ctdm_init(switch_loadable_module_interface_t *module_interface)
+{
+    switch_endpoint_interface_t *endpoint_interface;
+    ctdm.pool = module_interface->pool;
+    endpoint_interface = switch_loadable_module_create_interface(module_interface, SWITCH_ENDPOINT_INTERFACE);
+    endpoint_interface->interface_name = "tdm";
+    endpoint_interface->io_routines = &ctdm_io_routines;
+    endpoint_interface->state_handler = &ctdm_state_handlers;
+    ctdm.endpoint_interface = endpoint_interface;
+    
+}
+
+static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
+													switch_caller_profile_t *outbound_profile,
+													switch_core_session_t **new_session, 
+													switch_memory_pool_t **pool,
+													switch_originate_flag_t flags, switch_call_cause_t *cancel_cause)
+{
+    const char  *szspanid = switch_event_get_header(var_event, kSPAN_ID),
+                *szchanid = switch_event_get_header(var_event, kCHAN_ID);
+    int chan_id;
+    int span_id;
+    
+    ftdm_span_t *span;
+    ftdm_channel_t *chan;
+    switch_channel_t *channel;
+    char name[128];
+    const char *dname;
+    ftdm_codec_t codec;
+    uint32_t interval;
+    
+    ctdm_private_t *tech_pvt;
+    
+    if (zstr(szchanid) || zstr(szspanid)) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Both "kSPAN_ID" and "kCHAN_ID" have to be set.\n");
+        goto fail;
+    }
+    
+    chan_id = atoi(szchanid);
+    span_id = atoi(szspanid);
+    
+    
+    if (!(*new_session = switch_core_session_request(ctdm.endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, 0, pool))) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't request session.\n");
+        goto fail;
+    }
+    
+    channel = switch_core_session_get_channel(*new_session);
+    
+    if (ftdm_channel_open(span_id, chan_id, &chan) != FTDM_SUCCESS) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't open span or channel.\n"); 
+        goto fail;
+    }
+    
+    span = ftdm_channel_get_span(chan);
+    
+    tech_pvt = switch_core_session_alloc(*new_session, sizeof *tech_pvt);
+    tech_pvt->chan_id = chan_id;
+    tech_pvt->span_id = span_id;
+    tech_pvt->ftdm_channel = chan;
+    tech_pvt->session = *new_session;
+    switch_core_session_set_private(*new_session, tech_pvt);
+    
+    snprintf(name, sizeof(name), "tdm/%d:%d", span_id, chan_id);
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connect outbound channel %s\n", name);
+	switch_channel_set_name(channel, name);
+    
+    switch_channel_set_state(channel, CS_INIT);
+    
+	if (FTDM_SUCCESS != ftdm_channel_command(chan, FTDM_COMMAND_GET_CODEC, &codec)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to retrieve channel codec.\n");
+		return SWITCH_STATUS_GENERR;
+	}
+    
+    if (FTDM_SUCCESS != ftdm_channel_command(chan, FTDM_COMMAND_GET_INTERVAL, &interval)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to retrieve channel interval.\n");
+		return SWITCH_STATUS_GENERR;
+	}
+    
+	switch(codec) {
+        case FTDM_CODEC_ULAW:
+		{
+			dname = "PCMU";
+		}
+            break;
+        case FTDM_CODEC_ALAW:
+		{
+			dname = "PCMA";
+		}
+            break;
+        case FTDM_CODEC_SLIN:
+		{
+			dname = "L16";
+		}
+            break;
+        default:
+		{
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid codec value retrieved from channel, codec value: %d\n", codec);
+			goto fail;
+		}
+	}
+
+    
+	if (switch_core_codec_init(&tech_pvt->read_codec,
+							   dname,
+							   NULL,
+							   8000,
+							   interval,
+							   1,
+							   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+							   NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
+        goto fail;
+	} else {
+		if (switch_core_codec_init(&tech_pvt->write_codec,
+								   dname,
+								   NULL,
+								   8000,
+								   interval,
+								   1,
+								   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+								   NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
+			switch_core_codec_destroy(&tech_pvt->read_codec);
+            goto fail;
+		}
+	}
+    
+    if (switch_core_session_set_read_codec(*new_session, &tech_pvt->read_codec) != SWITCH_STATUS_SUCCESS) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set read codec?\n");
+        goto fail;
+    }
+    
+    if (switch_core_session_set_write_codec(*new_session, &tech_pvt->write_codec) != SWITCH_STATUS_SUCCESS) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set write codec?\n");        
+    }
+    
+    if (switch_core_session_thread_launch(*new_session) != SWITCH_STATUS_SUCCESS) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't start session thread.\n"); 
+        goto fail;
+    }
+    
+    return SWITCH_CAUSE_SUCCESS;
+
+fail:
+    
+    if (tech_pvt) {
+        if (tech_pvt->ftdm_channel) {
+            ftdm_channel_close(&tech_pvt->ftdm_channel);
+        }
+        
+        if (tech_pvt->read_codec.implementation) {
+			switch_core_codec_destroy(&tech_pvt->read_codec);
+		}
+		
+		if (tech_pvt->write_codec.implementation) {
+			switch_core_codec_destroy(&tech_pvt->write_codec);
+		}
+    }
+    
+    if (*new_session) {
+        switch_core_session_destroy(new_session);
+    }
+    return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+}
+
+static switch_status_t channel_on_init(switch_core_session_t *session)
+{
+    return SWITCH_STATUS_SUCCESS;   
+}
+
+static switch_status_t channel_on_destroy(switch_core_session_t *session)
+{
+    ctdm_private_t *tech_pvt = switch_core_session_get_private(session);
+    
+ 	if ((tech_pvt = switch_core_session_get_private(session))) {
+        
+		if (tech_pvt->read_codec.implementation) {
+			switch_core_codec_destroy(&tech_pvt->read_codec);
+		}
+		
+		if (tech_pvt->write_codec.implementation) {
+			switch_core_codec_destroy(&tech_pvt->write_codec);
+		}
+	}
+    
+    ftdm_channel_close(&tech_pvt->ftdm_channel);
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
+{
+    ftdm_wait_flag_t wflags = FTDM_READ;
+    ftdm_status_t status;
+    ctdm_private_t *tech_pvt;
+    const char *name;
+    switch_channel_t *channel;
+    int chunk;
+    uint32_t span_id, chan_id;
+    ftdm_size_t len;
+    char dtmf[128] = "";
+    
+    channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+	
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+    
+	name = switch_channel_get_name(channel);
+
+top:
+    wflags = FTDM_READ;
+    chunk = ftdm_channel_get_io_interval(tech_pvt->ftdm_channel) * 2;
+    status = ftdm_channel_wait(tech_pvt->ftdm_channel, &wflags, chunk);
+    
+    
+	span_id = ftdm_channel_get_span_id(tech_pvt->ftdm_channel);
+	chan_id = ftdm_channel_get_id(tech_pvt->ftdm_channel);
+
+    if (status == FTDM_FAIL) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to read from channel %s device %d:%d!\n", name, span_id, chan_id);
+        goto fail;
+    }
+
+    if (status == FTDM_TIMEOUT) {
+        goto top;
+    }
+
+    if (!(wflags & FTDM_READ)) {
+        goto top;
+    }
+
+    len = tech_pvt->read_frame.buflen;
+    if (ftdm_channel_read(tech_pvt->ftdm_channel, tech_pvt->read_frame.data, &len) != FTDM_SUCCESS) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to read from channel %s device %d:%d!\n", name, span_id, chan_id);
+    }
+
+    *frame = &tech_pvt->read_frame;
+    tech_pvt->read_frame.datalen = (uint32_t)len;
+    tech_pvt->read_frame.samples = tech_pvt->read_frame.datalen;
+
+    if (ftdm_channel_get_codec(tech_pvt->ftdm_channel) == FTDM_CODEC_SLIN) {
+        tech_pvt->read_frame.samples /= 2;
+    }
+
+    while (ftdm_channel_dequeue_dtmf(tech_pvt->ftdm_channel, dtmf, sizeof(dtmf))) {
+        switch_dtmf_t _dtmf = { 0, switch_core_default_dtmf_duration(0) };
+        char *p;
+        for (p = dtmf; p && *p; p++) {
+            if (is_dtmf(*p)) {
+                _dtmf.digit = *p;
+                ftdm_log(FTDM_LOG_DEBUG, "Queuing DTMF [%c] in channel %s device %d:%d\n", *p, name, span_id, chan_id);
+                switch_channel_queue_dtmf(channel, &_dtmf);
+            }
+        }
+    }
+
+    return SWITCH_STATUS_SUCCESS;
+
+fail:
+    return SWITCH_STATUS_GENERR;
+}
+
+static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
+{
+    ftdm_wait_flag_t wflags = FTDM_WRITE;
+    ctdm_private_t *tech_pvt;
+    const char *name;
+    switch_channel_t *channel;
+    uint32_t span_id, chan_id;
+    ftdm_size_t len;
+    unsigned char data[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0};
+    
+    channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+	
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+    
+	span_id = ftdm_channel_get_span_id(tech_pvt->ftdm_channel);
+	chan_id = ftdm_channel_get_id(tech_pvt->ftdm_channel);
+    
+	name = switch_channel_get_name(channel);   
+    
+    if (switch_test_flag(frame, SFF_CNG)) {
+		frame->data = data;
+		frame->buflen = sizeof(data);
+		if ((frame->datalen = tech_pvt->write_codec.implementation->encoded_bytes_per_packet) > frame->buflen) {
+			goto fail;
+		}
+		memset(data, 255, frame->datalen);
+	}
+    
+    wflags = FTDM_WRITE;	
+	ftdm_channel_wait(tech_pvt->ftdm_channel, &wflags, ftdm_channel_get_io_interval(tech_pvt->ftdm_channel) * 10);
+	
+	if (!(wflags & FTDM_WRITE)) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Dropping frame! (write not ready) in channel %s device %d:%d!\n", name, span_id, chan_id);
+		return SWITCH_STATUS_SUCCESS;
+	}
+    
+	len = frame->datalen;
+	if (ftdm_channel_write(tech_pvt->ftdm_channel, frame->data, frame->buflen, &len) != FTDM_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Failed to write to channel %s device %d:%d!\n", name, span_id, chan_id);
+	}
+    
+    return SWITCH_STATUS_SUCCESS;
+
+fail:
+    return SWITCH_STATUS_GENERR;
+}
+
+static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf)
+{
+	ctdm_private_t *tech_pvt = NULL;
+	char tmp[2] = "";
+    
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+        
+	tmp[0] = dtmf->digit;
+	ftdm_channel_command(tech_pvt->ftdm_channel, FTDM_COMMAND_SEND_DTMF, tmp);
+    
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+    return SWITCH_STATUS_SUCCESS;
+}
+
diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c
index 4dca25e452..a9cb0b4f2a 100644
--- a/libs/freetdm/src/ftdm_io.c
+++ b/libs/freetdm/src/ftdm_io.c
@@ -171,7 +171,7 @@ static void stop_chan_io_dump(ftdm_io_dump_t *dump)
 		return;
 	}
 	ftdm_safe_free(dump->buffer);
-	memset(dump, 0, sizeof(dump));
+	memset(dump, 0, sizeof(*dump));
 }
 
 static ftdm_status_t start_chan_io_dump(ftdm_channel_t *chan, ftdm_io_dump_t *dump, ftdm_size_t size)
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c
index c7bd95947b..c1595c39dd 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_cli.c
@@ -124,6 +124,7 @@ static ftdm_status_t handle_show_sctp_profile(ftdm_stream_handle_t *stream, char
 static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream);
 static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char* m2ua_profile_name);
 static ftdm_status_t handle_show_m2ua_peer_status(ftdm_stream_handle_t *stream, char* m2ua_profile_name);
+static ftdm_status_t handle_show_m2ua_cluster_status(ftdm_stream_handle_t *stream, char* m2ua_profile_name);
 static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream);
 static ftdm_status_t handle_show_nif_profile(ftdm_stream_handle_t *stream, char* profile_name);
 int get_assoc_resp_buf(char* buf,SbMgmt* cfm);
@@ -427,10 +428,17 @@ ftdm_status_t ftdm_sngss7_handle_cli_cmd(ftdm_stream_handle_t *stream, const cha
 					{
 						char* profile_name = argv[++c];
 						c++;
+						/***************************************************************/
 						if(!strcasecmp(argv[c],"peerstatus")){
+						/***************************************************************/
 							handle_show_m2ua_peer_status(stream, profile_name);
-						}
-						else{
+						/***************************************************************/
+						}else if(!strcasecmp(argv[c],"clusterstatus")){
+						/***************************************************************/
+							handle_show_m2ua_cluster_status(stream, profile_name);
+						/***************************************************************/
+						} else{
+						/***************************************************************/
 							stream->write_function(stream, "Unknown \"show m2ua \" command..\n");
 							goto handle_cli_error_argc;
 						}
@@ -933,6 +941,7 @@ static ftdm_status_t handle_print_usage(ftdm_stream_handle_t *stream)
 	stream->write_function(stream, "ftdm ss7 xmlshow m2ua \n");
 	stream->write_function(stream, "ftdm ss7 xmlshow m2ua <m2ua_interface_name>\n");
 	stream->write_function(stream, "ftdm ss7 xmlshow m2ua <m2ua_interface_name> peerstatus\n");
+	stream->write_function(stream, "ftdm ss7 xmlshow m2ua <m2ua_interface_name> clusterstatus\n");
 	stream->write_function(stream, "ftdm ss7 xmlshow nif \n");
 	stream->write_function(stream, "ftdm ss7 xmlshow nif <nif_interface_name>\n");
 	stream->write_function(stream, "\n");
@@ -3113,7 +3122,7 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream)
 	len = len + sprintf(buf + len, "<m2ua_profiles>\n");
 
 	if(ftmod_m2ua_ssta_req(STMWGEN, 0x00, &cfm)) {
-		stream->write_function(stream," Request to Trillium M2UA layer failed \n");
+		stream->write_function(stream," Request to  layer failed \n");
 		return FTDM_FAIL;
 	} else {
 		len = len + sprintf(buf + len, "<m2ua_gen>\n");
@@ -3142,7 +3151,7 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream)
 			 len = len + sprintf(buf + len, "<name> %s </name>\n", g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].name);
 
 			 if(ftmod_m2ua_ssta_req(STMWDLSAP,x,&cfm)) {
-				 stream->write_function(stream," Request to Trillium SCTP layer failed \n");
+				 stream->write_function(stream," Request to M2UA  layer failed \n");
 				 return FTDM_FAIL;
 			 } else {
 				 len = len + sprintf(buf + len, "<m2ua_dlsap>\n");
@@ -3156,7 +3165,7 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream)
 
 			 memset((U8 *)&cfm, 0, sizeof(MwMgmt));
 			 if(ftmod_m2ua_ssta_req(STMWCLUSTER,g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].clusterId,&cfm)) {
-				 stream->write_function(stream," Request to Trillium SCTP layer failed \n");
+				 stream->write_function(stream," Request to  M2UA layer failed \n");
 				 return FTDM_FAIL;
 			 } else {
 				 len = len + sprintf(buf + len, "<m2ua_cluster>\n");
@@ -3187,18 +3196,14 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream)
 					 if(LMW_PEER_DOWN != rsp.t.ssta.s.clusterSta.peerSt[idx].peerState){
 
 						 if(ftmod_m2ua_ssta_req(STMWPEER, peer_id, &cfm)) {
-							 stream->write_function(stream," Request to Trillium SCTP layer failed \n");
+							 stream->write_function(stream," Request to M2UA  layer failed \n");
 							 return FTDM_FAIL;
 						 } else {
 							 len = len + sprintf(buf + len, "<m2ua_peer>\n");
 							 len = len + sprintf(buf + len, "<name> %s </name>\n",g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[peer_id].name);
 							 len = len + sprintf(buf + len," <state> %s </state>\n", PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.peerSta.state));
 							 len = len + sprintf(buf + len, " <retry_count> %d </retry_count>\n",cfm.t.ssta.s.peerSta.retryCount);
-#ifdef BIT_64							 
-							 len = len + sprintf(buf + len, " <assoc_id> %d </assoc_id>\n", (int64_t) cfm.t.ssta.s.peerSta.assocSta.spAssocId);
-#else
-							 len = len + sprintf(buf + len, " <assoc_id> %lld </assoc_id>\n", (int64_t) cfm.t.ssta.s.peerSta.assocSta.spAssocId);
-#endif
+							 len = len + sprintf(buf + len, " <assoc_id> %d </assoc_id>\n", (int)cfm.t.ssta.s.peerSta.assocSta.spAssocId);
 							 len = len + sprintf(buf + len, " <connected_status> %s </connected_status>\n",(cfm.t.ssta.s.peerSta.assocSta.connected)?"CONNECTED":"NOT CONNECTED");
 							 len = len + sprintf(buf + len, " <flow_cntrl_progress> %d </flow_cntrl_progress>\n",cfm.t.ssta.s.peerSta.assocSta.flcInProg);
 							 len = len + sprintf(buf + len, " <flow_cntrl_level> %d </flow_cntrl_level>\n",cfm.t.ssta.s.peerSta.assocSta.flcLevel);
@@ -3218,17 +3223,13 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream)
 
 			 memset((U8 *)&cfm, 0, sizeof(MwMgmt));
 			 if(ftmod_m2ua_ssta_req(STMWSCTSAP,x,&cfm)) {
-				 stream->write_function(stream," Request to Trillium SCTP layer failed \n");
+				 stream->write_function(stream," Request to M2UA layer failed \n");
 				 return FTDM_FAIL;
 			 } else {
 				 len = len + sprintf(buf + len, "<m2ua_sctp_sap>\n");
 				 len = len + sprintf(buf + len," <state> %s </state>\n", PRNT_M2UA_SAP_STATE(cfm.t.ssta.s.sctSapSta.state));
 				 len = len + sprintf(buf + len," <end_point_open_state> %s </end_point_open_state>\n", (cfm.t.ssta.s.sctSapSta.endpOpen)?"END_POINT_OPENED_SUCCESSFULLY":"END_POINT_NOT_OPEN");
-#ifdef BIT_64							 
-				 len = len + sprintf(buf + len," <end_point_id> %d </end_point_id>\n", (int64_t) cfm.t.ssta.s.sctSapSta.spEndpId);
-#else
-				 len = len + sprintf(buf + len," <end_point_id> %lld </end_point_id>\n", (int64_t) cfm.t.ssta.s.sctSapSta.spEndpId);
-#endif
+				 len = len + sprintf(buf + len," <end_point_id> %d </end_point_id>\n", (int) cfm.t.ssta.s.sctSapSta.spEndpId);
 				 len = len + sprintf(buf + len," <nmb_of_retry_attemp> %d </nmb_of_retry_attemp>\n", cfm.t.ssta.s.sctSapSta.nmbPrimRetry);
 				 len = len + sprintf(buf + len, "</m2ua_sctp_sap>\n");
 			 }
@@ -3241,7 +3242,7 @@ static ftdm_status_t handle_show_m2ua_profiles(ftdm_stream_handle_t *stream)
 	len = len + sprintf(buf + len, "</m2ua_profiles>\n");
 	stream->write_function(stream,"\n%s\n",buf); 
 
-	return FTDM_FAIL;
+	return FTDM_SUCCESS;
 
 }
 
@@ -3294,7 +3295,7 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char
 	len = len + sprintf(buf + len, "<name> %s </name>\n", m2ua_profile_name);
 
 	if(ftmod_m2ua_ssta_req(STMWDLSAP,x,&cfm)) {
-		stream->write_function(stream," Request to Trillium SCTP layer failed \n");
+		stream->write_function(stream," Request to M2UA layer failed \n");
 		return FTDM_FAIL;
 	} else {
 		len = len + sprintf(buf + len, "<m2ua_dlsap>\n");
@@ -3307,7 +3308,7 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char
 	}
 
 	if(ftmod_m2ua_ssta_req(STMWCLUSTER, g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].clusterId, &cfm)) {
-		stream->write_function(stream," Request to Trillium SCTP layer failed \n");
+		stream->write_function(stream," Request to M2UA layer failed \n");
 		return FTDM_FAIL;
 	} else {
 		len = len + sprintf(buf + len, "<m2ua_cluster>\n");
@@ -3333,7 +3334,7 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char
 		memset((U8 *)&cfm, 0, sizeof(MwMgmt));
 
 		if(ftmod_m2ua_ssta_req(STMWPEER, rsp.t.ssta.s.clusterSta.peerSt[idx].peerId, &cfm)) {
-			stream->write_function(stream," Request to Trillium SCTP layer failed \n");
+			stream->write_function(stream," Request to M2UA layer failed \n");
 			return FTDM_FAIL;
 		} else {
 			len = len + sprintf(buf + len, "<m2ua_peer>\n");
@@ -3356,7 +3357,7 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char
 	}
 
 	if(ftmod_m2ua_ssta_req(STMWSCTSAP,x,&cfm)) {
-		stream->write_function(stream," Request to Trillium SCTP layer failed \n");
+		stream->write_function(stream," Request to M2UA layer failed \n");
 		return FTDM_FAIL;
 	} else {
 		len = len + sprintf(buf + len, "<m2ua_sctp_sap>\n");
@@ -3375,7 +3376,7 @@ static ftdm_status_t handle_show_m2ua_profile(ftdm_stream_handle_t *stream, char
 
 	stream->write_function(stream,"\n%s\n",buf); 
 
-	return FTDM_FAIL;
+	return FTDM_SUCCESS;
 
 }
 
@@ -3401,7 +3402,7 @@ static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream)
 	len = len + sprintf(buf + len, "<sctp_profiles>\n");
 
 	if(ftmod_sctp_ssta_req(STSBGEN, 0x00, &cfm)) {
-		stream->write_function(stream," Request to Trillium SCTP layer failed \n");
+		stream->write_function(stream," Request to  SCTP layer failed \n");
 		return FTDM_FAIL;
 	} else {
 		len = len + sprintf(buf + len, "<sctp_gen>\n");
@@ -3421,7 +3422,7 @@ static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream)
 
 #ifdef LSB12
 	if(ftmod_sctp_ssta_req(STSBTMR, 0x00, &cfm)) {
-		stream->write_function(stream," Request to Trillium SCTP layer failed \n");
+		stream->write_function(stream," Request to  SCTP layer failed \n");
 		return FTDM_FAIL;
 	} else {
 		len = len + sprintf(buf + len, "<sctp_timers>\n");
@@ -3453,7 +3454,7 @@ static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream)
 			len = len + sprintf(buf + len, "<sctp_profile>\n");
 
 			if(ftmod_sctp_ssta_req(STSBSCTSAP,x,&cfm)) {
-				stream->write_function(stream," Request to Trillium SCTP layer failed \n");
+				stream->write_function(stream," Request to  SCTP layer failed \n");
 				return FTDM_FAIL;
 			} else {
 				len = len + sprintf(buf + len, "<sctp_sap>\n");
@@ -3463,7 +3464,7 @@ static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream)
 			}
 
 			if(ftmod_sctp_ssta_req(STSBTSAP,x,&cfm)) {
-				stream->write_function(stream," Request to Trillium SCTP layer failed \n");
+				stream->write_function(stream," Request to  SCTP layer failed \n");
 				return FTDM_FAIL;
 			} else {
 				len = len + sprintf(buf + len, "<sctp_transport_sap>\n");
@@ -3478,7 +3479,7 @@ static ftdm_status_t handle_show_sctp_profiles(ftdm_stream_handle_t *stream)
 					len = len + sprintf(buf + len, " <status> SCT_ASSOC_STATE_CLOSED </status>\n");
 					len = len + sprintf(buf + len, "</sctp_association>\n");
 				}else{
-					stream->write_function(stream," Request to Trillium SCTP layer failed \n");
+					stream->write_function(stream," Request to  SCTP layer failed \n");
 					return FTDM_FAIL;
 				}
 			} else {
@@ -3647,7 +3648,7 @@ static ftdm_status_t handle_show_sctp_profile(ftdm_stream_handle_t *stream, char
 	len = len + sprintf(buf + len, "<sctp_profile>\n");
 
 	if(ftmod_sctp_ssta_req(STSBSCTSAP,x,&cfm)) {
-		stream->write_function(stream," Request to Trillium SCTP layer failed \n");
+		stream->write_function(stream," Request to  SCTP layer failed \n");
 		return FTDM_FAIL;
 	} else {
 		len = len + sprintf(buf + len, "<sctp_sap>\n");
@@ -3657,7 +3658,7 @@ static ftdm_status_t handle_show_sctp_profile(ftdm_stream_handle_t *stream, char
 	}
 
 	if(ftmod_sctp_ssta_req(STSBTSAP,x,&cfm)) {
-		stream->write_function(stream," Request to Trillium SCTP layer failed \n");
+		stream->write_function(stream," Request to  SCTP layer failed \n");
 		return FTDM_FAIL;
 	} else {
 		len = len + sprintf(buf + len, "<sctp_transport_sap>\n");
@@ -3673,7 +3674,7 @@ static ftdm_status_t handle_show_sctp_profile(ftdm_stream_handle_t *stream, char
 			len = len + sprintf(buf + len, " <status> SCT_ASSOC_STATE_CLOSED </status>\n");
 			len = len + sprintf(buf + len, "</sctp_association>\n");
 		}else{
-			stream->write_function(stream," Request to Trillium SCTP layer failed \n");
+			stream->write_function(stream," Request to  SCTP layer failed \n");
 			return FTDM_FAIL;
 		}
 	} else {
@@ -3713,7 +3714,7 @@ static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream)
 	len = len + sprintf(buf + len, "<nif_profiles>\n");
 
 	if(ftmod_nif_ssta_req(STNWGEN, 0x00, &cfm)) {
-		stream->write_function(stream," Request to Trillium NIF layer failed \n");
+		stream->write_function(stream," Request to  NIF layer failed \n");
 		return FTDM_FAIL;
 	} else {
 		len = len + sprintf(buf + len, "<nif_gen>\n");
@@ -3736,7 +3737,7 @@ static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream)
 			len = len + sprintf(buf + len, "<nif_profile>\n");
 
 			if(ftmod_nif_ssta_req(STNWDLSAP,x,&cfm)) {
-				stream->write_function(stream," Request to Trillium SCTP layer failed \n");
+				stream->write_function(stream," Request to NIF layer failed \n");
 				return FTDM_FAIL;
 			} else {
 				len = len + sprintf(buf + len, "<nif_dlsap>\n");
@@ -3758,7 +3759,7 @@ static ftdm_status_t handle_show_nif_profiles(ftdm_stream_handle_t *stream)
 	len = len + sprintf(buf + len, "</nif_profiles>\n");
 	stream->write_function(stream,"\n%s\n",buf); 
 
-	return FTDM_FAIL;
+	return FTDM_SUCCESS;
 }
 
 /******************************************************************************
@@ -3805,7 +3806,7 @@ static ftdm_status_t handle_show_nif_profile(ftdm_stream_handle_t *stream, char*
 	len = len + sprintf(buf + len, "<nif_profile>\n");
 
 	if(ftmod_nif_ssta_req(STNWDLSAP,x,&cfm)) {
-		stream->write_function(stream," Request to Trillium SCTP layer failed \n");
+		stream->write_function(stream," Request to NIF layer failed \n");
 		return FTDM_FAIL;
 	} else {
 		len = len + sprintf(buf + len, "<nif_dlsap>\n");
@@ -3823,7 +3824,7 @@ static ftdm_status_t handle_show_nif_profile(ftdm_stream_handle_t *stream, char*
 
 	stream->write_function(stream,"\n%s\n",buf); 
 
-	return FTDM_FAIL;
+	return FTDM_SUCCESS;
 }
 
 /******************************************************************************/
@@ -3883,7 +3884,7 @@ static ftdm_status_t handle_show_m2ua_peer_status(ftdm_stream_handle_t *stream,
 		peer = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[peer_id];
 
 		if(ftmod_m2ua_ssta_req(STMWPEER, peer_id, &cfm)) {
-			stream->write_function(stream," Request to Trillium M2UA layer failed \n");
+			stream->write_function(stream," Request to  M2UA layer failed \n");
 			return FTDM_FAIL;
 		} else {
 			len = len + sprintf(buf + len, "<m2ua_peer>\n");
@@ -3902,7 +3903,7 @@ static ftdm_status_t handle_show_m2ua_peer_status(ftdm_stream_handle_t *stream,
 				len = len + sprintf(buf + len, " <status> SCT_ASSOC_STATE_CLOSED </status>\n");
 				len = len + sprintf(buf + len, "</sctp_association>\n");
 			}else{
-				stream->write_function(stream," Request to Trillium SCTP layer failed \n");
+				stream->write_function(stream," Request to SCTP layer failed \n");
 				return FTDM_FAIL;
 			}
 		} else {
@@ -3914,7 +3915,82 @@ static ftdm_status_t handle_show_m2ua_peer_status(ftdm_stream_handle_t *stream,
 
 	stream->write_function(stream,"\n%s\n",buf); 
 
-	return FTDM_FAIL;
+	return FTDM_SUCCESS;
+}
+
+/******************************************************************************
+* Fun:  handle_show_m2ua_cluster_status()
+* Desc: display requested m2ua profile cluster information
+* Ret:  FTDM_SUCCESS | FTDM_FAIL
+* Note: 
+* author: Kapil Gupta
+*******************************************************************************/
+
+static ftdm_status_t handle_show_m2ua_cluster_status(ftdm_stream_handle_t *stream, char* m2ua_profile_name) 
+{
+	char*  xmlhdr = (char*)"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>";
+	char  buf[4096];
+	int x = 0x00;
+	int found = 0x00;
+	int len = 0x00;
+	int idx = 0x00;
+	MwMgmt cfm;
+	SbMgmt sctp_cfm;
+	sng_m2ua_cluster_cfg_t*     clust = NULL; 
+	sng_m2ua_cfg_t*             m2ua  = NULL;
+
+	memset((U8 *)&cfm, 0, sizeof(MwMgmt));
+	memset((U8 *)&sctp_cfm, 0, sizeof(SbMgmt));
+	memset(&buf[0], 0, sizeof(buf));
+
+	len = len + sprintf(buf + len, "%s\n", xmlhdr);
+
+	/*iterate through all the m2ua links and get required profile */
+	x = 1;
+	while(x<MW_MAX_NUM_OF_INTF){
+		if((g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].id !=0) &&
+				((g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].flags & SNGSS7_ACTIVE))) {
+
+			if(!strcasecmp(m2ua_profile_name, g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].name)){
+				found = 0x01;
+				break;
+			}
+		}
+		x++;
+	}
+
+	if(!found){
+		stream->write_function(stream,"Requested M2UA profile[%s] not configured\n", m2ua_profile_name);
+		return FTDM_FAIL;
+	}
+
+	m2ua  = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x];
+	clust = &g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_clus[m2ua->clusterId];
+
+	if(ftmod_m2ua_ssta_req(STMWCLUSTER,g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua[x].clusterId,&cfm)) {
+		stream->write_function(stream," Request to M2UA layer failed \n");
+		return FTDM_FAIL;
+	} else {
+		len = len + sprintf(buf + len, "<m2ua_cluster>\n");
+		len = len + sprintf(buf + len, "<name> %s </name>\n",clust->name);
+		len = len + sprintf(buf + len," <state> %s </state>\n", PRNT_M2UA_CLUSTER_STATE(cfm.t.ssta.s.clusterSta.state));
+		len = len + sprintf(buf + len, "<num_of_peers> %d </num_of_peers>\n",cfm.t.ssta.s.clusterSta.nmbPeer);
+		for(idx = 0; idx < cfm.t.ssta.s.clusterSta.nmbPeer; idx++)
+		{
+			len = len + sprintf(buf + len, "<m2ua_cluster_peer>\n");
+			len = len + sprintf(buf + len, " <peer_name> %s </peer_name>\n", g_ftdm_sngss7_data.cfg.g_m2ua_cfg.m2ua_peer[cfm.t.ssta.s.clusterSta.peerSt[idx].peerId].name);
+			len = len + sprintf(buf + len, " <peer_id> %d </peer_id>\n", cfm.t.ssta.s.clusterSta.peerSt[idx].peerId);
+			len = len + sprintf(buf + len, " <peer_state> %s </peer_state>\n",  PRNT_M2UA_PEER_STATE(cfm.t.ssta.s.clusterSta.peerSt[idx].peerState));
+			len = len + sprintf(buf + len, "</m2ua_cluster_peer>\n");
+		}
+		len = len + sprintf(buf + len, "<num_active_peer> %d </num_active_peer>\n",cfm.t.ssta.s.clusterSta.nmbActPeer);
+
+		len = len + sprintf(buf + len, "</m2ua_cluster>\n");
+	}
+
+	stream->write_function(stream,"\n%s\n",buf); 
+
+	return FTDM_SUCCESS;
 }
 
 /******************************************************************************/
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c
index ccaf3ce418..5b173bfc8b 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_m2ua.c
@@ -793,10 +793,10 @@ static int ftmod_m2ua_peer_config(int id)
 			ftdm_log (FTDM_LOG_INFO, " ftmod_m2ua_sctsap_config: M2UA SCTSAP for M2UA Intf Id[%d] config SUCCESS \n", id);
 		}
 		if(ftmod_m2ua_peer_config1(id, peer_id)){
-			ftdm_log (FTDM_LOG_ERROR, " ftmod_m2ua_peer_config1: M2UA Peer configuration for M2UA Intf Id[%d] config FAILED \n", id);
+			ftdm_log (FTDM_LOG_ERROR, " ftmod_m2ua_peer_config1: M2UA Peer[%d] configuration for M2UA Intf Id[%d] config FAILED \n", peer_id, id);
 			return 0x01;
 		}else{
-			ftdm_log (FTDM_LOG_INFO, " ftmod_m2ua_peer_config1: M2UA Peer configuration for M2UA Intf Id[%d] config SUCCESS \n", id);
+			ftdm_log (FTDM_LOG_INFO, " ftmod_m2ua_peer_config1: M2UA Peer[%d] configuration for M2UA Intf Id[%d] config SUCCESS \n", peer_id, id);
 		}
 
 		clust->sct_sap_id = id;
@@ -813,13 +813,28 @@ static int ftmod_m2ua_peer_config(int id)
 static int ftmod_m2ua_sctsap_config(int sct_sap_id, int sctp_id)
 {
    int    i;
+   int    ret;
    Pst    pst; 
    MwMgmt cfg;
+   MwMgmt cfm;
    sng_sctp_link_t *sctp = &g_ftdm_sngss7_data.cfg.sctpCfg.linkCfg[sctp_id];
 
+
+
    memset((U8 *)&cfg, 0, sizeof(MwMgmt));
+   memset((U8 *)&cfm, 0, sizeof(MwMgmt));
    memset((U8 *)&pst, 0, sizeof(Pst));
 
+   /* check is sct_sap is already configured */
+   if(!ftmod_m2ua_ssta_req(STMWSCTSAP, sct_sap_id, &cfm )){
+	   ftdm_log (FTDM_LOG_INFO, " ftmod_m2ua_sctsap_config: SCT SAP [%s] is already configured \n", sctp->name);
+	   return 0x00;
+   }
+
+   if(LCM_REASON_INVALID_SAP == cfm.cfm.reason){
+	   ftdm_log (FTDM_LOG_INFO, " ftmod_m2ua_sctsap_config: SCT SAP [%s] is not configured..configuring now \n", sctp->name);
+   }
+
    smPstInit(&pst);
 
    pst.dstEnt = ENTMW;
@@ -880,8 +895,11 @@ static int ftmod_m2ua_sctsap_config(int sct_sap_id, int sctp_id)
    cfg.t.cfg.s.sctSapCfg.reConfig.mem.region    = S_REG;
    cfg.t.cfg.s.sctSapCfg.reConfig.mem.pool      = S_POOL;
 
-     return (sng_cfg_m2ua (&pst, &cfg));
+     if (0 == (ret = sng_cfg_m2ua (&pst, &cfg))){
+		sctp->flags |= SNGSS7_CONFIGURED;
+     }
 
+     return ret;
 }
 
 /****************************************************************************************************/
diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c
index 027544a00a..781c0963f8 100644
--- a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c
+++ b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c
@@ -81,6 +81,7 @@ struct sdp_parser_s {
   unsigned   pr_insane : 1;
   unsigned   pr_c_missing : 1;
   unsigned   pr_config : 1;
+  unsigned   pr_megaco : 1;
 };
 
 #define is_posdigit(c) ((c) >= '1' && (c) <= '9')
@@ -176,6 +177,7 @@ sdp_parse(su_home_t *home, char const msg[], issize_t msgsize, int flags)
     if (flags & sdp_f_config)
       p->pr_c_missing = 1, p->pr_config = 1;
     p->pr_mode_manual = (flags & sdp_f_mode_manual) != 0;
+	p->pr_megaco = (flags & sdp_f_megaco) != 0;
     p->pr_session_mode = sdp_sendrecv;
 
     parse_message(p);
@@ -1502,8 +1504,18 @@ static void parse_payload(sdp_parser_t *p, char *r, sdp_rtpmap_t **result)
 {
   while (*r) {
     unsigned long value;
+	 if (((p->pr_config && r[0] == '*') || (p->pr_megaco && r[0] == MEGACO_CHOOSE_TOK)) && (r[1] == ' ' || r[1] == '\0')) {
+      PARSE_ALLOC(p, sdp_rtpmap_t, rm);
 
-    if (parse_ul(p, &r, &value, 128) == 0) {
+      *result = rm; result = &rm->rm_next;
+
+      rm->rm_predef = 1;
+      rm->rm_any = 1;
+      rm->rm_encoding = "*";
+      rm->rm_rate = 0;
+
+      return;
+    } else if (parse_ul(p, &r, &value, 128) == 0  && value < 128) {
       PARSE_ALLOC(p, sdp_rtpmap_t, rm);
 
       assert(0 <= value && value < 128);
@@ -1519,21 +1531,8 @@ static void parse_payload(sdp_parser_t *p, char *r, sdp_rtpmap_t **result)
 	rm->rm_encoding = "";
 	rm->rm_rate = 0;
       }
-    }
-    else if (p->pr_config && r[0] == '*' && (r[1] == ' ' || r[1] == '\0')) {
-      PARSE_ALLOC(p, sdp_rtpmap_t, rm);
-
-      *result = rm; result = &rm->rm_next;
-
-      rm->rm_predef = 1;
-      rm->rm_any = 1;
-      rm->rm_encoding = "*";
-      rm->rm_rate = 0;
-
-      return;
-    }
-    else {
-      parsing_error(p, "m= invalid format for RTP/AVT");
+    } else {
+      parsing_error(p, "m= invalid format for RTP/AVP");
 
       return;
     }
@@ -1797,6 +1796,13 @@ static int parse_ul(sdp_parser_t *p, char **r,
     return 0;
   }
 
+  if (p->pr_megaco && *ul == MEGACO_CHOOSE_TOK) {
+	*result = MEGACO_CHOOSE;
+	(*r)++;
+    *r += strspn(*r, SPACE TAB);
+	return 0;
+  }
+
   return -1;
 }
 
@@ -1824,6 +1830,13 @@ static int parse_ull(sdp_parser_t *p, char **r,
     return 0;
   }
 
+  if (p->pr_megaco && *s == MEGACO_CHOOSE_TOK) {
+	*result = MEGACO_CHOOSE;
+	(*r)++;
+    *r += strspn(*r, SPACE TAB);
+	return 0;
+  }
+
   return -1;
 }
 
diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h b/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h
index e4af3836a3..74d6adea4f 100644
--- a/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h
+++ b/libs/sofia-sip/libsofia-sip-ua/sdp/sofia-sip/sdp.h
@@ -24,6 +24,10 @@
 
 #ifndef SDP_H
 #define SDP_H
+
+#define MEGACO_CHOOSE_TOK '$'
+#define MEGACO_CHOOSE (UINT16_MAX + 1)
+
 /**@file sofia-sip/sdp.h  Simple SDP (RFC 2327) Interface.
  *
  * @author Pekka Pessi <Pekka.Pessi@nokia.com>
@@ -260,7 +264,7 @@ typedef enum {
 /** Media announcement.
  *
  * This structure describes one media type, e.g., audio.  The description
- * contains the transport address (IP address and port) used for the group,
+ * contains the transport address (IP address and port) used for the group,/Users/mrene/Downloads
  * the transport protocol used, the media formats or RTP payload types, and
  * optionally media-specific bandwidth specification, encryption key and
  * attributes.
@@ -525,7 +529,9 @@ enum sdp_parse_flags_e {
   /** Do not generate or parse SDP mode */
   sdp_f_mode_manual = 512,
   /** Always generate media-level mode attributes */
-  sdp_f_mode_always = 1024
+  sdp_f_mode_always = 1024,
+  /** Allow optional (choose) parameters */
+  sdp_f_megaco = 2048
 };
 
 /** SDP parser handle. */
diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c
index 591bb5f13d..ebc7b869f6 100644
--- a/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c
+++ b/src/mod/endpoints/mod_media_gateway/media_gateway_stack.c
@@ -257,6 +257,8 @@ switch_status_t sng_mgco_start(megaco_profile_t* profile )
 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, " mgco_mg_tsap_enable_cntrl SUCCESS \n");
 	}
 
+	mgco_mg_enble_debug();
+
 	return SWITCH_STATUS_SUCCESS;
 }
 
diff --git a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c
index 2d584ed0ed..ba5c20aabb 100644
--- a/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c
+++ b/src/mod/endpoints/mod_media_gateway/media_gateway_xml.c
@@ -12,6 +12,7 @@
 static switch_xml_config_item_t *get_instructions(megaco_profile_t *profile) ;
 static switch_xml_config_item_t *get_peer_instructions(mg_peer_profile_t *profile) ;
 static int mg_sap_id;
+static switch_status_t modify_mid(char* mid);
 
 /****************************************************************************************************************************/
 switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload)
@@ -57,6 +58,10 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload)
 			profile->total_peers++;
 		}
 
+		if(SWITCH_STATUS_FALSE == (status = modify_mid(profile->mid))){
+			goto done;
+		}
+
 		profile->idx = ++mg_sap_id;
 
 		/* we should break from here , profile name should be unique */
@@ -92,6 +97,10 @@ switch_status_t config_profile(megaco_profile_t *profile, switch_bool_t reload)
 					goto done;
 				}
 
+				if(SWITCH_STATUS_FALSE == (status = modify_mid(peer_profile->mid))){
+					goto done;
+				}
+
 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"peer_profile name[%s], ipaddr[%s] port[%s], mid[%s] transport_type[%s], encoding_type[%s] \n",
 						peer_profile->name, peer_profile->ipaddr, peer_profile->port,peer_profile->mid, peer_profile->transport_type, peer_profile->encoding_type);
 
@@ -190,3 +199,54 @@ static switch_xml_config_item_t *get_instructions(megaco_profile_t *profile) {
 }
 
 /****************************************************************************************************************************/
+
+static switch_status_t modify_mid(char* mid)
+{
+	char* 			dup = NULL;
+	char* 			val[10];
+	int 			count;
+
+	switch_assert(mid);
+
+	/* If MID type is IP then add mid into [] brackets ,
+	 * If MID type is domain then add mid into <> brackets *
+	 */
+
+	dup = strdup(mid);
+	count = switch_split(dup, '.', val);
+
+	if(!count) {
+		/* Input string is not separated by '.', check if its separated by '-' as format could be xxx-xx-xxx/xxx-xx-xx-xxx  */
+		free(dup);
+		dup = strdup(mid);
+		if(0 == (count = switch_split(dup, '-', val))){
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid input MID string[%s]\n",mid);
+			return SWITCH_STATUS_FALSE;
+		}
+	}
+
+	if(('<' == val[0][0]) || ('[' == val[0][0])){
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MID[%s] is already prefixed with proper brackets \n",mid);
+		return SWITCH_STATUS_SUCCESS;
+	}
+	
+	/*first check could be if count is 3 means domain name as generally we have xxx-xx-xxx/xxx.xx.xxx domain */
+	if(3 == count){
+		/* domain-type, add value into <> */
+		free(dup);
+		dup = strdup(mid);
+		sprintf(mid,"<%s>",dup);
+	}else if(4 == count){
+		/* IP address in xxx.xxx.xxx.xxx format */
+		free(dup);
+		dup = strdup(mid);
+		sprintf(mid,"[%s]",dup);
+	}else {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid input MID string[%s]\n",mid);
+		return SWITCH_STATUS_FALSE;
+	}
+
+
+	free(dup);
+	return SWITCH_STATUS_SUCCESS;
+}
diff --git a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c
index bcc66cc396..30de4f86fc 100644
--- a/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c
+++ b/src/mod/endpoints/mod_media_gateway/mod_media_gateway.c
@@ -118,14 +118,14 @@ void handle_sng_log(uint8_t level, char *fmt, ...)
 		case SNG_LOGLEVEL_DEBUG:    log_level = SWITCH_LOG_DEBUG;       break;
 		case SNG_LOGLEVEL_INFO:     log_level = SWITCH_LOG_INFO;        break;
 		case SNG_LOGLEVEL_WARN:     log_level = SWITCH_LOG_WARNING;     break;
-		case SNG_LOGLEVEL_ERROR:    log_level = SWITCH_LOG_ERROR;       break;
+		case SNG_LOGLEVEL_ERROR:    log_level = SWITCH_LOG_DEBUG;       break;
 		case SNG_LOGLEVEL_CRIT:     log_level = SWITCH_LOG_CRIT;        break;
 		default:                    log_level = SWITCH_LOG_DEBUG;       break;
 	};
 
 	vsprintf(&print_buf[0], fmt, ptr);
 
-	switch_log_printf(SWITCH_CHANNEL_LOG, log_level, " MOD_MEGACO: %s \n", &print_buf[0]); 
+	switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, log_level, " MOD_MEGACO: %s \n", &print_buf[0]); 
 
 	va_end(ptr);
 }
diff --git a/src/mod/endpoints/mod_sofia/Makefile.am b/src/mod/endpoints/mod_sofia/Makefile.am
index fb0ab25e0b..efd6b2c385 100644
--- a/src/mod/endpoints/mod_sofia/Makefile.am
+++ b/src/mod/endpoints/mod_sofia/Makefile.am
@@ -9,7 +9,7 @@ SOFIAUA_BUILDDIR=$(SOFIA_BUILDDIR)/libsofia-sip-ua
 SOFIALA=$(SOFIAUA_BUILDDIR)/libsofia-sip-ua.la
 
 mod_LTLIBRARIES = mod_sofia.la
-mod_sofia_la_SOURCES = mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sip-dig.c mod_sofia.h
+mod_sofia_la_SOURCES = mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sip-dig.c rtp.c mod_sofia.h
 mod_sofia_la_CFLAGS  = $(AM_CFLAGS) -I. $(SOFIA_CMD_LINE_CFLAGS)
 mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/bnf -I$(SOFIAUA_BUILDDIR)/bnf
 mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/http -I$(SOFIAUA_BUILDDIR)/http
diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c
index e47fb85c46..0f598573c0 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.c
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.c
@@ -5634,6 +5634,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
 	SWITCH_ADD_API(api_interface, "sofia_count_reg", "Count Sofia registration", sofia_count_reg_function, "[profile/]<user>@<domain>");
 	SWITCH_ADD_API(api_interface, "sofia_dig", "SIP DIG", sip_dig_function, "<url>");
 	SWITCH_ADD_CHAT(chat_interface, SOFIA_CHAT_PROTO, sofia_presence_chat_send);
+    
+    crtp_init(*module_interface);
 
 	/* indicate that the module should continue to be loaded */
 	return SWITCH_STATUS_SUCCESS;
diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h
index 217c95af8c..fa4fdc0b10 100644
--- a/src/mod/endpoints/mod_sofia/mod_sofia.h
+++ b/src/mod/endpoints/mod_sofia/mod_sofia.h
@@ -1152,3 +1152,4 @@ void sofia_process_dispatch_event(sofia_dispatch_event_t **dep);
 char *sofia_glue_get_host(const char *str, switch_memory_pool_t *pool);
 void sofia_presence_check_subscriptions(sofia_profile_t *profile, time_t now);
 void sofia_msg_thread_start(int idx);
+void crtp_init(switch_loadable_module_interface_t *module_interface);
diff --git a/src/mod/endpoints/mod_sofia/rtp.c b/src/mod/endpoints/mod_sofia/rtp.c
new file mode 100644
index 0000000000..8920e684a7
--- /dev/null
+++ b/src/mod/endpoints/mod_sofia/rtp.c
@@ -0,0 +1,653 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Mathieu Rene <mrene@avgs.ca>
+ *
+ * rtp.c -- RTP Controllable Channel Module
+ *
+ */
+
+#include <switch.h>
+#include "mod_sofia.h"
+
+#define kRSDP "r_sdp"
+#define kLSDP "l_sdp"
+#define kBINDADDRESS "bind_address"
+#define kCODECSTRING "codec_string"
+
+static struct {
+    switch_memory_pool_t *pool;
+    switch_endpoint_interface_t *endpoint_interface;
+} crtp;
+
+typedef struct {
+    switch_core_session_t *session;
+    switch_channel_t *channel;
+    switch_codec_t read_codec, write_codec;
+    switch_frame_t read_frame;
+    
+    switch_rtp_bug_flag_t rtp_bugs;
+    switch_rtp_t *rtp_session;
+    
+    const char *bind_address;
+    
+    
+    const switch_codec_implementation_t *negotiated_codecs[SWITCH_MAX_CODECS];
+	int num_negotiated_codecs;
+    
+    char *origin;
+    
+    int local_port;
+
+} crtp_private_t;
+
+static switch_status_t channel_on_init(switch_core_session_t *session);
+static switch_status_t channel_on_destroy(switch_core_session_t *session);
+static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
+													switch_caller_profile_t *outbound_profile,
+													switch_core_session_t **new_session, 
+													switch_memory_pool_t **pool,
+													switch_originate_flag_t flags, switch_call_cause_t *cancel_cause);
+static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id);
+static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id);
+static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg);
+static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf);
+
+switch_state_handler_table_t crtp_state_handlers = {
+	.on_init = channel_on_init,
+	.on_destroy = channel_on_destroy
+};
+
+switch_io_routines_t crtp_io_routines = {
+	.outgoing_channel = channel_outgoing_channel,
+	.read_frame = channel_read_frame,
+	.write_frame = channel_write_frame,
+	.receive_message = channel_receive_message,
+    .send_dtmf = channel_send_dtmf
+};
+
+SWITCH_STANDARD_API(test_function)
+{
+    return SWITCH_STATUS_SUCCESS;
+}
+
+void crtp_init(switch_loadable_module_interface_t *module_interface)
+{
+    switch_endpoint_interface_t *endpoint_interface;
+    switch_api_interface_t *api_interface;
+    crtp.pool = module_interface->pool;
+    endpoint_interface = switch_loadable_module_create_interface(module_interface, SWITCH_ENDPOINT_INTERFACE);
+    endpoint_interface->interface_name = "rtp";
+    endpoint_interface->io_routines = &crtp_io_routines;
+    endpoint_interface->state_handler = &crtp_state_handlers;
+    crtp.endpoint_interface = endpoint_interface;
+    
+//    SWITCH_ADD_API(api_interface, "rtp_test", "test", test_function, "");
+}
+
+
+typedef struct parsed_sdp_s {
+    const char *c; /*!< Connection */
+    
+    
+} parsed_sdp_t;
+
+
+//static switch_status_t check_codec 
+
+/* 
+ * Setup the local RTP side
+ * A lot of values can be chosen by the MG, those will have $ as a placeholder.
+ * We need to validate the SDP, making sure we can support everything that's offered on our behalf, 
+ * amend it if we don't support everything, or systematically reject it if we cannot support it.
+ *
+ * Would this function be called using NULL as l_sdp, we will generate an SDP payload.
+ */
+
+static switch_status_t setup_local_rtp(crtp_private_t *tech_pvt, const char *l_sdp, const char *codec_string)
+{
+    switch_core_session_t const * session = tech_pvt->session;    
+    int num_codecs;
+    const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS] = { 0 };
+    
+    char *codec_order[SWITCH_MAX_CODECS] = { 0 };
+    int codec_order_last;
+
+    
+    /* Load in the list of codecs we support. If we have a codec string we use our priorities first */
+    if (codec_string) {
+		char *tmp_codec_string;
+		if ((tmp_codec_string = switch_core_session_strdup(tech_pvt->session, codec_string))) {
+			codec_order_last = switch_separate_string(tmp_codec_string, ',', codec_order, SWITCH_MAX_CODECS);
+			num_codecs = switch_loadable_module_get_codecs_sorted(codecs, SWITCH_MAX_CODECS, codec_order, codec_order_last);
+		}
+	} else {
+		num_codecs = switch_loadable_module_get_codecs(codecs, switch_arraylen(codecs));
+	}
+    
+    /* TODO: Look at remote settings */
+    
+    if (zstr(l_sdp)) {
+        /* Generate a local SDP here */
+        const char *sdpbuf = switch_core_session_sprintf(session, "v=0\nIN IP4 %s\nm=audio %d RTP/AVP %d");
+        
+    } else {
+        /* Parse the SDP and remove anything we cannot support, then validate it to make sure it contains at least one codec 
+         * so that we reject invalid ones. */
+#if 1
+        uint8_t match = 0;
+        int first = 0, last = 0;
+        int ptime = 0, dptime = 0, maxptime = 0, dmaxptime = 0;
+        int sendonly = 0, recvonly = 0;
+        int greedy = 0, x = 0, skip = 0, mine = 0;
+        int got_crypto = 0, got_audio = 0, got_avp = 0, got_savp = 0, got_udptl = 0;
+#endif
+        int sdp_modified = 0;
+        int cur_codec = 0;
+        
+        sdp_parser_t *parser = NULL;
+        sdp_session_t *sdp, *lsdp;
+        sdp_media_t *m;
+        sdp_attribute_t *attr;
+        su_home_t *sdp_home;
+        
+        if (!(parser = sdp_parse(NULL, l_sdp, (int) strlen(l_sdp), sdp_f_megaco /* accept $ values */ | sdp_f_insane /* accept omitted o= */))) {
+            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Malformed SDP\n");
+            goto fail;
+        }
+        
+        if (!(sdp = sdp_session(parser))) {
+            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't get session from sdp.\n");
+            goto fail;
+        }
+        sdp_home = sdp_parser_home(parser);
+        for (m = sdp->sdp_media; m; m = m->m_next) {
+            
+            if (m->m_type == sdp_media_audio) {
+                sdp_rtpmap_t *map;
+                
+                for (attr = m->m_attributes; attr; attr = attr->a_next) {
+                    if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) {
+                        ptime = atoi(attr->a_value);
+                    } else if (!strcasecmp(attr->a_name, "maxptime") && attr->a_value) {
+                        maxptime = atoi(attr->a_value);
+                    }
+                }
+            
+                sdp_connection_t *connection;
+                connection = sdp->sdp_connection;
+                if (m->m_connections) {
+                    connection = m->m_connections;
+                }
+            
+                /* Check for wildcards in m= (media) and c= (connection) */
+                if (!zstr(connection->c_address)) {
+                    if (!strcmp(connection->c_address, "$")) {
+                        connection->c_address =  su_strdup(sdp_home, tech_pvt->bind_address);
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Using bind address: %s\n", tech_pvt->bind_address);
+                        switch_channel_set_variable(tech_pvt->channel, kBINDADDRESS, tech_pvt->bind_address);    
+                        sdp_modified = 1;
+                    } else if (strcmp(connection->c_address, tech_pvt->bind_address)) {
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MGC requested to bind on [%s] which is different than the configuration [%s]\n",
+                                        connection->c_address, tech_pvt->bind_address);
+                        goto fail;
+                    }
+                    
+                    if (m->m_port == MEGACO_CHOOSE) {
+                        tech_pvt->local_port = m->m_port = switch_rtp_request_port(tech_pvt->bind_address);
+                        switch_channel_set_variable_printf(tech_pvt->channel, "rtp_local_port", "%d", tech_pvt->local_port);
+                        if (!tech_pvt->local_port) {
+                            /* Port request failed */
+                            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No available RTP ports on [%s]\n", tech_pvt->bind_address);
+                            goto fail;
+                        }
+                        sdp_modified = 1;
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Using local port: %d\n", tech_pvt->local_port);
+                    }
+                }
+                
+                /* Validate codecs */
+                for (map = m->m_rtpmaps; map; map = map->rm_next) {
+                    if (map->rm_any) {
+                        /* Pick our first favorite codec */
+                        if (codecs[cur_codec]) {
+                            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Choosing a codec: %s/%d\n", codecs[cur_codec]->iananame, codecs[cur_codec]->ianacode);
+                            map->rm_encoding = su_strdup(sdp_home, codecs[cur_codec]->iananame);
+                            map->rm_pt = codecs[cur_codec]->ianacode;
+                            map->rm_any = 0;
+                            map->rm_predef = codecs[cur_codec]->ianacode < 96;
+                            cur_codec++;
+                        } else {
+                            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No more codecs in preferences!\n");
+                            goto fail;
+                        }
+                    }
+                }
+            } else if (m->m_type == sdp_media_image && m->m_port) {
+                /* TODO: Handle T38 */
+                
+            }
+        }
+        char sdpbuf[2048] = "";
+        sdp_printer_t *printer = sdp_print(sdp_home, sdp, sdpbuf, sizeof(sdpbuf), 0);
+        switch_channel_set_variable(tech_pvt->channel, kLSDP, sdpbuf);
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Setting local SDP: [%s]\n", sdpbuf);
+        sdp_printer_free(printer);
+        
+        goto done;
+        
+        fail:
+        if (tech_pvt->local_port) {
+            switch_rtp_release_port(tech_pvt->bind_address, tech_pvt->local_port);
+        }
+        
+        if (parser) {
+            sdp_parser_free(parser);
+        }
+        
+        return SWITCH_STATUS_FALSE;
+    }
+    
+done:
+    return SWITCH_STATUS_SUCCESS;
+    
+}
+
+#if 0
+static void setup_rtp(crtp_private_t *tech_pvt, const char *r_sdp, const char *l_sdp)
+{
+    switch_core_session_t const * session = tech_pvt->session;
+    uint8_t match = 0;
+    int first = 0, last = 0;
+	int ptime = 0, dptime = 0, maxptime = 0, dmaxptime = 0;
+	int sendonly = 0, recvonly = 0;
+	int greedy = 0, x = 0, skip = 0, mine = 0;
+    int got_crypto = 0, got_audio = 0, got_avp = 0, got_savp = 0, got_udptl = 0;
+
+    sdp_parser_t *parser = NULL, *l_parser = NULL;
+	sdp_session_t *sdp, *lsdp;
+    sdp_media_t *m;
+	sdp_attribute_t *attr;
+    
+    
+    int scrooge = 0;
+    
+    
+    if (zstr(r_sdp)) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No SDP\n");
+        goto fail;
+    }
+    
+    if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Malformed SDP\n");
+        goto fail;
+	}
+    
+	if (!(sdp = sdp_session(parser))) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't get session from sdp.\n");
+        goto fail;
+	}
+
+    for (m = sdp->sdp_media; m; m = m->m_next) {
+        sdp_connection_t *connection;
+        ptime = dptime;
+		maxptime = dmaxptime;
+        
+		if (m->m_proto == sdp_proto_srtp) {
+			got_savp++;
+		} else if (m->m_proto == sdp_proto_rtp) {
+			got_avp++;
+		} else if (m->m_proto == sdp_proto_udptl) {
+			got_udptl++;
+		}
+        
+        if (got_udptl && m->m_type == sdp_media_image && m->m_port) {
+			//switch_t38_options_t *t38_options = tech_process_udptl(tech_pvt, sdp, m);
+            
+            /* TODO: Process T38 */
+
+        } else if (m->m_type == sdp_media_audio && m->m_port && !got_audio) {
+            sdp_rtpmap_t *map;
+
+            connection = sdp->sdp_connection;
+			if (m->m_connections) {
+				connection = m->m_connections;
+			}
+            
+			if (!connection) {
+				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
+				match = 0;
+				break;
+			}
+            
+            /* Begin Codec Negotiation */
+            for (map = m->m_rtpmaps; map; map = map->rm_next) {
+				int32_t i;
+				uint32_t near_rate = 0;
+				const switch_codec_implementation_t *mimp = NULL, *near_match = NULL;
+				const char *rm_encoding;
+				uint32_t map_bit_rate = 0;
+				int codec_ms = 0;
+				switch_codec_fmtp_t codec_fmtp = { 0 };
+                
+				if (x++ < skip) {
+					continue;
+				}
+                
+				if (!(rm_encoding = map->rm_encoding)) {
+					rm_encoding = "";
+				}
+                
+				if (!strcasecmp(rm_encoding, "telephone-event")) {
+					if (!best_te || map->rm_rate == tech_pvt->rm_rate) {
+						best_te = (switch_payload_t) map->rm_pt;
+					}9
+				}
+				
+				if (!cng_pt && !strcasecmp(rm_encoding, "CN")) {
+					cng_pt = (switch_payload_t) map->rm_pt;
+					if (tech_pvt->rtp_session) {
+						switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Set comfort noise payload to %u\n", cng_pt);
+						switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt);
+					}
+				}
+                
+				if (match) {
+					continue;
+				}
+                
+				if (greedy) {
+					first = mine;
+					last = first + 1;
+				} else {
+					first = 0;
+					last = num_codecs;
+				}
+                
+				codec_ms = ptime;
+                
+				if (maxptime && (!codec_ms || codec_ms > maxptime)) {
+					codec_ms = maxptime;
+				}
+                
+				if (!codec_ms) {
+					codec_ms = switch_default_ptime(rm_encoding, map->rm_pt);
+				}
+                
+				map_bit_rate = switch_known_bitrate((switch_payload_t)map->rm_pt);
+				
+				if (!ptime && !strcasecmp(map->rm_encoding, "g723")) {
+					ptime = codec_ms = 30;
+				}
+				
+				if (zstr(map->rm_fmtp)) {
+					if (!strcasecmp(map->rm_encoding, "ilbc")) {
+						ptime = codec_ms = 30;
+						map_bit_rate = 13330;
+					}
+				} else {
+					if ((switch_core_codec_parse_fmtp(map->rm_encoding, map->rm_fmtp, map->rm_rate, &codec_fmtp)) == SWITCH_STATUS_SUCCESS) {
+						if (codec_fmtp.bits_per_second) {
+							map_bit_rate = codec_fmtp.bits_per_second;
+						}
+						if (codec_fmtp.microseconds_per_packet) {
+							codec_ms = (codec_fmtp.microseconds_per_packet / 1000);
+						}
+					}
+				}
+                
+				
+				for (i = first; i < last && i < total_codecs; i++) {
+					const switch_codec_implementation_t *imp = codec_array[i];
+					uint32_t bit_rate = imp->bits_per_second;
+					uint32_t codec_rate = imp->samples_per_second;
+					if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) {
+						continue;
+					}
+                    
+					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Audio Codec Compare [%s:%d:%u:%d:%u]/[%s:%d:%u:%d:%u]\n",
+									  rm_encoding, map->rm_pt, (int) map->rm_rate, codec_ms, map_bit_rate,
+									  imp->iananame, imp->ianacode, codec_rate, imp->microseconds_per_packet / 1000, bit_rate);
+					if ((zstr(map->rm_encoding) || (tech_pvt->profile->ndlb & PFLAG_NDLB_ALLOW_BAD_IANANAME)) && map->rm_pt < 96) {
+						match = (map->rm_pt == imp->ianacode) ? 1 : 0;
+					} else {
+						match = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1;
+					}
+                    
+					if (match && bit_rate && map_bit_rate && map_bit_rate != bit_rate && strcasecmp(map->rm_encoding, "ilbc")) {
+						/* nevermind */
+						match = 0;
+					}
+					
+					if (match) {
+						if (scrooge) {
+							switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
+											  "Bah HUMBUG! Sticking with %s@%uh@%ui\n",
+											  imp->iananame, imp->samples_per_second, imp->microseconds_per_packet / 1000);
+						} else {
+							if ((ptime && codec_ms && codec_ms * 1000 != imp->microseconds_per_packet) || map->rm_rate != codec_rate) {
+								near_rate = map->rm_rate;
+								near_match = imp;
+								match = 0;
+								continue;
+							}
+						}
+						mimp = imp;
+						break;
+					} else {
+						match = 0;
+					}
+				}
+            }
+                
+            /* End */
+            
+            
+        }
+    }
+
+fail:
+    if (parser) {
+        sdp_parser_free(parser);
+    }
+}
+#endif
+
+static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
+													switch_caller_profile_t *outbound_profile,
+													switch_core_session_t **new_session, 
+													switch_memory_pool_t **pool,
+													switch_originate_flag_t flags, switch_call_cause_t *cancel_cause)
+{
+    switch_channel_t *channel;
+    char name[128];
+    const char *dname = "PCMU";
+    uint32_t interval = 20;
+    crtp_private_t *tech_pvt;
+    const char *r_sdp = switch_event_get_header(var_event, kRSDP);
+    const char *l_sdp = switch_event_get_header(var_event, kLSDP);
+    const char *codec_string = switch_event_get_header_nil(var_event, kCODECSTRING);
+
+    
+    if (!(*new_session = switch_core_session_request(crtp.endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, 0, pool))) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't request session.\n");
+        goto fail;
+    }
+    
+    channel = switch_core_session_get_channel(*new_session);
+    
+    
+    
+    tech_pvt = switch_core_session_alloc(*new_session, sizeof *tech_pvt);
+    tech_pvt->session = *new_session;
+    tech_pvt->channel = channel;
+    tech_pvt->bind_address = switch_core_session_strdup(*new_session, switch_event_get_header_nil(var_event, kBINDADDRESS));
+    switch_core_session_set_private(*new_session, tech_pvt);
+    
+    if (setup_local_rtp(tech_pvt, l_sdp, codec_string) != SWITCH_STATUS_SUCCESS) {
+        goto fail;
+    }
+    
+    snprintf(name, sizeof(name), "rtp/ctrl"); /* TODO add addresses */
+	switch_channel_set_name(channel, name);
+    
+    switch_channel_set_state(channel, CS_INIT);
+
+	if (switch_core_codec_init(&tech_pvt->read_codec,
+							   dname,
+							   NULL,
+							   8000,
+							   interval,
+							   1,
+							   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+							   NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
+        goto fail;
+	} else {
+		if (switch_core_codec_init(&tech_pvt->write_codec,
+								   dname,
+								   NULL,
+								   8000,
+								   interval,
+								   1,
+								   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+								   NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
+			switch_core_codec_destroy(&tech_pvt->read_codec);
+            goto fail;
+		}
+	}
+    
+    if (switch_core_session_set_read_codec(*new_session, &tech_pvt->read_codec) != SWITCH_STATUS_SUCCESS) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set read codec?\n");
+        goto fail;
+    }
+    
+    if (switch_core_session_set_write_codec(*new_session, &tech_pvt->write_codec) != SWITCH_STATUS_SUCCESS) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't set write codec?\n");        
+    }
+    
+    if (switch_core_session_thread_launch(*new_session) != SWITCH_STATUS_SUCCESS) {
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't start session thread.\n"); 
+        goto fail;
+    }
+    
+    switch_channel_mark_answered(channel);
+    
+    return SWITCH_CAUSE_SUCCESS;
+    
+fail:
+     if (tech_pvt) {
+        if (tech_pvt->read_codec.implementation) {
+			switch_core_codec_destroy(&tech_pvt->read_codec);
+		}
+		
+		if (tech_pvt->write_codec.implementation) {
+			switch_core_codec_destroy(&tech_pvt->write_codec);
+		}
+    }
+    
+    if (*new_session) {
+        switch_core_session_destroy(new_session);
+    }
+    return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+}
+
+static switch_status_t channel_on_init(switch_core_session_t *session)
+{
+    
+    switch_channel_t *channel = switch_core_session_get_channel(session);
+    
+    switch_channel_set_state(channel, CS_ROUTING);
+    
+    return SWITCH_STATUS_SUCCESS;   
+}
+
+static switch_status_t channel_on_destroy(switch_core_session_t *session)
+{
+    crtp_private_t *tech_pvt = switch_core_session_get_private(session);
+    
+ 	if ((tech_pvt = switch_core_session_get_private(session))) {
+        
+		if (tech_pvt->read_codec.implementation) {
+			switch_core_codec_destroy(&tech_pvt->read_codec);
+		}
+		
+		if (tech_pvt->write_codec.implementation) {
+			switch_core_codec_destroy(&tech_pvt->write_codec);
+		}
+	}
+    
+    return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id)
+{
+    crtp_private_t *tech_pvt;
+    switch_channel_t *channel;
+    
+    channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+	
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+    
+    
+    return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id)
+{
+    crtp_private_t *tech_pvt;
+    switch_channel_t *channel;
+    
+    channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+	
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+    
+    
+    return SWITCH_STATUS_SUCCESS;
+
+}
+
+static switch_status_t channel_send_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf)
+{
+	crtp_private_t *tech_pvt = NULL;
+    
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+    
+    
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t channel_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+    return SWITCH_STATUS_SUCCESS;
+}
+