Skip to content

Commit

Permalink
Change SIGUSR2 to turn on and off reserving the output device.
Browse files Browse the repository at this point in the history
  • Loading branch information
mikebrady committed Oct 19, 2014
1 parent 1808d74 commit eef08e4
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 82 deletions.
42 changes: 23 additions & 19 deletions audio_alsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,15 +181,16 @@ 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;
snd_pcm_uframes_t frames = 441*10;
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);
Expand All @@ -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) {
Expand All @@ -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() {
Expand Down Expand Up @@ -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) {
Expand Down
12 changes: 12 additions & 0 deletions common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
6 changes: 6 additions & 0 deletions common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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, ...);
Expand Down
142 changes: 80 additions & 62 deletions player.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;

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 (abuf) {
alac_decode(abuf->data, data, len);
abuf->ready = 1;
abuf->timestamp = timestamp;
abuf->sequence_number = seqno;
}
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;

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;
}

// 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);
}

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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];
Expand Down
10 changes: 9 additions & 1 deletion shairport.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit eef08e4

Please sign in to comment.