remove debug output
[ardour.git] / libs / ardour / port.cc
1 /*
2     Copyright (C) 2009 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 #ifdef WAF_BUILD
21 #include "libardour-config.h"
22 #endif
23
24 #include "pbd/compose.h"
25 #include "pbd/error.h"
26 #include "pbd/failed_constructor.h"
27
28 #include "ardour/audioengine.h"
29 #include "ardour/debug.h"
30 #include "ardour/port.h"
31 #include "ardour/port_engine.h"
32
33 #include "pbd/i18n.h"
34
35 using namespace std;
36 using namespace ARDOUR;
37 using namespace PBD;
38
39 PBD::Signal2<void,boost::shared_ptr<Port>, boost::shared_ptr<Port> > Port::PostDisconnect;
40 PBD::Signal0<void> Port::PortDrop;
41 PBD::Signal0<void> Port::PortSignalDrop;
42
43 bool         Port::_connecting_blocked = false;
44 pframes_t    Port::_global_port_buffer_offset = 0;
45 pframes_t    Port::_cycle_nframes = 0;
46 std::string  Port::state_node_name = X_("Port");
47
48 /* a handy define to shorten what would otherwise be a needlessly verbose
49  * repeated phrase
50  */
51 #define port_engine AudioEngine::instance()->port_engine()
52 #define port_manager AudioEngine::instance()
53
54 /** @param n Port short name */
55 Port::Port (std::string const & n, DataType t, PortFlags f)
56         : _port_buffer_offset (0)
57         , _name (n)
58         , _flags (f)
59         , _last_monitor (false)
60 {
61         _private_playback_latency.min = 0;
62         _private_playback_latency.max = 0;
63         _private_capture_latency.min = 0;
64         _private_capture_latency.max = 0;
65
66         /* Unfortunately we have to pass the DataType into this constructor so that
67            we can create the right kind of port; aside from this we'll use the
68            virtual function type () to establish type.
69         */
70
71         assert (_name.find_first_of (':') == std::string::npos);
72
73         if (!port_engine.available ()) {
74                 DEBUG_TRACE (DEBUG::Ports, string_compose ("port-engine n/a postpone registering %1\n", name()));
75                 _port_handle = 0; // created during ::reestablish() later
76         } else if ((_port_handle = port_engine.register_port (_name, t, _flags)) == 0) {
77                 cerr << "Failed to register port \"" << _name << "\", reason is unknown from here\n";
78                 throw failed_constructor ();
79         }
80         DEBUG_TRACE (DEBUG::Ports, string_compose ("registed port %1 handle %2\n", name(), _port_handle));
81
82         PortDrop.connect_same_thread (drop_connection, boost::bind (&Port::drop, this));
83         PortSignalDrop.connect_same_thread (drop_connection, boost::bind (&Port::signal_drop, this));
84         port_manager->PortConnectedOrDisconnected.connect_same_thread (engine_connection,
85                         boost::bind (&Port::port_connected_or_disconnected, this, _1, _3, _5));
86 }
87
88 /** Port destructor */
89 Port::~Port ()
90 {
91         drop ();
92 }
93
94
95 std::string
96 Port::pretty_name(bool fallback_to_name) const
97 {
98         if (_port_handle) {
99                 std::string value;
100                 std::string type;
101                 if (0 == port_engine.get_port_property (_port_handle,
102                                         "http://jackaudio.org/metadata/pretty-name",
103                                         value, type))
104                 {
105                         return value;
106                 }
107         }
108         if (fallback_to_name) {
109                 return name ();
110         }
111         return "";
112 }
113
114 bool
115 Port::set_pretty_name(const std::string& n)
116 {
117         if (_port_handle) {
118                 if (0 == port_engine.set_port_property (_port_handle,
119                                         "http://jackaudio.org/metadata/pretty-name", n, ""))
120                 {
121                         return true;
122                 }
123         }
124         return false;
125 }
126
127 void
128 Port::signal_drop ()
129 {
130         engine_connection.disconnect ();
131 }
132
133 void
134 Port::drop ()
135 {
136         if (_port_handle) {
137                 DEBUG_TRACE (DEBUG::Ports, string_compose ("drop handle for port %1\n", name()));
138                 port_engine.unregister_port (_port_handle);
139                 _port_handle = 0;
140         }
141 }
142
143 void
144 Port::port_connected_or_disconnected (boost::weak_ptr<Port> w0, boost::weak_ptr<Port> w1, bool con)
145 {
146         if (con) {
147                 /* we're only interested in disconnect */
148                 return;
149         }
150         boost::shared_ptr<Port> p0 = w0.lock ();
151         boost::shared_ptr<Port> p1 = w1.lock ();
152         /* a cheaper, less hacky way to do boost::shared_from_this() ...  */
153         boost::shared_ptr<Port> pself = AudioEngine::instance()->get_port_by_name (name());
154
155         if (p0 == pself) {
156                 PostDisconnect (p0, p1); // emit signal
157         }
158         if (p1 == pself) {
159                 PostDisconnect (p1, p0); // emit signal
160         }
161 }
162
163 /** @return true if this port is connected to anything */
164 bool
165 Port::connected () const
166 {
167         if (_port_handle) {
168                 return (port_engine.connected (_port_handle) != 0);
169         }
170         return false;
171 }
172
173 int
174 Port::disconnect_all ()
175 {
176         if (_port_handle) {
177
178                 std::vector<std::string> connections;
179                 get_connections (connections);
180
181                 port_engine.disconnect_all (_port_handle);
182                 _connections.clear ();
183
184                 /* a cheaper, less hacky way to do boost::shared_from_this() ...
185                  */
186                 boost::shared_ptr<Port> pself = port_manager->get_port_by_name (name());
187                 for (vector<string>::const_iterator c = connections.begin(); c != connections.end() && pself; ++c) {
188                         boost::shared_ptr<Port> pother = AudioEngine::instance()->get_port_by_name (*c);
189                         if (pother) {
190                                 PostDisconnect (pself, pother); // emit signal
191                         }
192                 }
193         }
194
195         return 0;
196 }
197
198 /** @param o Port name
199  * @return true if this port is connected to o, otherwise false.
200  */
201 bool
202 Port::connected_to (std::string const & o) const
203 {
204         if (!_port_handle) {
205                 return false;
206         }
207
208         if (!port_engine.available()) {
209                 return false;
210         }
211
212         return port_engine.connected_to (_port_handle, AudioEngine::instance()->make_port_name_non_relative (o));
213 }
214
215 int
216 Port::get_connections (std::vector<std::string> & c) const
217 {
218         if (!port_engine.available()) {
219                 c.insert (c.end(), _connections.begin(), _connections.end());
220                 return c.size();
221         }
222
223         if (_port_handle) {
224                 return port_engine.get_connections (_port_handle, c);
225         }
226
227         return 0;
228 }
229
230 int
231 Port::connect (std::string const & other)
232 {
233         std::string const other_name = AudioEngine::instance()->make_port_name_non_relative (other);
234         std::string const our_name = AudioEngine::instance()->make_port_name_non_relative (_name);
235
236         int r = 0;
237
238         if (_connecting_blocked) {
239                 return r;
240         }
241
242         if (sends_output ()) {
243                 DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2\n", our_name, other_name));
244                 r = port_engine.connect (our_name, other_name);
245         } else {
246                 DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2\n", other_name, our_name));
247                 r = port_engine.connect (other_name, our_name);
248         }
249
250         if (r == 0) {
251                 _connections.insert (other);
252         }
253
254         return r;
255 }
256
257 int
258 Port::disconnect (std::string const & other)
259 {
260         std::string const other_fullname = port_manager->make_port_name_non_relative (other);
261         std::string const this_fullname = port_manager->make_port_name_non_relative (_name);
262
263         int r = 0;
264
265         if (sends_output ()) {
266                 r = port_engine.disconnect (this_fullname, other_fullname);
267         } else {
268                 r = port_engine.disconnect (other_fullname, this_fullname);
269         }
270
271         if (r == 0) {
272                 _connections.erase (other);
273         }
274
275         /* a cheaper, less hacky way to do boost::shared_from_this() ...  */
276         boost::shared_ptr<Port> pself = AudioEngine::instance()->get_port_by_name (name());
277         boost::shared_ptr<Port> pother = AudioEngine::instance()->get_port_by_name (other);
278
279         if (pself && pother) {
280                 /* Disconnecting from another Ardour port: need to allow
281                    a check on whether this may affect anything that we
282                    need to know about.
283                 */
284                 PostDisconnect (pself, pother); // emit signal
285         }
286
287         return r;
288 }
289
290
291 bool
292 Port::connected_to (Port* o) const
293 {
294         return connected_to (o->name ());
295 }
296
297 int
298 Port::connect (Port* o)
299 {
300         return connect (o->name ());
301 }
302
303 int
304 Port::disconnect (Port* o)
305 {
306         return disconnect (o->name ());
307 }
308
309 void
310 Port::request_input_monitoring (bool yn)
311 {
312         if (_port_handle) {
313                 port_engine.request_input_monitoring (_port_handle, yn);
314         }
315 }
316
317 void
318 Port::ensure_input_monitoring (bool yn)
319 {
320         if (_port_handle) {
321                 port_engine.ensure_input_monitoring (_port_handle, yn);
322         }
323 }
324
325 bool
326 Port::monitoring_input () const
327 {
328         if (_port_handle) {
329                 return port_engine.monitoring_input (_port_handle);
330         }
331         return false;
332 }
333
334 void
335 Port::reset ()
336 {
337         _last_monitor = false;
338 }
339
340 void
341 Port::cycle_start (pframes_t)
342 {
343         _port_buffer_offset = 0;
344 }
345
346 void
347 Port::increment_port_buffer_offset (pframes_t nframes)
348 {
349         _port_buffer_offset += nframes;
350 }
351
352 void
353 Port::set_public_latency_range (LatencyRange& range, bool playback) const
354 {
355         /* this sets the visible latency that the rest of the port system
356            sees. because we do latency compensation, all (most) of our visible
357            port latency values are identical.
358         */
359
360         DEBUG_TRACE (DEBUG::Latency,
361                      string_compose ("SET PORT %1 %4 PUBLIC latency now [%2 - %3]\n",
362                                      name(), range.min, range.max,
363                                      (playback ? "PLAYBACK" : "CAPTURE")));;
364
365         if (_port_handle) {
366                 port_engine.set_latency_range (_port_handle, playback, range);
367         }
368 }
369
370 void
371 Port::set_private_latency_range (LatencyRange& range, bool playback)
372 {
373         if (playback) {
374                 _private_playback_latency = range;
375                 DEBUG_TRACE (DEBUG::Latency, string_compose (
376                                      "SET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
377                                      name(),
378                                      _private_playback_latency.min,
379                                      _private_playback_latency.max));
380         } else {
381                 _private_capture_latency = range;
382                 DEBUG_TRACE (DEBUG::Latency, string_compose (
383                                      "SET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
384                                      name(),
385                                      _private_capture_latency.min,
386                                      _private_capture_latency.max));
387         }
388
389         /* push to public (port system) location so that everyone else can see it */
390
391         set_public_latency_range (range, playback);
392 }
393
394 const LatencyRange&
395 Port::private_latency_range (bool playback) const
396 {
397         if (playback) {
398                 DEBUG_TRACE (DEBUG::Latency, string_compose (
399                                      "GET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
400                                      name(),
401                                      _private_playback_latency.min,
402                                      _private_playback_latency.max));
403                 return _private_playback_latency;
404         } else {
405                 DEBUG_TRACE (DEBUG::Latency, string_compose (
406                                      "GET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
407                                      name(),
408                                      _private_playback_latency.min,
409                                      _private_playback_latency.max));
410                 return _private_capture_latency;
411         }
412 }
413
414 LatencyRange
415 Port::public_latency_range (bool /*playback*/) const
416 {
417         LatencyRange r;
418
419
420         if (_port_handle) {
421                 r = port_engine.get_latency_range (_port_handle, sends_output() ? true : false);
422
423                 DEBUG_TRACE (DEBUG::Latency, string_compose (
424                                      "GET PORT %1: %4 PUBLIC latency range %2 .. %3\n",
425                                      name(), r.min, r.max,
426                                      sends_output() ? "PLAYBACK" : "CAPTURE"));
427         }
428
429         return r;
430 }
431
432 void
433 Port::get_connected_latency_range (LatencyRange& range, bool playback) const
434 {
435         vector<string> connections;
436
437         get_connections (connections);
438
439         if (!connections.empty()) {
440
441                 range.min = ~((pframes_t) 0);
442                 range.max = 0;
443
444                 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: %2 connections to check for latency range\n", name(), connections.size()));
445
446                 for (vector<string>::const_iterator c = connections.begin();
447                      c != connections.end(); ++c) {
448
449                         LatencyRange lr;
450
451                         if (!AudioEngine::instance()->port_is_mine (*c)) {
452
453                                 /* port belongs to some other port-system client, use
454                                  * the port engine to lookup its latency information.
455                                  */
456
457                                 PortEngine::PortHandle remote_port = port_engine.get_port_by_name (*c);
458
459                                 if (remote_port) {
460                                         lr = port_engine.get_latency_range (remote_port, playback);
461
462                                         DEBUG_TRACE (DEBUG::Latency, string_compose (
463                                                              "\t%1 <-> %2 : latter has latency range %3 .. %4\n",
464                                                              name(), *c, lr.min, lr.max));
465
466                                         range.min = min (range.min, lr.min);
467                                         range.max = max (range.max, lr.max);
468                                 }
469
470                         } else {
471
472                                 /* port belongs to this instance of ardour,
473                                    so look up its latency information
474                                    internally, because our published/public
475                                    values already contain our plugin
476                                    latency compensation.
477                                 */
478
479                                 boost::shared_ptr<Port> remote_port = AudioEngine::instance()->get_port_by_name (*c);
480                                 if (remote_port) {
481                                         lr = remote_port->private_latency_range ((playback ? true : false));
482                                         DEBUG_TRACE (DEBUG::Latency, string_compose (
483                                                              "\t%1 <-LOCAL-> %2 : latter has latency range %3 .. %4\n",
484                                                              name(), *c, lr.min, lr.max));
485
486                                         range.min = min (range.min, lr.min);
487                                         range.max = max (range.max, lr.max);
488                                 }
489                         }
490                 }
491
492         } else {
493                 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: not connected to anything\n", name()));
494                 range.min = 0;
495                 range.max = 0;
496         }
497
498         DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: final connected latency range [ %2 .. %3 ] \n", name(), range.min, range.max));
499 }
500
501 int
502 Port::reestablish ()
503 {
504         DEBUG_TRACE (DEBUG::Ports, string_compose ("re-establish %1 port %2\n", type().to_string(), _name));
505         _port_handle = port_engine.register_port (_name, type(), _flags);
506
507         if (_port_handle == 0) {
508                 PBD::error << string_compose (_("could not reregister %1"), _name) << endmsg;
509                 return -1;
510         }
511
512         DEBUG_TRACE (DEBUG::Ports, string_compose ("Port::reestablish %1 handle %2\n", name(), _port_handle));
513
514         reset ();
515
516         port_manager->PortConnectedOrDisconnected.connect_same_thread (engine_connection,
517                         boost::bind (&Port::port_connected_or_disconnected, this, _1, _3, _5));
518         return 0;
519 }
520
521
522 int
523 Port::reconnect ()
524 {
525         /* caller must hold process lock; intended to be used only after reestablish() */
526
527         DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2 destinations\n",name(), _connections.size()));
528
529         for (std::set<string>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
530                 if (connect (*i)) {
531                         return -1;
532                 }
533         }
534
535         return 0;
536 }
537
538 /** @param n Short port name (no port-system client name) */
539 int
540 Port::set_name (std::string const & n)
541 {
542         if (n == _name || !_port_handle) {
543                 return 0;
544         }
545
546         int const r = port_engine.set_port_name (_port_handle, n);
547
548         if (r == 0) {
549                 AudioEngine::instance()->port_renamed (_name, n);
550                 _name = n;
551         }
552
553
554         return r;
555 }
556
557 bool
558 Port::physically_connected () const
559 {
560         if (!_port_handle) {
561                 return false;
562         }
563
564         return port_engine.physically_connected (_port_handle);
565 }
566
567 XMLNode&
568 Port::get_state () const
569 {
570         XMLNode* root = new XMLNode (state_node_name);
571
572         root->set_property (X_("name"), AudioEngine::instance()->make_port_name_relative (name()));
573
574         if (receives_input()) {
575                 root->set_property (X_("direction"), X_("input"));
576         } else {
577                 root->set_property (X_("direction"), X_("output"));
578         }
579
580         vector<string> c;
581
582         get_connections (c);
583
584         for (vector<string>::const_iterator i = c.begin(); i != c.end(); ++i) {
585                 XMLNode* child = new XMLNode (X_("Connection"));
586                 child->set_property (X_("other"), *i);
587                 root->add_child_nocopy (*child);
588         }
589
590         return *root;
591 }
592
593 int
594 Port::set_state (const XMLNode& node, int)
595 {
596         if (node.name() != state_node_name) {
597                 return -1;
598         }
599
600         std::string str;
601         if (node.get_property (X_("name"), str)) {
602                 set_name (str);
603         }
604
605         const XMLNodeList& children (node.children());
606
607         _connections.clear ();
608
609         for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
610
611                 if ((*c)->name() != X_("Connection")) {
612                         continue;
613                 }
614
615                 if (!(*c)->get_property (X_("other"), str)) {
616                         continue;
617                 }
618
619                 _connections.insert (str);
620         }
621
622         return 0;
623 }