diff options
author | Benny Prijono <bennylp@teluu.com> | 2007-10-12 05:24:32 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2007-10-12 05:24:32 +0000 |
commit | bb245dbd9520bcd8fe45d1874bed6b9d284366f4 (patch) | |
tree | 57c9ce551efd0dfeab04139c80b9ee681bb3491c /pjmedia | |
parent | d3dab1141d7384cbbe9732b3747f045a17f81851 (diff) |
Ticket #398: Initial support for Secret Rabbit Code (aka libsamplerate) sample rate conversionl library
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1493 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjmedia')
-rw-r--r-- | pjmedia/build/Makefile | 2 | ||||
-rw-r--r-- | pjmedia/build/pjmedia.dsp | 4 | ||||
-rw-r--r-- | pjmedia/include/pjmedia/config.h | 94 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/resample_libsamplerate.c | 206 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/resample_resample.c | 46 | ||||
-rw-r--r-- | pjmedia/src/pjmedia/resample_speex.c | 6 |
6 files changed, 296 insertions, 62 deletions
diff --git a/pjmedia/build/Makefile b/pjmedia/build/Makefile index 11ffdc9d..fd73580e 100644 --- a/pjmedia/build/Makefile +++ b/pjmedia/build/Makefile @@ -45,7 +45,7 @@ export PJMEDIA_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \ echo_suppress.o endpoint.o errno.o \ g711.o jbuf.o master_port.o mem_capture.o mem_player.o \ null_port.o plc_common.o port.o splitcomb.o \ - resample_resample.o \ + resample_resample.o resample_libsamplerate.o \ resample_port.o rtcp.o rtp.o sdp.o sdp_cmp.o sdp_neg.o \ session.o silencedet.o sound_port.o stream.o \ tonegen.o transport_ice.o transport_udp.o \ diff --git a/pjmedia/build/pjmedia.dsp b/pjmedia/build/pjmedia.dsp index 801b96a0..0a59d37e 100644 --- a/pjmedia/build/pjmedia.dsp +++ b/pjmedia/build/pjmedia.dsp @@ -181,6 +181,10 @@ SOURCE=..\src\pjmedia\port.c # End Source File
# Begin Source File
+SOURCE=..\src\pjmedia\resample_libsamplerate.c
+# End Source File
+# Begin Source File
+
SOURCE=..\src\pjmedia\resample_port.c
# End Source File
# Begin Source File
diff --git a/pjmedia/include/pjmedia/config.h b/pjmedia/include/pjmedia/config.h index f438f185..cc6695c3 100644 --- a/pjmedia/include/pjmedia/config.h +++ b/pjmedia/include/pjmedia/config.h @@ -127,55 +127,87 @@ /* - * ** THIS MACRO IS DEPRECATED in 0.6. ** - * ** See libresample for configuring this ** + * Warn about obsolete macros. * - * Include small filter table in resample. - * This adds about 9KB in rdata. + * PJMEDIA_HAS_SMALL_FILTER has been deprecated in 0.7. */ -/* -#ifndef PJMEDIA_HAS_SMALL_FILTER -# define PJMEDIA_HAS_SMALL_FILTER 1 +#if defined(PJMEDIA_HAS_SMALL_FILTER) +# ifdef _MSC_VER +# pragma message("Warning: PJMEDIA_HAS_SMALL_FILTER macro is deprecated"\ + " and has no effect") +# else +# warning "PJMEDIA_HAS_SMALL_FILTER macro is deprecated and has no effect" +# endif #endif -*/ + /* - * ** THIS MACRO IS DEPRECATED in 0.6. ** - * ** See libresample for configuring this ** + * Warn about obsolete macros. * - * Include large filter table in resample. - * This adds about 32KB in rdata. + * PJMEDIA_HAS_LARGE_FILTER has been deprecated in 0.7. */ -/* -#ifndef PJMEDIA_HAS_LARGE_FILTER -# define PJMEDIA_HAS_LARGE_FILTER 1 +#if defined(PJMEDIA_HAS_LARGE_FILTER) +# ifdef _MSC_VER +# pragma message("Warning: PJMEDIA_HAS_LARGE_FILTER macro is deprecated"\ + " and has no effect") +# else +# warning "PJMEDIA_HAS_LARGE_FILTER macro is deprecated" +# endif #endif -*/ -/** - * Specify whether libresample should be used for the sampling - * rate conversion. This macro and PJMEDIA_HAS_SPEEX_RESAMPLE - * are mutually exclusive. - * - * Default: 1 (Yes) + +/* + * These macros are obsolete in 0.7.1 so it will trigger compilation error. + * Please use PJMEDIA_RESAMPLE_IMP to select the resample implementation + * to use. */ -#ifndef PJMEDIA_HAS_LIBRESAMPLE -# define PJMEDIA_HAS_LIBRESAMPLE 1 +#ifdef PJMEDIA_HAS_LIBRESAMPLE +# error "PJMEDIA_HAS_LIBRESAMPLE macro is deprecated. Use '#define PJMEDIA_RESAMPLE_IMP PJMEDIA_RESAMPLE_LIBRESAMPLE'" #endif +#ifdef PJMEDIA_HAS_SPEEX_RESAMPLE +# error "PJMEDIA_HAS_SPEEX_RESAMPLE macro is deprecated. Use '#define PJMEDIA_RESAMPLE_IMP PJMEDIA_RESAMPLE_SPEEX'" +#endif -/** - * Specify whether Speex sample rate convertor should be used for the - * sampling rate conversion. This macro and PJMEDIA_HAS_LIBRESAMPLE - * are mutually exclusive. + +/* + * Sample rate conversion backends. + * Select one of these backends in PJMEDIA_RESAMPLE_IMP. + */ +#define PJMEDIA_RESAMPLE_NONE 1 /**< No resampling. */ +#define PJMEDIA_RESAMPLE_LIBRESAMPLE 2 /**< Sample rate conversion + using libresample. */ +#define PJMEDIA_RESAMPLE_SPEEX 3 /**< Sample rate conversion + using Speex. */ +#define PJMEDIA_RESAMPLE_LIBSAMPLERATE 4 /**< Sample rate conversion + using libsamplerate + (a.k.a Secret Rabbit Code) + */ + +/** + * Select which resample implementation to use. Currently pjmedia supports: + * - #PJMEDIA_RESAMPLE_LIBRESAMPLE, to use libresample-1.7, this is the default + * implementation to be used. + * - #PJMEDIA_RESAMPLE_LIBSAMPLERATE, to use libsamplerate implementation + * (a.k.a. Secret Rabbit Code). + * - #PJMEDIA_RESAMPLE_SPEEX, to use experimental sample rate conversion in + * Speex library. + * - #PJMEDIA_RESAMPLE_NONE, to disable sample rate conversion. Any calls to + * resample function will return error. * - * Default: 0 + * Default is PJMEDIA_RESAMPLE_LIBRESAMPLE */ -#ifndef PJMEDIA_HAS_SPEEX_RESAMPLE -# define PJMEDIA_HAS_SPEEX_RESAMPLE 0 +#ifndef PJMEDIA_RESAMPLE_IMP +# define PJMEDIA_RESAMPLE_IMP PJMEDIA_RESAMPLE_LIBRESAMPLE #endif +/** + * Specify whether libsamplerate, when used, should be linked statically + * into the application. This option is only useful for Visual Studio + * projects, and when this static linking is enabled + */ + /** * Default file player/writer buffer size. diff --git a/pjmedia/src/pjmedia/resample_libsamplerate.c b/pjmedia/src/pjmedia/resample_libsamplerate.c new file mode 100644 index 00000000..9bca5e1a --- /dev/null +++ b/pjmedia/src/pjmedia/resample_libsamplerate.c @@ -0,0 +1,206 @@ +/* $Id$ */ +/* + * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <pjmedia/resample.h> +#include <pjmedia/errno.h> +#include <pj/assert.h> +#include <pj/log.h> +#include <pj/pool.h> + +/* + * HOW TO ACTIVATE LIBSAMPLERATE (a.k.a SRC/Secret Rabbit Code) AS + * PJMEDIA'S SAMPLE RATE CONVERSION BACKEND + * + * See README.txt in third_party/samplerate directory. + */ + + +#if PJMEDIA_RESAMPLE_IMP==PJMEDIA_RESAMPLE_LIBSAMPLERATE + +#include "../../third_party/libsamplerate/src/samplerate.h" + +#define THIS_FILE "resample_libsamplerate.c" + +#if defined(_MSC_VER) +# ifdef _DEBUG +# pragma comment( lib, "../../third_party/lib/libsamplerate-i386-win32-vc-debug.lib") +# else +# pragma comment( lib, "../../third_party/lib/libsamplerate-i386-win32-vc-release.lib") +# endif +#endif + + +struct pjmedia_resample +{ + SRC_STATE *state; + unsigned in_samples; + unsigned out_samples; + float *frame_in, *frame_out; + unsigned in_extra, out_extra; + double ratio; +}; + + +PJ_DEF(pj_status_t) pjmedia_resample_create( pj_pool_t *pool, + pj_bool_t high_quality, + pj_bool_t large_filter, + unsigned channel_count, + unsigned rate_in, + unsigned rate_out, + unsigned samples_per_frame, + pjmedia_resample **p_resample) +{ + pjmedia_resample *resample; + int type, err; + + PJ_ASSERT_RETURN(pool && p_resample && rate_in && + rate_out && samples_per_frame, PJ_EINVAL); + + resample = PJ_POOL_ZALLOC_T(pool, pjmedia_resample); + PJ_ASSERT_RETURN(resample, PJ_ENOMEM); + + /* Select conversion type */ + if (high_quality) { + type = large_filter ? SRC_SINC_BEST_QUALITY : SRC_SINC_MEDIUM_QUALITY; + } else { + type = large_filter ? SRC_SINC_FASTEST : SRC_LINEAR; + } + + /* Create converter */ + resample->state = src_new(type, channel_count, &err); + if (resample->state == NULL) { + PJ_LOG(4,(THIS_FILE, "Error creating resample: %s", + src_strerror(err))); + return PJMEDIA_ERROR; + } + + /* Calculate ratio */ + resample->ratio = rate_out * 1.0 / rate_in; + + /* Calculate number of samples for input and output */ + resample->in_samples = samples_per_frame; + resample->out_samples = rate_out / (rate_in / samples_per_frame); + + resample->frame_in = (float*) + pj_pool_calloc(pool, + resample->in_samples + 8, + sizeof(float)); + + resample->frame_out = (float*) + pj_pool_calloc(pool, + resample->out_samples + 8, + sizeof(float)); + + /* Set the converter ratio */ + err = src_set_ratio(resample->state, resample->ratio); + if (err != 0) { + PJ_LOG(4,(THIS_FILE, "Error creating resample: %s", + src_strerror(err))); + return PJMEDIA_ERROR; + } + + /* Done */ + + PJ_LOG(5,(THIS_FILE, + "Resample using libsamplerate %s, type=%s (%s), " + "ch=%d, in/out rate=%d/%d", + src_get_version(), + src_get_name(type), src_get_description(type), + channel_count, rate_in, rate_out)); + + *p_resample = resample; + + return PJ_SUCCESS; +} + + +PJ_DEF(void) pjmedia_resample_run( pjmedia_resample *resample, + const pj_int16_t *input, + pj_int16_t *output ) +{ + SRC_DATA src_data; + + /* Convert samples to float */ + src_short_to_float_array(input, resample->frame_in, + resample->in_samples); + + if (resample->in_extra) { + unsigned i; + + for (i=0; i<resample->in_extra; ++i) + resample->frame_in[resample->in_samples+i] = + resample->frame_in[resample->in_samples-1]; + } + + /* Prepare SRC_DATA */ + pj_bzero(&src_data, sizeof(src_data)); + src_data.data_in = resample->frame_in; + src_data.data_out = resample->frame_out; + src_data.input_frames = resample->in_samples + resample->in_extra; + src_data.output_frames = resample->out_samples + resample->out_extra; + src_data.src_ratio = resample->ratio; + + /* Process! */ + src_process(resample->state, &src_data); + + /* Convert output back to short */ + src_float_to_short_array(resample->frame_out, output, + src_data.output_frames_gen); + + /* Replay last sample if conversion couldn't fill up the whole + * frame. This could happen for example with 22050 to 16000 conversion. + */ + if (src_data.output_frames_gen < (int)resample->out_samples) { + unsigned i; + + if (resample->in_extra < 4) + resample->in_extra++; + + for (i=src_data.output_frames_gen; + i<resample->out_samples; ++i) + { + output[i] = output[src_data.output_frames_gen-1]; + } + } +} + + +PJ_DEF(unsigned) pjmedia_resample_get_input_size(pjmedia_resample *resample) +{ + PJ_ASSERT_RETURN(resample != NULL, 0); + return resample->in_samples; +} + + +PJ_DEF(void) pjmedia_resample_destroy(pjmedia_resample *resample) +{ + PJ_ASSERT_ON_FAIL(resample, return); + if (resample->state) { + src_delete(resample->state); + resample->state = NULL; + + PJ_LOG(5,(THIS_FILE, "Resample destroyed")); + } +} + +#else /* PJMEDIA_RESAMPLE_IMP==PJMEDIA_RESAMPLE_LIBSAMPLERATE */ + +int pjmedia_libsamplerate_excluded; + +#endif /* PJMEDIA_RESAMPLE_IMP==PJMEDIA_RESAMPLE_LIBSAMPLERATE */ + diff --git a/pjmedia/src/pjmedia/resample_resample.c b/pjmedia/src/pjmedia/resample_resample.c index e013748f..d3b53d96 100644 --- a/pjmedia/src/pjmedia/resample_resample.c +++ b/pjmedia/src/pjmedia/resample_resample.c @@ -25,7 +25,7 @@ #include <pj/pool.h> -#if defined(PJMEDIA_HAS_LIBRESAMPLE) && PJMEDIA_HAS_LIBRESAMPLE != 0 +#if PJMEDIA_RESAMPLE_IMP==PJMEDIA_RESAMPLE_LIBRESAMPLE #include <third_party/resample/include/resamplesubs.h> @@ -215,16 +215,11 @@ PJ_DEF(void) pjmedia_resample_destroy(pjmedia_resample *resample) } -#else /* PJMEDIA_HAS_LIBRESAMPLE */ +#elif PJMEDIA_RESAMPLE_IMP==PJMEDIA_RESAMPLE_NONE /* * This is the configuration when sample rate conversion is disabled. */ -struct pjmedia_resample -{ - unsigned samples_per_frame; -}; - PJ_DEF(pj_status_t) pjmedia_resample_create( pj_pool_t *pool, pj_bool_t high_quality, pj_bool_t large_filter, @@ -234,40 +229,37 @@ PJ_DEF(pj_status_t) pjmedia_resample_create( pj_pool_t *pool, unsigned samples_per_frame, pjmedia_resample **p_resample) { - pjmedia_resample *resample; - - PJ_ASSERT_RETURN(rate_in == rate_out, PJ_EINVALIDOP); - - PJ_UNUSED_ARG(high_quality); - PJ_UNUSED_ARG(large_filter); - PJ_UNUSED_ARG(channel_count); - PJ_UNUSED_ARG(rate_in); - PJ_UNUSED_ARG(rate_out); - - resample = PJ_POOL_ZALLOC_T(pool, pjmedia_resample); - resample->samples_per_frame = samples_per_frame; - - *p_resample = resample; - - return PJ_SUCCESS; + PJ_UNUSED_ARG(pool); + PJ_UNUSED_ARG(high_quality); + PJ_UNUSED_ARG(large_filter); + PJ_UNUSED_ARG(channel_count); + PJ_UNUSED_ARG(rate_in); + PJ_UNUSED_ARG(rate_out); + PJ_UNUSED_ARG(samples_per_frame); + PJ_UNUSED_ARG(p_resample); + + return PJ_EINVALIDOP; } PJ_DEF(void) pjmedia_resample_run( pjmedia_resample *resample, const pj_int16_t *input, pj_int16_t *output ) { - pjmedia_copy_samples(output, input, resample->samples_per_frame); + PJ_UNUSED_ARG(resample); + PJ_UNUSED_ARG(input); + PJ_UNUSED_ARG(output); } PJ_DEF(unsigned) pjmedia_resample_get_input_size(pjmedia_resample *resample) { - return resample->samples_per_frame; + PJ_UNUSED_ARG(resample); + return 0; } PJ_DEF(void) pjmedia_resample_destroy(pjmedia_resample *resample) { - PJ_UNUSED_ARG(resample); + PJ_UNUSED_ARG(resample); } -#endif /* PJMEDIA_HAS_LIBRESAMPLE */ +#endif /* PJMEDIA_RESAMPLE_IMP */ diff --git a/pjmedia/src/pjmedia/resample_speex.c b/pjmedia/src/pjmedia/resample_speex.c index fcc42115..fc73b781 100644 --- a/pjmedia/src/pjmedia/resample_speex.c +++ b/pjmedia/src/pjmedia/resample_speex.c @@ -22,7 +22,7 @@ #include <pj/log.h> #include <pj/pool.h> -#if defined(PJMEDIA_HAS_SPEEX_RESAMPLE) && PJMEDIA_HAS_SPEEX_RESAMPLE != 0 +#if PJMEDIA_RESAMPLE_IMP==PJMEDIA_RESAMPLE_SPEEX #include <speex/speex_resampler.h> @@ -118,9 +118,9 @@ PJ_DEF(void) pjmedia_resample_destroy(pjmedia_resample *resample) } } -#else /* PJMEDIA_HAS_SPEEX_RESAMPLE */ +#else /* PJMEDIA_RESAMPLE_IMP==PJMEDIA_RESAMPLE_SPEEX */ int pjmedia_resample_speex_excluded; -#endif /* PJMEDIA_HAS_SPEEX_RESAMPLE */ +#endif /* PJMEDIA_RESAMPLE_IMP==PJMEDIA_RESAMPLE_SPEEX */ |