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