author | zhe.wang <zhe.wang@amlogic.com> | 2014-05-16 07:37:42 (GMT) |
---|---|---|
committer | tao.dong <tao.dong@amlogic.com> | 2014-05-29 01:27:04 (GMT) |
commit | 18e36ecadc19ae9696061580e1fed7aa72321fd0 (patch) | |
tree | 3fa3cd20c34b9fd567b355adccc1ca0082374d59 | |
parent | a4e1e138b54dda38ce41fd7fad6bb6b4a4cd14a2 (diff) | |
download | audio-18e36ecadc19ae9696061580e1fed7aa72321fd0.zip audio-18e36ecadc19ae9696061580e1fed7aa72321fd0.tar.gz audio-18e36ecadc19ae9696061580e1fed7aa72321fd0.tar.bz2 |
PD[91923]:1,change a new audio resample Algorithm for USB playback
2,free resample buffer when do standby
3,2 channels input data and 1 channel output resampled data
-rwxr-xr-x | Android.mk | 3 | ||||
-rwxr-xr-x | audio_hw.c | 13 | ||||
-rwxr-xr-x | audio_resampler.c | 103 | ||||
-rwxr-xr-x | audio_resampler.h | 19 | ||||
-rwxr-xr-x | usb_audio_hw.c | 60 |
5 files changed, 165 insertions, 33 deletions
@@ -52,7 +52,8 @@ ifeq ($(strip $(BOARD_ALSA_AUDIO)),tiny) LOCAL_MODULE := audio.usb.amlogic LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw LOCAL_SRC_FILES := \ - usb_audio_hw.c + usb_audio_hw.c \ + audio_resampler.c LOCAL_C_INCLUDES += \ external/tinyalsa/include \ system/media/audio_utils/include @@ -742,6 +742,14 @@ static int do_output_standby(struct aml_stream_out *out) out->frame_count = 0; adev->active_output = 0; + if (out->buffer){ + free(out->buffer); + out->buffer = NULL; + } + if (out->resampler){ + release_resampler(out->resampler); + out->resampler = NULL; + } /* if in call, don't turn off the output stage. This will be done when the call is ended */ if (adev->mode != AUDIO_MODE_IN_CALL) { @@ -1849,11 +1857,6 @@ static void adev_close_output_stream(struct audio_hw_device *dev, LOGFUNC("%s(%p, %p)", __FUNCTION__, dev, stream); out_standby(&stream->common); - if (out->buffer) - free(out->buffer); - if (out->resampler) - release_resampler(out->resampler); - free(stream); } diff --git a/audio_resampler.c b/audio_resampler.c new file mode 100755 index 0000000..7886824 --- a/dev/null +++ b/audio_resampler.c @@ -0,0 +1,103 @@ +#include <math.h>
+#include <cutils/log.h>
+
+#include "audio_resampler.h"
+
+#define LOG_TAG "usb_audio_resampler"
+
+//Clip from 16.16 fixed-point to 0.15 fixed-point.
+inline static short clip(int x) {
+ if (x < -32768) {
+ return -32768;
+ } else if (x > 32767) {
+ return 32767;
+ } else {
+ return x;
+ }
+}
+
+int resampler_init(struct resample_para *resample) {
+
+ ALOGD("%s, Init Resampler: input_sr = %d, output_sr = %d \n",
+ __FUNCTION__,resample->input_sr,resample->output_sr);
+
+ static const double kPhaseMultiplier = 1L << 28;
+
+ resample->FractionStep = (unsigned int) (resample->input_sr * kPhaseMultiplier
+ / resample->output_sr);
+ resample->SampleFraction = 0;
+ resample->lastsample_left = 0;
+ resample->lastsample_right = 0;
+ return 0;
+}
+
+int resample_process(struct resample_para *resample, unsigned int in_frame,
+ short* input, short* output) {
+ unsigned int inputIndex = 0;
+ unsigned int outputIndex = 0;
+ unsigned int FractionStep = resample->FractionStep;
+
+ static const unsigned int kPhaseMask = (1LU << 28) - 1;
+ unsigned int frac = resample->SampleFraction;
+ short lastsample_left = resample->lastsample_left;
+ short lastsample_right = resample->lastsample_right;
+
+ if(resample->channels == 2){
+ while (inputIndex == 0) {
+ *output++ = clip((int) lastsample_left +
+ ((((int) input[0] - (int) lastsample_left) * ((int) frac >> 13)) >> 15));
+ *output++ = clip((int) lastsample_right +
+ ((((int) input[1] - (int) lastsample_right) * ((int) frac >> 13)) >> 15));
+
+ frac += FractionStep;
+ inputIndex += (frac >> 28);
+ frac = (frac & kPhaseMask);
+ outputIndex++;
+ }
+
+ while (inputIndex < in_frame) {
+ *output++ = clip((int) input[2 * inputIndex - 2] + ((((int) input[2 * inputIndex]
+ - (int) input[2 * inputIndex - 2]) * ((int) frac >> 13)) >> 15));
+ *output++ = clip((int) input[2 * inputIndex - 1] + ((((int) input[2 * inputIndex + 1]
+ - (int) input[2 * inputIndex - 1]) * ((int) frac >> 13)) >> 15));
+
+ frac += FractionStep;
+ inputIndex += (frac >> 28);
+ frac = (frac & kPhaseMask);
+ outputIndex++;
+ }
+
+ resample->lastsample_left = input[2 * in_frame - 2];
+ resample->lastsample_right = input[2 * in_frame - 1];
+ resample->SampleFraction = frac;
+ }else{
+ //left channel as output
+ while (inputIndex == 0) {
+ *output++ = clip((int) lastsample_left +
+ ((((int) input[0] - (int) lastsample_left) * ((int) frac >> 13)) >> 15));
+
+ frac += FractionStep;
+ inputIndex += (frac >> 28);
+ frac = (frac & kPhaseMask);
+ outputIndex++;
+ }
+
+ while (inputIndex < in_frame) {
+ *output++ = clip((int) input[2 * inputIndex - 2] + ((((int) input[2 * inputIndex]
+ - (int) input[2 * inputIndex - 2]) * ((int) frac >> 13)) >> 15));
+
+ frac += FractionStep;
+ inputIndex += (frac >> 28);
+ frac = (frac & kPhaseMask);
+ outputIndex++;
+ }
+
+ resample->lastsample_left = input[2 * in_frame - 2];
+ resample->SampleFraction = frac;
+ }
+
+ return outputIndex;
+}
+
+
+
diff --git a/audio_resampler.h b/audio_resampler.h new file mode 100755 index 0000000..e43dfae --- a/dev/null +++ b/audio_resampler.h @@ -0,0 +1,19 @@ +#ifndef __AUDIO_RESAMPLER_H__
+#define __AUDIO_RESAMPLER_H__
+
+struct resample_para {
+ unsigned int FractionStep;
+ unsigned int SampleFraction;
+ short lastsample_left;
+ short lastsample_right;
+ unsigned int input_sr;
+ unsigned int output_sr;
+ unsigned int channels;
+};
+
+int resampler_init(struct resample_para *resample);
+int resample_process(struct resample_para *resample, unsigned int in_frame,
+ short* input, short* output);
+
+
+#endif
diff --git a/usb_audio_hw.c b/usb_audio_hw.c index 3788f62..a6f72ae 100755 --- a/usb_audio_hw.c +++ b/usb_audio_hw.c @@ -36,22 +36,27 @@ #include <tinyalsa/asoundlib.h> #include <audio_utils/resampler.h> +#include "audio_resampler.h" + #define DEFAULT_OUT_SAMPLING_RATE 44100 #define RESAMPLER_BUFFER_SIZE 4096 +#define DEFAULT_PERIOD_SIZE 1024 +#define PERIOD_COUNT 4 #define BUFFSIZE 100000 + struct pcm_config pcm_out_config = { .channels = 2, .rate = DEFAULT_OUT_SAMPLING_RATE, - .period_size = 1024, - .period_count = 4, + .period_size = DEFAULT_PERIOD_SIZE, + .period_count = PERIOD_COUNT, .format = PCM_FORMAT_S16_LE, }; struct pcm_config pcm_in_config = { .channels = 1, .rate = DEFAULT_OUT_SAMPLING_RATE, - .period_size = 1024, - .period_count = 4, + .period_size = DEFAULT_PERIOD_SIZE, + .period_count = PERIOD_COUNT, .format = PCM_FORMAT_S16_LE, }; @@ -75,8 +80,8 @@ struct aml_stream_out { pthread_mutex_t lock; /* see note below on mutex acquisition order */ struct pcm_config out_config; struct pcm *out_pcm; - struct resampler_itfe *resampler; - char *buffer; + struct resample_para resampler; + void *buffer; bool standby; struct aml_audio_device *dev; @@ -284,16 +289,15 @@ static int start_output_stream(struct aml_stream_out *out) return -EINVAL; } } + out->buffer = NULL; if (out->out_config.rate != pcm_out_config.rate){ - err = create_resampler(DEFAULT_OUT_SAMPLING_RATE, - out->out_config.rate, - 2, - RESAMPLER_QUALITY_DEFAULT, - NULL, - &out->resampler); - if (err != 0) - return -ENOMEM; - out->buffer = malloc(RESAMPLER_BUFFER_SIZE); /* todo: allow for reallocing */ + out->resampler.input_sr = pcm_out_config.rate; + out->resampler.output_sr = out->out_config.rate; + out->resampler.channels = out->out_config.channels; + resampler_init(&out->resampler); + int buffersize = DEFAULT_PERIOD_SIZE * out->out_config.rate / pcm_out_config.rate + 1; + out->buffer = malloc(buffersize*4); + ALOGE("out->buffer: %p, buffer_size = %d",out->buffer,buffersize); if (!out->buffer) return -ENOMEM; } @@ -362,7 +366,7 @@ static audio_format_t out_get_format(const struct audio_stream *stream) return AUDIO_FORMAT_PCM_16_BIT; } -static int out_set_format(struct audio_stream *stream, int format) +static int out_set_format(struct audio_stream *stream, audio_format_t format) { ALOGD("%s(%p)", __FUNCTION__, stream); @@ -375,12 +379,17 @@ static int do_output_standby(struct aml_stream_out *out) struct aml_audio_device *adev = out->dev; ALOGD("%s(%p)", __FUNCTION__, out); - + if (!out->standby) { pcm_close(out->out_pcm); out->out_pcm = NULL; adev->active_output = 0; + + if (out->buffer != NULL){ + free(out->buffer); + out->buffer = NULL; + } out->standby = true; } return 0; @@ -447,7 +456,7 @@ static char * out_get_parameters(const struct audio_stream *stream, const char * static uint32_t out_get_latency(const struct audio_stream_out *stream) { - struct aml_stream_out *out = (struct stream_out *)stream; + struct aml_stream_out *out = (struct aml_stream_out *)stream; return (pcm_out_config.period_size * pcm_out_config.period_count * 1000) / out->out_config.rate; } @@ -495,18 +504,15 @@ FILE * fp=fopen("/data/audio_in","a+"); #endif /* only use resampler if required */ if (out->out_config.rate != DEFAULT_OUT_SAMPLING_RATE) { - out->resampler->resample_from_input(out->resampler, - (int16_t *)buffer, - &in_frames, - (int16_t *)out->buffer, - &out_frames); + out_frames = resample_process(&out->resampler, in_frames, + (short *)buffer, (short *)out->buffer); buf = out->buffer; } else { out_frames = in_frames; buf = (void *)buffer; } - - pcm_write(out->out_pcm, (void *)buf, out_frames * frame_size); + + pcm_write(out->out_pcm, (void *)buf, out_frames * out->out_config.channels * 2); pthread_mutex_unlock(&out->lock); pthread_mutex_unlock(&out->dev->lock); @@ -1140,7 +1146,7 @@ static int adev_open_input_stream(struct audio_hw_device *dev, { struct aml_audio_device *adev = (struct aml_audio_device *)dev; struct aml_stream_in *in; - struct mixer *usb_mixer; + struct mixer *usb_mixer = NULL; int ret; in = (struct aml_stream_in *)calloc(1, sizeof(struct aml_stream_in)); @@ -1247,7 +1253,7 @@ static int adev_close(hw_device_t *device) { struct aml_audio_device *adev = (struct aml_audio_device *)device; - // LOGFUNC("%s(%p)", __FUNCTION__, device); + ALOGD("%s(%p)", __func__, device); free(device); return 0; |