]> git.alsa-project.org Git - alsa-plugins.git/commitdiff
rate-lav: Support multiple formats
authorTakashi Iwai <tiwai@suse.de>
Thu, 17 Jun 2021 09:03:04 +0000 (11:03 +0200)
committerTakashi Iwai <tiwai@suse.de>
Thu, 17 Jun 2021 10:14:41 +0000 (12:14 +0200)
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@suse.de>
rate-lav/rate_lavrate.c

index e9c6740ac870d87e0794bce8176549512fe4ae06..2ab1d8894e638df4ee03f24770cafb6cb5de1971 100644 (file)
@@ -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;
 }