| /* |
| ** 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)); |
| 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); |
| } |