@@ -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;
}
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 | 115 ++++++++++++++++++++++++++++++++++------ 1 file changed, 99 insertions(+), 16 deletions(-)