Support wrong-endian ALSA output

This commit is contained in:
David Woodhouse 2009-07-19 16:43:08 +01:00
parent 05693e2d5d
commit 49ede85827
1 changed files with 50 additions and 2 deletions

View File

@ -183,6 +183,19 @@ get_bitformat(const struct audio_format *af)
return SND_PCM_FORMAT_UNKNOWN; 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 * Set up the snd_pcm_t object which was opened by the caller. Set up
* the configured settings and the audio format. * 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:
/* configure HW params */ /* configure HW params */
snd_pcm_hw_params_alloca(&hwparams); snd_pcm_hw_params_alloca(&hwparams);
cmd = "snd_pcm_hw_params_any"; cmd = "snd_pcm_hw_params_any";
err = snd_pcm_hw_params_any(ad->pcm, hwparams); err = snd_pcm_hw_params_any(ad->pcm, hwparams);
if (err < 0) if (err < 0)
@ -236,13 +248,38 @@ configure_hw:
} }
err = snd_pcm_hw_params_set_format(ad->pcm, hwparams, bitformat); 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 || if (err == -EINVAL && (audio_format->bits == 24 ||
audio_format->bits == 16)) { audio_format->bits == 16)) {
/* fall back to 32 bit, let pcm_convert.c do the conversion */ /* fall back to 32 bit, let pcm_convert.c do the conversion */
err = snd_pcm_hw_params_set_format(ad->pcm, hwparams, err = snd_pcm_hw_params_set_format(ad->pcm, hwparams,
SND_PCM_FORMAT_S32); 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; 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) { if (err == -EINVAL && audio_format->bits != 16) {
@ -255,6 +292,17 @@ configure_hw:
audio_format->bits = 16; 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) { if (err < 0) {
g_set_error(error, alsa_output_quark(), err, g_set_error(error, alsa_output_quark(), err,