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