output/alsa: add option to enable DSD over USB
This commit is contained in:
		
							
								
								
									
										1
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								NEWS
									
									
									
									
									
								
							| @@ -17,6 +17,7 @@ ver 0.17 (2011/??/??) | ||||
|   - oggflac: delete this obsolete plugin | ||||
|   - dsdiff: new decoder plugin | ||||
| * output: | ||||
|   - alsa: support DSD-over-USB (dCS suggested standard) | ||||
|   - httpd: support for streaming to a DLNA client | ||||
|   - openal: improve buffer cancellation | ||||
|   - osx: allow user to specify other audio devices | ||||
|   | ||||
							
								
								
									
										17
									
								
								doc/user.xml
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								doc/user.xml
									
									
									
									
									
								
							| @@ -1119,6 +1119,23 @@ systemctl start mpd.socket</programlisting> | ||||
|                   bit, floating point, ...). | ||||
|                 </entry> | ||||
|               </row> | ||||
|               <row> | ||||
|                 <entry> | ||||
|                   <varname>dsd_usb</varname> | ||||
|                   <parameter>yes|no</parameter> | ||||
|                 </entry> | ||||
|                 <entry> | ||||
|                   If set to <parameter>yes</parameter>, then DSD over | ||||
|                   USB according to the <ulink | ||||
|                   url="http://www.dcsltd.co.uk/page/assets/DSDoverUSB.pdf">dCS | ||||
|                   suggested standard</ulink> is enabled.  This wrapsa | ||||
|                   DSD samples in fake 24 bit PCM, and is understood by | ||||
|                   some DSD capable products, but may be harmful to | ||||
|                   other hardware.  Therefore, the default is | ||||
|                   <parameter>no</parameter> and you can enable the | ||||
|                   option at your own risk. | ||||
|                 </entry> | ||||
|               </row> | ||||
|             </tbody> | ||||
|           </tgroup> | ||||
|         </informaltable> | ||||
|   | ||||
| @@ -55,6 +55,14 @@ struct alsa_data { | ||||
| 	/** use memory mapped I/O? */ | ||||
| 	bool use_mmap; | ||||
|  | ||||
| 	/** | ||||
| 	 * Enable DSD over USB according to the dCS suggested | ||||
| 	 * standard? | ||||
| 	 * | ||||
| 	 * @see http://www.dcsltd.co.uk/page/assets/DSDoverUSB.pdf | ||||
| 	 */ | ||||
| 	bool dsd_usb; | ||||
|  | ||||
| 	/** libasound's buffer_time setting (in microseconds) */ | ||||
| 	unsigned int buffer_time; | ||||
|  | ||||
| @@ -128,6 +136,8 @@ alsa_configure(struct alsa_data *ad, const struct config_param *param) | ||||
|  | ||||
| 	ad->use_mmap = config_get_block_bool(param, "use_mmap", false); | ||||
|  | ||||
| 	ad->dsd_usb = config_get_block_bool(param, "dsd_usb", false); | ||||
|  | ||||
| 	ad->buffer_time = config_get_block_unsigned(param, "buffer_time", | ||||
| 			MPD_ALSA_BUFFER_TIME_US); | ||||
| 	ad->period_time = config_get_block_unsigned(param, "period_time", 0); | ||||
| @@ -575,6 +585,49 @@ error: | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| static bool | ||||
| alsa_setup_dsd(struct alsa_data *ad, struct audio_format *audio_format, | ||||
| 	       GError **error_r) | ||||
| { | ||||
| 	assert(ad->dsd_usb); | ||||
| 	assert(audio_format->format == SAMPLE_FORMAT_DSD); | ||||
|  | ||||
| 	/* pass 24 bit to alsa_setup() */ | ||||
|  | ||||
| 	audio_format->format = SAMPLE_FORMAT_S24_P32; | ||||
| 	audio_format->sample_rate /= 2; | ||||
|  | ||||
| 	const struct audio_format check = *audio_format; | ||||
|  | ||||
| 	if (!alsa_setup(ad, audio_format, error_r)) | ||||
| 		return false; | ||||
|  | ||||
| 	if (!audio_format_equals(audio_format, &check)) { | ||||
| 		/* no bit-perfect playback, which is required | ||||
| 		   for DSD over USB */ | ||||
| 		g_set_error(error_r, alsa_output_quark(), 0, | ||||
| 			    "Failed to configure DSD-over-USB on ALSA device \"%s\"", | ||||
| 			    alsa_device(ad)); | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	/* the ALSA device has accepted 24 bit playback, | ||||
| 	   return DSD_OVER_USB to the caller */ | ||||
|  | ||||
| 	audio_format->format = SAMPLE_FORMAT_DSD_OVER_USB; | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| static bool | ||||
| alsa_setup_or_dsd(struct alsa_data *ad, struct audio_format *audio_format, | ||||
| 		  GError **error_r) | ||||
| { | ||||
| 	if (ad->dsd_usb && audio_format->format == SAMPLE_FORMAT_DSD) | ||||
| 		return alsa_setup_dsd(ad, audio_format, error_r); | ||||
|  | ||||
| 	return alsa_setup(ad, audio_format, error_r); | ||||
| } | ||||
|  | ||||
| static bool | ||||
| alsa_open(struct audio_output *ao, struct audio_format *audio_format, GError **error) | ||||
| { | ||||
| @@ -591,7 +644,7 @@ alsa_open(struct audio_output *ao, struct audio_format *audio_format, GError **e | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	success = alsa_setup(ad, audio_format, error); | ||||
| 	success = alsa_setup_or_dsd(ad, audio_format, error); | ||||
| 	if (!success) { | ||||
| 		snd_pcm_close(ad->pcm); | ||||
| 		return false; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Max Kellermann
					Max Kellermann