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:
+10
-13
@@ -46,7 +46,6 @@
|
||||
#include "dbus-service.h"
|
||||
#endif
|
||||
|
||||
|
||||
enum am_state 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) {
|
||||
#ifdef CONFIG_DBUS_INTERFACE
|
||||
if (dbus_service_is_running())
|
||||
shairport_sync_set_disable_standby(SHAIRPORT_SYNC(shairportSyncSkeleton), TRUE);
|
||||
else
|
||||
config.keep_dac_busy = 1;
|
||||
if (dbus_service_is_running())
|
||||
shairport_sync_set_disable_standby(SHAIRPORT_SYNC(shairportSyncSkeleton), TRUE);
|
||||
else
|
||||
config.keep_dac_busy = 1;
|
||||
#else
|
||||
config.keep_dac_busy = 1;
|
||||
#endif
|
||||
@@ -100,12 +99,12 @@ void going_inactive(int block) {
|
||||
|
||||
if (config.disable_standby_mode == disable_standby_auto) {
|
||||
#ifdef CONFIG_DBUS_INTERFACE
|
||||
if (dbus_service_is_running())
|
||||
shairport_sync_set_disable_standby(SHAIRPORT_SYNC(shairportSyncSkeleton), FALSE);
|
||||
else
|
||||
config.keep_dac_busy = 0;
|
||||
if (dbus_service_is_running())
|
||||
shairport_sync_set_disable_standby(SHAIRPORT_SYNC(shairportSyncSkeleton), FALSE);
|
||||
else
|
||||
config.keep_dac_busy = 0;
|
||||
#else
|
||||
config.keep_dac_busy = 0;
|
||||
config.keep_dac_busy = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -255,9 +254,7 @@ void *activity_monitor_thread_code(void *arg) {
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
enum am_state activity_status() {
|
||||
return (state);
|
||||
}
|
||||
enum am_state activity_status() { return (state); }
|
||||
|
||||
void activity_monitor_start() {
|
||||
// debug(1,"activity_monitor_start");
|
||||
|
||||
+1
-1
@@ -5,4 +5,4 @@ enum am_state { am_inactive, am_active, am_timing_out };
|
||||
void activity_monitor_start();
|
||||
void activity_monitor_stop();
|
||||
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
@@ -37,9 +37,9 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "activity_monitor.h"
|
||||
#include "audio.h"
|
||||
#include "common.h"
|
||||
|
||||
enum alsa_backend_mode {
|
||||
abm_disconnected,
|
||||
@@ -48,8 +48,8 @@ enum alsa_backend_mode {
|
||||
} alsa_backend_state; // under the control of alsa_mutex
|
||||
|
||||
typedef struct {
|
||||
snd_pcm_format_t alsa_code;
|
||||
int frame_size;
|
||||
snd_pcm_format_t alsa_code;
|
||||
int frame_size;
|
||||
} format_record;
|
||||
|
||||
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
|
||||
static double set_volume;
|
||||
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 use_monotonic_clock = 0; // this value will be set when the hardware is initialised
|
||||
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 use_monotonic_clock = 0; // this value will be set when the hardware is initialised
|
||||
|
||||
audio_output audio_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
|
||||
// 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;
|
||||
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
|
||||
|
||||
// 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_uframes_t) = snd_pcm_writei;
|
||||
snd_pcm_sframes_t (*alsa_pcm_write)(snd_pcm_t *, const void *, 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);
|
||||
int standard_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, standard.
|
||||
int (*delay_and_status)(snd_pcm_state_t *state, snd_pcm_sframes_t *delay, enum yndk_type *using_update_timestamps) = standard_delay_and_status;
|
||||
// use this to allow the use of standard or precision delay calculations, with standard the, uh,
|
||||
// standard.
|
||||
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
|
||||
// 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() {
|
||||
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);
|
||||
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
|
||||
// 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:"),
|
||||
// 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)
|
||||
// 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_sframes_t delay;
|
||||
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 ((uses_update_timestamps == YNDK_YES) && (is_a_real_hardware_device)) {
|
||||
precision_delay_available_status = YNDK_YES;
|
||||
debug(2,"alsa: precision delay timing is available.");
|
||||
debug(2, "alsa: precision delay timing is available.");
|
||||
} else {
|
||||
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 {
|
||||
debug(2,"alsa: precision delay timing is not available.");
|
||||
debug(2, "alsa: precision delay timing is not available.");
|
||||
}
|
||||
precision_delay_available_status = YNDK_NO;
|
||||
}
|
||||
@@ -234,7 +243,6 @@ int precision_delay_available() {
|
||||
return (precision_delay_available_status == YNDK_YES);
|
||||
}
|
||||
|
||||
|
||||
// static int play_number;
|
||||
// static int64_t accumulated_delay, accumulated_da_delay;
|
||||
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"
|
||||
" -m mixer-device set the mixer device, default is the output device.\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)
|
||||
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.
|
||||
// The lowest rate that the DAC is capable of is chosen.
|
||||
|
||||
unsigned int auto_speed_output_rates[] = {
|
||||
44100,
|
||||
88200,
|
||||
176400,
|
||||
352800,
|
||||
44100, 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.
|
||||
// If just one format is requested, then its entry is searched for in the array and checked on the device
|
||||
// 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.
|
||||
// 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.
|
||||
// So, it should be in the search order.
|
||||
|
||||
format_record fr[] = {
|
||||
{SND_PCM_FORMAT_UNKNOWN,0}, // unknown
|
||||
{SND_PCM_FORMAT_S8,2},
|
||||
{SND_PCM_FORMAT_U8,2},
|
||||
{SND_PCM_FORMAT_S16,4},
|
||||
{SND_PCM_FORMAT_S16_LE,4},
|
||||
{SND_PCM_FORMAT_S16_BE,4},
|
||||
{SND_PCM_FORMAT_S24,4},
|
||||
{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
|
||||
};
|
||||
format_record fr[] = {
|
||||
{SND_PCM_FORMAT_UNKNOWN, 0}, // unknown
|
||||
{SND_PCM_FORMAT_S8, 2}, {SND_PCM_FORMAT_U8, 2}, {SND_PCM_FORMAT_S16, 4},
|
||||
{SND_PCM_FORMAT_S16_LE, 4}, {SND_PCM_FORMAT_S16_BE, 4}, {SND_PCM_FORMAT_S24, 4},
|
||||
{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.
|
||||
// Ideally, audio should pass through Shairport Sync unaltered, apart from occasional interpolation.
|
||||
// If the user chooses a hardware mixer, then audio could go straight through, unaltered, as signed 16 bit stereo.
|
||||
// However, the user might, at any point, select an option that requires modification, such as stereo to mono mixing,
|
||||
// additional volume attenuation, convolution, and so on. For this reason,
|
||||
// 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.
|
||||
// This array is the sequence of formats to be tried if automatic selection of the format is
|
||||
// requested.
|
||||
// Ideally, audio should pass through Shairport Sync unaltered, apart from occasional interpolation.
|
||||
// If the user chooses a hardware mixer, then audio could go straight through, unaltered, as signed
|
||||
// 16 bit stereo.
|
||||
// However, the user might, at any point, select an option that requires modification, such as
|
||||
// stereo to mono mixing,
|
||||
// additional volume attenuation, convolution, and so on. For this reason,
|
||||
// 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[] = {
|
||||
SPS_FORMAT_S32,
|
||||
SPS_FORMAT_S32_LE,
|
||||
SPS_FORMAT_S32_BE,
|
||||
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,
|
||||
};
|
||||
enum sps_format_t auto_format_check_sequence[] = {
|
||||
SPS_FORMAT_S32, SPS_FORMAT_S32_LE, SPS_FORMAT_S32_BE, 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
|
||||
// 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;
|
||||
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 actual_buffer_length;
|
||||
snd_pcm_access_t access;
|
||||
@@ -444,7 +440,8 @@ int actual_open_alsa_device(int do_auto_setup) {
|
||||
} else {
|
||||
char errorstring[1024];
|
||||
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;
|
||||
}
|
||||
@@ -455,8 +452,8 @@ int actual_open_alsa_device(int do_auto_setup) {
|
||||
ret = snd_pcm_hw_params_any(alsa_handle, alsa_params);
|
||||
if (ret < 0) {
|
||||
die("audio_alsa: Broken configuration for device \"%s\": no configurations "
|
||||
"available",
|
||||
alsa_out_dev);
|
||||
"available",
|
||||
alsa_out_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -485,7 +482,6 @@ int actual_open_alsa_device(int do_auto_setup) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
ret = snd_pcm_hw_params_set_channels(alsa_handle, alsa_params, 2);
|
||||
if (ret < 0) {
|
||||
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;
|
||||
|
||||
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)) {
|
||||
sf = fr[config.output_format].alsa_code;
|
||||
frame_size = fr[config.output_format].frame_size;
|
||||
} else {
|
||||
warn("alsa: unexpected output format %d. Set to S16_LE.",config.output_format);
|
||||
config.output_format = SPS_FORMAT_S16_LE;
|
||||
sf = fr[config.output_format].alsa_code;
|
||||
frame_size = fr[config.output_format].frame_size;
|
||||
}
|
||||
ret = snd_pcm_hw_params_set_format(alsa_handle, alsa_params, sf);
|
||||
if (ret < 0) {
|
||||
warn("audio_alsa: Alsa sample format %d not available for device \"%s\": %s", sf,
|
||||
alsa_out_dev, snd_strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
if ((config.output_format > SPS_FORMAT_UNKNOWN) && (config.output_format < SPS_FORMAT_AUTO)) {
|
||||
sf = fr[config.output_format].alsa_code;
|
||||
frame_size = fr[config.output_format].frame_size;
|
||||
} else {
|
||||
warn("alsa: unexpected output format %d. Set to S16_LE.", config.output_format);
|
||||
config.output_format = SPS_FORMAT_S16_LE;
|
||||
sf = fr[config.output_format].alsa_code;
|
||||
frame_size = fr[config.output_format].frame_size;
|
||||
}
|
||||
ret = snd_pcm_hw_params_set_format(alsa_handle, alsa_params, sf);
|
||||
if (ret < 0) {
|
||||
warn("audio_alsa: Alsa sample format %d not available for device \"%s\": %s", sf,
|
||||
alsa_out_dev, snd_strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
} else { // auto format
|
||||
int number_of_formats_to_try;
|
||||
enum sps_format_t *formats;
|
||||
formats = auto_format_check_sequence;
|
||||
number_of_formats_to_try = sizeof(auto_format_check_sequence)/sizeof(sps_format_t);
|
||||
int i = 0;
|
||||
int format_found = 0;
|
||||
enum sps_format_t trial_format = SPS_FORMAT_UNKNOWN;
|
||||
while ((i < number_of_formats_to_try) && (format_found == 0)) {
|
||||
trial_format = formats[i];
|
||||
sf = fr[trial_format].alsa_code;
|
||||
frame_size = fr[trial_format].frame_size;
|
||||
ret = snd_pcm_hw_params_set_format(alsa_handle, alsa_params, sf);
|
||||
if (ret == 0)
|
||||
format_found = 1;
|
||||
else
|
||||
i++;
|
||||
}
|
||||
if (ret == 0) {
|
||||
config.output_format = trial_format;
|
||||
debug(1,"alsa: output format chosen is \"%s\".",sps_format_description_string(config.output_format));
|
||||
} else {
|
||||
warn("audio_alsa: Could not automatically set the output format for device \"%s\": %s",
|
||||
alsa_out_dev, snd_strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
int number_of_formats_to_try;
|
||||
enum sps_format_t *formats;
|
||||
formats = auto_format_check_sequence;
|
||||
number_of_formats_to_try = sizeof(auto_format_check_sequence) / sizeof(sps_format_t);
|
||||
int i = 0;
|
||||
int format_found = 0;
|
||||
enum sps_format_t trial_format = SPS_FORMAT_UNKNOWN;
|
||||
while ((i < number_of_formats_to_try) && (format_found == 0)) {
|
||||
trial_format = formats[i];
|
||||
sf = fr[trial_format].alsa_code;
|
||||
frame_size = fr[trial_format].frame_size;
|
||||
ret = snd_pcm_hw_params_set_format(alsa_handle, alsa_params, sf);
|
||||
if (ret == 0)
|
||||
format_found = 1;
|
||||
else
|
||||
i++;
|
||||
}
|
||||
if (ret == 0) {
|
||||
config.output_format = trial_format;
|
||||
debug(1, "alsa: output format chosen is \"%s\".",
|
||||
sps_format_description_string(config.output_format));
|
||||
} else {
|
||||
warn("audio_alsa: Could not automatically set the output format for device \"%s\": %s",
|
||||
alsa_out_dev, snd_strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
ret = snd_pcm_hw_params_set_rate_near(alsa_handle, alsa_params, &actual_sample_rate, &dir);
|
||||
if (ret < 0) {
|
||||
warn("audio_alsa: Rate %iHz not available for playback: %s", config.output_rate,
|
||||
snd_strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
int number_of_speeds_to_try;
|
||||
unsigned int *speeds;
|
||||
actual_sample_rate =
|
||||
config.output_rate; // this is the requested rate -- it'll be changed to the actual rate
|
||||
ret = snd_pcm_hw_params_set_rate_near(alsa_handle, alsa_params, &actual_sample_rate, &dir);
|
||||
if (ret < 0) {
|
||||
warn("audio_alsa: Rate %iHz not available for playback: %s", config.output_rate,
|
||||
snd_strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
int number_of_speeds_to_try;
|
||||
unsigned int *speeds;
|
||||
|
||||
speeds = auto_speed_output_rates;
|
||||
number_of_speeds_to_try = sizeof(auto_speed_output_rates)/sizeof(int);
|
||||
speeds = auto_speed_output_rates;
|
||||
number_of_speeds_to_try = sizeof(auto_speed_output_rates) / sizeof(int);
|
||||
|
||||
int i = 0;
|
||||
int speed_found = 0;
|
||||
int i = 0;
|
||||
int speed_found = 0;
|
||||
|
||||
while ((i < number_of_speeds_to_try) && (speed_found == 0)) {
|
||||
actual_sample_rate = speeds[i];
|
||||
ret = snd_pcm_hw_params_set_rate_near(alsa_handle, alsa_params, &actual_sample_rate, &dir);
|
||||
if (ret == 0) {
|
||||
speed_found = 1;
|
||||
if (actual_sample_rate != speeds[i])
|
||||
warn("Speed requested: %d. Speed available: %d.",speeds[i],actual_sample_rate);
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
config.output_rate = actual_sample_rate;
|
||||
debug(1,"alsa: output speed chosen is %d.",config.output_rate);
|
||||
} else {
|
||||
warn("audio_alsa: Could not automatically set the output rate for device \"%s\": %s",
|
||||
alsa_out_dev, snd_strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
while ((i < number_of_speeds_to_try) && (speed_found == 0)) {
|
||||
actual_sample_rate = speeds[i];
|
||||
ret = snd_pcm_hw_params_set_rate_near(alsa_handle, alsa_params, &actual_sample_rate, &dir);
|
||||
if (ret == 0) {
|
||||
speed_found = 1;
|
||||
if (actual_sample_rate != speeds[i])
|
||||
warn("Speed requested: %d. Speed available: %d.", speeds[i], actual_sample_rate);
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
config.output_rate = actual_sample_rate;
|
||||
debug(1, "alsa: output speed chosen is %d.", config.output_rate);
|
||||
} else {
|
||||
warn("audio_alsa: Could not automatically set the output rate for device \"%s\": %s",
|
||||
alsa_out_dev, snd_strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (set_period_size_request != 0) {
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
if (ret < 0) {
|
||||
@@ -683,8 +681,7 @@ int actual_open_alsa_device(int do_auto_setup) {
|
||||
|
||||
ret = snd_pcm_prepare(alsa_handle);
|
||||
if (ret < 0) {
|
||||
warn("audio_alsa: Unable to prepare the device: \"%s\": %s.", alsa_out_dev,
|
||||
snd_strerror(ret));
|
||||
warn("audio_alsa: Unable to prepare the device: \"%s\": %s.", alsa_out_dev, snd_strerror(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);
|
||||
}
|
||||
|
||||
|
||||
if (config.use_precision_timing == YNA_YES)
|
||||
delay_and_status = precision_delay_and_status;
|
||||
else if (config.use_precision_timing == YNA_AUTO) {
|
||||
if (precision_delay_available()) {
|
||||
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*/
|
||||
if (config_lookup_string(config.cfg, "alsa.output_format", &str)) {
|
||||
int temp_output_format_auto_requested = config.output_format_auto_requested;
|
||||
config.output_format_auto_requested = 0; // assume a valid format will be given.
|
||||
int temp_output_format_auto_requested = config.output_format_auto_requested;
|
||||
config.output_format_auto_requested = 0; // assume a valid format will be given.
|
||||
if (strcasecmp(str, "S16") == 0)
|
||||
config.output_format = SPS_FORMAT_S16;
|
||||
else if (strcasecmp(str, "S16_LE") == 0)
|
||||
@@ -1137,48 +1132,54 @@ static int init(int argc, char **argv) {
|
||||
else if (strcasecmp(str, "auto") == 0)
|
||||
config.output_format_auto_requested = 1;
|
||||
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\", "
|
||||
"\"S16\", \"S24\", \"S24_LE\", \"S24_BE\", "
|
||||
"\"S24_3LE\", \"S24_3BE\" or "
|
||||
"\"S32\", \"S32_LE\", \"S32_BE\". It remains set to \"%s\".", str,
|
||||
config.output_format_auto_requested == 1 ? "auto" : sps_format_description_string(config.output_format));
|
||||
"\"S32\", \"S32_LE\", \"S32_BE\". It remains set to \"%s\".",
|
||||
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 (strcasecmp(str, "auto") == 0) {
|
||||
config.output_rate_auto_requested = 1;
|
||||
} else {
|
||||
if (config.output_rate_auto_requested == 1)
|
||||
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);
|
||||
else
|
||||
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);
|
||||
}
|
||||
}
|
||||
if (strcasecmp(str, "auto") == 0) {
|
||||
config.output_rate_auto_requested = 1;
|
||||
} else {
|
||||
if (config.output_rate_auto_requested == 1)
|
||||
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);
|
||||
else
|
||||
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*/
|
||||
if (config_lookup_int(config.cfg, "alsa.output_rate", &value)) {
|
||||
debug(1, "alsa output rate is %d frames per second", value);
|
||||
switch (value) {
|
||||
case 44100:
|
||||
case 88200:
|
||||
case 176400:
|
||||
case 352800:
|
||||
config.output_rate = value;
|
||||
config.output_rate_auto_requested = 0;
|
||||
break;
|
||||
default:
|
||||
if (config.output_rate_auto_requested == 1)
|
||||
warn("Invalid output rate \"%d\". It should be \"auto\", 44100, 88200, 176400 or 352800. "
|
||||
"It remains set to \"auto\".",value);
|
||||
else
|
||||
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 output rate, which must be a multiple of 44,100*/
|
||||
if (config_lookup_int(config.cfg, "alsa.output_rate", &value)) {
|
||||
debug(1, "alsa output rate is %d frames per second", value);
|
||||
switch (value) {
|
||||
case 44100:
|
||||
case 88200:
|
||||
case 176400:
|
||||
case 352800:
|
||||
config.output_rate = value;
|
||||
config.output_rate_auto_requested = 0;
|
||||
break;
|
||||
default:
|
||||
if (config.output_rate_auto_requested == 1)
|
||||
warn("Invalid output rate \"%d\". It should be \"auto\", 44100, 88200, 176400 or 352800. "
|
||||
"It remains set to \"auto\".",
|
||||
value);
|
||||
else
|
||||
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. */
|
||||
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. */
|
||||
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;
|
||||
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.keep_dac_busy = 1;
|
||||
} else if (strcasecmp(str, "auto") == 0)
|
||||
@@ -1245,15 +1247,17 @@ static int init(int argc, char **argv) {
|
||||
else {
|
||||
warn("Invalid disable_standby_mode option choice \"%s\". It should be "
|
||||
"\"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 ((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;
|
||||
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.keep_dac_busy = 1;
|
||||
} else if (strcasecmp(str, "auto") == 0)
|
||||
@@ -1261,11 +1265,17 @@ static int init(int argc, char **argv) {
|
||||
else {
|
||||
warn("Invalid use_precision_timing option choice \"%s\". It should be "
|
||||
"\"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
|
||||
@@ -1362,12 +1372,13 @@ int set_mute_state() {
|
||||
close_mixer();
|
||||
}
|
||||
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);
|
||||
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.");
|
||||
|
||||
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;
|
||||
if (using_update_timestamps)
|
||||
*using_update_timestamps = YNDK_NO;
|
||||
*state = snd_pcm_state(alsa_handle);
|
||||
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 {
|
||||
// not running, thus no delay information, thus can't check for frame
|
||||
// rates
|
||||
// not running, thus no delay information, thus can't check for frame
|
||||
// rates
|
||||
frame_index = 0; // we'll be starting over...
|
||||
measurement_data_is_valid = 0;
|
||||
*delay = 0;
|
||||
@@ -1402,7 +1414,8 @@ int standard_delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay,
|
||||
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_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);
|
||||
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
|
||||
snd_pcm_status_get_htstamp(alsa_snd_pcm_status, &update_timestamp);
|
||||
snd_pcm_status_get_htstamp(alsa_snd_pcm_status, &update_timestamp);
|
||||
#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
|
||||
|
||||
*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;
|
||||
}
|
||||
|
||||
// user information
|
||||
// user information
|
||||
if (update_timestamp_ns == 0) {
|
||||
if (delay_type_notified != 1) {
|
||||
debug(2,"alsa: update timestamps unavailable");
|
||||
debug(2, "alsa: update timestamps unavailable");
|
||||
delay_type_notified = 1;
|
||||
}
|
||||
} else {
|
||||
// diagnostic
|
||||
// diagnostic
|
||||
if (delay_type_notified != 0) {
|
||||
debug(2,"alsa: update timestamps available");
|
||||
debug(2, "alsa: update timestamps available");
|
||||
delay_type_notified = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (update_timestamp_ns == 0) {
|
||||
ret = snd_pcm_delay (alsa_handle,delay);
|
||||
ret = snd_pcm_delay(alsa_handle, delay);
|
||||
} else {
|
||||
*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
|
||||
// the check for monotonic returns true. Might have to watch out for this.
|
||||
#if SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR < 28
|
||||
clock_gettime(CLOCK_REALTIME, &tn);
|
||||
#else
|
||||
clock_gettime(CLOCK_MONOTONIC, &tn);
|
||||
#endif
|
||||
*/
|
||||
/*
|
||||
// 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.
|
||||
#if SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR < 28
|
||||
clock_gettime(CLOCK_REALTIME, &tn);
|
||||
#else
|
||||
clock_gettime(CLOCK_MONOTONIC, &tn);
|
||||
#endif
|
||||
*/
|
||||
|
||||
if (use_monotonic_clock)
|
||||
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"
|
||||
", update_timestamp: %lx,%lx, stall_monitor_start_time %" PRIX64
|
||||
", stall_monitor_error_threshold %" PRIX64 ".",
|
||||
tn.tv_sec, tn.tv_nsec, update_timestamp.tv_sec, update_timestamp.tv_nsec, stall_monitor_start_time,
|
||||
stall_monitor_error_threshold);
|
||||
tn.tv_sec, tn.tv_nsec, update_timestamp.tv_sec, update_timestamp.tv_nsec,
|
||||
stall_monitor_start_time, stall_monitor_error_threshold);
|
||||
ret = sps_extra_code_output_stalled;
|
||||
}
|
||||
} else {
|
||||
@@ -1649,9 +1662,9 @@ int do_play(void *buf, int samples) {
|
||||
} else {
|
||||
char errorstring[1024];
|
||||
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 {
|
||||
@@ -1741,9 +1754,9 @@ int play(void *buf, int samples) {
|
||||
alsa_backend_state = abm_playing;
|
||||
|
||||
// mute_requested_internally = 0; // stop requesting a mute for backend's own
|
||||
// reasons, which might have been a flush
|
||||
//debug(2, "play() set_mute_state");
|
||||
//set_mute_state(); // try to action the request and return a status
|
||||
// reasons, which might have been a flush
|
||||
// debug(2, "play() set_mute_state");
|
||||
// set_mute_state(); // try to action the request and return a status
|
||||
// do_mute(0); // unmute for backend's reason
|
||||
}
|
||||
ret = do_play(buf, samples);
|
||||
@@ -1755,7 +1768,7 @@ int play(void *buf, int samples) {
|
||||
}
|
||||
|
||||
int prepare(void) {
|
||||
// this will leave the DAC open / connected.
|
||||
// this will leave the DAC open / connected.
|
||||
int ret = 0;
|
||||
|
||||
pthread_cleanup_debug_mutex_lock(&alsa_mutex, 50000, 0);
|
||||
@@ -1764,7 +1777,6 @@ int prepare(void) {
|
||||
ret = do_open(1); // do auto setup
|
||||
if (ret == 0)
|
||||
debug(2, "alsa: prepare() -- opened output device");
|
||||
|
||||
}
|
||||
|
||||
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_threshold_exceeded = 0;
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
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
|
||||
// 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 */.
|
||||
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;
|
||||
long buffer_size = 0;
|
||||
snd_pcm_state_t state;
|
||||
@@ -1976,9 +1990,13 @@ void *alsa_buffer_monitor_thread_code(__attribute__((unused)) void *arg) {
|
||||
error_count++;
|
||||
char errorstring[1024];
|
||||
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)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"); }
|
||||
|
||||
|
||||
audio_output audio_dummy = {.name = "dummy",
|
||||
.help = NULL,
|
||||
.init = &init,
|
||||
|
||||
+36
-39
@@ -20,10 +20,10 @@
|
||||
|
||||
#include "audio.h"
|
||||
#include "common.h"
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.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!
|
||||
#define NPORTS 2
|
||||
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_nframes_t sample_rate;
|
||||
@@ -76,7 +76,6 @@ static int flush_please = 0;
|
||||
static jack_latency_range_t latest_latency_range[NPORTS];
|
||||
static int64_t time_of_latest_transfer;
|
||||
|
||||
|
||||
static inline jack_default_audio_sample_t sample_conv(short sample) {
|
||||
// It sounds correct, but I don't understand it.
|
||||
// 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,
|
||||
jack_default_audio_sample_t* jack_output_buffer[],
|
||||
jack_nframes_t offset,
|
||||
jack_nframes_t nframes) {
|
||||
jack_default_audio_sample_t *jack_output_buffer[],
|
||||
jack_nframes_t offset, jack_nframes_t nframes) {
|
||||
jack_nframes_t f;
|
||||
// We're dealing with 16bit audio here:
|
||||
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) {
|
||||
jack_default_audio_sample_t *buffer[NPORTS];
|
||||
// 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;
|
||||
int frames_written = 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;
|
||||
if (thisbuf > nframes) {
|
||||
frames_required = nframes;
|
||||
} else {
|
||||
} else {
|
||||
frames_required = thisbuf;
|
||||
}
|
||||
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
|
||||
// have changed, so we recompute the latency.
|
||||
static int graph(__attribute__((unused)) void * arg) {
|
||||
static int graph(__attribute__((unused)) void *arg) {
|
||||
int latency = 0;
|
||||
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]);
|
||||
debug(2, "JACK latency for port %s\tmin: %d\t max: %d",
|
||||
port_name[i], latest_latency_range[i].min, latest_latency_range[i].max);
|
||||
debug(2, "JACK latency for port %s\tmin: %d\t max: %d", port_name[i],
|
||||
latest_latency_range[i].min, latest_latency_range[i].max);
|
||||
latency += latest_latency_range[i].max;
|
||||
}
|
||||
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.
|
||||
static void error(const char *desc) {
|
||||
warn("JACK error: \"%s\"", desc);
|
||||
}
|
||||
static void error(const char *desc) { warn("JACK error: \"%s\"", desc); }
|
||||
|
||||
// This is the function JACK will call in case of a non-critical event in the library.
|
||||
static void info(const char *desc) {
|
||||
inform("JACK information: \"%s\"", desc);
|
||||
}
|
||||
static void info(const char *desc) { inform("JACK information: \"%s\"", desc); }
|
||||
|
||||
int jack_init(__attribute__((unused)) int argc, __attribute__((unused)) char **argv) {
|
||||
int i;
|
||||
@@ -221,15 +215,16 @@ int jack_init(__attribute__((unused)) int argc, __attribute__((unused)) char **a
|
||||
sample_rate = jack_get_sample_rate(client);
|
||||
if (sample_rate != 44100) {
|
||||
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_graph_order_callback(client, &graph, NULL);
|
||||
jack_set_error_function(&error);
|
||||
jack_set_info_function(&info);
|
||||
for (i=0; i < NPORTS; i++) {
|
||||
port[i] = jack_port_register(client, port_name[i], JACK_DEFAULT_AUDIO_TYPE,
|
||||
JackPortIsOutput, 0);
|
||||
for (i = 0; i < NPORTS; i++) {
|
||||
port[i] =
|
||||
jack_port_register(client, port_name[i], JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
|
||||
}
|
||||
if (jack_activate(client)) {
|
||||
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) {
|
||||
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.
|
||||
// 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);
|
||||
if (port_list != NULL) {
|
||||
for (i = 0; i < NPORTS ; i++) {
|
||||
char* full_port_name[NPORTS];
|
||||
for (i = 0; i < NPORTS; i++) {
|
||||
char *full_port_name[NPORTS];
|
||||
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]);
|
||||
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]);
|
||||
switch (err) {
|
||||
case EEXIST:
|
||||
inform("The requested connection from %s to %s already exists.",
|
||||
full_port_name[i], port_list[i]);
|
||||
inform("The requested connection from %s to %s already exists.", full_port_name[i],
|
||||
port_list[i]);
|
||||
break;
|
||||
case 0:
|
||||
// success
|
||||
break;
|
||||
default:
|
||||
warn("JACK error no. %d occured while trying to connect %s to %s.",
|
||||
err, full_port_name[i], port_list[i]);
|
||||
warn("JACK error no. %d occured while trying to connect %s to %s.", err,
|
||||
full_port_name[i], port_list[i]);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
@@ -272,7 +268,8 @@ int jack_init(__attribute__((unused)) int argc, __attribute__((unused)) char **a
|
||||
free(full_port_name[i]);
|
||||
}
|
||||
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);
|
||||
}
|
||||
@@ -316,10 +313,10 @@ int jack_delay(long *the_delay) {
|
||||
// occupancy after another transfer had occurred, so we could "lose" a full transfer
|
||||
// (e.g. 1024 frames @ 44,100 fps ~ 23.2 milliseconds)
|
||||
pthread_mutex_lock(&buffer_mutex);
|
||||
int64_t time_now = get_absolute_time_in_fp();
|
||||
int64_t delta = time_now - time_of_latest_transfer;
|
||||
size_t audio_occupancy_now = jack_ringbuffer_read_space(jackbuf) / bytes_per_frame;
|
||||
debug(2, "audio_occupancy_now is %d.", audio_occupancy_now);
|
||||
int64_t time_now = get_absolute_time_in_fp();
|
||||
int64_t delta = time_now - time_of_latest_transfer;
|
||||
size_t audio_occupancy_now = jack_ringbuffer_read_space(jackbuf) / bytes_per_frame;
|
||||
debug(2, "audio_occupancy_now is %d.", audio_occupancy_now);
|
||||
pthread_mutex_unlock(&buffer_mutex);
|
||||
|
||||
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;
|
||||
// It's ok to lock here since we're not in the realtime callback:
|
||||
pthread_mutex_lock(&buffer_mutex);
|
||||
bytes_transferred = jack_ringbuffer_write(jackbuf, buf, bytes_to_transfer);
|
||||
time_of_latest_transfer = get_absolute_time_in_fp();
|
||||
bytes_transferred = jack_ringbuffer_write(jackbuf, buf, bytes_to_transfer);
|
||||
time_of_latest_transfer = get_absolute_time_in_fp();
|
||||
pthread_mutex_unlock(&buffer_mutex);
|
||||
if (bytes_transferred < bytes_to_transfer) {
|
||||
warn("JACK ringbuffer overrun. Only wrote %d of %d bytes.",
|
||||
bytes_transferred, bytes_to_transfer);
|
||||
warn("JACK ringbuffer overrun. Only wrote %d of %d bytes.", bytes_transferred,
|
||||
bytes_to_transfer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
+4
-3
@@ -47,15 +47,16 @@ int warned = 0;
|
||||
static void start(__attribute__((unused)) int sample_rate,
|
||||
__attribute__((unused)) int sample_format) {
|
||||
|
||||
|
||||
// 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:
|
||||
// "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);
|
||||
if ((fd == -1) && (errno != ENXIO) && (warned == 0)) {
|
||||
char errorstring[1024];
|
||||
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);
|
||||
warned = 1;
|
||||
}
|
||||
|
||||
+2
-3
@@ -76,7 +76,8 @@ struct sndio_formats {
|
||||
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},
|
||||
{"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_3LE", SPS_FORMAT_S24_3LE, 44100, 24, 3, 1, 1},
|
||||
{"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;
|
||||
at_least_one_onmove_cb_seen = 0;
|
||||
|
||||
|
||||
for (i = 0; i < sizeof(formats) / sizeof(formats[0]); i++) {
|
||||
if (formats[i].fmt == config.output_format) {
|
||||
par.bits = formats[i].bits;
|
||||
@@ -201,7 +201,6 @@ static int init(int argc, char **argv) {
|
||||
if (!found)
|
||||
die("sndio: could not set output device to the required format and rate.");
|
||||
|
||||
|
||||
framesize = par.bps * par.pchan;
|
||||
config.output_rate = par.rate;
|
||||
config.audio_backend_buffer_desired_length = 1.0 * par.bufsz / par.rate;
|
||||
|
||||
+2
-3
@@ -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_count = fill_bytes / outstream->bytes_per_frame;
|
||||
|
||||
debug(3,
|
||||
"[--->>] frame_count_min: %d , frame_count_max: %d , fill_bytes: %d , fill_count: %d , "
|
||||
"outstream->bytes_per_frame: %d",
|
||||
debug(3, "[--->>] frame_count_min: %d , frame_count_max: %d , fill_bytes: %d , fill_count: %d , "
|
||||
"outstream->bytes_per_frame: %d",
|
||||
frame_count_min, frame_count_max, fill_bytes, fill_count, outstream->bytes_per_frame);
|
||||
|
||||
if (frame_count_min > fill_count) {
|
||||
|
||||
@@ -87,9 +87,11 @@
|
||||
void set_alsa_out_dev(char *);
|
||||
#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))
|
||||
return sps_format_description_string_array[format];
|
||||
else
|
||||
@@ -115,12 +117,10 @@ void do_sps_log(__attribute__((unused)) int prio, const char *t, ...) {
|
||||
va_start(args, t);
|
||||
vsnprintf(s, sizeof(s), t, args);
|
||||
va_end(args);
|
||||
fprintf(stderr,"%s\n",s);
|
||||
fprintf(stderr, "%s\n", s);
|
||||
}
|
||||
|
||||
void log_to_stderr() {
|
||||
sps_log = do_sps_log;
|
||||
}
|
||||
void log_to_stderr() { sps_log = do_sps_log; }
|
||||
|
||||
shairport_cfg config;
|
||||
|
||||
@@ -436,7 +436,7 @@ char *base64_enc(uint8_t *input, int length) {
|
||||
b64 = BIO_push(b64, bmem);
|
||||
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
||||
BIO_write(b64, input, length);
|
||||
(void) BIO_flush(b64);
|
||||
(void)BIO_flush(b64);
|
||||
BIO_get_mem_ptr(b64, &bptr);
|
||||
|
||||
char *buf = (char *)malloc(bptr->length);
|
||||
@@ -468,7 +468,7 @@ uint8_t *base64_dec(char *input, int *outlen) {
|
||||
BIO_write(bmem, input, inlen);
|
||||
while (inlen++ & 3)
|
||||
BIO_write(bmem, "=", 1);
|
||||
(void) BIO_flush(bmem);
|
||||
(void)BIO_flush(bmem);
|
||||
|
||||
int bufsize = strlen(input) * 3 / 4 + 1;
|
||||
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) {
|
||||
|
||||
// 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
|
||||
// "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
|
||||
// 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
|
||||
// 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
|
||||
// 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
|
||||
// Third: {-17,lv} giving a fast slope from y=0 at x=-19 to y=-60 at x=-30
|
||||
// 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
|
||||
// "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
|
||||
// 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
|
||||
// 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
|
||||
// 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
|
||||
// Third: {-17,lv} giving a fast slope from y=0 at x=-19 to y=-60 at x=-30
|
||||
|
||||
#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) {
|
||||
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
|
||||
@@ -1189,9 +1189,8 @@ int sps_pthread_mutex_timedlock(pthread_mutex_t *mutex, useconds_t dally_time,
|
||||
et = (et * 1000000) >> 32; // microseconds
|
||||
char errstr[1000];
|
||||
if (r == ETIMEDOUT)
|
||||
debug(debuglevel,
|
||||
"timed out waiting for a mutex, having waiting %f seconds, with a maximum "
|
||||
"waiting time of %d microseconds. \"%s\".",
|
||||
debug(debuglevel, "timed out waiting for a mutex, having waiting %f seconds, with a maximum "
|
||||
"waiting time of %d microseconds. \"%s\".",
|
||||
(1.0 * et) / 1000000, dally_time, debugmessage);
|
||||
else
|
||||
debug(debuglevel, "error %d: \"%s\" waiting for a mutex: \"%s\".", r,
|
||||
@@ -1293,10 +1292,10 @@ char *get_version_string() {
|
||||
strcpy(version_string, PACKAGE_VERSION);
|
||||
|
||||
#ifdef CONFIG_LIBDAEMON
|
||||
strcat(version_string, "-libdaemon");
|
||||
strcat(version_string, "-libdaemon");
|
||||
#endif
|
||||
#ifdef CONFIG_MBEDTLS
|
||||
strcat(version_string, "-mbedTLS");
|
||||
strcat(version_string, "-mbedTLS");
|
||||
#endif
|
||||
#ifdef CONFIG_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;
|
||||
default:
|
||||
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;
|
||||
previous_random_number = r;
|
||||
|
||||
@@ -34,18 +34,10 @@ enum dbus_session_type {
|
||||
#define sps_extra_code_output_state_cannot_make_ready 32769
|
||||
|
||||
// yeah/no/auto
|
||||
enum yna_type {
|
||||
YNA_AUTO = -1,
|
||||
YNA_NO = 0,
|
||||
YNA_YES = 1
|
||||
} yna_type;
|
||||
enum yna_type { YNA_AUTO = -1, YNA_NO = 0, YNA_YES = 1 } yna_type;
|
||||
|
||||
// yeah/no/dont-care
|
||||
enum yndk_type {
|
||||
YNDK_DONT_KNOW = -1,
|
||||
YNDK_NO = 0,
|
||||
YNDK_YES = 1
|
||||
} yndk_type;
|
||||
enum yndk_type { YNDK_DONT_KNOW = -1, YNDK_NO = 0, YNDK_YES = 1 } yndk_type;
|
||||
|
||||
enum endian_type {
|
||||
SS_LITTLE_ENDIAN = 0,
|
||||
@@ -56,7 +48,7 @@ enum endian_type {
|
||||
enum stuffing_type {
|
||||
ST_basic = 0, // straight deletion or insertion of a frame in a 352-frame packet
|
||||
ST_soxr, // use libsoxr to make a 352 frame packet one frame longer or shorter
|
||||
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;
|
||||
|
||||
enum playback_mode_type {
|
||||
@@ -105,7 +97,7 @@ enum sps_format_t {
|
||||
SPS_FORMAT_INVALID,
|
||||
} 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 {
|
||||
config_t *cfg;
|
||||
@@ -172,7 +164,7 @@ typedef struct {
|
||||
uint32_t userSuppliedLatency; // overrides all other latencies -- use with caution
|
||||
uint32_t fixedLatencyOffset; // add this to all automatic latencies supplied to get the actual
|
||||
// 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
|
||||
int daemonise;
|
||||
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
|
||||
enum stuffing_type packet_stuffing;
|
||||
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 use_apple_decoder; // set to 1 if you want to use the apple decoder instead of the original by
|
||||
// David Hammerton
|
||||
@@ -215,16 +208,18 @@ typedef struct {
|
||||
// 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 active_state_timeout; // the amount of time from when play ends to when the system leaves
|
||||
// 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
|
||||
// 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
|
||||
// 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
|
||||
// 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
|
||||
// sw attenuation
|
||||
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;
|
||||
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;
|
||||
|
||||
#ifdef CONFIG_CONVOLUTION
|
||||
@@ -283,7 +278,8 @@ int get_requested_connection_state_to_output();
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
#include <netinet/in.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "metadata_hub.h"
|
||||
@@ -112,10 +112,7 @@ static void response_code(void *opaque, int code) {
|
||||
}
|
||||
|
||||
static const struct http_funcs responseFuncs = {
|
||||
response_realloc,
|
||||
response_body,
|
||||
response_header,
|
||||
response_code,
|
||||
response_realloc, response_body, response_header, response_code,
|
||||
};
|
||||
|
||||
// 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,"dacp_conversation_lock released.");
|
||||
} else {
|
||||
debug(3,
|
||||
"dacp_send_command: could not acquire a lock on the dacp transmit/receive section "
|
||||
"when attempting to "
|
||||
"send the command \"%s\". Possible timeout?",
|
||||
debug(3, "dacp_send_command: could not acquire a lock on the dacp transmit/receive section "
|
||||
"when attempting to "
|
||||
"send the command \"%s\". Possible timeout?",
|
||||
command);
|
||||
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)
|
||||
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
|
||||
dacp_server.dacp_id[0] = '\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) {
|
||||
debug_mutex_lock(&dacp_server_information_lock, 500000, 2);
|
||||
debug(3,
|
||||
"dacp_monitor_port_update_callback with Remote ID \"%s\", target ID \"%s\" and port "
|
||||
"number %d.",
|
||||
debug(3, "dacp_monitor_port_update_callback with Remote ID \"%s\", target ID \"%s\" and port "
|
||||
"number %d.",
|
||||
dacp_id, dacp_server.dacp_id, port);
|
||||
if (strcmp(dacp_id, dacp_server.dacp_id) == 0) {
|
||||
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.dacp_server_active = 0;
|
||||
metadata_store.advanced_dacp_server_active = 0;
|
||||
debug(2,
|
||||
"setting dacp_server_active and advanced_dacp_server_active to 0 with an update "
|
||||
"flag value of %d",
|
||||
debug(2, "setting dacp_server_active and advanced_dacp_server_active to 0 with an update "
|
||||
"flag value of %d",
|
||||
ch);
|
||||
metadata_hub_modify_epilog(ch);
|
||||
while (dacp_server.scan_enable == 0) {
|
||||
|
||||
+34
-34
@@ -433,12 +433,14 @@ gboolean notify_drift_tolerance_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);
|
||||
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.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.keep_dac_busy = 1;
|
||||
} else if (strcasecmp(th, "auto") == 0)
|
||||
@@ -446,17 +448,17 @@ gboolean notify_disable_standby_mode_callback(ShairportSync *skeleton,
|
||||
else {
|
||||
warn("An unrecognised disable_standby_mode: \"%s\" was requested via D-Bus interface.", th);
|
||||
switch (config.disable_standby_mode) {
|
||||
case disable_standby_off:
|
||||
shairport_sync_set_disable_standby_mode(skeleton, "off");
|
||||
break;
|
||||
case disable_standby_always:
|
||||
shairport_sync_set_disable_standby_mode(skeleton, "always");
|
||||
break;
|
||||
case disable_standby_auto:
|
||||
shairport_sync_set_disable_standby_mode(skeleton, "auto");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
case disable_standby_off:
|
||||
shairport_sync_set_disable_standby_mode(skeleton, "off");
|
||||
break;
|
||||
case disable_standby_always:
|
||||
shairport_sync_set_disable_standby_mode(skeleton, "always");
|
||||
break;
|
||||
case disable_standby_auto:
|
||||
shairport_sync_set_disable_standby_mode(skeleton, "auto");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
@@ -661,7 +663,7 @@ static void on_dbus_name_acquired(GDBusConnection *connection, const gchar *name
|
||||
G_CALLBACK(notify_alacdecoder_callback), NULL);
|
||||
g_signal_connect(shairportSyncSkeleton, "notify::disable-standby-mode",
|
||||
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_signal_connect(shairportSyncSkeleton, "notify::disable-standby",
|
||||
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\"");
|
||||
|
||||
switch (config.disable_standby_mode) {
|
||||
case disable_standby_off:
|
||||
shairport_sync_set_disable_standby_mode(SHAIRPORT_SYNC(shairportSyncSkeleton), "off");
|
||||
debug(1, ">> disable standby mode set to \"off\"");
|
||||
break;
|
||||
case disable_standby_always:
|
||||
shairport_sync_set_disable_standby_mode(SHAIRPORT_SYNC(shairportSyncSkeleton), "always");
|
||||
debug(1, ">> disable standby mode set to \"always\"");
|
||||
break;
|
||||
case disable_standby_auto:
|
||||
shairport_sync_set_disable_standby_mode(SHAIRPORT_SYNC(shairportSyncSkeleton), "auto");
|
||||
debug(1, ">> disable standby mode set to \"auto\"");
|
||||
break;
|
||||
default:
|
||||
debug(1,"invalid disable_standby mode!");
|
||||
break;
|
||||
case disable_standby_off:
|
||||
shairport_sync_set_disable_standby_mode(SHAIRPORT_SYNC(shairportSyncSkeleton), "off");
|
||||
debug(1, ">> disable standby mode set to \"off\"");
|
||||
break;
|
||||
case disable_standby_always:
|
||||
shairport_sync_set_disable_standby_mode(SHAIRPORT_SYNC(shairportSyncSkeleton), "always");
|
||||
debug(1, ">> disable standby mode set to \"always\"");
|
||||
break;
|
||||
case disable_standby_auto:
|
||||
shairport_sync_set_disable_standby_mode(SHAIRPORT_SYNC(shairportSyncSkeleton), "auto");
|
||||
debug(1, ">> disable standby mode set to \"auto\"");
|
||||
break;
|
||||
default:
|
||||
debug(1, "invalid disable_standby mode!");
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SOXR
|
||||
@@ -902,9 +904,7 @@ void stop_dbus_service() {
|
||||
g_bus_unown_name(ownerID);
|
||||
else
|
||||
debug(1, "Zero OwnerID for \"org.gnome.ShairportSync\".");
|
||||
service_is_running = 0;
|
||||
service_is_running = 0;
|
||||
}
|
||||
|
||||
int dbus_service_is_running() {
|
||||
return service_is_running;
|
||||
}
|
||||
int dbus_service_is_running() { return service_is_running; }
|
||||
|
||||
+1
-1
@@ -24,8 +24,8 @@
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "mdns.h"
|
||||
#include "common.h"
|
||||
#include <arpa/inet.h>
|
||||
#include <dns_sd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
+13
-13
@@ -46,8 +46,8 @@
|
||||
#include "metadata_hub.h"
|
||||
|
||||
#ifdef CONFIG_MBEDTLS
|
||||
#include <mbedtls/version.h>
|
||||
#include <mbedtls/md5.h>
|
||||
#include <mbedtls/version.h>
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
uint8_t img_md5[16];
|
||||
// uint8_t ap_md5[16];
|
||||
// uint8_t ap_md5[16];
|
||||
|
||||
#ifdef CONFIG_OPENSSL
|
||||
MD5_CTX ctx;
|
||||
@@ -233,17 +233,17 @@ char *metadata_write_image_file(const char *buf, int len) {
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MBEDTLS
|
||||
#if MBEDTLS_VERSION_MINOR >= 7
|
||||
mbedtls_md5_context tctx;
|
||||
mbedtls_md5_starts_ret(&tctx);
|
||||
mbedtls_md5_update_ret(&tctx, (const unsigned char *)buf, len);
|
||||
mbedtls_md5_finish_ret(&tctx, img_md5);
|
||||
#else
|
||||
mbedtls_md5_context tctx;
|
||||
mbedtls_md5_starts(&tctx);
|
||||
mbedtls_md5_update(&tctx, (const unsigned char *)buf, len);
|
||||
mbedtls_md5_finish(&tctx, img_md5);
|
||||
#endif
|
||||
#if MBEDTLS_VERSION_MINOR >= 7
|
||||
mbedtls_md5_context tctx;
|
||||
mbedtls_md5_starts_ret(&tctx);
|
||||
mbedtls_md5_update_ret(&tctx, (const unsigned char *)buf, len);
|
||||
mbedtls_md5_finish_ret(&tctx, img_md5);
|
||||
#else
|
||||
mbedtls_md5_context tctx;
|
||||
mbedtls_md5_starts(&tctx);
|
||||
mbedtls_md5_update(&tctx, (const unsigned char *)buf, len);
|
||||
mbedtls_md5_finish(&tctx, img_md5);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_POLARSSL
|
||||
|
||||
@@ -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 "
|
||||
"for %" PRId32 " interpolations in the last "
|
||||
"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_mean = 0.0;
|
||||
stat_M2 = 0.0;
|
||||
@@ -1802,7 +1803,6 @@ void *player_thread_func(void *arg) {
|
||||
(config.playback_mode == ST_mono))
|
||||
conn->enable_dither = 1;
|
||||
|
||||
|
||||
// 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
|
||||
|
||||
@@ -2386,15 +2386,17 @@ void *player_thread_func(void *arg) {
|
||||
if ((current_delay < conn->dac_buffer_queue_minimum_length) ||
|
||||
(config.packet_stuffing == ST_basic) ||
|
||||
(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
|
||||
play_samples =
|
||||
stuff_buffer_basic_32((int32_t *)conn->tbuf, inbuflength, config.output_format,
|
||||
conn->outbuf, amount_to_stuff, conn->enable_dither, conn);
|
||||
#ifdef CONFIG_SOXR
|
||||
}
|
||||
else { // soxr requested or auto requested with the index less or equal to the threshold
|
||||
} else { // soxr requested or auto requested with the index less or equal to the
|
||||
// threshold
|
||||
play_samples = stuff_buffer_soxr_32((int32_t *)conn->tbuf, (int32_t *)conn->sbuf,
|
||||
inbuflength, config.output_format, conn->outbuf,
|
||||
amount_to_stuff, conn->enable_dither, conn);
|
||||
@@ -2943,7 +2945,7 @@ int player_play(rtsp_conn_info *conn) {
|
||||
command_start();
|
||||
// call on the output device to prepare itself
|
||||
if ((config.output) && (config.output->prepare))
|
||||
config.output->prepare();
|
||||
config.output->prepare();
|
||||
|
||||
pthread_t *pt = malloc(sizeof(pthread_t));
|
||||
if (pt == NULL)
|
||||
|
||||
@@ -137,9 +137,8 @@ void *rtp_audio_receiver(void *arg) {
|
||||
stat_mean += stat_delta / stat_n;
|
||||
stat_M2 += stat_delta * (time_interval_us - stat_mean);
|
||||
if (stat_n % 2500 == 0) {
|
||||
debug(2,
|
||||
"Packet reception interval stats: mean, standard deviation and max for the last "
|
||||
"2,500 packets in microseconds: %10.1f, %10.1f, %10.1f.",
|
||||
debug(2, "Packet reception interval stats: mean, standard deviation and max for the last "
|
||||
"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_n = 0;
|
||||
stat_mean = 0.0;
|
||||
@@ -369,10 +368,9 @@ void *rtp_control_receiver(void *arg) {
|
||||
|
||||
if (la != conn->latency) {
|
||||
conn->latency = la;
|
||||
debug(3,
|
||||
"New latency detected: %" PRIu32 ", sync latency: %" PRIu32
|
||||
", minimum latency: %" PRIu32 ", maximum "
|
||||
"latency: %" PRIu32 ", fixed offset: %" PRIu32 ".",
|
||||
debug(3, "New latency detected: %" PRIu32 ", sync latency: %" PRIu32
|
||||
", minimum latency: %" PRIu32 ", maximum "
|
||||
"latency: %" PRIu32 ", fixed offset: %" PRIu32 ".",
|
||||
la, sync_rtp_timestamp - rtp_timestamp_less_latency, conn->minimum_latency,
|
||||
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
|
||||
// numerator and 64-bit denominator
|
||||
// integers
|
||||
conn->remote_frame_rate = conn->remote_frame_rate *
|
||||
(uint64_t)0x100000000; // this should just change the
|
||||
// [binary] exponent in the IEEE
|
||||
// FP representation; the
|
||||
// mantissa should be unaffected.
|
||||
conn->remote_frame_rate =
|
||||
conn->remote_frame_rate * (uint64_t)0x100000000; // this should just change the
|
||||
// [binary] exponent in the IEEE
|
||||
// FP representation; the
|
||||
// mantissa should be unaffected.
|
||||
} else {
|
||||
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;
|
||||
else {
|
||||
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 {
|
||||
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)
|
||||
calculated_frame_rate = ((1.0 * local_frames) / local_time) * one_fp;
|
||||
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) ||
|
||||
((calculated_frame_rate / conn->input_rate) < 0.998)) {
|
||||
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)
|
||||
frame_interval = (time_interval * frame_difference) / time_difference;
|
||||
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) {
|
||||
// debug(1,"Frame interval is %" PRId64 " frames.",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) {
|
||||
char em[1024];
|
||||
strerror_r(errno, em, sizeof(em));
|
||||
debug(1,
|
||||
"Error %d using sendto to an audio socket: \"%s\". Backing off for 1/16th of a "
|
||||
"second.",
|
||||
debug(1, "Error %d using sendto to an audio socket: \"%s\". Backing off for 1/16th of a "
|
||||
"second.",
|
||||
errno, em);
|
||||
conn->rtp_time_of_last_resend_request_error_fp = time_of_sending_fp;
|
||||
} else {
|
||||
|
||||
+81
-74
@@ -31,6 +31,7 @@
|
||||
#include <libconfig.h>
|
||||
#include <libgen.h>
|
||||
#include <memory.h>
|
||||
#include <net/if.h>
|
||||
#include <popt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -38,10 +39,8 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <net/if.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef CONFIG_MBEDTLS
|
||||
@@ -97,15 +96,14 @@
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SOXR
|
||||
#include <soxr.h>
|
||||
#include <math.h>
|
||||
#include <soxr.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CONVOLUTION
|
||||
#include <FFTConvolver/convolver.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CONFIG_LIBDAEMON
|
||||
pid_t pid;
|
||||
#endif
|
||||
@@ -165,14 +163,14 @@ void print_version(void) {
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SOXR
|
||||
pthread_t soxr_time_check_thread;
|
||||
void* soxr_time_check(__attribute__((unused)) void *arg) {
|
||||
pthread_t soxr_time_check_thread;
|
||||
void *soxr_time_check(__attribute__((unused)) void *arg) {
|
||||
const int buffer_length = 352;
|
||||
int32_t inbuffer[buffer_length*2];
|
||||
int32_t outbuffer[(buffer_length+1)*2];
|
||||
int32_t inbuffer[buffer_length * 2];
|
||||
int32_t outbuffer[(buffer_length + 1) * 2];
|
||||
|
||||
//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 *outbuffer = (int32_t*)malloc((buffer_length+1)*2*sizeof(int32_t));
|
||||
// int32_t *inbuffer = (int32_t*)malloc((buffer_length)*2*sizeof(int32_t));
|
||||
|
||||
// generate a sample signal
|
||||
const double frequency = 440; //
|
||||
@@ -181,12 +179,13 @@ void* soxr_time_check(__attribute__((unused)) void *arg) {
|
||||
|
||||
int number_of_iterations = 0;
|
||||
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) {
|
||||
|
||||
number_of_iterations++;
|
||||
for (i = 0; i < buffer_length ; i++) {
|
||||
double w = sin(i * (frequency + number_of_iterations * 2) * 2 * M_PI/44100);
|
||||
for (i = 0; i < buffer_length; i++) {
|
||||
double w = sin(i * (frequency + number_of_iterations * 2) * 2 * M_PI / 44100);
|
||||
int32_t wint = (int32_t)(w * INT32_MAX);
|
||||
inbuffer[i * 2] = wint;
|
||||
inbuffer[i * 2 + 1] = wint;
|
||||
@@ -201,11 +200,11 @@ void* soxr_time_check(__attribute__((unused)) void *arg) {
|
||||
|
||||
size_t odone;
|
||||
|
||||
soxr_oneshot(buffer_length, buffer_length + 1, 2, // Rates and # of chans.
|
||||
inbuffer, buffer_length, NULL, // Input.
|
||||
outbuffer, buffer_length + 1, &odone, // Output.
|
||||
&io_spec, // Input, output and transfer spec.
|
||||
NULL, NULL); // Default configuration.
|
||||
soxr_oneshot(buffer_length, buffer_length + 1, 2, // Rates and # of chans.
|
||||
inbuffer, buffer_length, NULL, // Input.
|
||||
outbuffer, buffer_length + 1, &odone, // Output.
|
||||
&io_spec, // Input, output and transfer spec.
|
||||
NULL, NULL); // Default configuration.
|
||||
|
||||
io_spec.itype = 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.flags = 0;
|
||||
|
||||
soxr_oneshot(buffer_length, buffer_length - 1, 2, // Rates and # of chans.
|
||||
inbuffer, buffer_length, NULL, // Input.
|
||||
outbuffer, buffer_length - 1, &odone, // Output.
|
||||
&io_spec, // Input, output and transfer spec.
|
||||
NULL, NULL); // Default configuration.
|
||||
|
||||
soxr_oneshot(buffer_length, buffer_length - 1, 2, // Rates and # of chans.
|
||||
inbuffer, buffer_length, NULL, // Input.
|
||||
outbuffer, buffer_length - 1, &odone, // Output.
|
||||
&io_spec, // Input, output and transfer spec.
|
||||
NULL, NULL); // Default configuration.
|
||||
}
|
||||
|
||||
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(inbuffer);
|
||||
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);
|
||||
if ((config.packet_stuffing == ST_soxr) && (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.");
|
||||
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);
|
||||
if ((config.packet_stuffing == ST_soxr) &&
|
||||
(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)
|
||||
debug(1,"\"%s\" interpolation has been chosen.", config.soxr_delay_index <= config.soxr_delay_threshold ? "soxr" : "basic");
|
||||
pthread_exit(NULL);
|
||||
debug(1, "\"%s\" interpolation has been chosen.",
|
||||
config.soxr_delay_index <= config.soxr_delay_threshold ? "soxr" : "basic");
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -428,10 +429,14 @@ int parse_options(int argc, char **argv) {
|
||||
config.fixedLatencyOffset = 11025; // this sounds like it works properly.
|
||||
config.diagnostic_drop_packet_fraction = 0.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.volume_range_hw_priority = 0; // if combining software and hardware volume control, give the software priority
|
||||
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.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.
|
||||
// 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
|
||||
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;
|
||||
#else
|
||||
warn("The soxr option not available because this version of shairport-sync was built "
|
||||
"without libsoxr "
|
||||
"support. Change the \"general/interpolation\" setting in the configuration file.");
|
||||
"without libsoxr "
|
||||
"support. Change the \"general/interpolation\" setting in the configuration file.");
|
||||
#endif
|
||||
else
|
||||
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;
|
||||
else
|
||||
warn("Invalid general soxr_delay_threshold setting option choice \"%d\". It should be "
|
||||
"between 0 and 100, "
|
||||
"inclusive. Default is %d (milliseconds).",
|
||||
value, config.soxr_delay_threshold);
|
||||
"between 0 and 100, "
|
||||
"inclusive. Default is %d (milliseconds).",
|
||||
value, config.soxr_delay_threshold);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1003,10 +1008,10 @@ int parse_options(int argc, char **argv) {
|
||||
config.mqtt_port = 1883;
|
||||
if (config_lookup_int(config.cfg, "mqtt.port", &value)) {
|
||||
if ((value < 0) || (value > 65535))
|
||||
die("Invalid mqtt port number \"%sd\". It should be between 0 and 65535, default is 1883",
|
||||
value);
|
||||
die("Invalid mqtt port number \"%sd\". It should be between 0 and 65535, default is 1883",
|
||||
value);
|
||||
else
|
||||
config.mqtt_port = value;
|
||||
config.mqtt_port = value;
|
||||
}
|
||||
|
||||
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);
|
||||
#ifndef CONFIG_AVAHI
|
||||
if (config.mqtt_enable_remote) {
|
||||
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 enabled, or disable remote control.");
|
||||
}
|
||||
if (config.mqtt_enable_remote) {
|
||||
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 enabled, or disable remote control.");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@@ -1125,7 +1130,6 @@ int parse_options(int argc, char **argv) {
|
||||
|
||||
// here, we are finally finished reading the options
|
||||
|
||||
|
||||
#ifdef CONFIG_LIBDAEMON
|
||||
if ((daemonisewith) && (daemonisewithout))
|
||||
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
|
||||
/* Check if we are called with -d or --daemon or -j or justDaemoniseNoPIDFile options*/
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1315,7 +1321,7 @@ void main_cleanup_handler(__attribute__((unused)) void *arg) {
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LIBDAEMON
|
||||
// only do this if you are the daemon
|
||||
// only do this if you are the daemon
|
||||
if (pid == 0) {
|
||||
daemon_retval_send(0);
|
||||
daemon_pid_file_remove();
|
||||
@@ -1366,12 +1372,12 @@ int main(int argc, char **argv) {
|
||||
die("can not allocate memory for the app name!");
|
||||
free(basec);
|
||||
|
||||
// debug(1,"startup");
|
||||
// debug(1,"startup");
|
||||
#ifdef CONFIG_LIBDAEMON
|
||||
daemon_set_verbosity(LOG_DEBUG);
|
||||
#else
|
||||
setlogmask (LOG_UPTO (LOG_DEBUG));
|
||||
openlog(NULL,0,LOG_DAEMON);
|
||||
setlogmask(LOG_UPTO(LOG_DEBUG));
|
||||
openlog(NULL, 0, LOG_DAEMON);
|
||||
#endif
|
||||
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.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.timeout = 120; // this number of seconds to wait for [more] audio before switching to idle.
|
||||
config.tolerance =
|
||||
@@ -1419,14 +1426,13 @@ int main(int argc, char **argv) {
|
||||
config.buffer_start_fill = 220;
|
||||
config.port = 5000;
|
||||
|
||||
|
||||
#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
|
||||
config.packet_stuffing = ST_basic; // simple interpolation or deletion
|
||||
#endif
|
||||
|
||||
|
||||
// char hostname[100];
|
||||
// gethostname(hostname, 100);
|
||||
// config.service_name = malloc(20 + 100);
|
||||
@@ -1488,7 +1494,6 @@ int main(int argc, char **argv) {
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// parse arguments into config -- needed to locate pid_dir
|
||||
int audio_arg = parse_options(argc, argv);
|
||||
|
||||
@@ -1512,7 +1517,8 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
return ret < 0 ? 1 : 0;
|
||||
#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;
|
||||
#endif
|
||||
}
|
||||
@@ -1608,7 +1614,7 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
#endif
|
||||
debug(1,"Started!");
|
||||
debug(1, "Started!");
|
||||
main_thread_id = pthread_self();
|
||||
if (!main_thread_id)
|
||||
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
|
||||
umask(S_IWGRP | S_IWOTH);
|
||||
|
||||
|
||||
/* print out version */
|
||||
|
||||
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, "mdns backend \"%s\".", config.mdns_name);
|
||||
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, "resync time is %f seconds.", config.resyncthreshold);
|
||||
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 range in dB (zero means use the range specified by the mixer): %u.",
|
||||
config.volume_range_db);
|
||||
debug(
|
||||
1,
|
||||
"volume_range_combined_hardware_priority (1 means hardware mixer attenuation is used first) is %d.",
|
||||
config.volume_range_hw_priority);
|
||||
debug(1, "volume_range_combined_hardware_priority (1 means hardware mixer attenuation is used "
|
||||
"first) is %d.",
|
||||
config.volume_range_hw_priority);
|
||||
debug(1, "playback_mode is %d (0-stereo, 1-mono, 1-reverse_stereo, 2-both_left, 3-both_right).",
|
||||
config.playback_mode);
|
||||
debug(1, "disable_synchronization is %d.", config.no_sync);
|
||||
debug(1, "use_mmap_if_available is %d.", config.no_mmap ? 0 : 1);
|
||||
debug(1, "output_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)
|
||||
debug(1,
|
||||
"output_format is \"%s\".",
|
||||
sps_format_description_string(config.output_format));
|
||||
debug(1, "output_rate automatic selection is %sabled.", config.output_rate_auto_requested ? "en" : "dis");
|
||||
debug(1, "output_format is \"%s\".", sps_format_description_string(config.output_format));
|
||||
debug(1, "output_rate automatic selection is %sabled.",
|
||||
config.output_rate_auto_requested ? "en" : "dis");
|
||||
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.",
|
||||
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 silence lead-in time is %f seconds. A value -1.0 means use the default.",
|
||||
config.audio_backend_silent_lead_in_time);
|
||||
@@ -1783,7 +1790,7 @@ int main(int argc, char **argv) {
|
||||
uint8_t ap_md5[16];
|
||||
|
||||
#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
|
||||
|
||||
#ifdef CONFIG_OPENSSL
|
||||
|
||||
Reference in New Issue
Block a user