remove compile errors (still will not link and JACKPortEngine is not close to done)
[ardour.git] / libs / ardour / port_manager.cc
1 /*
2     Copyright (C) 2013 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
21 #include "ardour/port_manager.h"
22
23 using namespace ARDOUR;
24
25 PortManager::PortManager ()
26         , ports (new Ports)
27 {
28 }
29
30 void
31 AudioEngine::remove_all_ports ()
32 {
33         /* make sure that JACK callbacks that will be invoked as we cleanup
34          * ports know that they have nothing to do.
35          */
36
37         port_remove_in_progress = true;
38
39         /* process lock MUST be held by caller
40         */
41
42         {
43                 RCUWriter<Ports> writer (ports);
44                 boost::shared_ptr<Ports> ps = writer.get_copy ();
45                 ps->clear ();
46         }
47
48         /* clear dead wood list in RCU */
49
50         ports.flush ();
51
52         port_remove_in_progress = false;
53 }
54
55
56 string
57 AudioEngine::make_port_name_relative (const string& portname) const
58 {
59         string::size_type len;
60         string::size_type n;
61
62         len = portname.length();
63
64         for (n = 0; n < len; ++n) {
65                 if (portname[n] == ':') {
66                         break;
67                 }
68         }
69
70         if ((n != len) && (portname.substr (0, n) == jack_client_name)) {
71                 return portname.substr (n+1);
72         }
73
74         return portname;
75 }
76
77 string
78 AudioEngine::make_port_name_non_relative (const string& portname) const
79 {
80         string str;
81
82         if (portname.find_first_of (':') != string::npos) {
83                 return portname;
84         }
85
86         str  = jack_client_name;
87         str += ':';
88         str += portname;
89
90         return str;
91 }
92
93 bool
94 AudioEngine::port_is_mine (const string& portname) const
95 {
96         if (portname.find_first_of (':') != string::npos) {
97                 if (portname.substr (0, jack_client_name.length ()) != jack_client_name) {
98                         return false;
99                 }
100         }
101         return true;
102 }
103
104 bool
105 AudioEngine::port_is_physical (const std::string& portname) const
106 {
107         GET_PRIVATE_JACK_POINTER_RET(_jack, false);
108
109         jack_port_t *port = jack_port_by_name (_priv_jack, portname.c_str());
110
111         if (!port) {
112                 return false;
113         }
114
115         return jack_port_flags (port) & JackPortIsPhysical;
116 }
117
118 ChanCount
119 AudioEngine::n_physical (unsigned long flags) const
120 {
121         ChanCount c;
122
123         GET_PRIVATE_JACK_POINTER_RET (_jack, c);
124
125         const char ** ports = jack_get_ports (_priv_jack, NULL, NULL, JackPortIsPhysical | flags);
126         if (ports == 0) {
127                 return c;
128         }
129
130         for (uint32_t i = 0; ports[i]; ++i) {
131                 if (!strstr (ports[i], "Midi-Through")) {
132                         DataType t (jack_port_type (jack_port_by_name (_jack, ports[i])));
133                         c.set (t, c.get (t) + 1);
134                 }
135         }
136
137         free (ports);
138
139         return c;
140 }
141
142 ChanCount
143 AudioEngine::n_physical_inputs () const
144 {
145         return n_physical (JackPortIsInput);
146 }
147
148 ChanCount
149 AudioEngine::n_physical_outputs () const
150 {
151         return n_physical (JackPortIsOutput);
152 }
153
154 void
155 AudioEngine::get_physical (DataType type, unsigned long flags, vector<string>& phy)
156 {
157         GET_PRIVATE_JACK_POINTER (_jack);
158         const char ** ports;
159
160         if ((ports = jack_get_ports (_priv_jack, NULL, type.to_jack_type(), JackPortIsPhysical | flags)) == 0) {
161                 return;
162         }
163
164         if (ports) {
165                 for (uint32_t i = 0; ports[i]; ++i) {
166                         if (strstr (ports[i], "Midi-Through")) {
167                                 continue;
168                         }
169                         phy.push_back (ports[i]);
170                 }
171                 free (ports);
172         }
173 }
174
175 /** Get physical ports for which JackPortIsOutput is set; ie those that correspond to
176  *  a physical input connector.
177  */
178 void
179 AudioEngine::get_physical_inputs (DataType type, vector<string>& ins)
180 {
181         get_physical (type, JackPortIsOutput, ins);
182 }
183
184 /** Get physical ports for which JackPortIsInput is set; ie those that correspond to
185  *  a physical output connector.
186  */
187 void
188 AudioEngine::get_physical_outputs (DataType type, vector<string>& outs)
189 {
190         get_physical (type, JackPortIsInput, outs);
191 }
192
193
194 bool
195 AudioEngine::can_request_hardware_monitoring ()
196 {
197         GET_PRIVATE_JACK_POINTER_RET (_jack,false);
198         const char ** ports;
199
200         if ((ports = jack_get_ports (_priv_jack, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortCanMonitor)) == 0) {
201                 return false;
202         }
203
204         free (ports);
205
206         return true;
207 }
208
209
210 /** @param name Full or short name of port
211  *  @return Corresponding Port or 0.
212  */
213
214 boost::shared_ptr<Port>
215 AudioEngine::get_port_by_name (const string& portname)
216 {
217         if (!_running) {
218                 if (!_has_run) {
219                         fatal << _("get_port_by_name() called before engine was started") << endmsg;
220                         /*NOTREACHED*/
221                 } else {
222                         boost::shared_ptr<Port> ();
223                 }
224         }
225
226         if (!port_is_mine (portname)) {
227                 /* not an ardour port */
228                 return boost::shared_ptr<Port> ();
229         }
230
231         boost::shared_ptr<Ports> pr = ports.reader();
232         std::string rel = make_port_name_relative (portname);
233         Ports::iterator x = pr->find (rel);
234
235         if (x != pr->end()) {
236                 /* its possible that the port was renamed by some 3rd party and
237                    we don't know about it. check for this (the check is quick
238                    and cheap), and if so, rename the port (which will alter
239                    the port map as a side effect).
240                 */
241                 const std::string check = make_port_name_relative (jack_port_name (x->second->jack_port()));
242                 if (check != rel) {
243                         x->second->set_name (check);
244                 }
245                 return x->second;
246         }
247
248         return boost::shared_ptr<Port> ();
249 }
250
251 void
252 AudioEngine::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
253 {
254         RCUWriter<Ports> writer (ports);
255         boost::shared_ptr<Ports> p = writer.get_copy();
256         Ports::iterator x = p->find (old_relative_name);
257         
258         if (x != p->end()) {
259                 boost::shared_ptr<Port> port = x->second;
260                 p->erase (x);
261                 p->insert (make_pair (new_relative_name, port));
262         }
263 }
264
265 const char **
266 AudioEngine::get_ports (const string& port_name_pattern, DataType type, uint32_t flags)
267 {
268         GET_PRIVATE_JACK_POINTER_RET (_jack,0);
269         if (!_running) {
270                 if (!_has_run) {
271                         fatal << _("get_ports called before engine was started") << endmsg;
272                         /*NOTREACHED*/
273                 } else {
274                         return 0;
275                 }
276         }
277
278         const char* jack_type_string;
279
280         switch (type) {
281         case DataType::AUDIO:
282                 jack_type_string = JACK_DEFAULT_AUDIO_TYPE;
283                 break;
284         case DataType::AUDIO:
285                 jack_type_string = JACK_DEFAULT_MIDI_TYPE;
286                 break;
287         case DataType::NIL
288                 return 0;
289         }
290
291         return jack_get_ports (_priv_jack, port_name_pattern.c_str(), jack_type_string, flags);
292 }
293
294 void
295 AudioEngine::port_registration_failure (const std::string& portname)
296 {
297         GET_PRIVATE_JACK_POINTER (_jack);
298         string full_portname = jack_client_name;
299         full_portname += ':';
300         full_portname += portname;
301
302
303         jack_port_t* p = jack_port_by_name (_priv_jack, full_portname.c_str());
304         string reason;
305
306         if (p) {
307                 reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname);
308         } else {
309                 reason = string_compose (_("No more JACK ports are available. You will need to stop %1 and restart JACK with more ports if you need this many tracks."), PROGRAM_NAME);
310         }
311
312         throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
313 }
314
315 boost::shared_ptr<Port>
316 AudioEngine::register_port (DataType dtype, const string& portname, bool input)
317 {
318         boost::shared_ptr<Port> newport;
319
320         try {
321                 if (dtype == DataType::AUDIO) {
322                         newport.reset (new AudioPort (portname, (input ? Port::IsInput : Port::IsOutput)));
323                 } else if (dtype == DataType::MIDI) {
324                         newport.reset (new MidiPort (portname, (input ? Port::IsInput : Port::IsOutput)));
325                 } else {
326                         throw PortRegistrationFailure("unable to create port (unknown type)");
327                 }
328
329                 RCUWriter<Ports> writer (ports);
330                 boost::shared_ptr<Ports> ps = writer.get_copy ();
331                 ps->insert (make_pair (make_port_name_relative (portname), newport));
332
333                 /* writer goes out of scope, forces update */
334
335                 return newport;
336         }
337
338         catch (PortRegistrationFailure& err) {
339                 throw err;
340         } catch (std::exception& e) {
341                 throw PortRegistrationFailure(string_compose(
342                                 _("unable to create port: %1"), e.what()).c_str());
343         } catch (...) {
344                 throw PortRegistrationFailure("unable to create port (unknown error)");
345         }
346 }
347
348 boost::shared_ptr<Port>
349 AudioEngine::register_input_port (DataType type, const string& portname)
350 {
351         return register_port (type, portname, true);
352 }
353
354 boost::shared_ptr<Port>
355 AudioEngine::register_output_port (DataType type, const string& portname)
356 {
357         return register_port (type, portname, false);
358 }
359
360 int
361 AudioEngine::unregister_port (boost::shared_ptr<Port> port)
362 {
363         /* caller must hold process lock */
364
365         if (!_running) {
366                 /* probably happening when the engine has been halted by JACK,
367                    in which case, there is nothing we can do here.
368                    */
369                 return 0;
370         }
371
372         {
373                 RCUWriter<Ports> writer (ports);
374                 boost::shared_ptr<Ports> ps = writer.get_copy ();
375                 Ports::iterator x = ps->find (make_port_name_relative (port->name()));
376
377                 if (x != ps->end()) {
378                         ps->erase (x);
379                 }
380
381                 /* writer goes out of scope, forces update */
382         }
383
384         ports.flush ();
385
386         return 0;
387 }
388
389 bool
390 PortManager::connected (const string& port_name)
391 {
392         PortEngine::PortHandle handle = _impl->get_port_by_name (port_name);
393
394         if (!handle) {
395                 return false;
396         }
397
398         return _impl->connected (handle);
399 }
400
401 int
402 AudioEngine::connect (const string& source, const string& destination)
403 {
404         int ret;
405
406         if (!_running) {
407                 if (!_has_run) {
408                         fatal << _("connect called before engine was started") << endmsg;
409                         /*NOTREACHED*/
410                 } else {
411                         return -1;
412                 }
413         }
414
415         string s = make_port_name_non_relative (source);
416         string d = make_port_name_non_relative (destination);
417
418
419         boost::shared_ptr<Port> src = get_port_by_name (s);
420         boost::shared_ptr<Port> dst = get_port_by_name (d);
421
422         if (src) {
423                 ret = src->connect (d);
424         } else if (dst) {
425                 ret = dst->connect (s);
426         } else {
427                 /* neither port is known to us, and this API isn't intended for use as a general patch bay */
428                 ret = -1;
429         }
430
431         if (ret > 0) {
432                 /* already exists - no error, no warning */
433         } else if (ret < 0) {
434                 error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
435                                         source, s, destination, d)
436                       << endmsg;
437         }
438
439         return ret;
440 }
441
442 int
443 AudioEngine::disconnect (const string& source, const string& destination)
444 {
445         int ret;
446
447         if (!_running) {
448                 if (!_has_run) {
449                         fatal << _("disconnect called before engine was started") << endmsg;
450                         /*NOTREACHED*/
451                 } else {
452                         return -1;
453                 }
454         }
455
456         string s = make_port_name_non_relative (source);
457         string d = make_port_name_non_relative (destination);
458
459         boost::shared_ptr<Port> src = get_port_by_name (s);
460         boost::shared_ptr<Port> dst = get_port_by_name (d);
461
462         if (src) {
463                         ret = src->disconnect (d);
464         } else if (dst) {
465                         ret = dst->disconnect (s);
466         } else {
467                 /* neither port is known to us, and this API isn't intended for use as a general patch bay */
468                 ret = -1;
469         }
470         return ret;
471 }
472
473 int
474 AudioEngine::disconnect (boost::shared_ptr<Port> port)
475 {
476         GET_PRIVATE_JACK_POINTER_RET (_jack,-1);
477
478         if (!_running) {
479                 if (!_has_run) {
480                         fatal << _("disconnect called before engine was started") << endmsg;
481                         /*NOTREACHED*/
482                 } else {
483                         return -1;
484                 }
485         }
486
487         return port->disconnect_all ();
488 }
489
490 int
491 PortManager::reestablish_ports ()
492 {
493         Ports::iterator i;
494
495         boost::shared_ptr<Ports> p = ports.reader ();
496
497         for (i = p->begin(); i != p->end(); ++i) {
498                 if (i->second->reestablish ()) {
499                         break;
500                 }
501         }
502
503         if (i != p->end()) {
504                 /* failed */
505                 remove_all_ports ();
506                 return -1;
507         }
508
509         MIDI::Manager::instance()->reestablish ();
510
511         return 0;
512 }
513
514 int
515 PortManager::reconnect_ports ()
516 {
517         boost::shared_ptr<Ports> p = ports.reader ();
518
519         /* re-establish connections */
520         
521         for (i = p->begin(); i != p->end(); ++i) {
522                 i->second->reconnect ();
523         }
524
525         MIDI::Manager::instance()->reconnect ();
526
527         return 0;
528 }