breakout control protocol code into LGPL library; fix panner buttons even more than...
[ardour.git] / libs / ardour / control_protocol_manager.cc
1 #include <dlfcn.h>
2
3 #include <pbd/compose.h>
4 #include <pbd/error.h>
5 #include <pbd/pathscanner.h>
6
7 #include "control_protocol.h"
8
9 #include <ardour/session.h>
10 #include <ardour/control_protocol_manager.h>
11
12
13
14
15 using namespace ARDOUR;
16 using namespace PBD;
17 using namespace std;
18
19 #include "i18n.h"
20
21 ControlProtocolManager* ControlProtocolManager::_instance = 0;
22 const string ControlProtocolManager::state_node_name = X_("ControlProtocols");
23
24 ControlProtocolManager::ControlProtocolManager ()
25 {
26         if (_instance == 0) {
27                 _instance = this;
28         }
29
30         _session = 0;
31 }
32
33 ControlProtocolManager::~ControlProtocolManager()
34 {
35         LockMonitor lm (protocols_lock, __LINE__, __FILE__);
36
37         for (list<ControlProtocol*>::iterator i = control_protocols.begin(); i != control_protocols.end(); ++i) {
38                 delete (*i);
39         }
40
41         control_protocols.clear ();
42                 
43 }
44
45 void
46 ControlProtocolManager::set_session (Session& s)
47 {
48         _session = &s;
49         _session->going_away.connect (mem_fun (*this, &ControlProtocolManager::drop_session));
50
51         for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
52                 if ((*i)->requested || (*i)->mandatory) {
53                         instantiate (**i);
54                         (*i)->requested = false;
55                 }
56         }
57 }
58
59 void
60 ControlProtocolManager::drop_session ()
61 {
62         _session = 0;
63
64         {
65                 LockMonitor lm (protocols_lock, __LINE__, __FILE__);
66                 for (list<ControlProtocol*>::iterator p = control_protocols.begin(); p != control_protocols.end(); ++p) {
67                         delete *p;
68                 }
69                 control_protocols.clear ();
70         }
71 }
72
73 ControlProtocol*
74 ControlProtocolManager::instantiate (ControlProtocolInfo& cpi)
75 {
76         if (_session == 0) {
77                 return 0;
78         }
79
80         cpi.descriptor = get_descriptor (cpi.path);
81
82         if (cpi.descriptor == 0) {
83                 error << string_compose (_("control protocol name \"%1\" has no descriptor"), cpi.name) << endmsg;
84                 return 0;
85         }
86
87         if ((cpi.protocol = cpi.descriptor->initialize (cpi.descriptor, _session)) == 0) {
88                 error << string_compose (_("control protocol name \"%1\" could not be initialized"), cpi.name) << endmsg;
89                 return 0;
90         }
91
92         LockMonitor lm (protocols_lock, __LINE__, __FILE__);
93         control_protocols.push_back (cpi.protocol);
94
95         return cpi.protocol;
96 }
97
98 int
99 ControlProtocolManager::teardown (ControlProtocolInfo& cpi)
100 {
101         if (!cpi.protocol) {
102                 return 0;
103         }
104
105         if (!cpi.descriptor) {
106                 return 0;
107         }
108
109         if (cpi.mandatory) {
110                 return 0;
111         }
112
113         cpi.descriptor->destroy (cpi.descriptor, cpi.protocol);
114         
115         {
116                 LockMonitor lm (protocols_lock, __LINE__, __FILE__);
117                 list<ControlProtocol*>::iterator p = find (control_protocols.begin(), control_protocols.end(), cpi.protocol);
118                 if (p != control_protocols.end()) {
119                         control_protocols.erase (p);
120                 }
121         }
122         
123         cpi.protocol = 0;
124         dlclose (cpi.descriptor->module);
125         return 0;
126 }
127
128 static bool protocol_filter (const string& str, void *arg)
129 {
130         /* Not a dotfile, has a prefix before a period, suffix is "so" */
131         
132         return str[0] != '.' && (str.length() > 3 && str.find (".so") == (str.length() - 3));
133 }
134
135 void
136 ControlProtocolManager::load_mandatory_protocols ()
137 {
138         if (_session == 0) {
139                 return;
140         }
141
142         for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
143                 if ((*i)->mandatory && ((*i)->protocol == 0)) {
144                         info << string_compose (_("Instantiating mandatory control protocol %1"), (*i)->name) << endmsg;
145                         instantiate (**i);
146                 }
147         }
148 }
149
150 void
151 ControlProtocolManager::discover_control_protocols (string path)
152 {
153         vector<string *> *found;
154         PathScanner scanner;
155
156         cerr << "looking for control protocols in " << path << endl;
157
158         found = scanner (path, protocol_filter, 0, false, true);
159
160         for (vector<string*>::iterator i = found->begin(); i != found->end(); ++i) {
161                 control_protocol_discover (**i);
162                 delete *i;
163         }
164
165         delete found;
166 }
167
168 int
169 ControlProtocolManager::control_protocol_discover (string path)
170 {
171         ControlProtocolDescriptor* descriptor;
172
173         if ((descriptor = get_descriptor (path)) != 0) {
174
175                 ControlProtocolInfo* cpi = new ControlProtocolInfo ();
176
177                 if (!descriptor->probe (descriptor)) {
178                         info << string_compose (_("Control protocol %1 not usable"), descriptor->name) << endmsg;
179                 } else {
180
181                         cpi->descriptor = descriptor;
182                         cpi->name = descriptor->name;
183                         cpi->path = path;
184                         cpi->protocol = 0;
185                         cpi->requested = false;
186                         cpi->mandatory = descriptor->mandatory;
187                         
188                         control_protocol_info.push_back (cpi);
189                         
190                         info << string_compose(_("Control surface protocol discovered: \"%1\""), cpi->name) << endmsg;
191                 }
192
193                 dlclose (descriptor->module);
194         }
195
196         return 0;
197 }
198
199 ControlProtocolDescriptor*
200 ControlProtocolManager::get_descriptor (string path)
201 {
202         void *module;
203         ControlProtocolDescriptor *descriptor = 0;
204         ControlProtocolDescriptor* (*dfunc)(void);
205         const char *errstr;
206
207         if ((module = dlopen (path.c_str(), RTLD_NOW)) == 0) {
208                 error << string_compose(_("ControlProtocolManager: cannot load module \"%1\" (%2)"), path, dlerror()) << endmsg;
209                 return 0;
210         }
211
212
213         dfunc = (ControlProtocolDescriptor* (*)(void)) dlsym (module, "protocol_descriptor");
214
215         if ((errstr = dlerror()) != 0) {
216                 error << string_compose(_("ControlProtocolManager: module \"%1\" has no descriptor function."), path) << endmsg;
217                 error << errstr << endmsg;
218                 dlclose (module);
219                 return 0;
220         }
221
222         descriptor = dfunc();
223         if (descriptor) {
224                 descriptor->module = module;
225         } else {
226                 dlclose (module);
227         }
228
229         return descriptor;
230 }
231
232 void
233 ControlProtocolManager::foreach_known_protocol (sigc::slot<void,const ControlProtocolInfo*> method)
234 {
235         for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
236                 method (*i);
237         }
238 }
239
240 ControlProtocolInfo*
241 ControlProtocolManager::cpi_by_name (string name)
242 {
243         for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
244                 if (name == (*i)->name) {
245                         return *i;
246                 }
247         }
248         return 0;
249 }
250
251 int
252 ControlProtocolManager::set_state (const XMLNode& node)
253 {
254         XMLNodeList clist;
255         XMLNodeConstIterator citer;
256         XMLProperty* prop;
257
258         clist = node.children();
259
260         for (citer = clist.begin(); citer != clist.end(); ++citer) {
261                 if ((*citer)->name() == X_("Protocol")) {
262                         prop = (*citer)->property (X_("active"));
263                         if (prop && prop->value() == X_("yes")) {
264                                 if ((prop = (*citer)->property (X_("name"))) != 0) {
265                                         ControlProtocolInfo* cpi = cpi_by_name (prop->value());
266                                         if (cpi) {
267                                                 if (_session) {
268                                                         instantiate (*cpi);
269                                                 } else {
270                                                         cpi->requested = true;
271                                                 }
272                                         }
273                                 }
274                         }
275                 }    
276         }
277         return 0;
278 }
279
280 XMLNode&
281 ControlProtocolManager::get_state (void)
282 {
283         XMLNode* root = new XMLNode (state_node_name);
284         LockMonitor lm (protocols_lock, __LINE__, __FILE__);
285
286         for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
287                 XMLNode* child = new XMLNode (X_("Protocol"));
288                 child->add_property (X_("name"), (*i)->name);
289                 child->add_property (X_("active"), (*i)->protocol ? "yes" : "no");
290                 root->add_child_nocopy (*child);
291         }
292
293         return *root;
294 }