/* ** Copyright 2011, The Android Open-Source Project ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. ** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** Unless required by applicable law or agreed to in writing, software ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and ** limitations under the License. */ //#define LOG_NDEBUG 0 #define LOG_TAG "resampler" #include <errno.h> #include <stdlib.h> #include <cutils/log.h> #include <system/audio.h> #include <audio_utils/resampler.h> #include <speex/speex_resampler.h> struct resampler { struct resampler_itfe itfe; SpeexResamplerState *speex_resampler; // handle on speex resampler struct resampler_buffer_provider *provider; // buffer provider installed by client uint32_t in_sample_rate; // input sampling rate in Hz uint32_t out_sample_rate; // output sampling rate in Hz uint32_t channel_count; // number of channels (interleaved) int16_t *in_buf; // input buffer size_t in_buf_size; // input buffer size size_t frames_in; // number of frames in input buffer size_t frames_rq; // cached number of output frames size_t frames_needed; // minimum number of input frames to produce // frames_rq output frames int32_t speex_delay_ns; // delay introduced by speex resampler in ns }; //------------------------------------------------------------------------------ // speex based resampler //------------------------------------------------------------------------------ static void resampler_reset(struct resampler_itfe *resampler) { struct resampler *rsmp = (struct resampler *)resampler; rsmp->frames_in = 0; rsmp->frames_rq = 0; if (rsmp != NULL && rsmp->speex_resampler != NULL) { speex_resampler_reset_mem(rsmp->speex_resampler); } } static int32_t resampler_delay_ns(struct resampler_itfe *resampler) { struct resampler *rsmp = (struct resampler *)resampler; int32_t delay = (int32_t)((1000000000 * (int64_t)rsmp->frames_in) / rsmp->in_sample_rate); delay += rsmp->speex_delay_ns; return delay; } // outputs a number of frames less or equal to *outFrameCount and updates *outFrameCount // with the actual number of frames produced. int resampler_resample_from_provider(struct resampler_itfe *resampler, int16_t *out, size_t *outFrameCount) { struct resampler *rsmp = (struct resampler *)resampler; if (rsmp == NULL || out == NULL || outFrameCount == NULL) { return -EINVAL; } if (rsmp->provider == NULL) { *outFrameCount = 0; return -ENOSYS; } size_t framesRq = *outFrameCount; // update and cache the number of frames needed at the input sampling rate to produce // the number of frames requested at the output sampling rate if (framesRq != rsmp->frames_rq) { rsmp->frames_needed = (framesRq * rsmp->in_sample_rate) / rsmp->out_sample_rate + 1; rsmp->frames_rq = framesRq; } size_t framesWr = 0; size_t inFrames = 0; while (framesWr < framesRq) { if (rsmp->frames_in < rsmp->frames_needed) { // make sure that the number of frames present in rsmp->in_buf (rsmp->frames_in) is at // least the number of frames needed to produce the number of frames requested at // the output sampling rate if (rsmp->in_buf_size < rsmp->frames_needed) { rsmp->in_buf_size = rsmp->frames_needed; rsmp->in_buf = (int16_t *)realloc(rsmp->in_buf, rsmp->in_buf_size * rsmp->channel_count * sizeof(int16_t)); } struct resampler_buffer buf; buf.frame_count = rsmp->frames_needed - rsmp->frames_in; rsmp->provider->get_next_buffer(rsmp->provider, &buf); if (buf.raw == NULL) { break; } memcpy(rsmp->in_buf + rsmp->frames_in * rsmp->channel_count, buf.raw, buf.frame_count * rsmp->channel_count * sizeof(int16_t)); rsmp->frames_in += buf.frame_count; rsmp->provider->release_buffer(rsmp->provider, &buf); } size_t outFrames = framesRq - framesWr; inFrames = rsmp->frames_in; if (rsmp->channel_count == 1) { speex_resampler_process_int(rsmp->speex_resampler, 0, rsmp->in_buf, &inFrames, out + framesWr, &outFrames); } else { speex_resampler_process_interleaved_int(rsmp->speex_resampler, rsmp->in_buf, &inFrames, out + framesWr * rsmp->channel_count, &outFrames); } framesWr += outFrames; rsmp->frames_in -= inFrames; ALOGW_IF((framesWr != framesRq) && (rsmp->frames_in != 0), "ReSampler::resample() remaining %d frames in and %d frames out", rsmp->frames_in, (framesRq - framesWr)); } if (rsmp->frames_in) { memmove(rsmp->in_buf, rsmp->in_buf + inFrames * rsmp->channel_count, rsmp->frames_in * rsmp->channel_count * sizeof(int16_t)); } *outFrameCount = framesWr; return 0; } int resampler_resample_from_input(struct resampler_itfe *resampler, int16_t *in, size_t *inFrameCount, int16_t *out, size_t *outFrameCount) { struct resampler *rsmp = (struct resampler *)resampler; if (rsmp == NULL || in == NULL || inFrameCount == NULL || out == NULL || outFrameCount == NULL) { return -EINVAL; } if (rsmp->provider != NULL) { *outFrameCount = 0; return -ENOSYS; } if (rsmp->channel_count == 1) { speex_resampler_process_int(rsmp->speex_resampler, 0, in, inFrameCount, out, outFrameCount); } else { speex_resampler_process_interleaved_int(rsmp->speex_resampler, in, inFrameCount, out, outFrameCount); } ALOGV("resampler_resample_from_input() DONE in %d out % d", *inFrameCount, *outFrameCount); return 0; } int create_resampler(uint32_t inSampleRate, uint32_t outSampleRate, uint32_t channelCount, uint32_t quality, struct resampler_buffer_provider* provider, struct resampler_itfe **resampler) { int error; struct resampler *rsmp; ALOGV("create_resampler() In SR %d Out SR %d channels %d", inSampleRate, outSampleRate, channelCount); if (resampler == NULL) { return -EINVAL; } *resampler = NULL; if (quality <= RESAMPLER_QUALITY_MIN || quality >= RESAMPLER_QUALITY_MAX) { return -EINVAL; } rsmp = (struct resampler *)calloc(1, sizeof(struct resampler)); rsmp->speex_resampler = speex_resampler_init(channelCount, inSampleRate, outSampleRate, quality, &error); if (rsmp->speex_resampler == NULL) { ALOGW("ReSampler: Cannot create speex resampler: %s", speex_resampler_strerror(error)); free(rsmp); return -ENODEV; } rsmp->itfe.reset = resampler_reset; rsmp->itfe.resample_from_provider = resampler_resample_from_provider; rsmp->itfe.resample_from_input = resampler_resample_from_input; rsmp->itfe.delay_ns = resampler_delay_ns; rsmp->provider = provider; rsmp->in_sample_rate = inSampleRate; rsmp->out_sample_rate = outSampleRate; rsmp->channel_count = channelCount; rsmp->in_buf = NULL; rsmp->in_buf_size = 0; resampler_reset(&rsmp->itfe); int frames = speex_resampler_get_input_latency(rsmp->speex_resampler); rsmp->speex_delay_ns = (int32_t)((1000000000 * (int64_t)frames) / rsmp->in_sample_rate); frames = speex_resampler_get_output_latency(rsmp->speex_resampler); rsmp->speex_delay_ns += (int32_t)((1000000000 * (int64_t)frames) / rsmp->out_sample_rate); *resampler = &rsmp->itfe; ALOGV("create_resampler() DONE rsmp %p &rsmp->itfe %p speex %p", rsmp, &rsmp->itfe, rsmp->speex_resampler); return 0; } void release_resampler(struct resampler_itfe *resampler) { struct resampler *rsmp = (struct resampler *)resampler; if (rsmp == NULL) { return; } free(rsmp->in_buf); if (rsmp->speex_resampler != NULL) { speex_resampler_destroy(rsmp->speex_resampler); } free(rsmp); }