]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-10416: [mod_commands] add new outbound channels to an in-progress originate
authorHristo Trendev <htrendev@gmail.com>
Wed, 21 Jun 2017 17:00:52 +0000 (19:00 +0200)
committerHristo Trendev <htrendev@gmail.com>
Wed, 21 Jun 2017 17:31:46 +0000 (19:31 +0200)
This allows new endpoints (outbound channels) to be called, after an originate
is already in progress, where any of the originally called endpoints need to
continue to ring.

One use case would be to convert a 302 Moved Temporarily destination to SIP
endpoint(s) and then to add the new endpoints to an in-progress originate,
without cancelling any of the other (already ringing) outbound channels.

src/include/switch_types.h
src/mod/applications/mod_commands/mod_commands.c
src/switch_core_session.c
src/switch_ivr_originate.c

index 2cc1000e2fa1dd3ec6d1c7eaf9642ec6f68d56c5..d9cd67332feac5f279418c740ab74227118c6c38 100644 (file)
@@ -1547,6 +1547,7 @@ typedef enum {
        CF_AWAITING_STREAM_CHANGE,
        CF_PROCESSING_STREAM_CHANGE,
        CF_STREAM_CHANGED,
+       CF_ADD_ENDPOINTS,
        /* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */
        /* IF YOU ADD NEW ONES CHECK IF THEY SHOULD PERSIST OR ZERO THEM IN switch_core_session.c switch_core_session_request_xml() */
        CF_FLAG_MAX
index 758e8c95702c9ece43e4bdec6e81a0842a68c7ec..7b0add370e996c2231e9b3a6967267a1c864d227 100644 (file)
@@ -4815,7 +4815,7 @@ SWITCH_STANDARD_API(pause_function)
        return SWITCH_STATUS_SUCCESS;
 }
 
-#define ORIGINATE_SYNTAX "<call url> <exten>|&<application_name>(<app_args>) [<dialplan>] [<context>] [<cid_name>] [<cid_num>] [<timeout_sec>]"
+#define ORIGINATE_SYNTAX "<call url> <exten>|&<application_name>(<app_args>) [<dialplan>] [<context>] [<cid_name>] [<cid_num>] [<timeout_sec>] [<originator_uuid>]"
 SWITCH_STANDARD_API(originate_function)
 {
        switch_channel_t *caller_channel;
@@ -4841,7 +4841,7 @@ SWITCH_STANDARD_API(originate_function)
        switch_assert(mycmd);
        argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
 
-       if (argc < 2 || argc > 7) {
+       if (argc < 2 || argc > 8) {
                stream->write_function(stream, "-USAGE: %s\n", ORIGINATE_SYNTAX);
                goto done;
        }
@@ -4871,6 +4871,30 @@ SWITCH_STANDARD_API(originate_function)
                timeout = atoi(argv[6]);
        }
 
+       /* It is OK to use the caller_session and caller_channel variables instead of adding new ones, since this isn't a real originate */
+       if (argv[7]) {
+               caller_session = switch_core_session_locate(argv[7]);
+               if (caller_session) {
+                       caller_channel = switch_core_session_get_channel(caller_session);
+                       if (caller_channel) {
+                               if (switch_channel_test_flag(caller_channel, CF_ORIGINATOR) && switch_channel_test_flag(caller_channel, CF_ADD_ENDPOINTS) &&
+                                                                                                                                                       !switch_channel_get_variable(caller_channel, "originate_add_endpoints")) {
+                                       switch_channel_set_variable(caller_channel, "originate_add_endpoints", aleg);
+                                       stream->write_function(stream, "+OK %s\n", switch_core_session_get_uuid(caller_session));
+                               } else {
+                                       stream->write_function(stream, "-ERR originator is in the wrong state (originator: %d, add endpoints: %d, var: %s)\n",
+                                                                                  switch_channel_test_flag(caller_channel, CF_ORIGINATOR),
+                                                                                  switch_channel_test_flag(caller_channel, CF_ADD_ENDPOINTS),
+                                                                                  switch_channel_get_variable(caller_channel, "originate_add_endpoints"));
+                               }
+                       }
+                       switch_core_session_rwunlock(caller_session);
+               } else {
+                       stream->write_function(stream, "-ERR originator session not found\n");
+               }
+               goto done;
+       }
+
        if (switch_ivr_originate(NULL, &caller_session, &cause, aleg, timeout, NULL, cid_name, cid_num, NULL, NULL, SOF_NONE, NULL) != SWITCH_STATUS_SUCCESS
                || !caller_session) {
                        stream->write_function(stream, "-ERR %s\n", switch_channel_cause2str(cause));
index a810cc45cdcf994884e19c11b80249c99ec83a19..c81cbe969b8c4335ea53166ddb4bc1e9e6c38544 100644 (file)
@@ -2153,6 +2153,7 @@ SWITCH_DECLARE(switch_core_session_t *) switch_core_session_request_xml(switch_e
        flags[CF_SIMPLIFY] = 0;
        flags[CF_VIDEO_READY] = 0;
        flags[CF_VIDEO_DECODED_READ] = 0;
+       flags[CF_ADD_ENDPOINTS] = 0;
 
        if (!(session = switch_core_session_request_uuid(endpoint_interface, direction, SOF_NO_LIMITS, pool, uuid))) {
                return NULL;
index a8b9ddfb44ed55e49bb522c710eba191fcf8ce2d..bcfa7ee18dbe38cb44b14b1b3097b3730b42eec0 100644 (file)
@@ -1929,6 +1929,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
        originate_status_t originate_status[MAX_PEERS] = { {0} };
        switch_originate_flag_t dftflags = SOF_NONE, myflags = dftflags;
        char *pipe_names[MAX_PEERS] = { 0 };
+       const char *newep = NULL;
        char *data = NULL;
        switch_status_t status = SWITCH_STATUS_SUCCESS;
        switch_channel_t *caller_channel = NULL;
@@ -1941,7 +1942,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
        time_t start, global_start;
        switch_time_t last_retry_start = 0;
        switch_frame_t *read_frame = NULL;
-       int r = 0, i, and_argc = 0, or_argc = 0;
+       int r = 0, i, and_argc = 0, or_argc = 0, and_argc_offset = 0;
        int32_t sleep_ms = 1000, try = 0, retries = 1, retry_timelimit_sec = 0;
        int32_t min_retry_period_ms = sleep_ms;
        switch_codec_t write_codec = { 0 };
@@ -2613,6 +2614,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
                                last_retry_start = switch_micro_time_now();
                        }
 
+               add_endpoints:
                        p = pipe_names[r];
 
                        while (p && *p) {
@@ -2646,20 +2648,20 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
                                p++;
                        }
 
-                       and_argc = switch_separate_string(pipe_names[r], ',', peer_names, (sizeof(peer_names) / sizeof(peer_names[0])));
+                       and_argc += switch_separate_string(pipe_names[r], ',', peer_names, (sizeof(peer_names) / sizeof(peer_names[0])));
 
                        if ((flags & SOF_NOBLOCK) && and_argc > 1) {
                                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Only calling the first element in the list in this mode.\n");
                                and_argc = 1;
                        }
 
-                       for (i = 0; i < and_argc; i++) {
+                       for (i = and_argc_offset; i < and_argc; i++) {
                                const char *current_variable;
                                switch_event_t *local_var_event = NULL, *originate_var_event = NULL;
 
                                end = NULL;
 
-                               chan_type = peer_names[i];
+                               chan_type = peer_names[i-and_argc_offset];
 
 
                                /* strip leading spaces */
@@ -3055,7 +3057,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
 
                        for (;;) {
                                uint32_t valid_channels = 0;
-                               for (i = 0; i < and_argc; i++) {
+                               for (i = and_argc_offset; i < and_argc; i++) {
                                        int state;
                                        time_t elapsed;
 
@@ -3135,6 +3137,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
 
                        if (caller_channel) {
                                soft_holding = switch_channel_get_variable(caller_channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE);
+                               switch_channel_set_flag(caller_channel, CF_ADD_ENDPOINTS);
                        }
 
                        while ((!caller_channel || switch_channel_ready(caller_channel) || switch_channel_test_flag(caller_channel, CF_XFER_ZOMBIE)) &&
@@ -3279,6 +3282,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
                                                                break;
                                                        case SWITCH_STATUS_BREAK:
                                                                status = SWITCH_STATUS_FALSE;
+                                                               switch_channel_clear_flag(caller_channel, CF_ADD_ENDPOINTS);
+                                                               switch_channel_set_variable(caller_channel, "originate_add_endpoints", NULL);
                                                                goto done;
                                                                break;
                                                        default:
@@ -3382,6 +3387,17 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
 
                        do_continue:
 
+                               if(caller_channel) {
+                                       newep = switch_channel_get_variable(caller_channel, "originate_add_endpoints");
+                                       if (newep) {
+                                               switch_channel_set_variable(caller_channel, "originate_add_endpoints", NULL);
+                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Add new originate endpoint(s): %s\n", newep);
+                                               and_argc_offset = and_argc;
+                                               pipe_names[r] = strdup(newep);
+                                               goto add_endpoints;
+                                       }
+                               }
+
                                if (!read_packet) {
                                        switch_yield(20000);
                                }
@@ -3390,6 +3406,21 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
                  notready:
 
                        if (caller_channel) {
+
+                               switch_channel_clear_flag(caller_channel, CF_ADD_ENDPOINTS);
+                               newep = switch_channel_get_variable(caller_channel, "originate_add_endpoints");
+                               if (newep) {
+                                       switch_channel_set_variable(caller_channel, "originate_add_endpoints", NULL);
+
+                                       /* Only add new endpoints at this stage, if it's not originator cancel and if no outbound leg was aswered */
+                                       if(oglobals.idx != IDX_CANCEL && oglobals.hups == and_argc) {
+                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Add new originate endpoints: %s\n", newep);
+                                               and_argc_offset = and_argc;
+                                               pipe_names[r] = strdup(newep);
+                                               goto add_endpoints;
+                                       }
+                               }
+
                                holding = switch_channel_get_variable(caller_channel, SWITCH_HOLDING_UUID_VARIABLE);
                                switch_channel_set_variable(caller_channel, SWITCH_HOLDING_UUID_VARIABLE, NULL);