diff options
author | Max Kellermann <max@duempel.org> | 2012-03-27 00:03:44 +0200 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2012-03-27 01:17:11 +0200 |
commit | ebfdd37451cea0151de74005d83db5ac31fcaf77 (patch) | |
tree | e87c20dc2951cdb617d78201d14e0b65476d2b2c | |
parent | f6d6110aaaf6ba3e252323c2bf6360ea9782dff2 (diff) | |
download | mpd-ebfdd37451cea0151de74005d83db5ac31fcaf77.tar.gz mpd-ebfdd37451cea0151de74005d83db5ac31fcaf77.tar.xz mpd-ebfdd37451cea0151de74005d83db5ac31fcaf77.zip |
pcm_export: support DSD to DSD-over-USB conversion
Prepare for removing SAMPLE_FORMAT_DSD_OVER_USB.
-rw-r--r-- | src/output/alsa_output_plugin.c | 8 | ||||
-rw-r--r-- | src/output/oss_output_plugin.c | 10 | ||||
-rw-r--r-- | src/pcm_export.c | 31 | ||||
-rw-r--r-- | src/pcm_export.h | 35 |
4 files changed, 74 insertions, 10 deletions
diff --git a/src/output/alsa_output_plugin.c b/src/output/alsa_output_plugin.c index 21c3b1d22..d131003e3 100644 --- a/src/output/alsa_output_plugin.c +++ b/src/output/alsa_output_plugin.c @@ -633,8 +633,9 @@ alsa_setup_or_dsd(struct alsa_data *ad, struct audio_format *audio_format, if (!success) return false; - pcm_export_open(&ad->export, audio_format->format, - packed, reverse_endian); + pcm_export_open(&ad->export, + audio_format->format, audio_format->channels, + false, packed, reverse_endian); return true; } @@ -777,7 +778,8 @@ alsa_play(struct audio_output *ao, const void *chunk, size_t size, if (ret > 0) { ad->period_position = (ad->period_position + ret) % ad->period_frames; - return ret * ad->in_frame_size; + return pcm_export_source_size(&ad->export, + ret * ad->in_frame_size); } if (ret < 0 && ret != -EAGAIN && ret != -EINTR && diff --git a/src/output/oss_output_plugin.c b/src/output/oss_output_plugin.c index 0724ed4c2..85bdc37dc 100644 --- a/src/output/oss_output_plugin.c +++ b/src/output/oss_output_plugin.c @@ -540,7 +540,7 @@ oss_probe_sample_format(int fd, enum sample_format sample_format, *oss_format_r = oss_format; #ifdef AFMT_S24_PACKED - pcm_export_open(export, sample_format, + pcm_export_open(export, sample_format, 0, false, oss_format == AFMT_S24_PACKED, oss_format == AFMT_S24_PACKED && G_BYTE_ORDER != G_LITTLE_ENDIAN); @@ -755,8 +755,12 @@ oss_output_play(struct audio_output *ao, const void *chunk, size_t size, while (true) { ret = write(od->fd, chunk, size); - if (ret > 0) - return (size_t)ret; + if (ret > 0) { +#ifdef AFMT_S24_PACKED + ret = pcm_export_source_size(&od->export, ret); +#endif + return ret; + } if (ret < 0 && errno != EINTR) { g_set_error(error, oss_output_quark(), errno, diff --git a/src/pcm_export.c b/src/pcm_export.c index 134acc18f..66ed6d351 100644 --- a/src/pcm_export.c +++ b/src/pcm_export.c @@ -19,6 +19,7 @@ #include "config.h" #include "pcm_export.h" +#include "pcm_dsd_usb.h" #include "pcm_pack.h" #include "util/byte_reverse.h" @@ -27,19 +28,31 @@ pcm_export_init(struct pcm_export_state *state) { pcm_buffer_init(&state->reverse_buffer); pcm_buffer_init(&state->pack_buffer); + pcm_buffer_init(&state->dsd_buffer); } void pcm_export_deinit(struct pcm_export_state *state) { pcm_buffer_deinit(&state->reverse_buffer); pcm_buffer_deinit(&state->pack_buffer); + pcm_buffer_deinit(&state->dsd_buffer); } void pcm_export_open(struct pcm_export_state *state, - enum sample_format sample_format, - bool pack, bool reverse_endian) + enum sample_format sample_format, unsigned channels, + bool dsd_usb, bool pack, bool reverse_endian) { + assert(audio_valid_sample_format(sample_format)); + assert(!dsd_usb || audio_valid_channel_count(channels)); + + state->channels = channels; + state->dsd_usb = dsd_usb && sample_format == SAMPLE_FORMAT_DSD; + if (state->dsd_usb) + /* after the conversion to DSD-over-USB, the DSD + samples are stuffed inside fake 24 bit samples */ + sample_format = SAMPLE_FORMAT_S24_P32; + state->pack24 = pack && (sample_format == SAMPLE_FORMAT_S24_P32 || sample_format == SAMPLE_FORMAT_DSD_OVER_USB); state->reverse_endian = 0; @@ -58,6 +71,10 @@ const void * pcm_export(struct pcm_export_state *state, const void *data, size_t size, size_t *dest_size_r) { + if (state->dsd_usb) + data = pcm_dsd_to_usb(&state->dsd_buffer, state->channels, + data, size, &size); + if (state->pack24) { assert(size % 4 == 0); @@ -90,3 +107,13 @@ pcm_export(struct pcm_export_state *state, const void *data, size_t size, *dest_size_r = size; return data; } + +size_t +pcm_export_source_size(const struct pcm_export_state *state, size_t size) +{ + if (state->dsd_usb) + /* DSD over USB doubles the transport size */ + size /= 2; + + return size; +} diff --git a/src/pcm_export.h b/src/pcm_export.h index 7ce35c096..c132c7169 100644 --- a/src/pcm_export.h +++ b/src/pcm_export.h @@ -35,6 +35,14 @@ struct audio_format; */ struct pcm_export_state { /** + * The buffer is used to convert DSD samples to the + * DSD-over-USB format. + * + * @see #dsd_usb + */ + struct pcm_buffer dsd_buffer; + + /** * The buffer is used to pack samples, removing padding. * * @see #pack24 @@ -49,6 +57,18 @@ struct pcm_export_state { struct pcm_buffer reverse_buffer; /** + * The number of channels. + */ + uint8_t channels; + + /** + * Convert DSD to DSD-over-USB? Input format must be + * SAMPLE_FORMAT_DSD and output format must be + * SAMPLE_FORMAT_S24_P32. + */ + bool dsd_usb; + + /** * Pack 24 bit samples? */ bool pack24; @@ -80,11 +100,13 @@ pcm_export_deinit(struct pcm_export_state *state); * times to reuse the object, until pcm_export_deinit() is called. * * This function cannot fail. + * + * @param channels the number of channels; ignored unless dsd_usb is set */ void pcm_export_open(struct pcm_export_state *state, - enum sample_format sample_format, - bool pack, bool reverse_endian); + enum sample_format sample_format, unsigned channels, + bool dsd_usb, bool pack, bool reverse_endian); /** * Export a PCM buffer. @@ -99,4 +121,13 @@ const void * pcm_export(struct pcm_export_state *state, const void *src, size_t src_size, size_t *dest_size_r); +/** + * Converts the number of consumed bytes from the pcm_export() + * destination buffer to the according number of bytes from the + * pcm_export() source buffer. + */ +G_GNUC_PURE +size_t +pcm_export_source_size(const struct pcm_export_state *state, size_t dest_size); + #endif |