Skip to content

Commit

Permalink
Use an explicit 'is_running' flag in the sndio back end. Correct/impr…
Browse files Browse the repository at this point in the history
…ove some sndio documentation.
  • Loading branch information
mikebrady committed Jul 22, 2024
1 parent 10b965a commit 597aba0
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 38 deletions.
94 changes: 60 additions & 34 deletions audio_sndio.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Copyright (c) 2017 Tobias Kortkamp <[email protected]>
*
* Modifications for audio synchronisation
* and related work, copyright (c) Mike Brady 2014 -- 2022
* and related work, copyright (c) Mike Brady 2014 -- 2024
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software for any
Expand All @@ -30,6 +30,7 @@

static pthread_mutex_t sndio_mutex = PTHREAD_MUTEX_INITIALIZER;
static struct sio_hdl *hdl;
static int is_running;
static int framesize;
static size_t played;
static size_t written;
Expand Down Expand Up @@ -58,7 +59,9 @@ static struct sndio_formats formats[] = {{"S8", SPS_FORMAT_S8, 44100, 8, 1, 1, S
{"S24_3BE", SPS_FORMAT_S24_3BE, 44100, 24, 3, 1, 0},
{"S32", SPS_FORMAT_S32, 44100, 32, 4, 1, SIO_LE_NATIVE}};

static void help() { printf(" -d output-device set the output device [default*|...]\n"); }
static void help() {
printf(" -d output-device set the output device [default|rsnd/0|rsnd/1...]\n");
}

void onmove_cb(__attribute__((unused)) void *arg, int delta) {
time_of_last_onmove_cb = get_absolute_time_in_ns();
Expand Down Expand Up @@ -155,6 +158,7 @@ static int init(int argc, char **argv) {
debug(1, "sndio: rate: %u.", par.rate);
debug(1, "sndio: bits: %u.", par.bits);

is_running = 0;
hdl = sio_open(devname, SIO_PLAY, 0);
if (!hdl)
die("sndio: cannot open audio device");
Expand Down Expand Up @@ -206,48 +210,54 @@ static int init(int argc, char **argv) {
}

static void deinit() {
// pthread_mutex_lock(&sndio_mutex);
pthread_cleanup_debug_mutex_lock(&sndio_mutex, 1000, 1);
sio_close(hdl);
// pthread_mutex_unlock(&sndio_mutex);
pthread_cleanup_pop(1); // unlock the mutex
}

static void start(__attribute__((unused)) int sample_rate,
__attribute__((unused)) int sample_format) {
// pthread_mutex_lock(&sndio_mutex);
pthread_cleanup_debug_mutex_lock(&sndio_mutex, 1000, 1);
at_least_one_onmove_cb_seen = 0;
// any previously-reported frame count

if (!sio_start(hdl))
die("sndio: unable to start");
written = played = 0;
time_of_last_onmove_cb = 0;
at_least_one_onmove_cb_seen = 0;
// pthread_mutex_unlock(&sndio_mutex);
if (hdl != NULL) {
if (is_running != 0) {
sio_flush(hdl);
is_running = 0;
}
sio_close(hdl);
hdl = NULL;
}
pthread_cleanup_pop(1); // unlock the mutex
}

static int play(void *buf, int frames, __attribute__((unused)) int sample_type,
__attribute__((unused)) uint32_t timestamp,
__attribute__((unused)) uint64_t playtime) {
if (frames > 0) {
// pthread_mutex_lock(&sndio_mutex);
pthread_cleanup_debug_mutex_lock(&sndio_mutex, 1000, 1);
if (is_running == 0) {
if (hdl != NULL) {
if (sio_start(hdl) != 1)
debug(1, "sndio: unable to start");
is_running = 1;
written = played = 0;
time_of_last_onmove_cb = 0;
at_least_one_onmove_cb_seen = 0;
} else {
debug(1, "sndio: output device is not open for play!");
}
}
written += sio_write(hdl, buf, frames * framesize);
// pthread_mutex_unlock(&sndio_mutex);
pthread_cleanup_pop(1); // unlock the mutex
}
return 0;
}

static void stop() {
pthread_cleanup_debug_mutex_lock(&sndio_mutex, 1000, 1);

if (!sio_stop(hdl))
die("sndio: unable to stop");
written = played = 0;
if (hdl != NULL) {
if (is_running != 0) {
if (sio_flush(hdl) != 1)
debug(1, "sndio: unable to stop");
written = played = is_running = 0;
} else {
debug(1, "sndio: stop: not running.");
}
} else {
debug(1, "sndio: output device is not open for stop!");
}
pthread_cleanup_pop(1); // unlock the mutex
}

Expand Down Expand Up @@ -276,18 +286,34 @@ int get_delay(long *delay) {
static int delay(long *delay) {
int result = 0;
pthread_cleanup_debug_mutex_lock(&sndio_mutex, 1000, 1);
result = get_delay(delay);
if (hdl != NULL) {
if (is_running != 0) {
result = get_delay(delay);
} else {
debug(1, "sndio: output device is not open for delay!");
if (delay != NULL)
*delay = 0;
}
} else {
debug(1, "sndio: output device is not open for delay!");
}
pthread_cleanup_pop(1); // unlock the mutex
return result;
}

static void flush() {
// pthread_mutex_lock(&sndio_mutex);
pthread_cleanup_debug_mutex_lock(&sndio_mutex, 1000, 1);
if (!sio_stop(hdl) || !sio_start(hdl))
die("sndio: unable to flush");
written = played = 0;
// pthread_mutex_unlock(&sndio_mutex);
if (hdl != NULL) {
if (is_running != 0) {
if (sio_flush(hdl) != 1)
debug(1, "sndio: unable to flush");
written = played = is_running = 0;
} else {
debug(1, "sndio: flush: not running.");
}
} else {
debug(1, "sndio: output device is not open for flush!");
}
pthread_cleanup_pop(1); // unlock the mutex
}

Expand All @@ -296,7 +322,7 @@ audio_output audio_sndio = {.name = "sndio",
.init = &init,
.deinit = &deinit,
.prepare = NULL,
.start = &start,
.start = NULL,
.stop = &stop,
.is_running = NULL,
.flush = &flush,
Expand Down
7 changes: 4 additions & 3 deletions player.c
Original file line number Diff line number Diff line change
Expand Up @@ -2141,9 +2141,10 @@ void *player_thread_func(void *arg) {
if ((config.output->parameters == NULL) || (conn->input_bit_depth > output_bit_depth) ||
(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

// call the backend's start() function if it exists.
if (config.output->start != NULL)
config.output->start(config.output_rate, config.output_format);

// we need an intermediate "transition" buffer

Expand Down
2 changes: 1 addition & 1 deletion scripts/shairport-sync.conf
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ pw =
// --with-sndio
sndio =
{
// device = "snd/0"; // optional setting to set the name of the output device. Default is the sndio system default.
// device = "default"; // optional setting to set the name of the output device, e.g. "rsnd/0", "rsnd/1", etc.
// rate = 44100; // optional setting which can be 44100, 88200, 176400 or 352800, but the device must have the capability. Default is 44100.
// format = "S16"; // optional setting which can be "U8", "S8", "S16", "S24", "S24_3LE", "S24_3BE" or "S32", but the device must have the capability. Except where stated using (*LE or *BE), endianness matches that of the processor.
// round = <number>; // advanced optional setting to set the period size near to this value
Expand Down

0 comments on commit 597aba0

Please sign in to comment.