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