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