]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
add uuid_bridge api call and ivr function Usage: uuid_bridge <uuid> <other_uuid>...
authorAnthony Minessale <anthony.minessale@gmail.com>
Tue, 19 Sep 2006 02:18:24 +0000 (02:18 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Tue, 19 Sep 2006 02:18:24 +0000 (02:18 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2748 d0543943-73ff-0310-b7d9-9358b9ac24b2

src/include/switch_channel.h
src/include/switch_ivr.h
src/mod/applications/mod_commands/mod_commands.c
src/switch_channel.c
src/switch_ivr.c

index ab19fdd4356ebf2cbb2c732a2546cbfd8909e71f..1f1d52fc970e0d4d01b6237743319dad456f6561 100644 (file)
@@ -247,6 +247,13 @@ SWITCH_DECLARE(int) switch_channel_test_flag(switch_channel_t *channel, switch_c
 */
 SWITCH_DECLARE(void) switch_channel_set_flag(switch_channel_t *channel, switch_channel_flag_t flags);
 
+/*!
+  \brief Set given flag(s) on a given channel to be applied on the next state change
+  \param channel channel on which to set flag(s)
+  \param flags or'd list of flags to set
+*/
+SWITCH_DECLARE(void) switch_channel_set_state_flag(switch_channel_t *channel, switch_channel_flag_t flags);
+
 /*!
   \brief Clear given flag(s) from a channel
   \param channel channel to clear flags from
index 3d9db37997cff251c79413c29340ceb86d482383..cde5758315c3ed34fa323e3771e46ba336e1118b 100644 (file)
@@ -233,6 +233,15 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses
 */
 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
+  \param originatee_uuid the uuid of the originator
+  \return SWITCH_STATUS_SUCCESS if all is well 
+*/
+SWITCH_DECLARE(switch_status_t) switch_ivr_uuid_bridge(char *originator_uuid, char *originatee_uuid);
+
 /** @} */
 
 SWITCH_END_EXTERN_C
index 9c63a876477a2dea1e3b1c0808b29988888601ec..19e8d92fd82dc81e3ad9ebfa4ebc188f9d65cf35 100644 (file)
@@ -178,6 +178,27 @@ static switch_status_t transfer_function(char *cmd, switch_core_session_t *isess
 
 
 
+static switch_status_t uuid_bridge_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream)
+{
+       char *argv[4] = {0};
+       int argc = 0;
+
+       if (isession) {
+               return SWITCH_STATUS_FALSE;
+       }
+       
+       argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+
+       if (argc != 2) {
+               stream->write_function(stream, "Invalid Parameters\nUsage: uuid_bridge <uuid> <other_uuid>\n");
+       } else {
+               switch_ivr_uuid_bridge(argv[0], argv[1]);
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+
 
 static switch_status_t pause_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream)
 {
@@ -415,11 +436,19 @@ static switch_status_t show_function(char *cmd, switch_core_session_t *session,
 }
 
 
+
+static switch_api_interface_t uuid_bridge_api_interface = {
+       /*.interface_name */ "uuid_bridge",
+       /*.desc */ "uuid_bridge",
+       /*.function */ uuid_bridge_function,
+       /*.next */ NULL
+};
+
 static switch_api_interface_t status_api_interface = {
        /*.interface_name */ "status",
        /*.desc */ "status",
        /*.function */ status_function,
-       /*.next */ NULL
+       /*.next */ &uuid_bridge_api_interface
 };
 
 static switch_api_interface_t show_api_interface = {
index dd88e6193820ec7b09bd195a0c2641a0ec84bf41..c40c386b7a6f66f784b72a7dac341adf071d2d4c 100644 (file)
@@ -98,6 +98,7 @@ struct switch_channel {
        switch_core_session_t *session;
        switch_channel_state_t state;
        uint32_t flags;
+       uint32_t state_flags;
        switch_caller_profile_t *caller_profile;
        switch_caller_profile_t *originator_caller_profile;
        switch_caller_profile_t *originatee_caller_profile;
@@ -374,6 +375,15 @@ SWITCH_DECLARE(void) switch_channel_set_flag(switch_channel_t *channel, switch_c
        switch_set_flag_locked(channel, flags);
 }
 
+SWITCH_DECLARE(void) switch_channel_set_state_flag(switch_channel_t *channel, switch_channel_flag_t flags)
+{
+       assert(channel != NULL);
+
+       switch_mutex_lock(channel->flag_mutex);
+       channel->state_flags |= flags;
+       switch_mutex_unlock(channel->flag_mutex);
+}
+
 SWITCH_DECLARE(void) switch_channel_clear_flag(switch_channel_t *channel, switch_channel_flag_t flags)
 {
        assert(channel != NULL);
@@ -395,7 +405,7 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_get_state(switch_channel_t
 SWITCH_DECLARE(unsigned int) switch_channel_ready(switch_channel_t *channel)
 {
        assert(channel != NULL);
-       return (channel->state > CS_RING && channel->state < CS_HANGUP) ? 1 : 0;
+       return (channel->state > CS_RING && channel->state < CS_HANGUP && !switch_test_flag(channel, CF_TRANSFER)) ? 1 : 0;
 }
 
 static const char *state_names[] = {
@@ -616,6 +626,12 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_set_state(switch_c
                }
        }
  done:
+       
+       if (channel->state_flags) {
+               channel->flags |= channel->state_flags;
+               channel->state_flags = 0;
+       }
+
        switch_mutex_unlock(channel->flag_mutex);
        return channel->state;
 }
index 6228190a5032ec285af48aaa3a21ebdaa5ae935e..1d944c4b4922b17edc32ebf3b4ae5628b8e73992 100644 (file)
@@ -1396,6 +1396,98 @@ static const switch_state_handler_table_t audio_bridge_peer_state_handlers = {
        /*.on_hold */ audio_bridge_on_hold,
 };
 
+
+static switch_status_t uuid_bridge_on_transmit(switch_core_session_t *session)
+{
+       switch_channel_t *channel = NULL;
+       switch_core_session_t *other_session;
+
+       channel = switch_core_session_get_channel(session);
+       assert(channel != NULL);
+
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "CUSTOM TRANSMIT\n");
+
+       if ((other_session = switch_channel_get_private(channel, "_uuid_bridge_"))) {
+               switch_channel_t *other_channel = switch_core_session_get_channel(other_session);
+               switch_channel_state_t state = switch_channel_get_state(other_channel);
+               switch_event_t *event;
+               uint8_t ready_a, ready_b;
+               switch_caller_profile_t *profile, *new_profile;
+
+               switch_channel_set_private(channel, "_uuid_bridge_", NULL);
+               while (state <= CS_HANGUP && state != CS_TRANSMIT) {
+                       switch_yield(1000);
+                       state = switch_channel_get_state(other_channel);
+               }
+
+               switch_channel_clear_flag(channel, CF_TRANSFER);
+               switch_channel_clear_flag(other_channel, CF_TRANSFER);
+
+               switch_core_session_reset(session);
+               switch_core_session_reset(other_session);
+               
+               ready_a = switch_channel_ready(channel);
+               ready_b = switch_channel_ready(other_channel);
+
+               if (!ready_a || !ready_b) {
+                       if (!ready_a) {
+                               switch_channel_hangup(other_channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+                       }
+
+                       if (!ready_b) {
+                               switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+                       }
+                       return SWITCH_STATUS_FALSE;
+               }
+               
+               /* add another profile to both sessions for CDR's sake */
+               if ((profile = switch_channel_get_caller_profile(channel))) {
+                       new_profile = switch_caller_profile_clone(session, profile);
+                       new_profile->destination_number = switch_core_session_strdup(session, switch_core_session_get_uuid(other_session));
+                       switch_channel_set_caller_profile(channel, new_profile);
+               } 
+
+               if ((profile = switch_channel_get_caller_profile(other_channel))) {
+                       new_profile = switch_caller_profile_clone(other_session, profile);
+                       new_profile->destination_number = switch_core_session_strdup(other_session, switch_core_session_get_uuid(session));
+                       switch_channel_set_caller_profile(other_channel, new_profile);
+               } 
+
+               /* fire events that will change the data table from "show channels" */
+               if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) {
+                       switch_channel_event_set_data(channel, event);
+                       switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "uuid_bridge");
+                       switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", switch_core_session_get_uuid(other_session));
+                       switch_event_fire(&event);
+               }
+
+               if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) {
+                       switch_channel_event_set_data(other_channel, event);
+                       switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "uuid_bridge");
+                       switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", switch_core_session_get_uuid(session));
+                       switch_event_fire(&event);
+               }
+
+               switch_ivr_multi_threaded_bridge(session, other_session, NULL, NULL, NULL);
+       } else {
+               switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+       }
+
+
+
+       return SWITCH_STATUS_FALSE;
+}
+
+static const switch_state_handler_table_t uuid_bridge_state_handlers = {
+       /*.on_init */ NULL,
+       /*.on_ring */ NULL,
+       /*.on_execute */ NULL,
+       /*.on_hangup */ NULL,
+       /*.on_loopback */ NULL,
+       /*.on_transmit */ uuid_bridge_on_transmit,
+       /*.on_hold */ NULL
+};
+
 struct key_collect {
        char *key;
        char *file;
@@ -2009,6 +2101,48 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses
 }
 
 
+SWITCH_DECLARE(switch_status_t) switch_ivr_uuid_bridge(char *originator_uuid, char *originatee_uuid)
+{
+       switch_core_session_t *originator_session, *originatee_session;
+       switch_channel_t *originator_channel, *originatee_channel;
+       switch_status_t status = SWITCH_STATUS_FALSE;
+
+       if ((originator_session = switch_core_session_locate(originator_uuid))) {
+               if ((originatee_session = switch_core_session_locate(originatee_uuid))) { 
+                       originator_channel = switch_core_session_get_channel(originator_session);
+                       originatee_channel = switch_core_session_get_channel(originatee_session);
+
+                       /* override transmit state for originator_channel to bridge to originatee_channel 
+                        * install pointer to originatee_session into originator_channel
+                        * set CF_TRANSFER on both channels and change state to CS_TRANSMIT to
+                        * inturrupt anything they are already doing.
+                        * originatee_session will fall asleep and originator_session will bridge to it
+                        */
+
+                       switch_channel_add_state_handler(originator_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(originator_channel, CF_TRANSFER);
+                       switch_channel_set_state_flag(originatee_channel, CF_TRANSFER);
+
+                       /* release the read locks we have on the channels */
+                       switch_core_session_rwunlock(originator_session);
+                       switch_core_session_rwunlock(originatee_session);
+
+                       /* change the states and let the chips fall where they may */
+                       switch_channel_set_state(originator_channel, CS_TRANSMIT);
+                       switch_channel_set_state(originatee_channel, CS_TRANSMIT);
+                       
+               } else {
+                       switch_core_session_rwunlock(originator_session);
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "no channel for uuid %s\n", originatee_uuid);
+               }
+       }
+
+       return status;
+
+}
 
 SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_t *session, char *extension, char *dialplan, char *context)
 {