diff --git a/src/include/switch_resample.h b/src/include/switch_resample.h index 7f4ce7dbbf..9f722d28d2 100644 --- a/src/include/switch_resample.h +++ b/src/include/switch_resample.h @@ -42,7 +42,7 @@ #ifndef SWITCH_RESAMPLE_H #define SWITCH_RESAMPLE_H - +#define SWITCH_RESAMPLE_QUALITY 0 #include 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 diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index a04d770551..7cb12ce1b4 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -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; } diff --git a/src/switch_core_file.c b/src/switch_core_file.c index 13e63155d5..9a43204e45 100644 --- a/src/switch_core_file.c +++ b/src/switch_core_file.c @@ -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; diff --git a/src/switch_core_io.c b/src/switch_core_io.c index af5216a612..e714ec6f8b 100644 --- a/src/switch_core_io.c +++ b/src/switch_core_io.c @@ -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; diff --git a/src/switch_resample.c b/src/switch_resample.c index ba8cd6e639..c17dcbdb6e 100644 --- a/src/switch_resample.c +++ b/src/switch_resample.c @@ -38,6 +38,9 @@ #ifndef DISABLE_RESAMPLE #include #endif + +#include + #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; }