}
// here, we should check for missing frames
+ int resend_interval = (((250 * 44100) / 352) / 1000); // approximately 250 ms intervals
const int number_of_resend_attempts = 8;
+ int latency_based_resend_interval =
+ (conn->latency) / (number_of_resend_attempts * conn->max_frames_per_packet);
+ if (latency_based_resend_interval > resend_interval)
+ resend_interval = latency_based_resend_interval;
+
+ if (conn->resend_interval != resend_interval) {
+ debug(1, "Resend interval for latency of %" PRId64 " frames is %d frames.", conn->latency,
+ resend_interval);
+ conn->resend_interval = resend_interval;
+ }
if (!conn->ab_buffering) {
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
- // int back_step = (((250 * 44100) / 352) / 1000) * (j); // approx 250 ms intervals
- // int back_step = ((BUFFER_FRAMES-(22050/352)) / number_of_resend_attempts) * j;
- int back_step = ((seq_diff(conn->ab_read, conn->ab_write,
- conn->ab_read)-(22050/352)) / number_of_resend_attempts) * j;
- if (back_step<(((190 * 44100) / 352) / 1000) * j) {
- // debug(1,"resend request back_step %d is too small. Reset to %d.",back_step,(((190 * 44100) / 352) / 1000) * j);
- back_step = (((190 * 44100) / 352) / 1000) * j;
- }
+
+ int back_step = resend_interval * j;
+
+ int32_t sd = seq_diff(conn->ab_read, conn->ab_write, conn->ab_read);
int k;
for (k = -2; k <= 2; k++) {
- if (back_step <
- seq_diff(conn->ab_read, conn->ab_write,
- conn->ab_read)) { // if it's within the range of frames in use...
- int item_to_check = (conn->ab_write - back_step) & 0xffff;
+ if ((back_step + k) < sd) { // if it's within the range of frames in use...
+ int item_to_check = (conn->ab_write - back_step + k) & 0xffff;
seq_t next = item_to_check;
abuf_t *check_buf = conn->audio_buffer + BUFIDX(next);
if ((!check_buf->ready) &&
check_buf->resend_level = j;
if (config.disable_resend_requests == 0) {
rtp_request_resend(next, 1, conn);
- if (j >= 6)
+ if (j >= number_of_resend_attempts - 2)
debug(2, "Resend request level #%d for packet %u in range %u to %u.", j, next,
conn->ab_read, conn->ab_write);
conn->resend_requests++;
} abuf_t;
// default buffer size
-// needs to be a power of 2 because of the way BUFIDX(seqno) works
+// This eeds to be a power of 2 because of the way BUFIDX(seqno) works.
+// 512 is the minimum for normal operation -- it gives 512*352/44100 or just over 4 seconds of
+// buffers.
+// For at least 10 seconds, you need to go to 2048.
+// Resend requests will be spaced out evenly in the latency period, subject to a minimum interval of
+// about 0.25 seconds.
+// Each buffer occupies 352*4 bytes plus about, say, 64 bytes of overhead in various places, say
+// rougly 1,500 bytes per buffer.
+// Thus, 2048 buffers will occupy about 3 megabytes -- no big deal in a normal machine but maybe a
+// problem in an embedded device.
+
#define BUFFER_FRAMES 1024
typedef struct {
typedef struct {
int connection_number; // for debug ID purposes, nothing else...
+ int resend_interval; // this is really just for debugging
int AirPlayVersion; // zero if not an AirPlay session. Used to help calculate latency
int64_t latency; // the actual latency used for this play session
int64_t minimum_latency; // set if an a=min-latency: line appears in the ANNOUNCE message; zero
optind = j;
optCon = poptGetContext(NULL, optind, (const char **)argv, optionsTable, 0);
- if (optCon==NULL)
+ if (optCon == NULL)
die("Can not get a secondary popt context.");
poptSetOtherOptionHelp(optCon, "[OPTIONS]* ");
}
poptFreeContext(optCon);
-
+
if ((daemonisewith) && (daemonisewithout))
die("Select either daemonize_with_pid_file or daemonize_without_pid_file -- you have selected "
"both!");
optind = j;
optCon = poptGetContext(NULL, optind, (const char **)argv, optionsTable, 0);
- if (optCon==NULL)
+ if (optCon == NULL)
die("Can not get a popt context.");
poptSetOtherOptionHelp(optCon, "[OPTIONS]* ");
}
}
-const char *pid_file_proc(char* fn,size_t max_length) {
+const char *pid_file_proc(char *fn, size_t max_length) {
if (fn) {
snprintf(fn, max_length, "%s/%s.pid", config.computed_piddir,
daemon_pid_file_ident ? daemon_pid_file_ident : "unknown");
// debug(1,"fn \"%s\".",fn);
} else {
- debug(1,"the sise of the buffer for the PID file path is zero.");
+ debug(1, "the sise of the buffer for the PID file path is zero.");
}
return fn;
}
// audio_backend_latency_offset instead.
if (config.userSuppliedLatency) {
- inform("The fixed latency setting is deprecated, as Shairport Sync can now get the correct "
- "latency from the source.");
- inform("Please remove this setting and use the relevant audio_backend_latency_offset setting, "
- "if necessary, to compensate for delays elsewhere.");
- if ((config.userSuppliedLatency!=0) && ((config.userSuppliedLatency<4410) || (config.userSuppliedLatency>BUFFER_FRAMES*352-22050)))
- die("An out-of-range fixed latency has been specified. It must be between 4410 and %d (at 44100 frames per second).",BUFFER_FRAMES*352-22050);
+ inform("The fixed latency setting is deprecated, as Shairport Sync gets the correct "
+ "latency automatically from the source.");
+ inform("Use the audio_backend_latency_offset_in_seconds setting "
+ "instead to compensate for timing issues.");
+ if ((config.userSuppliedLatency != 0) &&
+ ((config.userSuppliedLatency < 4410) ||
+ (config.userSuppliedLatency > BUFFER_FRAMES * 352 - 22050)))
+ die("An out-of-range fixed latency has been specified. It must be between 4410 and %d (at "
+ "44100 frames per second).",
+ BUFFER_FRAMES * 352 - 22050);
}
/* print out version */
/* Print out options */
debug(1, "statistics_requester status is %d.", config.statistics_requested);
debug(1, "daemon status is %d.", config.daemonise);
- debug(1, "deamon pid file is \"%s\".", pid_file_proc(pid_file_path_string,4096));
+ debug(1, "deamon pid file is \"%s\".", pid_file_proc(pid_file_path_string, 4096));
debug(1, "rtsp listening port is %d.", config.port);
debug(1, "udp base port is %d.", config.udp_port_base);
debug(1, "udp port range is %d.", config.udp_port_range);