From 75223dc44a35971c077bca793c870e1d2d4b074f Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Tue, 22 Dec 2020 15:32:48 -0500 Subject: [PATCH] [core] Update switch_ivr_record_session_event() to check event vars for RECORD_STEREO, etc --- src/include/switch_channel.h | 1 + src/include/test/switch_test.h | 1 + src/switch_channel.c | 15 ++-- src/switch_ivr_async.c | 159 +++++++++++++++++++++------------ tests/unit/switch_ivr_async.c | 39 ++++++++ 5 files changed, 153 insertions(+), 62 deletions(-) diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index 965575e783..5ee73c41fa 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -685,6 +685,7 @@ SWITCH_DECLARE(void) switch_channel_mark_hold(switch_channel_t *channel, switch_ /** @} */ SWITCH_DECLARE(switch_status_t) switch_channel_execute_on(switch_channel_t *channel, const char *variable_prefix); +SWITCH_DECLARE(switch_status_t) switch_channel_execute_on_value(switch_channel_t *channel, const char *variable_value); SWITCH_DECLARE(switch_status_t) switch_channel_api_on(switch_channel_t *channel, const char *variable_prefix); SWITCH_DECLARE(void) switch_channel_process_device_hangup(switch_channel_t *channel); SWITCH_DECLARE(switch_caller_extension_t *) switch_channel_get_queued_extension(switch_channel_t *channel); diff --git a/src/include/test/switch_test.h b/src/include/test/switch_test.h index 936c709bb1..7839a6c736 100644 --- a/src/include/test/switch_test.h +++ b/src/include/test/switch_test.h @@ -522,6 +522,7 @@ static switch_status_t fst_init_core_and_modload(const char *confdir, const char switch_channel_set_variable(fst_channel, "send_silence_when_idle", "-1"); \ switch_channel_set_variable(fst_channel, "RECORD_STEREO", "true"); \ switch_ivr_record_session(fst_session, (char *)"/tmp/"#name".wav", 0, NULL); \ + switch_channel_set_variable(fst_channel, "RECORD_STEREO", NULL); \ for(;;) { /** diff --git a/src/switch_channel.c b/src/switch_channel.c index baca416c9e..9a57466042 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -3759,15 +3759,16 @@ SWITCH_DECLARE(switch_status_t) switch_channel_api_on(switch_channel_t *channel, return x ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE; } -static void do_execute_on(switch_channel_t *channel, const char *variable) +SWITCH_DECLARE(switch_status_t) switch_channel_execute_on_value(switch_channel_t *channel, const char *variable_value) { + switch_status_t status; char *arg = NULL; char *p; int bg = 0; char *app; char *expanded = NULL; - app = switch_core_session_strdup(channel->session, variable); + app = switch_core_session_strdup(channel->session, variable_value); for(p = app; p && *p; p++) { if (*p == ' ' || (*p == ':' && (*(p+1) != ':'))) { @@ -3792,14 +3793,16 @@ static void do_execute_on(switch_channel_t *channel, const char *variable) } if (bg) { - switch_core_session_execute_application_async(channel->session, app, arg); + status = switch_core_session_execute_application_async(channel->session, app, arg); } else { - switch_core_session_execute_application(channel->session, app, arg); + status = switch_core_session_execute_application(channel->session, app, arg); } if (expanded && expanded != arg) { free(expanded); } + + return status; } SWITCH_DECLARE(switch_status_t) switch_channel_execute_on(switch_channel_t *channel, const char *variable_prefix) @@ -3821,11 +3824,11 @@ SWITCH_DECLARE(switch_status_t) switch_channel_execute_on(switch_channel_t *chan int i; for (i = 0; i < hp->idx; i++) { x++; - do_execute_on(channel, hp->array[i]); + switch_channel_execute_on_value(channel, hp->array[i]); } } else { x++; - do_execute_on(channel, val); + switch_channel_execute_on_value(channel, val); } } } diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index bcf5f17499..82e62cf90f 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -86,6 +86,8 @@ struct switch_ivr_dmachine { uint8_t pinging; }; +static const char *get_recording_var(switch_channel_t *channel, switch_event_t *vars, const char *name); +static int recording_var_true(switch_channel_t *channel, switch_event_t *vars, const char *name); static switch_status_t speech_on_dtmf(switch_core_session_t *session, const switch_dtmf_t *dtmf, switch_dtmf_direction_t direction); SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_last_ping(switch_ivr_dmachine_t *dmachine) @@ -1222,7 +1224,6 @@ static void send_record_stop_event(switch_channel_t *channel, switch_codec_imple { switch_event_t *event; - rh->start_event_sent = 0; if (rh->fh) { switch_channel_set_variable_printf(channel, "record_samples", "%d", rh->fh->samples_out); if (read_impl->actual_samples_per_second) { @@ -1243,8 +1244,21 @@ static void send_record_stop_event(switch_channel_t *channel, switch_codec_imple switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Record-Completion-Cause", rh->completion_cause); } switch_event_fire(&event); - switch_event_safe_destroy(rh->variables); } + + if (rh->start_event_sent) { + if (rh->variables) { + const char *exec_app = NULL; + exec_app = switch_event_get_header(rh->variables, "execute_on_record_stop"); + if (exec_app) { + switch_channel_execute_on_value(channel, exec_app); + } + } + switch_channel_execute_on(channel, "execute_on_record_stop"); + switch_channel_api_on(channel, "api_on_record_stop"); + } + + rh->start_event_sent = 0; } static void *SWITCH_THREAD_FUNC recording_thread(switch_thread_t *thread, void *obj) @@ -1338,6 +1352,40 @@ static void *SWITCH_THREAD_FUNC recording_thread(switch_thread_t *thread, void * return NULL; } +static void record_helper_post_process(struct record_helper *rh, switch_core_session_t *session) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + const char *var = NULL; + const char *post_process_exec = NULL; + if (rh->variables && (post_process_exec = switch_event_get_header(rh->variables, SWITCH_RECORD_POST_PROCESS_EXEC_APP_VARIABLE))) { + switch_channel_execute_on_value(channel, post_process_exec); + } + switch_channel_execute_on(channel, SWITCH_RECORD_POST_PROCESS_EXEC_APP_VARIABLE); + + if ((var = switch_channel_get_variable(channel, SWITCH_RECORD_POST_PROCESS_EXEC_API_VARIABLE))) { + char *cmd = switch_core_session_strdup(session, var); + char *data, *expanded = NULL; + switch_stream_handle_t stream = { 0 }; + + SWITCH_STANDARD_STREAM(stream); + + if ((data = strchr(cmd, ':'))) { + *data++ = '\0'; + expanded = switch_channel_expand_variables(channel, data); + } + + switch_api_execute(cmd, expanded, session, &stream); + + if (expanded && expanded != data) { + free(expanded); + } + + switch_safe_free(stream.data); + + } + +} + static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type) { switch_core_session_t *session = switch_core_media_bug_get_session(bug); @@ -1357,7 +1405,7 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s switch (type) { case SWITCH_ABC_TYPE_INIT: { - const char *var = switch_channel_get_variable(channel, "RECORD_USE_THREAD"); + const char *var = get_recording_var(channel, rh->variables, "RECORD_USE_THREAD"); switch_core_session_get_read_impl(session, &rh->read_impl); @@ -1435,6 +1483,15 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s merge_recording_variables(rh, event); switch_event_fire(&event); } + if (rh->variables) { + const char *exec_app = NULL; + exec_app = switch_event_get_header(rh->variables, "execute_on_record_start"); + if (exec_app) { + switch_channel_execute_on_value(channel, exec_app); + } + } + switch_channel_execute_on(channel, "execute_on_record_start"); + switch_channel_api_on(channel, "api_on_record_start"); } rh->silence_time = switch_micro_time_now(); @@ -1533,8 +1590,6 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s break; case SWITCH_ABC_TYPE_CLOSE: { - const char *var; - switch_codec_implementation_t read_impl = { 0 }; switch_core_session_get_read_impl(session, &read_impl); @@ -1635,31 +1690,7 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s } send_record_stop_event(channel, &read_impl, rh); - - switch_channel_execute_on(channel, SWITCH_RECORD_POST_PROCESS_EXEC_APP_VARIABLE); - - if ((var = switch_channel_get_variable(channel, SWITCH_RECORD_POST_PROCESS_EXEC_API_VARIABLE))) { - char *cmd = switch_core_session_strdup(session, var); - char *data, *expanded = NULL; - switch_stream_handle_t stream = { 0 }; - - SWITCH_STANDARD_STREAM(stream); - - if ((data = strchr(cmd, ':'))) { - *data++ = '\0'; - expanded = switch_channel_expand_variables(channel, data); - } - - switch_api_execute(cmd, expanded, session, &stream); - - if (expanded && expanded != data) { - free(expanded); - } - - switch_safe_free(stream.data); - - } - + record_helper_post_process(rh, session); record_helper_destroy(&rh, session); } @@ -2868,6 +2899,8 @@ static switch_status_t record_helper_destroy(struct record_helper **rh, switch_c switch_core_file_close((*rh)->fh); } + switch_event_safe_destroy((*rh)->variables); + pool = (*rh)->helper_pool; switch_core_destroy_memory_pool(&pool); *rh = NULL; @@ -2875,6 +2908,20 @@ static switch_status_t record_helper_destroy(struct record_helper **rh, switch_c return SWITCH_STATUS_SUCCESS; } +static const char *get_recording_var(switch_channel_t *channel, switch_event_t *vars, const char *name) +{ + const char *val = NULL; + if (vars && !(val = switch_event_get_header(vars, name))) { + val = switch_channel_get_variable(channel, name); + } + return val; +} + +static int recording_var_true(switch_channel_t *channel, switch_event_t *vars, const char *name) +{ + return switch_true(get_recording_var(channel, vars, name)); +} + SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_session_t *session, const char *file, uint32_t limit, switch_file_handle_t *fh, switch_event_t *vars) { switch_channel_t *channel = switch_core_session_get_channel(session); @@ -2893,7 +2940,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess char *ext; char *in_file = NULL, *out_file = NULL; - if ((p = switch_channel_get_variable(channel, "RECORD_HANGUP_ON_ERROR"))) { + if ((p = get_recording_var(channel, vars, "RECORD_HANGUP_ON_ERROR"))) { hangup_on_error = switch_true(p); } @@ -2910,7 +2957,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess channels = read_impl.number_of_channels; if ((bug = switch_channel_get_private(channel, file))) { - if (switch_channel_var_true(channel, "RECORD_TOGGLE_ON_REPEAT")) { + if (recording_var_true(channel, vars, "RECORD_TOGGLE_ON_REPEAT")) { return switch_ivr_stop_record_session(session, file); } @@ -2919,7 +2966,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess } - if (switch_channel_var_true(channel, "RECORD_CHECK_BRIDGE")) { + if (recording_var_true(channel, vars, "RECORD_CHECK_BRIDGE")) { switch_core_session_t *other_session; int exist = 0; switch_status_t rstatus = SWITCH_STATUS_SUCCESS; @@ -2960,44 +3007,44 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess } } - if (switch_channel_var_true(channel, "RECORD_WRITE_ONLY")) { + if (recording_var_true(channel, vars, "RECORD_WRITE_ONLY")) { flags &= ~SMBF_READ_STREAM; flags |= SMBF_WRITE_STREAM; } - if (switch_channel_var_true(channel, "RECORD_READ_ONLY")) { + if (recording_var_true(channel, vars, "RECORD_READ_ONLY")) { flags &= ~SMBF_WRITE_STREAM; flags |= SMBF_READ_STREAM; } if (channels == 1) { /* if leg is already stereo this feature is not available */ - if (switch_channel_var_true(channel, "RECORD_STEREO")) { + if (recording_var_true(channel, vars, "RECORD_STEREO")) { flags |= SMBF_STEREO; flags &= ~SMBF_STEREO_SWAP; channels = 2; } - if (switch_channel_var_true(channel, "RECORD_STEREO_SWAP")) { + if (recording_var_true(channel, vars, "RECORD_STEREO_SWAP")) { flags |= SMBF_STEREO; flags |= SMBF_STEREO_SWAP; channels = 2; } } - if (switch_channel_var_true(channel, "RECORD_ANSWER_REQ")) { + if (recording_var_true(channel, vars, "RECORD_ANSWER_REQ")) { flags |= SMBF_ANSWER_REQ; } - if (switch_channel_var_true(channel, "RECORD_BRIDGE_REQ")) { + if (recording_var_true(channel, vars, "RECORD_BRIDGE_REQ")) { flags |= SMBF_BRIDGE_REQ; } - if (switch_channel_var_true(channel, "RECORD_APPEND")) { + if (recording_var_true(channel, vars, "RECORD_APPEND")) { file_flags |= SWITCH_FILE_WRITE_APPEND; } fh->samplerate = 0; - if ((vval = switch_channel_get_variable(channel, "record_sample_rate"))) { + if ((vval = get_recording_var(channel, vars, "record_sample_rate"))) { int tmp = 0; tmp = atoi(vval); @@ -3013,7 +3060,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess fh->channels = channels; - if ((vval = switch_channel_get_variable(channel, "enable_file_write_buffering"))) { + if ((vval = get_recording_var(channel, vars, "enable_file_write_buffering"))) { int tmp = atoi(vval); if (tmp > 0) { @@ -3031,7 +3078,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess char *e; const char *prefix; - prefix = switch_channel_get_variable(channel, "sound_prefix"); + prefix = get_recording_var(channel, vars, "sound_prefix"); if (!prefix) { prefix = SWITCH_GLOBAL_dirs.base_dir; @@ -3109,10 +3156,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess //switch_core_media_set_video_file(session, fh, SWITCH_RW_READ); //switch_channel_set_flag_recursive(session->channel, CF_VIDEO_DECODED_READ); - if (switch_channel_var_true(channel, "record_concat_video")) { + if (recording_var_true(channel, vars, "record_concat_video")) { flags |= SMBF_READ_VIDEO_STREAM; flags |= SMBF_WRITE_VIDEO_STREAM; - } else if (switch_channel_var_true(channel, "record_bleg_video")) { + } else if (recording_var_true(channel, vars, "record_bleg_video")) { flags |= SMBF_WRITE_VIDEO_STREAM; } else { flags |= SMBF_READ_VIDEO_STREAM; @@ -3168,37 +3215,37 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess flags = tflags; } - if ((p = switch_channel_get_variable(channel, "RECORD_TITLE"))) { + if ((p = get_recording_var(channel, vars, "RECORD_TITLE"))) { vval = (const char *) switch_core_strdup(rh->helper_pool, p); if (fh) switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_TITLE, vval); switch_channel_set_variable(channel, "RECORD_TITLE", NULL); } - if ((p = switch_channel_get_variable(channel, "RECORD_COPYRIGHT"))) { + if ((p = get_recording_var(channel, vars, "RECORD_COPYRIGHT"))) { vval = (const char *) switch_core_strdup(rh->helper_pool, p); if (fh) switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_COPYRIGHT, vval); switch_channel_set_variable(channel, "RECORD_COPYRIGHT", NULL); } - if ((p = switch_channel_get_variable(channel, "RECORD_SOFTWARE"))) { + if ((p = get_recording_var(channel, vars, "RECORD_SOFTWARE"))) { vval = (const char *) switch_core_strdup(rh->helper_pool, p); if (fh) switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_SOFTWARE, vval); switch_channel_set_variable(channel, "RECORD_SOFTWARE", NULL); } - if ((p = switch_channel_get_variable(channel, "RECORD_ARTIST"))) { + if ((p = get_recording_var(channel, vars, "RECORD_ARTIST"))) { vval = (const char *) switch_core_strdup(rh->helper_pool, p); if (fh) switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_ARTIST, vval); switch_channel_set_variable(channel, "RECORD_ARTIST", NULL); } - if ((p = switch_channel_get_variable(channel, "RECORD_COMMENT"))) { + if ((p = get_recording_var(channel, vars, "RECORD_COMMENT"))) { vval = (const char *) switch_core_strdup(rh->helper_pool, p); if (fh) switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_COMMENT, vval); switch_channel_set_variable(channel, "RECORD_COMMENT", NULL); } - if ((p = switch_channel_get_variable(channel, "RECORD_DATE"))) { + if ((p = get_recording_var(channel, vars, "RECORD_DATE"))) { vval = (const char *) switch_core_strdup(rh->helper_pool, p); if (fh) switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_DATE, vval); switch_channel_set_variable(channel, "RECORD_DATE", NULL); @@ -3216,14 +3263,14 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess rh->min_sec = 3; } - if ((p = switch_channel_get_variable(channel, "RECORD_MIN_SEC"))) { + if ((p = get_recording_var(channel, vars, "RECORD_MIN_SEC"))) { int tmp = atoi(p); if (tmp >= 0) { rh->min_sec = tmp; } } - if ((p = switch_channel_get_variable(channel, "RECORD_INITIAL_TIMEOUT_MS"))) { + if ((p = get_recording_var(channel, vars, "RECORD_INITIAL_TIMEOUT_MS"))) { int tmp = atoi(p); if (tmp >= 0) { rh->initial_timeout_ms = tmp; @@ -3231,7 +3278,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess } } - if ((p = switch_channel_get_variable(channel, "RECORD_FINAL_TIMEOUT_MS"))) { + if ((p = get_recording_var(channel, vars, "RECORD_FINAL_TIMEOUT_MS"))) { int tmp = atoi(p); if (tmp >= 0) { rh->final_timeout_ms = tmp; @@ -3239,7 +3286,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess } } - if ((p = switch_channel_get_variable(channel, "RECORD_SILENCE_THRESHOLD"))) { + if ((p = get_recording_var(channel, vars, "RECORD_SILENCE_THRESHOLD"))) { int tmp = atoi(p); if (tmp >= 0) { rh->silence_threshold = tmp; @@ -3262,7 +3309,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess switch_goto_status(status, err); } - if ((p = switch_channel_get_variable(channel, "RECORD_PRE_BUFFER_FRAMES"))) { + if ((p = get_recording_var(channel, vars, "RECORD_PRE_BUFFER_FRAMES"))) { int tmp = atoi(p); if (tmp > 0) { diff --git a/tests/unit/switch_ivr_async.c b/tests/unit/switch_ivr_async.c index 3cf8a8a52e..affd47587c 100644 --- a/tests/unit/switch_ivr_async.c +++ b/tests/unit/switch_ivr_async.c @@ -117,6 +117,45 @@ FST_CORE_BEGIN("./conf_async") fst_xcheck(duration_ms > 3500 && duration_ms < 3700, "Expect recording to be between 3500 and 3700 ms"); } FST_SESSION_END() + + FST_SESSION_BEGIN(session_record_event_vars) + { + const char *record_filename = switch_core_session_sprintf(fst_session, "%s%s%s.wav", SWITCH_GLOBAL_dirs.temp_dir, SWITCH_PATH_SEPARATOR, switch_core_session_get_uuid(fst_session)); + switch_event_t *rec_vars = NULL; + switch_status_t status; + + switch_event_create_subclass(&rec_vars, SWITCH_EVENT_CLONE, SWITCH_EVENT_SUBCLASS_ANY); + fst_requires(rec_vars != NULL); + + // record READ stream only- should be complete silence which will trigger the initial timeout. + // Min seconds set to 2, which will cause the recording to be discarded. + // Expect the record_start_test_pass and record_stop_test_pass variables set to true + switch_event_add_header_string(rec_vars, SWITCH_STACK_BOTTOM, "execute_on_record_start", "set record_start_test_pass=true"); + switch_event_add_header_string(rec_vars, SWITCH_STACK_BOTTOM, "execute_on_record_stop", "set record_stop_test_pass=true"); + switch_event_add_header_string(rec_vars, SWITCH_STACK_BOTTOM, SWITCH_RECORD_POST_PROCESS_EXEC_APP_VARIABLE, "set record_post_process_test_pass=true"); + switch_event_add_header_string(rec_vars, SWITCH_STACK_BOTTOM, "RECORD_READ_ONLY", "true"); + switch_event_add_header_string(rec_vars, SWITCH_STACK_BOTTOM, "RECORD_INITIAL_TIMEOUT_MS", "500"); + switch_event_add_header_string(rec_vars, SWITCH_STACK_BOTTOM, "RECORD_MIN_SEC", "2"); + + status = switch_ivr_record_session_event(fst_session, record_filename, 0, NULL, rec_vars); + fst_xcheck(status == SWITCH_STATUS_SUCCESS, "Expect switch_ivr_record_session() to return SWITCH_STATUS_SUCCESS"); + + status = switch_ivr_play_file(fst_session, NULL, "tone_stream://%(400,200,400,450);%(400,2000,400,450)", NULL); + fst_xcheck(status == SWITCH_STATUS_SUCCESS, "Expect switch_ivr_play_file() to return SWITCH_STATUS_SUCCESS"); + + status = switch_ivr_record_session_pause(fst_session, record_filename, SWITCH_TRUE); + fst_xcheck(status != SWITCH_STATUS_SUCCESS, "Expect switch_ivr_record_session_pause(SWITCH_TRUE) not to return SWITCH_STATUS_SUCCESS because the recording has already stopped"); + + fst_xcheck(switch_file_exists(record_filename, fst_pool) != SWITCH_STATUS_SUCCESS, "Expect recording file not to exist since it was less than 2 seconds in duration"); + + fst_xcheck(switch_channel_var_true(fst_channel, "record_start_test_pass"), "Expect record_start_test_pass channel variable set to true"); + fst_xcheck(switch_channel_var_true(fst_channel, "record_stop_test_pass"), "Expect record_stop_test_pass channel variable set to true"); + fst_xcheck(switch_channel_var_true(fst_channel, "record_post_process_test_pass"), "Expect record_post_process_test_pass channel variable set to true"); + + unlink(record_filename); + switch_event_destroy(&rec_vars); + } + FST_SESSION_END() } FST_SUITE_END() }