Change SIGUSR2 to turn on and off reserving the output device.
This commit is contained in:
+23
-19
@@ -181,7 +181,7 @@ static void deinit(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void open_alsa_device(void) {
|
||||
int open_alsa_device(void) {
|
||||
|
||||
int ret, dir = 0;
|
||||
unsigned int my_sample_rate = desired_sample_rate;
|
||||
@@ -189,7 +189,8 @@ void open_alsa_device(void) {
|
||||
snd_pcm_uframes_t buffer_size = frames*4;
|
||||
ret = snd_pcm_open(&alsa_handle, alsa_out_dev, SND_PCM_STREAM_PLAYBACK, 0);
|
||||
if (ret < 0)
|
||||
die("Alsa initialization failed: unable to open pcm device: %s.", snd_strerror(ret));
|
||||
return(ret);
|
||||
// die("Alsa initialization failed: unable to open pcm device: %s.", snd_strerror(ret));
|
||||
|
||||
snd_pcm_hw_params_alloca(&alsa_params);
|
||||
snd_pcm_hw_params_any(alsa_handle, alsa_params);
|
||||
@@ -206,6 +207,7 @@ void open_alsa_device(void) {
|
||||
if (my_sample_rate!=desired_sample_rate) {
|
||||
die("Can't set the D/A converter to %d -- set to %d instead./n",desired_sample_rate,my_sample_rate);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
void close_alsa_device(void) {
|
||||
@@ -220,7 +222,6 @@ static void start(int sample_rate) {
|
||||
if (sample_rate != 44100)
|
||||
die("Unexpected sample rate %d -- only 44,100 supported!",sample_rate);
|
||||
desired_sample_rate = sample_rate; // must be a variable
|
||||
// open_alsa_device();
|
||||
}
|
||||
|
||||
static uint32_t delay() {
|
||||
@@ -259,25 +260,28 @@ static uint32_t delay() {
|
||||
}
|
||||
|
||||
static void play(short buf[], int samples) {
|
||||
int ret = 0;
|
||||
if (alsa_handle==NULL)
|
||||
open_alsa_device();
|
||||
pthread_mutex_lock(&alsa_mutex);
|
||||
snd_pcm_sframes_t current_delay = 0;
|
||||
int err,ignore;
|
||||
if ((snd_pcm_state(alsa_handle)==SND_PCM_STATE_PREPARED) || (snd_pcm_state(alsa_handle)==SND_PCM_STATE_RUNNING)) {
|
||||
err = snd_pcm_writei(alsa_handle, (char*)buf, samples);
|
||||
if (err < 0) {
|
||||
ignore = snd_pcm_recover(alsa_handle, err, 0);
|
||||
debug(1,"Error %d writing %d samples in play() %s.",err,samples, snd_strerror(err));
|
||||
}
|
||||
} else {
|
||||
debug(1,"Error -- ALSA device in incorrect state (%d) for play.",snd_pcm_state(alsa_handle));
|
||||
if (err = snd_pcm_prepare(alsa_handle)) {
|
||||
ignore = snd_pcm_recover(alsa_handle, err, 0);
|
||||
debug(1,"Error preparing after play error: %s.", snd_strerror(err));
|
||||
ret = open_alsa_device();
|
||||
if (ret==0) {
|
||||
pthread_mutex_lock(&alsa_mutex);
|
||||
snd_pcm_sframes_t current_delay = 0;
|
||||
int err,ignore;
|
||||
if ((snd_pcm_state(alsa_handle)==SND_PCM_STATE_PREPARED) || (snd_pcm_state(alsa_handle)==SND_PCM_STATE_RUNNING)) {
|
||||
err = snd_pcm_writei(alsa_handle, (char*)buf, samples);
|
||||
if (err < 0) {
|
||||
ignore = snd_pcm_recover(alsa_handle, err, 0);
|
||||
debug(1,"Error %d writing %d samples in play() %s.",err,samples, snd_strerror(err));
|
||||
}
|
||||
} else {
|
||||
debug(1,"Error -- ALSA device in incorrect state (%d) for play.",snd_pcm_state(alsa_handle));
|
||||
if (err = snd_pcm_prepare(alsa_handle)) {
|
||||
ignore = snd_pcm_recover(alsa_handle, err, 0);
|
||||
debug(1,"Error preparing after play error: %s.", snd_strerror(err));
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&alsa_mutex);
|
||||
}
|
||||
pthread_mutex_unlock(&alsa_mutex);
|
||||
}
|
||||
|
||||
static void flush(void) {
|
||||
|
||||
@@ -69,11 +69,23 @@
|
||||
#include "common.h"
|
||||
#include <libdaemon/dlog.h>
|
||||
|
||||
//true if Shairport Sync is supposed to be sending output to the output device, false otherwise
|
||||
|
||||
static volatile int requested_connection_state_to_output = 1;
|
||||
|
||||
shairport_cfg config;
|
||||
|
||||
int debuglev = 0;
|
||||
|
||||
int get_requested_connection_state_to_output() {
|
||||
return requested_connection_state_to_output;
|
||||
}
|
||||
|
||||
void set_requested_connection_state_to_output(int v) {
|
||||
requested_connection_state_to_output = v;
|
||||
}
|
||||
|
||||
|
||||
void die(char *format, ...) {
|
||||
char s[1024];
|
||||
s[0]=0;
|
||||
|
||||
@@ -63,6 +63,12 @@ typedef struct {
|
||||
char *errfile;
|
||||
} shairport_cfg;
|
||||
|
||||
//true if Shairport Sync is supposed to be sending output to the output device, false otherwise
|
||||
|
||||
int get_requested_connection_state_to_output();
|
||||
|
||||
void set_requested_connection_state_to_output(int v);
|
||||
|
||||
int debuglev;
|
||||
void die(char *format, ...);
|
||||
void warn(char *format, ...);
|
||||
|
||||
@@ -82,6 +82,8 @@ static aes_context dctx;
|
||||
static pthread_t player_thread;
|
||||
static int please_stop;
|
||||
|
||||
static int connection_state_to_output; // if true, then play incoming stuff; if false drop everything
|
||||
|
||||
static alac_file *decoder_info;
|
||||
|
||||
// debug variables
|
||||
@@ -296,72 +298,75 @@ static void free_buffer(void) {
|
||||
void player_put_packet(seq_t seqno,uint32_t timestamp, uint8_t *data, int len) {
|
||||
|
||||
packet_count++;
|
||||
time_of_last_audio_packet = get_absolute_time_in_fp();
|
||||
|
||||
pthread_mutex_lock(&ab_mutex);
|
||||
|
||||
if ((flush_rtp_timestamp!=0x7fffffff) && ((timestamp==flush_rtp_timestamp) || seq32_order(timestamp,flush_rtp_timestamp))) {
|
||||
debug(2,"Dropping flushed packet in player_put_packet, seqno %u, timestamp %u, flushing to timestamp: %u.",seqno,timestamp,flush_rtp_timestamp);
|
||||
} else {
|
||||
if ((flush_rtp_timestamp!=0x7fffffff) && (!seq32_order(timestamp,flush_rtp_timestamp))) // if we have gone past the flush boundary time
|
||||
flush_rtp_timestamp=0x7fffffff;
|
||||
if (connection_state_to_output) { // if we are supposed to be processing these packets
|
||||
|
||||
if ((flush_rtp_timestamp!=0x7fffffff) && ((timestamp==flush_rtp_timestamp) || seq32_order(timestamp,flush_rtp_timestamp))) {
|
||||
debug(2,"Dropping flushed packet in player_put_packet, seqno %u, timestamp %u, flushing to timestamp: %u.",seqno,timestamp,flush_rtp_timestamp);
|
||||
} else {
|
||||
if ((flush_rtp_timestamp!=0x7fffffff) && (!seq32_order(timestamp,flush_rtp_timestamp))) // if we have gone past the flush boundary time
|
||||
flush_rtp_timestamp=0x7fffffff;
|
||||
|
||||
abuf_t *abuf = 0;
|
||||
abuf_t *abuf = 0;
|
||||
|
||||
if (!ab_synced) {
|
||||
debug(2, "syncing to seqno %u.", seqno);
|
||||
ab_write = seqno;
|
||||
ab_read = seqno;
|
||||
ab_synced = 1;
|
||||
}
|
||||
if (ab_write == seqno) { // expected packet
|
||||
abuf = audio_buffer + BUFIDX(seqno);
|
||||
ab_write = SUCCESSOR(seqno);
|
||||
} else if (seq_order(ab_write, seqno)) { // newer than expected
|
||||
//if (ORDINATE(seqno)>(BUFFER_FRAMES*7)/8)
|
||||
// debug(1,"An interval of %u frames has opened, with ab_read: %u, ab_write: %u and seqno: %u.",seq_diff(ab_read,seqno),ab_read,ab_write,seqno);
|
||||
int32_t gap = seq_diff(ab_write,PREDECESSOR(seqno))+1;
|
||||
if (gap<=0)
|
||||
debug(1,"Unexpected gap size: %d.",gap);
|
||||
int i;
|
||||
for (i=0;i<gap;i++) {
|
||||
abuf = audio_buffer + BUFIDX(seq_sum(ab_write,i));
|
||||
abuf->ready = 0; // to be sure, to be sure
|
||||
abuf->timestamp = 0;
|
||||
abuf->sequence_number = 0;
|
||||
}
|
||||
// debug(1,"N %d s %u.",seq_diff(ab_write,PREDECESSOR(seqno))+1,ab_write);
|
||||
abuf = audio_buffer + BUFIDX(seqno);
|
||||
rtp_request_resend(ab_write,gap);
|
||||
resend_requests++;
|
||||
ab_write = SUCCESSOR(seqno);
|
||||
} else if (seq_order(ab_read, seqno)) { // late but not yet played
|
||||
late_packets++;
|
||||
abuf = audio_buffer + BUFIDX(seqno);
|
||||
} else { // too late.
|
||||
too_late_packets++;
|
||||
/*
|
||||
if (!late_packet_message_sent) {
|
||||
debug(1, "too-late packet received: %u; ab_read: %u; ab_write: %u.", seqno, ab_read, ab_write);
|
||||
late_packet_message_sent=1;
|
||||
}
|
||||
*/
|
||||
}
|
||||
// pthread_mutex_unlock(&ab_mutex);
|
||||
if (!ab_synced) {
|
||||
debug(2, "syncing to seqno %u.", seqno);
|
||||
ab_write = seqno;
|
||||
ab_read = seqno;
|
||||
ab_synced = 1;
|
||||
}
|
||||
if (ab_write == seqno) { // expected packet
|
||||
abuf = audio_buffer + BUFIDX(seqno);
|
||||
ab_write = SUCCESSOR(seqno);
|
||||
} else if (seq_order(ab_write, seqno)) { // newer than expected
|
||||
//if (ORDINATE(seqno)>(BUFFER_FRAMES*7)/8)
|
||||
// debug(1,"An interval of %u frames has opened, with ab_read: %u, ab_write: %u and seqno: %u.",seq_diff(ab_read,seqno),ab_read,ab_write,seqno);
|
||||
int32_t gap = seq_diff(ab_write,PREDECESSOR(seqno))+1;
|
||||
if (gap<=0)
|
||||
debug(1,"Unexpected gap size: %d.",gap);
|
||||
int i;
|
||||
for (i=0;i<gap;i++) {
|
||||
abuf = audio_buffer + BUFIDX(seq_sum(ab_write,i));
|
||||
abuf->ready = 0; // to be sure, to be sure
|
||||
abuf->timestamp = 0;
|
||||
abuf->sequence_number = 0;
|
||||
}
|
||||
// debug(1,"N %d s %u.",seq_diff(ab_write,PREDECESSOR(seqno))+1,ab_write);
|
||||
abuf = audio_buffer + BUFIDX(seqno);
|
||||
rtp_request_resend(ab_write,gap);
|
||||
resend_requests++;
|
||||
ab_write = SUCCESSOR(seqno);
|
||||
} else if (seq_order(ab_read, seqno)) { // late but not yet played
|
||||
late_packets++;
|
||||
abuf = audio_buffer + BUFIDX(seqno);
|
||||
} else { // too late.
|
||||
too_late_packets++;
|
||||
/*
|
||||
if (!late_packet_message_sent) {
|
||||
debug(1, "too-late packet received: %u; ab_read: %u; ab_write: %u.", seqno, ab_read, ab_write);
|
||||
late_packet_message_sent=1;
|
||||
}
|
||||
*/
|
||||
}
|
||||
// pthread_mutex_unlock(&ab_mutex);
|
||||
|
||||
if (abuf) {
|
||||
alac_decode(abuf->data, data, len);
|
||||
abuf->ready = 1;
|
||||
abuf->timestamp = timestamp;
|
||||
abuf->sequence_number = seqno;
|
||||
}
|
||||
if (abuf) {
|
||||
alac_decode(abuf->data, data, len);
|
||||
abuf->ready = 1;
|
||||
abuf->timestamp = timestamp;
|
||||
abuf->sequence_number = seqno;
|
||||
}
|
||||
|
||||
// pthread_mutex_lock(&ab_mutex);
|
||||
// pthread_mutex_lock(&ab_mutex);
|
||||
|
||||
time_of_last_audio_packet = get_absolute_time_in_fp();
|
||||
}
|
||||
int rc = pthread_cond_signal(&flowcontrol);
|
||||
if (rc)
|
||||
debug(1,"Error signalling flowcontrol.");
|
||||
}
|
||||
int rc = pthread_cond_signal(&flowcontrol);
|
||||
if (rc)
|
||||
debug(1,"Error signalling flowcontrol.");
|
||||
}
|
||||
pthread_mutex_unlock(&ab_mutex);
|
||||
}
|
||||
|
||||
@@ -411,7 +416,18 @@ static abuf_t *buffer_get_frame(void) {
|
||||
shutdown_requested=1;
|
||||
}
|
||||
}
|
||||
|
||||
int rco = get_requested_connection_state_to_output();
|
||||
|
||||
if (connection_state_to_output != rco) {
|
||||
connection_state_to_output=rco;
|
||||
// change happening
|
||||
if (connection_state_to_output==0) { //going off
|
||||
pthread_mutex_lock(&flush_mutex);
|
||||
flush_requested=1;
|
||||
pthread_mutex_unlock(&flush_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&flush_mutex);
|
||||
if (flush_requested==1) {
|
||||
if (config.output->flush)
|
||||
@@ -750,6 +766,8 @@ typedef struct stats { // statistics for running averages
|
||||
} stats_t;
|
||||
|
||||
static void *player_thread_func(void *arg) {
|
||||
connection_state_to_output = get_requested_connection_state_to_output();
|
||||
debug(1,"States: %d, %d.",connection_state_to_output,get_requested_connection_state_to_output());
|
||||
//this is about half a minute
|
||||
#define trend_interval 3758
|
||||
stats_t statistics[trend_interval];
|
||||
|
||||
+9
-1
@@ -95,6 +95,13 @@ static void sig_logrotate(int foo, siginfo_t *bar, void *baz) {
|
||||
// log_setup();
|
||||
}
|
||||
|
||||
static void sig_toggle_audio_output(int foo, siginfo_t *bar, void *baz) {
|
||||
if (get_requested_connection_state_to_output())
|
||||
set_requested_connection_state_to_output(0);
|
||||
else
|
||||
set_requested_connection_state_to_output(1);
|
||||
}
|
||||
|
||||
static void sig_pause_client(int foo, siginfo_t *bar, void *baz) {
|
||||
rtp_request_client_pause();
|
||||
}
|
||||
@@ -306,7 +313,7 @@ void signal_setup(void) {
|
||||
sa.sa_sigaction = &sig_logrotate;
|
||||
sigaction(SIGHUP, &sa, NULL);
|
||||
|
||||
sa.sa_sigaction = &sig_pause_client;
|
||||
sa.sa_sigaction = &sig_toggle_audio_output;
|
||||
sigaction(SIGUSR2, &sa, NULL);
|
||||
|
||||
sa.sa_sigaction = &sig_child;
|
||||
@@ -426,6 +433,7 @@ int main(int argc, char **argv) {
|
||||
gethostname(hostname, 100);
|
||||
config.apname = malloc(20 + 100);
|
||||
snprintf(config.apname, 20 + 100, "Shairport Sync on %s", hostname);
|
||||
set_requested_connection_state_to_output(1); // we expect to be able to connect to the output device
|
||||
|
||||
// parse arguments into config
|
||||
int audio_arg = parse_options(argc, argv);
|
||||
|
||||
Reference in New Issue
Block a user