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