more stuff compiles
[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
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.connected()) {
74                 throw failed_constructor ();
75         }
76
77         if ((_port_handle = port_engine.register_port (_name, t, _flags)) == 0) {
78                 cerr << "Failed to register port \"" << _name << "\", reason is unknown from here\n";
79                 throw failed_constructor ();
80         }
81         
82         PortDrop.connect_same_thread (drop_connection, boost::bind (&Port::drop, this));
83 }
84
85 /** Port destructor */
86 Port::~Port ()
87 {
88         drop ();
89 }
90
91 void
92 Port::drop ()
93 {
94         if (_port_handle) {
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.connected()) {
128                 /* in some senses, this answer isn't the right one all the time,
129                    because we know about our connections and will re-establish
130                    them when we reconnect to the port engine.
131                 */
132                 return false;
133         }
134
135         return port_engine.connected_to (_port_handle, AudioEngine::instance()->make_port_name_non_relative (o));
136 }
137
138 int
139 Port::get_connections (std::vector<std::string> & c) const
140 {
141         return port_engine.get_connections (_port_handle, c);
142 }
143
144 int
145 Port::connect (std::string const & other)
146 {
147         std::string const other_name = AudioEngine::instance()->make_port_name_non_relative (other);
148         std::string const our_name = AudioEngine::instance()->make_port_name_non_relative (_name);
149
150         int r = 0;
151
152         if (_connecting_blocked) {
153                 return r;
154         }
155
156         if (sends_output ()) {
157                 port_engine.connect (our_name, other_name);
158         } else {
159                 port_engine.connect (other_name, our_name);
160         }
161
162         if (r == 0) {
163                 _connections.insert (other);
164         }
165
166         return r;
167 }
168
169 int
170 Port::disconnect (std::string const & other)
171 {
172         std::string const other_fullname = port_manager->make_port_name_non_relative (other);
173         std::string const this_fullname = port_manager->make_port_name_non_relative (_name);
174
175         int r = 0;
176
177         if (sends_output ()) {
178                 r = port_engine.disconnect (this_fullname, other_fullname);
179         } else {
180                 r = port_engine.disconnect (other_fullname, this_fullname);
181         }
182
183         if (r == 0) {
184                 _connections.erase (other);
185         }
186
187         /* a cheaper, less hacky way to do boost::shared_from_this() ... 
188          */
189         boost::shared_ptr<Port> pself = AudioEngine::instance()->get_port_by_name (name());
190         boost::shared_ptr<Port> pother = AudioEngine::instance()->get_port_by_name (other);
191
192         if (pself && pother) {
193                 /* Disconnecting from another Ardour port: need to allow
194                    a check on whether this may affect anything that we
195                    need to know about.
196                 */
197                 PostDisconnect (pself, pother); // emit signal 
198         }
199
200         return r;
201 }
202
203
204 bool
205 Port::connected_to (Port* o) const
206 {
207         return connected_to (o->name ());
208 }
209
210 int
211 Port::connect (Port* o)
212 {
213         return connect (o->name ());
214 }
215
216 int
217 Port::disconnect (Port* o)
218 {
219         return disconnect (o->name ());
220 }
221
222 void
223 Port::request_input_monitoring (bool yn)
224 {
225         port_engine.request_input_monitoring (_port_handle, yn);
226 }
227
228 void
229 Port::ensure_input_monitoring (bool yn)
230 {
231         port_engine.ensure_input_monitoring (_port_handle, yn);
232 }
233
234 bool
235 Port::monitoring_input () const
236 {
237         
238         return port_engine.monitoring_input (_port_handle);
239 }
240
241 void
242 Port::reset ()
243 {
244         _last_monitor = false;
245 }
246
247 void
248 Port::cycle_start (pframes_t)
249 {
250         _port_buffer_offset = 0;
251 }
252
253 void
254 Port::increment_port_buffer_offset (pframes_t nframes)
255 {
256         _port_buffer_offset += nframes;
257 }
258
259 void
260 Port::set_public_latency_range (LatencyRange& range, bool playback) const
261 {
262         /* this sets the visible latency that the rest of the port system
263            sees. because we do latency compensation, all (most) of our visible
264            port latency values are identical.
265         */
266
267         DEBUG_TRACE (DEBUG::Latency,
268                      string_compose ("SET PORT %1 %4 PUBLIC latency now [%2 - %3]\n",
269                                      name(), range.min, range.max,
270                                      (playback ? "PLAYBACK" : "CAPTURE")));;
271
272         port_engine.set_latency_range (_port_handle, playback, range);
273 }
274
275 void
276 Port::set_private_latency_range (LatencyRange& range, bool playback)
277 {
278         if (playback) {
279                 _private_playback_latency = range;
280                 DEBUG_TRACE (DEBUG::Latency, string_compose (
281                                      "SET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
282                                      name(),
283                                      _private_playback_latency.min,
284                                      _private_playback_latency.max));
285         } else {
286                 _private_capture_latency = range;
287                 DEBUG_TRACE (DEBUG::Latency, string_compose (
288                                      "SET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
289                                      name(),
290                                      _private_capture_latency.min,
291                                      _private_capture_latency.max));
292         }
293
294         /* push to public (port system) location so that everyone else can see it */
295
296         set_public_latency_range (range, playback);
297 }
298
299 const LatencyRange&
300 Port::private_latency_range (bool playback) const
301 {
302         if (playback) {
303                 DEBUG_TRACE (DEBUG::Latency, string_compose (
304                                      "GET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
305                                      name(),
306                                      _private_playback_latency.min,
307                                      _private_playback_latency.max));
308                 return _private_playback_latency;
309         } else {
310                 DEBUG_TRACE (DEBUG::Latency, string_compose (
311                                      "GET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
312                                      name(),
313                                      _private_playback_latency.min,
314                                      _private_playback_latency.max));
315                 return _private_capture_latency;
316         }
317 }
318
319 LatencyRange
320 Port::public_latency_range (bool /*playback*/) const
321 {
322         LatencyRange r;
323
324         r = port_engine.get_latency_range (_port_handle, sends_output() ? true : false);
325
326         DEBUG_TRACE (DEBUG::Latency, string_compose (
327                              "GET PORT %1: %4 PUBLIC latency range %2 .. %3\n",
328                              name(), r.min, r.max,
329                              sends_output() ? "PLAYBACK" : "CAPTURE"));
330         return r;
331 }
332
333 void
334 Port::get_connected_latency_range (LatencyRange& range, bool playback) const
335 {
336         vector<string> connections;
337
338         get_connections (connections);
339
340         if (!connections.empty()) {
341
342                 range.min = ~((jack_nframes_t) 0);
343                 range.max = 0;
344
345                 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: %2 connections to check for latency range\n", name(), connections.size()));
346
347                 for (vector<string>::const_iterator c = connections.begin();
348                      c != connections.end(); ++c) {
349
350                         LatencyRange lr;
351
352                         if (!AudioEngine::instance()->port_is_mine (*c)) {
353
354                                 /* port belongs to some other port-system client, use
355                                  * the port engine to lookup its latency information.
356                                  */
357
358                                 PortEngine::PortHandle remote_port = port_engine.get_port_by_name (*c);
359
360                                 if (remote_port) {
361                                         lr = port_engine.get_latency_range (remote_port, playback);
362
363                                         DEBUG_TRACE (DEBUG::Latency, string_compose (
364                                                              "\t%1 <-> %2 : latter has latency range %3 .. %4\n",
365                                                              name(), *c, lr.min, lr.max));
366
367                                         range.min = min (range.min, lr.min);
368                                         range.max = max (range.max, lr.max);
369                                 }
370
371                         } else {
372
373                                 /* port belongs to this instance of ardour,
374                                    so look up its latency information
375                                    internally, because our published/public
376                                    values already contain our plugin
377                                    latency compensation.
378                                 */
379
380                                 boost::shared_ptr<Port> remote_port = AudioEngine::instance()->get_port_by_name (*c);
381                                 if (remote_port) {
382                                         lr = remote_port->private_latency_range ((playback ? JackPlaybackLatency : JackCaptureLatency));
383                                         DEBUG_TRACE (DEBUG::Latency, string_compose (
384                                                              "\t%1 <-LOCAL-> %2 : latter has latency range %3 .. %4\n",
385                                                              name(), *c, lr.min, lr.max));
386
387                                         range.min = min (range.min, lr.min);
388                                         range.max = max (range.max, lr.max);
389                                 }
390                         }
391                 }
392
393         } else {
394                 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: not connected to anything\n", name()));
395                 range.min = 0;
396                 range.max = 0;
397         }
398
399         DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: final connected latency range [ %2 .. %3 ] \n", name(), range.min, range.max));
400 }
401
402 int
403 Port::reestablish ()
404 {
405         _port_handle = port_engine.register_port (_name, type(), _flags);
406
407         if (_port_handle == 0) {
408                 PBD::error << string_compose (_("could not reregister %1"), _name) << endmsg;
409                 return -1;
410         }
411
412         reset ();
413
414         return 0;
415 }
416
417
418 int
419 Port::reconnect ()
420 {
421         /* caller must hold process lock; intended to be used only after reestablish() */
422
423         for (std::set<string>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
424                 if (connect (*i)) {
425                         return -1;
426                 }
427         }
428
429         return 0;
430 }
431
432 /** @param n Short port name (no port-system client name) */
433 int
434 Port::set_name (std::string const & n)
435 {
436         if (n == _name) {
437                 return 0;
438         }
439
440         int const r = port_engine.set_port_name (_port_handle, n);
441
442         if (r == 0) {
443                 AudioEngine::instance()->port_renamed (_name, n);
444                 _name = n;
445         }
446
447
448         return r;
449 }
450
451 bool
452 Port::physically_connected () const
453 {
454         return port_engine.physically_connected (_port_handle);
455 }
456