diff --git a/src/include/switch_apr.h b/src/include/switch_apr.h index e3f426e4ee..64ddbd6776 100644 --- a/src/include/switch_apr.h +++ b/src/include/switch_apr.h @@ -786,6 +786,8 @@ SWITCH_DECLARE(switch_status_t) switch_file_copy(const char *from_path, */ SWITCH_DECLARE(switch_status_t) switch_file_close(switch_file_t *thefile); +SWITCH_DECLARE(switch_status_t) switch_file_trunc(switch_file_t *thefile, int64_t offset); + SWITCH_DECLARE(switch_status_t) switch_file_lock(switch_file_t *thefile, int type); /** diff --git a/src/include/switch_core.h b/src/include/switch_core.h index cdca5308aa..61c39a0843 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -1505,6 +1505,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_get_string(_In_ switch_file_han \return SWITCH_STATUS_SUCCESS if the file handle was closed */ SWITCH_DECLARE(switch_status_t) switch_core_file_close(_In_ switch_file_handle_t *fh); + +SWITCH_DECLARE(switch_status_t) switch_core_file_truncate(switch_file_handle_t *fh, int64_t offset); + + ///\} ///\defgroup speech ASR/TTS Functions diff --git a/src/include/switch_module_interfaces.h b/src/include/switch_module_interfaces.h index d683dec7d3..118e63331f 100644 --- a/src/include/switch_module_interfaces.h +++ b/src/include/switch_module_interfaces.h @@ -262,6 +262,8 @@ struct switch_file_interface { switch_status_t (*file_open) (switch_file_handle_t *, const char *file_path); /*! function to close the file */ switch_status_t (*file_close) (switch_file_handle_t *); + /*! function to close the file */ + switch_status_t (*file_truncate) (switch_file_handle_t *, int64_t offset); /*! function to read from the file */ switch_status_t (*file_read) (switch_file_handle_t *, void *data, switch_size_t *len); /*! function to write from the file */ diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 9d2424f9b8..91d20f68e7 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1166,7 +1166,8 @@ typedef enum { SWITCH_FILE_OPEN = (1 << 11), SWITCH_FILE_CALLBACK = (1 << 12), SWITCH_FILE_DONE = (1 << 13), - SWITCH_FILE_BUFFER_DONE = (1 << 14) + SWITCH_FILE_BUFFER_DONE = (1 << 14), + SWITCH_FILE_WRITE_APPEND = (1 << 15) } switch_file_flag_enum_t; typedef uint32_t switch_file_flag_t; diff --git a/src/mod/formats/mod_native_file/mod_native_file.c b/src/mod/formats/mod_native_file/mod_native_file.c index 551a62426b..a5f42e3e87 100644 --- a/src/mod/formats/mod_native_file/mod_native_file.c +++ b/src/mod/formats/mod_native_file/mod_native_file.c @@ -57,7 +57,13 @@ static switch_status_t native_file_file_open(switch_file_handle_t *handle, const } if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { - flags |= SWITCH_FOPEN_WRITE | SWITCH_FOPEN_CREATE | SWITCH_FOPEN_TRUNCATE; + flags |= SWITCH_FOPEN_WRITE | SWITCH_FOPEN_CREATE; + if (switch_test_flag(handle, SWITCH_FILE_WRITE_APPEND)) { + flags |= SWITCH_FOPEN_READ; + } else { + flags |= SWITCH_FOPEN_TRUNCATE; + } + } if (switch_test_flag(handle, SWITCH_FILE_FLAG_READ)) { @@ -69,6 +75,12 @@ static switch_status_t native_file_file_open(switch_file_handle_t *handle, const return SWITCH_STATUS_GENERR; } + if (switch_test_flag(handle, SWITCH_FILE_WRITE_APPEND)) { + int64_t samples = 0; + switch_file_seek(context->fd, SEEK_END, &samples); + handle->pos = samples; + } + handle->samples = 0; handle->samplerate = 8000; handle->channels = 1; @@ -84,6 +96,19 @@ static switch_status_t native_file_file_open(switch_file_handle_t *handle, const return SWITCH_STATUS_SUCCESS; } +static switch_status_t native_file_file_truncate(switch_file_handle_t *handle, int64_t offset) +{ + native_file_context *context = handle->private_info; + switch_status_t status; + + if ((status = switch_file_trunc(context->fd, offset)) == SWITCH_STATUS_SUCCESS) { + handle->pos = 0; + } + + return status; + +} + static switch_status_t native_file_file_close(switch_file_handle_t *handle) { native_file_context *context = handle->private_info; @@ -161,6 +186,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_native_file_load) file_interface->extens = supported_formats; file_interface->file_open = native_file_file_open; file_interface->file_close = native_file_file_close; + file_interface->file_truncate = native_file_file_truncate; file_interface->file_read = native_file_file_read; file_interface->file_write = native_file_file_write; file_interface->file_seek = native_file_file_seek; diff --git a/src/mod/formats/mod_shout/mod_shout.c b/src/mod/formats/mod_shout/mod_shout.c index ef6f156568..a33b5ca4c3 100644 --- a/src/mod/formats/mod_shout/mod_shout.c +++ b/src/mod/formats/mod_shout/mod_shout.c @@ -626,6 +626,9 @@ static switch_status_t shout_file_open(switch_file_handle_t *handle, const char } } else if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { + if (switch_test_flag(handle, SWITCH_FILE_WRITE_APPEND)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Appending to MP3 not supported.\n"); + } if (!(context->gfp = lame_init())) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate lame\n"); goto error; diff --git a/src/mod/formats/mod_sndfile/mod_sndfile.c b/src/mod/formats/mod_sndfile/mod_sndfile.c index 896f711a2b..150a4e405d 100644 --- a/src/mod/formats/mod_sndfile/mod_sndfile.c +++ b/src/mod/formats/mod_sndfile/mod_sndfile.c @@ -83,7 +83,11 @@ static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const cha } if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { - mode += SFM_WRITE; + if (switch_test_flag(handle, SWITCH_FILE_WRITE_APPEND)) { + mode += SFM_RDWR; + } else { + mode += SFM_WRITE; + } } if (!mode) { @@ -98,8 +102,6 @@ static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const cha map = switch_core_hash_find(globals.format_hash, ext); if (mode & SFM_WRITE) { - sf_count_t frames = 0; - context->sfinfo.channels = handle->channels; context->sfinfo.samplerate = handle->samplerate; if (handle->samplerate == 8000 || handle->samplerate == 16000 || @@ -107,8 +109,6 @@ static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const cha handle->samplerate == 11025 || handle->samplerate == 22050 || handle->samplerate == 44100) { context->sfinfo.format |= SF_FORMAT_PCM_16; } - - sf_command(context->handle, SFC_FILE_TRUNCATE, &frames, sizeof(frames)); } if (map) { @@ -206,6 +206,14 @@ static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const cha handle->speed = 0; handle->private_info = context; + if (switch_test_flag(handle, SWITCH_FILE_WRITE_APPEND)) { + handle->pos = sf_seek(context->handle, 0, SEEK_END); + } else { + sf_count_t frames = 0; + sf_command(context->handle, SFC_FILE_TRUNCATE, &frames, sizeof(frames)); + } + + end: switch_safe_free(alt_path); @@ -214,6 +222,14 @@ static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const cha return status; } +static switch_status_t sndfile_file_truncate(switch_file_handle_t *handle, int64_t offset) +{ + sndfile_context *context = handle->private_info; + sf_command(context->handle, SFC_FILE_TRUNCATE, &offset, sizeof(offset)); + handle->pos = 0; + return SWITCH_STATUS_SUCCESS; +} + static switch_status_t sndfile_file_close(switch_file_handle_t *handle) { sndfile_context *context = handle->private_info; @@ -416,6 +432,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sndfile_load) file_interface->extens = supported_formats; file_interface->file_open = sndfile_file_open; file_interface->file_close = sndfile_file_close; + file_interface->file_truncate = sndfile_file_truncate; file_interface->file_read = sndfile_file_read; file_interface->file_write = sndfile_file_write; file_interface->file_seek = sndfile_file_seek; diff --git a/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c b/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c index 7281e0f573..c5fd2ccd0c 100644 --- a/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c +++ b/src/mod/languages/mod_spidermonkey/mod_spidermonkey.c @@ -1247,6 +1247,8 @@ static switch_status_t js_stream_input_callback(switch_core_session_t *session, switch_set_flag(fh, SWITCH_FILE_PAUSE); } return SWITCH_STATUS_SUCCESS; + } else if (!strcasecmp(ret, "truncate")) { + switch_core_file_truncate(fh, 0); } else if (!strcasecmp(ret, "restart")) { uint32_t pos = 0; fh->speed = 0; diff --git a/src/switch_apr.c b/src/switch_apr.c index 35bf67c69b..47a21d022f 100644 --- a/src/switch_apr.c +++ b/src/switch_apr.c @@ -420,6 +420,11 @@ SWITCH_DECLARE(switch_status_t) switch_file_close(switch_file_t *thefile) return apr_file_close(thefile); } +SWITCH_DECLARE(switch_status_t) switch_file_trunc(switch_file_t *thefile, int64_t offset) +{ + return apr_file_trunc(thefile, offset); +} + SWITCH_DECLARE(switch_status_t) switch_file_lock(switch_file_t *thefile, int type) { return apr_file_lock(thefile, type); diff --git a/src/switch_core_file.c b/src/switch_core_file.c index bc8f64b7f1..5daf3f8ba2 100644 --- a/src/switch_core_file.c +++ b/src/switch_core_file.c @@ -475,6 +475,36 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_get_string(switch_file_handle_t return fh->file_interface->file_get_string(fh, col, string); } +SWITCH_DECLARE(switch_status_t) switch_core_file_truncate(switch_file_handle_t *fh, int64_t offset) +{ + switch_status_t status; + + switch_assert(fh != NULL); + switch_assert(fh->file_interface != NULL); + + if (!(switch_test_flag(fh, SWITCH_FILE_OPEN) && switch_test_flag(fh, SWITCH_FILE_FLAG_WRITE))) { + return SWITCH_STATUS_FALSE; + } + + if (!fh->file_interface->file_truncate) { + return SWITCH_STATUS_FALSE; + } + + if ((status=fh->file_interface->file_truncate(fh, offset)) == SWITCH_STATUS_SUCCESS) { + if (fh->buffer) { + switch_buffer_zero(fh->buffer); + } + if (fh->pre_buffer) { + switch_buffer_zero(fh->pre_buffer); + } + fh->samples_out = 0; + fh->pos = 0; + } + + return status; + +} + SWITCH_DECLARE(switch_status_t) switch_core_file_close(switch_file_handle_t *fh) { switch_status_t status; diff --git a/src/switch_cpp.cpp b/src/switch_cpp.cpp index 5d746ff98c..db0b385680 100644 --- a/src/switch_cpp.cpp +++ b/src/switch_cpp.cpp @@ -1275,6 +1275,8 @@ SWITCH_DECLARE(switch_status_t) CoreSession::process_callback_result(char *resul return SWITCH_STATUS_SUCCESS; } else if (!strcasecmp(result, "stop")) { return SWITCH_STATUS_FALSE; + } else if (!strcasecmp(result, "truncate")) { + switch_core_file_truncate(fhp, 0); } else if (!strcasecmp(result, "restart")) { unsigned int pos = 0; fhp->speed = 0; diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index 428f0f49f4..337dc69167 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -879,7 +879,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t uint8_t channels; switch_codec_implementation_t read_impl = {0}; struct record_helper *rh = NULL; - + int file_flags = SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT; + switch_core_session_get_read_impl(session, &read_impl); if ((status = switch_channel_pre_answer(channel)) != SWITCH_STATUS_SUCCESS) { @@ -922,6 +923,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t flags |= SMBF_ANSWER_REQ; } + if ((p = switch_channel_get_variable(channel, "RECORD_APPEND")) && switch_true(p)) { + file_flags |= SWITCH_FILE_WRITE_APPEND; + } + fh->samplerate = 0; if ((vval = switch_channel_get_variable(channel, "record_sample_rate"))) { @@ -971,7 +976,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t file, channels, read_impl.actual_samples_per_second, - SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) { + file_flags, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error opening %s\n", file); switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE); diff --git a/src/switch_ivr_play_say.c b/src/switch_ivr_play_say.c index 3c22a624a6..48a63f6116 100644 --- a/src/switch_ivr_play_say.c +++ b/src/switch_ivr_play_say.c @@ -398,6 +398,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se unsigned char write_buf[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 }; switch_event_t *event; int divisor = 0; + int file_flags = SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT; switch_core_session_get_read_impl(session, &read_impl); @@ -505,11 +506,16 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se fh->pre_buffer_datalen = SWITCH_DEFAULT_FILE_BUFFER_LEN; } + if ((p = switch_channel_get_variable(channel, "RECORD_APPEND")) && switch_true(p)) { + file_flags |= SWITCH_FILE_WRITE_APPEND; + } + + if (switch_core_file_open(fh, file, fh->channels, read_impl.actual_samples_per_second, - SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) { + file_flags, NULL) != SWITCH_STATUS_SUCCESS) { switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE); return SWITCH_STATUS_GENERR;