FS-10416: [mod_commands] add new outbound channels to an in-progress originate
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.
This commit is contained in:
parent
dcc0bf72ec
commit
b11955db0b
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue