2 Copyright (C) 2000-2007 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <glibmm/fileutils.h>
24 #include "pbd/compose.h"
25 #include "pbd/file_utils.h"
26 #include "pbd/error.h"
28 #include "control_protocol/control_protocol.h"
30 #include "ardour/debug.h"
31 #include "ardour/control_protocol_manager.h"
32 #include "ardour/control_protocol_search_path.h"
34 using namespace ARDOUR;
40 ControlProtocolManager* ControlProtocolManager::_instance = 0;
41 const string ControlProtocolManager::state_node_name = X_("ControlProtocols");
43 ControlProtocolManager::ControlProtocolManager ()
47 ControlProtocolManager::~ControlProtocolManager()
49 Glib::Threads::Mutex::Lock lm (protocols_lock);
51 for (list<ControlProtocol*>::iterator i = control_protocols.begin(); i != control_protocols.end(); ++i) {
55 control_protocols.clear ();
58 for (list<ControlProtocolInfo*>::iterator p = control_protocol_info.begin(); p != control_protocol_info.end(); ++p) {
62 control_protocol_info.clear();
66 ControlProtocolManager::set_session (Session* s)
68 SessionHandlePtr::set_session (s);
71 Glib::Threads::Mutex::Lock lm (protocols_lock);
73 for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
74 if ((*i)->requested || (*i)->mandatory) {
75 (void) activate (**i);
82 ControlProtocolManager::activate (ControlProtocolInfo& cpi)
88 if ((cp = instantiate (cpi)) == 0) {
92 /* we split the set_state() and set_active() operations so that
93 protocols that need state to configure themselves (e.g. "What device
94 is connected, or supposed to be connected?") can get it before
95 actually starting any interaction.
99 /* force this by tweaking the internals of the state
102 cp->set_state (*cpi.state, Stateful::loading_state_version);
104 /* guarantee a call to
105 set_state() whether we have
106 existing state or not
108 cp->set_state (XMLNode(""), Stateful::loading_state_version);
111 cp->set_active (true);
117 ControlProtocolManager::deactivate (ControlProtocolInfo& cpi)
119 cpi.requested = false;
120 return teardown (cpi);
124 ControlProtocolManager::session_going_away()
126 SessionHandlePtr::session_going_away ();
129 Glib::Threads::Mutex::Lock lm (protocols_lock);
131 for (list<ControlProtocol*>::iterator p = control_protocols.begin(); p != control_protocols.end(); ++p) {
135 control_protocols.clear ();
137 for (list<ControlProtocolInfo*>::iterator p = control_protocol_info.begin(); p != control_protocol_info.end(); ++p) {
138 // mark existing protocols as requested
139 // otherwise the ControlProtocol instances are not recreated in set_session
140 if ((*p)->protocol) {
141 (*p)->requested = true;
149 ControlProtocolManager::instantiate (ControlProtocolInfo& cpi)
151 /* CALLER MUST HOLD LOCK */
157 cpi.descriptor = get_descriptor (cpi.path);
159 DEBUG_TRACE (DEBUG::ControlProtocols, string_compose ("instantiating %1\n", cpi.name));
161 if (cpi.descriptor == 0) {
162 error << string_compose (_("control protocol name \"%1\" has no descriptor"), cpi.name) << endmsg;
166 DEBUG_TRACE (DEBUG::ControlProtocols, string_compose ("initializing %1\n", cpi.name));
168 if ((cpi.protocol = cpi.descriptor->initialize (cpi.descriptor, _session)) == 0) {
169 error << string_compose (_("control protocol name \"%1\" could not be initialized"), cpi.name) << endmsg;
173 control_protocols.push_back (cpi.protocol);
175 ProtocolStatusChange (&cpi);
181 ControlProtocolManager::teardown (ControlProtocolInfo& cpi)
187 if (!cpi.descriptor) {
195 /* save current state */
198 cpi.state = new XMLNode (cpi.protocol->get_state());
199 cpi.state->add_property (X_("active"), "no");
201 cpi.descriptor->destroy (cpi.descriptor, cpi.protocol);
204 Glib::Threads::Mutex::Lock lm (protocols_lock);
205 list<ControlProtocol*>::iterator p = find (control_protocols.begin(), control_protocols.end(), cpi.protocol);
206 if (p != control_protocols.end()) {
207 control_protocols.erase (p);
209 cerr << "Programming error: ControlProtocolManager::teardown() called for " << cpi.name << ", but it was not found in control_protocols" << endl;
214 dlclose (cpi.descriptor->module);
216 ProtocolStatusChange (&cpi);
222 ControlProtocolManager::load_mandatory_protocols ()
228 Glib::Threads::Mutex::Lock lm (protocols_lock);
230 for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
231 if ((*i)->mandatory && ((*i)->protocol == 0)) {
232 DEBUG_TRACE (DEBUG::ControlProtocols,
233 string_compose (_("Instantiating mandatory control protocol %1"), (*i)->name));
240 ControlProtocolManager::discover_control_protocols ()
242 vector<std::string> cp_modules;
244 Glib::PatternSpec so_extension_pattern("*.so");
245 Glib::PatternSpec dylib_extension_pattern("*.dylib");
247 find_matching_files_in_search_path (control_protocol_search_path (),
248 so_extension_pattern, cp_modules);
250 find_matching_files_in_search_path (control_protocol_search_path (),
251 dylib_extension_pattern, cp_modules);
253 DEBUG_TRACE (DEBUG::ControlProtocols,
254 string_compose (_("looking for control protocols in %1\n"), control_protocol_search_path().to_string()));
256 for (vector<std::string>::iterator i = cp_modules.begin(); i != cp_modules.end(); ++i) {
257 control_protocol_discover (*i);
262 ControlProtocolManager::control_protocol_discover (string path)
264 ControlProtocolDescriptor* descriptor;
267 /* don't load OS X shared objects that are just symlinks to the real thing.
270 if (path.find (".dylib") && Glib::file_test (path, Glib::FILE_TEST_IS_SYMLINK)) {
275 if ((descriptor = get_descriptor (path)) != 0) {
277 if (!descriptor->probe (descriptor)) {
278 DEBUG_TRACE (DEBUG::ControlProtocols,
279 string_compose (_("Control protocol %1 not usable"), descriptor->name));
282 ControlProtocolInfo* cpi = new ControlProtocolInfo ();
284 cpi->descriptor = descriptor;
285 cpi->name = descriptor->name;
288 cpi->requested = false;
289 cpi->mandatory = descriptor->mandatory;
290 cpi->supports_feedback = descriptor->supports_feedback;
293 control_protocol_info.push_back (cpi);
295 DEBUG_TRACE (DEBUG::ControlProtocols,
296 string_compose(_("Control surface protocol discovered: \"%1\"\n"), cpi->name));
299 dlclose (descriptor->module);
305 ControlProtocolDescriptor*
306 ControlProtocolManager::get_descriptor (string path)
309 ControlProtocolDescriptor *descriptor = 0;
310 ControlProtocolDescriptor* (*dfunc)(void);
313 if ((module = dlopen (path.c_str(), RTLD_NOW)) == 0) {
314 error << string_compose(_("ControlProtocolManager: cannot load module \"%1\" (%2)"), path, dlerror()) << endmsg;
319 dfunc = (ControlProtocolDescriptor* (*)(void)) dlsym (module, "protocol_descriptor");
321 if ((errstr = dlerror()) != 0) {
322 error << string_compose(_("ControlProtocolManager: module \"%1\" has no descriptor function."), path) << endmsg;
323 error << errstr << endmsg;
328 descriptor = dfunc();
330 descriptor->module = module;
339 ControlProtocolManager::foreach_known_protocol (boost::function<void(const ControlProtocolInfo*)> method)
341 for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
347 ControlProtocolManager::cpi_by_name (string name)
349 for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
350 if (name == (*i)->name) {
358 ControlProtocolManager::set_state (const XMLNode& node, int /*version*/)
361 XMLNodeConstIterator citer;
364 Glib::Threads::Mutex::Lock lm (protocols_lock);
366 clist = node.children();
368 for (citer = clist.begin(); citer != clist.end(); ++citer) {
369 if ((*citer)->name() == X_("Protocol")) {
371 if ((prop = (*citer)->property (X_("active"))) == 0) {
375 bool active = string_is_affirmative (prop->value());
377 if ((prop = (*citer)->property (X_("name"))) == 0) {
381 ControlProtocolInfo* cpi = cpi_by_name (prop->value());
384 cpi->state = new XMLNode (**citer);
390 cpi->requested = true;
396 cpi->requested = false;
407 ControlProtocolManager::get_state ()
409 XMLNode* root = new XMLNode (state_node_name);
410 Glib::Threads::Mutex::Lock lm (protocols_lock);
412 for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
414 if ((*i)->protocol) {
415 XMLNode& child_state ((*i)->protocol->get_state());
416 child_state.add_property (X_("active"), "yes");
417 root->add_child_nocopy (child_state);
418 } else if ((*i)->state) {
419 XMLNode* child_state = new XMLNode (*(*i)->state);
420 child_state->add_property (X_("active"), "no");
421 root->add_child_nocopy (*child_state);
423 XMLNode* child_state = new XMLNode (X_("Protocol"));
424 child_state->add_property (X_("name"), (*i)->name);
425 child_state->add_property (X_("active"), "no");
426 root->add_child_nocopy (*child_state);
435 ControlProtocolManager&
436 ControlProtocolManager::instance ()
438 if (_instance == 0) {
439 _instance = new ControlProtocolManager ();
446 ControlProtocolManager::midi_connectivity_established ()
448 Glib::Threads::Mutex::Lock lm (protocols_lock);
450 for (list<ControlProtocol*>::iterator p = control_protocols.begin(); p != control_protocols.end(); ++p) {
451 (*p)->midi_connectivity_established ();