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