fix crash when opening session after one in which control surface(s) were used
[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 <pbd/compose.h>
23 #include <pbd/error.h>
24 #include <pbd/pathscanner.h>
25
26 #include <control_protocol/control_protocol.h>
27
28 #include <ardour/session.h>
29 #include <ardour/control_protocol_manager.h>
30
31 using namespace ARDOUR;
32 using namespace std;
33 using namespace PBD;
34
35 #include "i18n.h"
36
37 ControlProtocolManager* ControlProtocolManager::_instance = 0;
38 const string ControlProtocolManager::state_node_name = X_("ControlProtocols");
39
40 ControlProtocolManager::ControlProtocolManager ()
41 {
42         if (_instance == 0) {
43                 _instance = this;
44         }
45
46         _session = 0;
47 }
48
49 ControlProtocolManager::~ControlProtocolManager()
50 {
51         Glib::Mutex::Lock lm (protocols_lock);
52
53         for (list<ControlProtocol*>::iterator i = control_protocols.begin(); i != control_protocols.end(); ++i) {
54                 delete (*i);
55         }
56
57         control_protocols.clear ();
58
59         
60         for (list<ControlProtocolInfo*>::iterator p = control_protocol_info.begin(); p != control_protocol_info.end(); ++p) {
61                 delete (*p);
62         }
63
64         control_protocol_info.clear();
65 }
66
67 void
68 ControlProtocolManager::set_session (Session& s)
69 {
70         _session = &s;
71         _session->GoingAway.connect (mem_fun (*this, &ControlProtocolManager::drop_session));
72
73         for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
74                 if ((*i)->requested || (*i)->mandatory) {
75                         instantiate (**i);
76                         (*i)->requested = false;
77
78                         if ((*i)->protocol && (*i)->state) {
79                                 (*i)->protocol->set_state (*(*i)->state);
80                         }
81                 }
82         }
83 }
84
85 void
86 ControlProtocolManager::drop_session ()
87 {
88         _session = 0;
89
90         {
91                 Glib::Mutex::Lock lm (protocols_lock);
92                 for (list<ControlProtocol*>::iterator p = control_protocols.begin(); p != control_protocols.end(); ++p) {
93                         delete *p;
94                 }
95                 control_protocols.clear ();
96                 
97                 for (list<ControlProtocolInfo*>::iterator p = control_protocol_info.begin(); p != control_protocol_info.end(); ++p) {
98                         // otherwise the ControlProtocol instances are not recreated in set_session
99                         (*p)->requested = true;
100                         (*p)->protocol = 0;
101                 }
102         }
103 }
104
105 ControlProtocol*
106 ControlProtocolManager::instantiate (ControlProtocolInfo& cpi)
107 {
108         if (_session == 0) {
109                 return 0;
110         }
111
112         cpi.descriptor = get_descriptor (cpi.path);
113
114         if (cpi.descriptor == 0) {
115                 error << string_compose (_("control protocol name \"%1\" has no descriptor"), cpi.name) << endmsg;
116                 return 0;
117         }
118
119         if ((cpi.protocol = cpi.descriptor->initialize (cpi.descriptor, _session)) == 0) {
120                 error << string_compose (_("control protocol name \"%1\" could not be initialized"), cpi.name) << endmsg;
121                 return 0;
122         }
123
124         Glib::Mutex::Lock lm (protocols_lock);
125         control_protocols.push_back (cpi.protocol);
126
127         return cpi.protocol;
128 }
129
130 int
131 ControlProtocolManager::teardown (ControlProtocolInfo& cpi)
132 {
133         if (!cpi.protocol) {
134                 return 0;
135         }
136
137         if (!cpi.descriptor) {
138                 return 0;
139         }
140
141         if (cpi.mandatory) {
142                 return 0;
143         }
144
145         cpi.descriptor->destroy (cpi.descriptor, cpi.protocol);
146         
147         {
148                 Glib::Mutex::Lock lm (protocols_lock);
149                 list<ControlProtocol*>::iterator p = find (control_protocols.begin(), control_protocols.end(), cpi.protocol);
150                 if (p != control_protocols.end()) {
151                         control_protocols.erase (p);
152                 } else {
153                         cerr << "Programming error: ControlProtocolManager::teardown() called for " << cpi.name << ", but it was not found in control_protocols" << endl;
154                 }
155
156                 list<ControlProtocolInfo*>::iterator p2 = find (control_protocol_info.begin(), control_protocol_info.end(), &cpi);
157                 if (p2 != control_protocol_info.end()) {
158                         control_protocol_info.erase (p2);
159                 } else {
160                         cerr << "Programming error: ControlProtocolManager::teardown() called for " << cpi.name << ", but it was not found in control_protocol_info" << endl;
161                 }
162         }
163         
164         cpi.protocol = 0;
165         dlclose (cpi.descriptor->module);
166         return 0;
167 }
168
169 static bool protocol_filter (const string& str, void *arg)
170 {
171         /* Not a dotfile, has a prefix before a period, suffix is "so", or "dylib" */
172         
173         return str[0] != '.' 
174           && ((str.length() > 3 && str.find (".so") == (str.length() - 3))
175               || (str.length() > 6 && str.find (".dylib") == (str.length() - 6)));
176 }
177
178 void
179 ControlProtocolManager::load_mandatory_protocols ()
180 {
181         if (_session == 0) {
182                 return;
183         }
184
185         for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
186                 if ((*i)->mandatory && ((*i)->protocol == 0)) {
187                         info << string_compose (_("Instantiating mandatory control protocol %1"), (*i)->name) << endmsg;
188                         instantiate (**i);
189                 }
190         }
191 }
192
193 void
194 ControlProtocolManager::discover_control_protocols (string path)
195 {
196         vector<string *> *found;
197         PathScanner scanner;
198
199         info << string_compose (_("looking for control protocols in %1"), path) << endmsg;
200
201         found = scanner (path, protocol_filter, 0, false, true);
202
203         for (vector<string*>::iterator i = found->begin(); i != found->end(); ++i) {
204                 control_protocol_discover (**i);
205                 delete *i;
206         }
207
208         delete found;
209 }
210
211 int
212 ControlProtocolManager::control_protocol_discover (string path)
213 {
214         ControlProtocolDescriptor* descriptor;
215
216         if ((descriptor = get_descriptor (path)) != 0) {
217
218                 ControlProtocolInfo* cpi = new ControlProtocolInfo ();
219
220                 if (!descriptor->probe (descriptor)) {
221                         info << string_compose (_("Control protocol %1 not usable"), descriptor->name) << endmsg;
222                 } else {
223
224                         cpi->descriptor = descriptor;
225                         cpi->name = descriptor->name;
226                         cpi->path = path;
227                         cpi->protocol = 0;
228                         cpi->requested = false;
229                         cpi->mandatory = descriptor->mandatory;
230                         cpi->supports_feedback = descriptor->supports_feedback;
231                         cpi->state = 0;
232                         
233                         control_protocol_info.push_back (cpi);
234                         
235                         info << string_compose(_("Control surface protocol discovered: \"%1\""), cpi->name) << endmsg;
236                 }
237
238                 dlclose (descriptor->module);
239         }
240
241         return 0;
242 }
243
244 ControlProtocolDescriptor*
245 ControlProtocolManager::get_descriptor (string path)
246 {
247         void *module;
248         ControlProtocolDescriptor *descriptor = 0;
249         ControlProtocolDescriptor* (*dfunc)(void);
250         const char *errstr;
251
252         if ((module = dlopen (path.c_str(), RTLD_NOW)) == 0) {
253                 error << string_compose(_("ControlProtocolManager: cannot load module \"%1\" (%2)"), path, dlerror()) << endmsg;
254                 return 0;
255         }
256
257
258         dfunc = (ControlProtocolDescriptor* (*)(void)) dlsym (module, "protocol_descriptor");
259
260         if ((errstr = dlerror()) != 0) {
261                 error << string_compose(_("ControlProtocolManager: module \"%1\" has no descriptor function."), path) << endmsg;
262                 error << errstr << endmsg;
263                 dlclose (module);
264                 return 0;
265         }
266
267         descriptor = dfunc();
268         if (descriptor) {
269                 descriptor->module = module;
270         } else {
271                 dlclose (module);
272         }
273
274         return descriptor;
275 }
276
277 void
278 ControlProtocolManager::foreach_known_protocol (sigc::slot<void,const ControlProtocolInfo*> method)
279 {
280         for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
281                 method (*i);
282         }
283 }
284
285 ControlProtocolInfo*
286 ControlProtocolManager::cpi_by_name (string name)
287 {
288         for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
289                 if (name == (*i)->name) {
290                         return *i;
291                 }
292         }
293         return 0;
294 }
295
296 int
297 ControlProtocolManager::set_state (const XMLNode& node)
298 {
299         XMLNodeList clist;
300         XMLNodeConstIterator citer;
301         XMLProperty* prop;
302
303         clist = node.children();
304
305         for (citer = clist.begin(); citer != clist.end(); ++citer) {
306                 if ((*citer)->name() == X_("Protocol")) {
307
308                         prop = (*citer)->property (X_("active"));
309
310                         if (prop && prop->value() == X_("yes")) {
311                                 if ((prop = (*citer)->property (X_("name"))) != 0) {
312                                         ControlProtocolInfo* cpi = cpi_by_name (prop->value());
313                                         if (cpi) {
314                                                 if (!(*citer)->children().empty()) {
315                                                         cpi->state = (*citer)->children().front ();
316                                                 } else {
317                                                         cpi->state = 0;
318                                                 }
319                                                 
320                                                 if (_session) {
321                                                         instantiate (*cpi);
322                                                 } else {
323                                                         cpi->requested = true;
324                                                 }
325                                         }
326                                 }
327                         }
328                 }    
329         }
330         return 0;
331 }
332
333 XMLNode&
334 ControlProtocolManager::get_state (void)
335 {
336         XMLNode* root = new XMLNode (state_node_name);
337         Glib::Mutex::Lock lm (protocols_lock);
338
339         for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
340
341                 XMLNode * child;
342
343                 if ((*i)->protocol) {
344                         child = &((*i)->protocol->get_state());
345                         child->add_property (X_("active"), "yes");
346                         // should we update (*i)->state here?  probably.
347                         root->add_child_nocopy (*child);
348                 }
349                 else if ((*i)->state) {
350                         // keep ownership clear
351                         root->add_child_copy (*(*i)->state);
352                 }
353                 else {
354                         child = new XMLNode (X_("Protocol"));
355                         child->add_property (X_("name"), (*i)->name);
356                         child->add_property (X_("active"), "no");
357                         root->add_child_nocopy (*child);
358                 }
359         }
360
361         return *root;
362 }
363
364 void
365 ControlProtocolManager::set_protocol_states (const XMLNode& node)
366 {
367         XMLNodeList nlist;
368         XMLNodeConstIterator niter;
369         XMLProperty* prop;
370
371         nlist = node.children();
372
373         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
374
375                 XMLNode* child = (*niter);
376
377                 if ((prop = child->property ("name")) == 0) {
378                         error << _("control protocol XML node has no name property. Ignored.") << endmsg;
379                         continue;
380                 }
381
382                 ControlProtocolInfo* cpi = cpi_by_name (prop->value());
383
384                 if (!cpi) {
385                         warning << string_compose (_("control protocol \"%1\" is not known. Ignored"), prop->value()) << endmsg;
386                         continue;
387                 }
388
389                 /* copy the node so that ownership is clear */
390
391                 cpi->state = new XMLNode (*child);
392         }
393 }