Add "auto" to interpolation settings. Time a few soxr_oneshots to get a figure for soxr_delay_index. Add a soxr_delay_threshold and in auto mode, select soxr if delay is below threshold.
This commit is contained in:
+10
-3
@@ -46,9 +46,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
|
||||
|
||||
|
||||
// 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."
|
||||
fd = open(pipename, O_WRONLY | O_NONBLOCK);
|
||||
if ((fd < -1) && (warned == 0)) {
|
||||
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);
|
||||
warn("Error %d opening the pipe named \"%s\".", errno, pipename);
|
||||
warned = 1;
|
||||
}
|
||||
@@ -68,7 +75,7 @@ static int play(void *buf, int samples) {
|
||||
warn("Error %d writing to the pipe named \"%s\": \"%s\".", errno, pipename, errorstring);
|
||||
warned = 1;
|
||||
}
|
||||
} else if ((fd == -1) && (warned == 0)) {
|
||||
} else if ((fd == -1) && (errno != ENXIO) && (warned == 0)) {
|
||||
strerror_r(errno, (char *)errorstring, 1024);
|
||||
warn("Error %d opening the pipe named \"%s\": \"%s\".", errno, pipename, errorstring);
|
||||
warned = 1;
|
||||
|
||||
@@ -1282,11 +1282,12 @@ char *get_version_string() {
|
||||
char *version_string = malloc(1024);
|
||||
if (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");
|
||||
|
||||
@@ -56,6 +56,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
|
||||
} s_type;
|
||||
|
||||
enum playback_mode_type {
|
||||
@@ -179,6 +180,8 @@ typedef struct {
|
||||
int cmd_blocking, cmd_start_returns_output;
|
||||
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 decoders_supported;
|
||||
int use_apple_decoder; // set to 1 if you want to use the apple decoder instead of the original by
|
||||
// David Hammerton
|
||||
|
||||
+1
-1
@@ -184,8 +184,8 @@ AC_ARG_WITH(ssl, [ choose --with-ssl=openssl, --with-ssl=mbedtls or --with-ssl=p
|
||||
# Look for soxr flag
|
||||
AC_ARG_WITH(soxr, [ --with-soxr = choose libsoxr for high-quality interpolation], [
|
||||
AC_MSG_RESULT(>>Including support for soxr-based interpolation)
|
||||
AC_DEFINE([CONFIG_SOXR], 1, [Include support for using the SoX Resampler library for interpolation])
|
||||
if test "x${with_pkg_config}" = xyes ; then
|
||||
AC_DEFINE([CONFIG_SOXR], 1, [Include support for using the SoX Resampler library for interpolation])
|
||||
PKG_CHECK_MODULES(
|
||||
[SOXR], [soxr],
|
||||
[LIBS="${SOXR_LIBS} ${LIBS}"],
|
||||
|
||||
+33
-35
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* mDNS registration handler. This file is part of Shairport.
|
||||
* Copyright (c) Paul Lietar 2013
|
||||
* Amendments and updates copyright (c) Mike Brady 2014 -- 2019
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
@@ -24,8 +25,8 @@
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "mdns.h"
|
||||
#include "common.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
@@ -41,45 +42,42 @@ int mdns_pid = 0;
|
||||
*/
|
||||
static int fork_execvp(const char *file, char *const argv[]) {
|
||||
int execpipe[2];
|
||||
int pid = 0;
|
||||
if (pipe(execpipe) < 0) {
|
||||
return -1;
|
||||
}
|
||||
int response = -1;
|
||||
if (pipe(execpipe) >= 0) {
|
||||
|
||||
if (fcntl(execpipe[1], F_SETFD, fcntl(execpipe[1], F_GETFD) | FD_CLOEXEC) < 0) {
|
||||
close(execpipe[0]);
|
||||
close(execpipe[1]);
|
||||
return -1;
|
||||
}
|
||||
if (fcntl(execpipe[1], F_SETFD, fcntl(execpipe[1], F_GETFD) | FD_CLOEXEC) < 0) {
|
||||
close(execpipe[0]);
|
||||
close(execpipe[1]);
|
||||
} else {
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
close(execpipe[0]);
|
||||
close(execpipe[1]);
|
||||
return -1;
|
||||
} else if (pid == 0) { // Child
|
||||
close(execpipe[0]); // Close the read end
|
||||
execvp(file, argv);
|
||||
int pid = fork();
|
||||
if (pid < 0) {
|
||||
close(execpipe[0]);
|
||||
close(execpipe[1]);
|
||||
} else if (pid == 0) { // Child
|
||||
close(execpipe[0]); // Close the read end
|
||||
execvp(file, argv);
|
||||
// If we reach this point then execve has failed.
|
||||
// Write erno's value into the pipe and exit.
|
||||
if (write(execpipe[1], &errno, sizeof(errno)) != sizeof(errno))
|
||||
debug(1,
|
||||
"Execve has failed and there was a further error writing an error message, duh.");
|
||||
die("mdns_external: execve has failed.");
|
||||
} else { // Parent
|
||||
close(execpipe[1]); // Close the write end
|
||||
|
||||
// If we reach this point then execve has failed.
|
||||
// Write erno's value into the pipe and exit.
|
||||
if (write(execpipe[1], &errno, sizeof(errno)) != sizeof(errno))
|
||||
debug(1, "Execve has failed and there was a further error writing an error message, duh.");
|
||||
die("mdns_external: execve has failed.");
|
||||
// return 0; // Just to make the compiler happy.
|
||||
} else { // Parent
|
||||
close(execpipe[1]); // Close the write end
|
||||
|
||||
int childErrno;
|
||||
// Block until child closes the pipe or sends errno.
|
||||
if (read(execpipe[0], &childErrno, sizeof(childErrno)) ==
|
||||
sizeof(childErrno)) { // We received errno
|
||||
errno = childErrno;
|
||||
return -1;
|
||||
} else { // Child closed the pipe. execvp was successful.
|
||||
return pid;
|
||||
int childErrno;
|
||||
// Block until child closes the pipe or sends errno.
|
||||
if (read(execpipe[0], &childErrno, sizeof(childErrno)) ==
|
||||
sizeof(childErrno)) { // We received errno
|
||||
errno = childErrno;
|
||||
} else {
|
||||
response = pid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
static int mdns_external_avahi_register(char *apname, __attribute__((unused)) int port) {
|
||||
|
||||
@@ -891,7 +891,7 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
curframe->given_timestamp; // we will keep buffering until we are
|
||||
// supposed to start playing this
|
||||
have_sent_prefiller_silence = 0;
|
||||
|
||||
|
||||
// debug(1, "First packet timestamp is %" PRId64 ".", conn->first_packet_timestamp);
|
||||
|
||||
// say we have started playing here
|
||||
@@ -959,20 +959,22 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
conn);
|
||||
|
||||
conn->first_packet_time_to_play = should_be_time;
|
||||
|
||||
|
||||
// we want the frames of silence sent at the start to be fairly large in case the output
|
||||
// device's minimum buffer size is large. But they can't be greater than the silent lead_in time
|
||||
// which is either the agreed latency or the silent lead-in time specified by the setting
|
||||
// device's minimum buffer size is large. But they can't be greater than the silent
|
||||
// lead_in time
|
||||
// which is either the agreed latency or the silent lead-in time specified by the
|
||||
// setting
|
||||
// In fact, if should be some fraction of them, to allow for adjustment.
|
||||
|
||||
|
||||
int64_t max_dac_delay = conn->latency;
|
||||
if (config.audio_backend_silent_lead_in_time >= 0)
|
||||
max_dac_delay =
|
||||
(int64_t)(config.audio_backend_silent_lead_in_time * conn->input_rate);
|
||||
|
||||
(int64_t)(config.audio_backend_silent_lead_in_time * conn->input_rate);
|
||||
|
||||
max_dac_delay = max_dac_delay / 4;
|
||||
|
||||
// debug(1,"max_dac_delay is %" PRIu64 " frames.", max_dac_delay);
|
||||
|
||||
// debug(1,"max_dac_delay is %" PRIu64 " frames.", max_dac_delay);
|
||||
|
||||
int64_t filler_size = max_dac_delay;
|
||||
|
||||
@@ -1333,12 +1335,19 @@ static int stuff_buffer_basic_32(int32_t *inptr, int length, enum sps_format_t l
|
||||
// (d) outputs the result in the approprate format
|
||||
// formats accepted so far include U8, S8, S16, S24, S24_3LE, S24_3BE and S32
|
||||
|
||||
int32_t stat_n = 0;
|
||||
double stat_mean = 0.0;
|
||||
double stat_M2 = 0.0;
|
||||
double longest_soxr_execution_time_us = 0.0;
|
||||
int64_t packets_processed = 0;
|
||||
|
||||
int stuff_buffer_soxr_32(int32_t *inptr, int32_t *scratchBuffer, int length,
|
||||
enum sps_format_t l_output_format, char *outptr, int stuff, int dither,
|
||||
rtsp_conn_info *conn) {
|
||||
if (scratchBuffer == NULL) {
|
||||
die("soxr scratchBuffer not initialised.");
|
||||
}
|
||||
packets_processed++;
|
||||
int tstuff = stuff;
|
||||
if ((stuff > 1) || (stuff < -1) || (length < 100)) {
|
||||
// debug(1, "Stuff argument to stuff_buffer must be from -1 to +1 and length >100.");
|
||||
@@ -1357,6 +1366,8 @@ int stuff_buffer_soxr_32(int32_t *inptr, int32_t *scratchBuffer, int length,
|
||||
|
||||
size_t odone;
|
||||
|
||||
uint64_t soxr_start_time = get_absolute_time_in_fp();
|
||||
|
||||
soxr_error_t error = soxr_oneshot(length, length + tstuff, 2, // Rates and # of chans.
|
||||
inptr, length, NULL, // Input.
|
||||
scratchBuffer, length + tstuff, &odone, // Output.
|
||||
@@ -1369,6 +1380,19 @@ int stuff_buffer_soxr_32(int32_t *inptr, int32_t *scratchBuffer, int length,
|
||||
if (odone > (size_t)(length + 1))
|
||||
die("odone = %u!\n", odone);
|
||||
|
||||
// mean and variance calculations from "online_variance" algorithm at
|
||||
// https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Online_algorithm
|
||||
|
||||
double soxr_execution_time_us =
|
||||
(((get_absolute_time_in_fp() - soxr_start_time) * 1000000) >> 32) * 1.0;
|
||||
// debug(1,"soxr_execution_time_us: %10.1f",soxr_execution_time_us);
|
||||
if (soxr_execution_time_us > longest_soxr_execution_time_us)
|
||||
longest_soxr_execution_time_us = soxr_execution_time_us;
|
||||
stat_n += 1;
|
||||
double stat_delta = soxr_execution_time_us - stat_mean;
|
||||
stat_mean += stat_delta / stat_n;
|
||||
stat_M2 += stat_delta * (soxr_execution_time_us - stat_mean);
|
||||
|
||||
int i;
|
||||
int32_t *ip, *op;
|
||||
ip = inptr;
|
||||
@@ -1411,6 +1435,18 @@ int stuff_buffer_soxr_32(int32_t *inptr, int32_t *scratchBuffer, int length,
|
||||
process_sample(*ip++, &l_outptr, l_output_format, conn->fix_volume, dither, conn);
|
||||
};
|
||||
}
|
||||
|
||||
if (packets_processed % 1250 == 0) {
|
||||
debug(2, "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, sqrtf(stat_M2 / (stat_n - 1)), longest_soxr_execution_time_us);
|
||||
stat_n = 0;
|
||||
stat_mean = 0.0;
|
||||
stat_M2 = 0.0;
|
||||
longest_soxr_execution_time_us = 0.0;
|
||||
}
|
||||
|
||||
conn->amountStuffed = tstuff;
|
||||
return length + tstuff;
|
||||
}
|
||||
@@ -2246,15 +2282,19 @@ void *player_thread_func(void *arg) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SOXR
|
||||
if ((current_delay < conn->dac_buffer_queue_minimum_length) ||
|
||||
(config.packet_stuffing == ST_basic)) {
|
||||
(config.packet_stuffing == ST_basic) ||
|
||||
(config.soxr_delay_index == 0) || // not computed yet
|
||||
((config.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 if (config.packet_stuffing == ST_soxr) {
|
||||
// if (amount_to_stuff) debug(1,"Soxr stuff...");
|
||||
}
|
||||
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);
|
||||
|
||||
@@ -15,8 +15,7 @@ general =
|
||||
// %V for the full version string, e.g. 3.3-OpenSSL-Avahi-ALSA-soxr-metadata-sysconfdir:/etc
|
||||
// Overall length can not exceed 50 characters. Example: "Shairport Sync %v on %H".
|
||||
// password = "secret"; // leave this commented out if you don't want to require a password
|
||||
// interpolation = "basic"; // aka "stuffing". Default is "basic", alternative is "soxr". Use "soxr" only if you have a reasonably fast processor.
|
||||
// Note: if Shairport Sync is build with the --with-soxr configuration flag, interpolation will be "soxr" by default.
|
||||
// interpolation = "auto"; // aka "stuffing". Default is "auto". Alternatives are "basic" or "soxr". Choose "soxr" only if you have a reasonably fast processor and Shairport Sync has been built with "soxr" support.
|
||||
// output_backend = "alsa"; // Run "shairport-sync -h" to get a list of all output_backends, e.g. "alsa", "pipe", "stdout". The default is the first one.
|
||||
// mdns_backend = "avahi"; // Run "shairport-sync -h" to get a list of all mdns_backends. The default is the first one.
|
||||
// port = 5000; // Listen for service requests on this port
|
||||
|
||||
+122
-16
@@ -41,6 +41,7 @@
|
||||
#include <net/if.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef CONFIG_MBEDTLS
|
||||
@@ -95,6 +96,11 @@
|
||||
#include <syslog.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SOXR
|
||||
#include <soxr.h>
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CONVOLUTION
|
||||
#include <FFTConvolver/convolver.h>
|
||||
#endif
|
||||
@@ -158,6 +164,78 @@ void print_version(void) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SOXR
|
||||
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 *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; //
|
||||
|
||||
int i;
|
||||
|
||||
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
|
||||
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);
|
||||
int32_t wint = (int32_t)(w * INT32_MAX);
|
||||
inbuffer[i * 2] = wint;
|
||||
inbuffer[i * 2 + 1] = wint;
|
||||
}
|
||||
|
||||
soxr_io_spec_t io_spec;
|
||||
io_spec.itype = SOXR_INT32_I;
|
||||
io_spec.otype = SOXR_INT32_I;
|
||||
io_spec.scale = 1.0; // this seems to crash if not = 1.0
|
||||
io_spec.e = NULL;
|
||||
io_spec.flags = 0;
|
||||
|
||||
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.
|
||||
|
||||
io_spec.itype = SOXR_INT32_I;
|
||||
io_spec.otype = SOXR_INT32_I;
|
||||
io_spec.scale = 1.0; // this seems to crash if not = 1.0
|
||||
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.
|
||||
|
||||
}
|
||||
|
||||
double soxr_execution_time_us =
|
||||
(((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(1,"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);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void usage(char *progname) {
|
||||
printf("Usage: %s [options...]\n", progname);
|
||||
printf(" or: %s [options...] -- [audio output-specific options]\n", progname);
|
||||
@@ -350,8 +428,8 @@ 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.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
|
||||
|
||||
@@ -451,6 +529,8 @@ int parse_options(int argc, char **argv) {
|
||||
if (config_lookup_string(config.cfg, "general.interpolation", &str)) {
|
||||
if (strcasecmp(str, "basic") == 0)
|
||||
config.packet_stuffing = ST_basic;
|
||||
else if (strcasecmp(str, "auto") == 0)
|
||||
config.packet_stuffing = ST_auto;
|
||||
else if (strcasecmp(str, "soxr") == 0)
|
||||
#ifdef CONFIG_SOXR
|
||||
config.packet_stuffing = ST_soxr;
|
||||
@@ -460,8 +540,21 @@ int parse_options(int argc, char **argv) {
|
||||
"support. Change the \"general/interpolation\" setting in the configuration file.");
|
||||
#endif
|
||||
else
|
||||
die("Invalid interpolation option choice. It should be \"basic\" or \"soxr\"");
|
||||
die("Invalid interpolation option choice. It should be \"auto\", \"basic\" or \"soxr\"");
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SOXR
|
||||
/* Get the soxr_delay_threshold setting. */
|
||||
if (config_lookup_int(config.cfg, "general.soxr_delay_threshold", &value)) {
|
||||
if ((value >= 0) && (value <= 100))
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Get the statistics setting. */
|
||||
if (config_set_lookup_bool(config.cfg, "general.statistics",
|
||||
@@ -998,6 +1091,8 @@ int parse_options(int argc, char **argv) {
|
||||
case 'S':
|
||||
if (strcmp(stuffing, "basic") == 0)
|
||||
config.packet_stuffing = ST_basic;
|
||||
else if (strcmp(stuffing, "auto") == 0)
|
||||
config.packet_stuffing = ST_auto;
|
||||
else if (strcmp(stuffing, "soxr") == 0)
|
||||
#ifdef CONFIG_SOXR
|
||||
config.packet_stuffing = ST_soxr;
|
||||
@@ -1312,11 +1407,15 @@ int main(int argc, char **argv) {
|
||||
0.002; // this number of seconds of timing error before attempting to correct it.
|
||||
config.buffer_start_fill = 220;
|
||||
config.port = 5000;
|
||||
|
||||
|
||||
#ifdef CONFIG_SOXR
|
||||
config.packet_stuffing = ST_soxr; // use soxr interpolation by default if support has been included
|
||||
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);
|
||||
@@ -1506,6 +1605,19 @@ 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();
|
||||
if (version_dbs) {
|
||||
debug(1, "software version: \"%s\"", version_dbs);
|
||||
free(version_dbs);
|
||||
} else {
|
||||
debug(1, "can't print the version information!");
|
||||
}
|
||||
|
||||
debug(1, "log verbosity is %d.", debuglev);
|
||||
|
||||
config.output = audio_get_output(config.output_name);
|
||||
if (!config.output) {
|
||||
audio_ls_outputs();
|
||||
@@ -1551,18 +1663,7 @@ int main(int argc, char **argv) {
|
||||
BUFFER_FRAMES * 352 - 22050);
|
||||
}
|
||||
|
||||
/* print out version */
|
||||
|
||||
char *version_dbs = get_version_string();
|
||||
if (version_dbs) {
|
||||
debug(1, "software version: \"%s\"", version_dbs);
|
||||
free(version_dbs);
|
||||
} else {
|
||||
debug(1, "can't print the version information!");
|
||||
}
|
||||
|
||||
/* Print out options */
|
||||
debug(1, "log verbosity is %d.", debuglev);
|
||||
debug(1, "disable resend requests is %s.", config.disable_resend_requests ? "on" : "off");
|
||||
debug(1, "diagnostic_drop_packet_fraction is %f. A value of 0.0 means no packets will be dropped "
|
||||
"deliberately.",
|
||||
@@ -1587,7 +1688,8 @@ 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, "stuffing option is \"%d\" (0-basic, 1-soxr).", config.packet_stuffing);
|
||||
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);
|
||||
debug(1, "busy timeout time is %d.", config.timeout);
|
||||
@@ -1654,6 +1756,10 @@ 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);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OPENSSL
|
||||
MD5_CTX ctx;
|
||||
MD5_Init(&ctx);
|
||||
|
||||
Reference in New Issue
Block a user