pcm_export: support DSD to DSD-over-USB conversion
Prepare for removing SAMPLE_FORMAT_DSD_OVER_USB.
This commit is contained in:
		| @@ -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 && | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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; | ||||
| } | ||||
|   | ||||
| @@ -34,6 +34,14 @@ struct audio_format; | ||||
|  * representation which are not supported by the pcm_convert library. | ||||
|  */ | ||||
| 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. | ||||
| 	 * | ||||
| @@ -48,6 +56,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? | ||||
| 	 */ | ||||
| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Max Kellermann
					Max Kellermann