summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--audio.h1
-rw-r--r--audio_alsa.c37
-rw-r--r--audio_ao.c1
-rw-r--r--audio_dummy.c1
-rw-r--r--audio_jack.c1
-rw-r--r--audio_pa.c1
-rw-r--r--audio_pipe.c1
-rw-r--r--audio_sndio.c1
-rw-r--r--audio_soundio.c1
-rw-r--r--audio_stdout.c1
-rw-r--r--common.h3
11 files changed, 39 insertions, 10 deletions
diff --git a/audio.h b/audio.h
index a4f0f17..b8ecf95 100644
--- a/audio.h
+++ b/audio.h
@@ -22,6 +22,7 @@ typedef struct {
void (*start)(int sample_rate, int sample_format);
// block of samples
+ int (*preflight)(void *buf, int samples); // say you are about to send these samples (before interpolation)
int (*play)(void *buf, int samples);
void (*stop)(void);
diff --git a/audio_alsa.c b/audio_alsa.c
index b1c7ae7..b7a5de8 100644
--- a/audio_alsa.c
+++ b/audio_alsa.c
@@ -42,6 +42,7 @@ static int init(int argc, char **argv);
static void deinit(void);
static void start(int i_sample_rate, int i_sample_format);
static int play(void *buf, int samples);
+int preflight(void *buf, int samples);
static void stop(void);
static void flush(void);
int delay(long *the_delay);
@@ -632,6 +633,8 @@ static int init(int argc, char **argv) {
config.audio_backend_buffer_interpolation_threshold_in_seconds =
0.100; // below this, basic interpolation will be used to save time.
config.alsa_maximum_stall_time = 0.200; // 200 milliseconds -- if it takes longer, it's a problem
+ config.audio_backend_silence_threshold = 0.050; //start sending silent frames if the delay goes below this time
+ config.audio_backend_silence_scan_interval = 0.005; //check silence threshold this often
stall_monitor_error_threshold =
(uint64_t)1000000 * config.alsa_maximum_stall_time; // stall time max to microseconds;
@@ -1081,7 +1084,7 @@ int delay_and_status(snd_pcm_state_t *state, snd_pcm_sframes_t *delay) {
return ret;
}
-int untimed_delay(long *the_delay) {
+int delay(long *the_delay) {
// returns 0 if the device is in a valid state -- SND_PCM_STATE_RUNNING or SND_PCM_STATE_PREPARED
// or SND_PCM_STATE_DRAINING
// and returns the actual delay if running or 0 if prepared in *the_delay
@@ -1126,7 +1129,7 @@ int get_rate_information(uint64_t *elapsed_time, uint64_t *frames_played) {
return response;
}
-int untimed_play(void *buf, int samples) {
+int play(void *buf, int samples) {
// debug(3,"audio_alsa play called.");
int oldState;
@@ -1258,6 +1261,16 @@ static void flush(void) {
pthread_setcancelstate(oldState, NULL);
}
+int preflight(__attribute__((unused)) void *buf, __attribute__((unused)) int samples) {
+ uint64_t time_now =
+ get_absolute_time_in_fp(); // this is to regulate access by the silence filler thread
+ uint64_t standoff_time = 100; // milliseconds
+ standoff_time = (standoff_time << 32)/1000;
+ most_recent_write_time = time_now + standoff_time;
+ return 0;
+}
+
+/*
static int play(void *buf, int samples) {
uint64_t time_now =
get_absolute_time_in_fp(); // this is to regulate access by the silence filler thread
@@ -1273,6 +1286,7 @@ int delay(long *the_delay) {
most_recent_write_time = time_now;
return untimed_delay(the_delay);
}
+*/
static void stop(void) {
// debug(2,"audio_alsa stop called.");
@@ -1451,12 +1465,14 @@ void *alsa_buffer_monitor_thread_code(void *arg) {
debug(1, "alsa: dither will %sbe added to inter-session silence.", use_dither ? "" : "not ");
- int sleep_time_ms = 30;
+ int sleep_time_ms = (int)(config.audio_backend_silence_scan_interval * 1000);
+ long buffer_size_threshold = (long)(config.audio_backend_silence_threshold * desired_sample_rate);
+
uint64_t sleep_time_in_fp = sleep_time_ms;
sleep_time_in_fp = sleep_time_in_fp << 32;
sleep_time_in_fp = sleep_time_in_fp / 1000;
// debug(1,"alsa: sleep_time: %d ms or 0x%" PRIx64 " in fp form.",sleep_time_ms,sleep_time_in_fp);
- int frames_of_silence = (desired_sample_rate * sleep_time_ms * 2) / 1000;
+ int frames_of_silence = (desired_sample_rate * sleep_time_ms * 4) / 1000;
size_t size_of_silence_buffer = frames_of_silence * frame_size;
// debug(1,"Silence buffer length: %u bytes.",size_of_silence_buffer);
void *silence = malloc(size_of_silence_buffer);
@@ -1470,10 +1486,11 @@ void *alsa_buffer_monitor_thread_code(void *arg) {
if (config.keep_dac_busy != 0) {
uint64_t present_time = get_absolute_time_in_fp();
- if ((most_recent_write_time == 0) ||
- ((present_time > most_recent_write_time) &&
- ((present_time - most_recent_write_time) > (sleep_time_in_fp)))) {
- reply = untimed_delay(&buffer_size);
+ if ((most_recent_write_time == 0) || (present_time > most_recent_write_time)) {
+
+// ((present_time > most_recent_write_time) &&
+// ((present_time - most_recent_write_time) > (sleep_time_in_fp)))) {
+ reply = delay(&buffer_size);
if (reply != 0) {
buffer_size = 0;
char errorstring[1024];
@@ -1481,7 +1498,7 @@ void *alsa_buffer_monitor_thread_code(void *arg) {
debug(1, "alsa: alsa_buffer_monitor_thread_code delay error %d: \"%s\".", reply,
(char *)errorstring);
}
- if (buffer_size < frames_of_silence) {
+ if (buffer_size < buffer_size_threshold) {
if ((hardware_mixer == 0) && (config.ignore_volume_control == 0) &&
(config.airplay_volume != 0.0))
use_dither = 1;
@@ -1492,7 +1509,7 @@ void *alsa_buffer_monitor_thread_code(void *arg) {
dither_random_number_store);
// debug(1,"Play %d frames of silence with most_recent_write_time of %" PRIx64 ".",
// frames_of_silence,most_recent_write_time);
- untimed_play(silence, frames_of_silence);
+ play(silence, frames_of_silence);
}
} else {
// debug(2,"Skipping sending silence");
diff --git a/audio_ao.c b/audio_ao.c
index 42147ba..30f80d8 100644
--- a/audio_ao.c
+++ b/audio_ao.c
@@ -134,6 +134,7 @@ audio_output audio_ao = {.name = "ao",
.is_running = NULL,
.flush = NULL,
.delay = NULL,
+ .preflight = NULL,
.play = &play,
.volume = NULL,
.parameters = NULL,
diff --git a/audio_dummy.c b/audio_dummy.c
index d8dea87..69518cd 100644
--- a/audio_dummy.c
+++ b/audio_dummy.c
@@ -65,6 +65,7 @@ audio_output audio_dummy = {.name = "dummy",
.is_running = NULL,
.flush = NULL,
.delay = NULL,
+ .preflight = NULL,
.play = &play,
.volume = NULL,
.parameters = NULL,
diff --git a/audio_jack.c b/audio_jack.c
index 11ae607..90f08ac 100644
--- a/audio_jack.c
+++ b/audio_jack.c
@@ -67,6 +67,7 @@ audio_output audio_jack = {.name = "jack",
.is_running = &jack_is_running,
.flush = &jack_flush,
.delay = &jack_delay,
+ .preflight = NULL,
.play = &play,
.volume = NULL,
.parameters = NULL,
diff --git a/audio_pa.c b/audio_pa.c
index cd321bd..4ee20c7 100644
--- a/audio_pa.c
+++ b/audio_pa.c
@@ -312,6 +312,7 @@ audio_output audio_pa = {.name = "pa",
.flush = &flush,
.delay = &pa_delay,
.play = &play,
+ .preflight = NULL,
.volume = NULL,
.parameters = NULL,
.mute = NULL};
diff --git a/audio_pipe.c b/audio_pipe.c
index 89a09a0..0d4a42f 100644
--- a/audio_pipe.c
+++ b/audio_pipe.c
@@ -139,6 +139,7 @@ audio_output audio_pipe = {.name = "pipe",
.flush = NULL,
.delay = NULL,
.play = &play,
+ .preflight = NULL,
.volume = NULL,
.parameters = NULL,
.mute = NULL};
diff --git a/audio_sndio.c b/audio_sndio.c
index f22ed5a..e106b15 100644
--- a/audio_sndio.c
+++ b/audio_sndio.c
@@ -49,6 +49,7 @@ audio_output audio_sndio = {.name = "sndio",
.flush = &flush,
.delay = &delay,
.play = &play,
+ .preflight = NULL,
.volume = NULL,
.parameters = NULL,
.mute = NULL};
diff --git a/audio_soundio.c b/audio_soundio.c
index 7d3b48a..0449895 100644
--- a/audio_soundio.c
+++ b/audio_soundio.c
@@ -221,6 +221,7 @@ audio_output audio_soundio = {.name = "soundio",
.flush = &flush,
.delay = NULL,
.play = &play,
+ .preflight = NULL,
.volume = NULL,
.parameters = &parameters,
.mute = NULL};
diff --git a/audio_stdout.c b/audio_stdout.c
index 0438b1a..37d6f78 100644
--- a/audio_stdout.c
+++ b/audio_stdout.c
@@ -86,6 +86,7 @@ audio_output audio_stdout = {.name = "stdout",
.flush = NULL,
.delay = NULL,
.play = &play,
+ .preflight = NULL,
.volume = NULL,
.parameters = NULL,
.mute = NULL};
diff --git a/common.h b/common.h
index 35996fe..6f07f6d 100644
--- a/common.h
+++ b/common.h
@@ -171,6 +171,9 @@ typedef struct {
double audio_backend_buffer_interpolation_threshold_in_seconds; // below this, soxr interpolation
// will not occur -- it'll be
// basic interpolation instead.
+ double audio_backend_silence_threshold; // below this, silence will be added to the output buffer
+ double audio_backend_silence_scan_interval; // check the threshold this often
+
double audio_backend_latency_offset; // this will be the offset in seconds to compensate for any
// 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.