swaroop: only allow playback if configured lock file is present. v2.13.72
authorCarl Hetherington <cth@carlh.net>
Tue, 13 Nov 2018 00:04:23 +0000 (00:04 +0000)
committerCarl Hetherington <cth@carlh.net>
Tue, 13 Nov 2018 00:04:23 +0000 (00:04 +0000)
src/lib/checker.cc [new file with mode: 0644]
src/lib/checker.h [new file with mode: 0644]
src/lib/config.cc
src/lib/config.h
src/lib/lock_file_checker.cc [new file with mode: 0644]
src/lib/lock_file_checker.h [new file with mode: 0644]
src/lib/monitor_checker.cc
src/lib/monitor_checker.h
src/lib/wscript
src/tools/dcpomatic_player.cc
src/wx/player_config_dialog.cc

diff --git a/src/lib/checker.cc b/src/lib/checker.cc
new file mode 100644 (file)
index 0000000..13d9aac
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+    Copyright (C) 2018 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic 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.
+
+    DCP-o-matic 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 DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef DCPOMATIC_VARIANT_SWAROOP
+
+#include "checker.h"
+#include "config.h"
+#include "cross.h"
+
+using boost::bind;
+using boost::ref;
+
+Checker::Checker (int period)
+       : _thread (0)
+       , _terminate (false)
+       , _ok (true)
+       , _period (period)
+{
+
+}
+
+void
+Checker::run ()
+{
+       _thread = new boost::thread (boost::bind (&Checker::thread, this));
+}
+
+Checker::~Checker ()
+{
+       {
+               boost::mutex::scoped_lock lm (_mutex);
+               _terminate = true;
+       }
+
+       if (_thread) {
+               /* Ideally this would be a DCPOMATIC_ASSERT(_thread->joinable()) but we
+                  can't throw exceptions from a destructor.
+               */
+               _thread->interrupt ();
+               try {
+                       if (_thread->joinable ()) {
+                               _thread->join ();
+                       }
+               } catch (boost::thread_interrupted& e) {
+                       /* No problem */
+               }
+       }
+       delete _thread;
+}
+
+void
+Checker::thread ()
+{
+       while (true) {
+               boost::mutex::scoped_lock lm (_mutex);
+               if (_terminate) {
+                       break;
+               }
+
+               bool const was_ok = _ok;
+               _ok = check();
+               if (was_ok != _ok) {
+                       emit (bind(boost::ref(StateChanged)));
+               }
+
+               lm.unlock ();
+               dcpomatic_sleep (_period);
+       }
+}
+
+bool
+Checker::ok () const
+{
+       boost::mutex::scoped_lock lm (_mutex);
+       return _ok;
+}
+
+#endif
diff --git a/src/lib/checker.h b/src/lib/checker.h
new file mode 100644 (file)
index 0000000..fee3fc3
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+    Copyright (C) 2018 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic 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.
+
+    DCP-o-matic 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 DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+/** @file  src/lib/checker.h
+ *  @brief Checker class.
+ */
+
+#ifndef DCPOMATIC_CHECKER_H
+#define DCPOMATIC_CHECKER_H
+
+#include "signaller.h"
+#include <boost/signals2.hpp>
+
+/** Parent for classes which check some condition every so often and signal
+ *  when the state of the condition changes.
+ */
+class Checker : public Signaller, public boost::noncopyable
+{
+public:
+       virtual ~Checker ();
+
+       void run ();
+
+       bool ok () const;
+
+       /** Emitted when the state of our condition changes */
+       boost::signals2::signal<void (void)> StateChanged;
+
+protected:
+
+       Checker (int period);
+
+       /** @return true if the condition is `ok', otherwise false */
+       virtual bool check () const = 0;
+
+private:
+
+       void thread ();
+
+       boost::thread* _thread;
+       mutable boost::mutex _mutex;
+       bool _terminate;
+       bool _ok;
+       /** check period in seconds */
+       int _period;
+};
+
+#endif
index b64690aadf4df86569b3e6a047d223038c1fbbfb..31ae15b36a8942612789a48ad68e2a1e65fc088c 100644 (file)
@@ -177,6 +177,7 @@ Config::set_defaults ()
        _player_watermark_period = 1;
        _player_watermark_duration = 50;
        _allow_spl_editing = true;
        _player_watermark_period = 1;
        _player_watermark_duration = 50;
        _allow_spl_editing = true;
+       _player_lock_file = boost::none;
 #endif
 
        _allowed_dcp_frame_rates.clear ();
 #endif
 
        _allowed_dcp_frame_rates.clear ();
@@ -529,6 +530,7 @@ try
                _required_monitors.push_back(Monitor(i));
        }
        _allow_spl_editing = f.optional_bool_child("AllowSPLEditing").get_value_or(true);
                _required_monitors.push_back(Monitor(i));
        }
        _allow_spl_editing = f.optional_bool_child("AllowSPLEditing").get_value_or(true);
+       _player_lock_file = f.optional_string_child("PlayerLockFile");
 #endif
 
        /* Replace any cinemas from config.xml with those from the configured file */
 #endif
 
        /* Replace any cinemas from config.xml with those from the configured file */
@@ -942,6 +944,9 @@ Config::write_config () const
                i.as_xml(root->add_child("RequiredMonitor"));
        }
        root->add_child("AllowSPLEditing")->add_child_text(_allow_spl_editing ? "1" : "0");
                i.as_xml(root->add_child("RequiredMonitor"));
        }
        root->add_child("AllowSPLEditing")->add_child_text(_allow_spl_editing ? "1" : "0");
+       if (_player_lock_file) {
+               root->add_child("PlayerLockFile")->add_child_text(_player_lock_file->string());
+       }
 #endif
 
        try {
 #endif
 
        try {
index a162750febf9cd59a12cc02e28b075c3b8098e32..dd20b58e7d66974a1d7435dafb760ee68144886f 100644 (file)
@@ -524,6 +524,10 @@ public:
        std::vector<Monitor> required_monitors () const {
                return _required_monitors;
        }
        std::vector<Monitor> required_monitors () const {
                return _required_monitors;
        }
+
+       boost::optional<boost::filesystem::path> player_lock_file () const {
+               return _player_lock_file;
+       }
 #endif
 
        bool allow_spl_editing () const {
 #endif
 
        bool allow_spl_editing () const {
@@ -1020,6 +1024,18 @@ public:
        void set_required_monitors (std::vector<Monitor> monitors) {
                maybe_set (_required_monitors, monitors);
        }
        void set_required_monitors (std::vector<Monitor> monitors) {
                maybe_set (_required_monitors, monitors);
        }
+
+       void set_player_lock_file (boost::filesystem::path p) {
+               maybe_set (_player_lock_file, p);
+       }
+
+       void unset_player_lock_file () {
+               if (!_player_lock_file) {
+                       return;
+               }
+               _player_lock_file = boost::none;
+               changed ();
+       }
 #endif
 
        void set_allow_spl_editing (bool s) {
 #endif
 
        void set_allow_spl_editing (bool s) {
@@ -1229,6 +1245,8 @@ private:
        /** watermark duration in milliseconds */
        int _player_watermark_duration;
        std::vector<Monitor> _required_monitors;
        /** watermark duration in milliseconds */
        int _player_watermark_duration;
        std::vector<Monitor> _required_monitors;
+       /** a file which, if specified, must be present for the player to work */
+       boost::optional<boost::filesystem::path> _player_lock_file;
 #endif
        bool _allow_spl_editing;
 
 #endif
        bool _allow_spl_editing;
 
diff --git a/src/lib/lock_file_checker.cc b/src/lib/lock_file_checker.cc
new file mode 100644 (file)
index 0000000..9543c2c
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+    Copyright (C) 2018 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic 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.
+
+    DCP-o-matic 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 DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef DCPOMATIC_VARIANT_SWAROOP
+
+#include "lock_file_checker.h"
+#include "config.h"
+#include "cross.h"
+
+using boost::bind;
+using boost::ref;
+
+LockFileChecker* LockFileChecker::_instance = 0;
+
+LockFileChecker::LockFileChecker ()
+       : Checker (10)
+{
+
+}
+
+bool
+LockFileChecker::check () const
+{
+       return !Config::instance()->player_lock_file() || boost::filesystem::is_regular_file(Config::instance()->player_lock_file().get());
+}
+
+LockFileChecker *
+LockFileChecker::instance ()
+{
+       if (!_instance) {
+               _instance = new LockFileChecker ();
+       }
+
+       return _instance;
+}
+
+#endif
diff --git a/src/lib/lock_file_checker.h b/src/lib/lock_file_checker.h
new file mode 100644 (file)
index 0000000..76c0071
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+    Copyright (C) 2018 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic 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.
+
+    DCP-o-matic 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 DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "checker.h"
+#include <boost/signals2.hpp>
+
+class LockFileChecker : public Checker
+{
+public:
+       LockFileChecker ();
+
+       static LockFileChecker* instance ();
+
+protected:
+       bool check () const;
+
+private:
+       static LockFileChecker* _instance;
+};
index 19d8d8181943faaef5e58494d98b1a690c68feb5..d15dee63f99f7d0ba9dbb0a7e60d1b11ebde45b2 100644 (file)
 #include "config.h"
 #include "cross.h"
 
 #include "config.h"
 #include "cross.h"
 
-using boost::bind;
-using boost::ref;
-
 MonitorChecker* MonitorChecker::_instance = 0;
 
 MonitorChecker::MonitorChecker ()
 MonitorChecker* MonitorChecker::_instance = 0;
 
 MonitorChecker::MonitorChecker ()
-       : _thread (0)
-       , _terminate (false)
-       , _ok (true)
+       : Checker (60)
 {
 
 }
 
 {
 
 }
 
-void
-MonitorChecker::run ()
-{
-       _thread = new boost::thread (boost::bind (&MonitorChecker::thread, this));
-}
-
-MonitorChecker::~MonitorChecker ()
-{
-       {
-               boost::mutex::scoped_lock lm (_mutex);
-               _terminate = true;
-       }
-
-       if (_thread) {
-               /* Ideally this would be a DCPOMATIC_ASSERT(_thread->joinable()) but we
-                  can't throw exceptions from a destructor.
-               */
-               _thread->interrupt ();
-               try {
-                       if (_thread->joinable ()) {
-                               _thread->join ();
-                       }
-               } catch (boost::thread_interrupted& e) {
-                       /* No problem */
-               }
-       }
-       delete _thread;
-}
-
-void
-MonitorChecker::thread ()
-{
-       while (true) {
-               boost::mutex::scoped_lock lm (_mutex);
-               if (_terminate) {
-                       break;
-               }
-
-               bool const was_ok = _ok;
-               _ok = Config::instance()->required_monitors().empty() || get_monitors() == Config::instance()->required_monitors();
-               if (was_ok != _ok) {
-                       emit (bind(boost::ref(StateChanged)));
-               }
-
-               lm.unlock ();
-               dcpomatic_sleep (60);
-       }
-}
-
 bool
 bool
-MonitorChecker::ok () const
+MonitorChecker::check () const
 {
 {
-       boost::mutex::scoped_lock lm (_mutex);
-       return _ok;
+       return Config::instance()->required_monitors().empty() || get_monitors() == Config::instance()->required_monitors();
 }
 
 }
 
+
 MonitorChecker *
 MonitorChecker::instance ()
 {
 MonitorChecker *
 MonitorChecker::instance ()
 {
index 4f856f41fda6d51a6108c11d52b5a1bfb74b36c0..f99ab4b2a46e31c90e019877f0c1f7f021784569 100644 (file)
 
 */
 
 
 */
 
-#include "signaller.h"
+#include "checker.h"
 #include <boost/signals2.hpp>
 
 #include <boost/signals2.hpp>
 
-class MonitorChecker : public Signaller, public boost::noncopyable
+class MonitorChecker : public Checker
 {
 public:
 {
 public:
-       ~MonitorChecker ();
+       MonitorChecker ();
 
 
-       void run ();
+       static MonitorChecker* instance ();
 
 
-       bool ok () const;
-       boost::signals2::signal<void (void)> StateChanged;
+protected:
+       bool check () const;
 
 
-       static MonitorChecker* instance ();
 private:
        static MonitorChecker* _instance;
 private:
        static MonitorChecker* _instance;
-
-       MonitorChecker ();
-       void thread ();
-
-       boost::thread* _thread;
-       mutable boost::mutex _mutex;
-       bool _terminate;
-       bool _ok;
 };
 };
index e78227b6ba7dbfe53cb47b64b65454e30762a698..88cec75ec940868d829a04e4dc0bf1e9d22e6322 100644 (file)
@@ -41,6 +41,7 @@ sources = """
           text_content.cc
           text_decoder.cc
           case_insensitive_sorter.cc
           text_content.cc
           text_decoder.cc
           case_insensitive_sorter.cc
+          checker.cc
           check_content_change_job.cc
           cinema.cc
           cinema_kdms.cc
           check_content_change_job.cc
           cinema.cc
           cinema_kdms.cc
@@ -113,6 +114,7 @@ sources = """
           job_manager.cc
           j2k_encoder.cc
           json_server.cc
           job_manager.cc
           j2k_encoder.cc
           json_server.cc
+          lock_file_checker.cc
           log.cc
           log_entry.cc
           mid_side_decoder.cc
           log.cc
           log_entry.cc
           mid_side_decoder.cc
index db9463fe23b97b360a2fcebaa8a0b25579900ad7..473cc6d8bd7f17e696c5e89d30afd2e070863041 100644 (file)
@@ -48,6 +48,7 @@
 #include "lib/dcpomatic_socket.h"
 #include "lib/scoped_temporary.h"
 #include "lib/monitor_checker.h"
 #include "lib/dcpomatic_socket.h"
 #include "lib/scoped_temporary.h"
 #include "lib/monitor_checker.h"
+#include "lib/lock_file_checker.h"
 #include "lib/ffmpeg_content.h"
 #include <dcp/dcp.h>
 #include <dcp/raw_convert.h>
 #include "lib/ffmpeg_content.h"
 #include <dcp/dcp.h>
 #include <dcp/raw_convert.h>
@@ -206,6 +207,8 @@ public:
 #ifdef DCPOMATIC_VARIANT_SWAROOP
                MonitorChecker::instance()->StateChanged.connect(boost::bind(&DOMFrame::monitor_checker_state_changed, this));
                MonitorChecker::instance()->run ();
 #ifdef DCPOMATIC_VARIANT_SWAROOP
                MonitorChecker::instance()->StateChanged.connect(boost::bind(&DOMFrame::monitor_checker_state_changed, this));
                MonitorChecker::instance()->run ();
+               LockFileChecker::instance()->StateChanged.connect(boost::bind(&DOMFrame::lock_checker_state_changed, this));
+               LockFileChecker::instance()->run ();
 #endif
                setup_screen ();
 
 #endif
                setup_screen ();
 
@@ -248,8 +251,16 @@ public:
        void monitor_checker_state_changed ()
        {
                if (!MonitorChecker::instance()->ok()) {
        void monitor_checker_state_changed ()
        {
                if (!MonitorChecker::instance()->ok()) {
+                       _viewer->stop ();
                        error_dialog (this, _("The required display devices are not connected correctly."));
                        error_dialog (this, _("The required display devices are not connected correctly."));
+               }
+       }
+
+       void lock_checker_state_changed ()
+       {
+               if (!LockFileChecker::instance()->ok()) {
                        _viewer->stop ();
                        _viewer->stop ();
+                       error_dialog (this, _("The lock file is not present."));
                }
        }
 #endif
                }
        }
 #endif
@@ -273,6 +284,10 @@ public:
                        error_dialog (this, _("The required display devices are not connected correctly."));
                        return false;
                }
                        error_dialog (this, _("The required display devices are not connected correctly."));
                        return false;
                }
+               if (!LockFileChecker::instance()->ok()) {
+                       error_dialog (this, _("The lock file is not present."));
+                       return false;
+               }
 #endif
                if (!_film || !Config::instance()->respect_kdm_validity_periods()) {
                        return true;
 #endif
                if (!_film || !Config::instance()->respect_kdm_validity_periods()) {
                        return true;
index 62b216b11c248e7545f0aaa2d3f86d2cd84c31cc..de97f2b71f749d5cc8b562bc36e397ac4e4f43bf 100644 (file)
@@ -115,6 +115,11 @@ private:
                _kdm_server_url = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(400, -1));
                table->Add (_kdm_server_url, wxGBPosition (r, 1));
                ++r;
                _kdm_server_url = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(400, -1));
                table->Add (_kdm_server_url, wxGBPosition (r, 1));
                ++r;
+
+               add_label_to_sizer (table, _panel, _("Lock file"), true, wxGBPosition(r, 0));
+               _lock_file = new FilePickerCtrl (_panel, _("Select lock file"), "*", true);
+               table->Add (_lock_file, wxGBPosition (r, 1));
+               ++r;
 #endif
 
                _player_mode->Bind (wxEVT_CHOICE, bind(&PlayerGeneralPage::player_mode_changed, this));
 #endif
 
                _player_mode->Bind (wxEVT_CHOICE, bind(&PlayerGeneralPage::player_mode_changed, this));
@@ -123,6 +128,7 @@ private:
                _log_file->Bind (wxEVT_FILEPICKER_CHANGED, bind(&PlayerGeneralPage::log_file_changed, this));
 #ifdef DCPOMATIC_VARIANT_SWAROOP
                _kdm_server_url->Bind (wxEVT_TEXT, bind(&PlayerGeneralPage::kdm_server_url_changed, this));
                _log_file->Bind (wxEVT_FILEPICKER_CHANGED, bind(&PlayerGeneralPage::log_file_changed, this));
 #ifdef DCPOMATIC_VARIANT_SWAROOP
                _kdm_server_url->Bind (wxEVT_TEXT, bind(&PlayerGeneralPage::kdm_server_url_changed, this));
+               _lock_file->Bind (wxEVT_FILEPICKER_CHANGED, bind(&PlayerGeneralPage::lock_file_changed, this));
 #endif
        }
 
 #endif
        }
 
@@ -151,6 +157,9 @@ private:
                }
 #ifdef DCPOMATIC_VARIANT_SWAROOP
                checked_set (_kdm_server_url, config->kdm_server_url());
                }
 #ifdef DCPOMATIC_VARIANT_SWAROOP
                checked_set (_kdm_server_url, config->kdm_server_url());
+               if (config->player_lock_file()) {
+                       checked_set (_lock_file, config->player_lock_file().get());
+               }
 #endif
        }
 
 #endif
        }
 
@@ -190,6 +199,11 @@ private:
        {
                Config::instance()->set_kdm_server_url(wx_to_std(_kdm_server_url->GetValue()));
        }
        {
                Config::instance()->set_kdm_server_url(wx_to_std(_kdm_server_url->GetValue()));
        }
+
+       void lock_file_changed ()
+       {
+               Config::instance()->set_player_lock_file(wx_to_std(_lock_file->GetPath()));
+       }
 #endif
 
        wxChoice* _player_mode;
 #endif
 
        wxChoice* _player_mode;
@@ -198,6 +212,7 @@ private:
        FilePickerCtrl* _log_file;
 #ifdef DCPOMATIC_VARIANT_SWAROOP
        wxTextCtrl* _kdm_server_url;
        FilePickerCtrl* _log_file;
 #ifdef DCPOMATIC_VARIANT_SWAROOP
        wxTextCtrl* _kdm_server_url;
+       FilePickerCtrl* _lock_file;
 #endif
 };
 
 #endif
 };