new ControlProtocolManager API, and proper handling of view/model changes in the...
[ardour.git] / libs / ardour / control_protocol_manager.cc
1 /*
2     Copyright (C) 2000-2007 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #include <dlfcn.h>
21
22 #include <glibmm/fileutils.h>
23
24 #include "pbd/compose.h"
25 #include "pbd/file_utils.h"
26 #include "pbd/error.h"
27
28 #include "control_protocol/control_protocol.h"
29
30 #include "ardour/debug.h"
31 #include "ardour/control_protocol_manager.h"
32 #include "ardour/control_protocol_search_path.h"
33
34 using namespace ARDOUR;
35 using namespace std;
36 using namespace PBD;
37
38 #include "i18n.h"
39
40 ControlProtocolManager* ControlProtocolManager::_instance = 0;
41 const string ControlProtocolManager::state_node_name = X_("ControlProtocols");
42
43 ControlProtocolManager::ControlProtocolManager ()
44 {
45 }
46
47 ControlProtocolManager::~ControlProtocolManager()
48 {
49         Glib::Threads::Mutex::Lock lm (protocols_lock);
50
51         for (list<ControlProtocol*>::iterator i = control_protocols.begin(); i != control_protocols.end(); ++i) {
52                 delete (*i);
53         }
54
55         control_protocols.clear ();
56
57
58         for (list<ControlProtocolInfo*>::iterator p = control_protocol_info.begin(); p != control_protocol_info.end(); ++p) {
59                 delete (*p);
60         }
61
62         control_protocol_info.clear();
63 }
64
65 void
66 ControlProtocolManager::set_session (Session* s)
67 {
68         SessionHandlePtr::set_session (s);
69
70         if (_session) {
71                 Glib::Threads::Mutex::Lock lm (protocols_lock);
72
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);
76                         }
77                 }
78         }
79 }
80
81 int
82 ControlProtocolManager::activate (ControlProtocolInfo& cpi)
83 {
84         ControlProtocol* cp;
85
86         cpi.requested = true;
87
88         if ((cp = instantiate (cpi)) == 0) {
89                 return -1;
90         }
91
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.
96         */
97
98         if (cpi.state) {
99                 /* force this by tweaking the internals of the state
100                  * XMLNode. Ugh.
101                  */
102                 cp->set_state (*cpi.state, Stateful::loading_state_version);
103         } else {
104                 /* guarantee a call to
105                    set_state() whether we have
106                    existing state or not
107                 */
108                 cp->set_state (XMLNode(""), Stateful::loading_state_version);
109         }
110
111         cp->set_active (true);
112
113         return 0;
114 }       
115
116 int
117 ControlProtocolManager::deactivate (ControlProtocolInfo& cpi)
118 {
119         cpi.requested = false;
120         return teardown (cpi);
121 }
122
123 void
124 ControlProtocolManager::session_going_away()
125 {
126         SessionHandlePtr::session_going_away ();
127
128         {
129                 Glib::Threads::Mutex::Lock lm (protocols_lock);
130
131                 for (list<ControlProtocol*>::iterator p = control_protocols.begin(); p != control_protocols.end(); ++p) {
132                         delete *p;
133                 }
134
135                 control_protocols.clear ();
136
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;
142                                 (*p)->protocol = 0;
143                         }
144                 }
145         }
146 }
147
148 ControlProtocol*
149 ControlProtocolManager::instantiate (ControlProtocolInfo& cpi)
150 {
151         /* CALLER MUST HOLD LOCK */
152
153         if (_session == 0) {
154                 return 0;
155         }
156
157         cpi.descriptor = get_descriptor (cpi.path);
158
159         DEBUG_TRACE (DEBUG::ControlProtocols, string_compose ("instantiating %1\n", cpi.name));
160
161         if (cpi.descriptor == 0) {
162                 error << string_compose (_("control protocol name \"%1\" has no descriptor"), cpi.name) << endmsg;
163                 return 0;
164         }
165
166         DEBUG_TRACE (DEBUG::ControlProtocols, string_compose ("initializing %1\n", cpi.name));
167
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;
170                 return 0;
171         }
172
173         control_protocols.push_back (cpi.protocol);
174
175         ProtocolStatusChange (&cpi);
176
177         return cpi.protocol;
178 }
179
180 int
181 ControlProtocolManager::teardown (ControlProtocolInfo& cpi)
182 {
183         if (!cpi.protocol) {
184                 return 0;
185         }
186
187         if (!cpi.descriptor) {
188                 return 0;
189         }
190
191         if (cpi.mandatory) {
192                 return 0;
193         }
194         
195         /* save current state */
196
197         delete cpi.state;
198         cpi.state = new XMLNode (cpi.protocol->get_state());
199         cpi.state->add_property (X_("active"), "no");
200
201         cpi.descriptor->destroy (cpi.descriptor, cpi.protocol);
202
203         {
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);
208                 } else {
209                         cerr << "Programming error: ControlProtocolManager::teardown() called for " << cpi.name << ", but it was not found in control_protocols" << endl;
210                 }
211         }
212
213         cpi.protocol = 0;
214         dlclose (cpi.descriptor->module);
215
216         ProtocolStatusChange (&cpi);
217
218         return 0;
219 }
220
221 void
222 ControlProtocolManager::load_mandatory_protocols ()
223 {
224         if (_session == 0) {
225                 return;
226         }
227
228         Glib::Threads::Mutex::Lock lm (protocols_lock);
229
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));
234                         instantiate (**i);
235                 }
236         }
237 }
238
239 void
240 ControlProtocolManager::discover_control_protocols ()
241 {
242         vector<std::string> cp_modules;
243
244         Glib::PatternSpec so_extension_pattern("*.so");
245         Glib::PatternSpec dylib_extension_pattern("*.dylib");
246
247         find_matching_files_in_search_path (control_protocol_search_path (),
248                                             so_extension_pattern, cp_modules);
249
250         find_matching_files_in_search_path (control_protocol_search_path (),
251                                             dylib_extension_pattern, cp_modules);
252
253         DEBUG_TRACE (DEBUG::ControlProtocols, 
254                      string_compose (_("looking for control protocols in %1\n"), control_protocol_search_path().to_string()));
255         
256         for (vector<std::string>::iterator i = cp_modules.begin(); i != cp_modules.end(); ++i) {
257                 control_protocol_discover (*i);
258         }
259 }
260
261 int
262 ControlProtocolManager::control_protocol_discover (string path)
263 {
264         ControlProtocolDescriptor* descriptor;
265
266 #ifdef __APPLE__
267         /* don't load OS X shared objects that are just symlinks to the real thing.
268          */
269
270         if (path.find (".dylib") && Glib::file_test (path, Glib::FILE_TEST_IS_SYMLINK)) {
271                 return 0;
272         }
273 #endif
274
275         if ((descriptor = get_descriptor (path)) != 0) {
276
277                 if (!descriptor->probe (descriptor)) {
278                         DEBUG_TRACE (DEBUG::ControlProtocols,
279                                      string_compose (_("Control protocol %1 not usable"), descriptor->name));
280                 } else {
281
282                         ControlProtocolInfo* cpi = new ControlProtocolInfo ();
283
284                         cpi->descriptor = descriptor;
285                         cpi->name = descriptor->name;
286                         cpi->path = path;
287                         cpi->protocol = 0;
288                         cpi->requested = false;
289                         cpi->mandatory = descriptor->mandatory;
290                         cpi->supports_feedback = descriptor->supports_feedback;
291                         cpi->state = 0;
292
293                         control_protocol_info.push_back (cpi);
294
295                         DEBUG_TRACE (DEBUG::ControlProtocols, 
296                                      string_compose(_("Control surface protocol discovered: \"%1\"\n"), cpi->name));
297                 }
298
299                 dlclose (descriptor->module);
300         }
301
302         return 0;
303 }
304
305 ControlProtocolDescriptor*
306 ControlProtocolManager::get_descriptor (string path)
307 {
308         void *module;
309         ControlProtocolDescriptor *descriptor = 0;
310         ControlProtocolDescriptor* (*dfunc)(void);
311         const char *errstr;
312
313         if ((module = dlopen (path.c_str(), RTLD_NOW)) == 0) {
314                 error << string_compose(_("ControlProtocolManager: cannot load module \"%1\" (%2)"), path, dlerror()) << endmsg;
315                 return 0;
316         }
317
318
319         dfunc = (ControlProtocolDescriptor* (*)(void)) dlsym (module, "protocol_descriptor");
320
321         if ((errstr = dlerror()) != 0) {
322                 error << string_compose(_("ControlProtocolManager: module \"%1\" has no descriptor function."), path) << endmsg;
323                 error << errstr << endmsg;
324                 dlclose (module);
325                 return 0;
326         }
327
328         descriptor = dfunc();
329         if (descriptor) {
330                 descriptor->module = module;
331         } else {
332                 dlclose (module);
333         }
334
335         return descriptor;
336 }
337
338 void
339 ControlProtocolManager::foreach_known_protocol (boost::function<void(const ControlProtocolInfo*)> method)
340 {
341         for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
342                 method (*i);
343         }
344 }
345
346 ControlProtocolInfo*
347 ControlProtocolManager::cpi_by_name (string name)
348 {
349         for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
350                 if (name == (*i)->name) {
351                         return *i;
352                 }
353         }
354         return 0;
355 }
356
357 int
358 ControlProtocolManager::set_state (const XMLNode& node, int /*version*/)
359 {
360         XMLNodeList clist;
361         XMLNodeConstIterator citer;
362         XMLProperty* prop;
363
364         Glib::Threads::Mutex::Lock lm (protocols_lock);
365
366         clist = node.children();
367
368         for (citer = clist.begin(); citer != clist.end(); ++citer) {
369                 if ((*citer)->name() == X_("Protocol")) {
370
371                         if ((prop = (*citer)->property (X_("active"))) == 0) {
372                                 continue;
373                         }
374
375                         bool active = string_is_affirmative (prop->value());
376                         
377                         if ((prop = (*citer)->property (X_("name"))) == 0) {
378                                 continue;
379                         }
380
381                         ControlProtocolInfo* cpi = cpi_by_name (prop->value());
382                         
383                         if (cpi) {
384                                 cpi->state = new XMLNode (**citer);
385                                 
386                                 if (active) {
387                                         if (_session) {
388                                                 instantiate (*cpi);
389                                         } else {
390                                                 cpi->requested = true;
391                                         }
392                                 } else {
393                                         if (_session) {
394                                                 teardown (*cpi);
395                                         } else {
396                                                 cpi->requested = false;
397                                         }
398                                 }
399                         }
400                 }
401         }
402
403         return 0;
404 }
405
406 XMLNode&
407 ControlProtocolManager::get_state ()
408 {
409         XMLNode* root = new XMLNode (state_node_name);
410         Glib::Threads::Mutex::Lock lm (protocols_lock);
411
412         for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
413
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);
422                 } else {
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);
427                 }
428
429         }
430
431         return *root;
432 }
433
434
435 ControlProtocolManager&
436 ControlProtocolManager::instance ()
437 {
438         if (_instance == 0) {
439                 _instance = new ControlProtocolManager ();
440         }
441
442         return *_instance;
443 }
444
445 void
446 ControlProtocolManager::midi_connectivity_established ()
447 {
448         Glib::Threads::Mutex::Lock lm (protocols_lock);
449
450         for (list<ControlProtocol*>::iterator p = control_protocols.begin(); p != control_protocols.end(); ++p) {
451                 (*p)->midi_connectivity_established ();
452         }
453 }