From 49ede85827c095d0a6ead0ecb63e83e000a76d4f Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sun, 19 Jul 2009 16:43:08 +0100 Subject: [PATCH] Support wrong-endian ALSA output --- src/output/alsa_plugin.c | 52 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/src/output/alsa_plugin.c b/src/output/alsa_plugin.c index 818c83ca2..f271668b1 100644 --- a/src/output/alsa_plugin.c +++ b/src/output/alsa_plugin.c @@ -183,6 +183,19 @@ get_bitformat(const struct audio_format *af) return SND_PCM_FORMAT_UNKNOWN; } +static snd_pcm_format_t +byteswap_bitformat(snd_pcm_format_t fmt) +{ + switch(fmt) { + case SND_PCM_FORMAT_S16_LE: return SND_PCM_FORMAT_S16_BE; + case SND_PCM_FORMAT_S24_LE: return SND_PCM_FORMAT_S24_BE; + case SND_PCM_FORMAT_S32_LE: return SND_PCM_FORMAT_S32_BE; + case SND_PCM_FORMAT_S16_BE: return SND_PCM_FORMAT_S16_LE; + case SND_PCM_FORMAT_S24_BE: return SND_PCM_FORMAT_S24_LE; + case SND_PCM_FORMAT_S32_BE: return SND_PCM_FORMAT_S32_LE; + default: return SND_PCM_FORMAT_UNKNOWN; + } +} /** * Set up the snd_pcm_t object which was opened by the caller. Set up * the configured settings and the audio format. @@ -208,7 +221,6 @@ alsa_setup(struct alsa_data *ad, struct audio_format *audio_format, configure_hw: /* configure HW params */ snd_pcm_hw_params_alloca(&hwparams); - cmd = "snd_pcm_hw_params_any"; err = snd_pcm_hw_params_any(ad->pcm, hwparams); if (err < 0) @@ -236,13 +248,38 @@ configure_hw: } err = snd_pcm_hw_params_set_format(ad->pcm, hwparams, bitformat); + if (err == -EINVAL && + byteswap_bitformat(bitformat) != SND_PCM_FORMAT_UNKNOWN) { + err = snd_pcm_hw_params_set_format(ad->pcm, hwparams, + byteswap_bitformat(bitformat)); + if (err == 0) { + g_debug("ALSA device \"%s\": converting %u bit to reverse-endian\n", + alsa_device(ad), audio_format->bits); + audio_format->reverse_endian = 1; + } + } if (err == -EINVAL && (audio_format->bits == 24 || audio_format->bits == 16)) { /* fall back to 32 bit, let pcm_convert.c do the conversion */ err = snd_pcm_hw_params_set_format(ad->pcm, hwparams, SND_PCM_FORMAT_S32); - if (err == 0) + if (err == 0) { + g_debug("ALSA device \"%s\": converting %u bit to 32 bit\n", + alsa_device(ad), audio_format->bits); audio_format->bits = 32; + } + } + if (err == -EINVAL && (audio_format->bits == 24 || + audio_format->bits == 16)) { + /* fall back to 32 bit, let pcm_convert.c do the conversion */ + err = snd_pcm_hw_params_set_format(ad->pcm, hwparams, + byteswap_bitformat(SND_PCM_FORMAT_S32)); + if (err == 0) { + g_debug("ALSA device \"%s\": converting %u bit to 32 bit backward-endian\n", + alsa_device(ad), audio_format->bits); + audio_format->bits = 32; + audio_format->reverse_endian = 1; + } } if (err == -EINVAL && audio_format->bits != 16) { @@ -255,6 +292,17 @@ configure_hw: audio_format->bits = 16; } } + if (err == -EINVAL && audio_format->bits != 16) { + /* fall back to 16 bit, let pcm_convert.c do the conversion */ + err = snd_pcm_hw_params_set_format(ad->pcm, hwparams, + byteswap_bitformat(SND_PCM_FORMAT_S16)); + if (err == 0) { + g_debug("ALSA device \"%s\": converting %u bit to 16 bit backward-endian\n", + alsa_device(ad), audio_format->bits); + audio_format->bits = 16; + audio_format->reverse_endian = 1; + } + } if (err < 0) { g_set_error(error, alsa_output_quark(), err,