summaryrefslogtreecommitdiff
path: root/libs/ardour
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2006-04-05 00:24:57 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2006-04-05 00:24:57 +0000
commitc412d819699995c84bfb55bc57e8ee26d471bc98 (patch)
tree026f14447a16ba2c35d27e0082e7bb2e5001da39 /libs/ardour
parent9ae0f6cbeec4702b50bcd2360ea4d5dc1aeebd47 (diff)
add new control protocol related files
git-svn-id: svn://localhost/trunk/ardour2@443 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour')
-rw-r--r--libs/ardour/ardour/control_protocol_manager.h48
-rw-r--r--libs/ardour/control_protocol.cc242
-rw-r--r--libs/ardour/control_protocol_manager.cc211
3 files changed, 501 insertions, 0 deletions
diff --git a/libs/ardour/ardour/control_protocol_manager.h b/libs/ardour/ardour/control_protocol_manager.h
new file mode 100644
index 0000000000..f0b7846978
--- /dev/null
+++ b/libs/ardour/ardour/control_protocol_manager.h
@@ -0,0 +1,48 @@
+#ifndef ardour_control_protocol_manager_h
+#define ardour_control_protocol_manager_h
+
+#include <string>
+#include <list>
+
+#include <pbd/lockmonitor.h>
+
+namespace ARDOUR {
+
+class ControlProtocol;
+class ControlProtocolDescriptor;
+
+struct ControlProtocolInfo {
+ ControlProtocolDescriptor* descriptor;
+ ControlProtocol* protocol;
+ std::string name;
+ std::string path;
+};
+
+class ControlProtocolManager
+{
+ public:
+ ControlProtocolManager ();
+ ~ControlProtocolManager ();
+
+ static ControlProtocolManager& instance() { return *_instance; }
+
+ void discover_control_protocols (std::string search_path);
+ void startup (Session&);
+
+ ControlProtocol* instantiate (Session&, std::string protocol_name);
+ int teardown (std::string protocol_name);
+
+ private:
+ static ControlProtocolManager* _instance;
+
+ PBD::Lock protocols_lock;
+ std::list<ControlProtocolInfo*> control_protocol_info;
+ std::list<ControlProtocol*> control_protocols;
+
+ int control_protocol_discover (std::string path);
+ ControlProtocolDescriptor* get_descriptor (std::string path);
+};
+
+} // namespace
+
+#endif // ardour_control_protocol_manager_h
diff --git a/libs/ardour/control_protocol.cc b/libs/ardour/control_protocol.cc
new file mode 100644
index 0000000000..9e1cbfd4fd
--- /dev/null
+++ b/libs/ardour/control_protocol.cc
@@ -0,0 +1,242 @@
+/*
+ Copyright (C) 2006 Paul Davis
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ $Id$
+*/
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <poll.h>
+
+#include <pbd/pthread_utils.h>
+#include <pbd/error.h>
+#include <ardour/control_protocol.h>
+#include <ardour/configuration.h>
+#include <ardour/session.h>
+
+using namespace ARDOUR;
+using namespace std;
+
+#include "i18n.h"
+
+ControlProtocol::ControlProtocol (Session& s, string str)
+ : session (s),
+ _name (str)
+{
+ active_thread = 1;
+}
+
+ControlProtocol::~ControlProtocol ()
+{
+}
+
+void
+ControlProtocol::set_send (SendWhat sw)
+{
+ _send = sw;
+}
+
+int
+ControlProtocol::init_thread ()
+{
+ if (pipe (thread_request_pipe) != 0) {
+ error << string_compose (_("%1: cannot create thread request pipe (%1)"), _name, strerror (errno))
+ << endmsg;
+ return -1;
+ }
+
+ if (fcntl (thread_request_pipe[0], F_SETFL, O_NONBLOCK)) {
+ error << string_compose(_("%1: cannot set O_NONBLOCK on read pipe (%2)"), _name, strerror (errno)) << endmsg;
+ return -1;
+ }
+
+ if (fcntl (thread_request_pipe[1], F_SETFL, O_NONBLOCK)) {
+ error << string_compose(_("%1: cannot set O_NONBLOCK on signal write pipe (%2)"), _name, strerror (errno)) << endmsg;
+ return -1;
+ }
+
+ if (pthread_create_and_store ("tranzport delivery", &_thread, 0, _thread_work, this)) {
+ error << string_compose (_("%1: could not create thread"), _name) << endmsg;
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+ControlProtocol::poke_thread (ThreadRequest::Type why)
+{
+ char c = (char) why;
+ return !(write (thread_request_pipe[1], &c, 1) == 1);
+}
+
+int
+ControlProtocol::start_thread ()
+{
+ return poke_thread (ThreadRequest::Start);
+}
+
+int
+ControlProtocol::stop_thread ()
+{
+ return poke_thread (ThreadRequest::Stop);
+}
+
+void
+ControlProtocol::set_active (bool yn)
+{
+ if (yn != active_thread) {
+
+ if (yn) {
+ /* make sure the feedback thread is alive */
+ start_thread ();
+ } else {
+ /* maybe put the feedback thread to sleep */
+ stop_thread ();
+ }
+
+ ActiveChanged ();
+ }
+}
+
+void
+ControlProtocol::terminate_thread ()
+{
+ void* status;
+ poke_thread (ThreadRequest::Quit);
+ pthread_join (_thread, &status);
+}
+
+void*
+ControlProtocol::_thread_work (void* arg)
+{
+ return static_cast<ControlProtocol*> (arg)->thread_work ();
+}
+
+void*
+ControlProtocol::thread_work ()
+{
+ PBD::ThreadCreated (pthread_self(), _name);
+
+ struct pollfd pfd[1];
+ int timeout;
+
+ struct sched_param rtparam;
+ int err;
+
+ memset (&rtparam, 0, sizeof (rtparam));
+ rtparam.sched_priority = 3; /* XXX should be relative to audio (JACK) thread */
+
+ if ((err = pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam)) != 0) {
+ // do we care? not particularly.
+ info << string_compose (_("%1: delivery thread not running with realtime scheduling (%2)"), _name, strerror (errno)) << endmsg;
+ }
+
+ pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
+ pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
+
+
+ if (active_thread) {
+ timeout = max (5, (int) Config->get_feedback_interval_ms());
+ } else {
+ timeout = -1;
+ }
+
+ while (1) {
+
+ pfd[0].fd = thread_request_pipe[0];
+ pfd[0].events = POLLIN|POLLHUP|POLLERR;
+
+ if (poll (pfd, 1, timeout) < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ error << string_compose (_("Protocol \"%1\" thread: poll failed (%2)"), _name, strerror (errno))
+ << endmsg;
+ break;
+ }
+
+ if (pfd[0].revents & ~POLLIN) {
+ error << string_compose (_("Error thread request pipe for protocol \"%1\""), _name) << endmsg;
+ break;
+ }
+
+ if (pfd[0].revents & POLLIN) {
+
+ char req;
+
+ /* empty the pipe of all current requests */
+
+ while (1) {
+ size_t nread = read (thread_request_pipe[0], &req, sizeof (req));
+
+ if (nread == 1) {
+ switch ((ThreadRequest::Type) req) {
+
+ case ThreadRequest::Start:
+ timeout = max (5, (int) Config->get_feedback_interval_ms());
+ active_thread++;
+ break;
+
+ case ThreadRequest::Stop:
+ timeout = -1;
+ if (active_thread) {
+ active_thread--;
+ }
+ break;
+
+ case ThreadRequest::Quit:
+ pthread_exit_pbd (0);
+ /*NOTREACHED*/
+ break;
+
+ default:
+ break;
+ }
+
+ } else if (nread == 0) {
+ break;
+ } else if (errno == EAGAIN) {
+ break;
+ } else {
+ fatal << string_compose (_("Error reading from thread request pipe for protocol \"%1\""), _name) << endmsg;
+ /*NOTREACHED*/
+ }
+ }
+ }
+
+ if (!active_thread) {
+ continue;
+ }
+
+ cerr << ".\n";
+
+ if (send()) {
+
+ list<Route*> routes = session.get_routes(); /* copies the routes */
+
+ if (send_route_feedback ()) {
+ send_route_feedback (routes);
+ }
+
+ send_global_feedback ();
+ }
+ }
+
+ return 0;
+}
diff --git a/libs/ardour/control_protocol_manager.cc b/libs/ardour/control_protocol_manager.cc
new file mode 100644
index 0000000000..4944816177
--- /dev/null
+++ b/libs/ardour/control_protocol_manager.cc
@@ -0,0 +1,211 @@
+#include <dlfcn.h>
+
+#include <pbd/compose.h>
+#include <pbd/error.h>
+#include <pbd/pathscanner.h>
+
+#include <ardour/control_protocol.h>
+#include <ardour/control_protocol_manager.h>
+
+using namespace ARDOUR;
+using namespace PBD;
+using namespace std;
+
+#include "i18n.h"
+
+ControlProtocolManager* ControlProtocolManager::_instance = 0;
+
+ControlProtocolManager::ControlProtocolManager ()
+{
+ if (_instance == 0) {
+ _instance = this;
+ }
+}
+
+ControlProtocolManager::~ControlProtocolManager()
+{
+}
+
+void
+ControlProtocolManager::startup (Session& s)
+{
+ list<ControlProtocolInfo *>::iterator i;
+
+ for (i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
+
+ ControlProtocolInfo* cpi = (*i);
+
+ if (cpi->name == "Tranzport") {
+
+ cpi->descriptor = get_descriptor ((*i)->path);
+
+ if (cpi->descriptor == 0) {
+ error << string_compose (_("control protocol name \"%1\" has no descriptor"), cpi->name) << endmsg;
+ continue;
+ }
+
+ if ((cpi->protocol = cpi->descriptor->initialize (cpi->descriptor, &s)) == 0) {
+ error << string_compose (_("control protocol name \"%1\" could not be initialized"), cpi->name) << endmsg;
+ continue;
+ }
+
+ {
+ LockMonitor lm (protocols_lock, __LINE__, __FILE__);
+ control_protocols.push_back (cpi->protocol);
+ }
+
+ cerr << "start " << cpi->name << endl;
+ cpi->protocol->init ();
+
+ cerr << "activate " << cpi->name << endl;
+ cpi->protocol->set_active (true);
+
+ cerr << cpi->name << " now running\n";
+ }
+ }
+}
+
+ControlProtocol*
+ControlProtocolManager::instantiate (Session& session, string name)
+{
+ list<ControlProtocolInfo *>::iterator i;
+
+ for (i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
+ if ((*i)->name == name) {
+ break;
+ }
+ }
+
+ if (i == control_protocol_info.end()) {
+ error << string_compose (_("control protocol name \"%1\" is unknown"), name) << endmsg;
+ return 0;
+ }
+
+ ControlProtocolInfo* cpi = (*i);
+
+ cpi->descriptor = get_descriptor ((*i)->path);
+
+ if (cpi->descriptor == 0) {
+ error << string_compose (_("control protocol name \"%1\" has no descriptor"), name) << endmsg;
+ return 0;
+ }
+
+ if ((cpi->protocol = cpi->descriptor->initialize (cpi->descriptor, &session)) == 0) {
+ error << string_compose (_("control protocol name \"%1\" could not be initialized"), name) << endmsg;
+ return 0;
+ }
+
+ LockMonitor lm (protocols_lock, __LINE__, __FILE__);
+ control_protocols.push_back (cpi->protocol);
+ return cpi->protocol;
+}
+
+int
+ControlProtocolManager::teardown (string name)
+{
+ for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
+ ControlProtocolInfo* cpi = *i;
+
+ if (cpi->name == name && cpi->descriptor && cpi->protocol) {
+ cpi->descriptor->destroy (cpi->descriptor, cpi->protocol);
+
+ {
+ LockMonitor lm (protocols_lock, __LINE__, __FILE__);
+ list<ControlProtocol*>::iterator p = find (control_protocols.begin(), control_protocols.end(), cpi->protocol);
+ if (p != control_protocols.end()) {
+ control_protocols.erase (p);
+ }
+ }
+
+ cpi->protocol = 0;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+static bool protocol_filter (const string& str, void *arg)
+{
+ /* Not a dotfile, has a prefix before a period, suffix is "so" */
+
+ return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
+}
+
+void
+ControlProtocolManager::discover_control_protocols (string path)
+{
+ vector<string *> *found;
+ PathScanner scanner;
+
+ cerr << "CP Manager looking for surfaces\n";
+
+ found = scanner (path, protocol_filter, 0, false, true);
+
+ for (vector<string*>::iterator i = found->begin(); i != found->end(); ++i) {
+ cerr << "CP Manager looking at " << **i << endl;
+ control_protocol_discover (**i);
+ delete *i;
+ }
+
+ delete found;
+}
+
+int
+ControlProtocolManager::control_protocol_discover (string path)
+{
+ ControlProtocolDescriptor* descriptor;
+
+ if ((descriptor = get_descriptor (path)) != 0) {
+
+ ControlProtocolInfo* info = new ControlProtocolInfo ();
+
+ info->descriptor = descriptor;
+ info->name = descriptor->name;
+ info->path = path;
+
+ control_protocol_info.push_back (info);
+
+ cerr << "Found \"" << info->name << "\"\n";
+
+ dlclose (descriptor->module);
+
+ } else {
+ cerr << "no descriptor\n";
+ }
+
+ return 0;
+}
+
+ControlProtocolDescriptor*
+ControlProtocolManager::get_descriptor (string path)
+{
+ void *module;
+ ControlProtocolDescriptor *descriptor = 0;
+ ControlProtocolDescriptor* (*dfunc)(void);
+ const char *errstr;
+
+ if ((module = dlopen (path.c_str(), RTLD_NOW)) == 0) {
+ error << string_compose(_("ControlProtocolManager: cannot load module \"%1\" (%2)"), path, dlerror()) << endmsg;
+ return 0;
+ }
+
+
+ dfunc = (ControlProtocolDescriptor* (*)(void)) dlsym (module, "protocol_descriptor");
+
+ if ((errstr = dlerror()) != 0) {
+ error << string_compose(_("ControlProtocolManager: module \"%1\" has no descriptor function."), path) << endmsg;
+ error << errstr << endmsg;
+ dlclose (module);
+ return 0;
+ }
+
+ descriptor = dfunc();
+ if (descriptor) {
+ descriptor->module = module;
+ } else {
+ dlclose (module);
+ }
+
+ return descriptor;
+}