]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Media Management (Sponsored By Front Logic)
authorAnthony Minessale <anthony.minessale@gmail.com>
Tue, 31 Oct 2006 21:38:06 +0000 (21:38 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Tue, 31 Oct 2006 21:38:06 +0000 (21:38 +0000)
This modification makes it possible to change the media path of session in the switch on-the-fly and from the dialplan.
It adds some API interface calls usable from a remote client such as mod_event_socket or the test console.

1) media [off] <uuid>

   Turns on/off the media on the call described by <uuid>
   The media will be redirected as desiered either into the switch or point to point.

2) hold [off] <uuid>

   Turns on/off endpoint specific hold state on the session described by <uuid>

3) broadcast <uuid> "<path>[ <timer_name>]" or "speak:<tts_engine>|<tts_voice>|<text>[|<timer_name>]" [both]

   A message will be sent to the call described by uuid instructing it to play the file or speak the text indicated.

   If the 'both' option is specified both ends of the call will hear the message otherwise just the uuid specified
   will hear the message.

   During playback when only one side is hearing the message the other end will hear silence.

   If media is not flowing across the switch when the message is broadcasted, the media will be directed to the
   switch for the duration of the call and then returned to it's previous state.

Also the no_media=true option in the dialplan before a bridge makes it possible to place a call while proxying the session
description from one endpoint to the other and establishing an immidiate point-to-point media connection with no media
on the switch.

<action application="set" data="no_media=true"/>
<action application="bridge" data="sofia/mydomain.com/myid@myhost.com"/>

*NOTE* when connecting two outbound legs by using the "originate" api command with an extension that has no_media=true enabled,
the media for the first leg will be engaged with the switch until the second leg has answered and the other session description
is available to establish a point to point connection at which time point-to-point mode will be enabled.

*NOTE* it is reccommended you rebuild FreeSWITCH with "make sure" as there have been some changes to the core.

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3245 d0543943-73ff-0310-b7d9-9358b9ac24b2

src/include/switch_ivr.h
src/include/switch_module_interfaces.h
src/include/switch_types.h
src/mod/applications/mod_commands/mod_commands.c
src/mod/applications/mod_playback/mod_playback.c
src/mod/endpoints/mod_sofia/Makefile
src/mod/endpoints/mod_sofia/mod_sofia.c
src/switch_channel.c
src/switch_core.c
src/switch_ivr.c
src/switch_utils.c

index bc625a287e6a9458bdb781efe3ec7af164152021..df52f665cd30ee851ba2ce1493ef503c524e2310 100644 (file)
@@ -274,7 +274,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_signal_bridge(switch_core_session_t *
 */
 SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_t *session, char *extension, char *dialplan, char *context);
 
-
 /*!
   \brief Bridge two existing sessions
   \param originator_uuid the uuid of the originator
@@ -283,6 +282,59 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_
 */
 SWITCH_DECLARE(switch_status_t) switch_ivr_uuid_bridge(char *originator_uuid, char *originatee_uuid);
 
+/*!
+  \brief Signal a session to request direct media access to it's remote end
+  \param uuid the uuid of the session to request
+  \param flags flags to influence behaviour (SMF_REBRIDGE to rebridge the call in media mode)
+  \return SWITCH_STATUS_SUCCESS if all is well
+*/
+SWITCH_DECLARE(switch_status_t) switch_ivr_media(char *uuid, switch_media_flag_t flags);
+
+/*!
+  \brief Signal a session to request indirect media allowing it to exchange media directly with another device
+  \param uuid the uuid of the session to request
+  \param flags flags to influence behaviour (SMF_REBRIDGE to rebridge the call in no_media mode)
+  \return SWITCH_STATUS_SUCCESS if all is well
+*/
+SWITCH_DECLARE(switch_status_t) switch_ivr_nomedia(char *uuid, switch_media_flag_t flags);
+
+/*!
+  \brief Signal the session with a protocol specific hold message.
+  \param uuid the uuid of the session to hold
+  \return SWITCH_STATUS_SUCCESS if all is well
+*/
+SWITCH_DECLARE(switch_status_t) switch_ivr_hold_uuid(char *uuid);
+
+/*!
+  \brief Signal the session with a protocol specific unhold message.
+  \param uuid the uuid of the session to hold
+  \return SWITCH_STATUS_SUCCESS if all is well
+*/
+SWITCH_DECLARE(switch_status_t) switch_ivr_unhold_uuid(char *uuid);
+
+/*!
+  \brief Signal the session with a protocol specific hold message.
+  \param session the session to hold
+  \return SWITCH_STATUS_SUCCESS if all is well
+*/
+SWITCH_DECLARE(switch_status_t) switch_ivr_hold(switch_core_session_t *session);
+
+/*!
+  \brief Signal the session with a protocol specific unhold message.
+  \param uuid the uuid of the session to unhold
+  \return SWITCH_STATUS_SUCCESS if all is well
+*/
+SWITCH_DECLARE(switch_status_t) switch_ivr_unhold(switch_core_session_t *session);
+
+/*!
+  \brief Signal the session to broadcast audio
+  \param uuid the uuid of the session to broadcast on
+  \param path the path data of the broadcast "/path/to/file.wav [<timer name>]" or "speak:<engine>|<voice>|<Text to say>"
+  \param flags flags to send to the request (SMF_ECHO_BRIDGED to send the broadcast to both sides of the call)
+  \return SWITCH_STATUS_SUCCESS if all is well
+*/
+SWITCH_DECLARE(switch_status_t) switch_ivr_broadcast(char *uuid, char *path, switch_media_flag_t flags);
+
 /*!
   \brief Transfer variables from one session to another 
   \param sessa the original session
index 37c79fdd067e380576a1b6ff6b1fed462b01a6cf..33940c142c5ec8921c82eb9c83b5920b20a53b76 100644 (file)
@@ -60,6 +60,8 @@ struct switch_state_handler_table {
        switch_state_handler_t on_transmit;
        /*! executed when the state changes to hold*/
        switch_state_handler_t on_hold;
+       /*! executed when the state changes to hibernate*/
+       switch_state_handler_t on_hibernate;
 };
 
 struct switch_stream_handle {
index 39c45936f226f32c406fc3e9c144ef92f98ca690..510a91356771c90846018a02ee9cd0a9c9a40cd0 100644 (file)
@@ -74,12 +74,25 @@ SWITCH_BEGIN_EXTERN_C
 
 #define SWITCH_R_SDP_VARIABLE "_switch_r_sdp_"
 #define SWITCH_L_SDP_VARIABLE "_switch_l_sdp_"
-#define SWITCH_BRIDGE_VARIABLE "BRIDGETO"
-#define SWITCH_SIGNAL_BRIDGE_VARIABLE "SIGNAL_BRIDGETO"
+#define SWITCH_B_SDP_VARIABLE "_switch_m_sdp_"
+#define SWITCH_BRIDGE_VARIABLE "_bridge_to_"
+#define SWITCH_SIGNAL_BRIDGE_VARIABLE "_signal_bridge_to_"
+#define SWITCH_ORIGINATOR_VARIABLE "_originator_"
+#define SWITCH_LOCAL_MEDIA_IP_VARIABLE "_local_media_ip_"
+#define SWITCH_LOCAL_MEDIA_PORT_VARIABLE "_local_media_port_"
+#define SWITCH_REMOTE_MEDIA_IP_VARIABLE "_remote_media_ip_"
+#define SWITCH_REMOTE_MEDIA_PORT_VARIABLE "_remote_media_port_"
+
 
 #define SWITCH_BITS_PER_BYTE 8
 typedef uint8_t switch_byte_t;
 
+typedef enum {
+       SMF_NONE = 0,
+       SMF_REBRIDGE = (1 << 0),
+       SMF_ECHO_BRIDGED = (1 << 1)
+} switch_media_flag_t;
+
 typedef enum {
        SWITCH_BITPACK_MODE_RFC3551,
        SWITCH_BITPACK_MODE_AAL2
@@ -246,6 +259,10 @@ typedef enum {
        SWITCH_MESSAGE_INDICATE_BRIDGE    - indicate a bridge starting
        SWITCH_MESSAGE_INDICATE_UNBRIDGE  - indicate a bridge ending
        SWITCH_MESSAGE_INDICATE_TRANSFER  - indicate a transfer is taking place
+       SWITCH_MESSAGE_INDICATE_MEDIA     - indicate media is required
+       SWITCH_MESSAGE_INDICATE_NOMEDIA   - indicate no-media is required
+       SWITCH_MESSAGE_INDICATE_HOLD      - indicate hold
+       SWITCH_MESSAGE_INDICATE_UNHOLD    - indicate unhold
 </pre>
  */
 typedef enum {
@@ -255,7 +272,11 @@ typedef enum {
        SWITCH_MESSAGE_INDICATE_BRIDGE,
        SWITCH_MESSAGE_INDICATE_UNBRIDGE,
        SWITCH_MESSAGE_INDICATE_TRANSFER,
-       SWITCH_MESSAGE_INDICATE_RINGING
+       SWITCH_MESSAGE_INDICATE_RINGING,
+       SWITCH_MESSAGE_INDICATE_MEDIA,
+       SWITCH_MESSAGE_INDICATE_NOMEDIA,
+       SWITCH_MESSAGE_INDICATE_HOLD,
+       SWITCH_MESSAGE_INDICATE_UNHOLD,
 } switch_core_session_message_types_t;
 
 
@@ -376,6 +397,7 @@ CS_TRANSMIT  - Channel is in a passive transmit state
 CS_EXECUTE   - Channel is executing it's dialplan 
 CS_LOOPBACK  - Channel is in loopback
 CS_HOLD                 - Channel is on hold
+CS_HIBERNATE - Channel is in a sleep state
 CS_HANGUP    - Channel is flagged for hangup and ready to end
 CS_DONE      - Channel is ready to be destroyed and out of the state machine
 </pre>
@@ -388,6 +410,7 @@ typedef enum {
        CS_EXECUTE,
        CS_LOOPBACK,
        CS_HOLD,
+       CS_HIBERNATE,
        CS_HANGUP,
        CS_DONE 
 } switch_channel_state_t;
@@ -412,6 +435,8 @@ CF_TAGGED           = (1 << 10) - Channel is tagged
 CF_WINNER              = (1 << 11) - Channel is the winner
 CF_CONTROLLED  = (1 << 12) - Channel is under control
 CF_NOMEDIA             = (1 << 13) - Channel has no media
+CF_SUSPEND             = (1 << 14) - Suspend i/o
+CF_EVENT_PARSE  = (1 << 15) - Suspend control events
 </pre>
  */
 
@@ -429,7 +454,9 @@ typedef enum {
        CF_TAGGED               = (1 << 10),
        CF_WINNER               = (1 << 11),
        CF_CONTROLLED   = (1 << 12),
-       CF_NOMEDIA              = (1 << 13)
+       CF_NOMEDIA              = (1 << 13),
+       CF_SUSPEND              = (1 << 14),
+       CF_EVENT_PARSE  = (1 << 15)
 } switch_channel_flag_t;
 
 
index c51a13c2abb0440e45f70c1ffac0f6a68c1980e2..4985501290cb519dcb42add66af65f9d08beb673 100644 (file)
@@ -44,6 +44,9 @@ static switch_api_interface_t load_api_interface;
 static switch_api_interface_t reload_api_interface;
 static switch_api_interface_t kill_api_interface;
 static switch_api_interface_t originate_api_interface;
+static switch_api_interface_t media_api_interface;
+static switch_api_interface_t hold_api_interface;
+static switch_api_interface_t broadcast_api_interface;
 
 static switch_status_t status_function(char *cmd, switch_core_session_t *session, switch_stream_handle_t *stream)
 {
@@ -235,6 +238,97 @@ static switch_status_t transfer_function(char *cmd, switch_core_session_t *isess
        return SWITCH_STATUS_SUCCESS;
 }
 
+static switch_status_t uuid_media_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream)
+{
+       char *argv[4] = {0};
+       int argc = 0;
+       switch_status_t status = SWITCH_STATUS_FALSE;
+       
+       if (isession) {
+               return status;
+       }
+       
+       argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+
+       if (argc < 1) {
+               stream->write_function(stream, "USAGE: %s\n", media_api_interface.syntax);
+       } else {
+               if (!strcmp(argv[0], "off")) {
+                       status = switch_ivr_nomedia(argv[1], SMF_REBRIDGE);
+               } else {
+                       status = switch_ivr_media(argv[0], SMF_REBRIDGE);
+               }
+       }
+
+       if (status == SWITCH_STATUS_SUCCESS) {
+               stream->write_function(stream, "+OK Success\n");
+       } else {
+               stream->write_function(stream, "-ERR Operation Failed\n");
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status_t uuid_broadcast_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream)
+{
+       char *argv[4] = {0};
+       int argc = 0;
+       switch_status_t status = SWITCH_STATUS_FALSE;
+
+       if (isession) {
+               return status;
+       }
+       
+       argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+
+       if (argc < 2) {
+               stream->write_function(stream, "USAGE: %s\n", broadcast_api_interface.syntax);
+       } else {
+               switch_media_flag_t flags = SMF_NONE;
+
+               if (argv[2] && !strcmp(argv[2], "both")) {
+                       flags |= SMF_ECHO_BRIDGED;
+               }
+               
+               status = switch_ivr_broadcast(argv[0], argv[1], flags);
+               stream->write_function(stream, "+OK Message Sent\n");
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t uuid_hold_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream)
+{
+       char *argv[4] = {0};
+       int argc = 0;
+       switch_status_t status = SWITCH_STATUS_FALSE;
+       
+       if (isession) {
+               return status;
+       }
+       
+       argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+
+       if (argc < 1) {
+               stream->write_function(stream, "USAGE: %s\n", hold_api_interface.syntax);
+       } else {
+               if (!strcmp(argv[0], "off")) {
+                       status = switch_ivr_unhold_uuid(argv[1]);
+               } else {
+                       status = switch_ivr_hold_uuid(argv[0]);
+               }
+       }
+
+       if (status == SWITCH_STATUS_SUCCESS) {
+               stream->write_function(stream, "+OK Success\n");
+       } else {
+               stream->write_function(stream, "-ERR Operation Failed\n");
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
 static switch_status_t uuid_bridge_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream)
 {
        char *argv[4] = {0};
@@ -535,12 +629,36 @@ static switch_api_interface_t ctl_api_interface = {
        /*.next */ &help_api_interface
 };
 
+static switch_api_interface_t media_api_interface = {
+       /*.interface_name */ "media",
+       /*.desc */ "media",
+       /*.function */ uuid_media_function,
+       /*.syntax */ "<uuid>",
+       /*.next */ &ctl_api_interface
+};
+
+static switch_api_interface_t hold_api_interface = {
+       /*.interface_name */ "hold",
+       /*.desc */ "hold",
+       /*.function */ uuid_hold_function,
+       /*.syntax */ "<uuid>",
+       /*.next */ &media_api_interface
+};
+
+static switch_api_interface_t broadcast_api_interface = {
+       /*.interface_name */ "broadcast",
+       /*.desc */ "broadcast",
+       /*.function */ uuid_broadcast_function,
+       /*.syntax */ "<uuid> <path> [both]",
+       /*.next */ &hold_api_interface
+};
+
 static switch_api_interface_t uuid_bridge_api_interface = {
        /*.interface_name */ "uuid_bridge",
        /*.desc */ "uuid_bridge",
        /*.function */ uuid_bridge_function,
        /*.syntax */ "<uuid> <other_uuid>",
-       /*.next */ &ctl_api_interface
+       /*.next */ &broadcast_api_interface
 };
 
 static switch_api_interface_t status_api_interface = {
index 0fafa586b090a83f9d1adbdb146621f22336e9be..beae8295db193e95e3e5e7be4d2cd644bb1570bc 100644 (file)
@@ -88,7 +88,16 @@ static void speak_function(switch_core_session_t *session, char *data)
        timer_name = argv[3];
        
        if (!(engine && voice && text)) {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Params!\n");
+               if (!engine) {
+                       engine = "NULL";
+               }
+               if (!voice) {
+                       voice = "NULL";
+               }
+               if (!text) {
+                       text = "NULL";
+               }
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Params! [%s][%s][%s]\n", engine, voice, text);
                switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
        }
 
index 8e409148afeb25fb6eb1004b61e3de09162cc818..0eeccbbc51c54e06052479915b8b24b4f830003e 100644 (file)
@@ -1,6 +1,6 @@
 OS_ARCH         := $(subst /,_,$(shell uname -s | sed /\ /s//_/))
 VERSION = sofia-sip-1.12
-TARBALL = sofia-sip-1.12.3.8.tar.gz
+TARBALL = sofia-sip-1.12.3.9.tar.gz
 CFLAGS += -I. -I$(PREFIX)/include/$(VERSION)
 LDFLAGS += -lsofia-sip-ua
 LINKER=$(CC)
index 450bfc2ab253a2f1ba18e7e9ecc9bb49b6949ae9..cde844672db51029aae3f5927284824c39fcaea5 100644 (file)
@@ -77,6 +77,10 @@ typedef struct private_object private_object_t;
 
 extern su_log_t tport_log[];
 
+static switch_frame_t silence_frame = {};
+static char silence_data[13] = "";
+
+
 static char reg_sql[] =
 "CREATE TABLE sip_registrations (\n"
 "   user            VARCHAR(255),\n"
@@ -142,7 +146,7 @@ typedef enum {
 
 typedef enum {
        TFLAG_IO = (1 << 0),
-       TFLAG_INBOUND = (1 << 1),
+       TFLAG_USEME = (1 << 1),
        TFLAG_OUTBOUND = (1 << 2),
        TFLAG_READING = (1 << 3),
        TFLAG_WRITING = (1 << 4),
@@ -274,6 +278,8 @@ struct private_object {
        switch_port_t remote_sdp_audio_port;
        char *adv_sdp_audio_ip;
        switch_port_t adv_sdp_audio_port;
+       char *proxy_sdp_audio_ip;
+       switch_port_t proxy_sdp_audio_port;
        char *from_uri;
        char *to_uri;
        char *from_address;
@@ -333,7 +339,7 @@ static switch_status_t activate_rtp(private_object_t *tech_pvt);
 
 static void deactivate_rtp(private_object_t *tech_pvt);
 
-static void set_local_sdp(private_object_t *tech_pvt);
+static void set_local_sdp(private_object_t *tech_pvt, char *ip, uint32_t port, char *sr, int force);
 
 static void tech_set_codecs(private_object_t *tech_pvt);
 
@@ -648,30 +654,45 @@ static char *find_reg_url(sofia_profile_t *profile, char *user, char *host, char
 }
 
 
-static void set_local_sdp(private_object_t *tech_pvt)
+static void set_local_sdp(private_object_t *tech_pvt, char *ip, uint32_t port, char *sr, int force)
 {
        char buf[1024];
        switch_time_t now = switch_time_now();
 
-       if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
+       if (!force && !ip && !sr && switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
                return;
        }
 
+       if (!ip) {
+               if (!(ip = tech_pvt->adv_sdp_audio_ip)) {
+                       ip = tech_pvt->proxy_sdp_audio_ip;
+               }
+       }
+       if (!port) {
+               if (!(port = tech_pvt->adv_sdp_audio_port)) {
+                       port = tech_pvt->proxy_sdp_audio_port;
+               }
+       }
+       if (!sr) {
+               sr = "sendrecv";
+       }
+
        snprintf(buf, sizeof(buf), 
                         "v=0\n"
                         "o=FreeSWITCH %d%"APR_TIME_T_FMT" %d%"APR_TIME_T_FMT" IN IP4 %s\n"
                         "s=FreeSWITCH\n"
                         "c=IN IP4 %s\n"
                         "t=0 0\n"
-                        "a=sendrecv\n"
+                        "a=%s\n"
                         "m=audio %d RTP/AVP",
-                        tech_pvt->adv_sdp_audio_port,
+                        port,
                         now,
-                        tech_pvt->adv_sdp_audio_port,
+                        port,
                         now,
-                        tech_pvt->adv_sdp_audio_ip,
-                        tech_pvt->adv_sdp_audio_ip,
-                        tech_pvt->adv_sdp_audio_port
+                        ip,
+                        ip,
+                        sr,
+                        port
                         );
 
        if (tech_pvt->rm_encoding) {
@@ -715,11 +736,7 @@ static void set_local_sdp(private_object_t *tech_pvt)
                snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d telephone-event/8000\na=fmtp:%d 0-16\n", tech_pvt->te, tech_pvt->te);
        }
 
-
-
-       
        tech_pvt->local_sdp_str = switch_core_session_strdup(tech_pvt->session, buf);
-
 }
 
 static void tech_set_codecs(private_object_t *tech_pvt)
@@ -805,12 +822,17 @@ static void terminate_session(switch_core_session_t **session, switch_call_cause
        }
 }
 
+
 static switch_status_t tech_choose_port(private_object_t *tech_pvt)
 {
        char *ip = tech_pvt->profile->rtpip;
+       switch_channel_t *channel;
        switch_port_t sdp_port;
        char *err;
+       char tmp[50];
 
+       channel = switch_core_session_get_channel(tech_pvt->session);
+       
        if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA) || tech_pvt->adv_sdp_audio_port) {
                return SWITCH_STATUS_SUCCESS;
        }
@@ -846,6 +868,12 @@ static switch_status_t tech_choose_port(private_object_t *tech_pvt)
 
        tech_pvt->adv_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, ip);
        tech_pvt->adv_sdp_audio_port = sdp_port;
+
+       snprintf(tmp, sizeof(tmp), "%d", sdp_port);
+       switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip);
+       switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, tmp);
+       
+
        return SWITCH_STATUS_SUCCESS;
 }
 
@@ -859,6 +887,7 @@ static void do_invite(switch_core_session_t *session)
        switch_caller_profile_t *caller_profile;
        char *cid_name, *cid_num;
        char *e_dest = NULL;
+       char *holdstr = "";
 
     channel = switch_core_session_get_channel(session);
     assert(channel != NULL);
@@ -884,7 +913,7 @@ static void do_invite(switch_core_session_t *session)
                }
 
                tech_choose_port(tech_pvt);
-               set_local_sdp(tech_pvt);
+               set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
 
                switch_set_flag_locked(tech_pvt, TFLAG_READY);
 
@@ -934,14 +963,18 @@ static void do_invite(switch_core_session_t *session)
                        
                }
 
+               holdstr = switch_test_flag(tech_pvt, TFLAG_SIP_HOLD) ? "*" : "";
                nua_invite(tech_pvt->nh,
                                   TAG_IF(rpid, SIPTAG_HEADER_STR(rpid)),
                                   TAG_IF(alert_info, SIPTAG_HEADER_STR(alert_info)),
+                                  SIPTAG_CONTACT_STR(tech_pvt->profile->url),
                                   SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
                                   SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE),
                                   SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL),
                                   TAG_IF(rep, SIPTAG_REPLACES_STR(rep)),
+                                  SOATAG_HOLD(holdstr),
                                   TAG_END());
+
        } else {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
        }
@@ -988,6 +1021,7 @@ static void do_xfer_invite(switch_core_session_t *session)
 
                nua_invite(tech_pvt->nh2,
                                   TAG_IF(rpid, SIPTAG_HEADER_STR(rpid)),
+                                  SIPTAG_CONTACT_STR(tech_pvt->profile->url),
                                   SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
                                   SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE),
                                   SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL),
@@ -999,6 +1033,33 @@ static void do_xfer_invite(switch_core_session_t *session)
        
 }
 
+static void tech_absorb_sdp(private_object_t *tech_pvt)
+{
+       switch_channel_t *channel;
+       char *sdp_str;
+
+       channel = switch_core_session_get_channel(tech_pvt->session);
+       assert(channel != NULL);
+       
+       if ((sdp_str = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE))) {
+               sdp_parser_t *parser;
+               sdp_session_t *sdp;
+               sdp_media_t *m;
+
+               if ((parser = sdp_parse(tech_pvt->home, sdp_str, (int)strlen(sdp_str), 0))) {
+                       if ((sdp = sdp_session(parser))) {
+                               for (m = sdp->sdp_media; m ; m = m->m_next) {
+                                       tech_pvt->proxy_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, (char *)sdp->sdp_connection->c_address);
+                                       tech_pvt->proxy_sdp_audio_port = (switch_port_t)m->m_port;
+                                       break;
+                               }
+                       }
+                       sdp_parser_free(parser);
+               }       
+               tech_pvt->local_sdp_str = switch_core_session_strdup(tech_pvt->session, sdp_str);
+       }
+}
+
 /* 
    State methods they get called when the state changes to the specific state 
    returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
@@ -1008,8 +1069,7 @@ static switch_status_t sofia_on_init(switch_core_session_t *session)
 {
        private_object_t *tech_pvt;
        switch_channel_t *channel = NULL;
-       char *sdp;
-
+       
        channel = switch_core_session_get_channel(session);
        assert(channel != NULL);
 
@@ -1021,15 +1081,9 @@ static switch_status_t sofia_on_init(switch_core_session_t *session)
 
        switch_channel_set_variable(channel, "endpoint_disposition", "INIT");
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA INIT\n");
-
        if (switch_channel_test_flag(channel, CF_NOMEDIA)) {
                switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA);
-       }
-       
-       if ((sdp = switch_channel_get_variable(channel, SWITCH_L_SDP_VARIABLE))) {
-               tech_pvt->local_sdp_str = switch_core_session_strdup(session, sdp);
-               switch_set_flag(tech_pvt, TFLAG_NOMEDIA);
-               switch_channel_set_flag(channel, CF_NOMEDIA);
+               tech_absorb_sdp(tech_pvt);
        }
 
        if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
@@ -1170,7 +1224,7 @@ static switch_status_t sofia_on_hangup(switch_core_session_t *session)
                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending BYE\n");
                                nua_bye(tech_pvt->nh, TAG_END());
                        } else {
-                               if (switch_test_flag(tech_pvt, TFLAG_INBOUND)) {
+                               if (!switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Responding to INVITE with: %d\n", sip_cause);
                                        nua_respond(tech_pvt->nh, sip_cause, NULL, TAG_END());
                                } else {
@@ -1297,7 +1351,7 @@ static switch_status_t activate_rtp(private_object_t *tech_pvt)
        const char *err = NULL;
        switch_rtp_flag_t flags;
        switch_status_t status;
-
+       char tmp[50];
        assert(tech_pvt != NULL);
 
        channel = switch_core_session_get_channel(tech_pvt->session);
@@ -1333,7 +1387,10 @@ static switch_status_t activate_rtp(private_object_t *tech_pvt)
                                          tech_pvt->agreed_pt,
                                          tech_pvt->read_codec.implementation->microseconds_per_frame / 1000);
 
-
+       snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
+       switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip);
+       switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, tmp);
+       
        if (tech_pvt->rtp_session && switch_test_flag(tech_pvt, TFLAG_REINVITE)) {
                switch_clear_flag_locked(tech_pvt, TFLAG_REINVITE);
                
@@ -1390,7 +1447,6 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session)
 {
        private_object_t *tech_pvt;
        switch_channel_t *channel = NULL;
-       char *sdp;
        
        assert(session != NULL);
 
@@ -1400,19 +1456,17 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session)
        tech_pvt = (private_object_t *) switch_core_session_get_private(session);
        assert(tech_pvt != NULL);
 
-       if ((sdp = switch_channel_get_variable(channel, SWITCH_L_SDP_VARIABLE))) {
-               tech_pvt->local_sdp_str = switch_core_session_strdup(session, sdp);
-               switch_set_flag(tech_pvt, TFLAG_NOMEDIA);
-               switch_channel_set_flag(channel, CF_NOMEDIA);
+       if (switch_channel_test_flag(channel, CF_NOMEDIA)) {
+               switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA);
+               tech_absorb_sdp(tech_pvt);
        }
 
-
        if (!switch_test_flag(tech_pvt, TFLAG_ANS) && !switch_channel_test_flag(channel, CF_OUTBOUND)) {
                switch_set_flag_locked(tech_pvt, TFLAG_ANS);
 
 
                tech_choose_port(tech_pvt);
-               set_local_sdp(tech_pvt);
+               set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
                activate_rtp(tech_pvt);
                
                if (tech_pvt->nh) {
@@ -1440,7 +1494,7 @@ static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_f
        size_t bytes = 0, samples = 0, frames = 0, ms = 0;
        switch_channel_t *channel = NULL;
        int payload = 0;
-
+       
        channel = switch_core_session_get_channel(session);
        assert(channel != NULL);
 
@@ -1451,6 +1505,15 @@ static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_f
                return SWITCH_STATUS_FALSE;
        }
 
+       while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session))) {
+               if (switch_channel_ready(channel)) {
+                       switch_yield(10000);
+               } else {
+                       return SWITCH_STATUS_GENERR;
+               }
+       }
+
+
        tech_pvt->read_frame.datalen = 0;
        switch_set_flag_locked(tech_pvt, TFLAG_READING);
 
@@ -1558,6 +1621,14 @@ static switch_status_t sofia_write_frame(switch_core_session_t *session, switch_
        tech_pvt = (private_object_t *) switch_core_session_get_private(session);
        assert(tech_pvt != NULL);
 
+       while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session))) {
+               if (switch_channel_ready(channel)) {
+                       switch_yield(10000);
+               } else {
+                       return SWITCH_STATUS_GENERR;
+               }
+       }
+
        if (switch_test_flag(tech_pvt, TFLAG_HUP)) {
                return SWITCH_STATUS_FALSE;
        }
@@ -1680,6 +1751,53 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
 
 
        switch (msg->message_id) {
+       case SWITCH_MESSAGE_INDICATE_NOMEDIA: {
+               char *uuid;
+               switch_core_session_t *other_session;
+               switch_channel_t *other_channel;
+               char *ip = NULL, *port = NULL;
+
+               switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA);
+               tech_pvt->local_sdp_str = NULL;
+               if ((uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) {
+                       other_channel = switch_core_session_get_channel(other_session);
+                       ip = switch_channel_get_variable(other_channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE);
+                       port = switch_channel_get_variable(other_channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE);
+                       switch_core_session_rwunlock(other_session);
+                       if (ip && port) {
+                               set_local_sdp(tech_pvt, ip, atoi(port), NULL, 1);
+                       }
+               }
+               if (!tech_pvt->local_sdp_str) {
+                       tech_absorb_sdp(tech_pvt);
+               }
+
+               do_invite(session);
+       }
+               break;
+       case SWITCH_MESSAGE_INDICATE_MEDIA: {
+               switch_clear_flag_locked(tech_pvt, TFLAG_NOMEDIA);
+               tech_pvt->local_sdp_str = NULL;
+               if (!switch_rtp_ready(tech_pvt->rtp_session)) {
+                       tech_set_codecs(tech_pvt);
+                       tech_choose_port(tech_pvt);
+               }
+               set_local_sdp(tech_pvt, NULL, 0, NULL, 1);
+               do_invite(session);
+       }
+               break;
+
+       case SWITCH_MESSAGE_INDICATE_HOLD: {
+               switch_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+               do_invite(session);
+       }
+               break;
+
+       case SWITCH_MESSAGE_INDICATE_UNHOLD: {
+               switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+               do_invite(session);
+       }
+               break;
        case SWITCH_MESSAGE_INDICATE_BRIDGE:
 
                if (switch_test_flag(tech_pvt, TFLAG_XFER)) {
@@ -1704,7 +1822,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
                                        switch_core_session_rwunlock(asession);
                                }
 
-
+                               
                                msg->pointer_arg = NULL;
                                return SWITCH_STATUS_FALSE;
                        }
@@ -1726,7 +1844,6 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
        case SWITCH_MESSAGE_INDICATE_PROGRESS: {
                struct private_object *tech_pvt;
            switch_channel_t *channel = NULL;
-               char *sdp;
 
            channel = switch_core_session_get_channel(session);
            assert(channel != NULL);
@@ -1734,27 +1851,35 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
            tech_pvt = switch_core_session_get_private(session);
            assert(tech_pvt != NULL);
 
-           if (!switch_test_flag(tech_pvt, TFLAG_EARLY_MEDIA)) {
+           if (!switch_test_flag(tech_pvt, TFLAG_EARLY_MEDIA) && !switch_test_flag(tech_pvt, TFLAG_ANS)) {
                        switch_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Asked to send early media by %s\n", msg->from);
 
 
-                       if ((sdp = switch_channel_get_variable(channel, SWITCH_L_SDP_VARIABLE))) {
-                               tech_pvt->local_sdp_str = switch_core_session_strdup(session, sdp);
-                               switch_set_flag(tech_pvt, TFLAG_NOMEDIA);
-                               switch_channel_set_flag(channel, CF_NOMEDIA);
+                       if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
+                               tech_absorb_sdp(tech_pvt);
                        }
 
-
                        /* Transmit 183 Progress with SDP */
                        tech_choose_port(tech_pvt);
-                       set_local_sdp(tech_pvt);
+                       set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
                        activate_rtp(tech_pvt);
-                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "183 SDP:\n%s\n", tech_pvt->local_sdp_str);
-                       nua_respond(tech_pvt->nh, SIP_183_SESSION_PROGRESS,
-                                               SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
-                                               SOATAG_AUDIO_AUX("cn telephone-event"),
-                                               TAG_END());
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Ring SDP:\n%s\n", tech_pvt->local_sdp_str);
+
+                       
+                       if (msg->message_id == SWITCH_MESSAGE_INDICATE_RINGING) {
+                               nua_respond(tech_pvt->nh,
+                                                       SIP_180_RINGING,
+                                                       SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
+                                                       SOATAG_AUDIO_AUX("cn telephone-event"),
+                                                       TAG_END());
+                       } else {
+                               nua_respond(tech_pvt->nh,
+                                                       SIP_183_SESSION_PROGRESS,
+                                                       SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
+                                                       SOATAG_AUDIO_AUX("cn telephone-event"),
+                                                       TAG_END());
+                       }
            }
        }
                break;
@@ -1947,13 +2072,9 @@ static switch_status_t sofia_outgoing_channel(switch_core_session_t *session, sw
        *new_session = nsession;
        status = SWITCH_STATUS_SUCCESS;
        if (session) {
-               char *val;
-               switch_channel_t *channel = switch_core_session_get_channel(session);
+               //char *val;
+               //switch_channel_t *channel = switch_core_session_get_channel(session);
                switch_ivr_transfer_variable(session, nsession, SOFIA_REPLACES_HEADER);
-
-               if (switch_channel_test_flag(channel, CF_NOMEDIA) && (val = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE))) {
-                       switch_channel_set_variable(nchannel, SWITCH_L_SDP_VARIABLE, val);
-               }
        }
 
  done:
@@ -1967,10 +2088,12 @@ static uint8_t negotiate_sdp(switch_core_session_t *session, sdp_session_t *sdp)
        private_object_t *tech_pvt;
        sdp_media_t *m;
        sdp_attribute_t *a;
-
+       switch_channel_t *channel;
 
        tech_pvt = switch_core_session_get_private(session);
        assert(tech_pvt != NULL);                                                                                                                               
+
+       channel = switch_core_session_get_channel(session);
        
        if ((tech_pvt->origin = switch_core_session_strdup(session, (char *) sdp->sdp_origin->o_username))) {
                if (strstr(tech_pvt->origin, "CiscoSystemsSIP-GW-UserAgent")) {
@@ -2007,8 +2130,9 @@ static uint8_t negotiate_sdp(switch_core_session_t *session, sdp_session_t *sdp)
                                        } else {
                                                match = strcasecmp(map->rm_encoding, imp->iananame) ? 0 : 1;
                                        }
-                                       
+
                                        if (match && (map->rm_rate == imp->samples_per_second)) {
+                                               char tmp[50];
                                                tech_pvt->rm_encoding = switch_core_session_strdup(session, (char *)map->rm_encoding);
                                                tech_pvt->pt = (switch_payload_t)map->rm_pt;
                                                tech_pvt->rm_rate = map->rm_rate;
@@ -2017,6 +2141,9 @@ static uint8_t negotiate_sdp(switch_core_session_t *session, sdp_session_t *sdp)
                                                tech_pvt->rm_fmtp = switch_core_session_strdup(session, (char *)map->rm_fmtp);
                                                tech_pvt->remote_sdp_audio_port = (switch_port_t)m->m_port;
                                                tech_pvt->agreed_pt = (switch_payload_t)map->rm_pt;
+                                               snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
+                                               switch_channel_set_variable(channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
+                                               switch_channel_set_variable(channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
                                                break;
                                        } else {
                                                match = 0;
@@ -2269,6 +2396,30 @@ static void sip_i_message(int status,
        }
 }
 
+static void pass_sdp(switch_channel_t *channel, char *sdp) 
+{
+       char *val;
+       switch_core_session_t *other_session;
+       switch_channel_t *other_channel;
+       
+       if ((val = switch_channel_get_variable(channel, SWITCH_ORIGINATOR_VARIABLE)) && (other_session = switch_core_session_locate(val))) {
+               other_channel = switch_core_session_get_channel(other_session);
+               assert(other_channel != NULL);
+               if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
+                       switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, sdp);
+               }
+               if (
+                       switch_channel_test_flag(other_channel, CF_OUTBOUND) && 
+                       switch_channel_test_flag(other_channel, CF_NOMEDIA) && 
+                       switch_channel_test_flag(channel, CF_OUTBOUND) && 
+                       switch_channel_test_flag(channel, CF_NOMEDIA)) {
+                       switch_ivr_nomedia(val, SMF_NONE);
+               }
+               
+               switch_core_session_rwunlock(other_session);
+       }
+}
+
 
 static void sip_i_state(int status,
                                                char const *phrase, 
@@ -2323,10 +2474,14 @@ static void sip_i_state(int status,
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Remote SDP:\n%s\n", r_sdp);                    
                        tech_pvt->remote_sdp_str = switch_core_session_strdup(session, (char *)r_sdp);
                        switch_channel_set_variable(channel, SWITCH_R_SDP_VARIABLE, (char *) r_sdp);
+                       pass_sdp(channel, (char *) r_sdp);
 
                }
        }
 
+       if (status == 988) {
+               return;
+       }
 
        switch ((enum nua_callstate)ss_state) {
        case nua_callstate_init:
@@ -2339,7 +2494,7 @@ static void sip_i_state(int status,
                if (channel) {
                        if (status == 180) {
                                if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
-                                       if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BRIDGE_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) {
+                                       if ((uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) {
                                                switch_core_session_message_t msg;
                                                msg.message_id = SWITCH_MESSAGE_INDICATE_RINGING;
                                                msg.from = __FILE__;
@@ -2362,7 +2517,7 @@ static void sip_i_state(int status,
                                if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
                                        switch_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
                                        switch_channel_set_flag(channel, CF_EARLY_MEDIA);
-                                       if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BRIDGE_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) {
+                                       if ((uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) {
                                                other_channel = switch_core_session_get_channel(other_session);
                                                switch_channel_pre_answer(other_channel);
                                                switch_core_session_rwunlock(other_session);
@@ -2431,7 +2586,7 @@ static void sip_i_state(int status,
                                                switch_channel_set_variable(channel, "endpoint_disposition", "RECEIVED");
                                                switch_channel_set_state(channel, CS_INIT);
                                                switch_set_flag_locked(tech_pvt, TFLAG_READY);
-                                               //sofia_answer_channel(session);//XXX TMP
+
                                                switch_core_session_thread_launch(session);
                                                
                                                if (replaces_str && (replaces = sip_replaces_make(tech_pvt->home, replaces_str)) && (bnh = nua_handle_by_replaces(nua, replaces))) {
@@ -2491,7 +2646,7 @@ static void sip_i_state(int status,
                                        }
                                        if (match) {
                                                tech_choose_port(tech_pvt);
-                                               set_local_sdp(tech_pvt);
+                                               set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
                                                switch_set_flag_locked(tech_pvt, TFLAG_REINVITE);
                                                activate_rtp(tech_pvt);
                                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Processing Reinvite\n");
@@ -2519,7 +2674,7 @@ static void sip_i_state(int status,
                                if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
                                        switch_set_flag_locked(tech_pvt, TFLAG_ANS);
                                        switch_channel_set_flag(channel, CF_ANSWERED);
-                                       if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BRIDGE_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) {
+                                       if ((uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) {
                                                other_channel = switch_core_session_get_channel(other_session);
                                                switch_channel_answer(other_channel);
                                                switch_core_session_rwunlock(other_session);
@@ -3842,7 +3997,6 @@ static void sip_i_invite(nua_t *nua,
                                switch_safe_free(to_username);
                        }
 
-                       switch_set_flag_locked(tech_pvt, TFLAG_INBOUND);
                        tech_pvt->sofia_private.session = session;
                        nua_handle_bind(nh, &tech_pvt->sofia_private);
                }
@@ -3943,7 +4097,7 @@ static void sip_r_register(int status,
        }
 
        if (!oreg) {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Register handle to associate!\n");
+               //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Register handle to associate!\n");
                return;
        }
        
@@ -4249,7 +4403,7 @@ static void *SWITCH_THREAD_FUNC profile_thread_run(switch_thread_t *thread, void
                                                          TAG_END()); /* Last tag should always finish the sequence */
 
        nua_set_params(profile->nua,
-                                  NUTAG_EARLY_MEDIA(1),                                   
+                                  //NUTAG_EARLY_MEDIA(1),                                 
                                   NUTAG_AUTOANSWER(0),
                                   NUTAG_AUTOALERT(0),
                                   NUTAG_ALLOW("REGISTER"),
@@ -5001,6 +5155,12 @@ static void pres_event_handler(switch_event_t *event)
 SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface_t **module_interface, char *filename)
 {
 
+       silence_frame.data = silence_data;
+       silence_frame.datalen = sizeof(silence_data);
+       silence_frame.buflen = sizeof(silence_data);
+       silence_frame.flags = SFF_CNG;
+
+
        if (switch_core_new_memory_pool(&module_pool) != SWITCH_STATUS_SUCCESS) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OH OH no pool\n");
                return SWITCH_STATUS_TERM;
index 4534299a81c8b2da466730d06922e7d26b4c7d0e..832aed1d9195a2df31816215d3b75488e73455c0 100644 (file)
@@ -462,6 +462,7 @@ static const char *state_names[] = {
        "CS_EXECUTE",
        "CS_LOOPBACK",
        "CS_HOLD",
+       "CS_HIBERNATE",
        "CS_HANGUP",
        "CS_DONE",
        NULL
@@ -543,6 +544,7 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_set_state(switch_c
                case CS_RING:
                case CS_EXECUTE:
                case CS_HOLD:
+               case CS_HIBERNATE:
                        ok++;
                default:
                        break;
@@ -555,6 +557,7 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_set_state(switch_c
                case CS_RING:
                case CS_EXECUTE:
                case CS_HOLD:
+               case CS_HIBERNATE:
                        ok++;
                default:
                        break;
@@ -567,6 +570,7 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_set_state(switch_c
                case CS_RING:
                case CS_EXECUTE:
                case CS_HOLD:
+               case CS_HIBERNATE:
                        ok++;
                default:
                        break;
@@ -579,6 +583,19 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_set_state(switch_c
                case CS_RING:
                case CS_EXECUTE:
                case CS_TRANSMIT:
+               case CS_HIBERNATE:
+                       ok++;
+               default:
+                       break;
+               }
+               break;
+       case CS_HIBERNATE:
+               switch (state) {
+               case CS_LOOPBACK:
+               case CS_RING:
+               case CS_EXECUTE:
+               case CS_TRANSMIT:
+               case CS_HOLD:
                        ok++;
                default:
                        break;
@@ -592,6 +609,7 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_set_state(switch_c
                case CS_EXECUTE:
                case CS_TRANSMIT:
                case CS_HOLD:
+               case CS_HIBERNATE:
                        ok++;
                default:
                        break;
@@ -604,6 +622,7 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_set_state(switch_c
                case CS_TRANSMIT:
                case CS_RING:
                case CS_HOLD:
+               case CS_HIBERNATE:
                        ok++;
                default:
                        break;
index f6993db538f504e1e7f37e7dc620a0d44f3dd76b..32b85b1640ed80d83b20e67349c7f3fe5627fd91 100644 (file)
@@ -1367,6 +1367,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_outgoing_channel(switch_core
                switch_event_t *event;
                switch_channel_t *peer_channel = switch_core_session_get_channel(*new_session);
 
+               
                if (session && channel) {
                        profile = switch_channel_get_caller_profile(channel);
                }
@@ -1375,7 +1376,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_outgoing_channel(switch_core
                }
 
                if (channel && peer_channel) {
-                       char *export_vars;
+                       char *export_vars, *val;
+
+                       switch_channel_set_variable(peer_channel, SWITCH_ORIGINATOR_VARIABLE, switch_core_session_get_uuid(session));
+                       
                        /* A comma (,) separated list of variable names that should ne propagated from originator to originatee */
                        if ((export_vars = switch_channel_get_variable(channel, "export_vars"))) {
                                char *cptmp = switch_core_session_strdup(session, export_vars);
@@ -1394,6 +1398,14 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_outgoing_channel(switch_core
                                }
                        }
 
+                       if ((val = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE))) {
+                               switch_channel_set_variable(peer_channel, SWITCH_B_SDP_VARIABLE, val);
+                       }
+                       
+                       if (switch_channel_test_flag(channel, CF_NOMEDIA)) {
+                               switch_channel_set_flag(peer_channel, CF_NOMEDIA);
+                       }
+
                        if (profile) {
                                if ((cloned_profile = switch_caller_profile_clone(*new_session, profile)) != 0) {
                                        switch_channel_set_originator_caller_profile(peer_channel, cloned_profile);
@@ -1579,7 +1591,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_queue_private_event(switch_c
        switch_status_t status = SWITCH_STATUS_FALSE;
 
        assert(session != NULL);
-
+       
        if (!session->private_event_queue) {
                switch_queue_create(&session->private_event_queue, SWITCH_EVENT_QUEUE_LEN, session->pool);
        }
@@ -1608,8 +1620,17 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_dequeue_private_event(switch
 {
        switch_status_t status = SWITCH_STATUS_FALSE;
        void *pop;
+       switch_channel_t *channel;
 
        assert(session != NULL);
+
+       channel = switch_core_session_get_channel(session);
+       assert(channel != NULL);
+       
+       if (switch_channel_test_flag(channel, CF_EVENT_PARSE)) {
+               return status;
+       }
+
        
        if (session->private_event_queue) {
                if ((status = (switch_status_t) switch_queue_trypop(session->private_event_queue, &pop)) == SWITCH_STATUS_SUCCESS) {
@@ -1880,7 +1901,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess
 
        assert(session != NULL);
        assert(frame != NULL);
-       assert(frame->codec != NULL);
+
 
        if (switch_channel_test_flag(session->channel, CF_HOLD)) {
                return SWITCH_STATUS_SUCCESS;
@@ -1895,6 +1916,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess
                return SWITCH_STATUS_SUCCESS;
        }
 
+       assert(frame->codec != NULL);
 
        if ((session->write_codec && frame->codec && session->write_codec->implementation != frame->codec->implementation)) {
                need_codec = TRUE;
@@ -2587,6 +2609,12 @@ static void switch_core_standard_on_hold(switch_core_session_t *session)
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Standard HOLD\n");
 }
 
+static void switch_core_standard_on_hibernate(switch_core_session_t *session)
+{
+       assert(session != NULL);
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Standard HIBERNATE\n");
+}
+
 SWITCH_DECLARE(void) switch_core_session_signal_state_change(switch_core_session_t *session)
 {
 
@@ -2976,6 +3004,43 @@ SWITCH_DECLARE(void) switch_core_session_run(switch_core_session_t *session)
                                        }
                                }
                                break;
+                       case CS_HIBERNATE:      /* wait in limbo */
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "(%s) State HIBERNATE\n", switch_channel_get_name(session->channel));
+                               if (!driver_state_handler->on_hibernate ||
+                                       (driver_state_handler->on_hibernate &&
+                                        driver_state_handler->on_hibernate(session) == SWITCH_STATUS_SUCCESS &&
+                                        midstate == switch_channel_get_state(session->channel))) {
+
+                                       while((application_state_handler = switch_channel_get_state_handler(session->channel, index++)) != 0) {
+                                               if (!application_state_handler || !application_state_handler->on_hibernate ||
+                                                       (application_state_handler->on_hibernate &&
+                                                        application_state_handler->on_hibernate(session) == SWITCH_STATUS_SUCCESS &&
+                                                        midstate == switch_channel_get_state(session->channel))) {
+                                                       proceed++;
+                                                       continue;
+                                               } else {
+                                                       proceed = 0;
+                                                       break;
+                                               }
+                                       }
+                                       index = 0;
+                                       while(proceed && (application_state_handler = switch_core_get_state_handler(index++)) != 0) {
+                                               if (!application_state_handler || !application_state_handler->on_hibernate ||
+                                                       (application_state_handler->on_hibernate &&
+                                                        application_state_handler->on_hibernate(session) == SWITCH_STATUS_SUCCESS &&
+                                                        midstate == switch_channel_get_state(session->channel))) {
+                                                       proceed++;
+                                                       continue;
+                                               } else {
+                                                       proceed = 0;
+                                                       break;
+                                               }
+                                       }
+                                       if (proceed) {
+                                               switch_core_standard_on_hibernate(session);
+                                       }
+                               }
+                               break;
                        }
 
                        if (midstate == CS_DONE) {
index 8a9b76a4b4dab3b20f2258682f9776901826bb27..4aaab8b89fae93d403b9299295f8927c93114511 100644 (file)
@@ -89,11 +89,14 @@ static void switch_ivr_parse_event(switch_core_session_t *session, switch_event_
        apr_ssize_t hlen = APR_HASH_KEY_STRING;
        unsigned long CMD_EXECUTE = apr_hashfunc_default("execute", &hlen);
        unsigned long CMD_HANGUP = apr_hashfunc_default("hangup", &hlen);
-
+       unsigned long CMD_NOMEDIA = apr_hashfunc_default("nomedia", &hlen);
+       
     assert(channel != NULL);
        hlen = (switch_size_t) strlen(cmd);
        cmd_hash = apr_hashfunc_default(cmd, &hlen);
 
+       switch_channel_set_flag(channel, CF_EVENT_PARSE);
+       
        if (!switch_strlen_zero(cmd)) {
                if (cmd_hash == CMD_EXECUTE) {
                        const switch_application_interface_t *application_interface;
@@ -116,8 +119,14 @@ static void switch_ivr_parse_event(switch_core_session_t *session, switch_event_
                        }
 
                        switch_channel_hangup(channel, cause);
-               }
+               } else if (cmd_hash == CMD_NOMEDIA) {
+                       char *uuid = switch_event_get_header(event, "nomedia-uuid");
+                       switch_ivr_nomedia(uuid, SMF_REBRIDGE);
+               } 
        }
+
+       switch_channel_clear_flag(channel, CF_EVENT_PARSE);
+
 }
 
 SWITCH_DECLARE(switch_status_t) switch_ivr_park(switch_core_session_t *session)
@@ -1459,13 +1468,15 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj)
                }
 
                if (switch_channel_test_flag(chan_a, CF_TRANSFER)) {
+                       switch_channel_clear_flag(chan_a, CF_HOLD);
+                       switch_channel_clear_flag(chan_a, CF_SUSPEND);
                        break;
                }
-
+               
                if (switch_core_session_dequeue_private_event(session_a, &event) == SWITCH_STATUS_SUCCESS) {
-                       switch_channel_set_flag(chan_b, CF_HOLD);
+                       switch_channel_set_flag(chan_b, CF_SUSPEND);
                        switch_ivr_parse_event(session_a, event);
-                       switch_channel_clear_flag(chan_b, CF_HOLD);
+                       switch_channel_clear_flag(chan_b, CF_SUSPEND);
                        switch_event_destroy(&event);
                }
 
@@ -1474,7 +1485,7 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj)
                        char dtmf[128];
                        switch_channel_dequeue_dtmf(chan_a, dtmf, sizeof(dtmf));
                        switch_core_session_send_dtmf(session_b, dtmf);
-
+                       
                        if (input_callback) {
                                if (input_callback(session_a, dtmf, SWITCH_INPUT_TYPE_DTMF, user_data, 0) != SWITCH_STATUS_SUCCESS) {
                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s ended call via DTMF\n", switch_channel_get_name(chan_a));
@@ -1516,6 +1527,12 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj)
                        continue;
                }
 
+
+               if (switch_channel_test_flag(chan_a, CF_SUSPEND) || switch_channel_test_flag(chan_b, CF_SUSPEND)) {
+                       switch_yield(10000);
+                       continue;
+               }
+
                /* read audio from 1 channel and write it to the other */
                status = switch_core_session_read_frame(session_a, &read_frame, -1, stream_id);
 
@@ -1624,6 +1641,7 @@ static switch_status_t uuid_bridge_on_transmit(switch_core_session_t *session)
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CUSTOM TRANSMIT\n");
        switch_channel_clear_state_handler(channel, NULL);
 
+
        if (!switch_channel_test_flag(channel, CF_ORIGINATOR)) {
                switch_channel_set_flag(channel, CF_TAGGED);
                return SWITCH_STATUS_FALSE;
@@ -1637,6 +1655,7 @@ static switch_status_t uuid_bridge_on_transmit(switch_core_session_t *session)
                uint8_t ready_a, ready_b;
                switch_caller_profile_t *profile, *new_profile;
 
+
                switch_channel_clear_flag(channel, CF_TRANSFER);
                switch_channel_set_private(channel, "_uuid_bridge_", NULL);
 
@@ -1646,8 +1665,9 @@ static switch_status_t uuid_bridge_on_transmit(switch_core_session_t *session)
                        mystate = switch_channel_get_state(channel);
                }
 
-               switch_channel_clear_flag(other_channel, CF_TRANSFER|CF_TAGGED);
-
+               switch_channel_clear_flag(other_channel, CF_TRANSFER);
+               switch_channel_clear_flag(other_channel, CF_TAGGED);
+               
 
                switch_core_session_reset(session);
                switch_core_session_reset(other_session);
@@ -2175,7 +2195,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
 
        notready:
 
-               if (!switch_channel_ready(caller_channel)) {
+               if (caller_channel && !switch_channel_ready(caller_channel)) {
                        idx = IDX_CANCEL;
                }
 
@@ -2214,11 +2234,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
                }
 
                if (caller_channel) {
-                       char *val;
-                       if (switch_channel_test_flag(peer_channel, CF_NOMEDIA) && (val = switch_channel_get_variable(peer_channel, SWITCH_R_SDP_VARIABLE))) {
-                               switch_channel_set_variable(caller_channel, SWITCH_L_SDP_VARIABLE, val);
-                       }
-
                        if (switch_channel_test_flag(peer_channel, CF_ANSWERED)) {
                                switch_channel_answer(caller_channel);
                        } else if (switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA)) {
@@ -2294,6 +2309,221 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
        return status;
 }
 
+SWITCH_DECLARE(switch_status_t) switch_ivr_hold(switch_core_session_t *session)
+{
+       switch_core_session_message_t msg = {0};
+       switch_channel_t *channel;
+
+       msg.message_id = SWITCH_MESSAGE_INDICATE_HOLD;
+       msg.from = __FILE__;
+       
+       channel = switch_core_session_get_channel(session);
+       assert(channel != NULL);
+               
+       switch_channel_set_flag(channel, CF_HOLD);
+       switch_channel_set_flag(channel, CF_SUSPEND);
+
+       switch_core_session_receive_message(session, &msg);
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_hold_uuid(char *uuid)
+{
+       switch_core_session_t *session;
+
+       if ((session = switch_core_session_locate(uuid))) {
+               switch_ivr_hold(session);
+               switch_core_session_rwunlock(session);
+       }
+       
+       return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_unhold(switch_core_session_t *session)
+{
+       switch_core_session_message_t msg = {0};
+       switch_channel_t *channel;
+               
+       msg.message_id = SWITCH_MESSAGE_INDICATE_UNHOLD;
+       msg.from = __FILE__;
+       
+       channel = switch_core_session_get_channel(session);
+       assert(channel != NULL);
+               
+       switch_channel_clear_flag(channel, CF_HOLD);
+       switch_channel_clear_flag(channel, CF_SUSPEND);
+       
+       switch_core_session_receive_message(session, &msg);
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_unhold_uuid(char *uuid)
+{
+       switch_core_session_t *session;
+
+       if ((session = switch_core_session_locate(uuid))) {
+               switch_ivr_unhold(session);
+               switch_core_session_rwunlock(session);
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_broadcast(char *uuid, char *path, switch_media_flag_t flags)
+{
+    switch_channel_t *channel;
+       uint8_t nomedia;
+       switch_core_session_t *session;
+       switch_event_t *event;
+       switch_core_session_t *other_session;
+       char *other_uuid = NULL;
+
+       if ((session = switch_core_session_locate(uuid))) {
+               char *app;
+               
+               channel = switch_core_session_get_channel(session);
+               assert(channel != NULL);
+
+               if ((nomedia = switch_channel_test_flag(channel, CF_NOMEDIA))) {
+                       switch_ivr_media(uuid, SMF_REBRIDGE);
+               }
+               
+               if (!strncasecmp(path, "speak:", 6)) {
+                       path += 6;
+                       app = "speak";
+               } else {
+                       app = "playback";
+               }
+               
+               if ((flags & SMF_ECHO_BRIDGED) && (other_uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE))
+                       && (other_session = switch_core_session_locate(other_uuid))) {
+                       if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
+                               switch_event_add_header(event, SWITCH_STACK_BOTTOM, "call-command", "execute");
+                               switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-name", app);
+                               switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-arg", "%s", path);
+                               switch_core_session_queue_private_event(other_session, &event);
+                       }
+                       switch_core_session_rwunlock(other_session);
+                       other_session = NULL;
+               }
+
+               if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
+                       switch_event_add_header(event, SWITCH_STACK_BOTTOM, "call-command", "execute");
+                       switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-name", app);
+                       switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-arg", "%s", path);
+                       switch_core_session_queue_private_event(session, &event);
+               }
+
+               if (nomedia) {
+                       if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
+                               switch_event_add_header(event, SWITCH_STACK_BOTTOM, "call-command", "nomedia");
+                               switch_event_add_header(event, SWITCH_STACK_BOTTOM, "nomedia-uuid", "%s", uuid);
+                               switch_core_session_queue_private_event(session, &event);
+                       }
+               }
+               
+               switch_core_session_rwunlock(session);
+       }
+       return SWITCH_STATUS_SUCCESS;
+       
+}
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_media(char *uuid, switch_media_flag_t flags)
+{
+       char *other_uuid = NULL;
+       switch_channel_t *channel, *other_channel = NULL;
+    switch_core_session_t *session, *other_session;
+       switch_core_session_message_t msg = {0};
+       switch_status_t status = SWITCH_STATUS_GENERR;
+       
+       msg.message_id = SWITCH_MESSAGE_INDICATE_MEDIA;
+       msg.from = __FILE__;
+
+       if ((session = switch_core_session_locate(uuid))) {
+               channel = switch_core_session_get_channel(session);
+               assert(channel != NULL);
+               
+               if (switch_channel_test_flag(channel, CF_NOMEDIA)) {
+                       status = SWITCH_STATUS_SUCCESS;
+                       switch_channel_clear_flag(channel, CF_NOMEDIA);
+                       switch_core_session_receive_message(session, &msg);
+                       if ((flags & SMF_REBRIDGE) && (other_uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE)) 
+                               && (other_session = switch_core_session_locate(other_uuid))) {
+                               other_channel = switch_core_session_get_channel(other_session);
+                               assert(other_channel != NULL);
+                               switch_core_session_receive_message(other_session, &msg);
+                               switch_channel_clear_state_handler(other_channel, NULL);
+                               switch_core_session_rwunlock(other_session);
+                       }
+                       if (other_channel) {
+                               switch_channel_clear_state_handler(channel, NULL);
+                       }
+               }
+               
+               switch_core_session_rwunlock(session);
+
+               if (other_channel) {
+                       switch_ivr_uuid_bridge(uuid, other_uuid);
+               }
+       }
+
+       return status;
+}
+
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_nomedia(char *uuid, switch_media_flag_t flags)
+{
+       char *other_uuid;
+       switch_channel_t *channel, *other_channel = NULL;
+    switch_core_session_t *session, *other_session = NULL;
+       switch_core_session_message_t msg = {0};
+       switch_status_t status = SWITCH_STATUS_GENERR;
+
+       msg.message_id = SWITCH_MESSAGE_INDICATE_NOMEDIA;
+       msg.from = __FILE__;
+
+       if ((session = switch_core_session_locate(uuid))) {
+               status = SWITCH_STATUS_SUCCESS;
+               channel = switch_core_session_get_channel(session);
+               assert(channel != NULL);
+               if (!switch_channel_test_flag(channel, CF_NOMEDIA)) {
+                       switch_channel_set_flag(channel, CF_NOMEDIA);
+                       switch_core_session_receive_message(session, &msg);
+                       if ((flags & SMF_REBRIDGE) && (other_uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE)) &&
+                               (other_session = switch_core_session_locate(other_uuid))) {
+                               other_channel = switch_core_session_get_channel(other_session);
+                               assert(other_channel != NULL);
+                               switch_core_session_receive_message(other_session, &msg);
+                               switch_channel_clear_state_handler(other_channel, NULL);
+
+                       }
+                       if (other_channel) {
+                               switch_channel_clear_state_handler(channel, NULL);
+                               switch_ivr_signal_bridge(session, other_session);
+                               switch_core_session_rwunlock(other_session);
+                       }
+               }
+               switch_core_session_rwunlock(session);
+       }
+
+       return status;
+}
+
+static switch_status_t signal_bridge_on_hibernate(switch_core_session_t *session)
+{
+       switch_channel_t *channel = NULL;
+
+       channel = switch_core_session_get_channel(session);
+       assert(channel != NULL);
+       switch_channel_clear_flag(channel, CF_TRANSFER);
+       
+       switch_channel_set_variable(channel, SWITCH_BRIDGE_VARIABLE, switch_channel_get_variable(channel, SWITCH_SIGNAL_BRIDGE_VARIABLE));
+
+       return SWITCH_STATUS_SUCCESS;
+}
 
 static switch_status_t signal_bridge_on_hangup(switch_core_session_t *session)
 {
@@ -2314,7 +2544,7 @@ static switch_status_t signal_bridge_on_hangup(switch_core_session_t *session)
        }
 
 
-       if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BRIDGE_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) {
+       if ((uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) {
                switch_channel_t *other_channel = NULL;
 
                other_channel = switch_core_session_get_channel(other_session);
@@ -2324,6 +2554,7 @@ static switch_status_t signal_bridge_on_hangup(switch_core_session_t *session)
                switch_core_session_rwunlock(other_session);
        }
 
+
        return SWITCH_STATUS_SUCCESS;
 }
 
@@ -2334,7 +2565,8 @@ static const switch_state_handler_table_t signal_bridge_state_handlers = {
        /*.on_hangup */ signal_bridge_on_hangup,
        /*.on_loopback */ NULL,
        /*.on_transmit */ NULL,
-       /*.on_hold */ NULL
+       /*.on_hold */ NULL,
+       /*.on_hibernate*/ signal_bridge_on_hibernate
 };
 
 
@@ -2352,9 +2584,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_signal_bridge(switch_core_session_t *
        peer_channel = switch_core_session_get_channel(peer_session);
        assert(peer_channel != NULL);
 
-       switch_channel_set_variable(caller_channel, SWITCH_SIGNAL_BRIDGE_VARIABLE, switch_core_session_get_uuid(peer_session));
-       switch_channel_set_variable(peer_channel, SWITCH_SIGNAL_BRIDGE_VARIABLE, switch_core_session_get_uuid(session));
-
        switch_channel_clear_state_handler(caller_channel, NULL);
        switch_channel_clear_state_handler(peer_channel, NULL);
 
@@ -2382,8 +2611,15 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_signal_bridge(switch_core_session_t *
                switch_event_fire(&event);
        }
        
-       switch_channel_set_state(caller_channel, CS_TRANSMIT);
-       switch_channel_set_state(peer_channel, CS_TRANSMIT);
+       switch_channel_set_state_flag(caller_channel, CF_TRANSFER);
+       switch_channel_set_state_flag(peer_channel, CF_TRANSFER);
+
+
+       switch_channel_set_variable(caller_channel, SWITCH_SIGNAL_BRIDGE_VARIABLE, switch_core_session_get_uuid(peer_session));
+       switch_channel_set_variable(peer_channel, SWITCH_SIGNAL_BRIDGE_VARIABLE, switch_core_session_get_uuid(session));
+
+       switch_channel_set_state(caller_channel, CS_HIBERNATE);
+       switch_channel_set_state(peer_channel, CS_HIBERNATE);
 
        return SWITCH_STATUS_SUCCESS;
 }
@@ -2483,7 +2719,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses
                                switch_channel_event_set_data(caller_channel, event);
                                switch_event_fire(&event);
                        }
-
                        if (switch_channel_get_state(caller_channel) != CS_EXECUTE && !switch_channel_test_flag(caller_channel, CF_TRANSFER)) {
                                switch_channel_hangup(caller_channel, SWITCH_CAUSE_NORMAL_CLEARING);
                        }
@@ -2555,7 +2790,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_uuid_bridge(char *originator_uuid, ch
                        switch_channel_add_state_handler(originatee_channel, &uuid_bridge_state_handlers);
                        switch_channel_set_private(originator_channel, "_uuid_bridge_", originatee_session);
 
-                       /* switch_channel_set_state_flag sets flags you want to be set when the next stat change happens */
+                       /* switch_channel_set_state_flag sets flags you want to be set when the next state change happens */
                        switch_channel_set_state_flag(originator_channel, CF_TRANSFER);
                        switch_channel_set_state_flag(originatee_channel, CF_TRANSFER);
 
@@ -2585,6 +2820,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_
        switch_channel_t *channel;
        switch_caller_profile_t *profile, *new_profile;
        switch_core_session_message_t msg = {0};
+       switch_core_session_t *other_session;
+       char *uuid = NULL;
 
        assert(session != NULL);
        assert(extension != NULL);
@@ -2608,6 +2845,21 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_
                        context = new_profile->context;
                }
 
+               if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BRIDGE_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) {
+                       switch_channel_t *other_channel = NULL;
+
+                       other_channel = switch_core_session_get_channel(other_session);
+                       assert(other_channel != NULL);
+                       
+                       switch_channel_set_variable(channel, SWITCH_SIGNAL_BRIDGE_VARIABLE, NULL);
+                       switch_channel_set_variable(other_channel, SWITCH_SIGNAL_BRIDGE_VARIABLE, NULL);
+
+                       switch_channel_hangup(other_channel, SWITCH_CAUSE_BLIND_TRANSFER);
+                       switch_ivr_media(uuid, SMF_NONE);
+                       
+                       switch_core_session_rwunlock(other_session);
+               }
+
                switch_channel_set_caller_profile(channel, new_profile);
                switch_channel_set_flag(channel, CF_TRANSFER);
                switch_channel_set_state(channel, CS_RING);
index 14f54d33a68d52cd251feeb3509c6491485e1e99..965f4397dd532d5e1cc30926e82eb0645400ec91 100644 (file)
@@ -117,6 +117,8 @@ SWITCH_DECLARE(unsigned int) switch_separate_string(char *buf, char delim, char
        char *ptr;
        int quot = 0;
        char qc = '"';
+       char *e;
+       int x;
 
        if (!buf || !array || !arraylen) {
                return 0;
@@ -143,16 +145,19 @@ SWITCH_DECLARE(unsigned int) switch_separate_string(char *buf, char delim, char
        }
 
        if (*ptr) {
-               char *e;
-               if (*ptr == qc) {
-                       ptr++;
-               }
-               if ((e = strchr(ptr, qc))) {
-                       *e = '\0';
-               }
                array[argc++] = ptr;
        }
 
+       /* strip quotes */
+       for(x = 0; x < argc; x++) {
+               if (*(array[x]) == qc) {
+                       (array[x])++;
+                       if ((e = strchr(array[x], qc))) {
+                               *e = '\0';
+                       }
+               }
+       }
+
        return argc;
 }