From 44636d333fa1f875aa5c5e3ef0c90b540d041417 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 12 Dec 2007 21:30:55 +0000 Subject: [PATCH] sample platter git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@6706 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- src/include/switch_module_interfaces.h | 7 + src/include/switch_resample.h | 2 +- .../mod_conference/mod_conference.c | 3 + .../applications/mod_dptools/mod_dptools.c | 11 +- .../mod_local_stream/mod_local_stream.c | 73 +++++++--- .../formats/mod_native_file/mod_native_file.c | 2 +- src/mod/formats/mod_sndfile/mod_sndfile.c | 37 ++++- src/switch_core_file.c | 126 +++++++++++++++++- src/switch_core_session.c | 8 +- src/switch_ivr_play_say.c | 30 +---- src/switch_resample.c | 10 +- 11 files changed, 239 insertions(+), 70 deletions(-) diff --git a/src/include/switch_module_interfaces.h b/src/include/switch_module_interfaces.h index 0c5262717a..76a83141f6 100644 --- a/src/include/switch_module_interfaces.h +++ b/src/include/switch_module_interfaces.h @@ -40,6 +40,7 @@ #define SWITCH_MODULE_INTERFACES_H #include +#include "switch_resample.h" SWITCH_BEGIN_EXTERN_C /*! \brief A table of functions to execute at various states @@ -262,6 +263,8 @@ struct switch_file_handle { unsigned int samples; /*! the current samplerate */ uint32_t samplerate; + /*! the current native samplerate */ + uint32_t native_rate; /*! the number of channels */ uint8_t channels; /*! integer representation of the format */ @@ -289,6 +292,10 @@ struct switch_file_handle { uint32_t offset_pos; uint32_t last_pos; int32_t vol; + switch_audio_resampler_t *resampler; + switch_buffer_t *buffer; + switch_byte_t *dbuf; + switch_size_t dbuflen; }; /*! \brief Abstract interface to an asr module */ diff --git a/src/include/switch_resample.h b/src/include/switch_resample.h index 5b1c791030..747010fee1 100644 --- a/src/include/switch_resample.h +++ b/src/include/switch_resample.h @@ -91,7 +91,7 @@ SWITCH_DECLARE(switch_status_t) switch_resample_create(switch_audio_resampler_t \brief Destroy an existing resampler handle \param resampler the resampler handle to destroy */ -SWITCH_DECLARE(void) switch_resample_destroy(switch_audio_resampler_t *resampler); +SWITCH_DECLARE(void) switch_resample_destroy(switch_audio_resampler_t **resampler); /*! \brief Resample one float buffer into another using specifications of a given handle diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 521c481f72..9b2784b4b6 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -1465,6 +1465,9 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t * thread, } } + switch_resample_destroy(&member->read_resampler); + switch_resample_destroy(&member->mux_resampler); + switch_clear_flag_locked(member, MFLAG_ITHREAD); return NULL; diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index c745b0a453..94606166cc 100644 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -1239,7 +1239,9 @@ SWITCH_STANDARD_APP(record_function) int argc; char *mydata, *argv[4] = { 0 }; char *l = NULL; - + const char *tmp; + int rate; + channel = switch_core_session_get_channel(session); assert(channel != NULL); @@ -1280,6 +1282,13 @@ SWITCH_STANDARD_APP(record_function) } } + if ((tmp = switch_channel_get_variable(channel, "record_rate"))) { + rate = atoi(tmp); + if (rate > 0) { + fh.samplerate = rate; + } + } + args.input_callback = on_dtmf; status = switch_ivr_record_file(session, &fh, path, &args, limit); diff --git a/src/mod/formats/mod_local_stream/mod_local_stream.c b/src/mod/formats/mod_local_stream/mod_local_stream.c index b687bc206c..a9bf2e7c67 100644 --- a/src/mod/formats/mod_local_stream/mod_local_stream.c +++ b/src/mod/formats/mod_local_stream/mod_local_stream.c @@ -79,7 +79,7 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void local_stream_context_t *cp; char file_buf[128] = "", path_buf[512] = ""; switch_timer_t timer = {0}; - + int fd = -1; if (switch_core_timer_init(&timer, source->timer_name, source->interval, source->samples, source->pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't start timer.\n"); @@ -89,7 +89,7 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void while(RUNNING) { const char *fname; - + if (switch_dir_open(&source->dir_handle, source->location, source->pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Can't open directory: %s\n", source->location); return NULL; @@ -98,27 +98,37 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "open directory: %s\n", source->location); switch_yield(1000000); - while(RUNNING && (fname = switch_dir_next_file(source->dir_handle, file_buf, sizeof(file_buf)))) { + while(RUNNING) { switch_size_t olen; uint8_t abuf[SWITCH_RECOMMENDED_BUFFER_SIZE] = {0}; - snprintf(path_buf, sizeof(path_buf), "%s%s%s", source->location, SWITCH_PATH_SEPARATOR, fname); - if (switch_stristr(".loc", path_buf)) { - int fd, bytes; + if (fd > -1) { char *p; + if (switch_fd_read_line(fd, path_buf, sizeof(path_buf))) { + if ((p = strchr(path_buf, '\r')) || + (p = strchr(path_buf, '\n'))) { + *p = '\0'; + } + } else { + close(fd); + fd = -1; + continue; + } + } else { + if (!(fname = switch_dir_next_file(source->dir_handle, file_buf, sizeof(file_buf)))) { + break; + } - if ((fd = open(path_buf, O_RDONLY)) < 0) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", fname); - switch_yield(1000000); + snprintf(path_buf, sizeof(path_buf), "%s%s%s", source->location, SWITCH_PATH_SEPARATOR, fname); + + if (switch_stristr(".loc", path_buf)) { + if ((fd = open(path_buf, O_RDONLY)) < 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s\n", fname); + switch_yield(1000000); + } continue; } - bytes = read(fd, path_buf, sizeof(path_buf)); - if ((p = strchr(path_buf, '\r')) || - (p = strchr(path_buf, '\n'))) { - *p = '\0'; - } - close(fd); } fname = path_buf; @@ -139,6 +149,7 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void while (RUNNING) { switch_core_timer_next(&timer); olen = source->samples; + if (switch_core_file_read(&fh, abuf, &olen) != SWITCH_STATUS_SUCCESS || !olen) { switch_core_file_close(&fh); break; @@ -156,8 +167,13 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void } switch_dir_close(source->dir_handle); + source->dir_handle = NULL; } + + if (fd > -1) { + close(fd); + } switch_core_destroy_memory_pool(&source->pool); @@ -168,25 +184,37 @@ static switch_status_t local_stream_file_open(switch_file_handle_t *handle, cons { local_stream_context_t *context; local_stream_source_t *source; + char *alt_path = NULL; + switch_status_t status = SWITCH_STATUS_SUCCESS; if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "This format does not support writing!\n"); return SWITCH_STATUS_FALSE; } + alt_path = switch_mprintf("%s/%d", path, handle->samplerate); + switch_mutex_lock(globals.mutex); - source = switch_core_hash_find(globals.source_hash, path); + if ((source = switch_core_hash_find(globals.source_hash, alt_path))) { + path = alt_path; + } else { + source = switch_core_hash_find(globals.source_hash, path); + } switch_mutex_unlock(globals.mutex); if (!source) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "unknown source %s\n", path); - return SWITCH_STATUS_FALSE; + status = SWITCH_STATUS_FALSE; + goto end; } if ((context = switch_core_alloc(handle->memory_pool, sizeof(*context))) == 0) { - return SWITCH_STATUS_MEMERR; + status = SWITCH_STATUS_MEMERR; + goto end; } + + handle->samples = 0; handle->samplerate = source->rate; handle->channels = source->channels; @@ -201,7 +229,8 @@ static switch_status_t local_stream_file_open(switch_file_handle_t *handle, cons switch_mutex_init(&context->audio_mutex, SWITCH_MUTEX_NESTED, handle->memory_pool); if (switch_buffer_create_dynamic(&context->audio_buffer, 512, 1024, 0) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n"); - return SWITCH_STATUS_MEMERR; + status = SWITCH_STATUS_MEMERR; + goto end; } context->source = source; @@ -211,8 +240,9 @@ static switch_status_t local_stream_file_open(switch_file_handle_t *handle, cons source->context_list = context; switch_mutex_unlock(source->mutex); - - return SWITCH_STATUS_SUCCESS; + end: + switch_safe_free(alt_path); + return status; } static switch_status_t local_stream_file_close(switch_file_handle_t *handle) @@ -350,6 +380,7 @@ static void launch_threads(void) } source->samples = switch_bytes_per_frame(source->rate, source->interval); + switch_core_hash_insert(globals.source_hash, source->name, source); switch_mutex_init(&source->mutex, SWITCH_MUTEX_NESTED, source->pool); 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 8572a2ce13..a3fda415a1 100644 --- a/src/mod/formats/mod_native_file/mod_native_file.c +++ b/src/mod/formats/mod_native_file/mod_native_file.c @@ -26,7 +26,7 @@ * Anthony Minessale II * * - * mod_native_file.c -- Framework Demo Module + * mod_native_file.c -- Native Files * */ #include diff --git a/src/mod/formats/mod_sndfile/mod_sndfile.c b/src/mod/formats/mod_sndfile/mod_sndfile.c index cc29445523..2b7538f045 100644 --- a/src/mod/formats/mod_sndfile/mod_sndfile.c +++ b/src/mod/formats/mod_sndfile/mod_sndfile.c @@ -61,6 +61,9 @@ static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const cha int mode = 0; char *ext; struct format_map *map = NULL; + switch_status_t status = SWITCH_STATUS_SUCCESS; + char *alt_path = NULL, *next, *last, *ldup = NULL; + size_t alt_len = 0; if ((ext = strrchr(path, '.')) == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Format\n"); @@ -141,11 +144,28 @@ static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const cha if ((mode & SFM_WRITE) && sf_format_check(&context->sfinfo) == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error : file format is invalid (0x%08X).\n", context->sfinfo.format); return SWITCH_STATUS_GENERR; - }; + } - if ((context->handle = sf_open(path, mode, &context->sfinfo)) == 0) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening File [%s] [%s]\n", path, sf_strerror(context->handle)); - return SWITCH_STATUS_GENERR; + alt_len = strlen(path) + 10; + switch_zmalloc(alt_path, alt_len); + + switch_copy_string(alt_path, path, alt_len); + if ((last = strrchr(alt_path, *SWITCH_PATH_SEPARATOR))) { + next = ++last; + ldup = strdup(last); + switch_assert(ldup); + switch_snprintf(next, alt_len - (last - alt_path), "%d%s%s", handle->samplerate, SWITCH_PATH_SEPARATOR, ldup); + if ((context->handle = sf_open(alt_path, mode, &context->sfinfo))) { + path = alt_path; + } + } + + if (!context->handle) { + if ((context->handle = sf_open(path, mode, &context->sfinfo)) == 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening File [%s] [%s]\n", path, sf_strerror(context->handle)); + status = SWITCH_STATUS_GENERR; + goto end; + } } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Opening File [%s] %dhz\n", path, context->sfinfo.samplerate); @@ -157,8 +177,15 @@ static switch_status_t sndfile_file_open(switch_file_handle_t *handle, const cha handle->seekable = context->sfinfo.seekable; handle->speed = 0; handle->private_info = context; + - return SWITCH_STATUS_SUCCESS; + end: + + switch_safe_free(alt_path); + switch_safe_free(ldup); + + + return status; } static switch_status_t sndfile_file_close(switch_file_handle_t *handle) diff --git a/src/switch_core_file.c b/src/switch_core_file.c index b8242757a1..6c88c8e01e 100644 --- a/src/switch_core_file.c +++ b/src/switch_core_file.c @@ -73,10 +73,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_open(switch_file_handle_t *fh, fh->handler = switch_core_strdup(fh->memory_pool, rhs); } - if (rate) { - fh->samplerate = rate; - } else { - rate = 8000; + if (!fh->samplerate) { + if (!(fh->samplerate = rate)) { + fh->samplerate = 8000; + } } if (channels) { @@ -85,25 +85,130 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_open(switch_file_handle_t *fh, fh->channels = 1; } - if ((status = fh->file_interface->file_open(fh, file_path)) == SWITCH_STATUS_SUCCESS) { - switch_set_flag(fh, SWITCH_FILE_OPEN); + if ((status = fh->file_interface->file_open(fh, file_path)) != SWITCH_STATUS_SUCCESS) { + return status; } + if ((flags & SWITCH_FILE_FLAG_READ)) { + fh->native_rate = fh->samplerate; + } else { + fh->native_rate = rate; + } + + if (fh->samplerate != rate) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Sample rate doesn't match\n"); + if ((flags & SWITCH_FILE_FLAG_READ)) { + fh->samplerate = rate; + } + } + + switch_set_flag(fh, SWITCH_FILE_OPEN); + return status; } SWITCH_DECLARE(switch_status_t) switch_core_file_read(switch_file_handle_t *fh, void *data, switch_size_t *len) { + switch_status_t status; + switch_size_t orig_len = *len; + switch_assert(fh != NULL); switch_assert(fh->file_interface != NULL); - return fh->file_interface->file_read(fh, data, len); + if (fh->buffer && switch_buffer_inuse(fh->buffer)) { + *len = switch_buffer_read(fh->buffer, data, orig_len); + return SWITCH_STATUS_SUCCESS; + } + + if ((status = fh->file_interface->file_read(fh, data, len)) != SWITCH_STATUS_SUCCESS) { + goto done; + } + + if (!switch_test_flag(fh, SWITCH_FILE_NATIVE) && fh->native_rate != fh->samplerate) { + if (!fh->resampler) { + if (switch_resample_create(&fh->resampler, + fh->native_rate, + orig_len * 10, + fh->samplerate, + orig_len * 10, + fh->memory_pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to create resampler!\n"); + return SWITCH_STATUS_GENERR; + } + } + + fh->resampler->from_len = switch_short_to_float(data, fh->resampler->from, (int) *len); + fh->resampler->to_len = + switch_resample_process(fh->resampler, fh->resampler->from, fh->resampler->from_len, fh->resampler->to, fh->resampler->to_size, 0); + + if (fh->resampler->to_len > orig_len) { + if (!fh->buffer) { + switch_buffer_create_dynamic(&fh->buffer, fh->resampler->to_len * 2, fh->resampler->to_len * 4, fh->resampler->to_len * 8); + switch_assert(fh->buffer); + } + if (!fh->dbuf) { + fh->dbuflen = fh->resampler->to_len * 2; + fh->dbuf = switch_core_alloc(fh->memory_pool, fh->dbuflen); + } + switch_assert(fh->resampler->to_len <= fh->dbuflen); + + switch_float_to_short(fh->resampler->to, (int16_t *) fh->dbuf, fh->resampler->to_len); + switch_buffer_write(fh->buffer, fh->dbuf, fh->resampler->to_len * 2); + *len = switch_buffer_read(fh->buffer, data, orig_len); + } else { + switch_float_to_short(fh->resampler->to, data, fh->resampler->to_len); + *len = fh->resampler->to_len; + } + + } + + done: + + return status; } SWITCH_DECLARE(switch_status_t) switch_core_file_write(switch_file_handle_t *fh, void *data, switch_size_t *len) { + switch_size_t orig_len = *len; + switch_assert(fh != NULL); switch_assert(fh->file_interface != NULL); + + if (!switch_test_flag(fh, SWITCH_FILE_NATIVE) && fh->native_rate != fh->samplerate) { + if (!fh->resampler) { + if (switch_resample_create(&fh->resampler, + fh->native_rate, + orig_len * 10, + fh->samplerate, + orig_len * 10, + fh->memory_pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to create resampler!\n"); + return SWITCH_STATUS_GENERR; + } + } + + fh->resampler->from_len = switch_short_to_float(data, fh->resampler->from, (int) *len); + fh->resampler->to_len = + switch_resample_process(fh->resampler, fh->resampler->from, fh->resampler->from_len, fh->resampler->to, fh->resampler->to_size, 0); + if (fh->resampler->to_len > orig_len) { + if (!fh->dbuf) { + fh->dbuflen = fh->resampler->to_len * 2; + fh->dbuf = switch_core_alloc(fh->memory_pool, fh->dbuflen); + } + switch_assert(fh->resampler->to_len <= fh->dbuflen); + switch_float_to_short(fh->resampler->to, (int16_t *) fh->dbuf, fh->resampler->to_len); + data = fh->dbuf; + } else { + switch_float_to_short(fh->resampler->to, data, fh->resampler->to_len); + } + + *len = fh->resampler->to_len; + + } + + if (!*len) { + return SWITCH_STATUS_SUCCESS; + } return fh->file_interface->file_write(fh, data, len); } @@ -151,6 +256,13 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_close(switch_file_handle_t *fh) switch_clear_flag(fh, SWITCH_FILE_OPEN); status = fh->file_interface->file_close(fh); + if (fh->buffer) { + switch_buffer_destroy(&fh->buffer); + } + + switch_resample_destroy(&fh->resampler); + + if (switch_test_flag(fh, SWITCH_FILE_FLAG_FREE_POOL)) { switch_core_destroy_memory_pool(&fh->memory_pool); } diff --git a/src/switch_core_session.c b/src/switch_core_session.c index 0783e0133b..00e6e966a9 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -566,11 +566,9 @@ SWITCH_DECLARE(void) switch_core_session_reset(switch_core_session_t *session) char buf[256]; switch_size_t has; - /* sweep theese under the rug, they wont be leaked they will be reclaimed - when the session ends. - */ - session->read_resampler = NULL; - session->write_resampler = NULL; + /* clear resamplers*/ + switch_resample_destroy(&session->read_resampler); + switch_resample_destroy(&session->write_resampler); /* clear indications */ switch_core_session_flush_message(session); diff --git a/src/switch_ivr_play_say.c b/src/switch_ivr_play_say.c index b4772dad0d..72a72acd79 100644 --- a/src/switch_ivr_play_say.c +++ b/src/switch_ivr_play_say.c @@ -348,8 +348,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se const char *vval; time_t start = 0; uint32_t org_silence_hits = 0; - switch_audio_resampler_t *resampler = NULL; - int16_t resamp_out[2048]; if (!fh) { fh = &lfh; @@ -362,27 +360,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se switch_assert(read_codec != NULL); fh->channels = read_codec->implementation->number_of_channels; + fh->native_rate = read_codec->implementation->actual_samples_per_second; - if (fh->samplerate) { - if (fh->samplerate != read_codec->implementation->actual_samples_per_second) { - if (switch_resample_create(&resampler, - read_codec->implementation->actual_samples_per_second, - read_codec->implementation->actual_samples_per_second * 20, - fh->samplerate, - fh->samplerate * 20, - switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to create resampler!\n"); - return SWITCH_STATUS_GENERR; - } - } - } else { - fh->samplerate = read_codec->implementation->actual_samples_per_second; - } if (switch_core_file_open(fh, file, fh->channels, - fh->samplerate, + read_codec->implementation->actual_samples_per_second, SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); switch_core_session_reset(session); @@ -553,18 +537,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se } } - if (!switch_test_flag(fh, SWITCH_FILE_PAUSE)) { + if (!switch_test_flag(fh, SWITCH_FILE_PAUSE) && !switch_test_flag(read_frame, SFF_CNG)) { int16_t *data = read_frame->data; len = (switch_size_t) read_frame->datalen / 2; - if (resampler) { - resampler->from_len = switch_short_to_float(read_frame->data, resampler->from, (int) len); - resampler->to_len = switch_resample_process(resampler, resampler->from, resampler->from_len, resampler->to, resampler->to_size, 0); - switch_float_to_short(resampler->to, resamp_out, read_frame->datalen); - len = resampler->to_len; - data = resamp_out; - } - if (switch_core_file_write(fh, data, &len) != SWITCH_STATUS_SUCCESS) { break; } diff --git a/src/switch_resample.c b/src/switch_resample.c index ba2d6f3f8f..0b0e604c05 100644 --- a/src/switch_resample.c +++ b/src/switch_resample.c @@ -111,11 +111,17 @@ SWITCH_DECLARE(uint32_t) switch_resample_process(switch_audio_resampler_t *resam #endif } -SWITCH_DECLARE(void) switch_resample_destroy(switch_audio_resampler_t *resampler) +SWITCH_DECLARE(void) switch_resample_destroy(switch_audio_resampler_t **resampler) { + + if (resampler && *resampler) { #ifndef DISABLE_RESAMPLE - resample_close(resampler->resampler); + if ((*resampler)->resampler) { + resample_close((*resampler)->resampler); + } #endif + *resampler = NULL; + } }