Tidy up source using clang-format
This commit is contained in:
@@ -24,8 +24,8 @@
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "audio.h"
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -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",
|
||||
|
||||
+79
-75
@@ -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;
|
||||
}
|
||||
|
||||
+3
-4
@@ -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); }
|
||||
|
||||
|
||||
+38
-44
@@ -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; }
|
||||
|
||||
|
||||
+11
-12
@@ -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))
|
||||
|
||||
+1
-2
@@ -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) {
|
||||
|
||||
+19
-21
@@ -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;
|
||||
}
|
||||
|
||||
+4
-4
@@ -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");
|
||||
|
||||
+6
-6
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
+19
-24
@@ -1,54 +1,49 @@
|
||||
#include "loudness.h"
|
||||
#include <math.h>
|
||||
#include "common.h"
|
||||
#include <math.h>
|
||||
|
||||
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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
#include <openssl/aes.h>
|
||||
#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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
+57
-46
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user