sample platter

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@6706 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Anthony Minessale 2007-12-12 21:30:55 +00:00
parent 2ff5e3ec40
commit 44636d333f
11 changed files with 239 additions and 70 deletions

View File

@ -40,6 +40,7 @@
#define SWITCH_MODULE_INTERFACES_H
#include <switch.h>
#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 */

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -26,7 +26,7 @@
* Anthony Minessale II <anthmct@yahoo.com>
*
*
* mod_native_file.c -- Framework Demo Module
* mod_native_file.c -- Native Files
*
*/
#include <switch.h>

View File

@ -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)

View File

@ -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);
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}
}