Now that ALSA rate plugin core allows each rate plugin dealing with multiple formats, this patch extends the rate-lav plugin to accept more formats, namely, U8, S16 and S32. The code has been carefully modified so that it should still be compilable with old alsa-lib. Signed-off-by: Takashi Iwai <tiwai@xxxxxxx> --- rate-lav/rate_lavrate.c | 115 ++++++++++++++++++++++++++++++++++------ 1 file changed, 99 insertions(+), 16 deletions(-) diff --git a/rate-lav/rate_lavrate.c b/rate-lav/rate_lavrate.c index e9c6740ac870..2ab1d8894e63 100644 --- a/rate-lav/rate_lavrate.c +++ b/rate-lav/rate_lavrate.c @@ -32,6 +32,8 @@ struct rate_src { unsigned int in_rate; unsigned int out_rate; unsigned int channels; + + unsigned int version; }; static snd_pcm_uframes_t input_frames(void *obj ATTRIBUTE_UNUSED, @@ -52,9 +54,34 @@ static void pcm_src_free(void *obj) swr_free(&rate->avr); } +static int to_av_format(snd_pcm_format_t f) +{ + switch (f) { + case SND_PCM_FORMAT_FLOAT: + return AV_SAMPLE_FMT_FLT; + case SND_PCM_FORMAT_U8: + return AV_SAMPLE_FMT_U8; + case SND_PCM_FORMAT_S16: + return AV_SAMPLE_FMT_S16; + case SND_PCM_FORMAT_S32: + default: + return AV_SAMPLE_FMT_S32; + } +} + +static int support_multi_format(struct rate_src *rate) +{ +#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003 + return rate->version >= 0x010003; +#else + return 0; +#endif +} + static int pcm_src_init(void *obj, snd_pcm_rate_info_t *info) { struct rate_src *rate = obj; + int fmt; if (!rate->avr || rate->channels != info->channels) { int ret; @@ -74,8 +101,12 @@ static int pcm_src_init(void *obj, snd_pcm_rate_info_t *info) av_get_default_channel_layout(rate->channels), 0); av_opt_set_int(rate->avr, "in_sample_rate", rate->in_rate, 0); av_opt_set_int(rate->avr, "out_sample_rate", rate->out_rate, 0); - av_opt_set_sample_fmt(rate->avr, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0); - av_opt_set_sample_fmt(rate->avr, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); + fmt = support_multi_format(rate) ? info->in.format : SND_PCM_FORMAT_S16; + av_opt_set_sample_fmt(rate->avr, "in_sample_fmt", + to_av_format(fmt), 0); + fmt = support_multi_format(rate) ? info->out.format : SND_PCM_FORMAT_S16; + av_opt_set_sample_fmt(rate->avr, "out_sample_fmt", + to_av_format(fmt), 0); ret = swr_init(rate->avr); if (ret < 0) { @@ -109,12 +140,10 @@ static void pcm_src_reset(void *obj) } } -static void pcm_src_convert_s16(void *obj, int16_t *dst, - unsigned int dst_frames, - const int16_t *src, - unsigned int src_frames) +static void do_convert(struct rate_src *rate, + void *dst, unsigned int dst_frames, + const void *src, unsigned int src_frames) { - struct rate_src *rate = obj; unsigned int total_in = swr_get_delay(rate->avr, rate->in_rate) + src_frames; swr_convert(rate->avr, (uint8_t **)&dst, dst_frames, @@ -125,6 +154,38 @@ static void pcm_src_convert_s16(void *obj, int16_t *dst, src_frames); } +#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003 +static inline void *get_addr(const snd_pcm_channel_area_t *area, snd_pcm_uframes_t offset) +{ + return (char *)area->addr + (area->first + area->step * offset) / 8; +} + +static void pcm_src_convert(void *obj, + const snd_pcm_channel_area_t *dst_areas, + snd_pcm_uframes_t dst_offset, + unsigned int dst_frames, + const snd_pcm_channel_area_t *src_areas, + snd_pcm_uframes_t src_offset, + unsigned int src_frames) +{ + struct rate_src *rate = obj; + const void *src = get_addr(src_areas, src_offset); + void *dst = get_addr(dst_areas, dst_offset); + + do_convert(rate, dst, dst_frames, src, src_frames); +} +#endif + +static void pcm_src_convert_s16(void *obj, int16_t *dst, + unsigned int dst_frames, + const int16_t *src, + unsigned int src_frames) +{ + struct rate_src *rate = obj; + + do_convert(rate, dst, dst_frames, src, src_frames); +} + static void pcm_src_close(void *obj) { pcm_src_free(obj); @@ -145,12 +206,29 @@ static void dump(void *obj ATTRIBUTE_UNUSED, snd_output_t *out) } #endif +#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003 +static int get_supported_formats(void *obj, uint64_t *in_formats, + uint64_t *out_formats, + unsigned int *flags) +{ + *in_formats = *out_formats = + (1ULL << SND_PCM_FORMAT_U8) | + (1ULL << SND_PCM_FORMAT_S16) | + (1ULL << SND_PCM_FORMAT_S32); + *flags = SND_PCM_RATE_FLAG_INTERLEAVED; + return 0; +} +#endif + static snd_pcm_rate_ops_t pcm_src_ops = { .close = pcm_src_close, .init = pcm_src_init, .free = pcm_src_free, .reset = pcm_src_reset, .adjust_pitch = pcm_src_adjust_pitch, +#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003 + .convert = pcm_src_convert, +#endif .convert_s16 = pcm_src_convert_s16, .input_frames = input_frames, .output_frames = output_frames, @@ -159,30 +237,35 @@ static snd_pcm_rate_ops_t pcm_src_ops = { .get_supported_rates = get_supported_rates, .dump = dump, #endif +#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003 + .get_supported_formats = get_supported_formats, +#endif }; int pcm_src_open(unsigned int version, void **objp, snd_pcm_rate_ops_t *ops) { struct rate_src *rate; -#if SND_PCM_RATE_PLUGIN_VERSION < 0x010002 - if (version != SND_PCM_RATE_PLUGIN_VERSION) { - fprintf(stderr, "Invalid rate plugin version %x\n", version); - return -EINVAL; - } -#endif rate = calloc(1, sizeof(*rate)); if (!rate) return -ENOMEM; *objp = rate; rate->avr = NULL; + rate->version = version; #if SND_PCM_RATE_PLUGIN_VERSION >= 0x010002 - if (version == 0x010001) + if (version == 0x010001) { memcpy(ops, &pcm_src_ops, sizeof(snd_pcm_rate_old_ops_t)); - else + return 0; + } +#endif +#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003 + if (version == 0x010002) { + memcpy(ops, &pcm_src_ops, sizeof(snd_pcm_rate_v2_ops_t)); + return 0; + } #endif - *ops = pcm_src_ops; + *ops = pcm_src_ops; return 0; } -- 2.26.2