You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
265 lines
9.7 KiB
265 lines
9.7 KiB
/* |
|
** 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 <log/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; |
|
spx_uint32_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); |
|
} |
|
|
|
spx_uint32_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 %zu frames in and %zu 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, |
|
(spx_uint32_t *)inFrameCount, |
|
out, |
|
(spx_uint32_t *)outFrameCount); |
|
} else { |
|
speex_resampler_process_interleaved_int(rsmp->speex_resampler, |
|
in, |
|
(spx_uint32_t *)inFrameCount, |
|
out, |
|
(spx_uint32_t *)outFrameCount); |
|
} |
|
|
|
ALOGV("resampler_resample_from_input() DONE in %zu out %zu", *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); |
|
}
|
|
|