Author: anthm Date: Fri Mar 30 18:13:19 2007 New Revision: 4816 Modified: freeswitch/trunk/src/include/switch_channel.h freeswitch/trunk/src/include/switch_types.h freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c freeswitch/trunk/src/switch_channel.c freeswitch/trunk/src/switch_core_session.c freeswitch/trunk/src/switch_ivr.c freeswitch/trunk/src/switch_ivr_async.c freeswitch/trunk/src/switch_ivr_bridge.c Log: hold stuff Modified: freeswitch/trunk/src/include/switch_channel.h ============================================================================== --- freeswitch/trunk/src/include/switch_channel.h (original) +++ freeswitch/trunk/src/include/switch_channel.h Fri Mar 30 18:13:19 2007 @@ -259,6 +259,22 @@ 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's bridge partner + \param channel channel to derive the partner channel to set flag(s) on + \param flags or'd list of flags to set + \return true if the flag was set +*/ +SWITCH_DECLARE(switch_bool_t) switch_channel_set_flag_partner(switch_channel_t *channel, switch_channel_flag_t flags); + +/*! + \brief Clears given flag(s) on a given channel's bridge partner + \param channel channel to derive the partner channel to clear flag(s) from + \param flags the flags to clear + \return true if the flag was cleared +*/ +SWITCH_DECLARE(switch_bool_t) switch_channel_clear_flag_partner(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 Modified: freeswitch/trunk/src/include/switch_types.h ============================================================================== --- freeswitch/trunk/src/include/switch_types.h (original) +++ freeswitch/trunk/src/include/switch_types.h Fri Mar 30 18:13:19 2007 @@ -96,6 +96,7 @@ #endif #define SWITCH_URL_SEPARATOR "://" #define SWITCH_ENDPOINT_DISPOSITION_VARIABLE "endpoint_disposition" +#define SWITCH_HOLD_MUSIC_VARIABLE "hold_music" #define SWITCH_EXPORT_VARS_VARIABLE "export_vars" #define SWITCH_R_SDP_VARIABLE "switch_r_sdp" #define SWITCH_L_SDP_VARIABLE "switch_l_sdp" @@ -168,6 +169,7 @@ SMF_ECHO_ALEG = (1 << 1), SMF_ECHO_BLEG = (1 << 2), SMF_FORCE = (1 << 3), + SMF_LOOP = (1 << 4) } switch_media_flag_t; typedef enum { @@ -529,6 +531,8 @@ CF_REPEAT_STATE = (1 << 16) - Tell the state machine to repeat a state CF_GEN_RINGBACK = (1 << 17) - Channel is generating it's own ringback CF_RING_READY = (1 << 18) - Channel is ready to send ringback +CF_BREAK = (1 << 19) - Channel should stop what it's doing +CF_BROADCAST = (1 << 20) - Channel is broadcasting </pre> */ @@ -551,7 +555,9 @@ CF_EVENT_PARSE = (1 << 15), CF_REPEAT_STATE = (1 << 16), CF_GEN_RINGBACK = (1 << 17), - CF_RING_READY = (1 << 18) + CF_RING_READY = (1 << 18), + CF_BREAK = (1 << 19), + CF_BROADCAST = (1 << 20) } switch_channel_flag_t; Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c ============================================================================== --- freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c (original) +++ freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c Fri Mar 30 18:13:19 2007 @@ -90,7 +90,10 @@ "CREATE TABLE sip_registrations (\n" " user VARCHAR(255),\n" " host VARCHAR(255),\n" - " contact VARCHAR(1024),\n" " status VARCHAR(255),\n" " rpid VARCHAR(255),\n" " expires INTEGER(8)" ");\n"; + " contact VARCHAR(1024),\n" + " status VARCHAR(255),\n" + " rpid VARCHAR(255),\n" + " expires INTEGER(8)" ");\n"; static char sub_sql[] = @@ -102,13 +105,19 @@ " sub_to_host VARCHAR(255),\n" " event VARCHAR(255),\n" " contact VARCHAR(1024),\n" - " call_id VARCHAR(255),\n" " full_from VARCHAR(255),\n" " full_via VARCHAR(255),\n" " expires INTEGER(8)" ");\n"; + " call_id VARCHAR(255),\n" + " full_from VARCHAR(255),\n" + " full_via VARCHAR(255),\n" + " expires INTEGER(8)" ");\n"; static char auth_sql[] = "CREATE TABLE sip_authentication (\n" " user VARCHAR(255),\n" - " host VARCHAR(255),\n" " passwd VARCHAR(255),\n" " nonce VARCHAR(255),\n" " expires INTEGER(8)" + " host VARCHAR(255),\n" + " passwd VARCHAR(255),\n" + " nonce VARCHAR(255),\n" + " expires INTEGER(8)" ");\n"; static const char modname[] = "mod_sofia"; @@ -231,6 +240,7 @@ char *bindurl; char *sipdomain; char *timer_name; + char *hold_music; int sip_port; char *codec_string; int running; @@ -1024,7 +1034,7 @@ return SWITCH_STATUS_FALSE; } - + if ((alertbuf = switch_channel_get_variable(channel, "alert_info"))) { @@ -2418,10 +2428,29 @@ } for (a = sdp->sdp_attributes; a; a = a->a_next) { + if (switch_strlen_zero(a->a_name)) { + continue; + } if (!strcasecmp(a->a_name, "sendonly")) { - switch_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + if (!switch_test_flag(tech_pvt, TFLAG_SIP_HOLD)) { + char *stream; + + switch_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + switch_channel_set_flag(channel, CF_HOLD); + if (!(stream = switch_channel_get_variable(channel, SWITCH_HOLD_MUSIC_VARIABLE))) { + stream = tech_pvt->profile->hold_music; + } + if (stream) { + switch_ivr_broadcast(switch_core_session_get_uuid(tech_pvt->session), stream, SMF_ECHO_BLEG | SMF_LOOP); + } + } } else if (!strcasecmp(a->a_name, "sendrecv")) { - switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + if (switch_test_flag(tech_pvt, TFLAG_SIP_HOLD)) { + switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); + switch_channel_clear_flag(channel, CF_HOLD); + switch_channel_clear_flag_partner(channel, CF_BROADCAST); + switch_channel_set_flag_partner(channel, CF_BREAK); + } } else if (!strcasecmp(a->a_name, "ptime")) { dptime = atoi(a->a_value); } @@ -5135,6 +5164,8 @@ profile->sipdomain = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "rtp-timer-name")) { profile->timer_name = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "hold-music")) { + profile->hold_music = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "manage-presence")) { if (switch_true(val)) { profile->pflags |= PFLAG_PRESENCE; Modified: freeswitch/trunk/src/switch_channel.c ============================================================================== --- freeswitch/trunk/src/switch_channel.c (original) +++ freeswitch/trunk/src/switch_channel.c Fri Mar 30 18:13:19 2007 @@ -396,6 +396,42 @@ return switch_test_flag(channel, flags) ? 1 : 0; } +SWITCH_DECLARE(switch_bool_t) switch_channel_set_flag_partner(switch_channel_t *channel, switch_channel_flag_t flags) +{ + char *uuid; + + assert(channel != NULL); + + if ((uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE))) { + switch_core_session_t *session; + if ((session = switch_core_session_locate(uuid))) { + switch_channel_set_flag(switch_core_session_get_channel(session), flags); + switch_core_session_rwunlock(session); + return SWITCH_TRUE; + } + } + + return SWITCH_FALSE; +} + +SWITCH_DECLARE(switch_bool_t) switch_channel_clear_flag_partner(switch_channel_t *channel, switch_channel_flag_t flags) +{ + char *uuid; + + assert(channel != NULL); + + if ((uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE))) { + switch_core_session_t *session; + if ((session = switch_core_session_locate(uuid))) { + switch_channel_clear_flag(switch_core_session_get_channel(session), flags); + switch_core_session_rwunlock(session); + return SWITCH_TRUE; + } + } + + return SWITCH_FALSE; +} + SWITCH_DECLARE(void) switch_channel_set_flag(switch_channel_t *channel, switch_channel_flag_t flags) { assert(channel != NULL); @@ -431,9 +467,20 @@ SWITCH_DECLARE(uint8_t) switch_channel_ready(switch_channel_t *channel) { + uint8_t ret = 0; + assert(channel != NULL); + + if (!channel->hangup_cause && channel->state > CS_RING && channel->state < CS_HANGUP && !switch_test_flag(channel, CF_TRANSFER)) { + ret++; + } + + if (switch_test_flag(channel, CF_BREAK)) { + switch_clear_flag_locked(channel, CF_BREAK); + ret = (uint8_t) 0; + } - return (!channel->hangup_cause && channel->state > CS_RING && channel->state < CS_HANGUP && !switch_test_flag(channel, CF_TRANSFER)) ? 1 : 0; + return ret; } static const char *state_names[] = { Modified: freeswitch/trunk/src/switch_core_session.c ============================================================================== --- freeswitch/trunk/src/switch_core_session.c (original) +++ freeswitch/trunk/src/switch_core_session.c Fri Mar 30 18:13:19 2007 @@ -599,6 +599,7 @@ switch_channel_dequeue_dtmf(channel, buf, sizeof(buf)); } + switch_channel_clear_flag(channel, CF_BREAK); } Modified: freeswitch/trunk/src/switch_ivr.c ============================================================================== --- freeswitch/trunk/src/switch_ivr.c (original) +++ freeswitch/trunk/src/switch_ivr.c Fri Mar 30 18:13:19 2007 @@ -108,11 +108,25 @@ const switch_application_interface_t *application_interface; char *app_name = switch_event_get_header(event, "execute-app-name"); char *app_arg = switch_event_get_header(event, "execute-app-arg"); + char *loop_h = switch_event_get_header(event, "loops"); + int loops = 0; + + if (loop_h) { + loops = atoi(loop_h); + } if (app_name && app_arg) { if ((application_interface = switch_loadable_module_get_application_interface(app_name))) { if (application_interface->application_function) { - application_interface->application_function(session, app_arg); + int x; + switch_channel_set_flag(channel, CF_BROADCAST); + for (x = 0; x < loops || loops < 0; x++) { + application_interface->application_function(session, app_arg); + if (!switch_channel_test_flag(channel, CF_BROADCAST)) { + break; + } + } + switch_channel_clear_flag(channel, CF_BROADCAST); } } } Modified: freeswitch/trunk/src/switch_ivr_async.c ============================================================================== --- freeswitch/trunk/src/switch_ivr_async.c (original) +++ freeswitch/trunk/src/switch_ivr_async.c Fri Mar 30 18:13:19 2007 @@ -737,8 +737,13 @@ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "call-command", "execute"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-name", "%s", app); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-arg", "%s", path); + if ((flags & SMF_LOOP)) { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "loops", "%d", -1); + } + switch_core_session_queue_private_event(other_session, &event); } + switch_core_session_rwunlock(other_session); master = other_session; other_session = NULL; @@ -749,6 +754,9 @@ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "call-command", "execute"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-name", "%s", app); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-arg", "%s", path); + if ((flags & SMF_LOOP)) { + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "loops", "%d", -1); + } switch_core_session_queue_private_event(session, &event); } master = session; Modified: freeswitch/trunk/src/switch_ivr_bridge.c ============================================================================== --- freeswitch/trunk/src/switch_ivr_bridge.c (original) +++ freeswitch/trunk/src/switch_ivr_bridge.c Fri Mar 30 18:13:19 2007 @@ -81,11 +81,22 @@ switch_channel_set_flag(chan_a, CF_BRIDGED); - while (switch_channel_ready(chan_a) && data->running > 0 && his_thread->running > 0) { - switch_channel_state_t b_state = switch_channel_get_state(chan_b); + for (;;) { + switch_channel_state_t b_state; switch_status_t status; switch_event_t *event; + if (!(data->running > 0 && his_thread->running > 0)) { + break; + } + + /* if you really want to make sure it's not ready, test it twice because it might be just a break */ + if (!switch_channel_ready(chan_a) && !switch_channel_ready(chan_a)) { + break; + } + + b_state = switch_channel_get_state(chan_b); + switch (b_state) { case CS_HANGUP: case CS_DONE: