diff options
author | Mike Brady <mikebrady@eircom.net> | 2019-01-21 21:43:55 +0000 |
---|---|---|
committer | Mike Brady <mikebrady@eircom.net> | 2019-01-21 21:43:55 +0000 |
commit | 2e4428538d9f77233de0b0b9f151339b4ef8f923 (patch) | |
tree | abcdd06cb018b42436314a33d2cbd1ce441da614 /activity_monitor.c | |
parent | 604ca8dee458a07075453c0fde2b8a505846e3f5 (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.c | 171 |
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"); } - |