From 85ab7c305744b3b2cb16fc200f1619099c2ba3f3 Mon Sep 17 00:00:00 2001 From: ejurgensen Date: Tue, 22 Oct 2019 19:41:48 +0200 Subject: [PATCH] [alsa] Fix playback of 24 bit audio (issue #830) The player will write 24 bit samples using 3 bytes, not 4, so the appropriate sample format is SND_PCM_FORMAT_S24_3LE, not SND_PCM_FORMAT_S24_LE. For extra protection we also use snd_pcm_bytes_to_frames() instead of BTOS(), because that way we can be more certain that the buffer is not too short for snd_pcm_writei(). --- src/outputs/alsa.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/outputs/alsa.c b/src/outputs/alsa.c index ed1a0d9c..64d2dba8 100644 --- a/src/outputs/alsa.c +++ b/src/outputs/alsa.c @@ -179,7 +179,7 @@ bps2format(int bits_per_sample) if (bits_per_sample == 16) return SND_PCM_FORMAT_S16_LE; else if (bits_per_sample == 24) - return SND_PCM_FORMAT_S24_LE; + return SND_PCM_FORMAT_S24_3LE; else if (bits_per_sample == 32) return SND_PCM_FORMAT_S32_LE; else @@ -631,7 +631,7 @@ static int buffer_write(struct alsa_playback_session *pb, struct output_data *odata, snd_pcm_sframes_t avail) { uint8_t *buf; - size_t bufsize; + ssize_t bufsize; size_t wrote; snd_pcm_sframes_t nsamp; snd_pcm_sframes_t ret; @@ -643,7 +643,7 @@ buffer_write(struct alsa_playback_session *pb, struct output_data *odata, snd_pc if (wrote < odata->bufsize) DPRINTF(E_WARN, L_LAUDIO, "Bug! Partial prebuf write %zu/%zu\n", wrote, odata->bufsize); - nsamp = BTOS(wrote, pb->quality.bits_per_sample, pb->quality.channels); + nsamp = snd_pcm_bytes_to_frames(pb->pcm, wrote); return nsamp; } @@ -651,7 +651,7 @@ buffer_write(struct alsa_playback_session *pb, struct output_data *odata, snd_pc if (pb->prebuf.read_avail != 0) { // Maximum amount of bytes we want to read - bufsize = STOB(avail, pb->quality.bits_per_sample, pb->quality.channels); + bufsize = snd_pcm_frames_to_bytes(pb->pcm, avail); bufsize = ringbuffer_read(&buf, bufsize, &pb->prebuf); if (bufsize == 0) @@ -659,7 +659,8 @@ buffer_write(struct alsa_playback_session *pb, struct output_data *odata, snd_pc // DPRINTF(E_DBG, L_LAUDIO, "Writing prebuffer (read_avail=%zu, bufsize=%zu, avail=%li)\n", pb->prebuf.read_avail, bufsize, avail); - nsamp = BTOS(bufsize, pb->quality.bits_per_sample, pb->quality.channels); + nsamp = snd_pcm_bytes_to_frames(pb->pcm, bufsize); + ret = snd_pcm_writei(pb->pcm, buf, nsamp); if (ret < 0) return ret; @@ -680,7 +681,9 @@ buffer_write(struct alsa_playback_session *pb, struct output_data *odata, snd_pc return odata->samples; } - ret = snd_pcm_writei(pb->pcm, odata->buffer, odata->samples); + nsamp = snd_pcm_bytes_to_frames(pb->pcm, odata->bufsize); + + ret = snd_pcm_writei(pb->pcm, odata->buffer, nsamp); if (ret < 0) return ret; @@ -808,7 +811,7 @@ static int playback_drain(struct alsa_playback_session *pb) { uint8_t *buf; - size_t bufsize; + ssize_t bufsize; snd_pcm_state_t state; snd_pcm_sframes_t avail; snd_pcm_sframes_t delay; @@ -836,7 +839,7 @@ playback_drain(struct alsa_playback_session *pb) } // Maximum amount of bytes we want to read - bufsize = STOB(avail, pb->quality.bits_per_sample, pb->quality.channels); + bufsize = snd_pcm_frames_to_bytes(pb->pcm, avail); bufsize = ringbuffer_read(&buf, bufsize, &pb->prebuf); if (bufsize == 0) @@ -844,7 +847,7 @@ playback_drain(struct alsa_playback_session *pb) // DPRINTF(E_DBG, L_LAUDIO, "Draining prebuffer (read_avail=%zu, bufsize=%zu, avail=%li)\n", pb->prebuf.read_avail / 4, bufsize, avail); - nsamp = BTOS(bufsize, pb->quality.bits_per_sample, pb->quality.channels); + nsamp = snd_pcm_bytes_to_frames(pb->pcm, bufsize); ret = snd_pcm_writei(pb->pcm, buf, nsamp);