--- a
+++ b/sc2src/watcher.cpp
@@ -0,0 +1,119 @@
+/* Copyright (C) 2016 J.F.Dockes
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include "config.h"
+
+#include <unistd.h>
+#include <thread>
+
+#include "watcher.h"
+#include "rcvqueue.h"
+#include "smallut.h"
+
+using namespace std;
+
+/* Parameters */
+static string o_cmd;
+static unsigned int o_idlesecs;
+static unsigned int o_pollsecs;
+static bool o_doclosealsa;
+
+/* Queue we watch */
+static AudioEater *o_eater;
+
+/* Queue state */
+static bool o_active;
+static time_t o_last_active;
+static unsigned int o_lastcntvalue;
+
+static thread o_worker;
+
+static void watcher(void *)
+{
+ string argument;
+ for (;;) {
+ LOGDEB("watcher: active " << o_active << " lastpktcnt " <<
+ o_lastcntvalue << " pktcnt " << o_eater->pktcounter << endl);
+ if (!o_active && o_lastcntvalue != o_eater->pktcounter) {
+ // If not currently active and the packet counter changed,
+ // switch to active, exec command.
+ o_active = true;
+ argument = "on";
+ } else if (o_active && o_lastcntvalue == o_eater->pktcounter &&
+ time(0) - o_last_active > o_idlesecs) {
+ // If state currently active but no packet count change,
+ // and the delay is expired, switch to inactive and
+ // execute the command
+ o_active = false;
+ argument = "off";
+ LOGDEB("watcher: CLOSING ALSA " << endl);
+ if (o_doclosealsa) {
+ // The reopen is auto-performed by the audio queue to
+ // avoid delay.
+ alsa_close();
+ }
+ }
+ if (!argument.empty()) {
+ string cmd(o_cmd + " " + argument);
+ LOGDEB("watcher: executing " << cmd << endl);
+ int ret = system(cmd.c_str());
+ (void)ret;
+ argument.clear();
+ }
+ // In all cases, if the packet counter changed, record the new
+ // value and the current time
+ if (o_lastcntvalue != o_eater->pktcounter) {
+ o_lastcntvalue = o_eater->pktcounter;
+ o_last_active = time(0);
+ }
+ sleep(o_pollsecs);
+ }
+}
+
+void startWatcher(ConfSimple& config)
+{
+ string cmd, sidlesecs, spollsecs, sclosealsa;
+ unsigned int idlesecs(900), pollsecs(2);
+ bool closealsa(true);
+
+ config.get("scwatchercmd", cmd);
+ config.get("scwatcheridlesecs", sidlesecs);
+ if (!sidlesecs.empty()) {
+ idlesecs = (unsigned int)atoi(sidlesecs.c_str());
+ }
+ config.get("scwatcherpollsecs", spollsecs);
+ if (!spollsecs.empty()) {
+ pollsecs = (unsigned int)atoi(spollsecs.c_str());
+ }
+ config.get("scwatcherclosealsa", sclosealsa);
+ if (!sclosealsa.empty()) {
+ closealsa = stringToBool(sclosealsa);
+ }
+
+ if (cmd.empty() && !closealsa) {
+ LOGDEB("startWatcher: no watcher: empty cmd and closealsa is false\n");
+ return;
+ }
+
+ o_cmd = cmd;
+ o_idlesecs = idlesecs ? idlesecs : 900;
+ o_pollsecs = pollsecs ? pollsecs : 2;
+ o_doclosealsa = closealsa;
+ o_eater = &alsaAudioEater;
+
+ o_worker = thread(watcher, nullptr);
+ o_worker.detach();
+}