From 264583479e79b481251f1772b228f82cd77552d3 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 13 Nov 2018 00:04:23 +0000 Subject: [PATCH] swaroop: only allow playback if configured lock file is present. --- src/lib/checker.cc | 95 ++++++++++++++++++++++++++++++++++ src/lib/checker.h | 65 +++++++++++++++++++++++ src/lib/config.cc | 5 ++ src/lib/config.h | 18 +++++++ src/lib/lock_file_checker.cc | 54 +++++++++++++++++++ src/lib/lock_file_checker.h | 36 +++++++++++++ src/lib/monitor_checker.cc | 62 ++-------------------- src/lib/monitor_checker.h | 21 +++----- src/lib/wscript | 2 + src/tools/dcpomatic_player.cc | 15 ++++++ src/wx/player_config_dialog.cc | 15 ++++++ 11 files changed, 315 insertions(+), 73 deletions(-) create mode 100644 src/lib/checker.cc create mode 100644 src/lib/checker.h create mode 100644 src/lib/lock_file_checker.cc create mode 100644 src/lib/lock_file_checker.h diff --git a/src/lib/checker.cc b/src/lib/checker.cc new file mode 100644 index 000000000..13d9aacee --- /dev/null +++ b/src/lib/checker.cc @@ -0,0 +1,95 @@ +/* + Copyright (C) 2018 Carl Hetherington + + 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 . + +*/ + +#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 index 000000000..fee3fc3d9 --- /dev/null +++ b/src/lib/checker.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2018 Carl Hetherington + + 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 . + +*/ + +/** @file src/lib/checker.h + * @brief Checker class. + */ + +#ifndef DCPOMATIC_CHECKER_H +#define DCPOMATIC_CHECKER_H + +#include "signaller.h" +#include + +/** 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 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 diff --git a/src/lib/config.cc b/src/lib/config.cc index b64690aad..31ae15b36 100644 --- a/src/lib/config.cc +++ b/src/lib/config.cc @@ -177,6 +177,7 @@ Config::set_defaults () _player_watermark_period = 1; _player_watermark_duration = 50; _allow_spl_editing = true; + _player_lock_file = boost::none; #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); + _player_lock_file = f.optional_string_child("PlayerLockFile"); #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"); + if (_player_lock_file) { + root->add_child("PlayerLockFile")->add_child_text(_player_lock_file->string()); + } #endif try { diff --git a/src/lib/config.h b/src/lib/config.h index a162750fe..dd20b58e7 100644 --- a/src/lib/config.h +++ b/src/lib/config.h @@ -524,6 +524,10 @@ public: std::vector required_monitors () const { return _required_monitors; } + + boost::optional player_lock_file () const { + return _player_lock_file; + } #endif bool allow_spl_editing () const { @@ -1020,6 +1024,18 @@ public: void set_required_monitors (std::vector 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) { @@ -1229,6 +1245,8 @@ private: /** watermark duration in milliseconds */ int _player_watermark_duration; std::vector _required_monitors; + /** a file which, if specified, must be present for the player to work */ + boost::optional _player_lock_file; #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 index 000000000..9543c2c9f --- /dev/null +++ b/src/lib/lock_file_checker.cc @@ -0,0 +1,54 @@ +/* + Copyright (C) 2018 Carl Hetherington + + 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 . + +*/ + +#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 index 000000000..76c00717d --- /dev/null +++ b/src/lib/lock_file_checker.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2018 Carl Hetherington + + 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 . + +*/ + +#include "checker.h" +#include + +class LockFileChecker : public Checker +{ +public: + LockFileChecker (); + + static LockFileChecker* instance (); + +protected: + bool check () const; + +private: + static LockFileChecker* _instance; +}; diff --git a/src/lib/monitor_checker.cc b/src/lib/monitor_checker.cc index 19d8d8181..d15dee63f 100644 --- a/src/lib/monitor_checker.cc +++ b/src/lib/monitor_checker.cc @@ -24,75 +24,21 @@ #include "config.h" #include "cross.h" -using boost::bind; -using boost::ref; - 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 -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 () { diff --git a/src/lib/monitor_checker.h b/src/lib/monitor_checker.h index 4f856f41f..f99ab4b2a 100644 --- a/src/lib/monitor_checker.h +++ b/src/lib/monitor_checker.h @@ -18,28 +18,19 @@ */ -#include "signaller.h" +#include "checker.h" #include -class MonitorChecker : public Signaller, public boost::noncopyable +class MonitorChecker : public Checker { public: - ~MonitorChecker (); + MonitorChecker (); - void run (); + static MonitorChecker* instance (); - bool ok () const; - boost::signals2::signal StateChanged; +protected: + bool check () const; - static MonitorChecker* instance (); private: static MonitorChecker* _instance; - - MonitorChecker (); - void thread (); - - boost::thread* _thread; - mutable boost::mutex _mutex; - bool _terminate; - bool _ok; }; diff --git a/src/lib/wscript b/src/lib/wscript index e78227b6b..88cec75ec 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -41,6 +41,7 @@ sources = """ text_content.cc text_decoder.cc case_insensitive_sorter.cc + checker.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 + lock_file_checker.cc log.cc log_entry.cc mid_side_decoder.cc diff --git a/src/tools/dcpomatic_player.cc b/src/tools/dcpomatic_player.cc index db9463fe2..473cc6d8b 100644 --- a/src/tools/dcpomatic_player.cc +++ b/src/tools/dcpomatic_player.cc @@ -48,6 +48,7 @@ #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 #include @@ -206,6 +207,8 @@ public: #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 (); @@ -248,8 +251,16 @@ public: void monitor_checker_state_changed () { if (!MonitorChecker::instance()->ok()) { + _viewer->stop (); error_dialog (this, _("The required display devices are not connected correctly.")); + } + } + + void lock_checker_state_changed () + { + if (!LockFileChecker::instance()->ok()) { _viewer->stop (); + error_dialog (this, _("The lock file is not present.")); } } #endif @@ -273,6 +284,10 @@ public: 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; diff --git a/src/wx/player_config_dialog.cc b/src/wx/player_config_dialog.cc index 62b216b11..de97f2b71 100644 --- a/src/wx/player_config_dialog.cc +++ b/src/wx/player_config_dialog.cc @@ -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; + + 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)); @@ -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)); + _lock_file->Bind (wxEVT_FILEPICKER_CHANGED, bind(&PlayerGeneralPage::lock_file_changed, this)); #endif } @@ -151,6 +157,9 @@ private: } #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 } @@ -190,6 +199,11 @@ private: { 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; @@ -198,6 +212,7 @@ private: FilePickerCtrl* _log_file; #ifdef DCPOMATIC_VARIANT_SWAROOP wxTextCtrl* _kdm_server_url; + FilePickerCtrl* _lock_file; #endif }; -- 2.30.2