From 01e5128507341ac2434e19b3542dbf2029d5e30c Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Fri, 19 Aug 2016 12:51:15 +0100 Subject: [PATCH] Add ability to set output format and output rate --- audio.h | 2 +- audio_alsa.c | 54 +++++++++++++++++++++++++++++++++++++++++--------- audio_ao.c | 6 ++++-- audio_dummy.c | 2 +- audio_pipe.c | 2 +- audio_pulse.c | 6 ++++-- audio_sndio.c | 2 ++ audio_stdout.c | 2 +- common.h | 2 ++ player.c | 2 +- shairport.c | 2 ++ 11 files changed, 64 insertions(+), 18 deletions(-) diff --git a/audio.h b/audio.h index 4c86d7db..b93e48b5 100644 --- a/audio.h +++ b/audio.h @@ -19,7 +19,7 @@ typedef struct { // at end of program void (*deinit)(void); - void (*start)(int sample_rate); + void (*start)(int sample_rate, int sample_format); // block of samples void (*play)(short buf[], int samples); diff --git a/audio_alsa.c b/audio_alsa.c index ad5b0c74..db864f65 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -38,7 +38,7 @@ static void help(void); static int init(int argc, char **argv); static void deinit(void); -static void start(int sample_rate); +static void start(int i_sample_rate, int i_sample_format); static void play(short buf[], int samples); static void stop(void); static void flush(void); @@ -68,6 +68,7 @@ audio_output audio_alsa = { static pthread_mutex_t alsa_mutex = PTHREAD_MUTEX_INITIALIZER; static unsigned int desired_sample_rate; +static snd_pcm_format_t sample_format; static snd_pcm_t *alsa_handle = NULL; static snd_pcm_hw_params_t *alsa_params = NULL; @@ -205,6 +206,35 @@ static int init(int argc, char **argv) { die("Invalid disable_synchronization option choice \"%s\". It should be \"yes\" or \"no\""); } + /* Get the output format, using the same names as aplay does -- S16_LE, S32_LE to begin with*/ + if (config_lookup_string(config.cfg, "alsa.output_format", &str)) { + if (strcasecmp(str, "S16_LE") == 0) + config.output_format = SND_PCM_FORMAT_S16_LE; + else if (strcasecmp(str, "S24_LE") == 0) + config.output_format = SND_PCM_FORMAT_S24_LE; + else if (strcasecmp(str, "S32_LE") == 0) + config.output_format = SND_PCM_FORMAT_S32_LE; + else + die("Invalid output format \"%s\". It should be \"S16_LE\", \"S24_LE\" or \"S32_LE\"",str); + } + + /* Get the output rate, which must be a multiple of 44,100*/ + if (config_lookup_int(config.cfg, "alsa.output_rate", + &value)) { + debug(1,"Value read for output rate is %d.",value); + switch(value) { + case 44100: + case 88200: + case 176400: + case 352800: + config.output_rate = value; + break; + default : + die("Invalid output rate \"%d\". It should be a multiple of 44,100 up to 352,800",value); + } + } + + /* Get the use_mmap_if_available setting. */ if (config_lookup_string(config.cfg, "alsa.use_mmap_if_available", &str)) { if (strcasecmp(str, "no") == 0) @@ -424,11 +454,10 @@ int open_alsa_device(void) { alsa_out_dev, snd_strerror(ret)); } - ret = snd_pcm_hw_params_set_format(alsa_handle, alsa_params, - SND_PCM_FORMAT_S16); + ret = snd_pcm_hw_params_set_format(alsa_handle, alsa_params, sample_format); if (ret < 0) { - die("audio_alsa: Sample format not available for device \"%s\": %s", - alsa_out_dev, snd_strerror(ret)); + die("audio_alsa: Sample format %d not available for device \"%s\": %s", + sample_format, alsa_out_dev, snd_strerror(ret)); } ret = snd_pcm_hw_params_set_channels(alsa_handle, alsa_params, 2); @@ -640,11 +669,18 @@ int open_alsa_device(void) { return (0); } -static void start(int sample_rate) { +static void start(int i_sample_rate, int i_sample_format) { // debug(2,"audio_alsa start called."); - if (sample_rate != 44100) - die("Unexpected sample rate %d -- only 44,100 supported!", sample_rate); - desired_sample_rate = sample_rate; // must be a variable + if (i_sample_rate==0) + desired_sample_rate = 44100; // default + else + desired_sample_rate = i_sample_rate; // must be a variable + + if (i_sample_format==0) + sample_format = SND_PCM_FORMAT_S16_LE; // default + else + sample_format = i_sample_format; + } int delay(long* the_delay) { diff --git a/audio_ao.c b/audio_ao.c index 41b823b0..b6a09a07 100644 --- a/audio_ao.c +++ b/audio_ao.c @@ -134,9 +134,11 @@ static void deinit(void) { ao_shutdown(); } -static void start(int sample_rate) { - if (sample_rate != 44100) +static void start(int sample_rate, int sample_format) { + if (sample_rate != 0) die("unexpected sample rate!"); + if (sample_format != 0) + die("unexpected sample format!"); } static void play(short buf[], int samples) { ao_play(dev, (char *)buf, samples * 4); } diff --git a/audio_dummy.c b/audio_dummy.c index 659a7202..3f24dadd 100644 --- a/audio_dummy.c +++ b/audio_dummy.c @@ -41,7 +41,7 @@ static int init(int argc, char **argv) { return 0; } static void deinit(void) {} -static void start(int sample_rate) { +static void start(int sample_rate, int sample_format) { Fs = sample_rate; starttime = 0; samples_played = 0; diff --git a/audio_pipe.c b/audio_pipe.c index 17bf3103..dfde2a92 100644 --- a/audio_pipe.c +++ b/audio_pipe.c @@ -43,7 +43,7 @@ static int fd = -1; char *pipename = NULL; -static void start(int sample_rate) { +static void start(int sample_rate, int sample_format) { // this will leave fd as -1 if a reader hasn't been attached fd = open(pipename, O_WRONLY | O_NONBLOCK); } diff --git a/audio_pulse.c b/audio_pulse.c index 6fa94e97..e4118259 100644 --- a/audio_pulse.c +++ b/audio_pulse.c @@ -110,9 +110,11 @@ static void deinit(void) { pa_dev = NULL; } -static void start(int sample_rate) { - if (sample_rate != 44100) +static void start(int sample_rate, int sample_format) { + if (sample_rate != 0) die("unexpected sample rate!"); + if (sample_format != 0) + die("unexpected sample format!"); } static void play(short buf[], int samples) { diff --git a/audio_sndio.c b/audio_sndio.c index 7093261e..1d2e1532 100644 --- a/audio_sndio.c +++ b/audio_sndio.c @@ -56,6 +56,8 @@ static void deinit(void) { sio_close(sio); } static void start(int sample_rate) { if (sample_rate != par.rate) die("unexpected sample rate!"); + if (sample_format != 0) + die("unexpected sample format!"); sio_start(sio); } diff --git a/audio_stdout.c b/audio_stdout.c index b8b0aa53..61b8e6b1 100644 --- a/audio_stdout.c +++ b/audio_stdout.c @@ -38,7 +38,7 @@ static int fd = -1; -static void start(int sample_rate) { +static void start(int sample_rate int sample_format) { fd = STDOUT_FILENO; } diff --git a/common.h b/common.h index 32ee301d..625108b0 100644 --- a/common.h +++ b/common.h @@ -100,6 +100,8 @@ typedef struct { // audio backend buffer -- the DAC buffer for ALSA long audio_backend_latency_offset; // this will be the offset to compensate for any fixed latency there might be in the audio path uint32_t volume_range_db; // the range, in dB, from max dB to min dB. Zero means use the mixer's native range. + int output_format; + int output_rate; } shairport_cfg; // true if Shairport Sync is supposed to be sending output to the output device, false otherwise diff --git a/player.c b/player.c index 97eccfb2..3b86a373 100644 --- a/player.c +++ b/player.c @@ -1716,7 +1716,7 @@ int player_play(stream_cfg *stream, pthread_t *player_thread) { #endif if (rc) debug(1, "Error initialising condition variable."); - config.output->start(sampling_rate); + config.output->start(config.output_rate,config.output_format); size_t size = (PTHREAD_STACK_MIN + 256 * 1024); pthread_attr_t tattr; pthread_attr_init(&tattr); diff --git a/shairport.c b/shairport.c index f725d607..1b97099b 100644 --- a/shairport.c +++ b/shairport.c @@ -1016,6 +1016,8 @@ int main(int argc, char **argv) { debug(1, "playback_mode is %d (0-stereo, 1-mono).", config.playback_mode); debug(1, "disable_synchronization is %d.", config.no_sync); debug(1, "use_mmap_if_available is %d.", config.no_mmap ? 0 : 1); + debug(1, "output_rate is %d (0 means 44,100).", config.output_rate); + debug(1, "output_format is %d (0 means S16_LE).", config.output_format); debug(1, "audio backend desired buffer length is %d.", config.audio_backend_buffer_desired_length); debug(1, "audio backend latency offset is %d.", config.audio_backend_latency_offset);