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