Merged with trunk R1719.
[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                 }
101         }
102 }
103
104 ControlProtocol*
105 ControlProtocolManager::instantiate (ControlProtocolInfo& cpi)
106 {
107         if (_session == 0) {
108                 return 0;
109         }
110
111         cpi.descriptor = get_descriptor (cpi.path);
112
113         if (cpi.descriptor == 0) {
114                 error << string_compose (_("control protocol name \"%1\" has no descriptor"), cpi.name) << endmsg;
115                 return 0;
116         }
117
118         if ((cpi.protocol = cpi.descriptor->initialize (cpi.descriptor, _session)) == 0) {
119                 error << string_compose (_("control protocol name \"%1\" could not be initialized"), cpi.name) << endmsg;
120                 return 0;
121         }
122
123         Glib::Mutex::Lock lm (protocols_lock);
124         control_protocols.push_back (cpi.protocol);
125
126         return cpi.protocol;
127 }
128
129 int
130 ControlProtocolManager::teardown (ControlProtocolInfo& cpi)
131 {
132         if (!cpi.protocol) {
133                 return 0;
134         }
135
136         if (!cpi.descriptor) {
137                 return 0;
138         }
139
140         if (cpi.mandatory) {
141                 return 0;
142         }
143
144         cpi.descriptor->destroy (cpi.descriptor, cpi.protocol);
145         
146         {
147                 Glib::Mutex::Lock lm (protocols_lock);
148                 list<ControlProtocol*>::iterator p = find (control_protocols.begin(), control_protocols.end(), cpi.protocol);
149                 if (p != control_protocols.end()) {
150                         control_protocols.erase (p);
151                 } else {
152                         cerr << "Programming error: ControlProtocolManager::teardown() called for " << cpi.name << ", but it was not found in control_protocols" << endl;
153                 }
154
155                 list<ControlProtocolInfo*>::iterator p2 = find (control_protocol_info.begin(), control_protocol_info.end(), &cpi);
156                 if (p2 != control_protocol_info.end()) {
157                         control_protocol_info.erase (p2);
158                 } else {
159                         cerr << "Programming error: ControlProtocolManager::teardown() called for " << cpi.name << ", but it was not found in control_protocol_info" << endl;
160                 }
161         }
162         
163         cpi.protocol = 0;
164         dlclose (cpi.descriptor->module);
165         return 0;
166 }
167
168 static bool protocol_filter (const string& str, void *arg)
169 {
170         /* Not a dotfile, has a prefix before a period, suffix is "so", or "dylib" */
171         
172         return str[0] != '.' 
173           && ((str.length() > 3 && str.find (".so") == (str.length() - 3))
174               || (str.length() > 6 && str.find (".dylib") == (str.length() - 6)));
175 }
176
177 void
178 ControlProtocolManager::load_mandatory_protocols ()
179 {
180         if (_session == 0) {
181                 return;
182         }
183
184         for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
185                 if ((*i)->mandatory && ((*i)->protocol == 0)) {
186                         info << string_compose (_("Instantiating mandatory control protocol %1"), (*i)->name) << endmsg;
187                         instantiate (**i);
188                 }
189         }
190 }
191
192 void
193 ControlProtocolManager::discover_control_protocols (string path)
194 {
195         vector<string *> *found;
196         PathScanner scanner;
197
198         info << string_compose (_("looking for control protocols in %1"), path) << endmsg;
199
200         found = scanner (path, protocol_filter, 0, false, true);
201
202         for (vector<string*>::iterator i = found->begin(); i != found->end(); ++i) {
203                 control_protocol_discover (**i);
204                 delete *i;
205         }
206
207         delete found;
208 }
209
210 int
211 ControlProtocolManager::control_protocol_discover (string path)
212 {
213         ControlProtocolDescriptor* descriptor;
214
215         if ((descriptor = get_descriptor (path)) != 0) {
216
217                 ControlProtocolInfo* cpi = new ControlProtocolInfo ();
218
219                 if (!descriptor->probe (descriptor)) {
220                         info << string_compose (_("Control protocol %1 not usable"), descriptor->name) << endmsg;
221                 } else {
222
223                         cpi->descriptor = descriptor;
224                         cpi->name = descriptor->name;
225                         cpi->path = path;
226                         cpi->protocol = 0;
227                         cpi->requested = false;
228                         cpi->mandatory = descriptor->mandatory;
229                         cpi->supports_feedback = descriptor->supports_feedback;
230                         cpi->state = 0;
231                         
232                         control_protocol_info.push_back (cpi);
233                         
234                         info << string_compose(_("Control surface protocol discovered: \"%1\""), cpi->name) << endmsg;
235                 }
236
237                 dlclose (descriptor->module);
238         }
239
240         return 0;
241 }
242
243 ControlProtocolDescriptor*
244 ControlProtocolManager::get_descriptor (string path)
245 {
246         void *module;
247         ControlProtocolDescriptor *descriptor = 0;
248         ControlProtocolDescriptor* (*dfunc)(void);
249         const char *errstr;
250
251         if ((module = dlopen (path.c_str(), RTLD_NOW)) == 0) {
252                 error << string_compose(_("ControlProtocolManager: cannot load module \"%1\" (%2)"), path, dlerror()) << endmsg;
253                 return 0;
254         }
255
256
257         dfunc = (ControlProtocolDescriptor* (*)(void)) dlsym (module, "protocol_descriptor");
258
259         if ((errstr = dlerror()) != 0) {
260                 error << string_compose(_("ControlProtocolManager: module \"%1\" has no descriptor function."), path) << endmsg;
261                 error << errstr << endmsg;
262                 dlclose (module);
263                 return 0;
264         }
265
266         descriptor = dfunc();
267         if (descriptor) {
268                 descriptor->module = module;
269         } else {
270                 dlclose (module);
271         }
272
273         return descriptor;
274 }
275
276 void
277 ControlProtocolManager::foreach_known_protocol (sigc::slot<void,const ControlProtocolInfo*> method)
278 {
279         for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
280                 method (*i);
281         }
282 }
283
284 ControlProtocolInfo*
285 ControlProtocolManager::cpi_by_name (string name)
286 {
287         for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
288                 if (name == (*i)->name) {
289                         return *i;
290                 }
291         }
292         return 0;
293 }
294
295 int
296 ControlProtocolManager::set_state (const XMLNode& node)
297 {
298         XMLNodeList clist;
299         XMLNodeConstIterator citer;
300         XMLProperty* prop;
301
302         clist = node.children();
303
304         for (citer = clist.begin(); citer != clist.end(); ++citer) {
305                 if ((*citer)->name() == X_("Protocol")) {
306
307                         prop = (*citer)->property (X_("active"));
308
309                         if (prop && prop->value() == X_("yes")) {
310                                 if ((prop = (*citer)->property (X_("name"))) != 0) {
311                                         ControlProtocolInfo* cpi = cpi_by_name (prop->value());
312                                         if (cpi) {
313                                                 if (!(*citer)->children().empty()) {
314                                                         cpi->state = (*citer)->children().front ();
315                                                 } else {
316                                                         cpi->state = 0;
317                                                 }
318                                                 
319                                                 if (_session) {
320                                                         instantiate (*cpi);
321                                                 } else {
322                                                         cpi->requested = true;
323                                                 }
324                                         }
325                                 }
326                         }
327                 }    
328         }
329         return 0;
330 }
331
332 XMLNode&
333 ControlProtocolManager::get_state (void)
334 {
335         XMLNode* root = new XMLNode (state_node_name);
336         Glib::Mutex::Lock lm (protocols_lock);
337
338         for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
339
340                 XMLNode * child;
341
342                 if ((*i)->protocol) {
343                         child = &((*i)->protocol->get_state());
344                         child->add_property (X_("active"), "yes");
345                         // should we update (*i)->state here?  probably.
346                         root->add_child_nocopy (*child);
347                 }
348                 else if ((*i)->state) {
349                         // keep ownership clear
350                         root->add_child_copy (*(*i)->state);
351                 }
352                 else {
353                         child = new XMLNode (X_("Protocol"));
354                         child->add_property (X_("name"), (*i)->name);
355                         child->add_property (X_("active"), "no");
356                         root->add_child_nocopy (*child);
357                 }
358         }
359
360         return *root;
361 }
362
363 void
364 ControlProtocolManager::set_protocol_states (const XMLNode& node)
365 {
366         XMLNodeList nlist;
367         XMLNodeConstIterator niter;
368         XMLProperty* prop;
369
370         nlist = node.children();
371
372         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
373
374                 XMLNode* child = (*niter);
375
376                 if ((prop = child->property ("name")) == 0) {
377                         error << _("control protocol XML node has no name property. Ignored.") << endmsg;
378                         continue;
379                 }
380
381                 ControlProtocolInfo* cpi = cpi_by_name (prop->value());
382
383                 if (!cpi) {
384                         warning << string_compose (_("control protocol \"%1\" is not known. Ignored"), prop->value()) << endmsg;
385                         continue;
386                 }
387
388                 /* copy the node so that ownership is clear */
389
390                 cpi->state = new XMLNode (*child);
391         }
392 }