Fix a bug that was causing instability when soxr interpolalation is chosen
This commit is contained in:
+1
-1
@@ -2,7 +2,7 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ([2.50])
|
||||
AC_INIT([shairport-sync], [3.2], [mikebrady@eircom.net])
|
||||
AC_INIT([shairport-sync], [3.2.1], [mikebrady@eircom.net])
|
||||
AM_INIT_AUTOMAKE
|
||||
AC_CONFIG_SRCDIR([shairport.c])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
+76
-68
@@ -84,33 +84,34 @@ static void resolve_callback(AvahiServiceResolver *r, AVAHI_GCC_UNUSED AvahiIfIn
|
||||
|
||||
/* Called whenever a service has been resolved successfully or timed out */
|
||||
switch (event) {
|
||||
case AVAHI_RESOLVER_FAILURE:
|
||||
debug(2, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s.", name,
|
||||
type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r))));
|
||||
break;
|
||||
case AVAHI_RESOLVER_FOUND: {
|
||||
// char a[AVAHI_ADDRESS_STR_MAX], *t;
|
||||
// debug(1, "Resolve callback: Service '%s' of type '%s' in domain '%s':", name, type, domain);
|
||||
char *dacpid = strstr(name, "iTunes_Ctrl_");
|
||||
if (dacpid) {
|
||||
dacpid += strlen("iTunes_Ctrl_");
|
||||
if (strcmp(dacpid, dbs->dacp_id) == 0) {
|
||||
debug(3, "Client's DACP port: %u.", port);
|
||||
#ifdef HAVE_DACP_CLIENT
|
||||
dacp_monitor_port_update_callback(dacpid, port);
|
||||
#endif
|
||||
#ifdef CONFIG_METADATA
|
||||
char portstring[20];
|
||||
memset(portstring, 0, sizeof(portstring));
|
||||
snprintf(portstring, sizeof(portstring), "%u", port);
|
||||
send_ssnc_metadata('dapo', strdup(portstring), strlen(portstring), 0);
|
||||
#endif
|
||||
case AVAHI_RESOLVER_FAILURE:
|
||||
debug(2, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s.", name,
|
||||
type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r))));
|
||||
break;
|
||||
case AVAHI_RESOLVER_FOUND: {
|
||||
// char a[AVAHI_ADDRESS_STR_MAX], *t;
|
||||
// debug(1, "Resolve callback: Service '%s' of type '%s' in domain '%s':", name, type, domain);
|
||||
char *dacpid = strstr(name, "iTunes_Ctrl_");
|
||||
if (dacpid) {
|
||||
dacpid += strlen("iTunes_Ctrl_");
|
||||
if (strcmp(dacpid, dbs->dacp_id) == 0) {
|
||||
debug(3, "Client's DACP port: %u.", port);
|
||||
#ifdef HAVE_DACP_CLIENT
|
||||
dacp_monitor_port_update_callback(dacpid, port);
|
||||
#endif
|
||||
#ifdef CONFIG_METADATA
|
||||
char portstring[20];
|
||||
memset(portstring, 0, sizeof(portstring));
|
||||
snprintf(portstring, sizeof(portstring), "%u", port);
|
||||
send_ssnc_metadata('dapo', strdup(portstring), strlen(portstring), 0);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
debug(1, "Resolve callback: Can't see a DACP string in a DACP Record!");
|
||||
}
|
||||
} else {
|
||||
debug(1, "Resolve callback: Can't see a DACP string in a DACP Record!");
|
||||
}
|
||||
}
|
||||
}
|
||||
// debug(1,"service resolver freed by resolve_callback");
|
||||
check_avahi_response(1, avahi_service_resolver_free(r));
|
||||
}
|
||||
static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, AvahiProtocol protocol,
|
||||
@@ -163,47 +164,47 @@ static void register_service(AvahiClient *c);
|
||||
static void egroup_callback(AvahiEntryGroup *g, AvahiEntryGroupState state,
|
||||
AVAHI_GCC_UNUSED void *userdata) {
|
||||
switch (state) {
|
||||
case AVAHI_ENTRY_GROUP_ESTABLISHED:
|
||||
/* The entry group has been established successfully */
|
||||
debug(1, "avahi: service '%s' successfully added.", service_name);
|
||||
break;
|
||||
case AVAHI_ENTRY_GROUP_ESTABLISHED:
|
||||
/* The entry group has been established successfully */
|
||||
debug(1, "avahi: service '%s' successfully added.", service_name);
|
||||
break;
|
||||
|
||||
case AVAHI_ENTRY_GROUP_COLLISION: {
|
||||
char *n;
|
||||
case AVAHI_ENTRY_GROUP_COLLISION: {
|
||||
char *n;
|
||||
|
||||
/* A service name collision with a remote service
|
||||
* happened. Let's pick a new name */
|
||||
debug(1, "avahi name collision -- look for another");
|
||||
n = avahi_alternative_service_name(service_name);
|
||||
if (service_name)
|
||||
avahi_free(service_name);
|
||||
else
|
||||
debug(1, "avahi attempt to free a NULL service name");
|
||||
service_name = n;
|
||||
/* A service name collision with a remote service
|
||||
* happened. Let's pick a new name */
|
||||
debug(1, "avahi name collision -- look for another");
|
||||
n = avahi_alternative_service_name(service_name);
|
||||
if (service_name)
|
||||
avahi_free(service_name);
|
||||
else
|
||||
debug(1, "avahi attempt to free a NULL service name");
|
||||
service_name = n;
|
||||
|
||||
debug(2, "avahi: service name collision, renaming service to '%s'", service_name);
|
||||
debug(2, "avahi: service name collision, renaming service to '%s'", service_name);
|
||||
|
||||
/* And recreate the services */
|
||||
register_service(avahi_entry_group_get_client(g));
|
||||
break;
|
||||
}
|
||||
/* And recreate the services */
|
||||
register_service(avahi_entry_group_get_client(g));
|
||||
break;
|
||||
}
|
||||
|
||||
case AVAHI_ENTRY_GROUP_FAILURE:
|
||||
debug(1, "avahi: entry group failure: %s",
|
||||
avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))));
|
||||
break;
|
||||
case AVAHI_ENTRY_GROUP_FAILURE:
|
||||
debug(1, "avahi: entry group failure: %s",
|
||||
avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))));
|
||||
break;
|
||||
|
||||
case AVAHI_ENTRY_GROUP_UNCOMMITED:
|
||||
debug(2, "avahi: service '%s' group is not yet committed.", service_name);
|
||||
break;
|
||||
case AVAHI_ENTRY_GROUP_UNCOMMITED:
|
||||
debug(2, "avahi: service '%s' group is not yet committed.", service_name);
|
||||
break;
|
||||
|
||||
case AVAHI_ENTRY_GROUP_REGISTERING:
|
||||
debug(2, "avahi: service '%s' group is registering.", service_name);
|
||||
break;
|
||||
case AVAHI_ENTRY_GROUP_REGISTERING:
|
||||
debug(2, "avahi: service '%s' group is registering.", service_name);
|
||||
break;
|
||||
|
||||
default:
|
||||
debug(1, "avahi: unhandled egroup state: %d", state);
|
||||
break;
|
||||
default:
|
||||
debug(1, "avahi: unhandled egroup state: %d", state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -458,28 +459,35 @@ void *avahi_dacp_monitor(char *dacp_id) {
|
||||
free((char *)dbs);
|
||||
return NULL;
|
||||
}
|
||||
debug(3, "DACP monitor successfully started");
|
||||
debug(3, "Avahi DACP monitor successfully started");
|
||||
return (void *)dbs;
|
||||
}
|
||||
|
||||
void avahi_dacp_dont_monitor(void *userdata) {
|
||||
debug(3,"avahi_dacp_dont_monitor");
|
||||
if (userdata) {
|
||||
dacp_browser_struct *dbs = (dacp_browser_struct *)userdata;
|
||||
// stop and dispose of everything
|
||||
if ((dbs)->service_poll)
|
||||
/*if (dbs->service_poll)
|
||||
avahi_threaded_poll_stop((dbs)->service_poll);
|
||||
if ((dbs)->service_browser)
|
||||
avahi_service_browser_free((dbs)->service_browser);
|
||||
if ((dbs)->service_client)
|
||||
avahi_client_free((dbs)->service_client);
|
||||
if ((dbs)->service_poll)
|
||||
avahi_threaded_poll_free((dbs)->service_poll);
|
||||
*/
|
||||
if (dbs->service_poll) {
|
||||
avahi_threaded_poll_stop(dbs->service_poll);
|
||||
avahi_threaded_poll_lock(dbs->service_poll);
|
||||
if (dbs->service_browser)
|
||||
avahi_service_browser_free(dbs->service_browser);
|
||||
if (dbs->service_client)
|
||||
avahi_client_free(dbs->service_client);
|
||||
avahi_threaded_poll_unlock(dbs->service_poll);
|
||||
avahi_threaded_poll_free(dbs->service_poll);
|
||||
}
|
||||
free(dbs->dacp_id);
|
||||
free((char *)(dbs));
|
||||
debug(3, "DACP monitor successfully stopped");
|
||||
free(userdata);
|
||||
debug(3, "Avahi DACP monitor successfully stopped");
|
||||
} else {
|
||||
debug(1, "DACP Monitor is not running.");
|
||||
debug(1, "Avahi DACP Monitor is not running.");
|
||||
}
|
||||
debug(3,"avahi_dacp_dont_monitor exit");
|
||||
}
|
||||
|
||||
mdns_backend mdns_avahi = {.name = "avahi",
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syslog.h>
|
||||
@@ -316,16 +315,18 @@ static int alac_decode(short *dest, int *destlen, uint8_t *buf, int len, rtsp_co
|
||||
}
|
||||
|
||||
if (outsize > toutsize) {
|
||||
debug(2, "Output from alac_decode larger (%d bytes, not frames) than expected (%d bytes) -- "
|
||||
"truncated, but buffer overflow possible! Encrypted = %d.",
|
||||
debug(2,
|
||||
"Output from alac_decode larger (%d bytes, not frames) than expected (%d bytes) -- "
|
||||
"truncated, but buffer overflow possible! Encrypted = %d.",
|
||||
outsize, toutsize, conn->stream.encrypted);
|
||||
reply = -1; // output packet is the wrong size
|
||||
}
|
||||
|
||||
*destlen = outsize / conn->input_bytes_per_frame;
|
||||
if ((outsize % conn->input_bytes_per_frame) != 0)
|
||||
debug(1, "Number of audio frames (%d) does not correspond exactly to the number of bytes (%d) "
|
||||
"and the audio frame size (%d).",
|
||||
debug(1,
|
||||
"Number of audio frames (%d) does not correspond exactly to the number of bytes (%d) "
|
||||
"and the audio frame size (%d).",
|
||||
*destlen, outsize, conn->input_bytes_per_frame);
|
||||
return reply;
|
||||
}
|
||||
@@ -607,9 +608,10 @@ void player_put_packet(seq_t seqno, uint32_t actual_timestamp, int64_t timestamp
|
||||
int j;
|
||||
for (j = 1; j <= number_of_resend_attempts; j++) {
|
||||
// check j times, after a short period of has elapsed, assuming 352 frames per packet
|
||||
// the higher the step_exponent, the less it will try. 1 means it will try very hard. 2.0 seems good.
|
||||
// the higher the step_exponent, the less it will try. 1 means it will try very
|
||||
// hard. 2.0 seems good.
|
||||
float step_exponent = 2.0;
|
||||
int back_step = (int)(resend_interval * pow(j,step_exponent));
|
||||
int back_step = (int)(resend_interval * pow(j, step_exponent));
|
||||
int k;
|
||||
for (k = -1; k <= 1; k++) {
|
||||
if ((back_step + k) <
|
||||
@@ -623,10 +625,11 @@ void player_put_packet(seq_t seqno, uint32_t actual_timestamp, int64_t timestamp
|
||||
j)) { // prevent multiple requests from the same level of lookback
|
||||
check_buf->resend_level = j;
|
||||
if (config.disable_resend_requests == 0) {
|
||||
if (((int)(resend_interval * pow(j+1,step_exponent)) + k) >=
|
||||
if (((int)(resend_interval * pow(j + 1, step_exponent)) + k) >=
|
||||
seq_diff(conn->ab_read, conn->ab_write, conn->ab_read))
|
||||
debug(3, "Last-ditch (#%d) resend request for packet %u in range %u to %u. "
|
||||
"Looking back %d packets.",
|
||||
debug(3,
|
||||
"Last-ditch (#%d) resend request for packet %u in range %u to %u. "
|
||||
"Looking back %d packets.",
|
||||
j, next, conn->ab_read, conn->ab_write, back_step + k);
|
||||
debug_mutex_unlock(&conn->ab_mutex, 3);
|
||||
rtp_request_resend(next, 1, conn);
|
||||
@@ -671,10 +674,8 @@ static inline void process_sample(int32_t sample, char **outp, enum sps_format_t
|
||||
32; // Do not apply volume as it has already been done with the Loudness DSP filter
|
||||
} else {
|
||||
int64_t hyper_volume = (int64_t)volume << 16;
|
||||
hyper_sample =
|
||||
hyper_sample * hyper_volume; // this is 64 bit bit multiplication -- we may need to
|
||||
// dither it down to its
|
||||
// target resolution
|
||||
hyper_sample = hyper_sample * hyper_volume; // this is 64 bit bit multiplication -- we may need
|
||||
// to dither it down to its target resolution
|
||||
}
|
||||
|
||||
// next, do dither, if necessary
|
||||
@@ -819,8 +820,9 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
// if (conn->packet_count>500) { //for testing -- about 4 seconds of play first
|
||||
if ((local_time_now > conn->time_of_last_audio_packet) &&
|
||||
(local_time_now - conn->time_of_last_audio_packet >= ct << 32)) {
|
||||
debug(1, "As Yeats almost said, \"Too long a silence / can make a stone of the heart\" "
|
||||
"from RTSP conversation %d.",
|
||||
debug(1,
|
||||
"As Yeats almost said, \"Too long a silence / can make a stone of the heart\" "
|
||||
"from RTSP conversation %d.",
|
||||
conn->connection_number);
|
||||
conn->stop = 1;
|
||||
pthread_kill(conn->thread, SIGUSR1);
|
||||
@@ -897,9 +899,8 @@ static abuf_t *buffer_get_frame(rtsp_conn_info *conn) {
|
||||
notified_buffer_empty = 0; // at least one buffer now -- diagnostic only.
|
||||
if (conn->ab_buffering) { // if we are getting packets but not yet forwarding them to the
|
||||
// player
|
||||
int have_sent_prefiller_silence =
|
||||
1; // set true when we have sent some silent frames to the
|
||||
// DAC
|
||||
int have_sent_prefiller_silence = 1; // set true when we have sent some silent frames to
|
||||
// the DAC
|
||||
int64_t reference_timestamp;
|
||||
uint64_t reference_timestamp_time, remote_reference_timestamp_time;
|
||||
get_reference_timestamp_stuff(&reference_timestamp, &reference_timestamp_time,
|
||||
@@ -1351,9 +1352,9 @@ 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
|
||||
|
||||
static 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) {
|
||||
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.");
|
||||
}
|
||||
@@ -1365,6 +1366,7 @@ static int stuff_buffer_soxr_32(int32_t *inptr, int32_t *scratchBuffer, int leng
|
||||
|
||||
if (tstuff) {
|
||||
// debug(1,"Stuff %d.",stuff);
|
||||
|
||||
soxr_io_spec_t io_spec;
|
||||
io_spec.itype = SOXR_INT32_I;
|
||||
io_spec.otype = SOXR_INT32_I;
|
||||
@@ -1374,17 +1376,17 @@ static int stuff_buffer_soxr_32(int32_t *inptr, int32_t *scratchBuffer, int leng
|
||||
|
||||
size_t odone;
|
||||
|
||||
soxr_error_t error = soxr_oneshot(length, length + tstuff, 2, /* Rates and # of chans. */
|
||||
inptr, length, NULL, /* Input. */
|
||||
scratchBuffer, length + tstuff, &odone, /* Output. */
|
||||
&io_spec, /* Input, output and transfer spec. */
|
||||
NULL, NULL); /* Default configuration.*/
|
||||
soxr_error_t error = soxr_oneshot(length, length + tstuff, 2, // Rates and # of chans.
|
||||
inptr, length, NULL, // Input.
|
||||
scratchBuffer, length + tstuff, &odone, // Output.
|
||||
&io_spec, // Input, output and transfer spec.
|
||||
NULL, NULL); // Default configuration.
|
||||
|
||||
if (error)
|
||||
die("soxr error: %s\n", "error: %s\n", soxr_strerror(error));
|
||||
|
||||
if (odone > length + 1)
|
||||
die("odone = %d!\n", odone);
|
||||
if (odone > (size_t)(length + 1))
|
||||
die("odone = %u!\n", odone);
|
||||
|
||||
int i;
|
||||
int32_t *ip, *op;
|
||||
@@ -1399,8 +1401,10 @@ static int stuff_buffer_soxr_32(int32_t *inptr, int32_t *scratchBuffer, int leng
|
||||
}
|
||||
|
||||
// keep the last (dpm) samples, to mitigate the Gibbs phenomenon
|
||||
op = scratchBuffer + (length + tstuff - gpm) * sizeof(int32_t);
|
||||
ip = inptr + (length - gpm) * sizeof(int32_t);
|
||||
|
||||
// pointer arithmetic, baby -- it's da bomb.
|
||||
op = scratchBuffer + (length + tstuff - gpm) * 2;
|
||||
ip = inptr + (length - gpm) * 2;
|
||||
for (i = 0; i < gpm; i++) {
|
||||
*op++ = *ip++;
|
||||
*op++ = *ip++;
|
||||
@@ -1435,7 +1439,7 @@ typedef struct stats { // statistics for running averages
|
||||
int64_t sync_error, correction, drift;
|
||||
} stats_t;
|
||||
|
||||
static void *player_thread_func(void *arg) {
|
||||
void *player_thread_func(void *arg) {
|
||||
// note, the thread will be started up with the player_thread_lock locked. You must release it
|
||||
// quickly.
|
||||
|
||||
@@ -1507,10 +1511,9 @@ static void *player_thread_func(void *arg) {
|
||||
}
|
||||
|
||||
conn->timestamp_epoch = 0; // indicate that the next timestamp will be the first one.
|
||||
conn->maximum_timestamp_interval =
|
||||
conn->input_rate * 60; // actually there shouldn't be more than about 13
|
||||
// seconds of a gap between successive rtptimes, at
|
||||
// worst
|
||||
conn->maximum_timestamp_interval = conn->input_rate * 60; // actually there shouldn't be more than
|
||||
// about 13 seconds of a gap between
|
||||
// successive rtptimes, at worst
|
||||
|
||||
conn->output_sample_ratio = config.output_rate / conn->input_rate;
|
||||
|
||||
@@ -1636,15 +1639,18 @@ static void *player_thread_func(void *arg) {
|
||||
// if ((input_rate!=config.output_rate) || (input_bit_depth!=output_bit_depth)) {
|
||||
// debug(1,"Define tbuf of length
|
||||
// %d.",output_bytes_per_frame*(max_frames_per_packet*output_sample_ratio+max_frame_size_change));
|
||||
tbuf = malloc(sizeof(int32_t) * 2 * (conn->max_frames_per_packet * conn->output_sample_ratio +
|
||||
conn->max_frame_size_change));
|
||||
tbuf = malloc(
|
||||
sizeof(int32_t) * 2 *
|
||||
(conn->max_frames_per_packet * conn->output_sample_ratio + conn->max_frame_size_change));
|
||||
if (tbuf == NULL)
|
||||
die("Failed to allocate memory for the transition buffer.");
|
||||
|
||||
sbuf = 0;
|
||||
// initialise this, because soxr stuffing might be chosen later
|
||||
|
||||
sbuf = malloc(sizeof(int32_t) * 2 * (conn->max_frames_per_packet * conn->output_sample_ratio +
|
||||
conn->max_frame_size_change));
|
||||
sbuf = malloc(
|
||||
sizeof(int32_t) * 2 *
|
||||
(conn->max_frames_per_packet * conn->output_sample_ratio + conn->max_frame_size_change));
|
||||
if (sbuf == NULL)
|
||||
debug(1, "Failed to allocate memory for the sbuf buffer.");
|
||||
|
||||
@@ -1657,9 +1663,8 @@ static void *player_thread_func(void *arg) {
|
||||
die("Failed to allocate memory for an output buffer.");
|
||||
conn->first_packet_timestamp = 0;
|
||||
conn->missing_packets = conn->late_packets = conn->too_late_packets = conn->resend_requests = 0;
|
||||
conn->flush_rtp_timestamp =
|
||||
0; // it seems this number has a special significance -- it seems to be used
|
||||
// as a null operand, so we'll use it like that too
|
||||
conn->flush_rtp_timestamp = 0; // it seems this number has a special significance -- it seems to
|
||||
// be used as a null operand, so we'll use it like that too
|
||||
int sync_error_out_of_bounds =
|
||||
0; // number of times in a row that there's been a serious sync error
|
||||
|
||||
@@ -1671,7 +1676,10 @@ static void *player_thread_func(void *arg) {
|
||||
// this is only used for compatability, if dacp stuff isn't enabled.
|
||||
// start an mdns/zeroconf thread to look for DACP messages containing our DACP_ID and getting the
|
||||
// port number
|
||||
conn->dapo_private_storage = mdns_dacp_monitor(conn->dacp_id);
|
||||
if (conn->dapo_private_storage)
|
||||
debug(1, "DACP monitor already initialised?");
|
||||
else
|
||||
conn->dapo_private_storage = mdns_dacp_monitor(conn->dacp_id);
|
||||
#endif
|
||||
|
||||
conn->framesProcessedInThisEpoch = 0;
|
||||
@@ -1744,8 +1752,9 @@ static void *player_thread_func(void *arg) {
|
||||
} else {
|
||||
// the player may change the contents of the buffer, so it has to be zeroed each time;
|
||||
// might as well malloc and freee it locally
|
||||
memset(silence, 0, conn->output_bytes_per_frame * conn->max_frames_per_packet *
|
||||
conn->output_sample_ratio);
|
||||
memset(silence, 0,
|
||||
conn->output_bytes_per_frame * conn->max_frames_per_packet *
|
||||
conn->output_sample_ratio);
|
||||
config.output->play(silence, conn->max_frames_per_packet * conn->output_sample_ratio);
|
||||
free(silence);
|
||||
}
|
||||
@@ -1765,8 +1774,9 @@ static void *player_thread_func(void *arg) {
|
||||
} else {
|
||||
// the player may change the contents of the buffer, so it has to be zeroed each time;
|
||||
// might as well malloc and freee it locally
|
||||
memset(silence, 0, conn->output_bytes_per_frame * conn->max_frames_per_packet *
|
||||
conn->output_sample_ratio);
|
||||
memset(silence, 0,
|
||||
conn->output_bytes_per_frame * conn->max_frames_per_packet *
|
||||
conn->output_sample_ratio);
|
||||
config.output->play(silence, conn->max_frames_per_packet * conn->output_sample_ratio);
|
||||
free(silence);
|
||||
}
|
||||
@@ -1913,8 +1923,9 @@ static void *player_thread_func(void *arg) {
|
||||
SUCCESSOR(conn->last_seqno_read); // int32_t from seq_t, i.e. uint16_t, so okay.
|
||||
if (inframe->sequence_number !=
|
||||
conn->last_seqno_read) { // seq_t, ei.e. uint16_t and int32_t, so okay
|
||||
debug(2, "Player: packets out of sequence: expected: %u, got: %u, with ab_read: %u "
|
||||
"and ab_write: %u.",
|
||||
debug(2,
|
||||
"Player: packets out of sequence: expected: %u, got: %u, with ab_read: %u "
|
||||
"and ab_write: %u.",
|
||||
conn->last_seqno_read, inframe->sequence_number, conn->ab_read, conn->ab_write);
|
||||
conn->last_seqno_read = inframe->sequence_number; // reset warning...
|
||||
}
|
||||
@@ -2065,7 +2076,7 @@ static void *player_thread_func(void *arg) {
|
||||
#ifdef CONFIG_CONVOLUTION
|
||||
|| config.convolution
|
||||
#endif
|
||||
) {
|
||||
) {
|
||||
int32_t *tbuf32 = (int32_t *)tbuf;
|
||||
float fbuf_l[inbuflength];
|
||||
float fbuf_r[inbuflength];
|
||||
@@ -2267,10 +2278,10 @@ static void *player_thread_func(void *arg) {
|
||||
"%*d", /* max buffer occupancy */
|
||||
9, /* should be 10, but there's an explicit space at the start to ensure
|
||||
alignment */
|
||||
1000 * moving_average_sync_error / config.output_rate,
|
||||
10, moving_average_correction * 1000000 / (352 * conn->output_sample_ratio),
|
||||
10, moving_average_insertions_plus_deletions * 1000000 /
|
||||
(352 * conn->output_sample_ratio),
|
||||
1000 * moving_average_sync_error / config.output_rate, 10,
|
||||
moving_average_correction * 1000000 / (352 * conn->output_sample_ratio), 10,
|
||||
moving_average_insertions_plus_deletions * 1000000 /
|
||||
(352 * conn->output_sample_ratio),
|
||||
12, play_number, 7, conn->missing_packets, 7, conn->late_packets, 7,
|
||||
conn->too_late_packets, 7, conn->resend_requests, 7, minimum_dac_queue_size,
|
||||
5, minimum_buffer_occupancy, 5, maximum_buffer_occupancy);
|
||||
@@ -2286,11 +2297,10 @@ static void *player_thread_func(void *arg) {
|
||||
"%*d", /* max buffer occupancy */
|
||||
9, /* should be 10, but there's an explicit space at the start to ensure
|
||||
alignment */
|
||||
1000 * moving_average_sync_error / config.output_rate,
|
||||
12, play_number, 7, conn->missing_packets, 7, conn->late_packets, 7,
|
||||
conn->too_late_packets, 7, conn->resend_requests, 7,
|
||||
minimum_dac_queue_size, 5, minimum_buffer_occupancy, 5,
|
||||
maximum_buffer_occupancy);
|
||||
1000 * moving_average_sync_error / config.output_rate, 12, play_number, 7,
|
||||
conn->missing_packets, 7, conn->late_packets, 7, conn->too_late_packets, 7,
|
||||
conn->resend_requests, 7, minimum_dac_queue_size, 5,
|
||||
minimum_buffer_occupancy, 5, maximum_buffer_occupancy);
|
||||
}
|
||||
} else {
|
||||
inform(" %*.1f," /* Sync error in milliseconds */
|
||||
@@ -2303,10 +2313,10 @@ static void *player_thread_func(void *arg) {
|
||||
"%*d", /* max buffer occupancy */
|
||||
9, /* should be 10, but there's an explicit space at the start to ensure
|
||||
alignment */
|
||||
1000 * moving_average_sync_error / config.output_rate,
|
||||
12, play_number, 7, conn->missing_packets, 7, conn->late_packets, 7,
|
||||
conn->too_late_packets, 7, conn->resend_requests, 5,
|
||||
minimum_buffer_occupancy, 5, maximum_buffer_occupancy);
|
||||
1000 * moving_average_sync_error / config.output_rate, 12, play_number, 7,
|
||||
conn->missing_packets, 7, conn->late_packets, 7, conn->too_late_packets, 7,
|
||||
conn->resend_requests, 5, minimum_buffer_occupancy, 5,
|
||||
maximum_buffer_occupancy);
|
||||
}
|
||||
} else {
|
||||
inform("No frames received in the last sampling interval.");
|
||||
@@ -2335,7 +2345,12 @@ static void *player_thread_func(void *arg) {
|
||||
#ifndef HAVE_DACP_CLIENT
|
||||
// stop watching for DACP port number stuff
|
||||
// this is only used for compatability, if dacp stuff isn't enabled.
|
||||
mdns_dacp_dont_monitor(conn->dapo_private_storage);
|
||||
if (conn->dapo_private_storage) {
|
||||
mdns_dacp_dont_monitor(conn->dapo_private_storage);
|
||||
conn->dapo_private_storage = NULL;
|
||||
} else {
|
||||
debug(2, "DACP Monitor already stopped");
|
||||
}
|
||||
#endif
|
||||
|
||||
debug(3, "Connection %d: stopping output device.", conn->connection_number);
|
||||
|
||||
Reference in New Issue
Block a user