[Core] Fix hangup race in recording_follow_transfer.

This commit is contained in:
Andrey Volk 2020-07-01 04:19:25 +04:00
parent aaa4c09204
commit 2b8fa12baa
4 changed files with 300 additions and 72 deletions

View File

@ -1973,6 +1973,16 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_get_string(_In_ switch_file_han
*/
SWITCH_DECLARE(switch_status_t) switch_core_file_pre_close(_In_ switch_file_handle_t *fh);
/*!
\brief Duplicates a file handle using another pool
\param oldfh the file handle to duplicate
\param newfh pointer to assign new file handle to
\param pool the pool to use (NULL for new pool)
\return SWITCH_STATUS_SUCCESS if the file handle was duplicated
*/
SWITCH_DECLARE(switch_status_t) switch_core_file_handle_dup(switch_file_handle_t *oldfh, switch_file_handle_t **newfh, switch_memory_pool_t *pool);
/*!
\brief Close an open file handle
\param fh the file handle to close

View File

@ -940,6 +940,75 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_pre_close(switch_file_handle_t
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_file_handle_dup(switch_file_handle_t *oldfh, switch_file_handle_t **newfh, switch_memory_pool_t *pool)
{
switch_status_t status;
switch_file_handle_t *fh;
uint8_t destroy_pool = 0;
switch_assert(oldfh != NULL);
switch_assert(newfh != NULL);
if (!pool) {
if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) {
return status;
}
destroy_pool = 1;
}
if (!(fh = switch_core_alloc(pool, sizeof(switch_file_handle_t)))) {
switch_goto_status(SWITCH_STATUS_MEMERR, err);
}
memcpy(fh, oldfh, sizeof(switch_file_handle_t));
if (!destroy_pool) {
switch_clear_flag(fh, SWITCH_FILE_FLAG_FREE_POOL);
} else {
fh->memory_pool = pool;
switch_set_flag(fh, SWITCH_FILE_FLAG_FREE_POOL);
}
if ((status = switch_mutex_init(&fh->flag_mutex, SWITCH_MUTEX_NESTED, pool)) != SWITCH_STATUS_SUCCESS) {
switch_goto_status(status, err);
}
#define DUP_CHECK(dup) if (oldfh->dup && !(fh->dup = switch_core_strdup(pool, oldfh->dup))) {switch_goto_status(SWITCH_STATUS_MEMERR, err);}
DUP_CHECK(prefix);
DUP_CHECK(modname);
DUP_CHECK(mm.auth_username);
DUP_CHECK(mm.auth_password);
DUP_CHECK(stream_name);
DUP_CHECK(file_path);
DUP_CHECK(handler);
DUP_CHECK(spool_path);
fh->pre_buffer_data = NULL;
if (oldfh->pre_buffer_data) {
switch_size_t pre_buffer_data_size = oldfh->pre_buffer_datalen * oldfh->channels;
if (pre_buffer_data_size) {
if (!(fh->pre_buffer_data = switch_core_alloc(pool, pre_buffer_data_size))) {
switch_goto_status(SWITCH_STATUS_MEMERR, err);
}
memcpy(fh->pre_buffer_data, oldfh->pre_buffer_data, pre_buffer_data_size);
}
}
*newfh = fh;
return SWITCH_STATUS_SUCCESS;
err:
if (destroy_pool) {
switch_core_destroy_memory_pool(&pool);
}
return status;
}
SWITCH_DECLARE(switch_status_t) switch_core_file_close(switch_file_handle_t *fh)
{
switch_status_t status = SWITCH_STATUS_SUCCESS;

View File

@ -1038,7 +1038,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_flush_all(switch_core_sess
SWITCH_DECLARE(switch_status_t) switch_core_media_bug_transfer_callback(switch_core_session_t *orig_session, switch_core_session_t *new_session,
switch_media_bug_callback_t callback, void * (*user_data_dup_func) (switch_core_session_t *, void *))
{
switch_media_bug_t *new_bug = NULL, *cur = NULL, *bp = NULL, *last = NULL;
switch_media_bug_t *new_bug = NULL, *cur = NULL, *bp = NULL, *last = NULL, *old_last_next = NULL, *old_bugs = NULL;
int total = 0;
if (!switch_channel_media_ready(new_session->channel)) {
@ -1054,19 +1054,36 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_transfer_callback(switch_c
if (cur->callback == callback) {
if (last) {
old_last_next = last->next;
last->next = cur->next;
} else {
old_bugs = orig_session->bugs;
orig_session->bugs = cur->next;
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(orig_session), SWITCH_LOG_DEBUG, "Transfering %s from %s to %s\n", cur->target,
switch_core_session_get_name(orig_session), switch_core_session_get_name(new_session));
switch_core_media_bug_add(new_session, cur->function, cur->target, cur->callback,
user_data_dup_func(new_session, cur->user_data),
cur->stop_time, cur->flags, &new_bug);
switch_core_media_bug_destroy(&cur);
total++;
if ((switch_core_media_bug_add(new_session, cur->function, cur->target, cur->callback,
user_data_dup_func(new_session, cur->user_data),
cur->stop_time, cur->flags, &new_bug) == SWITCH_STATUS_SUCCESS)) {
switch_core_media_bug_destroy(&cur);
total++;
} else {
/* Call the dup function again to revert to original session */
user_data_dup_func(orig_session, cur->user_data);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(orig_session), SWITCH_LOG_DEBUG, "Adding a bug failed: abort transfering %s from %s to %s\n", cur->target,
switch_core_session_get_name(orig_session), switch_core_session_get_name(new_session));
/* Put the old bug back to the original session's list of bugs */
if (last) {
last->next = old_last_next;
} else {
orig_session->bugs = old_bugs;
}
last = cur;
}
} else {
last = cur;
}

View File

@ -1123,6 +1123,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_displace_session(switch_core_session_
struct record_helper {
switch_media_bug_t *bug;
switch_memory_pool_t *helper_pool;
switch_core_session_t *recording_session;
switch_core_session_t *transfer_from_session;
uint8_t transfer_complete;
char *file;
switch_file_handle_t *fh;
switch_file_handle_t in_fh;
@ -1146,6 +1151,7 @@ struct record_helper {
switch_thread_t *thread;
switch_mutex_t *buffer_mutex;
int thread_ready;
uint8_t thread_needs_transfer;
uint32_t writes;
uint32_t vwrites;
const char *completion_cause;
@ -1153,6 +1159,8 @@ struct record_helper {
switch_event_t *variables;
};
static switch_status_t record_helper_destroy(struct record_helper **rh, switch_core_session_t *session);
/**
* Set the recording completion cause. The cause can only be set once, to minimize the logic in the record_callback.
* [The completion_cause strings are essentially those of an MRCP Recorder resource.]
@ -1257,9 +1265,29 @@ static void *SWITCH_THREAD_FUNC recording_thread(switch_thread_t *thread, void *
rh->thread_ready = 1;
channels = switch_core_media_bug_test_flag(bug, SMBF_STEREO) ? 2 : rh->read_impl.number_of_channels;
data = switch_core_session_alloc(session, SWITCH_RECOMMENDED_BUFFER_SIZE);
data = switch_core_alloc(rh->helper_pool, SWITCH_RECOMMENDED_BUFFER_SIZE);
while(switch_test_flag(rh->fh, SWITCH_FILE_OPEN)) {
if (rh->thread_needs_transfer) {
assert(session != rh->recording_session);
if (switch_core_session_read_lock(rh->recording_session) != SWITCH_STATUS_SUCCESS) {
continue;
}
switch_core_session_rwunlock(session);
session = rh->recording_session;
channel = switch_core_session_get_channel(session);
bug = rh->bug;
channels = switch_core_media_bug_test_flag(bug, SMBF_STEREO) ? 2 : rh->read_impl.number_of_channels;
/* Tell record_callback that we transferred */
rh->thread_needs_transfer = 0;
/* Erasing the obj variable for safety because we transferred (we are under another bug) */
obj = NULL;
}
if (switch_core_file_has_video(rh->fh, SWITCH_TRUE)) {
switch_core_session_get_read_impl(session, &read_impl);
if (read_impl.decoded_bytes_per_packet > 0 && read_impl.decoded_bytes_per_packet <= SWITCH_RECOMMENDED_BUFFER_SIZE) {
@ -1309,22 +1337,71 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s
int mask = switch_core_media_bug_test_flag(bug, SMBF_MASK);
unsigned char null_data[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0};
/* Check if the recording was transferred (see recording_follow_transfer) */
if (rh->recording_session != session) {
return SWITCH_FALSE;
}
switch (type) {
case SWITCH_ABC_TYPE_INIT:
{
const char *var = switch_channel_get_variable(channel, "RECORD_USE_THREAD");
switch_core_session_get_read_impl(session, &rh->read_impl);
/* Check if recording is transferred from another session */
if (rh->transfer_from_session && rh->transfer_from_session != rh->recording_session) {
/* If there is a thread, we need to re-initiate it */
if (rh->thread_ready) {
switch_media_bug_t *oldbug = rh->bug;
int sanity = 200;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Re-initiating recording thread for file %s\n", rh->file);
rh->bug = bug;
rh->thread_needs_transfer = 1;
while (--sanity > 0 && rh->thread_needs_transfer) {
switch_yield(10000);
}
/* Check if the thread reacted on the transfer */
if (rh->thread_needs_transfer) {
/* Thread did not react, assuming it is cond_wait'ing */
rh->bug = oldbug;
switch_core_session_get_read_impl(rh->transfer_from_session, &rh->read_impl);
rh->thread_needs_transfer = 0;
return SWITCH_FALSE;
}
}
if (rh->fh) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Record session sample rate: %d -> %d\n", rh->fh->native_rate, rh->fh->samplerate);
rh->fh->native_rate = rh->read_impl.actual_samples_per_second;
if (switch_core_file_has_video(rh->fh, SWITCH_TRUE)) {
switch_core_media_bug_set_media_params(bug, &rh->fh->mm);
}
}
rh->transfer_from_session = NULL;
rh->transfer_complete = 1;
break;
}
/* Required for potential record_transfer */
rh->bug = bug;
if (!rh->native && rh->fh && (zstr(var) || switch_true(var))) {
switch_threadattr_t *thd_attr = NULL;
switch_memory_pool_t *pool = switch_core_session_get_pool(session);
int sanity = 200;
switch_core_session_get_read_impl(session, &rh->read_impl);
switch_mutex_init(&rh->buffer_mutex, SWITCH_MUTEX_NESTED, pool);
switch_threadattr_create(&thd_attr, pool);
switch_mutex_init(&rh->buffer_mutex, SWITCH_MUTEX_NESTED, rh->helper_pool);
switch_threadattr_create(&thd_attr, rh->helper_pool);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_thread_create(&rh->thread, thd_attr, recording_thread, bug, pool);
switch_thread_create(&rh->thread, thd_attr, recording_thread, bug, rh->helper_pool);
while(--sanity > 0 && !rh->thread_ready) {
switch_yield(10000);
@ -1346,7 +1423,6 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s
rh->speech_detected = SWITCH_FALSE;
rh->completion_cause = NULL;
switch_core_session_get_read_impl(session, &rh->read_impl);
if (rh->fh) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Record session sample rate: %d -> %d\n", rh->fh->native_rate, rh->fh->samplerate);
rh->fh->native_rate = rh->read_impl.actual_samples_per_second;
@ -1354,7 +1430,6 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s
switch_core_media_bug_set_media_params(bug, &rh->fh->mm);
}
}
}
break;
case SWITCH_ABC_TYPE_TAP_NATIVE_READ:
@ -1483,6 +1558,8 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s
switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
}
send_record_stop_event(channel, &read_impl, rh);
record_helper_destroy(&rh, session);
return SWITCH_FALSE;
}
}
@ -1558,7 +1635,7 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s
}
record_helper_destroy(&rh, session);
}
break;
@ -1779,20 +1856,19 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_stop_record_session(switch_core_sessi
static void* switch_ivr_record_user_data_dup(switch_core_session_t *session, void *user_data)
{
struct record_helper *rh = (struct record_helper *) user_data, *dup = NULL;
struct record_helper *rh = (struct record_helper *) user_data;
dup = switch_core_session_alloc(session, sizeof(*dup));
memcpy(dup, rh, sizeof(*rh));
dup->file = switch_core_session_strdup(session, rh->file);
dup->fh = switch_core_session_alloc(session, sizeof(switch_file_handle_t));
memcpy(dup->fh, rh->fh, sizeof(switch_file_handle_t));
dup->variables = NULL;
if (rh->variables) {
switch_event_dup(&dup->variables, rh->variables);
switch_event_safe_destroy(rh->variables);
if (!rh->transfer_complete && session == rh->transfer_from_session) {
/* Transfer failed and now we are called to put the original session back */
rh->recording_session = rh->transfer_from_session;
rh->transfer_from_session = NULL;
} else {
rh->transfer_from_session = rh->recording_session;
rh->recording_session = session;
rh->transfer_complete = 0;
}
return dup;
return rh;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_transfer_recordings(switch_core_session_t *orig_session, switch_core_session_t *new_session)
@ -2613,6 +2689,58 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session
return status;
}
static switch_status_t record_helper_create(struct record_helper **rh, switch_core_session_t *session)
{
switch_status_t status;
switch_memory_pool_t *pool;
struct record_helper *newrh;
assert(rh);
assert(session);
if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) {
return status;
}
if (!(newrh = switch_core_alloc(pool, sizeof(*newrh)))) {
switch_core_destroy_memory_pool(&pool);
return SWITCH_STATUS_MEMERR;
}
newrh->helper_pool = pool;
newrh->recording_session = session;
*rh = newrh;
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t record_helper_destroy(struct record_helper **rh, switch_core_session_t *session)
{
switch_memory_pool_t *pool;
assert(rh);
assert(*rh);
assert(session);
if ((*rh)->recording_session != session) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Destroying a record helper of another session!\n");
}
if ((*rh)->native) {
switch_core_file_close(&(*rh)->in_fh);
switch_core_file_close(&(*rh)->out_fh);
} else if((*rh)->fh) {
switch_core_file_close((*rh)->fh);
}
pool = (*rh)->helper_pool;
switch_core_destroy_memory_pool(&pool);
*rh = NULL;
return SWITCH_STATUS_SUCCESS;
}
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);
@ -2648,7 +2776,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_true(switch_channel_get_variable(channel, "RECORD_TOGGLE_ON_REPEAT"))) {
if (switch_channel_var_true(channel, "RECORD_TOGGLE_ON_REPEAT")) {
return switch_ivr_stop_record_session(session, file);
}
@ -2657,7 +2785,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess
}
if ((p = switch_channel_get_variable(channel, "RECORD_CHECK_BRIDGE")) && switch_true(p)) {
if (switch_channel_var_true(channel, "RECORD_CHECK_BRIDGE")) {
switch_core_session_t *other_session;
int exist = 0;
switch_status_t rstatus = SWITCH_STATUS_SUCCESS;
@ -2680,45 +2808,57 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess
}
}
if (!fh) {
if (!(fh = switch_core_session_alloc(session, sizeof(*fh)))) {
return SWITCH_STATUS_MEMERR;
if ((status = record_helper_create(&rh, session)) != SWITCH_STATUS_SUCCESS) {
return status;
}
if (fh) {
switch_file_handle_t *newfh;
if ((status = switch_core_file_handle_dup(fh, &newfh, rh->helper_pool)) != SWITCH_STATUS_SUCCESS) {
switch_goto_status(status, err);
}
fh = newfh;
} else {
if (!(fh = switch_core_alloc(rh->helper_pool, sizeof(*fh)))) {
switch_goto_status(SWITCH_STATUS_MEMERR, err);
}
}
if ((p = switch_channel_get_variable(channel, "RECORD_WRITE_ONLY")) && switch_true(p)) {
if (switch_channel_var_true(channel, "RECORD_WRITE_ONLY")) {
flags &= ~SMBF_READ_STREAM;
flags |= SMBF_WRITE_STREAM;
}
if ((p = switch_channel_get_variable(channel, "RECORD_READ_ONLY")) && switch_true(p)) {
if (switch_channel_var_true(channel, "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 ((p = switch_channel_get_variable(channel, "RECORD_STEREO")) && switch_true(p)) {
if (switch_channel_var_true(channel, "RECORD_STEREO")) {
flags |= SMBF_STEREO;
flags &= ~SMBF_STEREO_SWAP;
channels = 2;
}
if ((p = switch_channel_get_variable(channel, "RECORD_STEREO_SWAP")) && switch_true(p)) {
if (switch_channel_var_true(channel, "RECORD_STEREO_SWAP")) {
flags |= SMBF_STEREO;
flags |= SMBF_STEREO_SWAP;
channels = 2;
}
}
if ((p = switch_channel_get_variable(channel, "RECORD_ANSWER_REQ")) && switch_true(p)) {
if (switch_channel_var_true(channel, "RECORD_ANSWER_REQ")) {
flags |= SMBF_ANSWER_REQ;
}
if ((p = switch_channel_get_variable(channel, "RECORD_BRIDGE_REQ")) && switch_true(p)) {
if (switch_channel_var_true(channel, "RECORD_BRIDGE_REQ")) {
flags |= SMBF_BRIDGE_REQ;
}
if ((p = switch_channel_get_variable(channel, "RECORD_APPEND")) && switch_true(p)) {
if (switch_channel_var_true(channel, "RECORD_APPEND")) {
file_flags |= SWITCH_FILE_WRITE_APPEND;
}
@ -2739,8 +2879,6 @@ 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"))) {
int tmp = atoi(vval);
@ -2754,7 +2892,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess
fh->pre_buffer_datalen = SWITCH_DEFAULT_FILE_BUFFER_LEN;
}
if (!switch_is_file_path(file)) {
char *tfile = NULL;
char *e;
@ -2767,7 +2904,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess
}
if (*file == '[') {
tfile = switch_core_session_strdup(session, file);
tfile = switch_core_strdup(rh->helper_pool, file);
if ((e = switch_find_end_paren(tfile, '[', ']'))) {
*e = '\0';
file = e + 1;
@ -2775,17 +2912,17 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess
tfile = NULL;
}
} else {
file_path = switch_core_session_sprintf(session, "%s%s%s", prefix, SWITCH_PATH_SEPARATOR, file);
file_path = switch_core_sprintf(rh->helper_pool, "%s%s%s", prefix, SWITCH_PATH_SEPARATOR, file);
}
file = switch_core_session_sprintf(session, "%s%s%s%s%s", switch_str_nil(tfile), tfile ? "]" : "", prefix, SWITCH_PATH_SEPARATOR, file);
file = switch_core_sprintf(rh->helper_pool, "%s%s%s%s%s", switch_str_nil(tfile), tfile ? "]" : "", prefix, SWITCH_PATH_SEPARATOR, file);
} else {
file_path = switch_core_session_strdup(session, file);
file_path = switch_core_strdup(rh->helper_pool, file);
}
if (file_path && !strstr(file_path, SWITCH_URL_SEPARATOR)) {
char *p;
char *path = switch_core_session_strdup(session, file_path);
char *path = switch_core_strdup(rh->helper_pool, file_path);
if ((p = strrchr(path, *SWITCH_PATH_SEPARATOR))) {
*p = '\0';
@ -2796,7 +2933,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess
if (switch_dir_make_recursive(path, SWITCH_DEFAULT_DIR_PERMS, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error creating %s\n", path);
return SWITCH_STATUS_GENERR;
switch_goto_status(SWITCH_STATUS_GENERR, err);
}
} else {
@ -2805,8 +2942,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess
}
}
rh = switch_core_session_alloc(session, sizeof(*rh));
if ((ext = strrchr(file, '.'))) {
ext++;
@ -2820,7 +2955,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
}
return SWITCH_STATUS_GENERR;
switch_goto_status(SWITCH_STATUS_GENERR, err);
}
if (fh->params) {
@ -2859,8 +2994,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess
ext = read_impl.iananame;
in_file = switch_core_session_sprintf(session, "%s-in.%s", file, ext);
out_file = switch_core_session_sprintf(session, "%s-out.%s", file, ext);
in_file = switch_core_sprintf(rh->helper_pool, "%s-in.%s", file, ext);
out_file = switch_core_sprintf(rh->helper_pool, "%s-out.%s", file, ext);
rh->in_fh.pre_buffer_datalen = rh->out_fh.pre_buffer_datalen = fh->pre_buffer_datalen;
channels = 1;
switch_set_flag(&rh->in_fh, SWITCH_FILE_NATIVE);
@ -2872,7 +3007,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
}
return SWITCH_STATUS_GENERR;
switch_goto_status(SWITCH_STATUS_GENERR, err);
}
if (switch_core_file_open(&rh->out_fh, out_file, channels, read_impl.actual_samples_per_second, file_flags, NULL) != SWITCH_STATUS_SUCCESS) {
@ -2882,7 +3017,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
}
return SWITCH_STATUS_GENERR;
switch_goto_status(SWITCH_STATUS_GENERR, err);
}
rh->native = 1;
@ -2899,40 +3034,38 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess
flags = tflags;
}
if ((p = switch_channel_get_variable(channel, "RECORD_TITLE"))) {
vval = (const char *) switch_core_session_strdup(session, p);
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"))) {
vval = (const char *) switch_core_session_strdup(session, p);
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"))) {
vval = (const char *) switch_core_session_strdup(session, p);
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"))) {
vval = (const char *) switch_core_session_strdup(session, p);
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"))) {
vval = (const char *) switch_core_session_strdup(session, p);
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"))) {
vval = (const char *) switch_core_session_strdup(session, p);
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);
}
@ -2942,7 +3075,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess
}
rh->fh = fh;
rh->file = switch_core_session_strdup(session, file);
rh->file = switch_core_strdup(rh->helper_pool, file);
rh->packet_len = read_impl.decoded_bytes_per_packet;
if (file_flags & SWITCH_FILE_WRITE_APPEND) {
@ -2979,7 +3112,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess
}
}
if(vars) {
if (vars) {
switch_event_dup(&rh->variables, vars);
}
@ -2988,13 +3121,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess
if ((status = switch_core_media_bug_add(session, "session_record", file,
record_callback, rh, to, flags, &bug)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error adding media bug for file %s\n", file);
if (rh->native) {
switch_core_file_close(&rh->in_fh);
switch_core_file_close(&rh->out_fh);
} else {
switch_core_file_close(fh);
}
return status;
switch_goto_status(status, err);
}
if ((p = switch_channel_get_variable(channel, "RECORD_PRE_BUFFER_FRAMES"))) {
@ -3019,6 +3146,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_sess
}
return SWITCH_STATUS_SUCCESS;
err:
record_helper_destroy(&rh, session);
return status;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t *session, const char *file, uint32_t limit, switch_file_handle_t *fh)