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