add initial script-execution functionality to active mode. Make is possible to wait for start and stop scripts.
This commit is contained in:
+41
-19
@@ -48,25 +48,46 @@ pthread_t activity_monitor_thread;
|
||||
pthread_mutex_t activity_monitor_mutex;
|
||||
pthread_cond_t activity_monitor_cv;
|
||||
|
||||
void going_active(int block) {
|
||||
debug(1, "activity_monitor: state transitioning to \"active\" with%s blocking", block ? "" : "out");
|
||||
if (config.cmd_active_start)
|
||||
command_execute(config.cmd_active_start, "", block);
|
||||
}
|
||||
|
||||
void going_inactive(int block) {
|
||||
debug(1, "activity_monitor: state transitioning to \"inactive\" with%s blocking", block ? "" : "out");
|
||||
if (config.cmd_active_stop)
|
||||
command_execute(config.cmd_active_stop, "", block);
|
||||
}
|
||||
|
||||
void activity_monitor_signify_activity(int active) {
|
||||
pthread_mutex_lock(&activity_monitor_mutex);
|
||||
player_state = active == 0 ? ps_inactive : ps_active;
|
||||
pthread_cond_signal(&activity_monitor_cv);
|
||||
// Now, although we could simply let the state machine in the activity monitor thread
|
||||
// look after eveything, we will change state here in two situations:
|
||||
// 1. If the state machine is am_inactive and the player is ps_active
|
||||
// we will change the state to am_active and execute the going_active() function.
|
||||
// 2. If the state machine is am_active and the player is ps_inactive and
|
||||
// the activity_idle_timeout is 0, then we will change the state to am_inactive and
|
||||
// execute the going_inactive() function.
|
||||
//
|
||||
// The reason for all this is that we might want to perform the attached scripts
|
||||
// and wait for them to complete before continuing. If they were perfomed in the
|
||||
// activity monitor thread, then we coldn't wait for them to complete.
|
||||
|
||||
// Thus, the only time the thread will execute a going_... function is when a non-zero
|
||||
// timeout actually matures.
|
||||
|
||||
if ((state == am_inactive) && (player_state == ps_active)) {
|
||||
going_active(config.cmd_blocking); // note -- will be executed with the mutex locked, but that's okay
|
||||
} else if ((state == am_active) && (player_state == ps_inactive) && (config.active_mode_timeout == 0.0)) {
|
||||
going_inactive(config.cmd_blocking); // note -- will be executed with the mutex locked, but that's okay
|
||||
}
|
||||
|
||||
pthread_cond_signal(&activity_monitor_cv);
|
||||
pthread_mutex_unlock(&activity_monitor_mutex);
|
||||
}
|
||||
|
||||
void going_active() {
|
||||
pthread_mutex_unlock(&activity_monitor_mutex);
|
||||
debug(1, "activity_monitor: state transitioning to \"active\"");
|
||||
pthread_mutex_lock(&activity_monitor_mutex);
|
||||
}
|
||||
|
||||
void going_inactive() {
|
||||
pthread_mutex_unlock(&activity_monitor_mutex);
|
||||
debug(1, "activity_monitor: state transitioning to \"inactive\"");
|
||||
pthread_mutex_lock(&activity_monitor_mutex);
|
||||
}
|
||||
|
||||
void activity_thread_cleanup_handler(__attribute__((unused)) void *arg) {
|
||||
debug(3, "activity_monitor: thread exit.");
|
||||
pthread_cond_destroy(&activity_monitor_cv);
|
||||
@@ -110,19 +131,19 @@ void *activity_monitor_thread_code(void *arg) {
|
||||
while (player_state != ps_active)
|
||||
pthread_cond_wait(&activity_monitor_cv, &activity_monitor_mutex);
|
||||
state = am_active;
|
||||
going_active();
|
||||
// going_active(); // this is done in activity_monitor_signify_activity
|
||||
break;
|
||||
case am_active:
|
||||
debug(1,"am_state: am_active");
|
||||
while (player_state != ps_inactive)
|
||||
pthread_cond_wait(&activity_monitor_cv, &activity_monitor_mutex);
|
||||
if (config.active_timeout == 0.0) {
|
||||
if (config.active_mode_timeout == 0.0) {
|
||||
state = am_inactive;
|
||||
going_inactive();
|
||||
// going_inactive(); // this is done in activity_monitor_signify_activity
|
||||
} else {
|
||||
state = am_timing_out;
|
||||
|
||||
uint64_t time_to_wait_for_wakeup_fp = (uint64_t)(config.active_timeout *1000000); // resolution of microseconds
|
||||
uint64_t time_to_wait_for_wakeup_fp = (uint64_t)(config.active_mode_timeout *1000000); // resolution of microseconds
|
||||
time_to_wait_for_wakeup_fp = time_to_wait_for_wakeup_fp << 32;
|
||||
time_to_wait_for_wakeup_fp = time_to_wait_for_wakeup_fp / 1000000;
|
||||
|
||||
@@ -156,7 +177,9 @@ void *activity_monitor_thread_code(void *arg) {
|
||||
state = am_active; // player has gone active -- do nothing, because it's still active
|
||||
else if (rc == ETIMEDOUT) {
|
||||
state = am_inactive;
|
||||
going_inactive();
|
||||
pthread_mutex_unlock(&activity_monitor_mutex);
|
||||
going_inactive(0); // don't wait for completion -- it makes no sense
|
||||
pthread_mutex_lock(&activity_monitor_mutex);
|
||||
} else {
|
||||
// activity monitor was woken up in the state am_timing_out, but not by a timeout and player is not in ps_active state
|
||||
debug(1, "activity monitor was woken up in the state am_timing_out, but didn't change state");
|
||||
@@ -175,7 +198,6 @@ void *activity_monitor_thread_code(void *arg) {
|
||||
|
||||
void activity_monitor_start() {
|
||||
debug(1,"activity_monitor_start");
|
||||
config.active_timeout = 5.5; // hack
|
||||
pthread_create(&activity_monitor_thread, NULL, activity_monitor_thread_code, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -152,6 +152,7 @@ typedef struct {
|
||||
int statistics_requested, use_negotiated_latencies;
|
||||
enum playback_mode_type playback_mode;
|
||||
char *cmd_start, *cmd_stop, *cmd_set_volume, *cmd_unfixable;
|
||||
char *cmd_active_start, *cmd_active_stop;
|
||||
int cmd_blocking, cmd_start_returns_output;
|
||||
double tolerance; // allow this much drift before attempting to correct it
|
||||
enum stuffing_type packet_stuffing;
|
||||
@@ -177,7 +178,7 @@ typedef struct {
|
||||
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.
|
||||
double active_timeout; // the amount of time from when play ends to when the system does into the "inactive".
|
||||
double active_mode_timeout; // the amount of time from when play ends to when the system leaves into the "active" mode.
|
||||
uint32_t volume_range_db; // the range, in dB, from max dB to min dB. Zero means use the mixer's
|
||||
// native range.
|
||||
enum sps_format_t output_format;
|
||||
|
||||
@@ -1488,12 +1488,10 @@ void player_thread_cleanup_handler(void *arg) {
|
||||
clear_reference_timestamp(conn);
|
||||
conn->rtp_running = 0;
|
||||
pthread_setcancelstate(oldState, NULL);
|
||||
activity_monitor_signify_activity(0); // inactive
|
||||
}
|
||||
|
||||
void *player_thread_func(void *arg) {
|
||||
activity_monitor_signify_activity(1); // active
|
||||
rtsp_conn_info *conn = (rtsp_conn_info *)arg;
|
||||
rtsp_conn_info *conn = (rtsp_conn_info *)arg;
|
||||
// pthread_cleanup_push(player_thread_initial_cleanup_handler, arg);
|
||||
conn->packet_count = 0;
|
||||
conn->packet_count_since_flush = 0;
|
||||
@@ -2802,6 +2800,7 @@ int player_play(rtsp_conn_info *conn) {
|
||||
if (config.buffer_start_fill > BUFFER_FRAMES)
|
||||
die("specified buffer starting fill %d > buffer size %d", config.buffer_start_fill,
|
||||
BUFFER_FRAMES);
|
||||
activity_monitor_signify_activity(1); // active, and should be before play's command hook, command_start()
|
||||
command_start();
|
||||
pthread_t *pt = malloc(sizeof(pthread_t));
|
||||
if (pt == NULL)
|
||||
@@ -2850,6 +2849,7 @@ int player_stop(rtsp_conn_info *conn) {
|
||||
#endif
|
||||
// debuglev = dl;
|
||||
command_stop();
|
||||
activity_monitor_signify_activity(0); // inactive, and should be after command_stop()
|
||||
return 0;
|
||||
} else {
|
||||
debug(3, "Connection %d: player thread already deleted.", conn->connection_number);
|
||||
|
||||
+19
-1
@@ -331,6 +331,7 @@ int parse_options(int argc, char **argv) {
|
||||
// nothing else comes in first.
|
||||
config.fixedLatencyOffset = 11025; // this sounds like it works properly.
|
||||
config.diagnostic_drop_packet_fraction = 0.0;
|
||||
config.active_mode_timeout = 10.0;
|
||||
|
||||
#ifdef CONFIG_METADATA_HUB
|
||||
config.cover_art_cache_dir = "/tmp/shairport-sync/.cache/coverart";
|
||||
@@ -722,7 +723,24 @@ int parse_options(int argc, char **argv) {
|
||||
config.cmd_stop = (char *)str;
|
||||
}
|
||||
|
||||
if (config_lookup_string(config.cfg,
|
||||
if (config_lookup_string(config.cfg, "sessioncontrol.run_this_before_entering_active_mode", &str)) {
|
||||
config.cmd_active_start = (char *)str;
|
||||
}
|
||||
|
||||
if (config_lookup_string(config.cfg, "sessioncontrol.run_this_after_exiting_active_mode", &str)) {
|
||||
config.cmd_active_stop = (char *)str;
|
||||
}
|
||||
|
||||
if (config_lookup_float(config.cfg, "sessioncontrol.active_mode_timeout", &dvalue)) {
|
||||
if (dvalue < 0.0)
|
||||
warn("Invalid value \"%f\" for sessioncontrol.active_mode_timeout. It must be positive. The default of %f will be used instead.",
|
||||
dvalue, config.active_mode_timeout);
|
||||
else
|
||||
config.active_mode_timeout = dvalue;
|
||||
}
|
||||
|
||||
|
||||
if (config_lookup_string(config.cfg,
|
||||
"sessioncontrol.run_this_if_an_unfixable_error_is_detected", &str)) {
|
||||
config.cmd_unfixable = (char *)str;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user