commit 12c0d25ec4051d5db2be2c1dbfc5c4641a1268ff
Author: Jaroslav Kysela <perex(a)perex.cz>
Date: Tue Nov 9 12:07:26 2021 +0100
Updated to latest alsa git (libswresample)
Signed-off-by: Jaroslav Kysela <perex(a)perex.cz>
alsa-git.patch | 1312 +++++++++++++++++++++++++++++++++++++++++++
alsa-plugins-freeworld.spec | 7 +-
2 files changed, 1318 insertions(+), 1 deletion(-)
---
diff --git a/alsa-git.patch b/alsa-git.patch
new file mode 100644
index 0000000..876b275
--- /dev/null
+++ b/alsa-git.patch
@@ -0,0 +1,1312 @@
+diff --git a/a52/60-a52-encoder.conf b/a52/60-a52-encoder.conf
+index 346c94f..99cc98e 100644
+--- a/a52/60-a52-encoder.conf
++++ b/a52/60-a52-encoder.conf
+@@ -36,3 +36,10 @@ pcm.a52 {
+ description "Plugin to convert multichannel stream to A52 (AC3)
bitstream"
+ }
+ }
++
++#
++# A quick test command:
++# CARD=1 # replace with your IEC958 card
++# DEVICE=1 # replace with your IEC958 PCM device number
++# speaker-test -d -b 2000000 -c 6
-D"plug:{SLAVE=\"a52:${CARD},'hw:${CARD},${DEVICE}'\"}"
++#
+diff --git a/a52/pcm_a52.c b/a52/pcm_a52.c
+index b6a8f55..9da8897 100644
+--- a/a52/pcm_a52.c
++++ b/a52/pcm_a52.c
+@@ -41,7 +41,12 @@
+ #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 34, 0)
+ #include <libavutil/channel_layout.h>
+ #include <libavutil/mem.h>
+-#define USE_AVCODEC_FRAME
++#define USE_AVCODEC_FRAME 1
++#endif
++
++#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(58, 91, 0)
++#include <libavcodec/packet.h>
++#define USE_AVCODEC_PACKET_ALLOC
+ #endif
+
+ #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(54, 0, 0)
+@@ -62,6 +67,12 @@
+ #define AV_CODEC_ID_AC3 CODEC_ID_AC3
+ #endif
+
++#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(56, 56, 0)
++#ifndef AV_INPUT_BUFFER_PADDING_SIZE
++#define AV_INPUT_BUFFER_PADDING_SIZE FF_INPUT_BUFFER_PADDING_SIZE
++#endif
++#endif
++
+ #if LIBAVCODEC_VERSION_INT < 0x371c01
+ #define av_frame_alloc avcodec_alloc_frame
+ #define av_frame_free avcodec_free_frame
+@@ -72,20 +83,29 @@ struct a52_ctx {
+ snd_pcm_t *slave;
+ AVCodec *codec;
+ AVCodecContext *avctx;
++ snd_pcm_format_t src_format;
++ unsigned int src_sample_bits;
++ unsigned int src_sample_bytes;
+ snd_pcm_format_t format;
+ int av_format;
+ unsigned int channels;
+ unsigned int rate;
+ unsigned int bitrate;
+- short *inbuf;
++ void *inbuf;
+ unsigned char *outbuf;
++ unsigned char *outbuf1;
++ unsigned char *outbuf2;
+ int outbuf_size;
+- snd_pcm_uframes_t transfer;
+ int remain;
+ int filled;
+ unsigned int slave_period_size;
+ unsigned int slave_buffer_size;
++ snd_pcm_uframes_t pointer;
++ snd_pcm_uframes_t boundary;
+ snd_pcm_hw_params_t *hw_params;
++#ifdef USE_AVCODEC_PACKET_ALLOC
++ AVPacket *pkt;
++#endif
+ #ifdef USE_AVCODEC_FRAME
+ AVFrame *frame;
+ int is_planar;
+@@ -98,70 +118,103 @@ struct a52_ctx {
+ #define use_planar(rec) 0
+ #endif
+
+-#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 34, 0)
++#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(58, 91, 0)
++static int do_encode(struct a52_ctx *rec)
++{
++ AVPacket *pkt = rec->pkt;
++ int ret;
++
++ ret = avcodec_send_frame(rec->avctx, rec->frame);
++ if (ret < 0)
++ return -EINVAL;
++ ret = avcodec_receive_packet(rec->avctx, pkt);
++ if (ret < 0)
++ return -EINVAL;
++
++ if (pkt->size > rec->outbuf_size - 8)
++ return -EINVAL;
++ memcpy(rec->outbuf1 + 8, pkt->data, pkt->size);
++
++ return pkt->size;
++}
++#elif LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(53, 34, 0)
+ static int do_encode(struct a52_ctx *rec)
+ {
+ AVPacket pkt = {
+- .data = rec->outbuf + 8,
++ .data = rec->outbuf1 + 8,
+ .size = rec->outbuf_size - 8
+ };
+- int got_frame;
++ int ret, got_frame;
++
++ ret = avcodec_encode_audio2(rec->avctx, &pkt, rec->frame, &got_frame);
++ if (ret < 0)
++ return -EINVAL;
+
+- avcodec_encode_audio2(rec->avctx, &pkt, rec->frame, &got_frame);
+ return pkt.size;
+ }
+ #else
+ static int do_encode(struct a52_ctx *rec)
+ {
+- return avcodec_encode_audio(rec->avctx, rec->outbuf + 8,
+- rec->outbuf_size - 8,
+- rec->inbuf);
++ int ret = avcodec_encode_audio(rec->avctx, rec->outbuf1 + 8,
++ rec->outbuf_size - 8,
++ rec->inbuf);
++ if (ret < 0)
++ return -EINVAL;
++
++ return ret;
+ }
+ #endif
+
+ /* convert the PCM data to A52 stream in IEC958 */
+-static void convert_data(struct a52_ctx *rec)
++static int convert_data(struct a52_ctx *rec)
+ {
++ unsigned char *buf;
+ int out_bytes = do_encode(rec);
+
+- rec->outbuf[0] = 0xf8; /* sync words */
+- rec->outbuf[1] = 0x72;
+- rec->outbuf[2] = 0x4e;
+- rec->outbuf[3] = 0x1f;
+- rec->outbuf[4] = rec->outbuf[13] & 7; /* bsmod */
+- rec->outbuf[5] = 0x01; /* data type */
+- rec->outbuf[6] = ((out_bytes * 8) >> 8) & 0xff;
+- rec->outbuf[7] = (out_bytes * 8) & 0xff;
++ if (out_bytes < 0)
++ return out_bytes;
++
++ buf = rec->outbuf1;
++ buf[0] = 0xf8; /* sync words */
++ buf[1] = 0x72;
++ buf[2] = 0x4e;
++ buf[3] = 0x1f;
++ buf[4] = buf[13] & 7; /* bsmod */
++ buf[5] = 0x01; /* data type */
++ buf[6] = ((out_bytes * 8) >> 8) & 0xff;
++ buf[7] = (out_bytes * 8) & 0xff;
+ /* swap bytes for little-endian 16bit */
+- if (rec->format == SND_PCM_FORMAT_S16_LE)
+- swab(rec->outbuf, rec->outbuf, out_bytes + 8);
+- memset(rec->outbuf + 8 + out_bytes, 0,
++ if (rec->format == SND_PCM_FORMAT_S16_LE) {
++ swab(rec->outbuf1, rec->outbuf2, out_bytes + 8);
++ buf = rec->outbuf2;
++ }
++ rec->outbuf = buf;
++ memset(buf + 8 + out_bytes, 0,
+ rec->outbuf_size - 8 - out_bytes);
+ rec->remain = rec->outbuf_size / 4;
+ rec->filled = 0;
++
++ return 0;
+ }
+
+ /* write pending encoded data to the slave pcm */
+ static int write_out_pending(snd_pcm_ioplug_t *io, struct a52_ctx *rec)
+ {
+- int err, ofs = (rec->avctx->frame_size - rec->remain) * 4;
+-
+- if (! rec->remain)
+- return 0;
++ snd_pcm_sframes_t ret;
++ unsigned int ofs;
+
+ while (rec->remain) {
+- err = snd_pcm_writei(rec->slave, rec->outbuf + ofs, rec->remain);
+- if (err < 0) {
+- if (err == -EPIPE)
++ ofs = (rec->avctx->frame_size - rec->remain) * 4;
++ ret = snd_pcm_writei(rec->slave, rec->outbuf + ofs, rec->remain);
++ if (ret < 0) {
++ if (ret == -EPIPE)
+ io->state = SND_PCM_STATE_XRUN;
+- if (err == -EAGAIN)
++ if (ret == -EAGAIN)
+ break;
+- return err;
+- } else if (! err)
++ return ret;
++ } else if (! ret)
+ break;
+- if (err < rec->remain)
+- ofs += (rec->remain - err) * 4;
+- rec->remain -= err;
++ rec->remain -= ret;
+ }
+ return 0;
+ }
+@@ -176,8 +229,8 @@ static void clear_remaining_planar_data(snd_pcm_ioplug_t *io)
+ unsigned int i;
+
+ for (i = 0; i < io->channels; i++)
+- memset(rec->frame->data[i] + rec->filled * 2, 0,
+- (rec->avctx->frame_size - rec->filled) * 2);
++ memset(rec->frame->data[i] + rec->filled * rec->src_sample_bytes, 0,
++ (rec->avctx->frame_size - rec->filled) * rec->src_sample_bytes);
+ }
+ #else
+ #define clear_remaining_planar_data(io) /*NOP*/
+@@ -195,10 +248,12 @@ static int a52_drain(snd_pcm_ioplug_t *io)
+ if (use_planar(rec))
+ clear_remaining_planar_data(io);
+ else {
+- memset(rec->inbuf + rec->filled * io->channels, 0,
+- (rec->avctx->frame_size - rec->filled) * io->channels * 2);
++ memset(rec->inbuf + rec->filled * io->channels * rec->src_sample_bytes,
0,
++ (rec->avctx->frame_size - rec->filled) * io->channels *
rec->src_sample_bytes);
+ }
+- convert_data(rec);
++ err = convert_data(rec);
++ if (err < 0)
++ return err;
+ }
+ err = write_out_pending(io, rec);
+ if (err < 0)
+@@ -208,7 +263,8 @@ static int a52_drain(snd_pcm_ioplug_t *io)
+ }
+
+ /* check whether the areas consist of a continuous interleaved stream */
+-static int check_interleaved(const snd_pcm_channel_area_t *areas,
++static int check_interleaved(struct a52_ctx *rec,
++ const snd_pcm_channel_area_t *areas,
+ unsigned int channels)
+ {
+ unsigned int ch;
+@@ -218,8 +274,8 @@ static int check_interleaved(const snd_pcm_channel_area_t *areas,
+
+ for (ch = 0; ch < channels; ch++) {
+ if (areas[ch].addr != areas[0].addr ||
+- areas[ch].first != ch * 16 ||
+- areas[ch].step != channels * 16)
++ areas[ch].first != ch * rec->src_sample_bits ||
++ areas[ch].step != channels * rec->src_sample_bits)
+ return 0;
+ }
+ return 1;
+@@ -237,8 +293,7 @@ static int fill_data(snd_pcm_ioplug_t *io,
+ {
+ struct a52_ctx *rec = io->private_data;
+ unsigned int len = rec->avctx->frame_size - rec->filled;
+- short *src, *dst;
+- unsigned int src_step;
++ void *_dst;
+ int err;
+ static unsigned int ch_index[3][6] = {
+ { 0, 1 },
+@@ -257,20 +312,23 @@ static int fill_data(snd_pcm_ioplug_t *io,
+
+ /* If there are still frames left in outbuf, we can't
+ * accept a full a52 frame, because this would overwrite
+- * the frames in outbuf. */
+- if (rec->remain && len)
++ * the frames in outbuf. This should not happen! The a52_pointer()
++ * callback should limit the transferred frames correctly. */
++ if (rec->remain && len) {
++ SNDERR("fill data issue (remain is %i)", rec->remain);
+ len--;
++ }
+
+ if (size > len)
+ size = len;
+
+- dst = rec->inbuf + rec->filled * io->channels;
++ _dst = rec->inbuf + rec->filled * io->channels * rec->src_sample_bytes;
+ if (!use_planar(rec) && interleaved) {
+- memcpy(dst, areas->addr + offset * io->channels * 2,
+- size * io->channels * 2);
+- } else {
+- unsigned int i, ch, dst_step;
+- short *dst1;
++ memcpy(_dst, areas->addr + offset * io->channels * rec->src_sample_bytes,
++ size * io->channels * rec->src_sample_bytes);
++ } else if (rec->src_sample_bits == 16) {
++ unsigned int i, ch, src_step, dst_step;
++ short *src, *dst = _dst, *dst1;
+
+ /* flatten copy to n-channel interleaved */
+ dst_step = io->channels;
+@@ -281,8 +339,8 @@ static int fill_data(snd_pcm_ioplug_t *io,
+ (ap->first + offset * ap->step) / 8);
+
+ #ifdef USE_AVCODEC_FRAME
+- if (use_planar(rec)) {
+- memcpy(rec->frame->data[ch], src, size * 2);
++ if (use_planar(rec) && !interleaved) {
++ memcpy(rec->frame->data[ch] + rec->filled * 2, src, size * 2);
+ continue;
+ }
+ #endif
+@@ -294,10 +352,40 @@ static int fill_data(snd_pcm_ioplug_t *io,
+ dst1 += dst_step;
+ }
+ }
++ } else if (rec->src_sample_bits == 32) {
++ unsigned int i, ch, src_step, dst_step;
++ int *src, *dst = _dst, *dst1;
++
++ /* flatten copy to n-channel interleaved */
++ dst_step = io->channels;
++ for (ch = 0; ch < io->channels; ch++, dst++) {
++ const snd_pcm_channel_area_t *ap;
++ ap = &areas[ch_index[io->channels / 2 - 1][ch]];
++ src = (int *)(ap->addr +
++ (ap->first + offset * ap->step) / 8);
++
++#ifdef USE_AVCODEC_FRAME
++ if (use_planar(rec) && !interleaved) {
++ memcpy(rec->frame->data[ch] + rec->filled * 4, src, size * 4);
++ continue;
++ }
++#endif
++ dst1 = dst;
++ src_step = ap->step / 32; /* in word */
++ for (i = 0; i < size; i++) {
++ *dst1 = *src;
++ src += src_step;
++ dst1 += dst_step;
++ }
++ }
++ } else {
++ return -EIO;
+ }
+ rec->filled += size;
+ if (rec->filled == rec->avctx->frame_size) {
+- convert_data(rec);
++ err = convert_data(rec);
++ if (err < 0)
++ return err;
+ write_out_pending(io, rec);
+ }
+ return (int)size;
+@@ -314,7 +402,7 @@ static snd_pcm_sframes_t a52_transfer(snd_pcm_ioplug_t *io,
+ struct a52_ctx *rec = io->private_data;
+ snd_pcm_sframes_t result = 0;
+ int err = 0;
+- int interleaved = check_interleaved(areas, io->channels);
++ int interleaved = check_interleaved(rec, areas, io->channels);
+
+ do {
+ err = fill_data(io, areas, offset, size, interleaved);
+@@ -323,7 +411,8 @@ static snd_pcm_sframes_t a52_transfer(snd_pcm_ioplug_t *io,
+ offset += (unsigned int)err;
+ size -= (unsigned int)err;
+ result += err;
+- rec->transfer += err;
++ rec->pointer += err;
++ rec->pointer %= rec->boundary;
+ } while (size);
+ return result > 0 ? result : err;
+ }
+@@ -336,7 +425,7 @@ static snd_pcm_sframes_t a52_transfer(snd_pcm_ioplug_t *io,
+ static snd_pcm_sframes_t a52_pointer(snd_pcm_ioplug_t *io)
+ {
+ struct a52_ctx *rec = io->private_data;
+- snd_pcm_sframes_t avail;
++ snd_pcm_sframes_t avail, delay;
+ snd_pcm_state_t state;
+
+ state = snd_pcm_state(rec->slave);
+@@ -345,31 +434,31 @@ static snd_pcm_sframes_t a52_pointer(snd_pcm_ioplug_t *io)
+ case SND_PCM_STATE_DRAINING:
+ break;
+ case SND_PCM_STATE_XRUN:
+- case SND_PCM_STATE_SUSPENDED:
+ return -EPIPE;
++ case SND_PCM_STATE_SUSPENDED:
++ return -ESTRPIPE;
+ default:
+ return 0;
+ }
+
+- avail = 0;
+-
+ /* Write what we have from outbuf. */
+ write_out_pending(io, rec);
+
+- /* If there is anything remaining in outbuf, we can't
+- * accept any full packets. */
+- if (rec->remain == 0)
+- {
+- /* Round the slave frames to multiples of the packet size. */
+- avail += (snd_pcm_avail_update(rec->slave) / rec->avctx->frame_size) *
rec->avctx->frame_size;
+- }
+-
++ avail = snd_pcm_avail(rec->slave);
+ if (avail < 0)
+- avail = 0;
+- else if (avail >= io->buffer_size)
+- avail = io->buffer_size - 1;
++ return avail;
+
+- return (io->appl_ptr + avail) % io->buffer_size;
++ /* get buffer delay without additional FIFO information */
++ delay = rec->slave_buffer_size - avail;
++ while (delay < 0)
++ delay += rec->slave_buffer_size;
++
++ avail = rec->pointer - delay - rec->remain - rec->filled;
++#ifdef SND_PCM_IOPLUG_FLAG_BOUNDARY_WA
++ return avail % rec->boundary;
++#else
++ return avail % io->buffer_size;
++#endif
+ }
+
+ /* set up the fixed parameters of slave PCM hw_parmas */
+@@ -462,6 +551,25 @@ static int a52_hw_free(snd_pcm_ioplug_t *io)
+ return snd_pcm_hw_free(rec->slave);
+ }
+
++/*
++ * dump callback
++ */
++static void a52_dump(snd_pcm_ioplug_t *io, snd_output_t *out)
++{
++ struct a52_ctx *rec = io->private_data;
++ snd_pcm_t *pcm = io->pcm;
++
++ snd_output_printf(out, "%s\n", io->name);
++ snd_output_printf(out, "Its setup is:\n");
++ snd_pcm_dump_setup(pcm, out);
++ snd_output_printf(out, " %-13s: %s\n", "av_format",
av_get_sample_fmt_name(rec->av_format));
++ snd_output_printf(out, " %-13s: %i\n", "av_frame_size",
rec->avctx ? rec->avctx->frame_size : -1);
++ snd_output_printf(out, " %-13s: %i\n", "remain", rec->remain);
++ snd_output_printf(out, " %-13s: %i\n", "filled", rec->filled);
++ snd_output_printf(out, "Slave: ");
++ snd_pcm_dump(rec->slave, out);
++}
++
+ /*
+ * sw_params callback
+ *
+@@ -476,6 +584,7 @@ static int a52_sw_params(snd_pcm_ioplug_t *io, snd_pcm_sw_params_t
*params)
+
+ snd_pcm_sw_params_get_avail_min(params, &avail_min);
+ snd_pcm_sw_params_get_start_threshold(params, &start_threshold);
++ snd_pcm_sw_params_get_boundary(params, &rec->boundary);
+
+ len = avail_min;
+ len += (int)rec->slave_buffer_size - (int)io->buffer_size;
+@@ -525,21 +634,27 @@ static void a52_free(struct a52_ctx *rec)
+ }
+
+ #ifdef USE_AVCODEC_FRAME
+- if (rec->frame) {
++#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 91, 0)
++ if (rec->frame)
+ av_freep(&rec->frame->data[0]);
+- rec->inbuf = NULL;
+- }
++#endif
+ #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 28, 0)
+ av_frame_free(&rec->frame);
+ #else
+ av_freep(&rec->frame);
+ #endif
+-#endif
+-
++#else /* USE_AVCODEC_FRAME */
+ free(rec->inbuf);
+ rec->inbuf = NULL;
+- free(rec->outbuf);
+- rec->outbuf = NULL;
++#endif /* USE_AVCODEC_FRAME */
++
++#ifdef USE_AVCODEC_PACKET_ALLOC
++ av_packet_free(&rec->pkt);
++#endif
++ free(rec->outbuf2);
++ rec->outbuf2 = NULL;
++ free(rec->outbuf1);
++ rec->outbuf1 = NULL;
+ }
+
+ /*
+@@ -577,14 +692,22 @@ static int alloc_input_buffer(snd_pcm_ioplug_t *io)
+ rec->frame = av_frame_alloc();
+ if (!rec->frame)
+ return -ENOMEM;
++ rec->frame->nb_samples = rec->avctx->frame_size;
++#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(58, 91, 0)
++ rec->frame->format = rec->avctx->sample_fmt;
++ rec->frame->channels = rec->avctx->channels;
++ rec->frame->channel_layout = rec->avctx->channel_layout;
++ if (av_frame_get_buffer(rec->frame, 0))
++ return -ENOMEM;
++#else
+ if (av_samples_alloc(rec->frame->data, rec->frame->linesize,
+ io->channels, rec->avctx->frame_size,
+ rec->avctx->sample_fmt, 0) < 0)
+ return -ENOMEM;
+- rec->frame->nb_samples = rec->avctx->frame_size;
+- rec->inbuf = (short *)rec->frame->data[0];
++#endif
++ rec->inbuf = rec->frame->data[0];
+ #else
+- rec->inbuf = malloc(rec->avctx->frame_size * 2 * io->channels);
++ rec->inbuf = malloc(rec->avctx->frame_size * io->channels *
rec->src_sample_bytes);
+ #endif
+ if (!rec->inbuf)
+ return -ENOMEM;
+@@ -622,15 +745,28 @@ static int a52_prepare(snd_pcm_ioplug_t *io)
+ if (err < 0)
+ return -EINVAL;
+
++#ifdef USE_AVCODEC_PACKET_ALLOC
++ rec->pkt = av_packet_alloc();
++ if (!rec->pkt)
++ return -ENOMEM;
++#endif
++
+ rec->outbuf_size = rec->avctx->frame_size * 4;
+- rec->outbuf = malloc(rec->outbuf_size);
+- if (! rec->outbuf)
++ rec->outbuf1 = malloc(rec->outbuf_size + AV_INPUT_BUFFER_PADDING_SIZE);
++ if (! rec->outbuf1)
+ return -ENOMEM;
++ memset(rec->outbuf1 + rec->outbuf_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
++
++ if (rec->format == SND_PCM_FORMAT_S16_LE) {
++ rec->outbuf2 = malloc(rec->outbuf_size);
++ if ( !rec->outbuf2)
++ return -ENOMEM;
++ }
+
+ if (alloc_input_buffer(io))
+ return -ENOMEM;
+
+- rec->transfer = 0;
++ rec->pointer = 0;
+ rec->remain = 0;
+ rec->filled = 0;
+
+@@ -669,10 +805,9 @@ static int a52_close(snd_pcm_ioplug_t *io)
+ snd_pcm_t *slave = rec->slave;
+
+ a52_free(rec);
+- if (slave) {
+- rec->slave = NULL;
++ free(rec);
++ if (slave)
+ return snd_pcm_close(slave);
+- }
+ return 0;
+ }
+
+@@ -737,6 +872,7 @@ static snd_pcm_ioplug_callback_t a52_ops = {
+ .close = a52_close,
+ .hw_params = a52_hw_params,
+ .hw_free = a52_hw_free,
++ .dump = a52_dump,
+ .sw_params = a52_sw_params,
+ .prepare = a52_prepare,
+ .drain = a52_drain,
+@@ -773,8 +909,20 @@ static int a52_set_hw_constraint(struct a52_ctx *rec)
+ SND_PCM_ACCESS_MMAP_NONINTERLEAVED,
+ SND_PCM_ACCESS_RW_NONINTERLEAVED
+ };
+- unsigned int formats[] = { SND_PCM_FORMAT_S16 };
+- int err;
++ static struct format {
++ int av;
++ snd_pcm_format_t alib;
++ } formats[] = {
++ { .av = AV_SAMPLE_FMT_S16, .alib = SND_PCM_FORMAT_S16 },
++#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 95, 0) && USE_AVCODEC_FRAME
++ { .av = AV_SAMPLE_FMT_S16P, .alib = SND_PCM_FORMAT_S16 },
++ { .av = AV_SAMPLE_FMT_S32, .alib = SND_PCM_FORMAT_S32 },
++ { .av = AV_SAMPLE_FMT_S32P, .alib = SND_PCM_FORMAT_S32 },
++ { .av = AV_SAMPLE_FMT_FLTP, .alib = SND_PCM_FORMAT_FLOAT }
++#endif
++ };
++ int err, dir;
++ unsigned int i, fmt;
+ snd_pcm_uframes_t buffer_max;
+ unsigned int period_bytes, max_periods;
+
+@@ -791,8 +939,22 @@ static int a52_set_hw_constraint(struct a52_ctx *rec)
+ if (err < 0)
+ return err;
+
++ rec->src_format = SND_PCM_FORMAT_UNKNOWN;
++ for (i = 0; i < ARRAY_SIZE(formats); i++)
++ if (formats[i].av == rec->av_format) {
++ rec->src_format = formats[i].alib;
++ break;
++ }
++ if (rec->src_format == SND_PCM_FORMAT_UNKNOWN) {
++ SNDERR("A/V format '%s' is not supported",
av_get_sample_fmt_name(rec->av_format));
++ return -EINVAL;
++ }
++ fmt = rec->src_format;
++ rec->src_sample_bits = snd_pcm_format_physical_width(rec->src_format);
++ rec->src_sample_bytes = rec->src_sample_bits / 8;
++
+ if ((err = snd_pcm_ioplug_set_param_list(&rec->io, SND_PCM_IOPLUG_HW_FORMAT,
+- ARRAY_SIZE(formats), formats)) < 0 ||
++ 1, &fmt)) < 0 ||
+ (err = snd_pcm_ioplug_set_param_minmax(&rec->io,
SND_PCM_IOPLUG_HW_CHANNELS,
+ rec->channels, rec->channels)) < 0 ||
+ (err = snd_pcm_ioplug_set_param_minmax(&rec->io, SND_PCM_IOPLUG_HW_RATE,
+@@ -803,8 +965,11 @@ static int a52_set_hw_constraint(struct a52_ctx *rec)
+ return err;
+
+ snd_pcm_hw_params_get_buffer_size_max(rec->hw_params, &buffer_max);
++ dir = -1;
++ snd_pcm_hw_params_get_periods_max(rec->hw_params, &max_periods, &dir);
+ period_bytes = A52_FRAME_SIZE * 2 * rec->channels;
+- max_periods = buffer_max / A52_FRAME_SIZE;
++ if (buffer_max / A52_FRAME_SIZE < max_periods)
++ max_periods = buffer_max / A52_FRAME_SIZE;
+
+ if ((err = snd_pcm_ioplug_set_param_minmax(&rec->io,
SND_PCM_IOPLUG_HW_PERIOD_BYTES,
+ period_bytes, period_bytes)) < 0 ||
+@@ -824,11 +989,12 @@ SND_PCM_PLUGIN_DEFINE_FUNC(a52)
+ int err;
+ const char *card = NULL;
+ const char *pcm_string = NULL;
++ const char *avcodec = NULL;
+ unsigned int rate = 48000;
+ unsigned int bitrate = 448;
+ unsigned int channels = 6;
+ snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
+- char devstr[128], tmpcard[8];
++ char devstr[128], tmpcard[16];
+ struct a52_ctx *rec;
+
+ if (stream != SND_PCM_STREAM_PLAYBACK) {
+@@ -921,6 +1087,16 @@ SND_PCM_PLUGIN_DEFINE_FUNC(a52)
+ }
+ continue;
+ }
++ if (strcmp(id, "avcodec") == 0) {
++ const char *str;
++ err = snd_config_get_string(n, &str);
++ if (err < 0) {
++ SNDERR("invalid type for %s", id);
++ return -EINVAL;
++ }
++ avcodec = str;
++ continue;
++ }
+ SNDERR("Unknown field %s", id);
+ return -EINVAL;
+ }
+@@ -931,6 +1107,7 @@ SND_PCM_PLUGIN_DEFINE_FUNC(a52)
+ return -ENOMEM;
+ }
+
++ rec->src_format = SND_PCM_FORMAT_UNKNOWN;
+ rec->rate = rate;
+ rec->bitrate = bitrate;
+ rec->channels = channels;
+@@ -939,11 +1116,17 @@ SND_PCM_PLUGIN_DEFINE_FUNC(a52)
+ #ifndef USE_AVCODEC_FRAME
+ avcodec_init();
+ #endif
++#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 91, 0)
+ avcodec_register_all();
++#endif
+
+- rec->codec = avcodec_find_encoder_by_name("ac3_fixed");
+- if (rec->codec == NULL)
+- rec->codec = avcodec_find_encoder_by_name("ac3");
++ if (avcodec) {
++ rec->codec = avcodec_find_encoder_by_name(avcodec);
++ } else {
++ rec->codec = avcodec_find_encoder_by_name("ac3_fixed");
++ if (rec->codec == NULL)
++ rec->codec = avcodec_find_encoder_by_name("ac3");
++ }
+ if (rec->codec == NULL)
+ rec->codec = avcodec_find_encoder(AV_CODEC_ID_AC3);
+ if (rec->codec == NULL) {
+@@ -954,7 +1137,7 @@ SND_PCM_PLUGIN_DEFINE_FUNC(a52)
+
+ if (! pcm_string || pcm_string[0] == '\0') {
+ snprintf(devstr, sizeof(devstr),
+- "iec958:{AES0 0x%x AES1 0x%x AES2 0x%x AES3 0x%x %s%s}",
++ "iec958:{AES0 0x%x AES1 0x%x AES2 0x%x AES3 0x%x%s%s}",
+ IEC958_AES0_CON_EMPHASIS_NONE | IEC958_AES0_NONAUDIO |
+ IEC958_AES0_CON_NOT_COPYRIGHT,
+ IEC958_AES1_CON_ORIGINAL | IEC958_AES1_CON_PCM_CODER,
+@@ -980,6 +1163,9 @@ SND_PCM_PLUGIN_DEFINE_FUNC(a52)
+ rec->io.mmap_rw = 0;
+ rec->io.callback = &a52_ops;
+ rec->io.private_data = rec;
++#ifdef SND_PCM_IOPLUG_FLAG_BOUNDARY_WA
++ rec->io.flags = SND_PCM_IOPLUG_FLAG_BOUNDARY_WA;
++#endif
+ #ifdef USE_AVCODEC_FRAME
+ rec->av_format = rec->codec->sample_fmts[0];
+ rec->is_planar = av_sample_fmt_is_planar(rec->av_format);
+@@ -993,7 +1179,7 @@ SND_PCM_PLUGIN_DEFINE_FUNC(a52)
+
+ if ((err = a52_set_hw_constraint(rec)) < 0) {
+ snd_pcm_ioplug_delete(&rec->io);
+- goto error;
++ return err;
+ }
+
+ *pcmp = rec->io.pcm;
+diff --git a/configure.ac b/configure.ac
+index d5fe529..860daa9 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -93,7 +93,7 @@ AC_ARG_ENABLE([libav],
+ AS_HELP_STRING([--disable-libav], [Do not build plugins depending on libav/ffmpeg
(a52,lavrate...)]))
+
+ if test "x$enable_libav" != "xno"; then
+- PKG_CHECK_MODULES(LIBAV, [libavcodec libavutil libavresample], [HAVE_LIBAV=yes],
[HAVE_LIBAV=no])
++ PKG_CHECK_MODULES(LIBAV, [libavcodec libavutil libswresample], [HAVE_LIBAV=yes],
[HAVE_LIBAV=no])
+ fi
+
+ if test "x$HAVE_LIBAV" = "xno"; then
+diff --git a/doc/lavrate.txt b/doc/lavrate.txt
+index 6575183..fa6bbb0 100644
+--- a/doc/lavrate.txt
++++ b/doc/lavrate.txt
+@@ -2,7 +2,7 @@ Rate Converter Plugin Using libavresample
+ =========================================0
+
+ The plugin in rate-lavr subdirectory is an external rate converter using
+-libavresample library. You can use this rate converter plugin by defining a
++libswresample library. You can use this rate converter plugin by defining a
+ rate PCM with "converter" parameter, such as:
+
+ pcm.my_rate {
+@@ -16,7 +16,7 @@ The plug plugin has also a similar field, "rate_converter".
+ Or, more easily, define a global variable "defaults.pcm.rate_converter",
+ which is used as the default converter type by plug and rate plugins:
+
+- defaults.pcm.rate_converter "lavcrate"
++ defaults.pcm.rate_converter "lavrate"
+
+ Write the above in your ~/.asoundrc or /etc/asound.conf.
+
+diff --git a/jack/Makefile.am b/jack/Makefile.am
+index 7801194..117a5c9 100644
+--- a/jack/Makefile.am
++++ b/jack/Makefile.am
+@@ -12,7 +12,7 @@ AM_CFLAGS = -Wall -g @ALSA_CFLAGS@ @JACK_CFLAGS@
+ AM_LDFLAGS = -module -avoid-version -export-dynamic -no-undefined
$(LDFLAGS_NOUNDEFINED)
+
+ libasound_module_pcm_jack_la_SOURCES = pcm_jack.c
+-libasound_module_pcm_jack_la_LIBADD = @ALSA_LIBS@ @JACK_LIBS@
++libasound_module_pcm_jack_la_LIBADD = @ALSA_LIBS@ @JACK_LIBS@ -lpthread
+
+ include ../install-hooks.am
+
+diff --git a/jack/pcm_jack.c b/jack/pcm_jack.c
+index 26674fa..436aefe 100644
+--- a/jack/pcm_jack.c
++++ b/jack/pcm_jack.c
+@@ -28,6 +28,7 @@
+ #include <jack/jack.h>
+ #include <alsa/asoundlib.h>
+ #include <alsa/pcm_external.h>
++#include <pthread.h>
+
+ #define MAX_PERIODS_MULTIPLE 64
+
+@@ -44,6 +45,8 @@ typedef struct {
+
+ int fd;
+ int activated; /* jack is activated? */
++ pthread_mutex_t running_mutex;
++ int running; /* jack is running? */
+
+ snd_pcm_jack_port_list_t **port_names;
+ unsigned int num_ports;
+@@ -159,6 +162,7 @@ static void snd_pcm_jack_free(snd_pcm_jack_t *jack)
+ free(jack->port_names);
+ jack->port_names = NULL;
+ }
++ pthread_mutex_destroy (&jack->running_mutex);
+ if (jack->fd >= 0)
+ close(jack->fd);
+ if (jack->io.poll_fd >= 0)
+@@ -207,6 +211,18 @@ snd_pcm_jack_process_cb(jack_nframes_t nframes, snd_pcm_ioplug_t
*io)
+ snd_pcm_jack_t *jack = io->private_data;
+ snd_pcm_uframes_t xfer = 0;
+ unsigned int channel;
++
++ if (pthread_mutex_trylock (&jack->running_mutex) == EBUSY) {
++ /* Note that locking should only ever fail if
++ * snd_pcm_jack_start or snd_pcm_jack_stop is called at the
++ * same time, in which case dropping the current buffer is not
++ * an issue. */
++ return 0;
++ }
++ if (!jack->running) {
++ pthread_mutex_unlock (&jack->running_mutex);
++ return 0;
++ }
+
+ for (channel = 0; channel < io->channels; channel++) {
+ jack->areas[channel].addr =
+@@ -268,6 +284,8 @@ snd_pcm_jack_process_cb(jack_nframes_t nframes, snd_pcm_ioplug_t
*io)
+
+ pcm_poll_unblock_check(io); /* unblock socket for polling if needed */
+
++ pthread_mutex_unlock (&jack->running_mutex);
++
+ return 0;
+ }
+
+@@ -365,7 +383,10 @@ static int snd_pcm_jack_prepare(snd_pcm_ioplug_t *io)
+
+ static int snd_pcm_jack_start(snd_pcm_ioplug_t *io)
+ {
+- (void)io;
++ snd_pcm_jack_t *jack = io->private_data;
++ pthread_mutex_lock (&jack->running_mutex);
++ jack->running = 1;
++ pthread_mutex_unlock (&jack->running_mutex);
+ /*
+ * Since the processing of jack_activate() and jack_connect() take a
+ * while longer, snd_pcm_jack_start() was blocked.
+@@ -382,7 +403,10 @@ static int snd_pcm_jack_start(snd_pcm_ioplug_t *io)
+
+ static int snd_pcm_jack_stop(snd_pcm_ioplug_t *io)
+ {
+- (void)io;
++ snd_pcm_jack_t *jack = io->private_data;
++ pthread_mutex_lock (&jack->running_mutex);
++ jack->running = 0;
++ pthread_mutex_unlock (&jack->running_mutex);
+ return 0;
+ }
+
+@@ -548,6 +572,8 @@ static int snd_pcm_jack_open(snd_pcm_t **pcmp, const char *name,
+ if (!jack)
+ return -ENOMEM;
+
++ pthread_mutex_init (&jack->running_mutex, NULL);
++
+ jack->fd = -1;
+ jack->io.poll_fd = -1;
+ jack->use_period_alignment = use_period_alignment;
+diff --git a/rate-lav/rate_lavrate.c b/rate-lav/rate_lavrate.c
+index 2b992c5..f78eea5 100644
+--- a/rate-lav/rate_lavrate.c
++++ b/rate-lav/rate_lavrate.c
+@@ -1,5 +1,5 @@
+ /*
+- * Rate converter plugin using libavresample
++ * Rate converter plugin using libswresample
+ * Copyright (c) 2014 by Anton Khirnov
+ *
+ * This library is free software; you can redistribute it and/or
+@@ -17,7 +17,7 @@
+ #include <alsa/asoundlib.h>
+ #include <alsa/pcm_rate.h>
+
+-#include <libavresample/avresample.h>
++#include <libswresample/swresample.h>
+ #include <libavutil/channel_layout.h>
+ #include <libavutil/opt.h>
+ #include <libavutil/mathematics.h>
+@@ -25,15 +25,15 @@
+
+
+ static unsigned int filter_size = 16;
+-static unsigned int phase_shift = 10; /* auto-adjusts */
+-static double cutoff = 0; /* auto-adjusts */
+
+ struct rate_src {
+- AVAudioResampleContext *avr;
++ SwrContext *avr;
+
+ 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,
+@@ -51,51 +51,67 @@ static snd_pcm_uframes_t output_frames(void *obj ATTRIBUTE_UNUSED,
+ static void pcm_src_free(void *obj)
+ {
+ struct rate_src *rate = obj;
+- avresample_free(&rate->avr);
++ 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 i, ir, or;
++ int fmt;
+
+ if (!rate->avr || rate->channels != info->channels) {
+ int ret;
+
+ pcm_src_free(rate);
+ rate->channels = info->channels;
+- ir = rate->in_rate = info->in.rate;
+- or = rate->out_rate = info->out.rate;
+- i = av_gcd(or, ir);
+- if (or > ir) {
+- phase_shift = or/i;
+- } else {
+- phase_shift = ir/i;
+- }
+- if (cutoff <= 0.0) {
+- cutoff = 1.0 - 1.0/filter_size;
+- if (cutoff < 0.80)
+- cutoff = 0.80;
+- }
++ rate->in_rate = info->in.rate;
++ rate->out_rate = info->out.rate;
+
+- rate->avr = avresample_alloc_context();
++ rate->avr = swr_alloc();
+ if (!rate->avr)
+ return -ENOMEM;
+
+- av_opt_set_int(rate->avr, "in_sample_rate", info->in.rate, 0);
+- av_opt_set_int(rate->avr, "out_sample_rate", info->out.rate, 0);
+- av_opt_set_int(rate->avr, "in_sample_format", AV_SAMPLE_FMT_S16, 0);
+- av_opt_set_int(rate->avr, "out_sample_format", AV_SAMPLE_FMT_S16, 0);
+- av_opt_set_int(rate->avr, "in_channel_layout",
av_get_default_channel_layout(rate->channels), 0);
+- av_opt_set_int(rate->avr, "out_channel_layout",
av_get_default_channel_layout(rate->channels), 0);
+-
+- av_opt_set_int(rate->avr, "filter_size", filter_size, 0);
+- av_opt_set_int(rate->avr, "phase_shift", phase_shift, 0);
+- av_opt_set_double(rate->avr, "cutoff", cutoff, 0);
+-
+- ret = avresample_open(rate->avr);
++ av_opt_set_channel_layout(rate->avr, "in_channel_layout",
++ av_get_default_channel_layout(rate->channels), 0);
++ av_opt_set_channel_layout(rate->avr, "out_channel_layout",
++ 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);
++ 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) {
+- avresample_free(&rate->avr);
++ SNDERR("sw_init() error %d\n", ret);
++ swr_free(&rate->avr);
+ return -EINVAL;
+ }
+ }
+@@ -118,26 +134,51 @@ static void pcm_src_reset(void *obj)
+
+ if (rate->avr) {
+ #if 0
+- avresample_close(rate->avr);
+- avresample_open(rate->avr);
++ swr_free(rate->avr);
++ swr_init(rate->avr);
+ #endif
+ }
+ }
+
++static void do_convert(struct rate_src *rate,
++ void *dst, unsigned int dst_frames,
++ const void *src, unsigned int src_frames)
++{
++ unsigned int total_in = swr_get_delay(rate->avr, rate->in_rate) + src_frames;
++
++ swr_convert(rate->avr, (uint8_t **)&dst, dst_frames,
++ (const uint8_t **)&src, src_frames);
++
++ swr_set_compensation(rate->avr,
++ total_in - src_frames > filter_size ? 0 : 1,
++ src_frames);
++}
++
++#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003
++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 = snd_pcm_channel_area_addr(src_areas, src_offset);
++ void *dst = snd_pcm_channel_area_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;
+- int chans = rate->channels;
+- unsigned int total_in = avresample_get_delay(rate->avr) + src_frames;
+
+- avresample_convert(rate->avr, (uint8_t **)&dst, dst_frames * chans * 2,
dst_frames,
+- (uint8_t **)&src, src_frames * chans * 2, src_frames);
+-
+- avresample_set_compensation(rate->avr,
+- total_in - src_frames > filter_size ? 0 : 1,
src_frames);
++ do_convert(rate, dst, dst_frames, src, src_frames);
+ }
+
+ static void pcm_src_close(void *obj)
+@@ -156,7 +197,21 @@ static int get_supported_rates(void *obj ATTRIBUTE_UNUSED,
+
+ static void dump(void *obj ATTRIBUTE_UNUSED, snd_output_t *out)
+ {
+- snd_output_printf(out, "Converter: libavr\n");
++ snd_output_printf(out, "Converter: libswresample\n");
++}
++#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
+
+@@ -166,6 +221,9 @@ static snd_pcm_rate_ops_t pcm_src_ops = {
+ .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,
+@@ -174,31 +232,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;
+ }
+
+diff --git a/rate/rate_samplerate.c b/rate/rate_samplerate.c
+index 100d6f2..dd0a416 100644
+--- a/rate/rate_samplerate.c
++++ b/rate/rate_samplerate.c
+@@ -40,9 +40,12 @@
+ #include <alsa/pcm_rate.h>
+
+ struct rate_src {
++ unsigned int version;
+ double ratio;
+ int converter;
+ unsigned int channels;
++ int in_int;
++ int out_int;
+ float *src_buf;
+ float *dst_buf;
+ SRC_STATE *state;
+@@ -109,6 +112,13 @@ static int pcm_src_init(void *obj, snd_pcm_rate_info_t *info)
+ rate->data.src_ratio = rate->ratio;
+ rate->data.end_of_input = 0;
+
++#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003
++ if (rate->version >= 0x010003) {
++ rate->in_int = info->in.format == SND_PCM_FORMAT_S32;
++ rate->out_int = info->out.format == SND_PCM_FORMAT_S32;
++ }
++#endif
++
+ return 0;
+ }
+
+@@ -128,24 +138,56 @@ static void pcm_src_reset(void *obj)
+ src_reset(rate->state);
+ }
+
+-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 ofs;
+
+ rate->data.input_frames = src_frames;
+ rate->data.output_frames = dst_frames;
+ rate->data.end_of_input = 0;
+
+- src_short_to_float_array(src, rate->src_buf, src_frames * rate->channels);
++ if (rate->in_int)
++ src_int_to_float_array(src, rate->src_buf, src_frames * rate->channels);
++ else
++ src_short_to_float_array(src, rate->src_buf, src_frames * rate->channels);
+ src_process(rate->state, &rate->data);
+ if (rate->data.output_frames_gen < dst_frames)
+ ofs = dst_frames - rate->data.output_frames_gen;
+ else
+ ofs = 0;
+- src_float_to_short_array(rate->dst_buf, dst + ofs * rate->channels,
+- rate->data.output_frames_gen * rate->channels);
++ if (rate->out_int)
++ src_float_to_int_array(rate->dst_buf, dst + ofs * rate->channels * 4,
++ rate->data.output_frames_gen * rate->channels);
++ else
++ src_float_to_short_array(rate->dst_buf, dst + ofs * rate->channels * 2,
++ rate->data.output_frames_gen * rate->channels);
++}
++
++#if SND_PCM_RATE_PLUGIN_VERSION >= 0x010003
++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 = snd_pcm_channel_area_addr(src_areas, src_offset);
++ void *dst = snd_pcm_channel_area_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)
+@@ -167,12 +209,28 @@ 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_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,
+@@ -181,6 +239,9 @@ 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
+ };
+
+ static int pcm_src_open(unsigned int version, void **objp,
+@@ -188,24 +249,27 @@ static int pcm_src_open(unsigned int version, void **objp,
+ {
+ 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;
++
++ rate->version = version;
+ rate->converter = type;
+
+ *objp = rate;
+ #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;
+ }
+
diff --git a/alsa-plugins-freeworld.spec b/alsa-plugins-freeworld.spec
index 6f5404a..7810253 100644
--- a/alsa-plugins-freeworld.spec
+++ b/alsa-plugins-freeworld.spec
@@ -1,11 +1,12 @@
Name: alsa-plugins-freeworld
Version: 1.2.5
-Release: 2%{?dist}
+Release: 3%{?dist}
Summary: The ALSA Plugins - freeworld version
# All packages are LGPLv2+ with the exception of samplerate which is GPLv2+
License: LGPLv2+
URL:
http://www.alsa-project.org/
Source0:
https://www.alsa-project.org/files/pub/plugins/alsa-plugins-%{version}.ta...
+Patch0: alsa-git.patch
BuildRequires: autoconf automake libtool
BuildRequires: alsa-lib-devel >= 1.1.8
@@ -40,6 +41,7 @@ The plugin uses ffmpeg audio resample library to convert audio rates.
%prep
%setup -q -n alsa-plugins-%{version}%{?prever}
+%patch0 -p1 -b .alsa-git
%build
%configure --disable-static \
@@ -86,6 +88,9 @@ find %buildroot -name "*.la" -exec rm {} \;
%changelog
+* Tue Nov 9 2021 Jaroslav Kysela <perex(a)perex.cz> - 1.2.5-3
+- Updated to latest ALSA git (use libswresample)
+
* Mon Aug 02 2021 RPM Fusion Release Engineering <leigh123linux(a)gmail.com> -
1.2.5-2
- Rebuilt for
https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild