replace the resampler code with the awesome code from speex

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@12003 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Anthony Minessale 2009-02-13 23:35:17 +00:00
parent 86abd55aa1
commit c31a7f2563
5 changed files with 82 additions and 118 deletions

View File

@ -42,7 +42,7 @@
#ifndef SWITCH_RESAMPLE_H
#define SWITCH_RESAMPLE_H
#define SWITCH_RESAMPLE_QUALITY 0
#include <switch.h>
SWITCH_BEGIN_EXTERN_C
/*!
@ -51,7 +51,7 @@ SWITCH_BEGIN_EXTERN_C
\{
*/
/*! \brief An audio resampling handle */
typedef struct {
typedef struct {
/*! a pointer to store the resampler object */
void *resampler;
/*! the rate to resample from in hz */
@ -61,35 +61,29 @@ SWITCH_BEGIN_EXTERN_C
/*! the factor to resample by (from / to) */
double factor;
double rfactor;
/*! a pointer to store a float buffer for data to be resampled */
float *from;
/*! the size of the from buffer used */
int from_len;
/*! the total size of the from buffer */
switch_size_t from_size;
/*! a pointer to store a float buffer for resampled data */
float *to;
/*! the size of the to buffer used */
uint32_t to_len;
/*! the total size of the to buffer */
uint32_t to_size;
int16_t *to;
/*! the size of the to buffer used */
uint32_t to_len;
/*! the total size of the to buffer */
uint32_t to_size;
} switch_audio_resampler_t;
/*!
\brief Prepare a new resampler handle
\param new_resampler NULL pointer to aim at the new handle
\param from_rate the rate to transfer from in hz
\param from_size the size of the buffer to allocate for the from data
\param to_rate the rate to transfer to in hz
\param to_size the size of the buffer to allocate for the to data
\param pool the memory pool to use for buffer allocation
\param quality the quality desired
\return SWITCH_STATUS_SUCCESS if the handle was created
*/
SWITCH_DECLARE(switch_status_t) switch_resample_perform_create(switch_audio_resampler_t **new_resampler,
int from_rate, switch_size_t from_size, int to_rate,
uint32_t to_size, switch_memory_pool_t *pool, const char *file, const char *func, int line);
uint32_t from_rate, uint32_t to_rate, uint32_t to_size,
int quality,
const char *file, const char *func, int line);
#define switch_resample_create(_n, _fr, _fs, _tr, _ts, _p) switch_resample_perform_create(_n, _fr, _fs, _tr, _ts, _p, __FILE__, __SWITCH_FUNC__, __LINE__)
#define switch_resample_create(_n, _fr, _tr, _ts, _q) switch_resample_perform_create(_n, _fr, _tr, _ts, _q, __FILE__, __SWITCH_FUNC__, __LINE__)
/*!
\brief Destroy an existing resampler handle
@ -102,12 +96,10 @@ SWITCH_DECLARE(void) switch_resample_destroy(switch_audio_resampler_t **resample
\param resampler the resample handle
\param src the source data
\param srclen the length of the source data
\param dst the destination data
\param dstlen the length of the destination data
\param last parameter denoting the last sample is being resampled
\return the used size of dst
*/
SWITCH_DECLARE(uint32_t) switch_resample_process(switch_audio_resampler_t *resampler, float *src, int srclen, float *dst, uint32_t dstlen, int last);
SWITCH_DECLARE(uint32_t) switch_resample_process(switch_audio_resampler_t *resampler, int16_t *src, uint32_t srclen);
/*!
\brief Convert an array of floats to an array of shorts

View File

@ -1692,12 +1692,8 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
int16_t *bptr = (int16_t *) read_frame->data;
int len = (int) read_frame->datalen;
read_resampler->from_len = switch_short_to_float(bptr, read_resampler->from, (int) len / 2);
read_resampler->to_len = switch_resample_process(read_resampler,
read_resampler->from,
read_resampler->from_len, read_resampler->to, read_resampler->to_size, 0);
switch_float_to_short(read_resampler->to, member->resample_out, read_resampler->to_len);
switch_resample_process(read_resampler, bptr, len / 2);
memcpy(member->resample_out, read_resampler->to, read_resampler->to_len * 2);
len = read_resampler->to_len * 2;
datalen = len;
data = member->resample_out;
@ -4477,7 +4473,7 @@ static int setup_media(conference_member_t *member, conference_obj_t *conference
if (read_impl.actual_samples_per_second != conference->rate) {
if (switch_resample_create(&member->read_resampler,
read_impl.actual_samples_per_second,
member->frame_size, conference->rate, member->frame_size, member->pool) != SWITCH_STATUS_SUCCESS) {
conference->rate, member->frame_size, SWITCH_RESAMPLE_QUALITY) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to create resampler!\n");
goto done;
}

View File

@ -214,16 +214,14 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_read(switch_file_handle_t *fh,
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, fh->samplerate, (uint32_t) orig_len, fh->memory_pool) != SWITCH_STATUS_SUCCESS) {
fh->native_rate, fh->samplerate, (uint32_t) orig_len, SWITCH_RESAMPLE_QUALITY) != 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);
switch_resample_process(fh->resampler, data, *len);
if (fh->resampler->to_len < want || fh->resampler->to_len > orig_len) {
if (!fh->buffer) {
int factor = fh->resampler->to_len * fh->samplerate / 1000;
@ -235,8 +233,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_read(switch_file_handle_t *fh,
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);
memcpy((int16_t *) fh->dbuf, fh->resampler->to, fh->resampler->to_len * 2);
switch_buffer_write(fh->buffer, fh->dbuf, fh->resampler->to_len * 2);
if (switch_buffer_inuse(fh->buffer) < want * 2) {
@ -245,7 +243,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_read(switch_file_handle_t *fh,
}
*len = switch_buffer_read(fh->buffer, data, orig_len * 2) / 2;
} else {
switch_float_to_short(fh->resampler->to, data, fh->resampler->to_len);
memcpy(data, fh->resampler->to, fh->resampler->to_len * 2);
*len = fh->resampler->to_len;
}
@ -274,28 +272,25 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_write(switch_file_handle_t *fh,
if (!fh->resampler) {
if (switch_resample_create(&fh->resampler,
fh->native_rate,
orig_len * fh->channels,
fh->samplerate,
(uint32_t) orig_len *fh->channels,
fh->memory_pool) != SWITCH_STATUS_SUCCESS) {
SWITCH_RESAMPLE_QUALITY) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to create resampler!\n");
return SWITCH_STATUS_GENERR;
}
}
switch_resample_process(fh->resampler, data, *len * fh->channels);
fh->resampler->from_len = switch_short_to_float(data, fh->resampler->from, (int) *len * fh->channels);
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 * fh->channels) {
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);
memcpy(fh->dbuf, fh->resampler->to, fh->resampler->to_len);
data = fh->dbuf;
} else {
switch_float_to_short(fh->resampler->to, data, fh->resampler->to_len);
memcpy(data, fh->resampler->to, fh->resampler->to_len);
}
*len = fh->resampler->to_len / fh->channels;

View File

@ -271,9 +271,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi
switch_mutex_lock(session->resample_mutex);
status = switch_resample_create(&session->read_resampler,
read_frame->codec->implementation->actual_samples_per_second,
read_frame->codec->implementation->decoded_bytes_per_packet,
session->read_impl.actual_samples_per_second,
session->read_impl.decoded_bytes_per_packet, session->pool);
session->read_impl.actual_samples_per_second,
session->read_impl.decoded_bytes_per_packet,
SWITCH_RESAMPLE_QUALITY);
switch_mutex_unlock(session->resample_mutex);
if (status != SWITCH_STATUS_SUCCESS) {
@ -385,15 +386,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi
if (session->read_resampler) {
short *data = read_frame->data;
switch_mutex_lock(session->resample_mutex);
session->read_resampler->from_len = switch_short_to_float(data, session->read_resampler->from, (int) read_frame->datalen / 2);
session->read_resampler->to_len =
switch_resample_process(session->read_resampler, session->read_resampler->from,
session->read_resampler->from_len, session->read_resampler->to, session->read_resampler->to_size, 0);
switch_float_to_short(session->read_resampler->to, data, read_frame->datalen);
switch_resample_process(session->read_resampler, data, (int)read_frame->datalen / 2);
memcpy(data, session->read_resampler->to, session->read_resampler->to_len * 2);
read_frame->samples = session->read_resampler->to_len;
read_frame->datalen = session->read_resampler->to_len * 2;
read_frame->rate = session->read_resampler->to_rate;
read_frame->datalen = session->read_resampler->to_len * 2;
read_frame->rate = session->read_resampler->to_rate;
switch_mutex_unlock(session->resample_mutex);
}
@ -681,9 +678,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess
switch_mutex_lock(session->resample_mutex);
status = switch_resample_create(&session->write_resampler,
frame->codec->implementation->actual_samples_per_second,
frame->codec->implementation->decoded_bytes_per_packet,
session->write_impl.actual_samples_per_second,
session->write_impl.decoded_bytes_per_packet, session->pool);
session->write_impl.actual_samples_per_second,
session->write_impl.decoded_bytes_per_packet,
SWITCH_RESAMPLE_QUALITY);
switch_mutex_unlock(session->resample_mutex);
if (status != SWITCH_STATUS_SUCCESS) {
goto done;
@ -731,15 +729,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess
short *data = write_frame->data;
switch_mutex_lock(session->resample_mutex);
session->write_resampler->from_len = write_frame->datalen / 2;
switch_short_to_float(data, session->write_resampler->from, session->write_resampler->from_len);
session->write_resampler->to_len = (uint32_t)
switch_resample_process(session->write_resampler, session->write_resampler->from,
session->write_resampler->from_len, session->write_resampler->to, session->write_resampler->to_size, 0);
switch_float_to_short(session->write_resampler->to, data, session->write_resampler->to_len);
switch_resample_process(session->write_resampler, data, write_frame->datalen / 2);
memcpy(data, session->write_resampler->to, session->write_resampler->to_len * 2);
write_frame->samples = session->write_resampler->to_len;
write_frame->datalen = write_frame->samples * 2;
write_frame->rate = session->write_resampler->to_rate;
@ -946,9 +937,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess
switch_mutex_lock(session->resample_mutex);
status = switch_resample_create(&session->write_resampler,
frame->codec->implementation->actual_samples_per_second,
frame->codec->implementation->decoded_bytes_per_packet,
session->write_impl.actual_samples_per_second,
session->write_impl.decoded_bytes_per_packet, session->pool);
session->write_impl.actual_samples_per_second,
session->write_impl.decoded_bytes_per_packet,
SWITCH_RESAMPLE_QUALITY);
switch_mutex_unlock(session->resample_mutex);
if (status != SWITCH_STATUS_SUCCESS) {
@ -993,14 +985,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess
if (!did_write_resample && session->read_resampler) {
short *data = write_frame->data;
switch_mutex_lock(session->resample_mutex);
session->read_resampler->from_len =
switch_short_to_float(data, session->read_resampler->from, (int) write_frame->datalen / 2);
session->read_resampler->to_len = (uint32_t)
switch_resample_process(session->read_resampler, session->read_resampler->from,
session->read_resampler->from_len,
session->read_resampler->to, session->read_resampler->to_size, 0);
switch_float_to_short(session->read_resampler->to, data, write_frame->datalen * 2);
switch_resample_process(session->read_resampler, data, write_frame->datalen / 2);
memcpy(data, session->read_resampler->to, session->read_resampler->to_len * 2);
write_frame->samples = session->read_resampler->to_len;
write_frame->datalen = session->read_resampler->to_len * 2;
write_frame->rate = session->read_resampler->to_rate;

View File

@ -38,6 +38,9 @@
#ifndef DISABLE_RESAMPLE
#include <libresample.h>
#endif
#include <speex/speex_resampler.h>
#define NORMFACT (float)0x8000
#define MAXSAMPLE (float)0x7FFF
#define MAXSAMPLEC (char)0x7F
@ -54,62 +57,52 @@
#define resample_buffer(a, b, c) a > b ? ((a / 1000) / 2) * c : ((b / 1000) / 2) * c
SWITCH_DECLARE(switch_status_t) switch_resample_perform_create(switch_audio_resampler_t **new_resampler,
int from_rate, switch_size_t from_size, int to_rate,
uint32_t to_size, switch_memory_pool_t *pool, const char *file, const char *func, int line)
uint32_t from_rate, uint32_t to_rate,
uint32_t to_size,
int quality,
const char *file, const char *func, int line)
{
#ifdef DISABLE_RESAMPLE
*new_resampler = NULL;
return SWITCH_STATUS_NOTIMPL;
#else
int err = 0;
switch_audio_resampler_t *resampler;
double lto_rate, lfrom_rate;
if ((resampler = switch_core_alloc(pool, sizeof(*resampler))) == 0) {
return SWITCH_STATUS_MEMERR;
switch_zmalloc(resampler, sizeof(*resampler));
resampler->resampler = speex_resampler_init(1, from_rate, to_rate, quality, &err);
if (!resampler->resampler) {
free(resampler);
return SWITCH_STATUS_GENERR;
}
resampler->from_rate = from_rate;
resampler->to_rate = to_rate;
lto_rate = (double) resampler->to_rate;
lfrom_rate = (double) resampler->from_rate;
resampler->factor = (lto_rate / lfrom_rate);
resampler->rfactor = (lfrom_rate / lto_rate);
resampler->resampler = resample_open(QUALITY, resampler->factor, resampler->factor);
switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_NOTICE,
"Activate Resampler %d->%d %f\n", resampler->from_rate, resampler->to_rate, resampler->factor);
resampler->from_size = resample_buffer(to_rate, from_rate, (uint32_t) from_size);
resampler->from = (float *) switch_core_alloc(pool, resampler->from_size * sizeof(float));
resampler->to_size = resample_buffer(to_rate, from_rate, (uint32_t) to_size);;
resampler->to = (float *) switch_core_alloc(pool, resampler->to_size * sizeof(float));
*new_resampler = resampler;
lto_rate = (double) resampler->to_rate;
lfrom_rate = (double) resampler->from_rate;
resampler->from_rate = from_rate;
resampler->to_rate = to_rate;
resampler->factor = (lto_rate / lfrom_rate);
resampler->rfactor = (lfrom_rate / lto_rate);
resampler->to_size = resample_buffer(to_rate, from_rate, (uint32_t) to_size);
resampler->to = malloc(resampler->to_size * sizeof(int16_t));
return SWITCH_STATUS_SUCCESS;
#endif
}
SWITCH_DECLARE(uint32_t) switch_resample_process(switch_audio_resampler_t *resampler, float *src, int srclen, float *dst, uint32_t dstlen, int last)
SWITCH_DECLARE(uint32_t) switch_resample_process(switch_audio_resampler_t *resampler, int16_t *src, uint32_t srclen)
{
#ifdef DISABLE_RESAMPLE
return 0;
#else
int o = 0, srcused = 0, srcpos = 0, out = 0;
for (;;) {
int srcBlock = MIN(srclen - srcpos, srclen);
int lastFlag = (last && (srcBlock == srclen - srcpos));
o = resample_process(resampler->resampler, resampler->factor, &src[srcpos], srcBlock, lastFlag, &srcused, &dst[out], dstlen - out);
/* printf("resampling %d/%d (%d) %d %f\n", srcpos, srclen, MIN(dstlen-out, dstlen), srcused, factor); */
srcpos += srcused;
if (o >= 0) {
out += o;
}
if (o < 0 || (o == 0 && srcpos == srclen)) {
break;
}
}
return out;
resampler->to_len = resampler->to_size;
speex_resampler_process_int(resampler->resampler, 0, src, &srclen, resampler->to, &resampler->to_len);
return resampler->to_len;
#endif
}
@ -119,8 +112,10 @@ SWITCH_DECLARE(void) switch_resample_destroy(switch_audio_resampler_t **resample
if (resampler && *resampler) {
#ifndef DISABLE_RESAMPLE
if ((*resampler)->resampler) {
resample_close((*resampler)->resampler);
speex_resampler_destroy((*resampler)->resampler);
}
free((*resampler)->to);
free(*resampler);
#endif
*resampler = NULL;
}