diff --git a/audio.c b/audio.c index a1fcf614..8fbea259 100644 --- a/audio.c +++ b/audio.c @@ -24,8 +24,8 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#include "common.h" #include "audio.h" +#include "common.h" #include "config.h" #include #include @@ -117,7 +117,8 @@ void audio_ls_outputs(void) { } void parse_general_audio_options(void) { - /* this must be called after the output device has been initialised, so that the default values are set before any options are chosen */ + /* this must be called after the output device has been initialised, so that the default values + * are set before any options are chosen */ int value; double dvalue; if (config.cfg != NULL) { @@ -130,7 +131,7 @@ void parse_general_audio_options(void) { die("Invalid audio_backend_buffer_desired_length value: \"%d\". It " "should be between 0 and " "66150, default is %d", - value,(int)(config.audio_backend_buffer_desired_length*44100)); + value, (int)(config.audio_backend_buffer_desired_length * 44100)); } else { inform("The setting general.audio_backend_buffer_desired_length is deprecated. " "Use general.audio_backend_buffer_desired_length_in_seconds instead."); @@ -145,7 +146,7 @@ void parse_general_audio_options(void) { die("Invalid audio_backend_buffer_desired_length_in_seconds value: \"%f\". It " "should be between 0 and " "1.5, default is %.3f seconds", - dvalue,config.audio_backend_buffer_desired_length); + dvalue, config.audio_backend_buffer_desired_length); } else { config.audio_backend_buffer_desired_length = dvalue; } @@ -167,7 +168,8 @@ void parse_general_audio_options(void) { } /* Get the latency offset in seconds. */ - if (config_lookup_float(config.cfg, "general.audio_backend_latency_offset_in_seconds", &dvalue)) { + if (config_lookup_float(config.cfg, "general.audio_backend_latency_offset_in_seconds", + &dvalue)) { if ((dvalue < -1.0) || (dvalue > 1.5)) { die("Invalid audio_backend_latency_offset_in_seconds \"%f\". It " "should be between -1.0 and +1.5, default is 0 seconds", @@ -178,8 +180,7 @@ void parse_general_audio_options(void) { } /* Get the desired length of the silent lead-in. */ - if (config_lookup_float(config.cfg, "general.audio_backend_silent_lead_in_time", - &dvalue)) { + if (config_lookup_float(config.cfg, "general.audio_backend_silent_lead_in_time", &dvalue)) { if ((dvalue < 0.0) || (dvalue > 4)) { die("Invalid audio_backend_silent_lead_in_time \"%f\". It " "must be between 0.0 and 4.0 seconds. Omit setting to use the default value", diff --git a/audio_alsa.c b/audio_alsa.c index cd91e046..f880d1f7 100644 --- a/audio_alsa.c +++ b/audio_alsa.c @@ -53,18 +53,19 @@ static void mute(int do_mute); static double set_volume; static int output_method_signalled = 0; -audio_output audio_alsa = {.name = "alsa", - .help = &help, - .init = &init, - .deinit = &deinit, - .start = &start, - .stop = &stop, - .flush = &flush, - .delay = &delay, - .play = &play, - .mute = NULL, // a function will be provided if it can, and is allowed to, do hardware mute - .volume = NULL, // a function will be provided if it can do hardware volume - .parameters = ¶meters}; +audio_output audio_alsa = { + .name = "alsa", + .help = &help, + .init = &init, + .deinit = &deinit, + .start = &start, + .stop = &stop, + .flush = &flush, + .delay = &delay, + .play = &play, + .mute = NULL, // a function will be provided if it can, and is allowed to, do hardware mute + .volume = NULL, // a function will be provided if it can do hardware volume + .parameters = ¶meters}; static pthread_mutex_t alsa_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -87,8 +88,8 @@ static char *alsa_mix_ctrl = "Master"; static int alsa_mix_index = 0; static int hardware_mixer = 0; static int has_softvol = 0; -static int volume_set_request = 0; // set when an external request is made to set the volume. -int mute_request_pending = 0; // set when an external request is made to mute or unmute. +static int volume_set_request = 0; // set when an external request is made to set the volume. +int mute_request_pending = 0; // set when an external request is made to mute or unmute. int overriding_mute_state_requested = 0; // 1 = mute; 0 = unmute requested static snd_pcm_sframes_t (*alsa_pcm_write)(snd_pcm_t *, const void *, @@ -109,9 +110,7 @@ static void help(void) { " *) default option\n"); } -void set_alsa_out_dev(char *dev) { - alsa_out_dev = dev; -} +void set_alsa_out_dev(char *dev) { alsa_out_dev = dev; } int open_mixer() { if (hardware_mixer) { @@ -138,18 +137,20 @@ int open_mixer() { die("Failed to find mixer element"); return 1; } else { - return 0; + return 0; } } void close_mixer() { - if (alsa_mix_handle) { - snd_mixer_close(alsa_mix_handle); - alsa_mix_handle=NULL; - } + if (alsa_mix_handle) { + snd_mixer_close(alsa_mix_handle); + alsa_mix_handle = NULL; + } } -#define RELEASE_ALSA_MUTEX_AND_DIE(X) pthread_mutex_unlock(&alsa_mutex);die(X); +#define RELEASE_ALSA_MUTEX_AND_DIE(X) \ + pthread_mutex_unlock(&alsa_mutex); \ + die(X); static int init(int argc, char **argv) { pthread_mutex_lock(&alsa_mutex); @@ -164,11 +165,11 @@ static int init(int argc, char **argv) { config.alsa_use_playback_switch_for_mute = 1; config.audio_backend_latency_offset = 0; - config.audio_backend_buffer_desired_length = 0.15; + config.audio_backend_buffer_desired_length = 0.15; // get settings from settings file first, allow them to be overridden by // command line options - + // do the "general" audio options. Note, these options are in the "general" stanza! parse_general_audio_options(); @@ -209,7 +210,7 @@ static int init(int argc, char **argv) { die("Invalid disable_synchronization option choice \"%s\". It should be \"yes\" or \"no\""); } } - + /* Get the mute_using_playback_switch setting. */ if (config_lookup_string(config.cfg, "alsa.mute_using_playback_switch", &str)) { if (strcasecmp(str, "no") == 0) @@ -218,10 +219,11 @@ static int init(int argc, char **argv) { config.alsa_use_playback_switch_for_mute = 1; else { pthread_mutex_unlock(&alsa_mutex); - die("Invalid mute_use_playback_switch option choice \"%s\". It should be \"yes\" or \"no\""); + die("Invalid mute_use_playback_switch option choice \"%s\". It should be \"yes\" or " + "\"no\""); } } - + /* Get the output format, using the same names as aplay does*/ if (config_lookup_string(config.cfg, "alsa.output_format", &str)) { if (strcasecmp(str, "S16") == 0) @@ -413,15 +415,16 @@ static int init(int argc, char **argv) { */ } } - if ((config.alsa_use_playback_switch_for_mute==1) && (snd_mixer_selem_has_playback_switch(alsa_mix_elem))) { + if ((config.alsa_use_playback_switch_for_mute == 1) && + (snd_mixer_selem_has_playback_switch(alsa_mix_elem))) { audio_alsa.mute = &mute; // insert the mute function now we know it can do muting stuff // debug(1, "Has mixer and mute ability we will use."); } else { - // debug(1, "Has mixer but not using hardware mute."); - } + // debug(1, "Has mixer but not using hardware mute."); + } close_mixer(); } else { - // debug(1, "Has no mixer and thus no hardware mute."); + // debug(1, "Has no mixer and thus no hardware mute."); } alsa_mix_handle = NULL; @@ -435,7 +438,7 @@ static void deinit(void) { } int open_alsa_device(void) { -//the alsa mutex is already acquired when this is called + // the alsa mutex is already acquired when this is called const snd_pcm_uframes_t minimal_buffer_headroom = 352 * 2; // we accept this much headroom in the hardware buffer, but we'll @@ -467,7 +470,8 @@ int open_alsa_device(void) { ret = snd_pcm_hw_params_any(alsa_handle, alsa_params); if (ret < 0) { - pthread_mutex_unlock(&alsa_mutex);; + pthread_mutex_unlock(&alsa_mutex); + ; die("audio_alsa: Broken configuration for device \"%s\": no configurations " "available", alsa_out_dev); @@ -527,8 +531,8 @@ int open_alsa_device(void) { ret = snd_pcm_hw_params_set_format(alsa_handle, alsa_params, sf); if (ret < 0) { pthread_mutex_unlock(&alsa_mutex); - die("audio_alsa: Sample format %d not available for device \"%s\": %s", sample_format, 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); @@ -816,10 +820,10 @@ static void play(short buf[], int samples) { pthread_mutex_lock(&alsa_mutex); ret = open_alsa_device(); if (ret == 0) { - if (audio_alsa.volume) - do_volume(set_volume); - if (audio_alsa.mute) - do_mute(0); + if (audio_alsa.volume) + do_volume(set_volume); + if (audio_alsa.mute) + do_mute(0); } pthread_mutex_unlock(&alsa_mutex); } @@ -831,7 +835,7 @@ static void play(short buf[], int samples) { if ((err = snd_pcm_prepare(alsa_handle))) { ignore = snd_pcm_recover(alsa_handle, err, 1); debug(1, "Error preparing after underrun: \"%s\".", snd_strerror(err)); - } + } } if ((snd_pcm_state(alsa_handle) == SND_PCM_STATE_PREPARED) || (snd_pcm_state(alsa_handle) == SND_PCM_STATE_RUNNING)) { @@ -874,7 +878,7 @@ static void flush(void) { debug(1, "Error preparing after flush: \"%s\".", snd_strerror(derr)); // debug(1,"Frames successfully dropped."); */ - + /* if (snd_pcm_state(alsa_handle)==SND_PCM_STATE_PREPARED) debug(1,"Flush returns to SND_PCM_STATE_PREPARED state."); @@ -886,21 +890,20 @@ static void flush(void) { (snd_pcm_state(alsa_handle) == SND_PCM_STATE_RUNNING))) debug(1, "Flush returning unexpected state -- %d.", snd_pcm_state(alsa_handle)); */ - - - - // this is derived from http://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2latency_8c-example.html#a45 - - if ((derr=snd_pcm_nonblock(alsa_handle, 0))) + + // this is derived from + // http://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2latency_8c-example.html#a45 + + if ((derr = snd_pcm_nonblock(alsa_handle, 0))) debug(1, "Error %d (\"%s\") unblocking output device.", derr, snd_strerror(derr)); - if ((derr=snd_pcm_drain(alsa_handle))) + if ((derr = snd_pcm_drain(alsa_handle))) debug(1, "Error %d (\"%s\") draining output device.", derr, snd_strerror(derr)); - if ((derr=snd_pcm_nonblock(alsa_handle, 1))) + if ((derr = snd_pcm_nonblock(alsa_handle, 1))) debug(1, "Error %d (\"%s\") reblocking output device.", derr, snd_strerror(derr)); - if ((derr=snd_pcm_hw_free(alsa_handle))) + if ((derr = snd_pcm_hw_free(alsa_handle))) debug(1, "Error %d (\"%s\") freeing output device hardware.", derr, snd_strerror(derr)); - + // flush also closes the device snd_pcm_close(alsa_handle); alsa_handle = NULL; @@ -949,7 +952,7 @@ void do_volume(double vol) { // caller is assumed to have the alsa_mutex when us debug(1, "Can't set playback volume accurately to %f dB.", vol); if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, -1) != 0) if (snd_mixer_selem_set_playback_dB_all(alsa_mix_elem, vol, 1) != 0) - debug(1,"Could not set playback dB volume on the mixer."); + debug(1, "Could not set playback dB volume on the mixer."); } } volume_set_request = 0; // any external request that has been made is now satisfied @@ -994,31 +997,32 @@ static void mute(int mute_state_requested) { void do_mute(int mute_state_requested) { - // if a mute is requested now, then - // if an external mute request is in place, leave everything muted - // otherwise, if an external mute request is pending, action it - // otherwise, action the do_mute request - - int local_mute_state_requested = overriding_mute_state_requested; // go with whatever was asked by the external "mute" call - + // if a mute is requested now, then + // if an external mute request is in place, leave everything muted + // otherwise, if an external mute request is pending, action it + // otherwise, action the do_mute request + + int local_mute_state_requested = + overriding_mute_state_requested; // go with whatever was asked by the external "mute" call + // The mute state requested will be actioned unless mute_request_pending is set // If it is set, then that the pending request will be actioned. // If the hardware isn't there, or we are not allowed to use it, nothing will be done // The caller must have the alsa mutex - if (config.alsa_use_playback_switch_for_mute==1) { - if (mute_request_pending==0) - local_mute_state_requested = mute_state_requested; - if (open_mixer()) { - if (local_mute_state_requested) { - // debug(1,"Playback Switch mute actually done"); - snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 0); - } else if (overriding_mute_state_requested==0) { - // debug(1,"Playback Switch unmute actually done"); - snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 1); - } - close_mixer(); - } - } - mute_request_pending = 0; + if (config.alsa_use_playback_switch_for_mute == 1) { + if (mute_request_pending == 0) + local_mute_state_requested = mute_state_requested; + if (open_mixer()) { + if (local_mute_state_requested) { + // debug(1,"Playback Switch mute actually done"); + snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 0); + } else if (overriding_mute_state_requested == 0) { + // debug(1,"Playback Switch unmute actually done"); + snd_mixer_selem_set_playback_switch_all(alsa_mix_elem, 1); + } + close_mixer(); + } + } + mute_request_pending = 0; } diff --git a/audio_ao.c b/audio_ao.c index 49ff4efe..78fbea3f 100644 --- a/audio_ao.c +++ b/audio_ao.c @@ -47,7 +47,7 @@ static int init(int argc, char **argv) { ao_initialize(); int driver = ao_default_driver_id(); ao_option *ao_opts = NULL; - + // set up default values first config.audio_backend_buffer_desired_length = 1.0; @@ -55,7 +55,7 @@ static int init(int argc, char **argv) { // get settings from settings file first, allow them to be overridden by // command line options - + // do the "general" audio options. Note, these options are in the "general" stanza! parse_general_audio_options(); @@ -118,8 +118,7 @@ static void deinit(void) { ao_shutdown(); } -static void start(int sample_rate, int sample_format) { -} +static void start(int sample_rate, int sample_format) {} static void play(short buf[], int samples) { ao_play(dev, (char *)buf, samples * 4); } diff --git a/audio_pa.c b/audio_pa.c index 451d4d78..76a2eb13 100644 --- a/audio_pa.c +++ b/audio_pa.c @@ -39,15 +39,14 @@ void stream_state_cb(pa_stream *s, void *mainloop); void stream_success_cb(pa_stream *stream, int success, void *userdata); void stream_write_cb(pa_stream *stream, size_t requested_bytes, void *userdata); - static int init(int argc, char **argv) { // set up default values first config.audio_backend_buffer_desired_length = 0.35; config.audio_backend_latency_offset = 0; - + // get settings from settings file - + // do the "general" audio options. Note, these options are in the "general" stanza! parse_general_audio_options(); @@ -60,10 +59,9 @@ static int init(int argc, char **argv) { config.pa_application_name = (char *)str; } } - - + // finish collecting settings - + // allocate space for the audio buffer audio_lmb = malloc(audio_size); if (audio_lmb == NULL) @@ -71,7 +69,7 @@ static int init(int argc, char **argv) { audio_toq = audio_eoq = audio_lmb; audio_umb = audio_lmb + audio_size; audio_occupancy = 0; - + // Get a mainloop and its context mainloop = pa_threaded_mainloop_new(); assert(mainloop); @@ -79,7 +77,7 @@ static int init(int argc, char **argv) { if (config.pa_application_name) context = pa_context_new(mainloop_api, config.pa_application_name); else - context = pa_context_new(mainloop_api, "Shairport Sync"); + context = pa_context_new(mainloop_api, "Shairport Sync"); assert(context); // Set a callback so we can wait for the context to be ready @@ -135,9 +133,9 @@ static void start(int sample_rate, int sample_format) { // recommended settings, i.e. server uses sensible values pa_buffer_attr buffer_attr; - buffer_attr.maxlength = (uint32_t) -1; + buffer_attr.maxlength = (uint32_t)-1; buffer_attr.tlength = buffer_size_in_bytes; - buffer_attr.prebuf = (uint32_t) 0; + buffer_attr.prebuf = (uint32_t)0; buffer_attr.minreq = (uint32_t)-1; // Settings copied as per the chromium browser source @@ -145,7 +143,7 @@ static void start(int sample_rate, int sample_format) { stream_flags = PA_STREAM_START_CORKED | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_NOT_MONOTONIC | // PA_STREAM_AUTO_TIMING_UPDATE; PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_ADJUST_LATENCY; - + // Connect stream to the default audio output sink assert(pa_stream_connect_playback(stream, NULL, &buffer_attr, stream_flags, NULL, NULL) == 0); @@ -187,7 +185,6 @@ static void play(short buf[], int samples) { pa_threaded_mainloop_lock(mainloop); pa_stream_cork(stream, 0, stream_success_cb, mainloop); pa_threaded_mainloop_unlock(mainloop); - } } @@ -216,7 +213,7 @@ int pa_delay(long *the_delay) { void flush(void) { // Cork the stream so it will stop playing pa_threaded_mainloop_lock(mainloop); - if (pa_stream_is_corked(stream)==0) { + if (pa_stream_is_corked(stream) == 0) { // debug(1,"Flush and cork for flush."); pa_stream_flush(stream, stream_success_cb, NULL); pa_stream_cork(stream, 1, stream_success_cb, mainloop); @@ -230,7 +227,7 @@ void flush(void) { static void stop(void) { // Cork the stream so it will stop playing pa_threaded_mainloop_lock(mainloop); - if (pa_stream_is_corked(stream)==0) { + if (pa_stream_is_corked(stream) == 0) { // debug(1,"Flush and cork for stop."); pa_stream_flush(stream, stream_success_cb, NULL); pa_stream_cork(stream, 1, stream_success_cb, mainloop); @@ -244,9 +241,7 @@ static void stop(void) { pa_stream_disconnect(stream); } -static void help(void) { - printf(" no settings.\n"); -} +static void help(void) { printf(" no settings.\n"); } audio_output audio_pa = {.name = "pa", .help = &help, @@ -269,35 +264,35 @@ void stream_state_cb(pa_stream *s, void *mainloop) { pa_threaded_mainloop_signal void stream_write_cb(pa_stream *stream, size_t requested_bytes, void *userdata) { -/* - // play with timing information - const struct pa_timing_info *ti = pa_stream_get_timing_info(stream); - if ((ti == NULL) || (ti->write_index_corrupt)) { - debug(2, "Timing info invalid"); - } else { - struct timeval time_now; + /* + // play with timing information + const struct pa_timing_info *ti = pa_stream_get_timing_info(stream); + if ((ti == NULL) || (ti->write_index_corrupt)) { + debug(2, "Timing info invalid"); + } else { + struct timeval time_now; - pa_gettimeofday(&time_now); + pa_gettimeofday(&time_now); - uint64_t time_now_fp = ((uint64_t)time_now.tv_sec << 32) + - ((uint64_t)time_now.tv_usec << 32) / 1000000; // types okay - uint64_t time_of_ti_fp = ((uint64_t)(ti->timestamp.tv_sec) << 32) + - ((uint64_t)(ti->timestamp.tv_usec) << 32) / 1000000; // types okay + uint64_t time_now_fp = ((uint64_t)time_now.tv_sec << 32) + + ((uint64_t)time_now.tv_usec << 32) / 1000000; // types okay + uint64_t time_of_ti_fp = ((uint64_t)(ti->timestamp.tv_sec) << 32) + + ((uint64_t)(ti->timestamp.tv_usec) << 32) / 1000000; // types okay - if (time_now_fp >= time_of_ti_fp) { - uint64_t estimate_age = ((time_now_fp - time_of_ti_fp) * 1000000) >> 32; - uint64_t bytes_in_buffer = ti->write_index - ti->read_index; - pa_usec_t microseconds_to_write_buffer = (bytes_in_buffer * 1000000) / (44100 * 2 * 2); - pa_usec_t ea = (pa_usec_t)estimate_age; - pa_usec_t pa_latency = ti->sink_usec + ti->transport_usec + microseconds_to_write_buffer; - pa_usec_t estimated_latency = pa_latency - estimate_age; - // debug(1,"Estimated latency is %d microseconds.",estimated_latency); + if (time_now_fp >= time_of_ti_fp) { + uint64_t estimate_age = ((time_now_fp - time_of_ti_fp) * 1000000) >> 32; + uint64_t bytes_in_buffer = ti->write_index - ti->read_index; + pa_usec_t microseconds_to_write_buffer = (bytes_in_buffer * 1000000) / (44100 * 2 * 2); + pa_usec_t ea = (pa_usec_t)estimate_age; + pa_usec_t pa_latency = ti->sink_usec + ti->transport_usec + microseconds_to_write_buffer; + pa_usec_t estimated_latency = pa_latency - estimate_age; + // debug(1,"Estimated latency is %d microseconds.",estimated_latency); -// } else { -// debug(1, "Time now is earlier than time of timing information"); + // } else { + // debug(1, "Time now is earlier than time of timing information"); + } } - } -*/ + */ int bytes_to_transfer = requested_bytes; int bytes_transferred = 0; uint8_t *buffer = NULL; @@ -307,13 +302,13 @@ void stream_write_cb(pa_stream *stream, size_t requested_bytes, void *userdata) if (audio_occupancy < bytes_we_can_transfer) { // debug(1, "Underflow? We have %d bytes but we are asked for %d bytes", audio_occupancy, // bytes_we_can_transfer); - pa_stream_cork(stream,1, stream_success_cb, mainloop); + pa_stream_cork(stream, 1, stream_success_cb, mainloop); // debug(1, "Corked"); bytes_we_can_transfer = audio_occupancy; } // bytes we can transfer will never be greater than the bytes available - + pa_stream_begin_write(stream, (void **)&buffer, &bytes_we_can_transfer); if (bytes_we_can_transfer <= (audio_umb - audio_toq)) { // the bytes are all in a row in the audo buffer @@ -375,4 +370,3 @@ void alt_stream_write_cb(pa_stream *stream, size_t requested_bytes, void *userda } void stream_success_cb(pa_stream *stream, int success, void *userdata) { return; } - diff --git a/audio_pipe.c b/audio_pipe.c index 7ab4969d..131244c1 100644 --- a/audio_pipe.c +++ b/audio_pipe.c @@ -47,8 +47,8 @@ int warned = 0; 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); - if ((fd<-1) && (warned==0)) { - warn("Error %d opening the pipe named \"%s\".",errno,pipename); + if ((fd < -1) && (warned == 0)) { + warn("Error %d opening the pipe named \"%s\".", errno, pipename); warned = 1; } } @@ -62,16 +62,16 @@ static void play(short buf[], int samples) { // if it's got a reader, write to it. if (fd > 0) { int rc = non_blocking_write(fd, buf, samples * 4); - if ((rc<0) && (warned==0)) { - strerror_r(errno,(char*)errorstring,1024); - warn("Error %d writing to the pipe named \"%s\": \"%s\".",errno,pipename,errorstring); + if ((rc < 0) && (warned == 0)) { + strerror_r(errno, (char *)errorstring, 1024); + warn("Error %d writing to the pipe named \"%s\": \"%s\".", errno, pipename, errorstring); warned = 1; } - } else if ((fd == -1) && (warned==0)) { - strerror_r(errno,(char*)errorstring,1024); - warn("Error %d opening the pipe named \"%s\": \"%s\".",errno,pipename,errorstring); + } else if ((fd == -1) && (warned == 0)) { + strerror_r(errno, (char *)errorstring, 1024); + warn("Error %d opening the pipe named \"%s\": \"%s\".", errno, pipename, errorstring); warned = 1; - } + } } static void stop(void) { @@ -90,7 +90,7 @@ static int init(int argc, char **argv) { config.audio_backend_buffer_desired_length = 1.0; config.audio_backend_latency_offset = 0; - + // do the "general" audio options. Note, these options are in the "general" stanza! parse_general_audio_options(); @@ -100,10 +100,9 @@ static int init(int argc, char **argv) { if (config_lookup_string(config.cfg, "pipe.name", &str)) { pipename = (char *)str; } - + if ((pipename) && (strcasecmp(pipename, "STDOUT") == 0)) die("Can't use \"pipe\" backend for STDOUT. Use the \"stdout\" backend instead."); - } if ((pipename == NULL) && (argc != 1)) diff --git a/audio_pulse.c b/audio_pulse.c index 7d117980..96d7c320 100644 --- a/audio_pulse.c +++ b/audio_pulse.c @@ -110,8 +110,7 @@ static void deinit(void) { pa_dev = NULL; } -static void start(int sample_rate, int sample_format) { -} +static void start(int sample_rate, int sample_format) {} static void play(short buf[], int samples) { if (pa_simple_write(pa_dev, (char *)buf, (size_t)samples * 4, &pa_error) < 0) { diff --git a/audio_sndio.c b/audio_sndio.c index e7fd787b..5d980b7e 100644 --- a/audio_sndio.c +++ b/audio_sndio.c @@ -71,23 +71,20 @@ struct sndio_formats { unsigned int le; }; -static struct sndio_formats formats[] = { - {"S8", SPS_FORMAT_S8, 8, 1, 1, SIO_LE_NATIVE}, - {"U8", SPS_FORMAT_U8, 8, 1, 0, SIO_LE_NATIVE}, - {"S16", SPS_FORMAT_S16, 16, 2, 1, SIO_LE_NATIVE}, - {"S24", SPS_FORMAT_S24, 24, 4, 1, SIO_LE_NATIVE}, - {"S24_3LE", SPS_FORMAT_S24_3LE, 24, 3, 1, 1}, - {"S24_3BE", SPS_FORMAT_S24_3BE, 24, 3, 1, 0}, - {"S32", SPS_FORMAT_S32, 24, 4, 1, SIO_LE_NATIVE}}; +static struct sndio_formats formats[] = {{"S8", SPS_FORMAT_S8, 8, 1, 1, SIO_LE_NATIVE}, + {"U8", SPS_FORMAT_U8, 8, 1, 0, SIO_LE_NATIVE}, + {"S16", SPS_FORMAT_S16, 16, 2, 1, SIO_LE_NATIVE}, + {"S24", SPS_FORMAT_S24, 24, 4, 1, SIO_LE_NATIVE}, + {"S24_3LE", SPS_FORMAT_S24_3LE, 24, 3, 1, 1}, + {"S24_3BE", SPS_FORMAT_S24_3BE, 24, 3, 1, 0}, + {"S32", SPS_FORMAT_S32, 24, 4, 1, SIO_LE_NATIVE}}; -static void help() { - printf(" -d output-device set the output device [default*|...]\n"); -} +static void help() { printf(" -d output-device set the output device [default*|...]\n"); } static int init(int argc, char **argv) { int i, found, opt, round, rate, bufsz; const char *devname, *tmp; - + // set up default values first sio_initpar(&par); @@ -98,17 +95,17 @@ static int init(int argc, char **argv) { par.le = 1; par.sig = 1; devname = SIO_DEVANY; - + config.audio_backend_buffer_desired_length = 1.0; config.audio_backend_latency_offset = 0; - // get settings from settings file - + // get settings from settings file + // do the "general" audio options. Note, these options are in the "general" stanza! parse_general_audio_options(); // get the specific settings - + if (config.cfg != NULL) { if (!config_lookup_string(config.cfg, "sndio.device", &devname)) devname = SIO_DEVANY; @@ -186,8 +183,8 @@ static int init(int argc, char **argv) { if (!sio_setpar(hdl, &par) || !sio_getpar(hdl, &par)) die("sndio: failed to set audio parameters"); for (i = 0, found = 0; i < sizeof(formats) / sizeof(formats[0]); i++) { - if (formats[i].bits == par.bits && formats[i].bps == par.bps && - formats[i].sig == par.sig && formats[i].le == par.le) { + if (formats[i].bits == par.bits && formats[i].bps == par.bps && formats[i].sig == par.sig && + formats[i].le == par.le) { config.output_format = formats[i].fmt; found = 1; break; @@ -255,11 +252,12 @@ static int delay(long *_delay) { // and use it to estimate the frames that would have been output uint64_t time_difference = get_absolute_time_in_fp() - time_of_last_onmove_cb; uint64_t frame_difference = time_difference * par.rate; - uint64_t frame_difference_big_integer = frame_difference>>32; + uint64_t frame_difference_big_integer = frame_difference >> 32; estimated_extra_frames_output = frame_difference_big_integer; - // debug(1,"Frames played to last cb: %d, estimated to current time: %d.",played,estimated_extra_frames_output); + // debug(1,"Frames played to last cb: %d, estimated to current time: + // %d.",played,estimated_extra_frames_output); } - *_delay = (written / framesize) - (played+estimated_extra_frames_output); + *_delay = (written / framesize) - (played + estimated_extra_frames_output); pthread_mutex_unlock(&sndio_mutex); return 0; } diff --git a/audio_soundio.c b/audio_soundio.c index 7376f70b..6960fa35 100644 --- a/audio_soundio.c +++ b/audio_soundio.c @@ -84,17 +84,17 @@ static void underflow_callback(struct SoundIoOutStream *outstream) { static int init(int argc, char **argv) { int err; - + config.audio_backend_buffer_desired_length = 2.0; config.audio_backend_latency_offset = 0; - // get settings from settings file - + // get settings from settings file + // do the "general" audio options. Note, these options are in the "general" stanza! parse_general_audio_options(); // get the specific settings - + soundio = soundio_create(); if (!soundio) { debug(0, "out of memory\n"); diff --git a/audio_stdout.c b/audio_stdout.c index 66b9b3bd..a97df679 100644 --- a/audio_stdout.c +++ b/audio_stdout.c @@ -43,10 +43,10 @@ static void start(int sample_rate, int sample_format) { fd = STDOUT_FILENO; } static void play(short buf[], int samples) { char errorstring[1024]; int warned = 0; - int rc = write(fd, buf, samples * 4); - if ((rc<0) && (warned==0)) { - strerror_r(errno,(char*)errorstring,1024); - warn("Error %d writing to stdout: \"%s\".",errno,errorstring); + int rc = write(fd, buf, samples * 4); + if ((rc < 0) && (warned == 0)) { + strerror_r(errno, (char *)errorstring, 1024); + warn("Error %d writing to stdout: \"%s\".", errno, errorstring); warned = 1; } } @@ -59,8 +59,8 @@ static int init(int argc, char **argv) { // set up default values first config.audio_backend_buffer_desired_length = 1.0; config.audio_backend_latency_offset = 0; - - // get settings from settings file + + // get settings from settings file // do the "general" audio options. Note, these options are in the "general" stanza! parse_general_audio_options(); return 0; diff --git a/common.c b/common.c index fedff727..8f615be4 100644 --- a/common.c +++ b/common.c @@ -464,41 +464,40 @@ void command_set_volume(double volume) { /*Spawn a child to run the program.*/ pid_t pid = fork(); if (pid == 0) { /* child process */ - size_t command_buffer_size = strlen(config.cmd_set_volume)+32; - char* command_buffer = (char*)malloc(command_buffer_size); - if (command_buffer==NULL) { - inform("Couldn't allocate memory for set_volume argument string"); + size_t command_buffer_size = strlen(config.cmd_set_volume) + 32; + char *command_buffer = (char *)malloc(command_buffer_size); + if (command_buffer == NULL) { + inform("Couldn't allocate memory for set_volume argument string"); } else { - memset(command_buffer,0,command_buffer_size); - sprintf(command_buffer, "%s%f", config.cmd_set_volume,volume); - // debug(1,"command_buffer is \"%s\".",command_buffer); - int argC; - char **argV; - // debug(1,"set_volume command found."); - if (poptParseArgvString(command_buffer, &argC, (const char ***)&argV) != - 0) { - // note that argV should be free()'d after use, but we expect this fork to exit - // eventually. - warn("Can't decipher on-set-volume command arguments \"%s\".",command_buffer); - free(argV); - free(command_buffer); - } else { - free(command_buffer); - // debug(1,"Executing on-set-volume command %s with %d arguments.",argV[0],argC); - execv(argV[0], argV); - warn("Execution of on-set-volume command \"%s\" failed to start", config.cmd_set_volume); - // debug(1, "Error executing on-set-volume command %s", config.cmd_set_volume); - exit(127); /* only if execv fails */ - } + memset(command_buffer, 0, command_buffer_size); + sprintf(command_buffer, "%s%f", config.cmd_set_volume, volume); + // debug(1,"command_buffer is \"%s\".",command_buffer); + int argC; + char **argV; + // debug(1,"set_volume command found."); + if (poptParseArgvString(command_buffer, &argC, (const char ***)&argV) != 0) { + // note that argV should be free()'d after use, but we expect this fork to exit + // eventually. + warn("Can't decipher on-set-volume command arguments \"%s\".", command_buffer); + free(argV); + free(command_buffer); + } else { + free(command_buffer); + // debug(1,"Executing on-set-volume command %s with %d arguments.",argV[0],argC); + execv(argV[0], argV); + warn("Execution of on-set-volume command \"%s\" failed to start", config.cmd_set_volume); + // debug(1, "Error executing on-set-volume command %s", config.cmd_set_volume); + exit(127); /* only if execv fails */ + } } - + } else { if (config.cmd_blocking) { /* pid!=0 means parent process and if blocking is true, wait for process to finish */ pid_t rc = waitpid(pid, 0, 0); /* wait for child to exit */ if (rc != pid) { warn("Execution of on-set-volume command returned an error."); - debug(1, "on-set-volume command %s finished with error %d", config.cmd_set_volume,errno); + debug(1, "on-set-volume command %s finished with error %d", config.cmd_set_volume, errno); } } // debug(1,"Continue after on-set-volume command"); @@ -545,9 +544,10 @@ void command_start(void) { exit(127); /* only if execv fails */ } } else { - if (config.cmd_blocking || config.cmd_start_returns_output) { /* pid!=0 means parent process and if blocking is true, wait for + if (config.cmd_blocking || config.cmd_start_returns_output) { /* pid!=0 means parent process + and if blocking is true, wait for process to finish */ - pid_t rc = waitpid(pid, 0, 0); /* wait for child to exit */ + pid_t rc = waitpid(pid, 0, 0); /* wait for child to exit */ if (rc != pid) { warn("Execution of on-start command returned an error."); debug(1, "on-start command %s finished with error %d", config.cmd_start, errno); diff --git a/common.h b/common.h index 9327cab3..40bf594d 100644 --- a/common.h +++ b/common.h @@ -40,8 +40,8 @@ enum endian_type { enum stuffing_type { ST_basic = 0, // straight deletion or insertion of a frame in a 352-frame packet - ST_soxr, // use libsoxr to make a 352 frame packet one frame longer or shorter - } type; + ST_soxr, // use libsoxr to make a 352 frame packet one frame longer or shorter +} type; enum playback_mode_type { ST_stereo = 0, @@ -56,7 +56,8 @@ enum decoders_supported_type { decoder_apple_alac, } decoders_supported_type; -// the following enum is for the formats recognised -- currently only S16LE is recognised for input, so these are output only for the present +// the following enum is for the formats recognised -- currently only S16LE is recognised for input, +// so these are output only for the present enum sps_format_t { SPS_FORMAT_UNKNOWN = 0, @@ -75,8 +76,9 @@ typedef struct { char *service_name; // the name for the shairport service, e.g. "Shairport Sync Version %v running // on host %h" #ifdef CONFIG_PA - char *pa_application_name; // the name under which Shairport Sync shows up as an "Application" in the Sound Preferences in most desktop Linuxes. - // Defaults to "Shairport Sync". Shairport Sync must be playing to see it. + char *pa_application_name; // the name under which Shairport Sync shows up as an "Application" in + // the Sound Preferences in most desktop Linuxes. +// Defaults to "Shairport Sync". Shairport Sync must be playing to see it. #endif #ifdef CONFIG_METADATA int metadata_enabled; @@ -114,9 +116,9 @@ typedef struct { int64_t AirPlayLatency; // supplied with --AirPlayLatency option int64_t ForkedDaapdLatency; // supplied with --ForkedDaapdLatency option int daemonise; - int daemonise_store_pid; // don't try to save a PID file - char *piddir; - int logOutputLevel; // log output level + int daemonise_store_pid; // don't try to save a PID file + char *piddir; + int logOutputLevel; // log output level int statistics_requested, use_negotiated_latencies; enum playback_mode_type playback_mode; char *cmd_start, *cmd_stop, *cmd_set_volume; @@ -143,18 +145,18 @@ typedef struct { // native range. enum sps_format_t output_format; int output_rate; - + #ifdef CONFIG_CONVOLUTION int convolution; - const char* convolution_ir_file; + const char *convolution_ir_file; float convolution_gain; int convolution_max_length; #endif - + int loudness; float loudness_reference_volume_db; int alsa_use_playback_switch_for_mute; - + } shairport_cfg; // true if Shairport Sync is supposed to be sending output to the output device, false otherwise diff --git a/loudness.c b/loudness.c index 5db17a8c..b4dbc3c3 100644 --- a/loudness.c +++ b/loudness.c @@ -1,54 +1,49 @@ #include "loudness.h" -#include #include "common.h" +#include loudness_processor loudness_r; loudness_processor loudness_l; - -void _loudness_set_volume(loudness_processor *p, float volume) -{ - float gain = -(volume-config.loudness_reference_volume_db)*0.5; +void _loudness_set_volume(loudness_processor *p, float volume) { + float gain = -(volume - config.loudness_reference_volume_db) * 0.5; if (gain < 0) gain = 0; - + float Fc = 10.0; float Q = 0.5; - + // Formula from http://www.earlevel.com/main/2011/01/02/biquad-formulas/ float Fs = 44100.0; - + float K = tan(M_PI * Fc / Fs); float V = pow(10.0, gain / 20.0); - - float norm = 1 / (1 + 1/Q * K + K * K); - p->a0 = (1 + V/Q * K + K * K) * norm; + + float norm = 1 / (1 + 1 / Q * K + K * K); + p->a0 = (1 + V / Q * K + K * K) * norm; p->a1 = 2 * (K * K - 1) * norm; - p->a2 = (1 - V/Q * K + K * K) * norm; + p->a2 = (1 - V / Q * K + K * K) * norm; p->b1 = p->a1; - p->b2 = (1 - 1/Q * K + K * K) * norm; + p->b2 = (1 - 1 / Q * K + K * K) * norm; } -float loudness_process(loudness_processor *p, float i0) -{ - float o0 = p->a0*i0 + p->a1*p->i1 + p->a2*p->i2 - p->b1*p->o1 - p->b2*p->o2; - +float loudness_process(loudness_processor *p, float i0) { + float o0 = p->a0 * i0 + p->a1 * p->i1 + p->a2 * p->i2 - p->b1 * p->o1 - p->b2 * p->o2; + p->o2 = p->o1; p->o1 = o0; - + p->i2 = p->i1; p->i1 = i0; - + return o0; } - -void loudness_set_volume(float volume) -{ - float gain = -(volume-config.loudness_reference_volume_db)*0.5; +void loudness_set_volume(float volume) { + float gain = -(volume - config.loudness_reference_volume_db) * 0.5; if (gain < 0) gain = 0; - + inform("Volume: %.1f dB - Loudness gain @10Hz: %.1f dB", volume, gain); _loudness_set_volume(&loudness_l, volume); _loudness_set_volume(&loudness_r, volume); diff --git a/loudness.h b/loudness.h index c1a219a2..1e20c9b8 100644 --- a/loudness.h +++ b/loudness.h @@ -7,10 +7,8 @@ typedef struct { float i1, i2, o1, o2; } loudness_processor; - extern loudness_processor loudness_r; extern loudness_processor loudness_l; void loudness_set_volume(float volume); float loudness_process(loudness_processor *p, float sample); - diff --git a/mdns.h b/mdns.h index 7aa9dbb2..49bae008 100644 --- a/mdns.h +++ b/mdns.h @@ -24,7 +24,7 @@ typedef struct { // "sr=44100", "vn=3", "txtvers=1", config.password ? "pw=true" : "pw=false" #define MDNS_RECORD_WITH_METADATA \ - "sf=0x4", "fv=76400.10", "am=ShairportSync", "vs=105.1", "tp=TCP,UDP", "vn=65537", \ + "sf=0x4", "fv=76400.10", "am=ShairportSync", "vs=105.1", "tp=TCP,UDP", "vn=65537", \ METADATA_EXPRESSION, "ss=16", "sr=44100", "da=true", "sv=false", "et=0,1", "ek=1", "cn=0,1", \ "ch=2", "txtvers=1", config.password ? "pw=true" : "pw=false" @@ -35,7 +35,7 @@ typedef struct { // "txtvers=1", config.password ? "pw=true" : "pw=false" #define MDNS_RECORD_WITHOUT_METADATA \ - "sf=0x4", "fv=76400.10", "am=ShairportSync", "vs=105.1", "tp=TCP,UDP", "vn=65537", "ss=16", \ + "sf=0x4", "fv=76400.10", "am=ShairportSync", "vs=105.1", "tp=TCP,UDP", "vn=65537", "ss=16", \ "sr=44100", "da=true", "sv=false", "et=0,1", "ek=1", "cn=0,1", "ch=2", "txtvers=1", \ config.password ? "pw=true" : "pw=false" diff --git a/player.c b/player.c index 450c3d17..7b8b419b 100644 --- a/player.c +++ b/player.c @@ -869,13 +869,16 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) { (abs_delta << 32) / config.output_rate; // int64_t which is positive conn->first_packet_time_to_play = reference_timestamp_time - delta_fp_sec; } - + // now, the size of the initial silence must be affected by the lead-in time. - // it must be somewhat less than the lead-in time so that dynamic adjustments can be made + // it must be somewhat less than the lead-in time so that dynamic adjustments can be + // made // to compensate for delays due to paging, etc. // The suggestion is that it should be at least 100 ms less than the lead-in time. - - int64_t max_dac_delay = config.output_rate / 10; // so the lead-in time must be greater than this, say 0.2 sec, to allow for dynamic adjustment + + int64_t max_dac_delay = config.output_rate / 10; // so the lead-in time must be greater + // than this, say 0.2 sec, to allow for + // dynamic adjustment int64_t filler_size = max_dac_delay; // 0.1 second -- the maximum we'll add to the DAC if (local_time_now >= conn->first_packet_time_to_play) { @@ -889,27 +892,29 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) { // flush.",(((tn-conn->first_packet_time_to_play)*config.output_rate)>>32)+dac_delay,tn,conn->first_packet_time_to_play,dac_delay,seq_diff(ab_read, // ab_write)); -/* - if (config.output->flush) - config.output->flush(); - ab_resync(conn); - conn->first_packet_timestamp = 0; - conn->first_packet_time_to_play = 0; - conn->time_since_play_started = 0; -*/ + /* + if (config.output->flush) + config.output->flush(); + ab_resync(conn); + conn->first_packet_timestamp = 0; + conn->first_packet_time_to_play = 0; + conn->time_since_play_started = 0; + */ } else { // do some calculations - int64_t lead_time = conn->first_packet_time_to_play-local_time_now; - int64_t lead_in_time = (int64_t)(config.audio_backend_silent_lead_in_time*(int64_t)0x100000000); - // debug(1,"Lead time is %llx at fpttp %llx.",lead_time,conn->first_packet_time_to_play); + int64_t lead_time = conn->first_packet_time_to_play - local_time_now; + int64_t lead_in_time = + (int64_t)(config.audio_backend_silent_lead_in_time * (int64_t)0x100000000); + // debug(1,"Lead time is %llx at fpttp + // %llx.",lead_time,conn->first_packet_time_to_play); // an audio_backend_silent_lead_in_time of less than zero means start filling ASAP - if ((lead_in_time<0) || (lead_time<=lead_in_time)) { + if ((lead_in_time < 0) || (lead_time <= lead_in_time)) { // debug(1,"Checking"); if (config.output->delay) { // conn->first_packet_time_to_play is definitely later than local_time_now if (have_sent_prefiller_silence != 0) { int resp = config.output->delay(&dac_delay); - + if (resp != 0) { debug(1, "Error %d getting dac_delay in buffer_get_frame.", resp); dac_delay = 0; @@ -918,7 +923,8 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) { dac_delay = 0; } int64_t gross_frame_gap = - ((conn->first_packet_time_to_play - local_time_now) * config.output_rate) >> 32; + ((conn->first_packet_time_to_play - local_time_now) * config.output_rate) >> + 32; int64_t exact_frame_gap = gross_frame_gap - dac_delay; if (exact_frame_gap < 0) { // we've gone past the time... @@ -937,14 +943,16 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) { if (fs > (max_dac_delay - dac_delay)) fs = max_dac_delay - dac_delay; if (fs < 0) { - debug(2, "frame size (fs) < 0 with max_dac_delay of %lld and dac_delay of %ld", + debug(2, + "frame size (fs) < 0 with max_dac_delay of %lld and dac_delay of %ld", max_dac_delay, dac_delay); fs = 0; } if ((exact_frame_gap <= fs) || (exact_frame_gap <= conn->max_frames_per_packet * 2)) { fs = exact_frame_gap; - // debug(1,"Exact frame gap is %llu; play %d frames of silence. Dac_delay is %d, + // debug(1,"Exact frame gap is %llu; play %d frames of silence. Dac_delay is + // %d, // with %d packets, ab_read is %04x, ab_write is // %04x.",exact_frame_gap,fs,dac_delay,seq_diff(ab_read, // ab_write),ab_read,ab_write); @@ -954,8 +962,10 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) { // if (fs==0) // debug(2,"Zero length silence buffer needed with gross_frame_gap of %lld and // dac_delay of %lld.",gross_frame_gap,dac_delay); - // the fs (number of frames of silence to play) can be zero in the DAC doesn't start - // ouotputting frames for a while -- it could get loaded up but not start responding + // the fs (number of frames of silence to play) can be zero in the DAC doesn't + // start + // ouotputting frames for a while -- it could get loaded up but not start + // responding // for many milliseconds. if (fs > 0) { silence = malloc(conn->output_bytes_per_frame * fs); @@ -963,27 +973,30 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) { debug(1, "Failed to allocate %d byte silence buffer.", fs); else { memset(silence, 0, conn->output_bytes_per_frame * fs); - // debug(1,"Frames to start: %llu, DAC delay %d, buffer: %d packets.",exact_frame_gap,dac_delay,seq_diff(conn->ab_read, conn->ab_write, conn->ab_read)); + // debug(1,"Frames to start: %llu, DAC delay %d, buffer: %d + // packets.",exact_frame_gap,dac_delay,seq_diff(conn->ab_read, + // conn->ab_write, conn->ab_read)); config.output->play(silence, fs); free(silence); } } - have_sent_prefiller_silence = 1; // even if we haven't sent silence because it's zero frames long... + have_sent_prefiller_silence = + 1; // even if we haven't sent silence because it's zero frames long... } } else { - //no delay function on back end -- just send the prefiller silence + // no delay function on back end -- just send the prefiller silence // debug(1,"Back end has no delay function."); // send the appropriate prefiller here... - + signed short *silence; if (lead_time != 0) { int64_t frame_gap = (lead_time * config.output_rate) >> 32; // debug(1,"%d frames needed.",frame_gap); - while (frame_gap>0) { - size_t fs = config.output_rate/10; - if (fs>frame_gap) + while (frame_gap > 0) { + size_t fs = config.output_rate / 10; + if (fs > frame_gap) fs = frame_gap; - + silence = malloc(conn->output_bytes_per_frame * fs); if (silence == NULL) debug(1, "Failed to allocate %d frame silence buffer.", fs); @@ -992,7 +1005,6 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) { memset(silence, 0, conn->output_bytes_per_frame * fs); config.output->play(silence, fs); free(silence); - } frame_gap -= fs; } @@ -1085,7 +1097,6 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) { time_to_wait_for_wakeup_fp *= 4 * 352; // four full 352-frame packets time_to_wait_for_wakeup_fp /= 3; // four thirds of a packet time - #ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN uint64_t time_of_wakeup_fp = local_time_now + time_to_wait_for_wakeup_fp; uint64_t sec = time_of_wakeup_fp >> 32; diff --git a/player.h b/player.h index 0e58b3ba..d69792c6 100644 --- a/player.h +++ b/player.h @@ -19,8 +19,8 @@ #include #endif -#include "audio.h" #include "alac.h" +#include "audio.h" #define time_ping_history 8 @@ -62,8 +62,8 @@ typedef struct { pthread_t player_thread; abuf_t audio_buffer[BUFFER_FRAMES]; - int max_frames_per_packet,input_num_channels,input_bit_depth,input_rate; - int input_bytes_per_frame,output_bytes_per_frame,output_sample_ratio; + int max_frames_per_packet, input_num_channels, input_bit_depth, input_rate; + int input_bytes_per_frame, output_bytes_per_frame, output_sample_ratio; int max_frame_size_change; int64_t previous_random_number; alac_file *decoder_info; @@ -73,24 +73,25 @@ typedef struct { int connection_state_to_output; int player_thread_please_stop; int64_t first_packet_time_to_play, time_since_play_started; // nanoseconds - // stats - uint64_t missing_packets, late_packets, too_late_packets, resend_requests; - int decoder_in_use; - // debug variables - int32_t last_seqno_read; -// mutexes and condition variables - pthread_cond_t flowcontrol; - pthread_mutex_t ab_mutex,flush_mutex; - pthread_mutex_t vol_mutex; - int fix_volume; - uint32_t timestamp_epoch, last_timestamp, maximum_timestamp_interval; // timestamp_epoch of zero means not initialised, could start at 2 - // or 1. - int ab_buffering,ab_synced; - int64_t first_packet_timestamp; - int flush_requested; - int64_t flush_rtp_timestamp; - uint64_t time_of_last_audio_packet; - seq_t ab_read, ab_write; + // stats + uint64_t missing_packets, late_packets, too_late_packets, resend_requests; + int decoder_in_use; + // debug variables + int32_t last_seqno_read; + // mutexes and condition variables + pthread_cond_t flowcontrol; + pthread_mutex_t ab_mutex, flush_mutex; + pthread_mutex_t vol_mutex; + int fix_volume; + uint32_t timestamp_epoch, last_timestamp, + maximum_timestamp_interval; // timestamp_epoch of zero means not initialised, could start at 2 + // or 1. + int ab_buffering, ab_synced; + int64_t first_packet_timestamp; + int flush_requested; + int64_t flush_rtp_timestamp; + uint64_t time_of_last_audio_packet; + seq_t ab_read, ab_write; #ifdef HAVE_LIBMBEDTLS mbedtls_aes_context dctx; @@ -104,7 +105,7 @@ typedef struct { AES_KEY aes; #endif - int amountStuffed; + int amountStuffed; int32_t framesProcessedInThisEpoch; int32_t framesGeneratedInThisEpoch; @@ -118,9 +119,9 @@ typedef struct { char client_ip_string[INET6_ADDRSTRLEN]; // the ip string pointing to the client char self_ip_string[INET6_ADDRSTRLEN]; // the ip string being used by this program -- it // could be one of many, so we need to know it - uint32_t self_scope_id; // if it's an ipv6 connection, this will be its scope - short connection_ip_family; // AF_INET / AF_INET6 - uint32_t client_active_remote; // used when you want to control the client... + uint32_t self_scope_id; // if it's an ipv6 connection, this will be its scope + short connection_ip_family; // AF_INET / AF_INET6 + uint32_t client_active_remote; // used when you want to control the client... SOCKADDR rtp_client_control_socket; // a socket pointing to the control port of the client SOCKADDR rtp_client_timing_socket; // a socket pointing to the timing port of the client @@ -147,27 +148,29 @@ typedef struct { int timing_sender_stop; // for asking the timing-sending thread to stop int last_stuff_request; - + int64_t play_segment_reference_frame; uint64_t play_segment_reference_frame_remote_time; - + int32_t buffer_occupancy; // allow it to be negative because seq_diff may be negative int64_t session_corrections; - + int play_number_after_flush; - + } rtsp_conn_info; -int player_play(pthread_t *thread, rtsp_conn_info* conn); -void player_stop(pthread_t *thread, rtsp_conn_info* conn); +int player_play(pthread_t *thread, rtsp_conn_info *conn); +void player_stop(pthread_t *thread, rtsp_conn_info *conn); -void player_volume(double f, rtsp_conn_info* conn); -void player_flush(int64_t timestamp, rtsp_conn_info* conn); -void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, rtsp_conn_info* conn); +void player_volume(double f, rtsp_conn_info *conn); +void player_flush(int64_t timestamp, rtsp_conn_info *conn); +void player_put_packet(seq_t seqno, int64_t timestamp, uint8_t *data, int len, + rtsp_conn_info *conn); -int64_t monotonic_timestamp(uint32_t timestamp,rtsp_conn_info* conn); // add an epoch to the timestamp. The monotonic - // timestamp guaranteed to start between 2^32 2^33 - // frames and continue up to 2^64 frames +int64_t monotonic_timestamp(uint32_t timestamp, + rtsp_conn_info *conn); // add an epoch to the timestamp. The monotonic +// timestamp guaranteed to start between 2^32 2^33 +// frames and continue up to 2^64 frames // which is about 2*10^8 * 1,000 seconds at 384,000 frames per second -- about 2 trillion seconds. // assumes, without checking, that successive timestamps in a series always span an interval of less // than one minute. diff --git a/rtp.c b/rtp.c index af98b349..dfd15b95 100644 --- a/rtp.c +++ b/rtp.c @@ -42,30 +42,28 @@ #include "player.h" #include "rtp.h" -void rtp_initialise(rtsp_conn_info* conn) { +void rtp_initialise(rtsp_conn_info *conn) { conn->rtp_running = 0; -// initialise the timer mutex + // initialise the timer mutex int rc = pthread_mutex_init(&conn->reference_time_mutex, NULL); if (rc) debug(1, "Error initialising reference_time_mutex."); - } -void rtp_terminate(rtsp_conn_info* conn) { +void rtp_terminate(rtsp_conn_info *conn) { -// destroy the timer mutex + // destroy the timer mutex int rc = pthread_mutex_destroy(&conn->reference_time_mutex); if (rc) debug(1, "Error destroying reference_time_mutex variable."); } - -void *rtp_audio_receiver(void* arg) { +void *rtp_audio_receiver(void *arg) { debug(2, "Audio receiver -- Server RTP thread starting."); // we inherit the signal mask (SIGUSR1) - rtsp_conn_info *conn = (rtsp_conn_info*)arg; + rtsp_conn_info *conn = (rtsp_conn_info *)arg; int32_t last_seqno = -1; uint8_t packet[2048], *pktp; @@ -131,7 +129,7 @@ void *rtp_audio_receiver(void* arg) { // debug(3, "RTP: Packets out of sequence: expected: %d, got %d.", last_seqno, seqno); last_seqno = seqno; // reset warning... } - int64_t timestamp = monotonic_timestamp(ntohl(*(unsigned long *)(pktp + 4)),conn); + int64_t timestamp = monotonic_timestamp(ntohl(*(unsigned long *)(pktp + 4)), conn); // if (packet[1]&0x10) // debug(1,"Audio packet Extension bit set."); @@ -141,7 +139,7 @@ void *rtp_audio_receiver(void* arg) { // check if packet contains enough content to be reasonable if (plen >= 16) { - player_put_packet(seqno, timestamp, pktp, plen,conn); + player_put_packet(seqno, timestamp, pktp, plen, conn); continue; } if (type == 0x56 && seqno == 0) { @@ -160,12 +158,12 @@ void *rtp_audio_receiver(void* arg) { return NULL; } -void *rtp_control_receiver(void* arg) { +void *rtp_control_receiver(void *arg) { // we inherit the signal mask (SIGUSR1) debug(2, "Control receiver -- Server RTP thread starting."); - - rtsp_conn_info *conn = (rtsp_conn_info*)arg; + + rtsp_conn_info *conn = (rtsp_conn_info *)arg; conn->reference_timestamp = 0; // nothing valid received yet uint8_t packet[2048], *pktp; @@ -202,8 +200,8 @@ void *rtp_control_receiver(void* arg) { // debug(1,"Remote Sync Time: %0llx.",remote_time_of_sync); - rtp_timestamp_less_latency = monotonic_timestamp(ntohl(*((uint32_t *)&packet[4])),conn); - sync_rtp_timestamp = monotonic_timestamp(ntohl(*((uint32_t *)&packet[16])),conn); + rtp_timestamp_less_latency = monotonic_timestamp(ntohl(*((uint32_t *)&packet[4])), conn); + sync_rtp_timestamp = monotonic_timestamp(ntohl(*((uint32_t *)&packet[16])), conn); if (config.use_negotiated_latencies) { int64_t la = sync_rtp_timestamp - rtp_timestamp_less_latency + 11025; @@ -222,7 +220,8 @@ void *rtp_control_receiver(void* arg) { } pthread_mutex_lock(&conn->reference_time_mutex); conn->remote_reference_timestamp_time = remote_time_of_sync; - conn->reference_timestamp_time = remote_time_of_sync - conn->local_to_remote_time_difference; + conn->reference_timestamp_time = + remote_time_of_sync - conn->local_to_remote_time_difference; conn->reference_timestamp = sync_rtp_timestamp; pthread_mutex_unlock(&conn->reference_time_mutex); // debug(1,"New Reference timestamp and timestamp time..."); @@ -242,7 +241,7 @@ void *rtp_control_receiver(void* arg) { plen -= 4; seq_t seqno = ntohs(*(unsigned short *)(pktp + 2)); - int64_t timestamp = monotonic_timestamp(ntohl(*(unsigned long *)(pktp + 4)),conn); + int64_t timestamp = monotonic_timestamp(ntohl(*(unsigned long *)(pktp + 4)), conn); pktp += 12; plen -= 12; @@ -266,7 +265,7 @@ void *rtp_control_receiver(void* arg) { void *rtp_timing_sender(void *arg) { debug(2, "Timing sender thread starting."); - rtsp_conn_info *conn = (rtsp_conn_info*)arg; + rtsp_conn_info *conn = (rtsp_conn_info *)arg; struct timing_request { char leader; char type; @@ -306,8 +305,8 @@ void *rtp_timing_sender(void *arg) { msgsize = sizeof(struct sockaddr_in6); } #endif - if (sendto(conn->timing_socket, &req, sizeof(req), 0, (struct sockaddr *)&conn->rtp_client_timing_socket, - msgsize) == -1) { + if (sendto(conn->timing_socket, &req, sizeof(req), 0, + (struct sockaddr *)&conn->rtp_client_timing_socket, msgsize) == -1) { perror("Error sendto-ing to timing socket"); } request_number++; @@ -323,7 +322,7 @@ void *rtp_timing_sender(void *arg) { void *rtp_timing_receiver(void *arg) { debug(2, "Timing receiver -- Server RTP thread starting."); // we inherit the signal mask (SIGUSR1) - rtsp_conn_info *conn = (rtsp_conn_info*)arg; + rtsp_conn_info *conn = (rtsp_conn_info *)arg; uint8_t packet[2048], *pktp; ssize_t nread; @@ -391,11 +390,11 @@ void *rtp_timing_receiver(void *arg) { uint64_t local_time_by_remote_clock = distant_transmit_time + return_time / 2; - unsigned int cc,chosen; + unsigned int cc, chosen; for (cc = time_ping_history - 1; cc > 0; cc--) { conn->time_pings[cc] = conn->time_pings[cc - 1]; conn->time_pings[cc].dispersion = (conn->time_pings[cc].dispersion * 110) / - 100; // make the dispersions 'age' by this rational factor + 100; // make the dispersions 'age' by this rational factor } // these are for diagnostics only -- not used conn->time_pings[0].local_time = arrival_time; @@ -463,9 +462,8 @@ void *rtp_timing_receiver(void *arg) { clock_drift_in_usec = (clock_drift * 1000000) >> 32; else clock_drift_in_usec = -(((-clock_drift) * 1000000) >> 32); - clock_drift_ppm = (1.0*clock_drift_in_usec)/(local_time_change>>32); - } - + clock_drift_ppm = (1.0 * clock_drift_in_usec) / (local_time_change >> 32); + } int64_t source_drift_usec; if (conn->play_segment_reference_frame != 0) { @@ -475,15 +473,16 @@ void *rtp_timing_receiver(void *arg) { &remote_reference_timestamp_time, conn); uint64_t frame_difference = 0; if (reference_timestamp >= conn->play_segment_reference_frame) - frame_difference = (uint64_t)reference_timestamp - (uint64_t)conn->play_segment_reference_frame; - else // rollover frame_difference = - (uint64_t)reference_timestamp + 0x100000000 - (uint64_t)conn->play_segment_reference_frame; + (uint64_t)reference_timestamp - (uint64_t)conn->play_segment_reference_frame; + else // rollover + frame_difference = (uint64_t)reference_timestamp + 0x100000000 - + (uint64_t)conn->play_segment_reference_frame; uint64_t frame_time_difference_calculated = (((uint64_t)frame_difference << 32) / 44100); uint64_t frame_time_difference_actual = remote_reference_timestamp_time - conn->play_segment_reference_frame_remote_time; // this is all done by reference to the - // sources' system clock + // sources' system clock // debug(1,"%llu frames since play started, %llu usec calculated, %llu usec // actual",frame_difference, (frame_time_difference_calculated*1000000)>>32, // (frame_time_difference_actual*1000000)>>32); @@ -505,13 +504,14 @@ void *rtp_timing_receiver(void *arg) { // config.output->delay(¤t_delay); //} // Useful for troubleshooting: - //debug(1, "clock_drift_ppm %f\tchosen %5d\tsource_drift_usec %10.1lld\treturn_time_in_usec %10.1llu", - //clock_drift_ppm, - //chosen, + // debug(1, "clock_drift_ppm %f\tchosen %5d\tsource_drift_usec %10.1lld\treturn_time_in_usec + // %10.1llu", + // clock_drift_ppm, + // chosen, //(session_corrections*1000000)/44100, - //current_delay, - //source_drift_usec, - //buffer_occupancy, + // current_delay, + // source_drift_usec, + // buffer_occupancy, //(return_time*1000000)>>32); } else { @@ -568,7 +568,8 @@ static int bind_port(int ip_family, const char *self_ip_address, uint32_t scope_ if (ret < 0) { close(local_socket); - die("error: could not bind a UDP port! Check the udp_port_range is large enough (>= 10) or check for restrictive firewall settings or a bad router!"); + die("error: could not bind a UDP port! Check the udp_port_range is large enough (>= 10) or " + "check for restrictive firewall settings or a bad router!"); } int sport; @@ -610,7 +611,8 @@ void rtp_setup(SOCKADDR *local, SOCKADDR *remote, int cport, int tport, uint32_t char client_port_str[64]; char self_addr_str[64]; - conn->connection_ip_family = remote->SAFAMILY; // keep information about the kind of ip of the client + conn->connection_ip_family = + remote->SAFAMILY; // keep information about the kind of ip of the client #ifdef AF_INET6 if (conn->connection_ip_family == AF_INET6) { @@ -632,10 +634,13 @@ void rtp_setup(SOCKADDR *local, SOCKADDR *remote, int cport, int tport, uint32_t self_port = ntohs(sa4->sin_port); } - inet_ntop(conn->connection_ip_family, client_addr, conn->client_ip_string, sizeof(conn->client_ip_string)); - inet_ntop(conn->connection_ip_family, self_addr, conn->self_ip_string, sizeof(conn->self_ip_string)); + inet_ntop(conn->connection_ip_family, client_addr, conn->client_ip_string, + sizeof(conn->client_ip_string)); + inet_ntop(conn->connection_ip_family, self_addr, conn->self_ip_string, + sizeof(conn->self_ip_string)); - debug(1, "Set up play connection from %s to self at %s.", conn->client_ip_string, conn->self_ip_string); + debug(1, "Set up play connection from %s to self at %s.", conn->client_ip_string, + conn->self_ip_string); // set up a the record of the remote's control socket struct addrinfo hints; @@ -683,9 +688,12 @@ void rtp_setup(SOCKADDR *local, SOCKADDR *remote, int cport, int tport, uint32_t // now, we open three sockets -- one for the audio stream, one for the timing and one for the // control - *lsport = bind_port(conn->connection_ip_family, conn->self_ip_string, conn->self_scope_id, &conn->audio_socket); - *lcport = bind_port(conn->connection_ip_family, conn->self_ip_string, conn->self_scope_id, &conn->control_socket); - *ltport = bind_port(conn->connection_ip_family, conn->self_ip_string, conn->self_scope_id, &conn->timing_socket); + *lsport = bind_port(conn->connection_ip_family, conn->self_ip_string, conn->self_scope_id, + &conn->audio_socket); + *lcport = bind_port(conn->connection_ip_family, conn->self_ip_string, conn->self_scope_id, + &conn->control_socket); + *ltport = bind_port(conn->connection_ip_family, conn->self_ip_string, conn->self_scope_id, + &conn->timing_socket); debug(2, "listening for audio, control and timing on ports %d, %d, %d.", *lsport, *lcport, *ltport); @@ -752,8 +760,8 @@ void rtp_request_resend(seq_t first, uint32_t count, rtsp_conn_info *conn) { msgsize = sizeof(struct sockaddr_in6); } #endif - if (sendto(conn->audio_socket, req, sizeof(req), 0, (struct sockaddr *)&conn->rtp_client_control_socket, - msgsize) == -1) { + if (sendto(conn->audio_socket, req, sizeof(req), 0, + (struct sockaddr *)&conn->rtp_client_control_socket, msgsize) == -1) { perror("Error sendto-ing to audio socket"); } } else { diff --git a/rtp.h b/rtp.h index a78548ab..e0ebefa9 100644 --- a/rtp.h +++ b/rtp.h @@ -5,8 +5,8 @@ #include "player.h" -void rtp_initialise(rtsp_conn_info* conn); -void rtp_terminate(rtsp_conn_info* conn); +void rtp_initialise(rtsp_conn_info *conn); +void rtp_terminate(rtsp_conn_info *conn); void *rtp_audio_receiver(void *arg); void *rtp_control_receiver(void *arg); @@ -14,14 +14,14 @@ void *rtp_timing_receiver(void *arg); void rtp_setup(SOCKADDR *local, SOCKADDR *remote, int controlport, int timingport, uint32_t active_remote, int *local_server_port, int *local_control_port, - int *local_timing_port, rtsp_conn_info* conn); -void rtp_shutdown(rtsp_conn_info* conn); -void rtp_request_resend(seq_t first, uint32_t count, rtsp_conn_info* conn); -void rtp_request_client_pause(rtsp_conn_info* conn); // ask the client to pause + int *local_timing_port, rtsp_conn_info *conn); +void rtp_shutdown(rtsp_conn_info *conn); +void rtp_request_resend(seq_t first, uint32_t count, rtsp_conn_info *conn); +void rtp_request_client_pause(rtsp_conn_info *conn); // ask the client to pause void get_reference_timestamp_stuff(int64_t *timestamp, uint64_t *timestamp_time, - uint64_t *remote_timestamp_time, rtsp_conn_info* conn); -void clear_reference_timestamp(rtsp_conn_info* conn); + uint64_t *remote_timestamp_time, rtsp_conn_info *conn); +void clear_reference_timestamp(rtsp_conn_info *conn); uint64_t static local_to_remote_time_jitters; uint64_t static local_to_remote_time_jitters_count; diff --git a/rtsp.c b/rtsp.c index 42565914..c4c2dd72 100644 --- a/rtsp.c +++ b/rtsp.c @@ -646,7 +646,7 @@ static void handle_record(rtsp_conn_info *conn, rtsp_message *req, rtsp_message rtptime = uatoi(p + 1); // unsigned integer -- up to 2^32-1 rtptime--; // debug(1,"RTSP Flush Requested by handle_record: %u.",rtptime); - player_flush(rtptime,conn); + player_flush(rtptime, conn); } } } @@ -665,7 +665,7 @@ static void handle_teardown(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag "it's sending a response to teardown anyway"); resp->respcode = 200; msg_add_header(resp, "Connection", "close"); - debug(2,"TEARDOWN asking connection to stop"); + debug(2, "TEARDOWN asking connection to stop"); conn->stop = 1; } @@ -687,14 +687,14 @@ static void handle_flush(rtsp_conn_info *conn, rtsp_message *req, rtsp_message * rtptime = uatoi(p + 1); // unsigned integer -- up to 2^32-1 } } - // debug(1,"RTSP Flush Requested: %u.",rtptime); - #ifdef CONFIG_METADATA +// debug(1,"RTSP Flush Requested: %u.",rtptime); +#ifdef CONFIG_METADATA if (p) send_metadata('ssnc', 'flsr', p, strlen(p), req, 1); else - send_metadata('ssnc', 'flsr', NULL, 0, NULL,0); - #endif - player_flush(rtptime,conn); + send_metadata('ssnc', 'flsr', NULL, 0, NULL, 0); +#endif + player_flush(rtptime, conn); resp->respcode = 200; } @@ -799,7 +799,8 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message * tport = atoi(p); // rtsp_take_player(); - rtp_setup(&conn->local, &conn->remote, cport, tport, active_remote, &lsport, &lcport, <port, conn); + rtp_setup(&conn->local, &conn->remote, cport, tport, active_remote, &lsport, &lcport, <port, + conn); if (!lsport) goto error; char *q; @@ -818,7 +819,7 @@ static void handle_setup(rtsp_conn_info *conn, rtsp_message *req, rtsp_message * strcat(hdr, q); // should unsplice the timing port entry } - player_play(&conn->player_thread,conn); // the thread better be 0 + player_play(&conn->player_thread, conn); // the thread better be 0 char *resphdr = alloca(200); *resphdr = 0; @@ -857,7 +858,7 @@ static void handle_set_parameter_parameter(rtsp_conn_info *conn, rtsp_message *r if (!strncmp(cp, "volume: ", 8)) { float volume = atof(cp + 8); // debug(1, "AirPlay request to set volume to: %f\n", volume); - player_volume(volume,conn); + player_volume(volume, conn); } else #ifdef CONFIG_METADATA if (!strncmp(cp, "progress: ", 10)) { @@ -943,13 +944,10 @@ static void handle_set_parameter_parameter(rtsp_conn_info *conn, rtsp_message *r // `clip` -- the payload is the IP number of the client, i.e. the sender of audio. // Can be an IPv4 or an IPv6 number. - - // A special sub-protocol is used for sending large data items over UDP // If the payload exceeded 4 MB, it is chunked using the following format: // "ssnc", "chnk", packet_ix, packet_counts, packet_tag, packet_type, chunked_data. -// Notice that the number of items is different to the standard - +// Notice that the number of items is different to the standard // including a simple base64 encoder to minimise malloc/free activity @@ -1093,15 +1091,15 @@ void metadata_process(uint32_t type, uint32_t code, char *data, uint32_t length) } else if (metadata_sock >= 0) { // send metadata in numbered chunks using the protocol: // ("ssnc", "chnk", packet_ix, packet_counts, packet_tag, packet_type, chunked_data) - + uint32_t chunk_ix = 0; uint32_t chunk_total = length / (config.metadata_sockmsglength - 24); if (chunk_total * (config.metadata_sockmsglength - 24) < length) { - chunk_total++; + chunk_total++; } uint32_t remaining = length; uint32_t v; - char* data_crsr = data; + char *data_crsr = data; do { char *ptr = metadata_sockmsg; memcpy(ptr, "ssncchnk", 8); @@ -1120,15 +1118,16 @@ void metadata_process(uint32_t type, uint32_t code, char *data, uint32_t length) ptr += 4; uint32_t datalen = remaining; if (datalen > config.metadata_sockmsglength - 24) { - datalen = config.metadata_sockmsglength - 24; + datalen = config.metadata_sockmsglength - 24; } memcpy(ptr, data_crsr, datalen); data_crsr += datalen; - sendto(metadata_sock, metadata_sockmsg, datalen + 24, 0, (struct sockaddr *)&metadata_sockaddr, - sizeof(metadata_sockaddr)); + sendto(metadata_sock, metadata_sockmsg, datalen + 24, 0, + (struct sockaddr *)&metadata_sockaddr, sizeof(metadata_sockaddr)); chunk_ix++; remaining -= datalen; - if (remaining == 0) break; + if (remaining == 0) + break; } while (1); } @@ -1400,14 +1399,15 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag if (config.allow_session_interruption == 1) { // some other thread has the player ... ask it to relinquish the thread if (playing_conn) { - debug(1,"Playing connection asked to stop"); - if (playing_conn==conn) { - debug(1,"ANNOUNCE asking to stop itself."); + debug(1, "Playing connection asked to stop"); + if (playing_conn == conn) { + debug(1, "ANNOUNCE asking to stop itself."); } else { playing_conn->stop = 1; memory_barrier(); pthread_kill(playing_conn->thread, SIGUSR1); - usleep(1000000); // here, it is possible for other connections to come in and nab the player. + usleep( + 1000000); // here, it is possible for other connections to come in and nab the player. } } else { die("Non existent the_playing_conn with play_lock enabled."); @@ -1417,7 +1417,7 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag if (pthread_mutex_trylock(&play_lock) == 0) have_the_player = 1; else - debug(1,"ANNOUNCE failed to get the player"); + debug(1, "ANNOUNCE failed to get the player"); } } @@ -1496,7 +1496,7 @@ static void handle_announce(rtsp_conn_info *conn, rtsp_message *req, rtsp_messag for (i = 0; i < sizeof(conn->stream.fmtp) / sizeof(conn->stream.fmtp[0]); i++) conn->stream.fmtp[i] = atoi(strsep(&pfmtp, " \t")); // here we should check the sanity ot the fmtp values - //for (i = 0; i < sizeof(conn->stream.fmtp) / sizeof(conn->stream.fmtp[0]); i++) + // for (i = 0; i < sizeof(conn->stream.fmtp) / sizeof(conn->stream.fmtp[0]); i++) // debug(1," fmtp[%2d] is: %10d",i,conn->stream.fmtp[i]); char *hdr = msg_get_header(req, "X-Apple-Client-Name"); @@ -1762,7 +1762,7 @@ static void *rtsp_conversation_thread_func(void *pconn) { pthread_sigmask(SIG_UNBLOCK, &set, NULL); rtsp_conn_info *conn = pconn; - + rtp_initialise(conn); rtsp_message *req, *resp; @@ -1812,7 +1812,7 @@ static void *rtsp_conversation_thread_func(void *pconn) { debug(1, "Closing down RTSP conversation thread..."); if (rtsp_playing()) { - player_stop(&conn->player_thread,conn); // might be less noisy doing this first + player_stop(&conn->player_thread, conn); // might be less noisy doing this first rtp_shutdown(conn); // usleep(400000); // let an angel pass... pthread_mutex_unlock(&play_lock); @@ -1974,7 +1974,7 @@ void rtsp_listen_loop(void) { continue; rtsp_conn_info *conn = malloc(sizeof(rtsp_conn_info)); - if (conn==0) + if (conn == 0) die("Couldn't allocate memory for an rtsp_conn_info record."); memset(conn, 0, sizeof(rtsp_conn_info)); socklen_t slen = sizeof(conn->remote); @@ -2033,13 +2033,14 @@ void rtsp_listen_loop(void) { } else { debug(1, "Error figuring out Shairport Sync's own IP number."); } -// usleep(500000); -// pthread_t rtsp_conversation_thread; -// conn->thread = rtsp_conversation_thread; -// conn->stop = 0; // record's memory has been zeroed -// conn->authorized = 0; // record's memory has been zeroed + // usleep(500000); + // pthread_t rtsp_conversation_thread; + // conn->thread = rtsp_conversation_thread; + // conn->stop = 0; // record's memory has been zeroed + // conn->authorized = 0; // record's memory has been zeroed conn->running = 1; - ret = pthread_create(&conn->thread, NULL, rtsp_conversation_thread_func, conn); // also acts as a memory barrier + ret = pthread_create(&conn->thread, NULL, rtsp_conversation_thread_func, + conn); // also acts as a memory barrier if (ret) die("Failed to create RTSP receiver thread!"); track_thread(conn); diff --git a/shairport.c b/shairport.c index bad20077..53d0fdcd 100644 --- a/shairport.c +++ b/shairport.c @@ -254,8 +254,9 @@ void usage(char *progname) { "88) before trying to correct it.\n"); printf(" --password=PASSWORD require PASSWORD to connect. Default is not to require a " "password.\n"); - printf(" --logOutputLevel log the output level setting -- useful for setting maximum volume.\n"); - #ifdef CONFIG_METADATA + printf(" --logOutputLevel log the output level setting -- useful for setting maximum " + "volume.\n"); +#ifdef CONFIG_METADATA printf(" --metadata-pipename=PIPE send metadata to PIPE, e.g. " "--metadata-pipename=/tmp/shairport-sync-metadata.\n"); printf(" The default is /tmp/shairport-sync-metadata.\n"); @@ -285,7 +286,7 @@ int parse_options(int argc, char **argv) { {"reconnectToOutput", 'R', POPT_ARG_NONE, NULL, 0, NULL}, {"kill", 'k', POPT_ARG_NONE, NULL, 0, NULL}, {"daemon", 'd', POPT_ARG_NONE, &daemonisewith, 0, NULL}, - {"justDaemoniseNoPIDFile", 'j', POPT_ARG_NONE,&daemonisewithout, 0, NULL}, + {"justDaemoniseNoPIDFile", 'j', POPT_ARG_NONE, &daemonisewithout, 0, NULL}, {"configfile", 'c', POPT_ARG_STRING, &config.configfile, 0, NULL}, {"statistics", 0, POPT_ARG_NONE, &config.statistics_requested, 0, NULL}, {"logOutputLevel", 0, POPT_ARG_NONE, &config.logOutputLevel, 0, NULL}, @@ -363,17 +364,18 @@ int parse_options(int argc, char **argv) { } if ((daemonisewith) && (daemonisewithout)) - die("Select either daemonize_with_pid_file or daemonize_without_pid_file -- you have selected both!"); + die("Select either daemonize_with_pid_file or daemonize_without_pid_file -- you have selected " + "both!"); if ((daemonisewith) || (daemonisewithout)) { config.daemonise = 1; if (daemonisewith) config.daemonise_store_pid = 1; - }; + }; config.resyncthreshold = 1.0 * fResyncthreshold / 44100; config.tolerance = 1.0 * fTolerance / 44100; config.audio_backend_silent_lead_in_time = -1.0; // flag to indicate it has not been set - + config_setting_t *setting; const char *str = 0; int value = 0; @@ -405,7 +407,8 @@ int parse_options(int argc, char **argv) { else if (strcasecmp(str, "yes") == 0) daemonisewith = 1; else - die("Invalid daemonize_with_pid_file option choice \"%s\". It should be \"yes\" or \"no\""); + die("Invalid daemonize_with_pid_file option choice \"%s\". It should be \"yes\" or " + "\"no\""); } /* Get the Just_Daemonize setting. */ @@ -415,15 +418,17 @@ int parse_options(int argc, char **argv) { else if (strcasecmp(str, "yes") == 0) daemonisewithout = 1; else - die("Invalid daemonize_without_pid_file option choice \"%s\". It should be \"yes\" or \"no\""); + die("Invalid daemonize_without_pid_file option choice \"%s\". It should be \"yes\" or " + "\"no\""); } if ((daemonisewith) && (daemonisewithout)) - die("Select either daemonize_with_pid_file or daemonize_without_pid_file -- you have selected both!"); + die("Select either daemonize_with_pid_file or daemonize_without_pid_file -- you have " + "selected both!"); if ((daemonisewith) || (daemonisewithout)) { config.daemonise = 1; if (daemonisewith) config.daemonise_store_pid = 1; - } + } /* Get the directory path for the pid file created when the program is daemonised. */ if (config_lookup_string(config.cfg, "sessioncontrol.daemon_pid_dir", &str)) config.piddir = (char *)str; @@ -695,13 +700,15 @@ int parse_options(int argc, char **argv) { "\"yes\" or \"no\""); } - if (config_lookup_string(config.cfg, "sessioncontrol.before_play_begins_returns_output", &str)) { + if (config_lookup_string(config.cfg, "sessioncontrol.before_play_begins_returns_output", + &str)) { if (strcasecmp(str, "no") == 0) config.cmd_start_returns_output = 0; else if (strcasecmp(str, "yes") == 0) config.cmd_start_returns_output = 1; else - die("Invalid session control before_play_begins_returns_output option choice \"%s\". It should be " + die("Invalid session control before_play_begins_returns_output option choice \"%s\". It " + "should be " "\"yes\" or \"no\""); } @@ -721,9 +728,9 @@ int parse_options(int argc, char **argv) { config.timeout = value; config.dont_check_timeout = 0; // this is for legacy -- only set by -t 0 } - + #ifdef CONFIG_CONVOLUTION - + if (config_lookup_string(config.cfg, "dsp.convolution", &str)) { if (strcasecmp(str, "no") == 0) config.convolution = 0; @@ -731,33 +738,33 @@ int parse_options(int argc, char **argv) { config.convolution = 1; else die("Invalid dsp.convolution. It should be \"yes\" or \"no\""); - } - + if (config_lookup_float(config.cfg, "dsp.convolution_gain", &dvalue)) { config.convolution_gain = dvalue; if (dvalue > 10 || dvalue < -50) - die("Invalid value \"%f\" for dsp.convolution_gain. It should be between -50 and +10 dB", dvalue); + die("Invalid value \"%f\" for dsp.convolution_gain. It should be between -50 and +10 dB", + dvalue); } - + config.convolution_max_length = 8192; if (config_lookup_int(config.cfg, "dsp.convolution_max_length", &value)) { config.convolution_max_length = value; - + if (value < 1 || value > 200000) die("dsp.convolution_max_length must be within 1 and 200000"); } - + if (config_lookup_string(config.cfg, "dsp.convolution_ir_file", &str)) { config.convolution_ir_file = str; convolver_init(config.convolution_ir_file, config.convolution_max_length); } - + if (config.convolution && config.convolution_ir_file == NULL) { die("Convolution enabled but no convolution_ir_file provided"); } #endif - + if (config_lookup_string(config.cfg, "dsp.loudness", &str)) { if (strcasecmp(str, "no") == 0) config.loudness = 0; @@ -766,17 +773,20 @@ int parse_options(int argc, char **argv) { else die("Invalid dsp.convolution. It should be \"yes\" or \"no\""); } - + config.loudness_reference_volume_db = -20; if (config_lookup_float(config.cfg, "dsp.loudness_reference_volume_db", &dvalue)) { config.loudness_reference_volume_db = dvalue; if (dvalue > 0 || dvalue < -100) - die("Invalid value \"%f\" for dsp.loudness_reference_volume_db. It should be between -100 and 0", dvalue); + die("Invalid value \"%f\" for dsp.loudness_reference_volume_db. It should be between " + "-100 and 0", + dvalue); } - + if (config.loudness == 1 && config_lookup_string(config.cfg, "alsa.mixer_control_name", &str)) - die("Loudness activated but hardware volume is active. You must remove \"alsa.mixer_control_name\" to use the loudness filter."); - + die("Loudness activated but hardware volume is active. You must remove " + "\"alsa.mixer_control_name\" to use the loudness filter."); + } else { if (config_error_type(&config_file_stuff) == CONFIG_ERR_FILE_IO) debug(1, "Error reading configuration file \"%s\": \"%s\".", @@ -924,21 +934,20 @@ void shairport_startup_complete(void) { } } - const char *pid_file_proc(void) { - #ifdef USE_CUSTOM_PID_DIR - char * use_this_pid_dir = PIDDIR; - #else - char * use_this_pid_dir = "/var/run/shairport-sync"; - #endif - // debug(1,"config.piddir \"%s\".",config.piddir); - if (config.piddir) - use_this_pid_dir = config.piddir; - char fn[8192]; - snprintf(fn, sizeof(fn), "%s/%s.pid", use_this_pid_dir, - daemon_pid_file_ident ? daemon_pid_file_ident : "unknown"); - //debug(1,"fn \"%s\".",fn); - return strdup(fn); +#ifdef USE_CUSTOM_PID_DIR + char *use_this_pid_dir = PIDDIR; +#else + char *use_this_pid_dir = "/var/run/shairport-sync"; +#endif + // debug(1,"config.piddir \"%s\".",config.piddir); + if (config.piddir) + use_this_pid_dir = config.piddir; + char fn[8192]; + snprintf(fn, sizeof(fn), "%s/%s.pid", use_this_pid_dir, + daemon_pid_file_ident ? daemon_pid_file_ident : "unknown"); + // debug(1,"fn \"%s\".",fn); + return strdup(fn); } void exit_function() { @@ -982,7 +991,8 @@ int main(int argc, char **argv) { die("Can not recognise the endianness of the processor."); strcpy(configuration_file_path, SYSCONFDIR); - // strcat(configuration_file_path, "/shairport-sync"); // thinking about adding a special shairport-sync directory + // strcat(configuration_file_path, "/shairport-sync"); // thinking about adding a special + // shairport-sync directory strcat(configuration_file_path, "/"); strcat(configuration_file_path, appName); strcat(configuration_file_path, ".conf"); @@ -1102,7 +1112,7 @@ int main(int argc, char **argv) { // parse arguments into config -- needed to locate pid_dir int audio_arg = parse_options(argc, argv); - /* Check if we are called with -k or --kill parameter */ + /* Check if we are called with -k or --kill parameter */ if (argc >= 2 && ((strcmp(argv[1], "-k") == 0) || (strcmp(argv[1], "--kill") == 0))) { int ret; @@ -1279,7 +1289,7 @@ int main(int argc, char **argv) { /* Print out options */ debug(1, "statistics_requester status is %d.", config.statistics_requested); debug(1, "daemon status is %d.", config.daemonise); - debug(1, "deamon pid file is \"%s\".",pid_file_proc()); + debug(1, "deamon pid file is \"%s\".", pid_file_proc()); debug(1, "rtsp listening port is %d.", config.port); debug(1, "udp base port is %d.", config.udp_port_base); debug(1, "udp port range is %d.", config.udp_port_range); @@ -1316,7 +1326,8 @@ int main(int argc, char **argv) { debug(1, "audio backend desired buffer length is %f seconds.", config.audio_backend_buffer_desired_length); debug(1, "audio backend latency offset is %f seconds.", config.audio_backend_latency_offset); - debug(1, "audio backend silence lead-in time is %f seconds. A value -1.0 means use the default.", config.audio_backend_silent_lead_in_time); + debug(1, "audio backend silence lead-in time is %f seconds. A value -1.0 means use the default.", + config.audio_backend_silent_lead_in_time); debug(1, "volume range in dB (zero means use the range specified by the mixer): %u.", config.volume_range_db); debug(1, "zeroconf regtype is \"%s\".", config.regtype); @@ -1352,7 +1363,7 @@ int main(int argc, char **argv) { #endif debug(1, "loudness is %d.", config.loudness); debug(1, "loudness reference level is %f", config.loudness_reference_volume_db); - + uint8_t ap_md5[16]; #ifdef HAVE_LIBSSL