~ubuntu-branches/ubuntu/utopic/ardour3/utopic

« back to all changes in this revision

Viewing changes to libs/ardour/control_protocol_manager.cc

  • Committer: Package Import Robot
  • Author(s): Felipe Sateler
  • Date: 2013-09-21 19:05:02 UTC
  • Revision ID: package-import@ubuntu.com-20130921190502-8gsftrku6jnzhd7v
Tags: upstream-3.4~dfsg
ImportĀ upstreamĀ versionĀ 3.4~dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 <glibmm/fileutils.h>
 
23
 
 
24
#include "pbd/compose.h"
 
25
#include "pbd/file_utils.h"
 
26
#include "pbd/error.h"
 
27
 
 
28
#include "control_protocol/control_protocol.h"
 
29
 
 
30
#include "ardour/debug.h"
 
31
#include "ardour/control_protocol_manager.h"
 
32
#include "ardour/control_protocol_search_path.h"
 
33
 
 
34
using namespace ARDOUR;
 
35
using namespace std;
 
36
using namespace PBD;
 
37
 
 
38
#include "i18n.h"
 
39
 
 
40
ControlProtocolManager* ControlProtocolManager::_instance = 0;
 
41
const string ControlProtocolManager::state_node_name = X_("ControlProtocols");
 
42
 
 
43
ControlProtocolManager::ControlProtocolManager ()
 
44
{
 
45
}
 
46
 
 
47
ControlProtocolManager::~ControlProtocolManager()
 
48
{
 
49
        Glib::Threads::Mutex::Lock lm (protocols_lock);
 
50
 
 
51
        for (list<ControlProtocol*>::iterator i = control_protocols.begin(); i != control_protocols.end(); ++i) {
 
52
                delete (*i);
 
53
        }
 
54
 
 
55
        control_protocols.clear ();
 
56
 
 
57
 
 
58
        for (list<ControlProtocolInfo*>::iterator p = control_protocol_info.begin(); p != control_protocol_info.end(); ++p) {
 
59
                delete (*p);
 
60
        }
 
61
 
 
62
        control_protocol_info.clear();
 
63
}
 
64
 
 
65
void
 
66
ControlProtocolManager::set_session (Session* s)
 
67
{
 
68
        SessionHandlePtr::set_session (s);
 
69
 
 
70
        if (_session) {
 
71
                Glib::Threads::Mutex::Lock lm (protocols_lock);
 
72
 
 
73
                for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
 
74
                        if ((*i)->requested || (*i)->mandatory) {
 
75
                                
 
76
                                instantiate (**i);
 
77
                                (*i)->requested = false;
 
78
 
 
79
                                if ((*i)->protocol) {
 
80
                                        if ((*i)->state) {
 
81
                                                (*i)->protocol->set_state (*(*i)->state, Stateful::loading_state_version);
 
82
                                        } else {
 
83
                                                /* guarantee a call to
 
84
                                                   set_state() whether we have
 
85
                                                   existing state or not
 
86
                                                */
 
87
                                                (*i)->protocol->set_state (XMLNode(""), Stateful::loading_state_version);
 
88
                                        }
 
89
                                }
 
90
                        }
 
91
                }
 
92
        }
 
93
}
 
94
 
 
95
void
 
96
ControlProtocolManager::session_going_away()
 
97
{
 
98
        SessionHandlePtr::session_going_away ();
 
99
 
 
100
        {
 
101
                Glib::Threads::Mutex::Lock lm (protocols_lock);
 
102
 
 
103
                for (list<ControlProtocol*>::iterator p = control_protocols.begin(); p != control_protocols.end(); ++p) {
 
104
                        delete *p;
 
105
                }
 
106
 
 
107
                control_protocols.clear ();
 
108
 
 
109
                for (list<ControlProtocolInfo*>::iterator p = control_protocol_info.begin(); p != control_protocol_info.end(); ++p) {
 
110
                        // mark existing protocols as requested
 
111
                        // otherwise the ControlProtocol instances are not recreated in set_session
 
112
                        if ((*p)->protocol) {
 
113
                                (*p)->requested = true;
 
114
                                (*p)->protocol = 0;
 
115
                        }
 
116
                }
 
117
        }
 
118
}
 
119
 
 
120
ControlProtocol*
 
121
ControlProtocolManager::instantiate (ControlProtocolInfo& cpi)
 
122
{
 
123
        /* CALLER MUST HOLD LOCK */
 
124
 
 
125
        if (_session == 0) {
 
126
                return 0;
 
127
        }
 
128
 
 
129
        cpi.descriptor = get_descriptor (cpi.path);
 
130
 
 
131
        DEBUG_TRACE (DEBUG::ControlProtocols, string_compose ("instantiating %1\n", cpi.name));
 
132
 
 
133
        if (cpi.descriptor == 0) {
 
134
                error << string_compose (_("control protocol name \"%1\" has no descriptor"), cpi.name) << endmsg;
 
135
                return 0;
 
136
        }
 
137
 
 
138
        DEBUG_TRACE (DEBUG::ControlProtocols, string_compose ("initializing %1\n", cpi.name));
 
139
 
 
140
        if ((cpi.protocol = cpi.descriptor->initialize (cpi.descriptor, _session)) == 0) {
 
141
                error << string_compose (_("control protocol name \"%1\" could not be initialized"), cpi.name) << endmsg;
 
142
                return 0;
 
143
        }
 
144
 
 
145
        control_protocols.push_back (cpi.protocol);
 
146
 
 
147
        ProtocolStatusChange (&cpi);
 
148
 
 
149
        return cpi.protocol;
 
150
}
 
151
 
 
152
int
 
153
ControlProtocolManager::teardown (ControlProtocolInfo& cpi)
 
154
{
 
155
        if (!cpi.protocol) {
 
156
                return 0;
 
157
        }
 
158
 
 
159
        if (!cpi.descriptor) {
 
160
                return 0;
 
161
        }
 
162
 
 
163
        if (cpi.mandatory) {
 
164
                return 0;
 
165
        }
 
166
 
 
167
        cpi.descriptor->destroy (cpi.descriptor, cpi.protocol);
 
168
 
 
169
        {
 
170
                Glib::Threads::Mutex::Lock lm (protocols_lock);
 
171
                list<ControlProtocol*>::iterator p = find (control_protocols.begin(), control_protocols.end(), cpi.protocol);
 
172
                if (p != control_protocols.end()) {
 
173
                        control_protocols.erase (p);
 
174
                } else {
 
175
                        cerr << "Programming error: ControlProtocolManager::teardown() called for " << cpi.name << ", but it was not found in control_protocols" << endl;
 
176
                }
 
177
        }
 
178
 
 
179
        cpi.protocol = 0;
 
180
        delete cpi.state;
 
181
        cpi.state = 0;
 
182
        dlclose (cpi.descriptor->module);
 
183
 
 
184
        ProtocolStatusChange (&cpi);
 
185
 
 
186
        return 0;
 
187
}
 
188
 
 
189
void
 
190
ControlProtocolManager::load_mandatory_protocols ()
 
191
{
 
192
        if (_session == 0) {
 
193
                return;
 
194
        }
 
195
 
 
196
        Glib::Threads::Mutex::Lock lm (protocols_lock);
 
197
 
 
198
        for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
 
199
                if ((*i)->mandatory && ((*i)->protocol == 0)) {
 
200
                        DEBUG_TRACE (DEBUG::ControlProtocols,
 
201
                                     string_compose (_("Instantiating mandatory control protocol %1"), (*i)->name));
 
202
                        instantiate (**i);
 
203
                }
 
204
        }
 
205
}
 
206
 
 
207
void
 
208
ControlProtocolManager::discover_control_protocols ()
 
209
{
 
210
        vector<std::string> cp_modules;
 
211
 
 
212
        Glib::PatternSpec so_extension_pattern("*.so");
 
213
        Glib::PatternSpec dylib_extension_pattern("*.dylib");
 
214
 
 
215
        find_matching_files_in_search_path (control_protocol_search_path (),
 
216
                                            so_extension_pattern, cp_modules);
 
217
 
 
218
        find_matching_files_in_search_path (control_protocol_search_path (),
 
219
                                            dylib_extension_pattern, cp_modules);
 
220
 
 
221
        DEBUG_TRACE (DEBUG::ControlProtocols, 
 
222
                     string_compose (_("looking for control protocols in %1\n"), control_protocol_search_path().to_string()));
 
223
        
 
224
        for (vector<std::string>::iterator i = cp_modules.begin(); i != cp_modules.end(); ++i) {
 
225
                control_protocol_discover (*i);
 
226
        }
 
227
}
 
228
 
 
229
int
 
230
ControlProtocolManager::control_protocol_discover (string path)
 
231
{
 
232
        ControlProtocolDescriptor* descriptor;
 
233
 
 
234
#ifdef __APPLE__
 
235
        /* don't load OS X shared objects that are just symlinks to the real thing.
 
236
         */
 
237
 
 
238
        if (path.find (".dylib") && Glib::file_test (path, Glib::FILE_TEST_IS_SYMLINK)) {
 
239
                return 0;
 
240
        }
 
241
#endif
 
242
 
 
243
        if ((descriptor = get_descriptor (path)) != 0) {
 
244
 
 
245
                if (!descriptor->probe (descriptor)) {
 
246
                        DEBUG_TRACE (DEBUG::ControlProtocols,
 
247
                                     string_compose (_("Control protocol %1 not usable"), descriptor->name));
 
248
                } else {
 
249
 
 
250
                        ControlProtocolInfo* cpi = new ControlProtocolInfo ();
 
251
 
 
252
                        cpi->descriptor = descriptor;
 
253
                        cpi->name = descriptor->name;
 
254
                        cpi->path = path;
 
255
                        cpi->protocol = 0;
 
256
                        cpi->requested = false;
 
257
                        cpi->mandatory = descriptor->mandatory;
 
258
                        cpi->supports_feedback = descriptor->supports_feedback;
 
259
                        cpi->state = 0;
 
260
 
 
261
                        control_protocol_info.push_back (cpi);
 
262
 
 
263
                        DEBUG_TRACE (DEBUG::ControlProtocols, 
 
264
                                     string_compose(_("Control surface protocol discovered: \"%1\"\n"), cpi->name));
 
265
                }
 
266
 
 
267
                dlclose (descriptor->module);
 
268
        }
 
269
 
 
270
        return 0;
 
271
}
 
272
 
 
273
ControlProtocolDescriptor*
 
274
ControlProtocolManager::get_descriptor (string path)
 
275
{
 
276
        void *module;
 
277
        ControlProtocolDescriptor *descriptor = 0;
 
278
        ControlProtocolDescriptor* (*dfunc)(void);
 
279
        const char *errstr;
 
280
 
 
281
        if ((module = dlopen (path.c_str(), RTLD_NOW)) == 0) {
 
282
                error << string_compose(_("ControlProtocolManager: cannot load module \"%1\" (%2)"), path, dlerror()) << endmsg;
 
283
                return 0;
 
284
        }
 
285
 
 
286
 
 
287
        dfunc = (ControlProtocolDescriptor* (*)(void)) dlsym (module, "protocol_descriptor");
 
288
 
 
289
        if ((errstr = dlerror()) != 0) {
 
290
                error << string_compose(_("ControlProtocolManager: module \"%1\" has no descriptor function."), path) << endmsg;
 
291
                error << errstr << endmsg;
 
292
                dlclose (module);
 
293
                return 0;
 
294
        }
 
295
 
 
296
        descriptor = dfunc();
 
297
        if (descriptor) {
 
298
                descriptor->module = module;
 
299
        } else {
 
300
                dlclose (module);
 
301
        }
 
302
 
 
303
        return descriptor;
 
304
}
 
305
 
 
306
void
 
307
ControlProtocolManager::foreach_known_protocol (boost::function<void(const ControlProtocolInfo*)> method)
 
308
{
 
309
        for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
 
310
                method (*i);
 
311
        }
 
312
}
 
313
 
 
314
ControlProtocolInfo*
 
315
ControlProtocolManager::cpi_by_name (string name)
 
316
{
 
317
        for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
 
318
                if (name == (*i)->name) {
 
319
                        return *i;
 
320
                }
 
321
        }
 
322
        return 0;
 
323
}
 
324
 
 
325
int
 
326
ControlProtocolManager::set_state (const XMLNode& node, int /*version*/)
 
327
{
 
328
        XMLNodeList clist;
 
329
        XMLNodeConstIterator citer;
 
330
        XMLProperty* prop;
 
331
 
 
332
        Glib::Threads::Mutex::Lock lm (protocols_lock);
 
333
 
 
334
        clist = node.children();
 
335
 
 
336
        for (citer = clist.begin(); citer != clist.end(); ++citer) {
 
337
                if ((*citer)->name() == X_("Protocol")) {
 
338
 
 
339
                        if ((prop = (*citer)->property (X_("active"))) == 0) {
 
340
                                continue;
 
341
                        }
 
342
 
 
343
                        bool active = string_is_affirmative (prop->value());
 
344
                        
 
345
                        if ((prop = (*citer)->property (X_("name"))) == 0) {
 
346
                                continue;
 
347
                        }
 
348
 
 
349
                        ControlProtocolInfo* cpi = cpi_by_name (prop->value());
 
350
                        
 
351
                        if (cpi) {
 
352
                                cpi->state = new XMLNode (**citer);
 
353
                                
 
354
                                if (active) {
 
355
                                        if (_session) {
 
356
                                                instantiate (*cpi);
 
357
                                        } else {
 
358
                                                cpi->requested = true;
 
359
                                        }
 
360
                                } else {
 
361
                                        if (_session) {
 
362
                                                teardown (*cpi);
 
363
                                        } else {
 
364
                                                cpi->requested = false;
 
365
                                        }
 
366
                                }
 
367
                        }
 
368
                }
 
369
        }
 
370
 
 
371
        return 0;
 
372
}
 
373
 
 
374
XMLNode&
 
375
ControlProtocolManager::get_state ()
 
376
{
 
377
        XMLNode* root = new XMLNode (state_node_name);
 
378
        Glib::Threads::Mutex::Lock lm (protocols_lock);
 
379
 
 
380
        for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
 
381
 
 
382
                XMLNode * child;
 
383
 
 
384
                if ((*i)->protocol) {
 
385
                        child = &((*i)->protocol->get_state());
 
386
                        child->add_property (X_("active"), "yes");
 
387
                        // should we update (*i)->state here?  probably.
 
388
                        root->add_child_nocopy (*child);
 
389
                } else if ((*i)->state) {
 
390
                        // keep ownership clear
 
391
                        root->add_child_copy (*(*i)->state);
 
392
                } else {
 
393
                        child = new XMLNode (X_("Protocol"));
 
394
                        child->add_property (X_("name"), (*i)->name);
 
395
                        child->add_property (X_("active"), "no");
 
396
                        root->add_child_nocopy (*child);
 
397
                }
 
398
        }
 
399
 
 
400
        return *root;
 
401
}
 
402
 
 
403
 
 
404
ControlProtocolManager&
 
405
ControlProtocolManager::instance ()
 
406
{
 
407
        if (_instance == 0) {
 
408
                _instance = new ControlProtocolManager ();
 
409
        }
 
410
 
 
411
        return *_instance;
 
412
}
 
413
 
 
414
void
 
415
ControlProtocolManager::midi_connectivity_established ()
 
416
{
 
417
        Glib::Threads::Mutex::Lock lm (protocols_lock);
 
418
 
 
419
        for (list<ControlProtocol*>::iterator p = control_protocols.begin(); p != control_protocols.end(); ++p) {
 
420
                (*p)->midi_connectivity_established ();
 
421
        }
 
422
}