From ba6b7651b2df154b0b41f70fa71cdceba6c0b3b2 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 25 Apr 2006 18:02:12 +0000 Subject: [PATCH] improve bridge code git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@1251 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- src/include/switch_channel.h | 7 +++++ src/include/switch_types.h | 11 ++++++-- src/switch_channel.c | 20 +++++++++++++ src/switch_core.c | 7 +++++ src/switch_ivr.c | 55 +++++++++++++++++++++++++----------- 5 files changed, 80 insertions(+), 20 deletions(-) diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index 986ed23aaf..f65defe179 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -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 diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 76eacc68ee..8f668fbdd2 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -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 */ @@ -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
 SWITCH_SIG_KILL - Kill the channel
+SWITCH_SIG_XFER - Stop the current io but leave it viable
 
*/ typedef enum { - SWITCH_SIG_KILL + SWITCH_SIG_NONE, + SWITCH_SIG_KILL, + SWITCH_SIG_XFER } switch_signal; /*! diff --git a/src/switch_channel.c b/src/switch_channel.c index 90a91b7760..e9389e3f9f 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -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) { diff --git a/src/switch_core.c b/src/switch_core.c index 4abc785077..b02b31531b 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -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); diff --git a/src/switch_ivr.c b/src/switch_ivr.c index 359ec4eed0..a4b9f74e52 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -32,6 +32,8 @@ #include #include +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; }