]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
*deep breath*
authorAnthony Minessale <anthony.minessale@gmail.com>
Thu, 17 Aug 2006 00:53:09 +0000 (00:53 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Thu, 17 Aug 2006 00:53:09 +0000 (00:53 +0000)
Ok,

This one adds a bunch of stuff on top of the framework restructuring from yesterday.

1) originate api function:
Usage: originate <call url> <exten> [<dialplan>] [<context>] [<cid_name>] [<cid_num>] [<timeout_sec>]

This will call the specified url then transfer the call to the specified extension

example: originate exosip/1000@somehost 1000 XML default

2) mutiple destinations in outbound calls:

This means any dialstring may contain an '&' separated list of call urls
When using mutiple urls in this manner it is possible to map a certian key as required
indication of an accepted call.  You may also supply a filename to play possibly instructing the
call recipiant to press the desired key etc...

The example below will call 2 locations playing prompt.wav to any who answer and
completing the call to the first offhook recipiant to dial "4"

      <extension name="3002">
        <condition field="destination_number" expression="^3002$">
          <action application="set" data="call_timeout=60"/>
          <action application="set" data="group_confirm_file=/path/to/prompt.wav"/>
          <action application="set" data="group_confirm_key=4"/>
          <action application="bridge" data="iax/guest@somebox/1234&exosip/1000@somehost"/>
        </condition>
      </extension>

The following is the equivilant but the confirm data is passed vial the bridge parameters
(This is for situations where there is no originating channel to set variables to)

      <extension name="3002">
        <condition field="destination_number" expression="^3002$">
          <action application="bridge" data=/path/to/prompt.wav:4"confirm=iax/guest@somebox/1234&exosip/1000@somehost"/>
        </condition>
      </extension>

Omitting the file and key stuff will simply comeplete the call to whoever answers first.
(this is similar to how other less fortunate software handles the situation with thier best effort.)

This logic should be permitted in anything that establishes an outgoing call with
switch_ivr_originate()

Yes! That means even in this new originate api command you can call mutiple targets and send
whoever answers first to an extension that calls more mutiple targets.  (better test it though!)

Oh, and you should be able to do the same in the mod_conference dial and dynamic conference features

please report any behaviour contrary to this account to me ASAP cos i would not be terribly
suprised if I forgot some scenerio that causes an explosion I did all this in 1 afternoon so it probably needs tuning still.

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

src/include/switch_ivr.h
src/include/switch_types.h
src/mod/applications/mod_bridgecall/mod_bridgecall.c
src/mod/applications/mod_commands/mod_commands.c
src/mod/applications/mod_conference/mod_conference.c
src/mod/languages/mod_spidermonkey/mod_spidermonkey.c
src/switch_channel.c
src/switch_ivr.c
src/switch_utils.c

index 72840a4a4e94abbdda1b5e3a4e686ea42fd88d0c..381cad1b859c44c3a34d0937a337cc7e757b0ebf 100644 (file)
@@ -169,6 +169,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text(switch_core_session_t *ses
   \param session originating session
   \param bleg B leg session
   \param bridgeto the desired remote callstring
+  \param timelimit_sec timeout in seconds for outgoing call
   \param table optional state handler table to install on the channel
   \param cid_name_override override the caller id name
   \param cid_num_override override the caller id number
@@ -177,6 +178,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text(switch_core_session_t *ses
 SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *session,
                                                                                                         switch_core_session_t **bleg,
                                                                                                         char *bridgeto,
+                                                                                                        uint32_t timelimit_sec,
                                                                                                         const switch_state_handler_table_t *table,
                                                                                                         char *cid_name_override,
                                                                                                         char *cid_num_override);
@@ -185,18 +187,16 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
   \brief Bridge Audio from one session to another
   \param session one session
   \param peer_session the other session
-  \param timelimit maximum number of seconds to wait for both channels to be answered
   \param dtmf_callback code to execute if any dtmf is dialed during the bridge
   \param session_data data to pass to the DTMF callback for session
   \param peer_session_data data to pass to the DTMF callback for peer_session
   \return SWITCH_STATUS_SUCCESS if all is well
 */
 SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_session_t *session, 
-                                                                                                                          switch_core_session_t *peer_session,
-                                                                                                                          unsigned int timelimit,
-                                                                                                                          switch_input_callback_function_t dtmf_callback,
-                                                                                                                          void *session_data,
-                                                                                                                          void *peer_session_data);
+                                                                                                                                switch_core_session_t *peer_session,
+                                                                                                                                switch_input_callback_function_t dtmf_callback,
+                                                                                                                                void *session_data,
+                                                                                                                                void *peer_session_data);
 
 
 /*!
index 46d5fc61d39d575eface8bca20c94184e10f1014..405656d1d2e5fee49eed335093a59465decce59e 100644 (file)
@@ -355,6 +355,8 @@ CF_LOCK_THREAD      = (1 <<  6) - Prevent the channel thread from exiting while this
 CF_BRIDGED             = (1 <<  7) - Channel in a bridge
 CF_HOLD                        = (1 <<  8) - Channel is on hold
 CF_SERVICE             = (1 <<  9) - Channel has a service thread
+CF_TAGGED              = (1 << 10) - Channel is tagged
+CF_WINNER              = (1 << 10) - Channel is the winner
 </pre>
  */
 
@@ -368,7 +370,9 @@ typedef enum {
        CF_LOCK_THREAD  = (1 <<  6),
        CF_BRIDGED              = (1 <<  7),
        CF_HOLD                 = (1 <<  8),
-       CF_SERVICE              = (1 <<  9)
+       CF_SERVICE              = (1 <<  9),
+       CF_TAGGED               = (1 << 10),
+       CF_WINNER               = (1 << 11)
 } switch_channel_flag_t;
 
 
@@ -636,7 +640,8 @@ typedef enum {
        SWITCH_CAUSE_PROTOCOL_ERROR = 111,
        SWITCH_CAUSE_INTERWORKING = 127,
        SWITCH_CAUSE_CRASH = 500,
-       SWITCH_CAUSE_SYSTEM_SHUTDOWN = 501
+       SWITCH_CAUSE_SYSTEM_SHUTDOWN = 501,
+       SWITCH_CAUSE_LOSE_RACE = 502
 } switch_call_cause_t;
 
 
index c1e2f76a738caf492cf79121cadb300be164e751..8192cce3a7b64b7e1038265dd87cd0caf470c41c 100644 (file)
@@ -40,18 +40,23 @@ static void audio_bridge_function(switch_core_session_t *session, char *data)
 {
        switch_channel_t *caller_channel;
        switch_core_session_t *peer_session;
-       unsigned int timelimit = 60; /* probably a useful option to pass in when there's time */
+       unsigned int timelimit = 60;
+       char *var;
 
        caller_channel = switch_core_session_get_channel(session);
        assert(caller_channel != NULL);
 
-       if (switch_ivr_originate(session, &peer_session, data, NULL, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
+       if ((var = switch_channel_get_variable(caller_channel, "call_timeout"))) {
+               timelimit = atoi(var);
+       }
+
+       if (switch_ivr_originate(session, &peer_session, data, timelimit, NULL, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Create Outgoing Channel!\n");
                switch_channel_hangup(caller_channel, SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL);
                return;
        } else {
                /* peer channel is read locked now the bridge func will unlock it for us */
-               switch_ivr_multi_threaded_bridge(session, peer_session, timelimit, NULL, NULL, NULL);
+               switch_ivr_multi_threaded_bridge(session, peer_session, NULL, NULL, NULL);
        }
 }
 
index fec1d62191ff5acb8e99f7d654040bdd3cf9572c..cd7424fda11d72604f95130a9fc95e115a79dc6e 100644 (file)
@@ -209,6 +209,72 @@ static switch_status_t pause_function(char *cmd, switch_core_session_t *isession
        return SWITCH_STATUS_SUCCESS;
 }
 
+static switch_status_t originate_function(char *cmd, switch_core_session_t *isession, switch_stream_handle_t *stream)
+{
+       switch_channel_t *caller_channel;
+       switch_core_session_t *caller_session;
+       char *argv[7] = {0};
+       int x, argc = 0;
+       char *aleg, *exten, *dp, *context, *cid_name, *cid_num;
+       uint32_t timeout = 60;
+
+       if (isession) {
+               stream->write_function(stream, "Illegal Usage\n");
+               return SWITCH_STATUS_SUCCESS;
+       }
+
+       if (switch_strlen_zero(cmd)) {
+               stream->write_function(stream, "Usage: originate <call url> <exten> [<dialplan>] [<context>] [<cid_name>] [<cid_num>] [<timeout_sec>]\n");
+               return SWITCH_STATUS_SUCCESS;
+       }
+
+       argc = switch_separate_string(cmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+
+       for(x = 0; x < argc; x++) {
+               if (!strcasecmp(argv[x], "undef")) {
+                       argv[x] = NULL;
+               }
+       }
+
+       aleg = argv[0];
+       exten = argv[1];
+       dp = argv[2];
+       context = argv[3];
+       cid_name = argv[4];
+       cid_num = argv[5];
+       
+       if (!dp) {
+               dp = "XML";
+       }
+
+       if (!context) {
+               context = "default";
+       }
+
+       if (argv[6]) {
+               timeout = atoi(argv[6]);
+       }
+
+       if (!aleg && exten) {
+               stream->write_function(stream, "Invalid Arguements\n");
+               return SWITCH_STATUS_SUCCESS;
+       }
+
+       if (switch_ivr_originate(NULL, &caller_session, aleg, timeout, NULL, cid_name, cid_num) != SWITCH_STATUS_SUCCESS) {
+               stream->write_function(stream, "Cannot Create Outgoing Channel! [%s]\n", aleg);
+               return SWITCH_STATUS_SUCCESS;
+       } 
+
+       caller_channel = switch_core_session_get_channel(caller_session);
+       assert(caller_channel != NULL);
+       switch_channel_clear_state_handler(caller_channel, NULL);
+       switch_core_session_rwunlock(caller_session);
+
+       switch_ivr_session_transfer(caller_session, exten, dp, context);
+
+       return SWITCH_STATUS_SUCCESS;;
+}
+
 struct holder {
        switch_stream_handle_t *stream;
        char *http;
@@ -349,7 +415,7 @@ static switch_api_interface_t transfer_api_interface = {
 
 static switch_api_interface_t load_api_interface = {
        /*.interface_name */ "load",
-       /*.desc */ "Load Modile",
+       /*.desc */ "Load Module",
        /*.function */ load_function,
        /*.next */ &transfer_api_interface
 };
@@ -369,6 +435,14 @@ static switch_api_interface_t commands_api_interface = {
        /*.next */ &reload_api_interface
 };
 
+static switch_api_interface_t originate_api_interface = {
+       /*.interface_name */ "originate",
+       /*.desc */ "Originate a Call",
+       /*.function */ originate_function,
+       /*.next */ &commands_api_interface
+};
+
+
 static const switch_loadable_module_interface_t mod_commands_module_interface = {
        /*.module_name */ modname,
        /*.endpoint_interface */ NULL,
@@ -376,7 +450,7 @@ static const switch_loadable_module_interface_t mod_commands_module_interface =
        /*.dialplan_interface */ NULL,
        /*.codec_interface */ NULL,
        /*.application_interface */ NULL,
-       /*.api_interface */ &commands_api_interface
+       /*.api_interface */ &originate_api_interface
 };
 
 
index aeb0d74bd411b6b71cd83d1e00f619ea72a81d67..2648b3e4803e42a4335ae908ce5c23a404182567 100644 (file)
@@ -192,7 +192,12 @@ static switch_status_t conference_say(conference_obj_t *conference, char *text,
 static void conference_list(conference_obj_t *conference, switch_stream_handle_t *stream, char *delim);
 static switch_status_t conf_function(char *buf, switch_core_session_t *session, switch_stream_handle_t *stream);
 static switch_status_t audio_bridge_on_ring(switch_core_session_t *session);
-static switch_status_t conference_outcall(conference_obj_t *conference, switch_core_session_t *session, char *bridgeto, char *cid_name, char *cid_num);
+static switch_status_t conference_outcall(conference_obj_t *conference,
+                                                                                 switch_core_session_t *session,
+                                                                                 char *bridgeto,
+                                                                                 uint32_t timeout,
+                                                                                 char *cid_name,
+                                                                                 char *cid_num);
 static void conference_function(switch_core_session_t *session, char *data);
 static void launch_conference_thread(conference_obj_t *conference);
 static void *SWITCH_THREAD_FUNC input_thread_run(switch_thread_t *thread, void *obj);
@@ -1387,7 +1392,7 @@ static switch_status_t conf_function(char *buf, switch_core_session_t *session,
                                        goto done;
                                } else if (!strcasecmp(argv[1], "dial")) {
                                        if (argc > 2) {
-                                               conference_outcall(conference, NULL, argv[2], argv[3], argv[4]);
+                                               conference_outcall(conference, NULL, argv[2], 60, argv[3], argv[4]);
                                                stream->write_function(stream, "OK\n");
                                                goto done;
                                        } else {
@@ -1971,7 +1976,12 @@ static const switch_state_handler_table_t audio_bridge_peer_state_handlers = {
        /*.on_hold */ NULL,
 };
 
-static switch_status_t conference_outcall(conference_obj_t *conference, switch_core_session_t *session, char *bridgeto, char *cid_name, char *cid_num)
+static switch_status_t conference_outcall(conference_obj_t *conference,
+                                                                                 switch_core_session_t *session,
+                                                                                 char *bridgeto,
+                                                                                 uint32_t timeout,
+                                                                                 char *cid_name,
+                                                                                 char *cid_num)
 {
        switch_core_session_t *peer_session;
        switch_channel_t *peer_channel;
@@ -1979,7 +1989,7 @@ static switch_status_t conference_outcall(conference_obj_t *conference, switch_c
        switch_channel_t *caller_channel = NULL;
 
 
-       if (switch_ivr_originate(session, &peer_session, bridgeto, &audio_bridge_peer_state_handlers, cid_name, cid_num) != SWITCH_STATUS_SUCCESS) {
+       if (switch_ivr_originate(session, &peer_session, bridgeto, timeout, &audio_bridge_peer_state_handlers, cid_name, cid_num) != SWITCH_STATUS_SUCCESS) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Create Outgoing Channel!\n");
                if (session) {
                        caller_channel = switch_core_session_get_channel(session);
@@ -2172,7 +2182,11 @@ static void conference_function(switch_core_session_t *session, char *data)
 
                        if (strlen(pin) < strlen(conference->pin)) {
                                buf = pin + strlen(pin);
-                               switch_ivr_collect_digits_count(session, buf, sizeof(pin) - (unsigned int)strlen(pin), (unsigned int)strlen(conference->pin) - (unsigned int)strlen(pin), "#", &term, 10000);
+                               switch_ivr_collect_digits_count(session,
+                                                                                               buf,
+                                                                                               sizeof(pin) - (unsigned int)strlen(pin),
+                                                                                               (unsigned int)strlen(conference->pin) - (unsigned int)strlen(pin),
+                                                                                               "#", &term, 10000);
                        }
 
                        if (strcmp(pin, conference->pin)) {
@@ -2196,7 +2210,7 @@ static void conference_function(switch_core_session_t *session, char *data)
        }
 
        if (bridgeto) {
-               if (conference_outcall(conference, session, bridgeto, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
+               if (conference_outcall(conference, session, bridgeto, 60, NULL, NULL) != SWITCH_STATUS_SUCCESS) {
                        goto done;
                }
        }
index 4ebf9521dd8fedc76659fba83c704c2312f6895e..72acdea955b2efb8aa1efced048c5e7e7786b991 100644 (file)
@@ -1903,7 +1903,7 @@ static JSBool js_bridge(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, j
                return JS_FALSE;
        }
 
-       switch_ivr_multi_threaded_bridge(jss_a->session, jss_b->session, timelimit, NULL, NULL, NULL);
+       switch_ivr_multi_threaded_bridge(jss_a->session, jss_b->session, NULL, NULL, NULL);
        return JS_TRUE;
 }
 
index 01d5d7c69f300f3f0964de89f0bf6c7e8fd1cab7..374fff3f2767bc1fa33b2391b9021d2d0c018670 100644 (file)
@@ -84,6 +84,7 @@ static struct switch_cause_table CAUSE_CHART[] = {
        { "INTERWORKING", SWITCH_CAUSE_INTERWORKING },
        { "CRASH", SWITCH_CAUSE_CRASH },
        { "SYSTEM_SHUTDOWN", SWITCH_CAUSE_SYSTEM_SHUTDOWN },
+       { "LOSE_RACE", SWITCH_CAUSE_LOSE_RACE },
        { NULL, 0 }
 };
 
@@ -798,17 +799,20 @@ SWITCH_DECLARE(void) switch_channel_clear_state_handler(switch_channel_t *channe
 
        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];
+       if (state_handler) {
+               for (index = 0; index < channel->state_handler_index; index++) {
+                       if (channel->state_handlers[index] != state_handler) {
+                               new_handlers[i++] = channel->state_handlers[index];
+                       }
                }
        }
        for (index = 0; index < SWITCH_MAX_STATE_HANDLERS; index++) {
                channel->state_handlers[index] = NULL;
        }
-       for (index = 0; index < i; index++) {
-               channel->state_handlers[index] = new_handlers[i];
+       if (state_handler) {
+               for (index = 0; index < i; index++) {
+                       channel->state_handlers[index] = new_handlers[i];
+               }
        }
 
 }
index 39c8dc3ec4bd10a0b5cf63803f3f9b7be0a60c1a..33c5671ab0fb2e2d1ffaac9cbeeb11481463bcea 100644 (file)
@@ -541,7 +541,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess
 
                if (fh->speed > 2) {
                        fh->speed = 2;
-               } else if(fh->speed < -2) {
+               } else if (fh->speed < -2) {
                        fh->speed = -2;
                }
                
@@ -1140,131 +1140,344 @@ static const switch_state_handler_table_t audio_bridge_peer_state_handlers = {
        /*.on_hold */ audio_bridge_on_hold,
 };
 
+struct key_collect {
+       char *key;
+       char *file;
+       switch_core_session_t *session;
+};
+
 
+static void *SWITCH_THREAD_FUNC collect_thread_run(switch_thread_t *thread, void *obj)
+{
+       struct key_collect *collect = (struct key_collect *) obj;
+       switch_channel_t *channel = switch_core_session_get_channel(collect->session);
+       char buf[10] = "";
+       char *p, term;
+
+       while(switch_channel_ready(channel)) {
+               memset(buf, 0, sizeof(buf));
 
+               if (collect->file) {
+                       switch_ivr_play_file(collect->session, NULL, collect->file, NULL, NULL, buf, sizeof(buf));
+               } else {
+                       switch_ivr_collect_digits_count(collect->session, buf, sizeof(buf), 1, "", &term, 0);
+               }
+
+               for(p = buf; *p; p++) {
+                       if (*collect->key == *p) {
+                               switch_channel_set_flag(channel, CF_WINNER);
+                               goto wbreak;
+                       }
+               }
+       }
+ wbreak:
+
+       return NULL;
+}
+
+static void launch_collect_thread(struct key_collect *collect)
+{
+       switch_thread_t *thread;
+       switch_threadattr_t *thd_attr = NULL;
+       
+       switch_threadattr_create(&thd_attr, switch_core_session_get_pool(collect->session));
+       switch_threadattr_detach_set(thd_attr, 1);
+       switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
+       switch_thread_create(&thread, thd_attr, collect_thread_run, collect, switch_core_session_get_pool(collect->session));
+}
+
+static uint8_t check_channel_status(switch_channel_t **peer_channels,
+                                                                       switch_core_session_t **peer_sessions,
+                                                                       uint32_t len,
+                                                                       int32_t *idx,
+                                                                       char *file,
+                                                                       char *key)
+{
+
+       int32_t i;
+       *idx = -1;
+       
+       if (len == 1) {
+               *idx = 0;
+               return (switch_channel_get_state(peer_channels[0]) < CS_HANGUP &&
+                               !switch_channel_test_flag(peer_channels[0], CF_ANSWERED) &&
+                               !switch_channel_test_flag(peer_channels[0], CF_EARLY_MEDIA)) ? 1 : 0;
+       } else {
+               int32_t hups = 0;
+
+               for (i = 0; i < len; i++) {
+                       if (!peer_channels[i]) {
+                               continue;
+                       }
+                       if (switch_channel_get_state(peer_channels[i]) >= CS_HANGUP) {
+                               hups++;
+                       } else if (switch_channel_test_flag(peer_channels[i], CF_ANSWERED) && !switch_channel_test_flag(peer_channels[i], CF_TAGGED)) {
+
+                               if (key) {
+                                       struct key_collect *collect;
+
+                                       if ((collect = switch_core_session_alloc(peer_sessions[i], sizeof(*collect)))) {
+                                               switch_channel_set_flag(peer_channels[i], CF_TAGGED);
+                                               collect->key = key;
+                                               if (file) {
+                                                       collect->file = switch_core_session_strdup(peer_sessions[i], file);
+                                               }
+                                               collect->session = peer_sessions[i];
+                                               launch_collect_thread(collect);
+                                       }
+                               } else {
+                                       *idx = i;
+                    return 0;
+                                       
+                               }
+                       } else if (switch_channel_test_flag(peer_channels[i], CF_WINNER)) {
+                               *idx = i;
+                               return 0;
+                       }
+               }
+
+               if (hups == len) {
+                       return 0;
+               } else {
+                       return 1;
+               }
+       }
+}
+
+#define MAX_PEERS 256
 SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *session,
                                                                                                         switch_core_session_t **bleg,
                                                                                                         char *bridgeto,
+                                                                                                        uint32_t timelimit_sec,
                                                                                                         const switch_state_handler_table_t *table,
                                                                                                         char *cid_name_override,
                                                                                                         char *cid_num_override)
                                                                                  
 {
-       switch_core_session_t *peer_session;
-       switch_caller_profile_t *caller_profile, *caller_caller_profile;
-       char *chan_type, *chan_data;
-       unsigned int timelimit = 60;
-       switch_channel_t *peer_channel;
+       char *peer_names[MAX_PEERS];
+       switch_core_session_t *peer_session, *peer_sessions[MAX_PEERS];
+       switch_caller_profile_t *caller_profiles[MAX_PEERS], *caller_caller_profile;
+       char *chan_type = NULL, *chan_data;
+       switch_channel_t *peer_channel = NULL, *peer_channels[MAX_PEERS];
        time_t start;
        switch_frame_t *read_frame = NULL;
        switch_status_t status = SWITCH_STATUS_SUCCESS;
        switch_channel_t *caller_channel = NULL;
+       switch_memory_pool_t *pool;
+       char *data = NULL;
+       int i, argc;
+       int32_t idx = -1, ccount = 0;
+       switch_codec_t write_codec = {0};
+       switch_frame_t write_frame = {0};
+       uint8_t err = 0, fdata[1024];
+       char *file = NULL, *key = NULL, *odata, *var;
 
+       write_frame.data = fdata;
+       
        *bleg = NULL;
-       chan_type = strdup(bridgeto);
-               
-       if ((chan_data = strchr(chan_type, '/')) != 0) {
-               *chan_data = '\0';
-               chan_data++;
+       odata = strdup(bridgeto);
+       data = odata;
+
+       if (!strncasecmp(data, "confirm=", 8)) {
+               data += 8;
+               file = data;
+               if ((data = strchr(file, ';'))) {
+                       *data++ = '\0';
+                       if ((key = strchr(file, ':'))) {
+                               *key++ = '\0';
+                       } else {
+                               err++;
+                       }
+               } else {
+                       err++;
+               }
+       }
+
+       if (err) {
+               status = SWITCH_STATUS_GENERR;
+               goto done;
        }
        
        if (session) {
                caller_channel = switch_core_session_get_channel(session);
                assert(caller_channel != NULL);
-               caller_caller_profile = switch_channel_get_caller_profile(caller_channel);
 
-               if (!cid_name_override) {
-                       cid_name_override = caller_caller_profile->caller_id_name;
-               }
-               if (!cid_num_override) {
-                       cid_num_override = caller_caller_profile->caller_id_number;
-               }
 
-               caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session),
-                                                                                                  caller_caller_profile->username,
-                                                                                                  caller_caller_profile->dialplan,
-                                                                                                  cid_name_override,
-                                                                                                  cid_num_override,
-                                                                                                  caller_caller_profile->network_addr, 
-                                                                                                  NULL,
-                                                                                                  NULL, 
-                                                                                                  caller_caller_profile->rdnis,
-                                                                                                  caller_caller_profile->source,
-                                                                                                  caller_caller_profile->context,
-                                                                                                  chan_data);
-       } else {
-               if (!cid_name_override) {
-                       cid_name_override = "FreeSWITCH";
-               }
-               if (!cid_num_override) {
-                       cid_num_override = "0000000000";
+
+               if ((var = switch_channel_get_variable(caller_channel, "group_confirm_key"))) {
+                       key = switch_core_session_strdup(session, var);
+                       if ((var = switch_channel_get_variable(caller_channel, "group_confirm_file"))) {
+                               file = switch_core_session_strdup(session, var);
+                       }
                }
-               caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session),
-                                                                                                  NULL,
-                                                                                                  NULL,
-                                                                                                  cid_name_override,
-                                                                                                  cid_num_override,
-                                                                                                  NULL,
-                                                                                                  NULL, 
-                                                                                                  NULL, 
-                                                                                                  NULL,
-                                                                                                  __FILE__,
-                                                                                                  NULL,
-                                                                                                  chan_data);
        }
+       
 
 
+       if (file && !strcmp(file, "undef")) {
+               file = NULL;
+       }
 
-       if (switch_core_session_outgoing_channel(session, chan_type, caller_profile, &peer_session, NULL) != SWITCH_STATUS_SUCCESS) {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Create Outgoing Channel!\n");
-               status = SWITCH_STATUS_FALSE;
-               goto done;
-       } 
+       argc = switch_separate_string(data, '&', peer_names, (sizeof(peer_names) / sizeof(peer_names[0])));
+       
+       for (i = 0; i < argc; i++) {
+               
+               chan_type = peer_names[i];
+               if ((chan_data = strchr(chan_type, '/')) != 0) {
+                       *chan_data = '\0';
+                       chan_data++;
+               }
+       
+               if (session) {
+                       if (!switch_channel_ready(caller_channel)) {
+                               status = SWITCH_STATUS_FALSE;
+                               goto done;
+                       }
 
-       switch_core_session_read_lock(peer_session);
+                       caller_caller_profile = switch_channel_get_caller_profile(caller_channel);
 
-       peer_channel = switch_core_session_get_channel(peer_session);
-       assert(peer_channel != NULL);
+                       if (!cid_name_override) {
+                               cid_name_override = caller_caller_profile->caller_id_name;
+                       }
+                       if (!cid_num_override) {
+                               cid_num_override = caller_caller_profile->caller_id_number;
+                       }
+
+                       caller_profiles[i] = switch_caller_profile_new(switch_core_session_get_pool(session),
+                                                                                                                  caller_caller_profile->username,
+                                                                                                                  caller_caller_profile->dialplan,
+                                                                                                                  cid_name_override,
+                                                                                                                  cid_num_override,
+                                                                                                                  caller_caller_profile->network_addr, 
+                                                                                                                  NULL,
+                                                                                                                  NULL, 
+                                                                                                                  caller_caller_profile->rdnis,
+                                                                                                                  caller_caller_profile->source,
+                                                                                                                  caller_caller_profile->context,
+                                                                                                                  chan_data);
+                       pool = NULL;
+               } else {
+                       if (!cid_name_override) {
+                               cid_name_override = "FreeSWITCH";
+                       }
+                       if (!cid_num_override) {
+                               cid_num_override = "0000000000";
+                       }
+
+                       if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OH OH no pool\n");
+                               status = SWITCH_STATUS_TERM;
+                               goto done;
+                       }
+
+                       caller_profiles[i] = switch_caller_profile_new(pool,
+                                                                                                                  NULL,
+                                                                                                                  NULL,
+                                                                                                                  cid_name_override,
+                                                                                                                  cid_num_override,
+                                                                                                                  NULL,
+                                                                                                                  NULL, 
+                                                                                                                  NULL,
+                                                                                                                  NULL,
+                                                                                                                  __FILE__,
+                                                                                                                  NULL,
+                                                                                                                  chan_data);
+               }
+
+
+               if (switch_core_session_outgoing_channel(session, chan_type, caller_profiles[i], &peer_sessions[i], pool) != SWITCH_STATUS_SUCCESS) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Create Outgoing Channel!\n");
+                       if (pool) {
+                               switch_core_destroy_memory_pool(&pool);
+                       }
+                       caller_profiles[i] = NULL;
+                       peer_channels[i] = NULL;
+                       peer_sessions[i] = NULL;
+                       continue;
+               } 
+               pool = NULL;
+       
+               peer_channels[i] = switch_core_session_get_channel(peer_sessions[i]);
+               assert(peer_channels[i] != NULL);
                
-       if (!table) {
-               table = &audio_bridge_peer_state_handlers;
-       }
+               if (!table) {
+                       table = &audio_bridge_peer_state_handlers;
+               }
 
-       switch_channel_add_state_handler(peer_channel, table);
+               switch_channel_add_state_handler(peer_channels[i], table);
 
-       if (switch_core_session_runing(peer_session)) {
-               switch_channel_set_state(peer_channel, CS_RING);
-       } else {
-               switch_core_session_thread_launch(peer_session);
+               if (switch_core_session_runing(peer_sessions[i])) {
+                       switch_channel_set_state(peer_channels[i], CS_RING);
+               } else {
+                       switch_core_session_thread_launch(peer_sessions[i]);
+               }
        }
 
        time(&start);
+       for (i = 0; i < argc; i++) {
+               if (peer_channels[i]) {
+                       ccount++;
+               }
+       }
+       
+       if (ccount == 1) {
+               key = file = NULL;
+       }
 
        for (;;) {
-               int state = switch_channel_get_state(peer_channel);
-               if (state >= CS_RING) {
-                       break;
-               }
+               for (i = 0; i < argc; i++) {
+                       int state;
+
+                       if (!peer_channels[i]) {
+                               continue;
+                       }
+
+                       state = switch_channel_get_state(peer_channels[i]);
+
+                       if (state >= CS_RING) {
+                               goto endfor1;
+                       }
                
-               if (caller_channel && !switch_channel_ready(caller_channel)) {
-                       break;
-               }
+                       if (caller_channel && !switch_channel_ready(caller_channel)) {
+                               break;
+                       }
                
-               if ((time(NULL) - start) > (time_t)timelimit) {
-                       break;
+                       if ((time(NULL) - start) > (time_t)timelimit_sec) {
+                               break;
+                       }
+                       switch_yield(1000);
                }
-               switch_yield(1000);
        }
+ endfor1:
 
-       if (caller_channel) {
+       if (session) {
+               switch_codec_t *read_codec = switch_core_session_get_read_codec(session);
                switch_channel_pre_answer(caller_channel);
-       }
 
-       while ((!caller_channel || switch_channel_ready(caller_channel)) &&
-                  !switch_channel_test_flag(peer_channel, CF_ANSWERED) &&
-                  !switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA) &&
-                  ((time(NULL) - start) < (time_t)timelimit)) {
+               if (switch_core_codec_init(&write_codec,
+                                                                  "L16",
+                                                                  read_codec->implementation->samples_per_second,
+                                                                  read_codec->implementation->microseconds_per_frame / 1000,
+                                                                  1,
+                                                                  SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+                                                                  NULL,
+                                                                  pool) == SWITCH_STATUS_SUCCESS) {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Raw Codec Activation Success L16@%uhz 1 channel %dms\n",
+                                                         read_codec->implementation->samples_per_second,
+                                                         read_codec->implementation->microseconds_per_frame / 1000);
+                       write_frame.codec = &write_codec;
+                       write_frame.datalen = read_codec->implementation->bytes_per_frame;
+                       write_frame.samples = write_frame.datalen / 2;
+                       memset(write_frame.data, 255, write_frame.datalen);
+               } else {
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec Error!");
+                       switch_channel_hangup(caller_channel, SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE);
+               }
+       }
 
+       while ((!caller_channel || switch_channel_ready(caller_channel)) && 
+                  check_channel_status(peer_channels, peer_sessions, argc, &idx, file, key) && ((time(NULL) - start) < (time_t)timelimit_sec)) {
+               
                /* read from the channel while we wait if the audio is up on it */
                if (session && (switch_channel_test_flag(caller_channel, CF_ANSWERED) || switch_channel_test_flag(caller_channel, CF_EARLY_MEDIA))) {
                        switch_status_t status = switch_core_session_read_frame(session, &read_frame, 1000, 0);
@@ -1273,7 +1486,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
                                break;
                        }
                        if (read_frame) {
-                               if (switch_core_session_write_frame(session, read_frame, 1000, 0) != SWITCH_STATUS_SUCCESS) {
+                               if (switch_core_session_write_frame(session, &write_frame, 1000, 0) != SWITCH_STATUS_SUCCESS) {
                                        break;
                                }
                        }
@@ -1284,11 +1497,32 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
                
        }
 
+       switch_core_session_reset(session);
+
+       for (i = 0; i < argc; i++) {
+               if (!peer_channels[i]) {
+                       continue;
+               }
+               if (i != idx) {
+                       switch_channel_hangup(peer_channels[i], SWITCH_CAUSE_LOSE_RACE);
+               }
+       }
+
+
+       if (idx > -1) {
+               peer_session = peer_sessions[idx];
+               peer_channel = peer_channels[idx];
+       } else {
+               status = SWITCH_STATUS_FALSE;
+               goto done;
+       }
+
        if (caller_channel && switch_channel_test_flag(peer_channel, CF_ANSWERED)) {
                switch_channel_answer(caller_channel);
        }
 
        if (switch_channel_test_flag(peer_channel, CF_ANSWERED) || switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA)) {
+               switch_core_session_read_lock(peer_session);
                *bleg = peer_session;
                status = SWITCH_STATUS_SUCCESS;
        } else {
@@ -1298,18 +1532,22 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
 
 
  done:
-       free(chan_type);
+       if (odata) {
+               free(odata);
+       }
+       if (write_codec.implementation) {
+               switch_core_codec_destroy(&write_codec);
+       }
        return status;
 }
 
 
 SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_session_t *session, 
-                                                                                                                          switch_core_session_t *peer_session,
-                                                                                                                          unsigned int timelimit,
-                                                                                                                          switch_input_callback_function_t input_callback,
-                                                                                                                          void *session_data,
-                                                                                                                          void *peer_session_data)
-                                                                                                                          
+                                                                                                                                switch_core_session_t *peer_session,
+                                                                                                                                switch_input_callback_function_t input_callback,
+                                                                                                                                void *session_data,
+                                                                                                                                void *peer_session_data)
+        
 
                                                                                                                           
 {
index 3de793bae9d39045c106f9ddb8e46308835dd07d..056189a308a5091092111ac17c4ccf33145239ab 100644 (file)
@@ -75,8 +75,9 @@ SWITCH_DECLARE(unsigned char) switch_char_to_rfc2833(char key)
 SWITCH_DECLARE(unsigned int) switch_separate_string(char *buf, char delim, char **array, int arraylen)
 {
        int argc;
-       char *scan;
-       int paren = 0;
+       char *ptr;
+       int quot = 0;
+       char qc = '"';
 
        if (!buf || !array || !arraylen) {
                return 0;
@@ -84,25 +85,33 @@ SWITCH_DECLARE(unsigned int) switch_separate_string(char *buf, char delim, char
 
        memset(array, 0, arraylen * sizeof(*array));
 
-       scan = buf;
-
-       for (argc = 0; *scan && (argc < arraylen - 1); argc++) {
-               array[argc] = scan;
-               for (; *scan; scan++) {
-                       if (*scan == '(')
-                               paren++;
-                       else if (*scan == ')') {
-                               if (paren)
-                                       paren--;
-                       } else if ((*scan == delim) && !paren) {
-                               *scan++ = '\0';
+       ptr = buf;
+
+       for (argc = 0; *ptr && (argc < arraylen - 1); argc++) {
+               array[argc] = ptr;
+               for (; *ptr; ptr++) {
+                       if (*ptr == qc) {
+                               if (quot) {
+                                       quot--;
+                               } else {
+                                       quot++;
+                               }
+                       } else if ((*ptr == delim) && !quot) {
+                               *ptr++ = '\0';
                                break;
                        }
                }
        }
 
-       if (*scan) {
-               array[argc++] = scan;
+       if (*ptr) {
+               char *e;
+               if (*ptr == qc) {
+                       ptr++;
+               }
+               if ((e = strchr(ptr, qc))) {
+                       *e = '\0';
+               }
+               array[argc++] = ptr;
        }
 
        return argc;