summaryrefslogtreecommitdiff
path: root/activity_monitor.c
diff options
context:
space:
mode:
authorMike Brady <mikebrady@eircom.net>2019-01-21 21:43:55 +0000
committerMike Brady <mikebrady@eircom.net>2019-01-21 21:43:55 +0000
commit2e4428538d9f77233de0b0b9f151339b4ef8f923 (patch)
treeabcdd06cb018b42436314a33d2cbd1ce441da614 /activity_monitor.c
parent604ca8dee458a07075453c0fde2b8a505846e3f5 (diff)
Add an "active" mode that can time out after a period -- 10 seconds by default -- after play ends.
Diffstat (limited to 'activity_monitor.c')
-rw-r--r--activity_monitor.c171
1 files changed, 90 insertions, 81 deletions
diff --git a/activity_monitor.c b/activity_monitor.c
index 53e3d7f..6452a08 100644
--- a/activity_monitor.c
+++ b/activity_monitor.c
@@ -1,11 +1,11 @@
/*
* Activity Monitor
- *
+ *
* Contains code to run an activity flag and associated timer
- * A pthread implements a simple state machine with three states,
+ * A pthread implements a simple state machine with three states,
* "idle", "active" and "timing out".
- *
- *
+ *
+ *
* This file is part of Shairport Sync.
* Copyright (c) Mike Brady 2019
* All rights reserved.
@@ -31,41 +31,43 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <stdlib.h>
#include <errno.h>
#include <inttypes.h>
+#include <stdlib.h>
#include <sys/types.h>
#include "config.h"
+#include "activity_monitor.h"
#include "common.h"
#include "rtsp.h"
-#include "activity_monitor.h"
-enum am_state {am_inactive, am_active, am_timing_out} state;
-enum ps_state {ps_inactive, ps_active} player_state;
+enum am_state { am_inactive, am_active, am_timing_out } state;
+enum ps_state { ps_inactive, ps_active } player_state;
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");
+ // 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);
#ifdef CONFIG_METADATA
- debug(2, "abeg"); // active mode begin
- send_ssnc_metadata('pend', NULL, 0, 1); // contains cancellation points
+ debug(2, "abeg"); // active mode begin
+ send_ssnc_metadata('pend', NULL, 0, 1); // contains cancellation points
#endif
}
void going_inactive(int block) {
- // debug(1, "activity_monitor: state transitioning to \"inactive\" with%s blocking", block ? "" : "out");
+ // 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);
#ifdef CONFIG_METADATA
- debug(2, "aend"); // active mode end
- send_ssnc_metadata('pend', NULL, 0, 1); // contains cancellation points
+ debug(2, "aend"); // active mode end
+ send_ssnc_metadata('pend', NULL, 0, 1); // contains cancellation points
#endif
}
@@ -83,17 +85,20 @@ void activity_monitor_signify_activity(int active) {
// 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
+ 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_cond_signal(&activity_monitor_cv);
pthread_mutex_unlock(&activity_monitor_mutex);
}
@@ -115,7 +120,7 @@ void *activity_monitor_thread_code(void *arg) {
pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); // can't do this in OS X, and don't need it.
rc = pthread_cond_init(&activity_monitor_cv, &attr);
pthread_condattr_destroy(&attr);
-
+
#endif
#ifdef COMPILE_FOR_OSX
rc = pthread_cond_init(&activity_monitor_cv, NULL);
@@ -123,84 +128,89 @@ void *activity_monitor_thread_code(void *arg) {
if (rc)
die("activity_monitor: error %d initialising activity_monitor_cv.");
pthread_cleanup_push(activity_thread_cleanup_handler, arg);
-
+
uint64_t sec;
uint64_t nsec;
int rc;
struct timespec time_for_wait;
-
+
state = am_inactive;
player_state = ps_inactive;
-
+
pthread_mutex_lock(&activity_monitor_mutex);
do {
switch (state) {
- case am_inactive:
- // debug(1,"am_state: am_inactive");
- while (player_state != ps_active)
- pthread_cond_wait(&activity_monitor_cv, &activity_monitor_mutex);
- state = am_active;
- // going_active(); // this is done in activity_monitor_signify_activity
+ case am_inactive:
+ // debug(1,"am_state: am_inactive");
+ while (player_state != ps_active)
+ pthread_cond_wait(&activity_monitor_cv, &activity_monitor_mutex);
+ state = am_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_mode_timeout == 0.0) {
- state = am_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_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;
-
+ 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_mode_timeout == 0.0) {
+ state = am_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_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;
+
#ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN_AND_OPENBSD
- uint64_t time_of_wakeup_fp = get_absolute_time_in_fp() + time_to_wait_for_wakeup_fp;
- sec = time_of_wakeup_fp >> 32;
- nsec = ((time_of_wakeup_fp & 0xffffffff) * 1000000000) >> 32;
- time_for_wait.tv_sec = sec;
- time_for_wait.tv_nsec = nsec;
+ uint64_t time_of_wakeup_fp = get_absolute_time_in_fp() + time_to_wait_for_wakeup_fp;
+ sec = time_of_wakeup_fp >> 32;
+ nsec = ((time_of_wakeup_fp & 0xffffffff) * 1000000000) >> 32;
+ time_for_wait.tv_sec = sec;
+ time_for_wait.tv_nsec = nsec;
#endif
#ifdef COMPILE_FOR_OSX
- sec = time_to_wait_for_wakeup_fp >> 32;
- nsec = ((time_to_wait_for_wakeup_fp & 0xffffffff) * 1000000000) >> 32;
- time_for_wait.tv_sec = sec;
- time_for_wait.tv_nsec = nsec;
+ sec = time_to_wait_for_wakeup_fp >> 32;
+ nsec = ((time_to_wait_for_wakeup_fp & 0xffffffff) * 1000000000) >> 32;
+ time_for_wait.tv_sec = sec;
+ time_for_wait.tv_nsec = nsec;
#endif
- }
+ }
break;
- case am_timing_out:
- // debug(1,"am_state: am_timing_out");
- rc = 0;
- while ((player_state != ps_active) && (rc != ETIMEDOUT)) {
+ case am_timing_out:
+ // debug(1,"am_state: am_timing_out");
+ rc = 0;
+ while ((player_state != ps_active) && (rc != ETIMEDOUT)) {
#ifdef COMPILE_FOR_LINUX_AND_FREEBSD_AND_CYGWIN_AND_OPENBSD
- rc = pthread_cond_timedwait(&activity_monitor_cv, &activity_monitor_mutex, &time_for_wait); // this is a pthread cancellation point
+ rc = pthread_cond_timedwait(&activity_monitor_cv, &activity_monitor_mutex,
+ &time_for_wait); // this is a pthread cancellation point
#endif
#ifdef COMPILE_FOR_OSX
- rc = pthread_cond_timedwait_relative_np(&activity_monitor_cv, &activity_monitor_mutex, &time_for_wait);
+ rc = pthread_cond_timedwait_relative_np(&activity_monitor_cv, &activity_monitor_mutex,
+ &time_for_wait);
#endif
- }
- if (player_state == ps_active)
- state = am_active; // player has gone active -- do nothing, because it's still active
- else if (rc == ETIMEDOUT) {
- state = am_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");
- }
- break;
- default:
- debug(1,"activity monitor in an illegal state!");
+ }
+ if (player_state == ps_active)
+ state = am_active; // player has gone active -- do nothing, because it's still active
+ else if (rc == ETIMEDOUT) {
state = am_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");
+ }
+ break;
+ default:
+ debug(1, "activity monitor in an illegal state!");
+ state = am_inactive;
break;
}
} while (1);
- pthread_mutex_unlock(&activity_monitor_mutex);
+ pthread_mutex_unlock(&activity_monitor_mutex);
pthread_cleanup_pop(0); // should never happen
pthread_exit(NULL);
}
@@ -211,9 +221,8 @@ void activity_monitor_start() {
}
void activity_monitor_stop() {
- debug(1,"activity_monitor_stop start...");
+ debug(1, "activity_monitor_stop start...");
pthread_cancel(activity_monitor_thread);
- pthread_join(activity_monitor_thread,NULL);
- debug(1,"activity_monitor_stop complete");
+ pthread_join(activity_monitor_thread, NULL);
+ debug(1, "activity_monitor_stop complete");
}
-