SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(_In_ switch_core_session_t *session,
_In_ switch_file_handle_t *fh,
_In_z_ const char *file, _In_opt_ switch_input_args_t *args, _In_ uint32_t limit);
-
+/*!
+ \brief record a file from the session to a file
+ \param session the session to record from
+ \param fh file handle to use
+ \param file the path to the file
+ \param args arguements to pass for callbacks etc
+ \param limit max limit to record for (0 for infinite)
+ \param vars vars to add to RECORD_START and RECORD_STOP automatically prefixed with Recording-Variable-
+ \return SWITCH_STATUS_SUCCESS if all is well
+*/
+SWITCH_DECLARE(switch_status_t) switch_ivr_record_file_event(_In_ switch_core_session_t *session,
+ _In_ switch_file_handle_t *fh,
+ _In_z_ const char *file, _In_opt_ switch_input_args_t *args, _In_ uint32_t limit, switch_event_t *vars);
/*!
\brief Play a sound and gather digits with the number of retries specified if the user doesn't give digits in the set time
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))) {
+ if (!vars || !(val = switch_event_get_header(vars, name))) {
val = switch_channel_get_variable(channel, name);
}
return val;
return status;
}
-SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *session,
- switch_file_handle_t *fh, const char *file, switch_input_args_t *args, uint32_t limit)
+static void merge_recording_variables(switch_event_t *vars, switch_event_t *event)
+{
+ switch_event_header_t *hi;
+ if (vars) {
+ for (hi = vars->headers; hi; hi = hi->next) {
+ char buf[1024];
+ char *vvar = NULL, *vval = NULL;
+
+ vvar = (char *) hi->name;
+ vval = (char *) hi->value;
+
+ switch_assert(vvar && vval);
+ switch_snprintf(buf, sizeof(buf), "Recording-Variable-%s", vvar);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, buf, vval);
+ }
+ }
+}
+
+static const char *get_recording_var(switch_channel_t *channel, switch_event_t *vars, switch_file_handle_t *fh, const char *name)
+{
+ const char *val = NULL;
+ if (vars) {
+ val = switch_event_get_header(vars, name);
+ }
+ if (!val && fh && fh->params) {
+ val = switch_event_get_header(fh->params, name);
+ }
+ if (!val) {
+ val = switch_channel_get_variable(channel, name);
+ }
+ return val;
+}
+
+static int recording_var_true(switch_channel_t *channel, switch_event_t *vars, switch_file_handle_t *fh, const char *name)
+{
+ return switch_true(get_recording_var(channel, vars, fh, name));
+}
+
+SWITCH_DECLARE(switch_status_t) switch_ivr_record_file_event(switch_core_session_t *session,
+ switch_file_handle_t *fh, const char *file, switch_input_args_t *args, uint32_t limit, switch_event_t *vars)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_dtmf_t dtmf = { 0 };
return SWITCH_STATUS_FALSE;
}
- prefix = switch_channel_get_variable(channel, "sound_prefix");
+ prefix = get_recording_var(channel, vars, fh, "sound_prefix");
if (!prefix) {
prefix = SWITCH_GLOBAL_dirs.sounds_dir;
}
- if ((p = switch_channel_get_variable(channel, "record_sample_rate"))) {
+ if ((p = get_recording_var(channel, vars, fh, "record_sample_rate"))) {
int tmp = 0;
tmp = atoi(p);
}
- vval = switch_channel_get_variable(channel, "enable_file_write_buffering");
+ vval = get_recording_var(channel, vars, fh, "enable_file_write_buffering");
if (!vval || switch_true(vval)) {
fh->pre_buffer_datalen = SWITCH_DEFAULT_FILE_BUFFER_LEN;
}
- if (switch_test_flag(fh, SWITCH_FILE_WRITE_APPEND) || ((p = switch_channel_get_variable(channel, "RECORD_APPEND")) && switch_true(p))) {
+ if (switch_test_flag(fh, SWITCH_FILE_WRITE_APPEND) || recording_var_true(channel, vars, fh, "RECORD_APPEND")) {
file_flags |= SWITCH_FILE_WRITE_APPEND;
}
- if (switch_test_flag(fh, SWITCH_FILE_WRITE_OVER) || ((p = switch_channel_get_variable(channel, "RECORD_WRITE_OVER")) && switch_true(p))) {
+ if (switch_test_flag(fh, SWITCH_FILE_WRITE_OVER) || recording_var_true(channel, vars, fh, "RECORD_WRITE_OVER")) {
file_flags |= SWITCH_FILE_WRITE_OVER;
}
}
- if ((p = switch_channel_get_variable(channel, "record_fill_cng")) || (fh->params && (p = switch_event_get_header(fh->params, "record_fill_cng")))) {
+ if ((p = get_recording_var(channel, vars, fh, "record_fill_cng"))) {
if (!strcasecmp(p, "true")) {
fill_cng = 1400;
} else {
}
}
- if ((p = switch_channel_get_variable(channel, "record_waste_resources")) ||
- (fh->params && (p = switch_event_get_header(fh->params, "record_waste_resources")))) {
+ if ((p = get_recording_var(channel, vars, fh, "record_waste_resources"))) {
if (!strcasecmp(p, "true")) {
waste_resources = 1400;
if (switch_core_file_has_video(fh, SWITCH_TRUE)) {
switch_core_session_request_video_refresh(session);
- if ((p = switch_channel_get_variable(channel, "record_play_video")) ||
-
- (fh->params && (p = switch_event_get_header(fh->params, "record_play_video")))) {
+ if ((p = get_recording_var(channel, vars, fh, "record_play_video"))) {
video_file = switch_core_session_strdup(session, p);
asis = 1;
}
- restart_limit_on_dtmf = switch_true(switch_channel_get_variable(channel, "record_restart_limit_on_dtmf"));
+ restart_limit_on_dtmf = recording_var_true(channel, vars, fh, "record_restart_limit_on_dtmf");
- if ((p = switch_channel_get_variable(channel, "record_title")) || (fh->params && (p = switch_event_get_header(fh->params, "record_title")))) {
+ if ((p = get_recording_var(channel, vars, fh, "record_title"))) {
vval = switch_core_session_strdup(session, p);
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")) || (fh->params && (p = switch_event_get_header(fh->params, "record_copyright")))) {
+ if ((p = get_recording_var(channel, vars, fh, "record_copyright"))) {
vval = switch_core_session_strdup(session, p);
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")) || (fh->params && (p = switch_event_get_header(fh->params, "record_software")))) {
+ if ((p = get_recording_var(channel, vars, fh, "record_software"))) {
vval = switch_core_session_strdup(session, p);
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")) || (fh->params && (p = switch_event_get_header(fh->params, "record_artist")))) {
+ if ((p = get_recording_var(channel, vars, fh, "record_artist"))) {
vval = switch_core_session_strdup(session, p);
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")) || (fh->params && (p = switch_event_get_header(fh->params, "record_comment")))) {
+ if ((p = get_recording_var(channel, vars, fh, "record_comment"))) {
vval = switch_core_session_strdup(session, p);
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")) || (fh->params && (p = switch_event_get_header(fh->params, "record_date")))) {
+ if ((p = get_recording_var(channel, vars, fh, "record_date"))) {
vval = switch_core_session_strdup(session, p);
switch_core_file_set_string(fh, SWITCH_AUDIO_COL_STR_DATE, vval);
switch_channel_set_variable(channel, "record_date", NULL);
if (switch_event_create(&event, SWITCH_EVENT_RECORD_START) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(channel, event);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Record-File-Path", file);
+ merge_recording_variables(vars, event);
switch_event_fire(&event);
}
+ {
+ const char *app_exec = NULL;
+ if (vars && (app_exec = switch_event_get_header(vars, "execute_on_record_start"))) {
+ switch_channel_execute_on_value(channel, app_exec);
+ }
+ switch_channel_execute_on(channel, "execute_on_record_start");
+ switch_channel_api_on(channel, "api_on_record_start");
+ }
+
for (;;) {
switch_size_t len;
switch_core_file_get_string(fh, SWITCH_AUDIO_COL_STR_FILE_SIZE, &file_size);
switch_core_file_get_string(fh, SWITCH_AUDIO_COL_STR_FILE_TRIMMED, &file_trimmed);
switch_core_file_get_string(fh, SWITCH_AUDIO_COL_STR_FILE_TRIMMED_MS, &file_trimmed_ms);
- if (file_trimmed_ms) switch_channel_set_variable(channel, "record_record_trimmed_ms", file_trimmed_ms);
- if (file_size) switch_channel_set_variable(channel, "record_record_file_size", file_size);
- if (file_trimmed) switch_channel_set_variable(channel, "record_record_trimmed", file_trimmed);
+ if (file_trimmed_ms) {
+ switch_channel_set_variable(channel, "record_record_trimmed_ms", file_trimmed_ms);
+ switch_channel_set_variable(channel, "record_trimmed_ms", file_trimmed_ms);
+ }
+ if (file_size) {
+ switch_channel_set_variable(channel, "record_record_file_size", file_size);
+ switch_channel_set_variable(channel, "record_file_size", file_size);
+ }
+ if (file_trimmed) {
+ switch_channel_set_variable(channel, "record_record_trimmed", file_trimmed);
+ switch_channel_set_variable(channel, "record_trimmed", file_trimmed);
+ }
switch_core_file_close(fh);
if (switch_event_create(&event, SWITCH_EVENT_RECORD_STOP) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(channel, event);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Record-File-Path", file);
+ merge_recording_variables(vars, event);
switch_event_fire(&event);
}
+ {
+ const char *app_exec = NULL;
+ if (vars && (app_exec = switch_event_get_header(vars, "execute_on_record_stop"))) {
+ switch_channel_execute_on_value(channel, app_exec);
+ }
+ switch_channel_execute_on(channel, "execute_on_record_stop");
+ switch_channel_api_on(channel, "api_on_record_stop");
+ }
+
switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
arg_recursion_check_stop(args);
return status;
}
+SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *session,
+ switch_file_handle_t *fh, const char *file, switch_input_args_t *args, uint32_t limit)
+{
+ return switch_ivr_record_file_event(session, fh, file, args, limit, NULL);
+}
+
static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
{
switch_buffer_t *audio_buffer = ts->user_data;
switch_event_destroy(&rec_vars);
}
FST_SESSION_END()
+
+ FST_SESSION_BEGIN(session_record_chan_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_status_t status;
+
+ // 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_channel_set_variable(fst_channel, "execute_on_record_start", "set record_start_test_pass=true");
+ switch_channel_set_variable(fst_channel, "execute_on_record_stop", "set record_stop_test_pass=true");
+ switch_channel_set_variable(fst_channel, SWITCH_RECORD_POST_PROCESS_EXEC_APP_VARIABLE, "set record_post_process_test_pass=true");
+ switch_channel_set_variable(fst_channel, "RECORD_READ_ONLY", "true");
+ switch_channel_set_variable(fst_channel, "RECORD_INITIAL_TIMEOUT_MS", "500");
+ switch_channel_set_variable(fst_channel, "RECORD_MIN_SEC", "2");
+
+ status = switch_ivr_record_session_event(fst_session, record_filename, 0, NULL, NULL);
+ 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);
+ }
+ FST_SESSION_END()
}
FST_SUITE_END()
}
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
- * Copyright (C) 2005-2019, Anthony Minessale II <anthm@freeswitch.org>
+ * Copyright (C) 2005-2020, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
#include <test/switch_test.h>
+static void on_record_start(switch_event_t *event)
+{
+ char *str = NULL;
+ switch_event_serialize(event, &str, SWITCH_FALSE);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s", str);
+ switch_safe_free(str);
+ const char *uuid = switch_event_get_header(event, "Unique-ID");
+ if (uuid) {
+ switch_core_session_t *session = switch_core_session_locate(uuid);
+ if (session) {
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+ const char *recording_id = switch_event_get_header_nil(event, "Recording-Variable-ID");
+ if (!strcmp(recording_id, "foo")) {
+ switch_channel_set_variable(channel, "record_start_event_test_pass", "true");
+ }
+ switch_core_session_rwunlock(session);
+ }
+ }
+}
+
+static void on_record_stop(switch_event_t *event)
+{
+ char *str = NULL;
+ switch_event_serialize(event, &str, SWITCH_FALSE);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s", str);
+ switch_safe_free(str);
+ const char *uuid = switch_event_get_header(event, "Unique-ID");
+ if (uuid) {
+ switch_core_session_t *session = switch_core_session_locate(uuid);
+ if (session) {
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+ const char *recording_id = switch_event_get_header_nil(event, "Recording-Variable-ID");
+ if (!strcmp(recording_id, "foo")) {
+ switch_channel_set_variable(channel, "record_stop_event_test_pass", "true");
+ }
+ switch_core_session_rwunlock(session);
+ }
+ }
+}
+
static switch_status_t partial_play_and_collect_input_callback(switch_core_session_t *session, void *input, switch_input_type_t input_type, void *data, __attribute__((unused))unsigned int len)
{
switch_status_t status = SWITCH_STATUS_SUCCESS;
cJSON_Delete(recognition_result);
}
FST_SESSION_END()
+
+ FST_SESSION_BEGIN(record_file_event_vars)
+ {
+ const char *record_filename = switch_core_session_sprintf(fst_session, "%s" SWITCH_PATH_SEPARATOR "record_file_event_vars-tmp-%s.wav", SWITCH_GLOBAL_dirs.temp_dir, 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);
+ switch_event_bind("record_file_event", SWITCH_EVENT_RECORD_START, SWITCH_EVENT_SUBCLASS_ANY, on_record_start, NULL);
+ switch_event_bind("record_file_event", SWITCH_EVENT_RECORD_STOP, SWITCH_EVENT_SUBCLASS_ANY, on_record_stop, NULL);
+ 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, "ID", "foo");
+ switch_ivr_displace_session(fst_session, "file_string://silence_stream://500,0!tone_stream://%%(2000,0,350,440)", 0, "r");
+ status = switch_ivr_record_file_event(fst_session, NULL, record_filename, NULL, 4, rec_vars);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ 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");
+ switch_sleep(1000 * 1000);
+ fst_xcheck(switch_channel_var_true(fst_channel, "record_start_event_test_pass"), "Expect RECORD_START event received with Recording-Variable-ID set");
+ fst_xcheck(switch_channel_var_true(fst_channel, "record_stop_event_test_pass"), "Expect RECORD_STOP event received with Recording-Variable-ID set");
+ switch_event_unbind_callback(on_record_start);
+ switch_event_unbind_callback(on_record_stop);
+ switch_event_destroy(&rec_vars);
+ fst_xcheck(switch_file_exists(record_filename, fst_pool) == SWITCH_STATUS_SUCCESS, "Expect recording file to exist");
+ unlink(record_filename);
+ }
+ FST_SESSION_END()
+
+ FST_SESSION_BEGIN(record_file_event_chan_vars)
+ {
+ const char *record_filename = switch_core_session_sprintf(fst_session, "%s" SWITCH_PATH_SEPARATOR "record_file_event_chan_vars-tmp-%s.wav", SWITCH_GLOBAL_dirs.temp_dir, 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);
+ switch_event_bind("record_file_event", SWITCH_EVENT_RECORD_START, SWITCH_EVENT_SUBCLASS_ANY, on_record_start, NULL);
+ switch_event_bind("record_file_event", SWITCH_EVENT_RECORD_STOP, SWITCH_EVENT_SUBCLASS_ANY, on_record_stop, NULL);
+ switch_channel_set_variable(fst_channel, "execute_on_record_start_1", "set record_start_test_pass=true");
+ switch_channel_set_variable(fst_channel, "execute_on_record_stop_1", "set record_stop_test_pass=true");
+ switch_event_add_header_string(rec_vars, SWITCH_STACK_BOTTOM, "ID", "foo");
+ switch_ivr_displace_session(fst_session, "file_string://silence_stream://500,0!tone_stream://%%(2000,0,350,440)", 0, "r");
+ status = switch_ivr_record_file_event(fst_session, NULL, record_filename, NULL, 4, rec_vars);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ 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");
+ switch_sleep(1000 * 1000);
+ fst_xcheck(switch_channel_var_true(fst_channel, "record_start_event_test_pass"), "Expect RECORD_START event received with Recording-Variable-ID set");
+ fst_xcheck(switch_channel_var_true(fst_channel, "record_stop_event_test_pass"), "Expect RECORD_STOP event received with Recording-Variable-ID set");
+ switch_event_unbind_callback(on_record_start);
+ switch_event_unbind_callback(on_record_stop);
+ switch_event_destroy(&rec_vars);
+ fst_xcheck(switch_file_exists(record_filename, fst_pool) == SWITCH_STATUS_SUCCESS, "Expect recording file to exist");
+ unlink(record_filename);
+ }
+ FST_SESSION_END()
+
+ FST_SESSION_BEGIN(record_file_event_chan_vars_only)
+ {
+ const char *record_filename = switch_core_session_sprintf(fst_session, "%s" SWITCH_PATH_SEPARATOR "record_file_event_chan_vars-tmp-%s.wav", SWITCH_GLOBAL_dirs.temp_dir, switch_core_session_get_uuid(fst_session));
+ switch_status_t status;
+ switch_channel_set_variable(fst_channel, "execute_on_record_start_1", "set record_start_test_pass=true");
+ switch_channel_set_variable(fst_channel, "execute_on_record_stop_1", "set record_stop_test_pass=true");
+ switch_ivr_displace_session(fst_session, "file_string://silence_stream://500,0!tone_stream://%%(2000,0,350,440)", 0, "r");
+ status = switch_ivr_record_file_event(fst_session, NULL, record_filename, NULL, 4, NULL);
+ fst_check(status == SWITCH_STATUS_SUCCESS);
+ 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");
+ switch_sleep(1000 * 1000);
+ fst_xcheck(switch_file_exists(record_filename, fst_pool) == SWITCH_STATUS_SUCCESS, "Expect recording file to exist");
+ unlink(record_filename);
+ }
+ FST_SESSION_END()
}
FST_SUITE_END()
}