diff options
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | src/output/alsa_output_plugin.c | 64 |
2 files changed, 62 insertions, 3 deletions
diff --git a/Makefile.am b/Makefile.am index 3115ceb08..7a59cb6a9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1201,6 +1201,7 @@ test_run_output_LDADD = $(MPD_LIBS) \ $(ENCODER_LIBS) \ libmixer_plugins.a \ $(FILTER_LIBS) \ + libutil.a \ $(GLIB_LIBS) test_run_output_SOURCES = test/run_output.c \ test/stdbin.h \ diff --git a/src/output/alsa_output_plugin.c b/src/output/alsa_output_plugin.c index 35bea3ce5..c62ad2a46 100644 --- a/src/output/alsa_output_plugin.c +++ b/src/output/alsa_output_plugin.c @@ -21,6 +21,8 @@ #include "alsa_output_plugin.h" #include "output_api.h" #include "mixer_list.h" +#include "pcm_buffer.h" +#include "pcm_byteswap.h" #include <glib.h> #include <alsa/asoundlib.h> @@ -45,6 +47,13 @@ typedef snd_pcm_sframes_t alsa_writei_t(snd_pcm_t * pcm, const void *buffer, struct alsa_data { struct audio_output base; + /** + * The buffer used to reverse the byte order. + * + * @see #reverse_endian + */ + struct pcm_buffer reverse_buffer; + /** the configured name of the ALSA device; NULL for the default device */ char *device; @@ -52,6 +61,21 @@ struct alsa_data { /** use memory mapped I/O? */ bool use_mmap; + /** + * Does ALSA expect samples in reverse byte order? (i.e. not + * host byte order) + * + * This attribute is only valid while the device is open. + */ + bool reverse_endian; + + /** + * Which sample format is being sent to the play() method? + * + * This attribute is only valid while the device is open. + */ + enum sample_format sample_format; + /** libasound's buffer_time setting (in microseconds) */ unsigned int buffer_time; @@ -168,6 +192,23 @@ alsa_finish(struct audio_output *ao) } static bool +alsa_output_enable(struct audio_output *ao, G_GNUC_UNUSED GError **error_r) +{ + struct alsa_data *ad = (struct alsa_data *)ao; + + pcm_buffer_init(&ad->reverse_buffer); + return true; +} + +static void +alsa_output_disable(struct audio_output *ao) +{ + struct alsa_data *ad = (struct alsa_data *)ao; + + pcm_buffer_deinit(&ad->reverse_buffer); +} + +static bool alsa_test_default_device(void) { snd_pcm_t *handle; @@ -288,13 +329,18 @@ alsa_output_try_reverse(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams, static int alsa_output_try_format_both(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams, struct audio_format *audio_format, + bool *reverse_endian_r, enum sample_format sample_format) { + *reverse_endian_r = false; + int err = alsa_output_try_format(pcm, hwparams, audio_format, sample_format); - if (err == -EINVAL) + if (err == -EINVAL) { + *reverse_endian_r = true; err = alsa_output_try_reverse(pcm, hwparams, audio_format, sample_format); + } return err; } @@ -304,11 +350,13 @@ alsa_output_try_format_both(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams, */ static int alsa_output_setup_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams, - struct audio_format *audio_format) + struct audio_format *audio_format, + bool *reverse_endian_r) { /* try the input format first */ int err = alsa_output_try_format_both(pcm, hwparams, audio_format, + reverse_endian_r, audio_format->format); if (err != -EINVAL) return err; @@ -329,6 +377,7 @@ alsa_output_setup_format(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwparams, continue; err = alsa_output_try_format_both(pcm, hwparams, audio_format, + reverse_endian_r, probe_formats[i]); if (err != -EINVAL) return err; @@ -387,7 +436,8 @@ configure_hw: ad->writei = snd_pcm_writei; } - err = alsa_output_setup_format(ad->pcm, hwparams, audio_format); + err = alsa_output_setup_format(ad->pcm, hwparams, audio_format, + &ad->reverse_endian); if (err < 0) { g_set_error(error, alsa_output_quark(), err, "ALSA device \"%s\" does not support format %s: %s", @@ -397,6 +447,8 @@ configure_hw: return false; } + ad->sample_format = audio_format->format; + err = snd_pcm_hw_params_set_channels_near(ad->pcm, hwparams, &channels); if (err < 0) { @@ -660,6 +712,10 @@ alsa_play(struct audio_output *ao, const void *chunk, size_t size, { struct alsa_data *ad = (struct alsa_data *)ao; + if (ad->reverse_endian) + chunk = pcm_byteswap(&ad->reverse_buffer, ad->sample_format, + chunk, size); + size /= ad->frame_size; while (true) { @@ -684,6 +740,8 @@ const struct audio_output_plugin alsa_output_plugin = { .test_default_device = alsa_test_default_device, .init = alsa_init, .finish = alsa_finish, + .enable = alsa_output_enable, + .disable = alsa_output_disable, .open = alsa_open, .play = alsa_play, .drain = alsa_drain, |