find . \( -name \*.cpp -or -name \*.h -or -name \*.c \) -exec clang-format -i -style='{BasedOnStyle: llvm, IndentWidth: 2, ColumnLimit: 100}' '{}' \;

This commit is contained in:
Mike Brady
2019-06-19 19:06:54 +01:00
parent 7fc977d8d3
commit c8b0be30b4
19 changed files with 575 additions and 570 deletions
+10 -13
View File
@@ -46,7 +46,6 @@
#include "dbus-service.h" #include "dbus-service.h"
#endif #endif
enum am_state state; enum am_state state;
enum ps_state { ps_inactive, ps_active } player_state; enum ps_state { ps_inactive, ps_active } player_state;
@@ -73,10 +72,10 @@ void going_active(int block) {
if (config.disable_standby_mode == disable_standby_auto) { if (config.disable_standby_mode == disable_standby_auto) {
#ifdef CONFIG_DBUS_INTERFACE #ifdef CONFIG_DBUS_INTERFACE
if (dbus_service_is_running()) if (dbus_service_is_running())
shairport_sync_set_disable_standby(SHAIRPORT_SYNC(shairportSyncSkeleton), TRUE); shairport_sync_set_disable_standby(SHAIRPORT_SYNC(shairportSyncSkeleton), TRUE);
else else
config.keep_dac_busy = 1; config.keep_dac_busy = 1;
#else #else
config.keep_dac_busy = 1; config.keep_dac_busy = 1;
#endif #endif
@@ -100,12 +99,12 @@ void going_inactive(int block) {
if (config.disable_standby_mode == disable_standby_auto) { if (config.disable_standby_mode == disable_standby_auto) {
#ifdef CONFIG_DBUS_INTERFACE #ifdef CONFIG_DBUS_INTERFACE
if (dbus_service_is_running()) if (dbus_service_is_running())
shairport_sync_set_disable_standby(SHAIRPORT_SYNC(shairportSyncSkeleton), FALSE); shairport_sync_set_disable_standby(SHAIRPORT_SYNC(shairportSyncSkeleton), FALSE);
else else
config.keep_dac_busy = 0; config.keep_dac_busy = 0;
#else #else
config.keep_dac_busy = 0; config.keep_dac_busy = 0;
#endif #endif
} }
} }
@@ -255,9 +254,7 @@ void *activity_monitor_thread_code(void *arg) {
pthread_exit(NULL); pthread_exit(NULL);
} }
enum am_state activity_status() { enum am_state activity_status() { return (state); }
return (state);
}
void activity_monitor_start() { void activity_monitor_start() {
// debug(1,"activity_monitor_start"); // debug(1,"activity_monitor_start");
+1 -1
View File
@@ -5,4 +5,4 @@ enum am_state { am_inactive, am_active, am_timing_out };
void activity_monitor_start(); void activity_monitor_start();
void activity_monitor_stop(); void activity_monitor_stop();
void activity_monitor_signify_activity(int active); // 0 means inactive, non-zero means active void activity_monitor_signify_activity(int active); // 0 means inactive, non-zero means active
enum am_state activity_status(); // true if non inactive; false if inactive enum am_state activity_status(); // true if non inactive; false if inactive
+257 -239
View File
@@ -37,9 +37,9 @@
#include "config.h" #include "config.h"
#include "common.h"
#include "activity_monitor.h" #include "activity_monitor.h"
#include "audio.h" #include "audio.h"
#include "common.h"
enum alsa_backend_mode { enum alsa_backend_mode {
abm_disconnected, abm_disconnected,
@@ -48,8 +48,8 @@ enum alsa_backend_mode {
} alsa_backend_state; // under the control of alsa_mutex } alsa_backend_state; // under the control of alsa_mutex
typedef struct { typedef struct {
snd_pcm_format_t alsa_code; snd_pcm_format_t alsa_code;
int frame_size; int frame_size;
} format_record; } format_record;
static void help(void); static void help(void);
@@ -72,8 +72,9 @@ static void parameters(audio_parameters *info);
int mute(int do_mute); // returns true if it actually is allowed to use the mute int mute(int do_mute); // returns true if it actually is allowed to use the mute
static double set_volume; static double set_volume;
static int output_method_signalled = 0; // for reporting whether it's using mmap or not static int output_method_signalled = 0; // for reporting whether it's using mmap or not
int delay_type_notified = -1; // for controlling the reporting of whether the output device can do precison delays (e.g. alsa->pulsaudio virtual devices can't) int delay_type_notified = -1; // for controlling the reporting of whether the output device can do
int use_monotonic_clock = 0; // this value will be set when the hardware is initialised // precison delays (e.g. alsa->pulsaudio virtual devices can't)
int use_monotonic_clock = 0; // this value will be set when the hardware is initialised
audio_output audio_alsa = { audio_output audio_alsa = {
.name = "alsa", .name = "alsa",
@@ -122,7 +123,8 @@ int frame_size; // in bytes for interleaved stereo
int alsa_device_initialised; // boolean to ensure the initialisation is only int alsa_device_initialised; // boolean to ensure the initialisation is only
// done once // done once
enum yndk_type precision_delay_available_status = YNDK_DONT_KNOW; // initially, we don't know if the device can do precision delay enum yndk_type precision_delay_available_status =
YNDK_DONT_KNOW; // initially, we don't know if the device can do precision delay
snd_pcm_t *alsa_handle = NULL; snd_pcm_t *alsa_handle = NULL;
static snd_pcm_hw_params_t *alsa_params = NULL; static snd_pcm_hw_params_t *alsa_params = NULL;
@@ -155,15 +157,17 @@ int volume_based_mute_is_active =
0; // set when muting is being done by a setting the volume to a magic value 0; // set when muting is being done by a setting the volume to a magic value
// use this to allow the use of snd_pcm_writei or snd_pcm_mmap_writei // use this to allow the use of snd_pcm_writei or snd_pcm_mmap_writei
snd_pcm_sframes_t (*alsa_pcm_write)(snd_pcm_t *, const void *, snd_pcm_sframes_t (*alsa_pcm_write)(snd_pcm_t *, const void *, snd_pcm_uframes_t) = snd_pcm_writei;
snd_pcm_uframes_t) = snd_pcm_writei;
int precision_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay,
enum yndk_type *using_update_timestamps);
int standard_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay,
enum yndk_type *using_update_timestamps);
int precision_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay, enum yndk_type *using_update_timestamps); // use this to allow the use of standard or precision delay calculations, with standard the, uh,
int standard_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay, enum yndk_type *using_update_timestamps); // standard.
int (*delay_and_status)(snd_pcm_state_t *state, snd_pcm_sframes_t *delay,
// use this to allow the use of standard or precision delay calculations, with standard the, uh, standard. enum yndk_type *using_update_timestamps) = standard_delay_and_status;
int (*delay_and_status)(snd_pcm_state_t *state, snd_pcm_sframes_t *delay, enum yndk_type *using_update_timestamps) = standard_delay_and_status;
// this will return true if the DAC can return precision delay information and false if not // this will return true if the DAC can return precision delay information and false if not
// if it is not yet known, it will test the output device to find out // if it is not yet known, it will test the output device to find out
@@ -175,14 +179,16 @@ int (*delay_and_status)(snd_pcm_state_t *state, snd_pcm_sframes_t *delay, enum y
int precision_delay_available() { int precision_delay_available() {
if (precision_delay_available_status == YNDK_DONT_KNOW) { if (precision_delay_available_status == YNDK_DONT_KNOW) {
// this is very crude -- if the device is a hardware device, then it's assumed the delay is precise // this is very crude -- if the device is a hardware device, then it's assumed the delay is
// precise
const char *output_device_name = snd_pcm_name(alsa_handle); const char *output_device_name = snd_pcm_name(alsa_handle);
int is_a_real_hardware_device = (strstr(output_device_name,"hw:") == output_device_name); int is_a_real_hardware_device = (strstr(output_device_name, "hw:") == output_device_name);
// The criteria as to whether precision delay is available // The criteria as to whether precision delay is available
// is whether the device driver returns non-zero update timestamps // is whether the device driver returns non-zero update timestamps
// If it does, and the device is a hardware device (i.e. its name begins with "hw:"), // If it does, and the device is a hardware device (i.e. its name begins with "hw:"),
// it is considered that precision delay is available. Otherwise, it's considered to be unavailable. // it is considered that precision delay is available. Otherwise, it's considered to be
// unavailable.
// To test, we play a silence buffer (fairly large to avoid underflow) // To test, we play a silence buffer (fairly large to avoid underflow)
// and then we check the delay return. It will tell us if it // and then we check the delay return. It will tell us if it
@@ -215,16 +221,19 @@ int precision_delay_available() {
snd_pcm_state_t state; snd_pcm_state_t state;
snd_pcm_sframes_t delay; snd_pcm_sframes_t delay;
int ret = precision_delay_and_status(&state, &delay, &uses_update_timestamps); int ret = precision_delay_and_status(&state, &delay, &uses_update_timestamps);
// debug(3,"alsa: precision_delay_available asking for delay and status with a return status of %d, a delay of %ld and a uses_update_timestamps of %d.", ret, delay, uses_update_timestamps); // debug(3,"alsa: precision_delay_available asking for delay and status with a return status
// of %d, a delay of %ld and a uses_update_timestamps of %d.", ret, delay,
// uses_update_timestamps);
if (ret == 0) { if (ret == 0) {
if ((uses_update_timestamps == YNDK_YES) && (is_a_real_hardware_device)) { if ((uses_update_timestamps == YNDK_YES) && (is_a_real_hardware_device)) {
precision_delay_available_status = YNDK_YES; precision_delay_available_status = YNDK_YES;
debug(2,"alsa: precision delay timing is available."); debug(2, "alsa: precision delay timing is available.");
} else { } else {
if ((uses_update_timestamps == YNDK_YES) && (!is_a_real_hardware_device)) { if ((uses_update_timestamps == YNDK_YES) && (!is_a_real_hardware_device)) {
debug(2,"alsa: precision delay timing is not available because it's not definitely a hardware device."); debug(2, "alsa: precision delay timing is not available because it's not definitely a "
"hardware device.");
} else { } else {
debug(2,"alsa: precision delay timing is not available."); debug(2, "alsa: precision delay timing is not available.");
} }
precision_delay_available_status = YNDK_NO; precision_delay_available_status = YNDK_NO;
} }
@@ -234,7 +243,6 @@ int precision_delay_available() {
return (precision_delay_available_status == YNDK_YES); return (precision_delay_available_status == YNDK_YES);
} }
// static int play_number; // static int play_number;
// static int64_t accumulated_delay, accumulated_da_delay; // static int64_t accumulated_delay, accumulated_da_delay;
int alsa_characteristics_already_listed = 0; int alsa_characteristics_already_listed = 0;
@@ -259,7 +267,9 @@ static void help(void) {
" -c mixer-control set the mixer control name, default is to use no mixer.\n" " -c mixer-control set the mixer control name, default is to use no mixer.\n"
" -m mixer-device set the mixer device, default is the output device.\n" " -m mixer-device set the mixer device, default is the output device.\n"
" -i mixer-index set the mixer index, default is 0.\n"); " -i mixer-index set the mixer index, default is 0.\n");
int r = system("if [ -d /proc/asound ] ; then echo \" hardware output devices:\" ; ls -al /proc/asound/ 2>/dev/null | grep '\\->' | tr -s ' ' | cut -d ' ' -f 9 | while read line; do echo \" \\\"hw:$line\\\"\" ; done ; fi"); int r = system("if [ -d /proc/asound ] ; then echo \" hardware output devices:\" ; ls -al "
"/proc/asound/ 2>/dev/null | grep '\\->' | tr -s ' ' | cut -d ' ' -f 9 | while "
"read line; do echo \" \\\"hw:$line\\\"\" ; done ; fi");
if (r != 0) if (r != 0)
debug(2, "error %d executing a script to list alsa hardware device names", r); debug(2, "error %d executing a script to list alsa hardware device names", r);
} }
@@ -343,66 +353,51 @@ void actual_close_alsa_device() {
} }
} }
// This array is a sequence of the output rates to be tried if automatic speed selection is requested. // This array is a sequence of the output rates to be tried if automatic speed selection is
// requested.
// There is no benefit to upconverting the frame rate, other than for compatibility. // There is no benefit to upconverting the frame rate, other than for compatibility.
// The lowest rate that the DAC is capable of is chosen. // The lowest rate that the DAC is capable of is chosen.
unsigned int auto_speed_output_rates[] = { unsigned int auto_speed_output_rates[] = {
44100, 44100, 88200, 176400, 352800,
88200,
176400,
352800,
}; };
// This array is of all the formats known to Shairport Sync, in order of the SPS_FORMAT definitions, with their equivalent alsa codes and their frame sizes. // This array is of all the formats known to Shairport Sync, in order of the SPS_FORMAT definitions,
// If just one format is requested, then its entry is searched for in the array and checked on the device // with their equivalent alsa codes and their frame sizes.
// If just one format is requested, then its entry is searched for in the array and checked on the
// device
// If auto format is requested, then each entry in turn is tried until a working format is found. // If auto format is requested, then each entry in turn is tried until a working format is found.
// So, it should be in the search order. // So, it should be in the search order.
format_record fr[] = { format_record fr[] = {
{SND_PCM_FORMAT_UNKNOWN,0}, // unknown {SND_PCM_FORMAT_UNKNOWN, 0}, // unknown
{SND_PCM_FORMAT_S8,2}, {SND_PCM_FORMAT_S8, 2}, {SND_PCM_FORMAT_U8, 2}, {SND_PCM_FORMAT_S16, 4},
{SND_PCM_FORMAT_U8,2}, {SND_PCM_FORMAT_S16_LE, 4}, {SND_PCM_FORMAT_S16_BE, 4}, {SND_PCM_FORMAT_S24, 4},
{SND_PCM_FORMAT_S16,4}, {SND_PCM_FORMAT_S24_LE, 8}, {SND_PCM_FORMAT_S24_BE, 8}, {SND_PCM_FORMAT_S24_3LE, 6},
{SND_PCM_FORMAT_S16_LE,4}, {SND_PCM_FORMAT_S24_3BE, 6}, {SND_PCM_FORMAT_S32, 8}, {SND_PCM_FORMAT_S32_LE, 8},
{SND_PCM_FORMAT_S16_BE,4}, {SND_PCM_FORMAT_S32_BE, 8}, {SND_PCM_FORMAT_UNKNOWN, 0}, // auto
{SND_PCM_FORMAT_S24,4}, {SND_PCM_FORMAT_UNKNOWN, 0}, // illegal
{SND_PCM_FORMAT_S24_LE,8}, };
{SND_PCM_FORMAT_S24_BE,8},
{SND_PCM_FORMAT_S24_3LE,6},
{SND_PCM_FORMAT_S24_3BE,6},
{SND_PCM_FORMAT_S32,8},
{SND_PCM_FORMAT_S32_LE,8},
{SND_PCM_FORMAT_S32_BE,8},
{SND_PCM_FORMAT_UNKNOWN,0}, // auto
{SND_PCM_FORMAT_UNKNOWN,0}, // illegal
};
// This array is the sequence of formats to be tried if automatic selection of the format is requested. // This array is the sequence of formats to be tried if automatic selection of the format is
// Ideally, audio should pass through Shairport Sync unaltered, apart from occasional interpolation. // requested.
// If the user chooses a hardware mixer, then audio could go straight through, unaltered, as signed 16 bit stereo. // Ideally, audio should pass through Shairport Sync unaltered, apart from occasional interpolation.
// However, the user might, at any point, select an option that requires modification, such as stereo to mono mixing, // If the user chooses a hardware mixer, then audio could go straight through, unaltered, as signed
// additional volume attenuation, convolution, and so on. For this reason, // 16 bit stereo.
// we look for the greatest depth the DAC is capable of, since upconverting it is completely lossless. // However, the user might, at any point, select an option that requires modification, such as
// If audio processing is required, then the dither that must be added will // stereo to mono mixing,
// be added at the lowest possible level. // additional volume attenuation, convolution, and so on. For this reason,
// Hence, selecting the greatest bit depth is always either beneficial or neutral. // we look for the greatest depth the DAC is capable of, since upconverting it is completely
// lossless.
// If audio processing is required, then the dither that must be added will
// be added at the lowest possible level.
// Hence, selecting the greatest bit depth is always either beneficial or neutral.
enum sps_format_t auto_format_check_sequence[] = { enum sps_format_t auto_format_check_sequence[] = {
SPS_FORMAT_S32, SPS_FORMAT_S32, SPS_FORMAT_S32_LE, SPS_FORMAT_S32_BE, SPS_FORMAT_S24, SPS_FORMAT_S24_LE,
SPS_FORMAT_S32_LE, SPS_FORMAT_S24_BE, SPS_FORMAT_S24_3LE, SPS_FORMAT_S24_3BE, SPS_FORMAT_S16, SPS_FORMAT_S16_LE,
SPS_FORMAT_S32_BE, SPS_FORMAT_S16_BE, SPS_FORMAT_S8, SPS_FORMAT_U8,
SPS_FORMAT_S24, };
SPS_FORMAT_S24_LE,
SPS_FORMAT_S24_BE,
SPS_FORMAT_S24_3LE,
SPS_FORMAT_S24_3BE,
SPS_FORMAT_S16,
SPS_FORMAT_S16_LE,
SPS_FORMAT_S16_BE,
SPS_FORMAT_S8,
SPS_FORMAT_U8,
};
// assuming pthread cancellation is disabled // assuming pthread cancellation is disabled
// if do_auto_setting is true and auto format or auto speed has been requested, // if do_auto_setting is true and auto format or auto speed has been requested,
@@ -420,7 +415,8 @@ int actual_open_alsa_device(int do_auto_setup) {
*/ */
int ret, dir = 0; int ret, dir = 0;
unsigned int actual_sample_rate; // this will be given the rate requested and will be given the actual rate unsigned int
actual_sample_rate; // this will be given the rate requested and will be given the actual rate
// snd_pcm_uframes_t frames = 441 * 10; // snd_pcm_uframes_t frames = 441 * 10;
snd_pcm_uframes_t actual_buffer_length; snd_pcm_uframes_t actual_buffer_length;
snd_pcm_access_t access; snd_pcm_access_t access;
@@ -444,7 +440,8 @@ int actual_open_alsa_device(int do_auto_setup) {
} else { } else {
char errorstring[1024]; char errorstring[1024];
strerror_r(-ret, (char *)errorstring, sizeof(errorstring)); strerror_r(-ret, (char *)errorstring, sizeof(errorstring));
warn("alsa: error %d (\"%s\") opening alsa device \"%s\".", ret, (char *)errorstring, alsa_out_dev); warn("alsa: error %d (\"%s\") opening alsa device \"%s\".", ret, (char *)errorstring,
alsa_out_dev);
} }
return ret; return ret;
} }
@@ -455,8 +452,8 @@ int actual_open_alsa_device(int do_auto_setup) {
ret = snd_pcm_hw_params_any(alsa_handle, alsa_params); ret = snd_pcm_hw_params_any(alsa_handle, alsa_params);
if (ret < 0) { if (ret < 0) {
die("audio_alsa: Broken configuration for device \"%s\": no configurations " die("audio_alsa: Broken configuration for device \"%s\": no configurations "
"available", "available",
alsa_out_dev); alsa_out_dev);
return ret; return ret;
} }
@@ -485,7 +482,6 @@ int actual_open_alsa_device(int do_auto_setup) {
return ret; return ret;
} }
ret = snd_pcm_hw_params_set_channels(alsa_handle, alsa_params, 2); ret = snd_pcm_hw_params_set_channels(alsa_handle, alsa_params, 2);
if (ret < 0) { if (ret < 0) {
warn("audio_alsa: Channels count (2) not available for device \"%s\": %s", alsa_out_dev, warn("audio_alsa: Channels count (2) not available for device \"%s\": %s", alsa_out_dev,
@@ -496,87 +492,89 @@ int actual_open_alsa_device(int do_auto_setup) {
snd_pcm_format_t sf; snd_pcm_format_t sf;
if ((do_auto_setup == 0) || (config.output_format_auto_requested == 0)) { // no auto format if ((do_auto_setup == 0) || (config.output_format_auto_requested == 0)) { // no auto format
if ((config.output_format > SPS_FORMAT_UNKNOWN) && (config.output_format < SPS_FORMAT_AUTO)) { if ((config.output_format > SPS_FORMAT_UNKNOWN) && (config.output_format < SPS_FORMAT_AUTO)) {
sf = fr[config.output_format].alsa_code; sf = fr[config.output_format].alsa_code;
frame_size = fr[config.output_format].frame_size; frame_size = fr[config.output_format].frame_size;
} else { } else {
warn("alsa: unexpected output format %d. Set to S16_LE.",config.output_format); warn("alsa: unexpected output format %d. Set to S16_LE.", config.output_format);
config.output_format = SPS_FORMAT_S16_LE; config.output_format = SPS_FORMAT_S16_LE;
sf = fr[config.output_format].alsa_code; sf = fr[config.output_format].alsa_code;
frame_size = fr[config.output_format].frame_size; frame_size = fr[config.output_format].frame_size;
} }
ret = snd_pcm_hw_params_set_format(alsa_handle, alsa_params, sf); ret = snd_pcm_hw_params_set_format(alsa_handle, alsa_params, sf);
if (ret < 0) { if (ret < 0) {
warn("audio_alsa: Alsa sample format %d not available for device \"%s\": %s", sf, warn("audio_alsa: Alsa sample format %d not available for device \"%s\": %s", sf,
alsa_out_dev, snd_strerror(ret)); alsa_out_dev, snd_strerror(ret));
return ret; return ret;
} }
} else { // auto format } else { // auto format
int number_of_formats_to_try; int number_of_formats_to_try;
enum sps_format_t *formats; enum sps_format_t *formats;
formats = auto_format_check_sequence; formats = auto_format_check_sequence;
number_of_formats_to_try = sizeof(auto_format_check_sequence)/sizeof(sps_format_t); number_of_formats_to_try = sizeof(auto_format_check_sequence) / sizeof(sps_format_t);
int i = 0; int i = 0;
int format_found = 0; int format_found = 0;
enum sps_format_t trial_format = SPS_FORMAT_UNKNOWN; enum sps_format_t trial_format = SPS_FORMAT_UNKNOWN;
while ((i < number_of_formats_to_try) && (format_found == 0)) { while ((i < number_of_formats_to_try) && (format_found == 0)) {
trial_format = formats[i]; trial_format = formats[i];
sf = fr[trial_format].alsa_code; sf = fr[trial_format].alsa_code;
frame_size = fr[trial_format].frame_size; frame_size = fr[trial_format].frame_size;
ret = snd_pcm_hw_params_set_format(alsa_handle, alsa_params, sf); ret = snd_pcm_hw_params_set_format(alsa_handle, alsa_params, sf);
if (ret == 0) if (ret == 0)
format_found = 1; format_found = 1;
else else
i++; i++;
} }
if (ret == 0) { if (ret == 0) {
config.output_format = trial_format; config.output_format = trial_format;
debug(1,"alsa: output format chosen is \"%s\".",sps_format_description_string(config.output_format)); debug(1, "alsa: output format chosen is \"%s\".",
} else { sps_format_description_string(config.output_format));
warn("audio_alsa: Could not automatically set the output format for device \"%s\": %s", } else {
alsa_out_dev, snd_strerror(ret)); warn("audio_alsa: Could not automatically set the output format for device \"%s\": %s",
return ret; alsa_out_dev, snd_strerror(ret));
} return ret;
}
} }
if ((do_auto_setup == 0) || (config.output_rate_auto_requested == 0)) { // no auto format if ((do_auto_setup == 0) || (config.output_rate_auto_requested == 0)) { // no auto format
actual_sample_rate = config.output_rate; // this is the requested rate -- it'll be changed to the actual rate actual_sample_rate =
ret = snd_pcm_hw_params_set_rate_near(alsa_handle, alsa_params, &actual_sample_rate, &dir); config.output_rate; // this is the requested rate -- it'll be changed to the actual rate
if (ret < 0) { ret = snd_pcm_hw_params_set_rate_near(alsa_handle, alsa_params, &actual_sample_rate, &dir);
warn("audio_alsa: Rate %iHz not available for playback: %s", config.output_rate, if (ret < 0) {
snd_strerror(ret)); warn("audio_alsa: Rate %iHz not available for playback: %s", config.output_rate,
return ret; snd_strerror(ret));
} return ret;
} else { }
int number_of_speeds_to_try; } else {
unsigned int *speeds; int number_of_speeds_to_try;
unsigned int *speeds;
speeds = auto_speed_output_rates; speeds = auto_speed_output_rates;
number_of_speeds_to_try = sizeof(auto_speed_output_rates)/sizeof(int); number_of_speeds_to_try = sizeof(auto_speed_output_rates) / sizeof(int);
int i = 0; int i = 0;
int speed_found = 0; int speed_found = 0;
while ((i < number_of_speeds_to_try) && (speed_found == 0)) { while ((i < number_of_speeds_to_try) && (speed_found == 0)) {
actual_sample_rate = speeds[i]; actual_sample_rate = speeds[i];
ret = snd_pcm_hw_params_set_rate_near(alsa_handle, alsa_params, &actual_sample_rate, &dir); ret = snd_pcm_hw_params_set_rate_near(alsa_handle, alsa_params, &actual_sample_rate, &dir);
if (ret == 0) { if (ret == 0) {
speed_found = 1; speed_found = 1;
if (actual_sample_rate != speeds[i]) if (actual_sample_rate != speeds[i])
warn("Speed requested: %d. Speed available: %d.",speeds[i],actual_sample_rate); warn("Speed requested: %d. Speed available: %d.", speeds[i], actual_sample_rate);
} else { } else {
i++; i++;
} }
} }
if (ret == 0) { if (ret == 0) {
config.output_rate = actual_sample_rate; config.output_rate = actual_sample_rate;
debug(1,"alsa: output speed chosen is %d.",config.output_rate); debug(1, "alsa: output speed chosen is %d.", config.output_rate);
} else { } else {
warn("audio_alsa: Could not automatically set the output rate for device \"%s\": %s", warn("audio_alsa: Could not automatically set the output rate for device \"%s\": %s",
alsa_out_dev, snd_strerror(ret)); alsa_out_dev, snd_strerror(ret));
return ret; return ret;
} }
} }
if (set_period_size_request != 0) { if (set_period_size_request != 0) {
debug(1, "Attempting to set the period size to %lu", period_size_requested); debug(1, "Attempting to set the period size to %lu", period_size_requested);
@@ -649,7 +647,7 @@ int actual_open_alsa_device(int do_auto_setup) {
return -EINVAL; return -EINVAL;
} }
use_monotonic_clock = snd_pcm_hw_params_is_monotonic(alsa_params); use_monotonic_clock = snd_pcm_hw_params_is_monotonic(alsa_params);
ret = snd_pcm_hw_params_get_buffer_size(alsa_params, &actual_buffer_length); ret = snd_pcm_hw_params_get_buffer_size(alsa_params, &actual_buffer_length);
if (ret < 0) { if (ret < 0) {
@@ -683,8 +681,7 @@ int actual_open_alsa_device(int do_auto_setup) {
ret = snd_pcm_prepare(alsa_handle); ret = snd_pcm_prepare(alsa_handle);
if (ret < 0) { if (ret < 0) {
warn("audio_alsa: Unable to prepare the device: \"%s\": %s.", alsa_out_dev, warn("audio_alsa: Unable to prepare the device: \"%s\": %s.", alsa_out_dev, snd_strerror(ret));
snd_strerror(ret));
return ret; return ret;
} }
@@ -717,13 +714,12 @@ int actual_open_alsa_device(int do_auto_setup) {
actual_buffer_length, config.audio_backend_buffer_desired_length); actual_buffer_length, config.audio_backend_buffer_desired_length);
} }
if (config.use_precision_timing == YNA_YES) if (config.use_precision_timing == YNA_YES)
delay_and_status = precision_delay_and_status; delay_and_status = precision_delay_and_status;
else if (config.use_precision_timing == YNA_AUTO) { else if (config.use_precision_timing == YNA_AUTO) {
if (precision_delay_available()) { if (precision_delay_available()) {
delay_and_status = precision_delay_and_status; delay_and_status = precision_delay_and_status;
debug(2,"alsa: precision timing selected for \"auto\" mode"); debug(2, "alsa: precision timing selected for \"auto\" mode");
} }
} }
@@ -1103,11 +1099,10 @@ static int init(int argc, char **argv) {
} }
} }
/* Get the output format, using the same names as aplay does*/ /* Get the output format, using the same names as aplay does*/
if (config_lookup_string(config.cfg, "alsa.output_format", &str)) { if (config_lookup_string(config.cfg, "alsa.output_format", &str)) {
int temp_output_format_auto_requested = config.output_format_auto_requested; int temp_output_format_auto_requested = config.output_format_auto_requested;
config.output_format_auto_requested = 0; // assume a valid format will be given. config.output_format_auto_requested = 0; // assume a valid format will be given.
if (strcasecmp(str, "S16") == 0) if (strcasecmp(str, "S16") == 0)
config.output_format = SPS_FORMAT_S16; config.output_format = SPS_FORMAT_S16;
else if (strcasecmp(str, "S16_LE") == 0) else if (strcasecmp(str, "S16_LE") == 0)
@@ -1137,48 +1132,54 @@ static int init(int argc, char **argv) {
else if (strcasecmp(str, "auto") == 0) else if (strcasecmp(str, "auto") == 0)
config.output_format_auto_requested = 1; config.output_format_auto_requested = 1;
else { else {
config.output_format_auto_requested = temp_output_format_auto_requested; //format was invalid; recall the original setting config.output_format_auto_requested =
temp_output_format_auto_requested; // format was invalid; recall the original setting
warn("Invalid output format \"%s\". It should be \"auto\", \"U8\", \"S8\", " warn("Invalid output format \"%s\". It should be \"auto\", \"U8\", \"S8\", "
"\"S16\", \"S24\", \"S24_LE\", \"S24_BE\", " "\"S16\", \"S24\", \"S24_LE\", \"S24_BE\", "
"\"S24_3LE\", \"S24_3BE\" or " "\"S24_3LE\", \"S24_3BE\" or "
"\"S32\", \"S32_LE\", \"S32_BE\". It remains set to \"%s\".", str, "\"S32\", \"S32_LE\", \"S32_BE\". It remains set to \"%s\".",
config.output_format_auto_requested == 1 ? "auto" : sps_format_description_string(config.output_format)); str, config.output_format_auto_requested == 1 ? "auto" : sps_format_description_string(
config.output_format));
} }
} }
if (config_lookup_string(config.cfg, "alsa.output_rate", &str)) { if (config_lookup_string(config.cfg, "alsa.output_rate", &str)) {
if (strcasecmp(str, "auto") == 0) { if (strcasecmp(str, "auto") == 0) {
config.output_rate_auto_requested = 1; config.output_rate_auto_requested = 1;
} else { } else {
if (config.output_rate_auto_requested == 1) if (config.output_rate_auto_requested == 1)
warn("Invalid output rate \"%s\". It should be \"auto\", 44100, 88200, 176400 or 352800. " warn("Invalid output rate \"%s\". It should be \"auto\", 44100, 88200, 176400 or 352800. "
"It remains set to \"auto\". Note: numbers should not be placed in quotes.", str); "It remains set to \"auto\". Note: numbers should not be placed in quotes.",
else str);
warn("Invalid output rate \"%s\". It should be \"auto\", 44100, 88200, 176400 or 352800. " else
"It remains set to %d. Note: numbers should not be placed in quotes.", str, config.output_rate); warn("Invalid output rate \"%s\". It should be \"auto\", 44100, 88200, 176400 or 352800. "
} "It remains set to %d. Note: numbers should not be placed in quotes.",
} str, config.output_rate);
}
}
/* Get the output rate, which must be a multiple of 44,100*/ /* Get the output rate, which must be a multiple of 44,100*/
if (config_lookup_int(config.cfg, "alsa.output_rate", &value)) { if (config_lookup_int(config.cfg, "alsa.output_rate", &value)) {
debug(1, "alsa output rate is %d frames per second", value); debug(1, "alsa output rate is %d frames per second", value);
switch (value) { switch (value) {
case 44100: case 44100:
case 88200: case 88200:
case 176400: case 176400:
case 352800: case 352800:
config.output_rate = value; config.output_rate = value;
config.output_rate_auto_requested = 0; config.output_rate_auto_requested = 0;
break; break;
default: default:
if (config.output_rate_auto_requested == 1) if (config.output_rate_auto_requested == 1)
warn("Invalid output rate \"%d\". It should be \"auto\", 44100, 88200, 176400 or 352800. " warn("Invalid output rate \"%d\". It should be \"auto\", 44100, 88200, 176400 or 352800. "
"It remains set to \"auto\".",value); "It remains set to \"auto\".",
else value);
warn("Invalid output rate \"%d\".It should be \"auto\", 44100, 88200, 176400 or 352800. " else
"It remains set to %d.", value, config.output_rate); warn("Invalid output rate \"%d\".It should be \"auto\", 44100, 88200, 176400 or 352800. "
} "It remains set to %d.",
} value, config.output_rate);
}
}
/* Get the use_mmap_if_available setting. */ /* Get the use_mmap_if_available setting. */
if (config_lookup_string(config.cfg, "alsa.use_mmap_if_available", &str)) { if (config_lookup_string(config.cfg, "alsa.use_mmap_if_available", &str)) {
@@ -1232,12 +1233,13 @@ static int init(int argc, char **argv) {
} }
} }
/* Get the optional disable_standby_mode setting. */ /* Get the optional disable_standby_mode setting. */
if (config_lookup_string(config.cfg, "alsa.disable_standby_mode", &str)) { if (config_lookup_string(config.cfg, "alsa.disable_standby_mode", &str)) {
if ((strcasecmp(str, "no") == 0) || (strcasecmp(str, "off") == 0) || (strcasecmp(str, "never") == 0)) if ((strcasecmp(str, "no") == 0) || (strcasecmp(str, "off") == 0) ||
(strcasecmp(str, "never") == 0))
config.disable_standby_mode = disable_standby_off; config.disable_standby_mode = disable_standby_off;
else if ((strcasecmp(str, "yes") == 0) || (strcasecmp(str, "on") == 0) || (strcasecmp(str, "always") == 0)) { else if ((strcasecmp(str, "yes") == 0) || (strcasecmp(str, "on") == 0) ||
(strcasecmp(str, "always") == 0)) {
config.disable_standby_mode = disable_standby_always; config.disable_standby_mode = disable_standby_always;
config.keep_dac_busy = 1; config.keep_dac_busy = 1;
} else if (strcasecmp(str, "auto") == 0) } else if (strcasecmp(str, "auto") == 0)
@@ -1245,15 +1247,17 @@ static int init(int argc, char **argv) {
else { else {
warn("Invalid disable_standby_mode option choice \"%s\". It should be " warn("Invalid disable_standby_mode option choice \"%s\". It should be "
"\"always\", \"auto\" or \"never\". " "\"always\", \"auto\" or \"never\". "
"It remains set to \"never\".", str); "It remains set to \"never\".",
str);
} }
} }
if (config_lookup_string(config.cfg, "alsa.use_precision_timing", &str)) { if (config_lookup_string(config.cfg, "alsa.use_precision_timing", &str)) {
if ((strcasecmp(str, "no") == 0) || (strcasecmp(str, "off") == 0) || (strcasecmp(str, "never") == 0)) if ((strcasecmp(str, "no") == 0) || (strcasecmp(str, "off") == 0) ||
(strcasecmp(str, "never") == 0))
config.use_precision_timing = YNA_NO; config.use_precision_timing = YNA_NO;
else if ((strcasecmp(str, "yes") == 0) || (strcasecmp(str, "on") == 0) || (strcasecmp(str, "always") == 0)) { else if ((strcasecmp(str, "yes") == 0) || (strcasecmp(str, "on") == 0) ||
(strcasecmp(str, "always") == 0)) {
config.use_precision_timing = YNA_YES; config.use_precision_timing = YNA_YES;
config.keep_dac_busy = 1; config.keep_dac_busy = 1;
} else if (strcasecmp(str, "auto") == 0) } else if (strcasecmp(str, "auto") == 0)
@@ -1261,11 +1265,17 @@ static int init(int argc, char **argv) {
else { else {
warn("Invalid use_precision_timing option choice \"%s\". It should be " warn("Invalid use_precision_timing option choice \"%s\". It should be "
"\"yes\", \"auto\" or \"no\". " "\"yes\", \"auto\" or \"no\". "
"It remains set to \"%s\".", config.use_precision_timing == YNA_NO ? "no" : config.use_precision_timing == YNA_AUTO ? "auto" : "yes"); "It remains set to \"%s\".",
config.use_precision_timing == YNA_NO ? "no" : config.use_precision_timing == YNA_AUTO
? "auto"
: "yes");
} }
} }
debug(1, "alsa: disable_standby_mode is \"%s\".", config.disable_standby_mode == disable_standby_off ? "never" : config.disable_standby_mode == disable_standby_always ? "always" : "auto"); debug(1, "alsa: disable_standby_mode is \"%s\".",
config.disable_standby_mode == disable_standby_off
? "never"
: config.disable_standby_mode == disable_standby_always ? "always" : "auto");
} }
optind = 1; // optind=0 is equivalent to optind=1 plus special behaviour optind = 1; // optind=0 is equivalent to optind=1 plus special behaviour
@@ -1362,12 +1372,13 @@ int set_mute_state() {
close_mixer(); close_mixer();
} }
debug_mutex_unlock(&alsa_mixer_mutex, 3); // release the mutex debug_mutex_unlock(&alsa_mixer_mutex, 3); // release the mutex
pthread_cleanup_pop(0); // release the mutex pthread_cleanup_pop(0); // release the mutex
pthread_setcancelstate(oldState, NULL); pthread_setcancelstate(oldState, NULL);
return response; return response;
} }
static void start(__attribute__((unused)) int i_sample_rate, __attribute__((unused)) int i_sample_format) { static void start(__attribute__((unused)) int i_sample_rate,
__attribute__((unused)) int i_sample_format) {
debug(3, "audio_alsa start called."); debug(3, "audio_alsa start called.");
frame_index = 0; frame_index = 0;
@@ -1381,16 +1392,17 @@ static void start(__attribute__((unused)) int i_sample_rate, __attribute__((unus
} }
} }
int standard_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay, enum yndk_type *using_update_timestamps) { int standard_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay,
enum yndk_type *using_update_timestamps) {
int ret = 0; int ret = 0;
if (using_update_timestamps) if (using_update_timestamps)
*using_update_timestamps = YNDK_NO; *using_update_timestamps = YNDK_NO;
*state = snd_pcm_state(alsa_handle); *state = snd_pcm_state(alsa_handle);
if ((*state == SND_PCM_STATE_RUNNING) || (*state == SND_PCM_STATE_DRAINING)) { if ((*state == SND_PCM_STATE_RUNNING) || (*state == SND_PCM_STATE_DRAINING)) {
ret = snd_pcm_delay(alsa_handle,delay); ret = snd_pcm_delay(alsa_handle, delay);
} else { } else {
// not running, thus no delay information, thus can't check for frame // not running, thus no delay information, thus can't check for frame
// rates // rates
frame_index = 0; // we'll be starting over... frame_index = 0; // we'll be starting over...
measurement_data_is_valid = 0; measurement_data_is_valid = 0;
*delay = 0; *delay = 0;
@@ -1402,7 +1414,8 @@ int standard_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay,
return ret; return ret;
} }
int precision_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay, enum yndk_type *using_update_timestamps) { int precision_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay,
enum yndk_type *using_update_timestamps) {
snd_pcm_status_t *alsa_snd_pcm_status; snd_pcm_status_t *alsa_snd_pcm_status;
snd_pcm_status_alloca(&alsa_snd_pcm_status); snd_pcm_status_alloca(&alsa_snd_pcm_status);
@@ -1415,11 +1428,11 @@ int precision_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay,
int ret = snd_pcm_status(alsa_handle, alsa_snd_pcm_status); int ret = snd_pcm_status(alsa_handle, alsa_snd_pcm_status);
if (ret == 0) { if (ret == 0) {
// must be 1.1 or later to use snd_pcm_status_get_driver_htstamp // must be 1.1 or later to use snd_pcm_status_get_driver_htstamp
#if SND_LIB_MINOR == 0 #if SND_LIB_MINOR == 0
snd_pcm_status_get_htstamp(alsa_snd_pcm_status, &update_timestamp); snd_pcm_status_get_htstamp(alsa_snd_pcm_status, &update_timestamp);
#else #else
snd_pcm_status_get_driver_htstamp(alsa_snd_pcm_status, &update_timestamp); snd_pcm_status_get_driver_htstamp(alsa_snd_pcm_status, &update_timestamp);
#endif #endif
*state = snd_pcm_status_get_state(alsa_snd_pcm_status); *state = snd_pcm_status_get_state(alsa_snd_pcm_status);
@@ -1440,34 +1453,34 @@ int precision_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay,
*using_update_timestamps = YNDK_YES; *using_update_timestamps = YNDK_YES;
} }
// user information // user information
if (update_timestamp_ns == 0) { if (update_timestamp_ns == 0) {
if (delay_type_notified != 1) { if (delay_type_notified != 1) {
debug(2,"alsa: update timestamps unavailable"); debug(2, "alsa: update timestamps unavailable");
delay_type_notified = 1; delay_type_notified = 1;
} }
} else { } else {
// diagnostic // diagnostic
if (delay_type_notified != 0) { if (delay_type_notified != 0) {
debug(2,"alsa: update timestamps available"); debug(2, "alsa: update timestamps available");
delay_type_notified = 0; delay_type_notified = 0;
} }
} }
if (update_timestamp_ns == 0) { if (update_timestamp_ns == 0) {
ret = snd_pcm_delay (alsa_handle,delay); ret = snd_pcm_delay(alsa_handle, delay);
} else { } else {
*delay = snd_pcm_status_get_delay(alsa_snd_pcm_status); *delay = snd_pcm_status_get_delay(alsa_snd_pcm_status);
/* /*
// It seems that the alsa library uses CLOCK_REALTIME before 1.0.28, even though // It seems that the alsa library uses CLOCK_REALTIME before 1.0.28, even though
// the check for monotonic returns true. Might have to watch out for this. // the check for monotonic returns true. Might have to watch out for this.
#if SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR < 28 #if SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR < 28
clock_gettime(CLOCK_REALTIME, &tn); clock_gettime(CLOCK_REALTIME, &tn);
#else #else
clock_gettime(CLOCK_MONOTONIC, &tn); clock_gettime(CLOCK_MONOTONIC, &tn);
#endif #endif
*/ */
if (use_monotonic_clock) if (use_monotonic_clock)
clock_gettime(CLOCK_MONOTONIC, &tn); clock_gettime(CLOCK_MONOTONIC, &tn);
@@ -1491,8 +1504,8 @@ int precision_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay,
debug(2, "DAC seems to have stalled with time_now: %lx,%lx" debug(2, "DAC seems to have stalled with time_now: %lx,%lx"
", update_timestamp: %lx,%lx, stall_monitor_start_time %" PRIX64 ", update_timestamp: %lx,%lx, stall_monitor_start_time %" PRIX64
", stall_monitor_error_threshold %" PRIX64 ".", ", stall_monitor_error_threshold %" PRIX64 ".",
tn.tv_sec, tn.tv_nsec, update_timestamp.tv_sec, update_timestamp.tv_nsec, stall_monitor_start_time, tn.tv_sec, tn.tv_nsec, update_timestamp.tv_sec, update_timestamp.tv_nsec,
stall_monitor_error_threshold); stall_monitor_start_time, stall_monitor_error_threshold);
ret = sps_extra_code_output_stalled; ret = sps_extra_code_output_stalled;
} }
} else { } else {
@@ -1649,9 +1662,9 @@ int do_play(void *buf, int samples) {
} else { } else {
char errorstring[1024]; char errorstring[1024];
strerror_r(-ret, (char *)errorstring, sizeof(errorstring)); strerror_r(-ret, (char *)errorstring, sizeof(errorstring));
debug(1, "alsa: error %d (\"%s\") writing %d samples to alsa device.", ret, (char *)errorstring, samples); debug(1, "alsa: error %d (\"%s\") writing %d samples to alsa device.", ret,
(char *)errorstring, samples);
} }
} }
} }
} else { } else {
@@ -1741,9 +1754,9 @@ int play(void *buf, int samples) {
alsa_backend_state = abm_playing; alsa_backend_state = abm_playing;
// mute_requested_internally = 0; // stop requesting a mute for backend's own // mute_requested_internally = 0; // stop requesting a mute for backend's own
// reasons, which might have been a flush // reasons, which might have been a flush
//debug(2, "play() set_mute_state"); // debug(2, "play() set_mute_state");
//set_mute_state(); // try to action the request and return a status // set_mute_state(); // try to action the request and return a status
// do_mute(0); // unmute for backend's reason // do_mute(0); // unmute for backend's reason
} }
ret = do_play(buf, samples); ret = do_play(buf, samples);
@@ -1755,7 +1768,7 @@ int play(void *buf, int samples) {
} }
int prepare(void) { int prepare(void) {
// this will leave the DAC open / connected. // this will leave the DAC open / connected.
int ret = 0; int ret = 0;
pthread_cleanup_debug_mutex_lock(&alsa_mutex, 50000, 0); pthread_cleanup_debug_mutex_lock(&alsa_mutex, 50000, 0);
@@ -1764,7 +1777,6 @@ int prepare(void) {
ret = do_open(1); // do auto setup ret = do_open(1); // do auto setup
if (ret == 0) if (ret == 0)
debug(2, "alsa: prepare() -- opened output device"); debug(2, "alsa: prepare() -- opened output device");
} }
debug_mutex_unlock(&alsa_mutex, 0); debug_mutex_unlock(&alsa_mutex, 0);
@@ -1888,9 +1900,10 @@ void *alsa_buffer_monitor_thread_code(__attribute__((unused)) void *arg) {
int error_count = 0; int error_count = 0;
int error_threshold_exceeded = 0; int error_threshold_exceeded = 0;
int okb = -1; int okb = -1;
while (error_threshold_exceeded == 0) { // if too many play errors occur early on, we will turn off the disable stanby mode while (error_threshold_exceeded ==
0) { // if too many play errors occur early on, we will turn off the disable stanby mode
if (okb != config.keep_dac_busy) { if (okb != config.keep_dac_busy) {
debug(2,"keep_dac_busy is now \"%s\"",config.keep_dac_busy == 0 ? "no" : "yes"); debug(2, "keep_dac_busy is now \"%s\"", config.keep_dac_busy == 0 ? "no" : "yes");
okb = config.keep_dac_busy; okb = config.keep_dac_busy;
} }
if ((config.keep_dac_busy != 0) && (alsa_device_initialised == 0)) { if ((config.keep_dac_busy != 0) && (alsa_device_initialised == 0)) {
@@ -1921,7 +1934,8 @@ void *alsa_buffer_monitor_thread_code(__attribute__((unused)) void *arg) {
// to be in the // to be in the
// abm_connected state in the first place...) then do the silence-filling // abm_connected state in the first place...) then do the silence-filling
// thing, if needed /* only if the output device is capable of precision delay */. // thing, if needed /* only if the output device is capable of precision delay */.
if ((alsa_backend_state != abm_disconnected) && (config.keep_dac_busy != 0) /* && precision_delay_available() */ ) { if ((alsa_backend_state != abm_disconnected) &&
(config.keep_dac_busy != 0) /* && precision_delay_available() */) {
int reply; int reply;
long buffer_size = 0; long buffer_size = 0;
snd_pcm_state_t state; snd_pcm_state_t state;
@@ -1976,9 +1990,13 @@ void *alsa_buffer_monitor_thread_code(__attribute__((unused)) void *arg) {
error_count++; error_count++;
char errorstring[1024]; char errorstring[1024];
strerror_r(-ret, (char *)errorstring, sizeof(errorstring)); strerror_r(-ret, (char *)errorstring, sizeof(errorstring));
debug(2, "alsa: alsa_buffer_monitor_thread_code error %d (\"%s\") writing %d samples to alsa device -- %d errors in %d trials.", ret, (char *)errorstring, frames_of_silence, error_count, frame_count); debug(2, "alsa: alsa_buffer_monitor_thread_code error %d (\"%s\") writing %d samples "
"to alsa device -- %d errors in %d trials.",
ret, (char *)errorstring, frames_of_silence, error_count, frame_count);
if ((error_count > 40) && (frame_count < 100)) { if ((error_count > 40) && (frame_count < 100)) {
warn("disable_standby_mode has been turned off because too many underruns occurred. Is Shairport Sync outputting to a virtual device or running in a virtual machine?"); warn("disable_standby_mode has been turned off because too many underruns "
"occurred. Is Shairport Sync outputting to a virtual device or running in a "
"virtual machine?");
error_threshold_exceeded = 1; error_threshold_exceeded = 1;
} }
} }
-1
View File
@@ -54,7 +54,6 @@ static int play(__attribute__((unused)) void *buf, __attribute__((unused)) int s
static void stop(void) { debug(1, "dummy audio stopped\n"); } static void stop(void) { debug(1, "dummy audio stopped\n"); }
audio_output audio_dummy = {.name = "dummy", audio_output audio_dummy = {.name = "dummy",
.help = NULL, .help = NULL,
.init = &init, .init = &init,
+36 -39
View File
@@ -20,10 +20,10 @@
#include "audio.h" #include "audio.h"
#include "common.h" #include "common.h"
#include <stdlib.h>
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
#include <pthread.h> #include <pthread.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <jack/jack.h> #include <jack/jack.h>
@@ -64,7 +64,7 @@ audio_output audio_jack = {.name = "jack",
// So make it exactly the number of incoming audio channels! // So make it exactly the number of incoming audio channels!
#define NPORTS 2 #define NPORTS 2
static jack_port_t *port[NPORTS]; static jack_port_t *port[NPORTS];
static const char* port_name[NPORTS] = { "out_L", "out_R" }; static const char *port_name[NPORTS] = {"out_L", "out_R"};
static jack_client_t *client; static jack_client_t *client;
static jack_nframes_t sample_rate; static jack_nframes_t sample_rate;
@@ -76,7 +76,6 @@ static int flush_please = 0;
static jack_latency_range_t latest_latency_range[NPORTS]; static jack_latency_range_t latest_latency_range[NPORTS];
static int64_t time_of_latest_transfer; static int64_t time_of_latest_transfer;
static inline jack_default_audio_sample_t sample_conv(short sample) { static inline jack_default_audio_sample_t sample_conv(short sample) {
// It sounds correct, but I don't understand it. // It sounds correct, but I don't understand it.
// Zero int needs to be zero float. Check. // Zero int needs to be zero float. Check.
@@ -88,9 +87,8 @@ static inline jack_default_audio_sample_t sample_conv(short sample) {
} }
static void deinterleave_and_convert(const char *interleaved_input_buffer, static void deinterleave_and_convert(const char *interleaved_input_buffer,
jack_default_audio_sample_t* jack_output_buffer[], jack_default_audio_sample_t *jack_output_buffer[],
jack_nframes_t offset, jack_nframes_t offset, jack_nframes_t nframes) {
jack_nframes_t nframes) {
jack_nframes_t f; jack_nframes_t f;
// We're dealing with 16bit audio here: // We're dealing with 16bit audio here:
short *ifp = (short *)interleaved_input_buffer; short *ifp = (short *)interleaved_input_buffer;
@@ -111,7 +109,7 @@ static void deinterleave_and_convert(const char *interleaved_input_buffer,
static int process(jack_nframes_t nframes, __attribute__((unused)) void *arg) { static int process(jack_nframes_t nframes, __attribute__((unused)) void *arg) {
jack_default_audio_sample_t *buffer[NPORTS]; jack_default_audio_sample_t *buffer[NPORTS];
// Expect an array of two elements because of possible ringbuffer wrap-around: // Expect an array of two elements because of possible ringbuffer wrap-around:
jack_ringbuffer_data_t v[2] = { 0 }; jack_ringbuffer_data_t v[2] = {0};
jack_nframes_t i, thisbuf; jack_nframes_t i, thisbuf;
int frames_written = 0; int frames_written = 0;
int frames_required = 0; int frames_required = 0;
@@ -130,7 +128,7 @@ static int process(jack_nframes_t nframes, __attribute__((unused)) void *arg) {
thisbuf = v[i].len / bytes_per_frame; thisbuf = v[i].len / bytes_per_frame;
if (thisbuf > nframes) { if (thisbuf > nframes) {
frames_required = nframes; frames_required = nframes;
} else { } else {
frames_required = thisbuf; frames_required = thisbuf;
} }
deinterleave_and_convert(v[i].buf, buffer, frames_written, frames_required); deinterleave_and_convert(v[i].buf, buffer, frames_written, frames_required);
@@ -154,13 +152,13 @@ static int process(jack_nframes_t nframes, __attribute__((unused)) void *arg) {
// This is the JACK graph reorder callback. Now we know some JACK connections // This is the JACK graph reorder callback. Now we know some JACK connections
// have changed, so we recompute the latency. // have changed, so we recompute the latency.
static int graph(__attribute__((unused)) void * arg) { static int graph(__attribute__((unused)) void *arg) {
int latency = 0; int latency = 0;
debug(2, "JACK graph reorder callback called."); debug(2, "JACK graph reorder callback called.");
for (int i=0; i<NPORTS; i++) { for (int i = 0; i < NPORTS; i++) {
jack_port_get_latency_range(port[i], JackPlaybackLatency, &latest_latency_range[i]); jack_port_get_latency_range(port[i], JackPlaybackLatency, &latest_latency_range[i]);
debug(2, "JACK latency for port %s\tmin: %d\t max: %d", debug(2, "JACK latency for port %s\tmin: %d\t max: %d", port_name[i],
port_name[i], latest_latency_range[i].min, latest_latency_range[i].max); latest_latency_range[i].min, latest_latency_range[i].max);
latency += latest_latency_range[i].max; latency += latest_latency_range[i].max;
} }
latency /= NPORTS; latency /= NPORTS;
@@ -170,14 +168,10 @@ static int graph(__attribute__((unused)) void * arg) {
} }
// This the function JACK will call in case of an error in the library. // This the function JACK will call in case of an error in the library.
static void error(const char *desc) { static void error(const char *desc) { warn("JACK error: \"%s\"", desc); }
warn("JACK error: \"%s\"", desc);
}
// This is the function JACK will call in case of a non-critical event in the library. // This is the function JACK will call in case of a non-critical event in the library.
static void info(const char *desc) { static void info(const char *desc) { inform("JACK information: \"%s\"", desc); }
inform("JACK information: \"%s\"", desc);
}
int jack_init(__attribute__((unused)) int argc, __attribute__((unused)) char **argv) { int jack_init(__attribute__((unused)) int argc, __attribute__((unused)) char **argv) {
int i; int i;
@@ -221,15 +215,16 @@ int jack_init(__attribute__((unused)) int argc, __attribute__((unused)) char **a
sample_rate = jack_get_sample_rate(client); sample_rate = jack_get_sample_rate(client);
if (sample_rate != 44100) { if (sample_rate != 44100) {
die("The JACK server is running at the wrong sample rate (%d) for Shairport Sync." die("The JACK server is running at the wrong sample rate (%d) for Shairport Sync."
" Must be 44100 Hz.", sample_rate); " Must be 44100 Hz.",
sample_rate);
} }
jack_set_process_callback(client, &process, NULL); jack_set_process_callback(client, &process, NULL);
jack_set_graph_order_callback(client, &graph, NULL); jack_set_graph_order_callback(client, &graph, NULL);
jack_set_error_function(&error); jack_set_error_function(&error);
jack_set_info_function(&info); jack_set_info_function(&info);
for (i=0; i < NPORTS; i++) { for (i = 0; i < NPORTS; i++) {
port[i] = jack_port_register(client, port_name[i], JACK_DEFAULT_AUDIO_TYPE, port[i] =
JackPortIsOutput, 0); jack_port_register(client, port_name[i], JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
} }
if (jack_activate(client)) { if (jack_activate(client)) {
die("Could not activate %s JACK client.", config.jack_client_name); die("Could not activate %s JACK client.", config.jack_client_name);
@@ -238,14 +233,15 @@ int jack_init(__attribute__((unused)) int argc, __attribute__((unused)) char **a
} }
if (config.jack_autoconnect_pattern != NULL) { if (config.jack_autoconnect_pattern != NULL) {
inform("config.jack_autoconnect_pattern is %s. If you see the program die after this," inform("config.jack_autoconnect_pattern is %s. If you see the program die after this,"
"you made a syntax error.", config.jack_autoconnect_pattern); "you made a syntax error.",
config.jack_autoconnect_pattern);
// Sadly, this will throw a segfault if the user provides a syntactically incorrect regex. // Sadly, this will throw a segfault if the user provides a syntactically incorrect regex.
// I've reported it to the jack-devel mailing list, they're in a better place to fix it. // I've reported it to the jack-devel mailing list, they're in a better place to fix it.
const char** port_list = jack_get_ports(client, config.jack_autoconnect_pattern, const char **port_list = jack_get_ports(client, config.jack_autoconnect_pattern,
JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput); JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput);
if (port_list != NULL) { if (port_list != NULL) {
for (i = 0; i < NPORTS ; i++) { for (i = 0; i < NPORTS; i++) {
char* full_port_name[NPORTS]; char *full_port_name[NPORTS];
full_port_name[i] = malloc(sizeof(char) * jack_port_name_size()); full_port_name[i] = malloc(sizeof(char) * jack_port_name_size());
sprintf(full_port_name[i], "%s:%s", config.jack_client_name, port_name[i]); sprintf(full_port_name[i], "%s:%s", config.jack_client_name, port_name[i]);
if (port_list[i] != NULL) { if (port_list[i] != NULL) {
@@ -254,15 +250,15 @@ int jack_init(__attribute__((unused)) int argc, __attribute__((unused)) char **a
err = jack_connect(client, full_port_name[i], port_list[i]); err = jack_connect(client, full_port_name[i], port_list[i]);
switch (err) { switch (err) {
case EEXIST: case EEXIST:
inform("The requested connection from %s to %s already exists.", inform("The requested connection from %s to %s already exists.", full_port_name[i],
full_port_name[i], port_list[i]); port_list[i]);
break; break;
case 0: case 0:
// success // success
break; break;
default: default:
warn("JACK error no. %d occured while trying to connect %s to %s.", warn("JACK error no. %d occured while trying to connect %s to %s.", err,
err, full_port_name[i], port_list[i]); full_port_name[i], port_list[i]);
break; break;
} }
} else { } else {
@@ -272,7 +268,8 @@ int jack_init(__attribute__((unused)) int argc, __attribute__((unused)) char **a
free(full_port_name[i]); free(full_port_name[i]);
} }
while (port_list[i++] != NULL) { while (port_list[i++] != NULL) {
inform("Additional matching port %s found. Check that the connections are what you intended."); inform(
"Additional matching port %s found. Check that the connections are what you intended.");
} }
jack_free(port_list); jack_free(port_list);
} }
@@ -316,10 +313,10 @@ int jack_delay(long *the_delay) {
// occupancy after another transfer had occurred, so we could "lose" a full transfer // occupancy after another transfer had occurred, so we could "lose" a full transfer
// (e.g. 1024 frames @ 44,100 fps ~ 23.2 milliseconds) // (e.g. 1024 frames @ 44,100 fps ~ 23.2 milliseconds)
pthread_mutex_lock(&buffer_mutex); pthread_mutex_lock(&buffer_mutex);
int64_t time_now = get_absolute_time_in_fp(); int64_t time_now = get_absolute_time_in_fp();
int64_t delta = time_now - time_of_latest_transfer; int64_t delta = time_now - time_of_latest_transfer;
size_t audio_occupancy_now = jack_ringbuffer_read_space(jackbuf) / bytes_per_frame; size_t audio_occupancy_now = jack_ringbuffer_read_space(jackbuf) / bytes_per_frame;
debug(2, "audio_occupancy_now is %d.", audio_occupancy_now); debug(2, "audio_occupancy_now is %d.", audio_occupancy_now);
pthread_mutex_unlock(&buffer_mutex); pthread_mutex_unlock(&buffer_mutex);
int64_t frames_processed_since_latest_latency_check = (delta * 44100) >> 32; int64_t frames_processed_since_latest_latency_check = (delta * 44100) >> 32;
@@ -339,12 +336,12 @@ int play(void *buf, int samples) {
bytes_to_transfer = samples * bytes_per_frame; bytes_to_transfer = samples * bytes_per_frame;
// It's ok to lock here since we're not in the realtime callback: // It's ok to lock here since we're not in the realtime callback:
pthread_mutex_lock(&buffer_mutex); pthread_mutex_lock(&buffer_mutex);
bytes_transferred = jack_ringbuffer_write(jackbuf, buf, bytes_to_transfer); bytes_transferred = jack_ringbuffer_write(jackbuf, buf, bytes_to_transfer);
time_of_latest_transfer = get_absolute_time_in_fp(); time_of_latest_transfer = get_absolute_time_in_fp();
pthread_mutex_unlock(&buffer_mutex); pthread_mutex_unlock(&buffer_mutex);
if (bytes_transferred < bytes_to_transfer) { if (bytes_transferred < bytes_to_transfer) {
warn("JACK ringbuffer overrun. Only wrote %d of %d bytes.", warn("JACK ringbuffer overrun. Only wrote %d of %d bytes.", bytes_transferred,
bytes_transferred, bytes_to_transfer); bytes_to_transfer);
} }
return 0; return 0;
} }
+4 -3
View File
@@ -47,15 +47,16 @@ int warned = 0;
static void start(__attribute__((unused)) int sample_rate, static void start(__attribute__((unused)) int sample_rate,
__attribute__((unused)) int sample_format) { __attribute__((unused)) int sample_format) {
// this will leave fd as -1 if a reader hasn't been attached to the pipe // this will leave fd as -1 if a reader hasn't been attached to the pipe
// we check that it's not a "real" error though. From the "man 2 open" page: // we check that it's not a "real" error though. From the "man 2 open" page:
// "ENXIO O_NONBLOCK | O_WRONLY is set, the named file is a FIFO, and no process has the FIFO open for reading." // "ENXIO O_NONBLOCK | O_WRONLY is set, the named file is a FIFO, and no process has the FIFO
// open for reading."
fd = open(pipename, O_WRONLY | O_NONBLOCK); fd = open(pipename, O_WRONLY | O_NONBLOCK);
if ((fd == -1) && (errno != ENXIO) && (warned == 0)) { if ((fd == -1) && (errno != ENXIO) && (warned == 0)) {
char errorstring[1024]; char errorstring[1024];
strerror_r(errno, (char *)errorstring, sizeof(errorstring)); strerror_r(errno, (char *)errorstring, sizeof(errorstring));
debug(1, "pipe: start -- error %d (\"%s\") opening the pipe named \"%s\".", errno, (char*)errorstring, pipename); debug(1, "pipe: start -- error %d (\"%s\") opening the pipe named \"%s\".", errno,
(char *)errorstring, pipename);
warn("Error %d opening the pipe named \"%s\".", errno, pipename); warn("Error %d opening the pipe named \"%s\".", errno, pipename);
warned = 1; warned = 1;
} }
+2 -3
View File
@@ -76,7 +76,8 @@ struct sndio_formats {
static struct sndio_formats formats[] = {{"S8", SPS_FORMAT_S8, 44100, 8, 1, 1, SIO_LE_NATIVE}, static struct sndio_formats formats[] = {{"S8", SPS_FORMAT_S8, 44100, 8, 1, 1, SIO_LE_NATIVE},
{"U8", SPS_FORMAT_U8, 44100, 8, 1, 0, SIO_LE_NATIVE}, {"U8", SPS_FORMAT_U8, 44100, 8, 1, 0, SIO_LE_NATIVE},
{"S16", SPS_FORMAT_S16, 44100, 16, 2, 1, SIO_LE_NATIVE}, {"S16", SPS_FORMAT_S16, 44100, 16, 2, 1, SIO_LE_NATIVE},
{"AUTOMATIC", SPS_FORMAT_S16, 44100, 16, 2, 1, SIO_LE_NATIVE}, // TODO: make this really automatic? {"AUTOMATIC", SPS_FORMAT_S16, 44100, 16, 2, 1,
SIO_LE_NATIVE}, // TODO: make this really automatic?
{"S24", SPS_FORMAT_S24, 44100, 24, 4, 1, SIO_LE_NATIVE}, {"S24", SPS_FORMAT_S24, 44100, 24, 4, 1, SIO_LE_NATIVE},
{"S24_3LE", SPS_FORMAT_S24_3LE, 44100, 24, 3, 1, 1}, {"S24_3LE", SPS_FORMAT_S24_3LE, 44100, 24, 3, 1, 1},
{"S24_3BE", SPS_FORMAT_S24_3BE, 44100, 24, 3, 1, 0}, {"S24_3BE", SPS_FORMAT_S24_3BE, 44100, 24, 3, 1, 0},
@@ -177,7 +178,6 @@ static int init(int argc, char **argv) {
time_of_last_onmove_cb = 0; time_of_last_onmove_cb = 0;
at_least_one_onmove_cb_seen = 0; at_least_one_onmove_cb_seen = 0;
for (i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) { for (i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) {
if (formats[i].fmt == config.output_format) { if (formats[i].fmt == config.output_format) {
par.bits = formats[i].bits; par.bits = formats[i].bits;
@@ -201,7 +201,6 @@ static int init(int argc, char **argv) {
if (!found) if (!found)
die("sndio: could not set output device to the required format and rate."); die("sndio: could not set output device to the required format and rate.");
framesize = par.bps * par.pchan; framesize = par.bps * par.pchan;
config.output_rate = par.rate; config.output_rate = par.rate;
config.audio_backend_buffer_desired_length = 1.0 * par.bufsz / par.rate; config.audio_backend_buffer_desired_length = 1.0 * par.bufsz / par.rate;
+2 -3
View File
@@ -27,9 +27,8 @@ static void write_callback(struct SoundIoOutStream *outstream, int frame_count_m
int fill_bytes = soundio_ring_buffer_fill_count(ring_buffer); int fill_bytes = soundio_ring_buffer_fill_count(ring_buffer);
int fill_count = fill_bytes / outstream->bytes_per_frame; int fill_count = fill_bytes / outstream->bytes_per_frame;
debug(3, debug(3, "[--->>] frame_count_min: %d , frame_count_max: %d , fill_bytes: %d , fill_count: %d , "
"[--->>] frame_count_min: %d , frame_count_max: %d , fill_bytes: %d , fill_count: %d , " "outstream->bytes_per_frame: %d",
"outstream->bytes_per_frame: %d",
frame_count_min, frame_count_max, fill_bytes, fill_count, outstream->bytes_per_frame); frame_count_min, frame_count_max, fill_bytes, fill_count, outstream->bytes_per_frame);
if (frame_count_min > fill_count) { if (frame_count_min > fill_count) {
+25 -26
View File
@@ -87,9 +87,11 @@
void set_alsa_out_dev(char *); void set_alsa_out_dev(char *);
#endif #endif
const char * sps_format_description_string_array[] = {"unknown", "S8", "U8" ,"S16", "S16_LE", "S16_BE", "S24", "S24_LE", "S24_BE", "S24_3LE", "S24_3BE", "S32", "S32_LE", "S32_BE", "auto", "invalid" }; const char *sps_format_description_string_array[] = {
"unknown", "S8", "U8", "S16", "S16_LE", "S16_BE", "S24", "S24_LE",
"S24_BE", "S24_3LE", "S24_3BE", "S32", "S32_LE", "S32_BE", "auto", "invalid"};
const char * sps_format_description_string(enum sps_format_t format) { const char *sps_format_description_string(enum sps_format_t format) {
if ((format >= SPS_FORMAT_UNKNOWN) && (format <= SPS_FORMAT_AUTO)) if ((format >= SPS_FORMAT_UNKNOWN) && (format <= SPS_FORMAT_AUTO))
return sps_format_description_string_array[format]; return sps_format_description_string_array[format];
else else
@@ -115,12 +117,10 @@ void do_sps_log(__attribute__((unused)) int prio, const char *t, ...) {
va_start(args, t); va_start(args, t);
vsnprintf(s, sizeof(s), t, args); vsnprintf(s, sizeof(s), t, args);
va_end(args); va_end(args);
fprintf(stderr,"%s\n",s); fprintf(stderr, "%s\n", s);
} }
void log_to_stderr() { void log_to_stderr() { sps_log = do_sps_log; }
sps_log = do_sps_log;
}
shairport_cfg config; shairport_cfg config;
@@ -436,7 +436,7 @@ char *base64_enc(uint8_t *input, int length) {
b64 = BIO_push(b64, bmem); b64 = BIO_push(b64, bmem);
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
BIO_write(b64, input, length); BIO_write(b64, input, length);
(void) BIO_flush(b64); (void)BIO_flush(b64);
BIO_get_mem_ptr(b64, &bptr); BIO_get_mem_ptr(b64, &bptr);
char *buf = (char *)malloc(bptr->length); char *buf = (char *)malloc(bptr->length);
@@ -468,7 +468,7 @@ uint8_t *base64_dec(char *input, int *outlen) {
BIO_write(bmem, input, inlen); BIO_write(bmem, input, inlen);
while (inlen++ & 3) while (inlen++ & 3)
BIO_write(bmem, "=", 1); BIO_write(bmem, "=", 1);
(void) BIO_flush(bmem); (void)BIO_flush(bmem);
int bufsize = strlen(input) * 3 / 4 + 1; int bufsize = strlen(input) * 3 / 4 + 1;
uint8_t *buf = malloc(bufsize); uint8_t *buf = malloc(bufsize);
@@ -862,17 +862,17 @@ double flat_vol2attn(double vol, long max_db, long min_db) {
double vol2attn(double vol, long max_db, long min_db) { double vol2attn(double vol, long max_db, long min_db) {
// We use a little coordinate geometry to build a transfer function from the volume passed in to // We use a little coordinate geometry to build a transfer function from the volume passed in to
// the device's dynamic range. (See the diagram in the documents folder.) The x axis is the // the device's dynamic range. (See the diagram in the documents folder.) The x axis is the
// "volume in" which will be from -30 to 0. The y axis will be the "volume out" which will be from // "volume in" which will be from -30 to 0. The y axis will be the "volume out" which will be from
// the bottom of the range to the top. We build the transfer function from one or more lines. We // the bottom of the range to the top. We build the transfer function from one or more lines. We
// characterise each line with two numbers: the first is where on x the line starts when y=0 (x // characterise each line with two numbers: the first is where on x the line starts when y=0 (x
// can be from 0 to -30); the second is where on y the line stops when when x is -30. thus, if the // can be from 0 to -30); the second is where on y the line stops when when x is -30. thus, if the
// line was characterised as {0,-30}, it would be an identity transfer. Assuming, for example, a // line was characterised as {0,-30}, it would be an identity transfer. Assuming, for example, a
// dynamic range of lv=-60 to hv=0 Typically we'll use three lines -- a three order transfer // dynamic range of lv=-60 to hv=0 Typically we'll use three lines -- a three order transfer
// function First: {0,30} giving a gentle slope -- the 30 comes from half the dynamic range // function First: {0,30} giving a gentle slope -- the 30 comes from half the dynamic range
// Second: {-5,-30-(lv+30)/2} giving a faster slope from y=0 at x=-12 to y=-42.5 at x=-30 // Second: {-5,-30-(lv+30)/2} giving a faster slope from y=0 at x=-12 to y=-42.5 at x=-30
// Third: {-17,lv} giving a fast slope from y=0 at x=-19 to y=-60 at x=-30 // Third: {-17,lv} giving a fast slope from y=0 at x=-19 to y=-60 at x=-30
#define order 3 #define order 3
@@ -1000,7 +1000,7 @@ ssize_t non_blocking_write_with_timeout(int fd, const void *buf, size_t count, i
} }
ssize_t non_blocking_write(int fd, const void *buf, size_t count) { ssize_t non_blocking_write(int fd, const void *buf, size_t count) {
return non_blocking_write_with_timeout(fd,buf,count,5000); // default is 5 seconds. return non_blocking_write_with_timeout(fd, buf, count, 5000); // default is 5 seconds.
} }
/* from /* from
@@ -1189,9 +1189,8 @@ int sps_pthread_mutex_timedlock(pthread_mutex_t *mutex, useconds_t dally_time,
et = (et * 1000000) >> 32; // microseconds et = (et * 1000000) >> 32; // microseconds
char errstr[1000]; char errstr[1000];
if (r == ETIMEDOUT) if (r == ETIMEDOUT)
debug(debuglevel, debug(debuglevel, "timed out waiting for a mutex, having waiting %f seconds, with a maximum "
"timed out waiting for a mutex, having waiting %f seconds, with a maximum " "waiting time of %d microseconds. \"%s\".",
"waiting time of %d microseconds. \"%s\".",
(1.0 * et) / 1000000, dally_time, debugmessage); (1.0 * et) / 1000000, dally_time, debugmessage);
else else
debug(debuglevel, "error %d: \"%s\" waiting for a mutex: \"%s\".", r, debug(debuglevel, "error %d: \"%s\" waiting for a mutex: \"%s\".", r,
@@ -1293,10 +1292,10 @@ char *get_version_string() {
strcpy(version_string, PACKAGE_VERSION); strcpy(version_string, PACKAGE_VERSION);
#ifdef CONFIG_LIBDAEMON #ifdef CONFIG_LIBDAEMON
strcat(version_string, "-libdaemon"); strcat(version_string, "-libdaemon");
#endif #endif
#ifdef CONFIG_MBEDTLS #ifdef CONFIG_MBEDTLS
strcat(version_string, "-mbedTLS"); strcat(version_string, "-mbedTLS");
#endif #endif
#ifdef CONFIG_POLARSSL #ifdef CONFIG_POLARSSL
strcat(version_string, "-PolarSSL"); strcat(version_string, "-PolarSSL");
@@ -1549,7 +1548,7 @@ int64_t generate_zero_frames(char *outp, size_t number_of_frames, enum sps_forma
break; break;
default: default:
result = 0; // stop a compiler warning result = 0; // stop a compiler warning
die("Unexpected SPS_FORMAT_* with index %d while outputting silence",format); die("Unexpected SPS_FORMAT_* with index %d while outputting silence", format);
} }
p += result; p += result;
previous_random_number = r; previous_random_number = r;
+17 -21
View File
@@ -34,18 +34,10 @@ enum dbus_session_type {
#define sps_extra_code_output_state_cannot_make_ready 32769 #define sps_extra_code_output_state_cannot_make_ready 32769
// yeah/no/auto // yeah/no/auto
enum yna_type { enum yna_type { YNA_AUTO = -1, YNA_NO = 0, YNA_YES = 1 } yna_type;
YNA_AUTO = -1,
YNA_NO = 0,
YNA_YES = 1
} yna_type;
// yeah/no/dont-care // yeah/no/dont-care
enum yndk_type { enum yndk_type { YNDK_DONT_KNOW = -1, YNDK_NO = 0, YNDK_YES = 1 } yndk_type;
YNDK_DONT_KNOW = -1,
YNDK_NO = 0,
YNDK_YES = 1
} yndk_type;
enum endian_type { enum endian_type {
SS_LITTLE_ENDIAN = 0, SS_LITTLE_ENDIAN = 0,
@@ -56,7 +48,7 @@ enum endian_type {
enum stuffing_type { enum stuffing_type {
ST_basic = 0, // straight deletion or insertion of a frame in a 352-frame packet 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 ST_soxr, // use libsoxr to make a 352 frame packet one frame longer or shorter
ST_auto, // use soxr if compiled for it and if the soxr_index is low enough ST_auto, // use soxr if compiled for it and if the soxr_index is low enough
} s_type; } s_type;
enum playback_mode_type { enum playback_mode_type {
@@ -105,7 +97,7 @@ enum sps_format_t {
SPS_FORMAT_INVALID, SPS_FORMAT_INVALID,
} sps_format_t; } sps_format_t;
const char * sps_format_description_string(enum sps_format_t format); const char *sps_format_description_string(enum sps_format_t format);
typedef struct { typedef struct {
config_t *cfg; config_t *cfg;
@@ -172,7 +164,7 @@ typedef struct {
uint32_t userSuppliedLatency; // overrides all other latencies -- use with caution uint32_t userSuppliedLatency; // overrides all other latencies -- use with caution
uint32_t fixedLatencyOffset; // add this to all automatic latencies supplied to get the actual uint32_t fixedLatencyOffset; // add this to all automatic latencies supplied to get the actual
// total latency // total latency
// the total latency will be limited to the min and max-latency values, if supplied // the total latency will be limited to the min and max-latency values, if supplied
#ifdef CONFIG_LIBDAEMON #ifdef CONFIG_LIBDAEMON
int daemonise; int daemonise;
int daemonise_store_pid; // don't try to save a PID file int daemonise_store_pid; // don't try to save a PID file
@@ -192,7 +184,8 @@ typedef struct {
double tolerance; // allow this much drift before attempting to correct it double tolerance; // allow this much drift before attempting to correct it
enum stuffing_type packet_stuffing; enum stuffing_type packet_stuffing;
int soxr_delay_index; int soxr_delay_index;
int soxr_delay_threshold; // the soxr delay must be less or equal to this for soxr interpolation to be enabled under the auto setting int soxr_delay_threshold; // the soxr delay must be less or equal to this for soxr interpolation
// to be enabled under the auto setting
int decoders_supported; int decoders_supported;
int use_apple_decoder; // set to 1 if you want to use the apple decoder instead of the original by int use_apple_decoder; // set to 1 if you want to use the apple decoder instead of the original by
// David Hammerton // David Hammerton
@@ -215,16 +208,18 @@ typedef struct {
// fixed latency there might be in the audio path // fixed latency there might be in the audio path
double audio_backend_silent_lead_in_time; // the length of the silence that should precede a play. double audio_backend_silent_lead_in_time; // the length of the silence that should precede a play.
double active_state_timeout; // the amount of time from when play ends to when the system leaves double active_state_timeout; // the amount of time from when play ends to when the system leaves
// into the "active" mode. // into the "active" mode.
uint32_t volume_range_db; // the range, in dB, from max dB to min dB. Zero means use the mixer's uint32_t volume_range_db; // the range, in dB, from max dB to min dB. Zero means use the mixer's
// native range. // native range.
int volume_range_hw_priority; // when extending the volume range by combining sw and hw attenuators, lowering the volume, use all the hw attenuation before using int volume_range_hw_priority; // when extending the volume range by combining sw and hw
// attenuators, lowering the volume, use all the hw attenuation
// before using
// sw attenuation // sw attenuation
enum volume_control_profile_type volume_control_profile; enum volume_control_profile_type volume_control_profile;
int output_format_auto_requested; // true if the configuration requests auto configuration int output_format_auto_requested; // true if the configuration requests auto configuration
enum sps_format_t output_format; enum sps_format_t output_format;
int output_rate_auto_requested; // true if the configuration requests auto configuration int output_rate_auto_requested; // true if the configuration requests auto configuration
unsigned int output_rate; unsigned int output_rate;
#ifdef CONFIG_CONVOLUTION #ifdef CONFIG_CONVOLUTION
@@ -283,7 +278,8 @@ int get_requested_connection_state_to_output();
void set_requested_connection_state_to_output(int v); void set_requested_connection_state_to_output(int v);
ssize_t non_blocking_write_with_timeout(int fd, const void *buf, size_t count, int timeout); // timeout in milliseconds ssize_t non_blocking_write_with_timeout(int fd, const void *buf, size_t count,
int timeout); // timeout in milliseconds
ssize_t non_blocking_write(int fd, const void *buf, size_t count); // used in a few places ssize_t non_blocking_write(int fd, const void *buf, size_t count); // used in a few places
+10 -16
View File
@@ -39,8 +39,8 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <pthread.h> #include <pthread.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h>
#include <sys/time.h> #include <sys/time.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#include "metadata_hub.h" #include "metadata_hub.h"
@@ -112,10 +112,7 @@ static void response_code(void *opaque, int code) {
} }
static const struct http_funcs responseFuncs = { static const struct http_funcs responseFuncs = {
response_realloc, response_realloc, response_body, response_header, response_code,
response_body,
response_header,
response_code,
}; };
// static pthread_mutex_t dacp_conversation_lock = PTHREAD_MUTEX_INITIALIZER; // static pthread_mutex_t dacp_conversation_lock = PTHREAD_MUTEX_INITIALIZER;
@@ -323,10 +320,9 @@ int dacp_send_command(const char *command, char **body, ssize_t *bodysize) {
// debug(1,"Sent command\"%s\" with a response body of size %d.",command,response.size); // debug(1,"Sent command\"%s\" with a response body of size %d.",command,response.size);
// debug(1,"dacp_conversation_lock released."); // debug(1,"dacp_conversation_lock released.");
} else { } else {
debug(3, debug(3, "dacp_send_command: could not acquire a lock on the dacp transmit/receive section "
"dacp_send_command: could not acquire a lock on the dacp transmit/receive section " "when attempting to "
"when attempting to " "send the command \"%s\". Possible timeout?",
"send the command \"%s\". Possible timeout?",
command); command);
response.code = 494; // This client is already busy response.code = 494; // This client is already busy
} }
@@ -378,7 +374,7 @@ void set_dacp_server_information(rtsp_conn_info *conn) {
if ((conn->dacp_id == NULL) || (strcmp(conn->dacp_id, dacp_server.dacp_id) != 0)) { if ((conn->dacp_id == NULL) || (strcmp(conn->dacp_id, dacp_server.dacp_id) != 0)) {
if (conn->dacp_id) if (conn->dacp_id)
strncpy(dacp_server.dacp_id, conn->dacp_id, sizeof(dacp_server.dacp_id)-1); strncpy(dacp_server.dacp_id, conn->dacp_id, sizeof(dacp_server.dacp_id) - 1);
else else
dacp_server.dacp_id[0] = '\0'; dacp_server.dacp_id[0] = '\0';
dacp_server.port = 0; dacp_server.port = 0;
@@ -423,9 +419,8 @@ void set_dacp_server_information(rtsp_conn_info *conn) {
void dacp_monitor_port_update_callback(char *dacp_id, uint16_t port) { void dacp_monitor_port_update_callback(char *dacp_id, uint16_t port) {
debug_mutex_lock(&dacp_server_information_lock, 500000, 2); debug_mutex_lock(&dacp_server_information_lock, 500000, 2);
debug(3, debug(3, "dacp_monitor_port_update_callback with Remote ID \"%s\", target ID \"%s\" and port "
"dacp_monitor_port_update_callback with Remote ID \"%s\", target ID \"%s\" and port " "number %d.",
"number %d.",
dacp_id, dacp_server.dacp_id, port); dacp_id, dacp_server.dacp_id, port);
if (strcmp(dacp_id, dacp_server.dacp_id) == 0) { if (strcmp(dacp_id, dacp_server.dacp_id) == 0) {
dacp_server.port = port; dacp_server.port = port;
@@ -473,9 +468,8 @@ void *dacp_monitor_thread_code(__attribute__((unused)) void *na) {
(metadata_store.advanced_dacp_server_active != 0); (metadata_store.advanced_dacp_server_active != 0);
metadata_store.dacp_server_active = 0; metadata_store.dacp_server_active = 0;
metadata_store.advanced_dacp_server_active = 0; metadata_store.advanced_dacp_server_active = 0;
debug(2, debug(2, "setting dacp_server_active and advanced_dacp_server_active to 0 with an update "
"setting dacp_server_active and advanced_dacp_server_active to 0 with an update " "flag value of %d",
"flag value of %d",
ch); ch);
metadata_hub_modify_epilog(ch); metadata_hub_modify_epilog(ch);
while (dacp_server.scan_enable == 0) { while (dacp_server.scan_enable == 0) {
+34 -34
View File
@@ -433,12 +433,14 @@ gboolean notify_drift_tolerance_callback(ShairportSync *skeleton,
} }
gboolean notify_disable_standby_mode_callback(ShairportSync *skeleton, gboolean notify_disable_standby_mode_callback(ShairportSync *skeleton,
__attribute__((unused)) gpointer user_data) { __attribute__((unused)) gpointer user_data) {
char *th = (char *)shairport_sync_get_disable_standby_mode(skeleton); char *th = (char *)shairport_sync_get_disable_standby_mode(skeleton);
if ((strcasecmp(th, "no") == 0) || (strcasecmp(th, "off") == 0) || (strcasecmp(th, "never") == 0)) { if ((strcasecmp(th, "no") == 0) || (strcasecmp(th, "off") == 0) ||
(strcasecmp(th, "never") == 0)) {
config.disable_standby_mode = disable_standby_off; config.disable_standby_mode = disable_standby_off;
config.keep_dac_busy = 0; config.keep_dac_busy = 0;
} else if ((strcasecmp(th, "yes") == 0) || (strcasecmp(th, "on") == 0) || (strcasecmp(th, "always") == 0)) { } else if ((strcasecmp(th, "yes") == 0) || (strcasecmp(th, "on") == 0) ||
(strcasecmp(th, "always") == 0)) {
config.disable_standby_mode = disable_standby_always; config.disable_standby_mode = disable_standby_always;
config.keep_dac_busy = 1; config.keep_dac_busy = 1;
} else if (strcasecmp(th, "auto") == 0) } else if (strcasecmp(th, "auto") == 0)
@@ -446,17 +448,17 @@ gboolean notify_disable_standby_mode_callback(ShairportSync *skeleton,
else { else {
warn("An unrecognised disable_standby_mode: \"%s\" was requested via D-Bus interface.", th); warn("An unrecognised disable_standby_mode: \"%s\" was requested via D-Bus interface.", th);
switch (config.disable_standby_mode) { switch (config.disable_standby_mode) {
case disable_standby_off: case disable_standby_off:
shairport_sync_set_disable_standby_mode(skeleton, "off"); shairport_sync_set_disable_standby_mode(skeleton, "off");
break; break;
case disable_standby_always: case disable_standby_always:
shairport_sync_set_disable_standby_mode(skeleton, "always"); shairport_sync_set_disable_standby_mode(skeleton, "always");
break; break;
case disable_standby_auto: case disable_standby_auto:
shairport_sync_set_disable_standby_mode(skeleton, "auto"); shairport_sync_set_disable_standby_mode(skeleton, "auto");
break; break;
default: default:
break; break;
} }
} }
return TRUE; return TRUE;
@@ -661,7 +663,7 @@ static void on_dbus_name_acquired(GDBusConnection *connection, const gchar *name
G_CALLBACK(notify_alacdecoder_callback), NULL); G_CALLBACK(notify_alacdecoder_callback), NULL);
g_signal_connect(shairportSyncSkeleton, "notify::disable-standby-mode", g_signal_connect(shairportSyncSkeleton, "notify::disable-standby-mode",
G_CALLBACK(notify_disable_standby_mode_callback), NULL); G_CALLBACK(notify_disable_standby_mode_callback), NULL);
g_signal_connect(shairportSyncSkeleton, "notify::volume-control-profile", g_signal_connect(shairportSyncSkeleton, "notify::volume-control-profile",
G_CALLBACK(notify_volume_control_profile_callback), NULL); G_CALLBACK(notify_volume_control_profile_callback), NULL);
g_signal_connect(shairportSyncSkeleton, "notify::disable-standby", g_signal_connect(shairportSyncSkeleton, "notify::disable-standby",
G_CALLBACK(notify_disable_standby_callback), NULL); G_CALLBACK(notify_disable_standby_callback), NULL);
@@ -749,21 +751,21 @@ static void on_dbus_name_acquired(GDBusConnection *connection, const gchar *name
debug(1, ">> Active set to \"false\""); debug(1, ">> Active set to \"false\"");
switch (config.disable_standby_mode) { switch (config.disable_standby_mode) {
case disable_standby_off: case disable_standby_off:
shairport_sync_set_disable_standby_mode(SHAIRPORT_SYNC(shairportSyncSkeleton), "off"); shairport_sync_set_disable_standby_mode(SHAIRPORT_SYNC(shairportSyncSkeleton), "off");
debug(1, ">> disable standby mode set to \"off\""); debug(1, ">> disable standby mode set to \"off\"");
break; break;
case disable_standby_always: case disable_standby_always:
shairport_sync_set_disable_standby_mode(SHAIRPORT_SYNC(shairportSyncSkeleton), "always"); shairport_sync_set_disable_standby_mode(SHAIRPORT_SYNC(shairportSyncSkeleton), "always");
debug(1, ">> disable standby mode set to \"always\""); debug(1, ">> disable standby mode set to \"always\"");
break; break;
case disable_standby_auto: case disable_standby_auto:
shairport_sync_set_disable_standby_mode(SHAIRPORT_SYNC(shairportSyncSkeleton), "auto"); shairport_sync_set_disable_standby_mode(SHAIRPORT_SYNC(shairportSyncSkeleton), "auto");
debug(1, ">> disable standby mode set to \"auto\""); debug(1, ">> disable standby mode set to \"auto\"");
break; break;
default: default:
debug(1,"invalid disable_standby mode!"); debug(1, "invalid disable_standby mode!");
break; break;
} }
#ifdef CONFIG_SOXR #ifdef CONFIG_SOXR
@@ -902,9 +904,7 @@ void stop_dbus_service() {
g_bus_unown_name(ownerID); g_bus_unown_name(ownerID);
else else
debug(1, "Zero OwnerID for \"org.gnome.ShairportSync\"."); debug(1, "Zero OwnerID for \"org.gnome.ShairportSync\".");
service_is_running = 0; service_is_running = 0;
} }
int dbus_service_is_running() { int dbus_service_is_running() { return service_is_running; }
return service_is_running;
}
+1 -1
View File
@@ -24,8 +24,8 @@
* OTHER DEALINGS IN THE SOFTWARE. * OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include "common.h"
#include "mdns.h" #include "mdns.h"
#include "common.h"
#include <arpa/inet.h> #include <arpa/inet.h>
#include <dns_sd.h> #include <dns_sd.h>
#include <stdlib.h> #include <stdlib.h>
+13 -13
View File
@@ -46,8 +46,8 @@
#include "metadata_hub.h" #include "metadata_hub.h"
#ifdef CONFIG_MBEDTLS #ifdef CONFIG_MBEDTLS
#include <mbedtls/version.h>
#include <mbedtls/md5.h> #include <mbedtls/md5.h>
#include <mbedtls/version.h>
#endif #endif
#ifdef CONFIG_POLARSSL #ifdef CONFIG_POLARSSL
@@ -223,7 +223,7 @@ char *metadata_write_image_file(const char *buf, int len) {
char *path = NULL; // this will be what is returned char *path = NULL; // this will be what is returned
uint8_t img_md5[16]; uint8_t img_md5[16];
// uint8_t ap_md5[16]; // uint8_t ap_md5[16];
#ifdef CONFIG_OPENSSL #ifdef CONFIG_OPENSSL
MD5_CTX ctx; MD5_CTX ctx;
@@ -233,17 +233,17 @@ char *metadata_write_image_file(const char *buf, int len) {
#endif #endif
#ifdef CONFIG_MBEDTLS #ifdef CONFIG_MBEDTLS
#if MBEDTLS_VERSION_MINOR >= 7 #if MBEDTLS_VERSION_MINOR >= 7
mbedtls_md5_context tctx; mbedtls_md5_context tctx;
mbedtls_md5_starts_ret(&tctx); mbedtls_md5_starts_ret(&tctx);
mbedtls_md5_update_ret(&tctx, (const unsigned char *)buf, len); mbedtls_md5_update_ret(&tctx, (const unsigned char *)buf, len);
mbedtls_md5_finish_ret(&tctx, img_md5); mbedtls_md5_finish_ret(&tctx, img_md5);
#else #else
mbedtls_md5_context tctx; mbedtls_md5_context tctx;
mbedtls_md5_starts(&tctx); mbedtls_md5_starts(&tctx);
mbedtls_md5_update(&tctx, (const unsigned char *)buf, len); mbedtls_md5_update(&tctx, (const unsigned char *)buf, len);
mbedtls_md5_finish(&tctx, img_md5); mbedtls_md5_finish(&tctx, img_md5);
#endif #endif
#endif #endif
#ifdef CONFIG_POLARSSL #ifdef CONFIG_POLARSSL
+8 -6
View File
@@ -1522,7 +1522,8 @@ int stuff_buffer_soxr_32(int32_t *inptr, int32_t *scratchBuffer, int length,
debug(3, "soxr_oneshot execution time in microseconds: mean, standard deviation and max " debug(3, "soxr_oneshot execution time in microseconds: mean, standard deviation and max "
"for %" PRId32 " interpolations in the last " "for %" PRId32 " interpolations in the last "
"1250 packets. %10.1f, %10.1f, %10.1f.", "1250 packets. %10.1f, %10.1f, %10.1f.",
stat_n, stat_mean, stat_n <= 1 ? 0.0 : sqrtf(stat_M2 / (stat_n - 1)), longest_soxr_execution_time_us); stat_n, stat_mean, stat_n <= 1 ? 0.0 : sqrtf(stat_M2 / (stat_n - 1)),
longest_soxr_execution_time_us);
stat_n = 0; stat_n = 0;
stat_mean = 0.0; stat_mean = 0.0;
stat_M2 = 0.0; stat_M2 = 0.0;
@@ -1802,7 +1803,6 @@ void *player_thread_func(void *arg) {
(config.playback_mode == ST_mono)) (config.playback_mode == ST_mono))
conn->enable_dither = 1; conn->enable_dither = 1;
// remember, the output device may never have been initialised prior to this call // remember, the output device may never have been initialised prior to this call
config.output->start(config.output_rate, config.output_format); // will need a corresponding stop config.output->start(config.output_rate, config.output_format); // will need a corresponding stop
@@ -2386,15 +2386,17 @@ void *player_thread_func(void *arg) {
if ((current_delay < conn->dac_buffer_queue_minimum_length) || if ((current_delay < conn->dac_buffer_queue_minimum_length) ||
(config.packet_stuffing == ST_basic) || (config.packet_stuffing == ST_basic) ||
(config.soxr_delay_index == 0) || // not computed yet (config.soxr_delay_index == 0) || // not computed yet
((config.packet_stuffing == ST_auto) && (config.soxr_delay_index > config.soxr_delay_threshold)) // if the CPU is deemed too slow ((config.packet_stuffing == ST_auto) &&
(config.soxr_delay_index >
config.soxr_delay_threshold)) // if the CPU is deemed too slow
) { ) {
#endif #endif
play_samples = play_samples =
stuff_buffer_basic_32((int32_t *)conn->tbuf, inbuflength, config.output_format, stuff_buffer_basic_32((int32_t *)conn->tbuf, inbuflength, config.output_format,
conn->outbuf, amount_to_stuff, conn->enable_dither, conn); conn->outbuf, amount_to_stuff, conn->enable_dither, conn);
#ifdef CONFIG_SOXR #ifdef CONFIG_SOXR
} } else { // soxr requested or auto requested with the index less or equal to the
else { // soxr requested or auto requested with the index less or equal to the threshold // threshold
play_samples = stuff_buffer_soxr_32((int32_t *)conn->tbuf, (int32_t *)conn->sbuf, play_samples = stuff_buffer_soxr_32((int32_t *)conn->tbuf, (int32_t *)conn->sbuf,
inbuflength, config.output_format, conn->outbuf, inbuflength, config.output_format, conn->outbuf,
amount_to_stuff, conn->enable_dither, conn); amount_to_stuff, conn->enable_dither, conn);
@@ -2943,7 +2945,7 @@ int player_play(rtsp_conn_info *conn) {
command_start(); command_start();
// call on the output device to prepare itself // call on the output device to prepare itself
if ((config.output) && (config.output->prepare)) if ((config.output) && (config.output->prepare))
config.output->prepare(); config.output->prepare();
pthread_t *pt = malloc(sizeof(pthread_t)); pthread_t *pt = malloc(sizeof(pthread_t));
if (pt == NULL) if (pt == NULL)
+15 -18
View File
@@ -137,9 +137,8 @@ void *rtp_audio_receiver(void *arg) {
stat_mean += stat_delta / stat_n; stat_mean += stat_delta / stat_n;
stat_M2 += stat_delta * (time_interval_us - stat_mean); stat_M2 += stat_delta * (time_interval_us - stat_mean);
if (stat_n % 2500 == 0) { if (stat_n % 2500 == 0) {
debug(2, debug(2, "Packet reception interval stats: mean, standard deviation and max for the last "
"Packet reception interval stats: mean, standard deviation and max for the last " "2,500 packets in microseconds: %10.1f, %10.1f, %10.1f.",
"2,500 packets in microseconds: %10.1f, %10.1f, %10.1f.",
stat_mean, sqrtf(stat_M2 / (stat_n - 1)), longest_packet_time_interval_us); stat_mean, sqrtf(stat_M2 / (stat_n - 1)), longest_packet_time_interval_us);
stat_n = 0; stat_n = 0;
stat_mean = 0.0; stat_mean = 0.0;
@@ -369,10 +368,9 @@ void *rtp_control_receiver(void *arg) {
if (la != conn->latency) { if (la != conn->latency) {
conn->latency = la; conn->latency = la;
debug(3, debug(3, "New latency detected: %" PRIu32 ", sync latency: %" PRIu32
"New latency detected: %" PRIu32 ", sync latency: %" PRIu32 ", minimum latency: %" PRIu32 ", maximum "
", minimum latency: %" PRIu32 ", maximum " "latency: %" PRIu32 ", fixed offset: %" PRIu32 ".",
"latency: %" PRIu32 ", fixed offset: %" PRIu32 ".",
la, sync_rtp_timestamp - rtp_timestamp_less_latency, conn->minimum_latency, la, sync_rtp_timestamp - rtp_timestamp_less_latency, conn->minimum_latency,
conn->maximum_latency, config.fixedLatencyOffset); conn->maximum_latency, config.fixedLatencyOffset);
} }
@@ -396,11 +394,11 @@ void *rtp_control_receiver(void *arg) {
remote_frame_time_interval; // an IEEE double calculation with a 32-bit remote_frame_time_interval; // an IEEE double calculation with a 32-bit
// numerator and 64-bit denominator // numerator and 64-bit denominator
// integers // integers
conn->remote_frame_rate = conn->remote_frame_rate * conn->remote_frame_rate =
(uint64_t)0x100000000; // this should just change the conn->remote_frame_rate * (uint64_t)0x100000000; // this should just change the
// [binary] exponent in the IEEE // [binary] exponent in the IEEE
// FP representation; the // FP representation; the
// mantissa should be unaffected. // mantissa should be unaffected.
} else { } else {
conn->remote_frame_rate = 0.0; // use as a flag. conn->remote_frame_rate = 0.0; // use as a flag.
} }
@@ -824,7 +822,7 @@ void *rtp_timing_receiver(void *arg) {
conn->local_to_remote_time_gradient = (1.0 * mtl) / mbl; conn->local_to_remote_time_gradient = (1.0 * mtl) / mbl;
else { else {
conn->local_to_remote_time_gradient = 1.0; conn->local_to_remote_time_gradient = 1.0;
debug(1,"rtp_timing_receiver: mbl is 0"); debug(1, "rtp_timing_receiver: mbl is 0");
} }
} else { } else {
conn->local_to_remote_time_gradient = 1.0; conn->local_to_remote_time_gradient = 1.0;
@@ -1105,7 +1103,7 @@ int sanitised_source_rate_information(uint32_t *frames, uint64_t *time, rtsp_con
if (local_time) if (local_time)
calculated_frame_rate = ((1.0 * local_frames) / local_time) * one_fp; calculated_frame_rate = ((1.0 * local_frames) / local_time) * one_fp;
else else
debug(1,"sanitised_source_rate_information: local_time is zero"); debug(1, "sanitised_source_rate_information: local_time is zero");
if ((local_time == 0) || ((calculated_frame_rate / conn->input_rate) > 1.002) || if ((local_time == 0) || ((calculated_frame_rate / conn->input_rate) > 1.002) ||
((calculated_frame_rate / conn->input_rate) < 0.998)) { ((calculated_frame_rate / conn->input_rate) < 0.998)) {
debug(3, "input frame rate out of bounds at %.2f fps.", calculated_frame_rate); debug(3, "input frame rate out of bounds at %.2f fps.", calculated_frame_rate);
@@ -1188,7 +1186,7 @@ int local_time_to_frame(uint64_t time, uint32_t *frame, rtsp_conn_info *conn) {
if (time_difference) if (time_difference)
frame_interval = (time_interval * frame_difference) / time_difference; frame_interval = (time_interval * frame_difference) / time_difference;
else else
debug(1,"local_time_to_frame: time_difference is zero"); debug(1, "local_time_to_frame: time_difference is zero");
if (reference_time_was_earlier) { if (reference_time_was_earlier) {
// debug(1,"Frame interval is %" PRId64 " frames.",frame_interval); // debug(1,"Frame interval is %" PRId64 " frames.",frame_interval);
*frame = (conn->reference_timestamp + frame_interval); *frame = (conn->reference_timestamp + frame_interval);
@@ -1240,9 +1238,8 @@ void rtp_request_resend(seq_t first, uint32_t count, rtsp_conn_info *conn) {
(struct sockaddr *)&conn->rtp_client_control_socket, msgsize) == -1) { (struct sockaddr *)&conn->rtp_client_control_socket, msgsize) == -1) {
char em[1024]; char em[1024];
strerror_r(errno, em, sizeof(em)); strerror_r(errno, em, sizeof(em));
debug(1, debug(1, "Error %d using sendto to an audio socket: \"%s\". Backing off for 1/16th of a "
"Error %d using sendto to an audio socket: \"%s\". Backing off for 1/16th of a " "second.",
"second.",
errno, em); errno, em);
conn->rtp_time_of_last_resend_request_error_fp = time_of_sending_fp; conn->rtp_time_of_last_resend_request_error_fp = time_of_sending_fp;
} else { } else {
+81 -74
View File
@@ -31,6 +31,7 @@
#include <libconfig.h> #include <libconfig.h>
#include <libgen.h> #include <libgen.h>
#include <memory.h> #include <memory.h>
#include <net/if.h>
#include <popt.h> #include <popt.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@@ -38,10 +39,8 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <net/if.h>
#include <unistd.h> #include <unistd.h>
#include "config.h" #include "config.h"
#ifdef CONFIG_MBEDTLS #ifdef CONFIG_MBEDTLS
@@ -97,15 +96,14 @@
#endif #endif
#ifdef CONFIG_SOXR #ifdef CONFIG_SOXR
#include <soxr.h>
#include <math.h> #include <math.h>
#include <soxr.h>
#endif #endif
#ifdef CONFIG_CONVOLUTION #ifdef CONFIG_CONVOLUTION
#include <FFTConvolver/convolver.h> #include <FFTConvolver/convolver.h>
#endif #endif
#ifdef CONFIG_LIBDAEMON #ifdef CONFIG_LIBDAEMON
pid_t pid; pid_t pid;
#endif #endif
@@ -165,14 +163,14 @@ void print_version(void) {
} }
#ifdef CONFIG_SOXR #ifdef CONFIG_SOXR
pthread_t soxr_time_check_thread; pthread_t soxr_time_check_thread;
void* soxr_time_check(__attribute__((unused)) void *arg) { void *soxr_time_check(__attribute__((unused)) void *arg) {
const int buffer_length = 352; const int buffer_length = 352;
int32_t inbuffer[buffer_length*2]; int32_t inbuffer[buffer_length * 2];
int32_t outbuffer[(buffer_length+1)*2]; int32_t outbuffer[(buffer_length + 1) * 2];
//int32_t *outbuffer = (int32_t*)malloc((buffer_length+1)*2*sizeof(int32_t)); // int32_t *outbuffer = (int32_t*)malloc((buffer_length+1)*2*sizeof(int32_t));
//int32_t *inbuffer = (int32_t*)malloc((buffer_length)*2*sizeof(int32_t)); // int32_t *inbuffer = (int32_t*)malloc((buffer_length)*2*sizeof(int32_t));
// generate a sample signal // generate a sample signal
const double frequency = 440; // const double frequency = 440; //
@@ -181,12 +179,13 @@ void* soxr_time_check(__attribute__((unused)) void *arg) {
int number_of_iterations = 0; int number_of_iterations = 0;
uint64_t soxr_start_time = get_absolute_time_in_fp(); uint64_t soxr_start_time = get_absolute_time_in_fp();
uint64_t loop_until_time = (uint64_t)0x180000000 + soxr_start_time; // loop for a second and a half, max uint64_t loop_until_time =
(uint64_t)0x180000000 + soxr_start_time; // loop for a second and a half, max
while (get_absolute_time_in_fp() < loop_until_time) { while (get_absolute_time_in_fp() < loop_until_time) {
number_of_iterations++; number_of_iterations++;
for (i = 0; i < buffer_length ; i++) { for (i = 0; i < buffer_length; i++) {
double w = sin(i * (frequency + number_of_iterations * 2) * 2 * M_PI/44100); double w = sin(i * (frequency + number_of_iterations * 2) * 2 * M_PI / 44100);
int32_t wint = (int32_t)(w * INT32_MAX); int32_t wint = (int32_t)(w * INT32_MAX);
inbuffer[i * 2] = wint; inbuffer[i * 2] = wint;
inbuffer[i * 2 + 1] = wint; inbuffer[i * 2 + 1] = wint;
@@ -201,11 +200,11 @@ void* soxr_time_check(__attribute__((unused)) void *arg) {
size_t odone; size_t odone;
soxr_oneshot(buffer_length, buffer_length + 1, 2, // Rates and # of chans. soxr_oneshot(buffer_length, buffer_length + 1, 2, // Rates and # of chans.
inbuffer, buffer_length, NULL, // Input. inbuffer, buffer_length, NULL, // Input.
outbuffer, buffer_length + 1, &odone, // Output. outbuffer, buffer_length + 1, &odone, // Output.
&io_spec, // Input, output and transfer spec. &io_spec, // Input, output and transfer spec.
NULL, NULL); // Default configuration. NULL, NULL); // Default configuration.
io_spec.itype = SOXR_INT32_I; io_spec.itype = SOXR_INT32_I;
io_spec.otype = SOXR_INT32_I; io_spec.otype = SOXR_INT32_I;
@@ -213,25 +212,27 @@ void* soxr_time_check(__attribute__((unused)) void *arg) {
io_spec.e = NULL; io_spec.e = NULL;
io_spec.flags = 0; io_spec.flags = 0;
soxr_oneshot(buffer_length, buffer_length - 1, 2, // Rates and # of chans. soxr_oneshot(buffer_length, buffer_length - 1, 2, // Rates and # of chans.
inbuffer, buffer_length, NULL, // Input. inbuffer, buffer_length, NULL, // Input.
outbuffer, buffer_length - 1, &odone, // Output. outbuffer, buffer_length - 1, &odone, // Output.
&io_spec, // Input, output and transfer spec. &io_spec, // Input, output and transfer spec.
NULL, NULL); // Default configuration. NULL, NULL); // Default configuration.
} }
double soxr_execution_time_us = double soxr_execution_time_us =
(((get_absolute_time_in_fp() - soxr_start_time) * 1000000) >> 32) * 1.0; (((get_absolute_time_in_fp() - soxr_start_time) * 1000000) >> 32) * 1.0;
// free(outbuffer); // free(outbuffer);
// free(inbuffer); // free(inbuffer);
config.soxr_delay_index = (int)(0.9 + soxr_execution_time_us/(number_of_iterations *1000)); config.soxr_delay_index = (int)(0.9 + soxr_execution_time_us / (number_of_iterations * 1000));
debug(2,"soxr_delay_index: %d.", config.soxr_delay_index); debug(2, "soxr_delay_index: %d.", config.soxr_delay_index);
if ((config.packet_stuffing == ST_soxr) && (config.soxr_delay_index > config.soxr_delay_threshold)) if ((config.packet_stuffing == ST_soxr) &&
inform("Note: this device may be too slow for \"soxr\" interpolation. Consider choosing the \"basic\" or \"auto\" interpolation setting."); (config.soxr_delay_index > config.soxr_delay_threshold))
inform("Note: this device may be too slow for \"soxr\" interpolation. Consider choosing the "
"\"basic\" or \"auto\" interpolation setting.");
if (config.packet_stuffing == ST_auto) if (config.packet_stuffing == ST_auto)
debug(1,"\"%s\" interpolation has been chosen.", config.soxr_delay_index <= config.soxr_delay_threshold ? "soxr" : "basic"); debug(1, "\"%s\" interpolation has been chosen.",
pthread_exit(NULL); config.soxr_delay_index <= config.soxr_delay_threshold ? "soxr" : "basic");
pthread_exit(NULL);
} }
#endif #endif
@@ -428,10 +429,14 @@ int parse_options(int argc, char **argv) {
config.fixedLatencyOffset = 11025; // this sounds like it works properly. config.fixedLatencyOffset = 11025; // this sounds like it works properly.
config.diagnostic_drop_packet_fraction = 0.0; config.diagnostic_drop_packet_fraction = 0.0;
config.active_state_timeout = 10.0; config.active_state_timeout = 10.0;
config.soxr_delay_threshold = 30; // the soxr measurement time (milliseconds) of two oneshots must not exceed this if soxr interpolation is to be chosen automatically. config.soxr_delay_threshold = 30; // the soxr measurement time (milliseconds) of two oneshots must
config.volume_range_hw_priority = 0; // if combining software and hardware volume control, give the software priority // not exceed this if soxr interpolation is to be chosen
// automatically.
config.volume_range_hw_priority =
0; // if combining software and hardware volume control, give the software priority
// i.e. when reducing volume, reduce the sw first before reducing the software. // i.e. when reducing volume, reduce the sw first before reducing the software.
// this is because some hw mixers mute at the bottom of their range, and they don't always advertise this fact // this is because some hw mixers mute at the bottom of their range, and they don't always advertise
// this fact
#ifdef CONFIG_METADATA_HUB #ifdef CONFIG_METADATA_HUB
config.cover_art_cache_dir = "/tmp/shairport-sync/.cache/coverart"; config.cover_art_cache_dir = "/tmp/shairport-sync/.cache/coverart";
@@ -536,8 +541,8 @@ int parse_options(int argc, char **argv) {
config.packet_stuffing = ST_soxr; config.packet_stuffing = ST_soxr;
#else #else
warn("The soxr option not available because this version of shairport-sync was built " warn("The soxr option not available because this version of shairport-sync was built "
"without libsoxr " "without libsoxr "
"support. Change the \"general/interpolation\" setting in the configuration file."); "support. Change the \"general/interpolation\" setting in the configuration file.");
#endif #endif
else else
die("Invalid interpolation option choice. It should be \"auto\", \"basic\" or \"soxr\""); die("Invalid interpolation option choice. It should be \"auto\", \"basic\" or \"soxr\"");
@@ -550,9 +555,9 @@ int parse_options(int argc, char **argv) {
config.soxr_delay_threshold = value; config.soxr_delay_threshold = value;
else else
warn("Invalid general soxr_delay_threshold setting option choice \"%d\". It should be " warn("Invalid general soxr_delay_threshold setting option choice \"%d\". It should be "
"between 0 and 100, " "between 0 and 100, "
"inclusive. Default is %d (milliseconds).", "inclusive. Default is %d (milliseconds).",
value, config.soxr_delay_threshold); value, config.soxr_delay_threshold);
} }
#endif #endif
@@ -1003,10 +1008,10 @@ int parse_options(int argc, char **argv) {
config.mqtt_port = 1883; config.mqtt_port = 1883;
if (config_lookup_int(config.cfg, "mqtt.port", &value)) { if (config_lookup_int(config.cfg, "mqtt.port", &value)) {
if ((value < 0) || (value > 65535)) if ((value < 0) || (value > 65535))
die("Invalid mqtt port number \"%sd\". It should be between 0 and 65535, default is 1883", die("Invalid mqtt port number \"%sd\". It should be between 0 and 65535, default is 1883",
value); value);
else else
config.mqtt_port = value; config.mqtt_port = value;
} }
if (config_lookup_string(config.cfg, "mqtt.username", &str)) { if (config_lookup_string(config.cfg, "mqtt.username", &str)) {
@@ -1051,11 +1056,11 @@ int parse_options(int argc, char **argv) {
} }
config_set_lookup_bool(config.cfg, "mqtt.enable_remote", &config.mqtt_enable_remote); config_set_lookup_bool(config.cfg, "mqtt.enable_remote", &config.mqtt_enable_remote);
#ifndef CONFIG_AVAHI #ifndef CONFIG_AVAHI
if (config.mqtt_enable_remote) { if (config.mqtt_enable_remote) {
die("You have enabled MQTT remote control which requires shairport-sync to be built with " die("You have enabled MQTT remote control which requires shairport-sync to be built with "
"Avahi, but your installation is not using avahi. Please reinstall/recompile with " "Avahi, but your installation is not using avahi. Please reinstall/recompile with "
"avahi enabled, or disable remote control."); "avahi enabled, or disable remote control.");
} }
#endif #endif
#endif #endif
} }
@@ -1125,7 +1130,6 @@ int parse_options(int argc, char **argv) {
// here, we are finally finished reading the options // here, we are finally finished reading the options
#ifdef CONFIG_LIBDAEMON #ifdef CONFIG_LIBDAEMON
if ((daemonisewith) && (daemonisewithout)) if ((daemonisewith) && (daemonisewithout))
die("Select either daemonize_with_pid_file or daemonize_without_pid_file -- you have selected " die("Select either daemonize_with_pid_file or daemonize_without_pid_file -- you have selected "
@@ -1138,7 +1142,9 @@ int parse_options(int argc, char **argv) {
#else #else
/* Check if we are called with -d or --daemon or -j or justDaemoniseNoPIDFile options*/ /* Check if we are called with -d or --daemon or -j or justDaemoniseNoPIDFile options*/
if ((daemonisewith != 0) || (daemonisewithout != 0)) { if ((daemonisewith != 0) || (daemonisewithout != 0)) {
fprintf(stderr,"%s was built without libdaemon, so does not support daemonisation using the -d, --deamon, -j or --justDaemoniseNoPIDFile options\n",config.appName); fprintf(stderr, "%s was built without libdaemon, so does not support daemonisation using the "
"-d, --deamon, -j or --justDaemoniseNoPIDFile options\n",
config.appName);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -1315,7 +1321,7 @@ void main_cleanup_handler(__attribute__((unused)) void *arg) {
} }
#ifdef CONFIG_LIBDAEMON #ifdef CONFIG_LIBDAEMON
// only do this if you are the daemon // only do this if you are the daemon
if (pid == 0) { if (pid == 0) {
daemon_retval_send(0); daemon_retval_send(0);
daemon_pid_file_remove(); daemon_pid_file_remove();
@@ -1366,12 +1372,12 @@ int main(int argc, char **argv) {
die("can not allocate memory for the app name!"); die("can not allocate memory for the app name!");
free(basec); free(basec);
// debug(1,"startup"); // debug(1,"startup");
#ifdef CONFIG_LIBDAEMON #ifdef CONFIG_LIBDAEMON
daemon_set_verbosity(LOG_DEBUG); daemon_set_verbosity(LOG_DEBUG);
#else #else
setlogmask (LOG_UPTO (LOG_DEBUG)); setlogmask(LOG_UPTO(LOG_DEBUG));
openlog(NULL,0,LOG_DAEMON); openlog(NULL, 0, LOG_DAEMON);
#endif #endif
atexit(exit_function); atexit(exit_function);
@@ -1411,7 +1417,8 @@ int main(int argc, char **argv) {
// config.statistics_requested = 0; // don't print stats in the log // config.statistics_requested = 0; // don't print stats in the log
// config.userSuppliedLatency = 0; // zero means none supplied // config.userSuppliedLatency = 0; // zero means none supplied
config.debugger_show_relative_time = 1; // by default, log the time back to the previous debug message config.debugger_show_relative_time =
1; // by default, log the time back to the previous debug message
config.resyncthreshold = 0.05; // 50 ms config.resyncthreshold = 0.05; // 50 ms
config.timeout = 120; // this number of seconds to wait for [more] audio before switching to idle. config.timeout = 120; // this number of seconds to wait for [more] audio before switching to idle.
config.tolerance = config.tolerance =
@@ -1419,14 +1426,13 @@ int main(int argc, char **argv) {
config.buffer_start_fill = 220; config.buffer_start_fill = 220;
config.port = 5000; config.port = 5000;
#ifdef CONFIG_SOXR #ifdef CONFIG_SOXR
config.packet_stuffing = ST_auto; // use soxr interpolation by default if support has been included and if the CPU is fast enough config.packet_stuffing = ST_auto; // use soxr interpolation by default if support has been
// included and if the CPU is fast enough
#else #else
config.packet_stuffing = ST_basic; // simple interpolation or deletion config.packet_stuffing = ST_basic; // simple interpolation or deletion
#endif #endif
// char hostname[100]; // char hostname[100];
// gethostname(hostname, 100); // gethostname(hostname, 100);
// config.service_name = malloc(20 + 100); // config.service_name = malloc(20 + 100);
@@ -1488,7 +1494,6 @@ int main(int argc, char **argv) {
#endif #endif
// parse arguments into config -- needed to locate pid_dir // parse arguments into config -- needed to locate pid_dir
int audio_arg = parse_options(argc, argv); int audio_arg = parse_options(argc, argv);
@@ -1512,7 +1517,8 @@ int main(int argc, char **argv) {
} }
return ret < 0 ? 1 : 0; return ret < 0 ? 1 : 0;
#else #else
fprintf(stderr,"%s was built without libdaemon, so does not support the -k or --kill option\n",config.appName); fprintf(stderr, "%s was built without libdaemon, so does not support the -k or --kill option\n",
config.appName);
return 1; return 1;
#endif #endif
} }
@@ -1608,7 +1614,7 @@ int main(int argc, char **argv) {
} }
#endif #endif
debug(1,"Started!"); debug(1, "Started!");
main_thread_id = pthread_self(); main_thread_id = pthread_self();
if (!main_thread_id) if (!main_thread_id)
debug(1, "Main thread is set up to be NULL!"); debug(1, "Main thread is set up to be NULL!");
@@ -1618,7 +1624,6 @@ int main(int argc, char **argv) {
// make sure the program can create files that group and world can read // make sure the program can create files that group and world can read
umask(S_IWGRP | S_IWOTH); umask(S_IWGRP | S_IWOTH);
/* print out version */ /* print out version */
char *version_dbs = get_version_string(); char *version_dbs = get_version_string();
@@ -1701,7 +1706,9 @@ int main(int argc, char **argv) {
debug(1, "active_state_timeout is %f seconds.", config.active_state_timeout); debug(1, "active_state_timeout is %f seconds.", config.active_state_timeout);
debug(1, "mdns backend \"%s\".", config.mdns_name); debug(1, "mdns backend \"%s\".", config.mdns_name);
debug(2, "userSuppliedLatency is %d.", config.userSuppliedLatency); debug(2, "userSuppliedLatency is %d.", config.userSuppliedLatency);
debug(1, "interpolation setting is \"%s\".", config.packet_stuffing == ST_basic ? "basic" : config.packet_stuffing == ST_soxr ? "soxr" : "auto"); debug(1, "interpolation setting is \"%s\".",
config.packet_stuffing == ST_basic ? "basic" : config.packet_stuffing == ST_soxr ? "soxr"
: "auto");
debug(1, "interpolation soxr_delay_threshold is %d.", config.soxr_delay_threshold); debug(1, "interpolation soxr_delay_threshold is %d.", config.soxr_delay_threshold);
debug(1, "resync time is %f seconds.", config.resyncthreshold); debug(1, "resync time is %f seconds.", config.resyncthreshold);
debug(1, "allow a session to be interrupted: %d.", config.allow_session_interruption); debug(1, "allow a session to be interrupted: %d.", config.allow_session_interruption);
@@ -1715,25 +1722,25 @@ int main(int argc, char **argv) {
debug(1, "volume_max_db is not set"); debug(1, "volume_max_db is not set");
debug(1, "volume range in dB (zero means use the range specified by the mixer): %u.", debug(1, "volume range in dB (zero means use the range specified by the mixer): %u.",
config.volume_range_db); config.volume_range_db);
debug( debug(1, "volume_range_combined_hardware_priority (1 means hardware mixer attenuation is used "
1, "first) is %d.",
"volume_range_combined_hardware_priority (1 means hardware mixer attenuation is used first) is %d.", config.volume_range_hw_priority);
config.volume_range_hw_priority);
debug(1, "playback_mode is %d (0-stereo, 1-mono, 1-reverse_stereo, 2-both_left, 3-both_right).", debug(1, "playback_mode is %d (0-stereo, 1-mono, 1-reverse_stereo, 2-both_left, 3-both_right).",
config.playback_mode); config.playback_mode);
debug(1, "disable_synchronization is %d.", config.no_sync); debug(1, "disable_synchronization is %d.", config.no_sync);
debug(1, "use_mmap_if_available is %d.", config.no_mmap ? 0 : 1); debug(1, "use_mmap_if_available is %d.", config.no_mmap ? 0 : 1);
debug(1, "output_format automatic selection is %sabled.", config.output_format_auto_requested ? "en" : "dis"); debug(1, "output_format automatic selection is %sabled.",
config.output_format_auto_requested ? "en" : "dis");
if (config.output_format_auto_requested == 0) if (config.output_format_auto_requested == 0)
debug(1, debug(1, "output_format is \"%s\".", sps_format_description_string(config.output_format));
"output_format is \"%s\".", debug(1, "output_rate automatic selection is %sabled.",
sps_format_description_string(config.output_format)); config.output_rate_auto_requested ? "en" : "dis");
debug(1, "output_rate automatic selection is %sabled.", config.output_rate_auto_requested ? "en" : "dis");
if (config.output_rate_auto_requested == 0) if (config.output_rate_auto_requested == 0)
debug(1, "output_rate is %d.", config.output_rate); debug(1, "output_rate is %d.", config.output_rate);
debug(1, "audio backend desired buffer length is %f seconds.", debug(1, "audio backend desired buffer length is %f seconds.",
config.audio_backend_buffer_desired_length); config.audio_backend_buffer_desired_length);
debug(1, "audio_backend_buffer_interpolation_threshold_in_seconds is %f seconds.", config.audio_backend_buffer_interpolation_threshold_in_seconds); debug(1, "audio_backend_buffer_interpolation_threshold_in_seconds is %f seconds.",
config.audio_backend_buffer_interpolation_threshold_in_seconds);
debug(1, "audio backend latency offset is %f seconds.", config.audio_backend_latency_offset); 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.", 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); config.audio_backend_silent_lead_in_time);
@@ -1783,7 +1790,7 @@ int main(int argc, char **argv) {
uint8_t ap_md5[16]; uint8_t ap_md5[16];
#ifdef CONFIG_SOXR #ifdef CONFIG_SOXR
pthread_create(&soxr_time_check_thread, NULL, &soxr_time_check, NULL); pthread_create(&soxr_time_check_thread, NULL, &soxr_time_check, NULL);
#endif #endif
#ifdef CONFIG_OPENSSL #ifdef CONFIG_OPENSSL