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