]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
improve bridge code
authorAnthony Minessale <anthony.minessale@gmail.com>
Tue, 25 Apr 2006 18:02:12 +0000 (18:02 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Tue, 25 Apr 2006 18:02:12 +0000 (18:02 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@1251 d0543943-73ff-0310-b7d9-9358b9ac24b2

src/include/switch_channel.h
src/include/switch_types.h
src/switch_channel.c
src/switch_core.c
src/switch_ivr.c

index 986ed23aaf154a3474241448afd39f505b1325e2..f65defe1794b119e234973afe0053c73f778cc09 100644 (file)
@@ -253,6 +253,13 @@ SWITCH_DECLARE(switch_status) switch_channel_pre_answer(switch_channel *channel)
 */
 SWITCH_DECLARE(int) switch_channel_add_state_handler(switch_channel *channel, const switch_state_handler_table *state_handler);
 
+/*!
+  \brief clear a state handler table from a given channel
+  \param channel channel from which to clear the state handler table
+  \param state_handler table of state handler functions
+*/
+SWITCH_DECLARE(void) switch_channel_clear_state_handler(switch_channel *channel, const switch_state_handler_table *state_handler);
+
 /*!
   \brief Retrieve an state handler tablefrom a given channel at given index level
   \param channel channel from which to retrieve the state handler table
index 76eacc68ee305ed99b726495260f0c475cb5d236..8f668fbdd2e17b4fb6d1e2d9b9dc896211175dde 100644 (file)
@@ -323,7 +323,8 @@ CF_OUTBOUND     = (1 <<  1) - Channel is an outbound channel
 CF_EARLY_MEDIA  = (1 <<  2) - Channel is ready for audio before answer 
 CF_ORIGINATOR  = (1 <<  3) - Channel is an originator
 CF_TRANSFER            = (1 <<  4) - Channel is being transfered
-CF_ACCEPT_CNG     = (1 <<  5) - Channel will accept CNG frames
+CF_ACCEPT_CNG  = (1 <<  5) - Channel will accept CNG frames
+CF_LOCK_THREAD = (1 <<  6) - Prevent the channel thread from exiting while this flag is set
 </pre>
  */
 
@@ -333,7 +334,8 @@ typedef enum {
        CF_EARLY_MEDIA  = (1 <<  2),
        CF_ORIGINATOR   = (1 <<  3),
        CF_TRANSFER             = (1 <<  4),
-       CF_ACCEPT_CNG     = (1 <<  5)
+       CF_ACCEPT_CNG   = (1 <<  5),
+       CF_LOCK_THREAD  = (1 <<  6)
 } switch_channel_flag;
 
 
@@ -357,11 +359,14 @@ typedef enum {
   \brief Signals to send to channels
 <pre>
 SWITCH_SIG_KILL - Kill the channel
+SWITCH_SIG_XFER - Stop the current io but leave it viable
 </pre>
  */
 
 typedef enum {
-       SWITCH_SIG_KILL
+       SWITCH_SIG_NONE,
+       SWITCH_SIG_KILL,
+       SWITCH_SIG_XFER
 } switch_signal;
 
 /*!
index 90a91b7760cdecbeb6749090d0d0b6e8375294c7..e9389e3f9fe074b550bc6048b34e601e75677f3a 100644 (file)
@@ -645,6 +645,26 @@ SWITCH_DECLARE(const switch_state_handler_table *) switch_channel_get_state_hand
        return channel->state_handlers[index];
 }
 
+SWITCH_DECLARE(void) switch_channel_clear_state_handler(switch_channel *channel, const switch_state_handler_table *state_handler)
+{
+       int index, i = 0;
+       const switch_state_handler_table *new_handlers[SWITCH_MAX_STATE_HANDLERS] = {0};
+
+       assert(channel != NULL);
+
+
+       for (index = 0; index < channel->state_handler_index; index++) {
+               if (channel->state_handlers[index] != state_handler) {
+                       new_handlers[i++] = channel->state_handlers[index];
+               }
+       }
+       memset(channel->state_handlers, 0, sizeof(channel->state_handlers));
+       for (index = 0; index < i; index++) {
+               channel->state_handlers[index] = new_handlers[i];
+       }
+
+}
+
 SWITCH_DECLARE(void) switch_channel_set_caller_extension(switch_channel *channel,
                                                                                                                 switch_caller_extension *caller_extension)
 {
index 4abc7850779c9fbe4921de8836c2ada337a32d48..b02b31531b71abaeecbe22fdbab97d9a8d2b3a54 100644 (file)
@@ -2197,6 +2197,13 @@ static void *SWITCH_THREAD_FUNC switch_core_session_thread(switch_thread *thread
 
        switch_core_hash_insert(runtime.session_table, session->uuid_str, session);
        switch_core_session_run(session);
+
+       if (switch_channel_test_flag(session->channel, CF_LOCK_THREAD)) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Session %u (%s) Locked\n", session->id, switch_channel_get_name(session->channel));
+               while(switch_channel_test_flag(session->channel, CF_LOCK_THREAD)) {
+                       switch_yield(10000);
+               }
+       }
        switch_core_hash_delete(runtime.session_table, session->uuid_str);
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Session %u (%s) Ended\n", session->id, switch_channel_get_name(session->channel));
        switch_core_session_destroy(&session);
index 359ec4eed0ce3b6b89da02e7ce492936b1e15822..a4b9f74e5287eb9e56acab1b1a6840a99f78b8d8 100644 (file)
@@ -32,6 +32,8 @@
 #include <switch.h>
 #include <switch_ivr.h>
 
+static const switch_state_handler_table audio_bridge_peer_state_handlers;
+
 
 SWITCH_DECLARE(switch_status) switch_ivr_collect_digits_callback(switch_core_session *session,
                                                                                                                                 switch_dtmf_callback_function dtmf_callback,
@@ -779,16 +781,19 @@ static void *audio_bridge_thread(switch_thread *thread, void *obj)
 
        data->running = 0;
 
-       if (his_thread->running > 0 && switch_channel_test_flag(chan_a, CF_ORIGINATOR)) {
-               if (!switch_channel_test_flag(chan_b, CF_TRANSFER)) {
+       if (switch_channel_test_flag(chan_a, CF_ORIGINATOR)) {
+               if (switch_channel_test_flag(chan_b, CF_TRANSFER)) {
+                       if (switch_channel_get_state(chan_b) < CS_HANGUP) {
+                               switch_channel_set_state(chan_b, CS_RING);
+                               /* TBD we need to teach all the endpoints to honor this still */
+                               switch_core_session_kill_channel(session_b, SWITCH_SIG_XFER);
+                       }
+               } else {
                        switch_core_session_kill_channel(session_b, SWITCH_SIG_KILL);
                        switch_channel_hangup(chan_b, SWITCH_CAUSE_NORMAL_CLEARING);
                }
                switch_channel_clear_flag(chan_a, CF_ORIGINATOR);
-       } else if (!switch_channel_test_flag(chan_a, CF_ORIGINATOR) && !switch_channel_test_flag(chan_a, CF_TRANSFER)) {
-               switch_core_session_kill_channel(session_a, SWITCH_SIG_KILL);
-               switch_channel_hangup(chan_a, SWITCH_CAUSE_NORMAL_CLEARING);
-       }
+       } 
        
        while (his_thread->running > 0) {
                his_thread->running = -1;
@@ -799,10 +804,26 @@ static void *audio_bridge_thread(switch_thread *thread, void *obj)
        }
 
        data->running = 0;              
-       switch_sleep(1000000);
        return NULL;
 }
 
+static switch_status audio_bridge_on_transmit(switch_core_session *session)
+{
+       switch_channel *channel = NULL;
+       void *arg;
+
+       channel = switch_core_session_get_channel(session);
+       assert(channel != NULL);
+
+       arg = switch_channel_get_private(channel);      
+       audio_bridge_thread(NULL, (void *) arg);
+       switch_channel_set_private(channel, NULL);      
+       switch_channel_clear_state_handler(channel, &audio_bridge_peer_state_handlers);
+
+       return SWITCH_STATUS_FALSE;
+}
+
+
 static switch_status audio_bridge_on_ring(switch_core_session *session)
 {
        switch_channel *channel = NULL;
@@ -814,7 +835,7 @@ static switch_status audio_bridge_on_ring(switch_core_session *session)
 
        /* put the channel in a passive state so we can loop audio to it */
        if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
-               switch_channel_set_state(channel, CS_TRANSMIT);
+               //switch_channel_set_state(channel, CS_TRANSMIT);
                return SWITCH_STATUS_FALSE;
        }
 
@@ -828,7 +849,7 @@ static const switch_state_handler_table audio_bridge_peer_state_handlers = {
        /*.on_execute */ NULL,
        /*.on_hangup */ NULL,
        /*.on_loopback */ NULL,
-       /*.on_transmit */ NULL
+       /*.on_transmit */ audio_bridge_on_transmit,
 };
 
 
@@ -876,12 +897,10 @@ SWITCH_DECLARE(switch_status) switch_ivr_multi_threaded_bridge(switch_core_sessi
        this_audio_thread.objs[5] = &other_audio_thread;
        this_audio_thread.running = 2;
 
-
-       switch_channel_set_private(caller_channel, peer_session);
-       switch_channel_set_private(peer_channel, session);
        switch_channel_add_state_handler(peer_channel, &audio_bridge_peer_state_handlers);
+
        if (switch_core_session_runing(peer_session)) {
-               switch_channel_set_state(peer_channel, CS_TRANSMIT);
+               switch_channel_set_state(peer_channel, CS_RING);
        } else {
                switch_core_session_thread_launch(peer_session);
        }
@@ -890,7 +909,7 @@ SWITCH_DECLARE(switch_status) switch_ivr_multi_threaded_bridge(switch_core_sessi
 
        for (;;) {
                int state = switch_channel_get_state(peer_channel);
-               if (state > CS_RING) {
+               if (state >= CS_RING) {
                        break;
                }
                
@@ -951,15 +970,17 @@ SWITCH_DECLARE(switch_status) switch_ivr_multi_threaded_bridge(switch_core_sessi
                switch_core_session_receive_message(peer_session, &msg);
                msg.pointer_arg = peer_session;
                switch_core_session_receive_message(session, &msg);
-               
-               
-               switch_core_session_launch_thread(peer_session, audio_bridge_thread, (void *) &other_audio_thread);
+
+               switch_channel_set_flag(peer_channel, CF_LOCK_THREAD);
+               switch_channel_set_private(peer_channel, &other_audio_thread);  
+               switch_channel_set_state(peer_channel, CS_TRANSMIT);
                audio_bridge_thread(NULL, (void *) &this_audio_thread);
 
                if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_UNBRIDGE) == SWITCH_STATUS_SUCCESS) {
                        switch_channel_event_set_data(caller_channel, event);
                        switch_event_fire(&event);
                }
+               switch_channel_clear_flag(peer_channel, CF_LOCK_THREAD);
        }
        return SWITCH_STATUS_SUCCESS;
 }