diff options
Diffstat (limited to 'src/output/alsa_plugin.c')
-rw-r--r-- | src/output/alsa_plugin.c | 69 |
1 files changed, 62 insertions, 7 deletions
diff --git a/src/output/alsa_plugin.c b/src/output/alsa_plugin.c index 818c83ca2..870115998 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, @@ -448,11 +496,19 @@ alsa_recover(struct alsa_data *ad, int err) } static void +alsa_drain(void *data) +{ + struct alsa_data *ad = data; + + snd_pcm_drain(ad->pcm); +} + +static void alsa_cancel(void *data) { struct alsa_data *ad = data; - alsa_recover(ad, snd_pcm_drop(ad->pcm)); + snd_pcm_drop(ad->pcm); } static void @@ -460,9 +516,6 @@ alsa_close(void *data) { struct alsa_data *ad = data; - if (snd_pcm_state(ad->pcm) == SND_PCM_STATE_RUNNING) - snd_pcm_drain(ad->pcm); - snd_pcm_close(ad->pcm); } @@ -494,7 +547,9 @@ const struct audio_output_plugin alsaPlugin = { .finish = alsa_finish, .open = alsa_open, .play = alsa_play, + .drain = alsa_drain, .cancel = alsa_cancel, .close = alsa_close, - .mixer_plugin = &alsa_mixer, + + .mixer_plugin = &alsa_mixer_plugin, }; |