properly use and publish private/public port latency values for JACK latency API
[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 <stdexcept>
25
26 #include <jack/weakjack.h> // so that we can test for new functions at runtime
27
28 #include "pbd/error.h"
29 #include "pbd/compose.h"
30
31 #include "ardour/debug.h"
32 #include "ardour/port.h"
33 #include "ardour/audioengine.h"
34 #include "pbd/failed_constructor.h"
35
36 #include "i18n.h"
37
38 using namespace std;
39 using namespace ARDOUR;
40 using namespace PBD;
41
42 AudioEngine* Port::_engine = 0;
43 bool Port::_connecting_blocked = false;
44 pframes_t Port::_global_port_buffer_offset = 0;
45 pframes_t Port::_cycle_nframes = 0;
46
47 /** @param n Port short name */
48 Port::Port (std::string const & n, DataType t, Flags f)
49         : _port_buffer_offset (0)
50         , _name (n)
51         , _flags (f)
52         , _last_monitor (false)
53 {
54
55         /* Unfortunately we have to pass the DataType into this constructor so that we can
56            create the right kind of JACK port; aside from this we'll use the virtual function type ()
57            to establish type.
58         */
59
60         assert (_name.find_first_of (':') == std::string::npos);
61
62         if (!_engine->connected()) {
63                 throw failed_constructor ();
64         }
65
66         if ((_jack_port = jack_port_register (_engine->jack (), _name.c_str (), t.to_jack_type (), _flags, 0)) == 0) {
67                 cerr << "Failed to register JACK port, reason is unknown from here\n";
68                 throw failed_constructor ();
69         }
70 }
71
72 /** Port destructor */
73 Port::~Port ()
74 {
75         if (_engine->jack ()) {
76                 jack_port_unregister (_engine->jack (), _jack_port);
77         }
78 }
79
80 /** @return true if this port is connected to anything */
81 bool
82 Port::connected () const
83 {
84         return (jack_port_connected (_jack_port) != 0);
85 }
86
87 int
88 Port::disconnect_all ()
89 {
90         jack_port_disconnect (_engine->jack(), _jack_port);
91         _connections.clear ();
92
93         return 0;
94 }
95
96 /** @param o Port name
97  * @return true if this port is connected to o, otherwise false.
98  */
99 bool
100 Port::connected_to (std::string const & o) const
101 {
102         if (!_engine->connected()) {
103                 /* in some senses, this answer isn't the right one all the time, 
104                    because we know about our connections and will re-establish
105                    them when we reconnect to JACK.
106                 */
107                 return false;
108         }
109
110         return jack_port_connected_to (_jack_port, _engine->make_port_name_non_relative(o).c_str ());
111 }
112
113 /** @param o Filled in with port full names of ports that we are connected to */
114 int
115 Port::get_connections (std::vector<std::string> & c) const
116 {
117         int n = 0;
118
119         if (_engine->connected()) {
120                 const char** jc = jack_port_get_connections (_jack_port);
121                 if (jc) {
122                         for (int i = 0; jc[i]; ++i) {
123                                 c.push_back (jc[i]);
124                                 ++n;
125                         }
126                         
127                         jack_free (jc);
128                 }
129         }
130
131         return n;
132 }
133
134 int
135 Port::connect (std::string const & other)
136 {
137         std::string const other_shrt = _engine->make_port_name_non_relative (other);
138         std::string const this_shrt = _engine->make_port_name_non_relative (_name);
139
140         int r = 0;
141
142         if (_connecting_blocked) {
143                 return r;
144         }
145
146         if (sends_output ()) {
147                 r = jack_connect (_engine->jack (), this_shrt.c_str (), other_shrt.c_str ());
148         } else {
149                 r = jack_connect (_engine->jack (), other_shrt.c_str (), this_shrt.c_str());
150         }
151
152         if (r == 0) {
153                 _connections.insert (other);
154         }
155
156         return r;
157 }
158
159 int
160 Port::disconnect (std::string const & other)
161 {
162         std::string const other_shrt = _engine->make_port_name_non_relative (other);
163         std::string const this_shrt = _engine->make_port_name_non_relative (_name);
164
165         int r = 0;
166
167         if (sends_output ()) {
168                 r = jack_disconnect (_engine->jack (), this_shrt.c_str (), other_shrt.c_str ());
169         } else {
170                 r = jack_disconnect (_engine->jack (), other_shrt.c_str (), this_shrt.c_str ());
171         }
172
173         if (r == 0) {
174                 _connections.erase (other);
175         }
176
177         return r;
178 }
179
180
181 bool
182 Port::connected_to (Port* o) const
183 {
184         return connected_to (o->name ());
185 }
186
187 int
188 Port::connect (Port* o)
189 {
190         return connect (o->name ());
191 }
192
193 int
194 Port::disconnect (Port* o)
195 {
196         return disconnect (o->name ());
197 }
198
199 void
200 Port::set_engine (AudioEngine* e)
201 {
202         _engine = e;
203 }
204
205 void
206 Port::ensure_monitor_input (bool yn)
207 {
208         jack_port_ensure_monitor (_jack_port, yn);
209 }
210
211 bool
212 Port::monitoring_input () const
213 {
214         return jack_port_monitoring_input (_jack_port);
215 }
216
217 void
218 Port::reset ()
219 {
220         _last_monitor = false;
221 }
222
223 void
224 Port::cycle_start (pframes_t nframes)
225 {
226         _port_buffer_offset = 0;
227 }
228
229 void
230 Port::increment_port_buffer_offset (pframes_t nframes)
231 {
232         _port_buffer_offset += nframes;
233 }
234         
235 void
236 Port::set_public_latency_range (jack_latency_range_t& range, bool playback) const
237 {
238         /* this sets the visible latency that the rest of JACK sees. because we do latency
239            compensation, all (most) of our visible port latency values are identical.
240         */
241
242         if (!jack_port_set_latency_range) {
243                 return;
244         }
245
246         DEBUG_TRACE (DEBUG::Latency, string_compose ("PORT %1 %4 latency now [%2 - %3]\n", name(), 
247                                                      range.min, 
248                                                      range.max,
249                                                      (playback ? "PLAYBACK" : "CAPTURE")));;
250
251         jack_port_set_latency_range (_jack_port, (playback ? JackPlaybackLatency : JackCaptureLatency), &range);
252 }
253
254 void
255 Port::set_private_latency_range (jack_latency_range_t& range, bool playback)
256 {
257         if (playback) {
258                 _private_playback_latency = range;
259                 DEBUG_TRACE (DEBUG::Latency, string_compose ("PORT %1 playback latency now [%2 - %3]\n", name(), 
260                                                              _private_playback_latency.min, 
261                                                              _private_playback_latency.max));
262         } else {
263                 _private_capture_latency = range;
264                 DEBUG_TRACE (DEBUG::Latency, string_compose ("PORT %1 capture latency now [%2 - %3]\n", name(), 
265                                                              _private_playback_latency.min, 
266                                                              _private_playback_latency.max));
267         }
268
269         /* push to public (JACK) location so that everyone else can see it */
270
271         set_public_latency_range (range, playback);
272 }
273
274 const jack_latency_range_t&
275 Port::private_latency_range (bool playback) const
276 {
277         if (playback) {
278                 return _private_playback_latency;
279         } else {
280                 return _private_capture_latency;
281         }
282 }
283
284 jack_latency_range_t
285 Port::public_latency_range (bool playback) const
286 {
287         jack_latency_range_t r;
288
289         jack_port_get_latency_range (_jack_port, 
290                                      sends_output() ? JackPlaybackLatency : JackCaptureLatency,
291                                      &r);
292         DEBUG_TRACE (DEBUG::Latency, string_compose ("PORT %1: %4 public latency range %2 .. %3\n", 
293                                                      name(), r.min, r.max,
294                                                      sends_output() ? "PLAYBACK" : "CAPTURE"));
295         return r;
296 }
297
298 void
299 Port::get_connected_latency_range (jack_latency_range_t& range, bool playback) const
300 {
301         if (!jack_port_get_latency_range) {
302                 return;
303         }
304
305         vector<string> connections;
306         jack_client_t* jack = _engine->jack();
307         
308         if (!jack) {
309                 range.min = 0;
310                 range.max = 0;
311                 PBD::warning << _("get_connected_latency_range() called while disconnected from JACK") << endmsg;
312                 return;
313         }
314
315         get_connections (connections);
316
317         if (!connections.empty()) {
318                 
319                 range.min = ~((jack_nframes_t) 0);
320                 range.max = 0;
321
322                 for (vector<string>::iterator c = connections.begin(); c != connections.end(); ++c) {
323                         jack_port_t* remote_port = jack_port_by_name (_engine->jack(), (*c).c_str());
324                         jack_latency_range_t lr;
325
326                         if (remote_port) {
327                                 jack_port_get_latency_range (remote_port, (playback ? JackPlaybackLatency : JackCaptureLatency), &lr);
328                                 DEBUG_TRACE (DEBUG::Latency, string_compose ("\t\%1 has latency range %2 .. %3\n", *c, lr.min, lr.max));
329                                 range.min = min (range.min, lr.min);
330                                 range.max = max (range.max, lr.max);
331                         }
332                 }
333
334         } else {
335
336                 range.min = 0;
337                 range.max = 0;
338         }
339 }
340
341 int
342 Port::reestablish ()
343 {
344         jack_client_t* jack = _engine->jack();
345
346         if (!jack) {
347                 return -1;
348         }
349
350         _jack_port = jack_port_register (jack, _name.c_str(), type().to_jack_type(), _flags, 0);
351
352         if (_jack_port == 0) {
353                 PBD::error << string_compose (_("could not reregister %1"), _name) << endmsg;
354                 return -1;
355         }
356
357         reset ();
358
359         return 0;
360 }
361
362
363 int
364 Port::reconnect ()
365 {
366         /* caller must hold process lock; intended to be used only after reestablish() */
367
368         for (std::set<string>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
369                 if (connect (*i)) {
370                         return -1;
371                 }
372         }
373
374         return 0;
375 }
376
377 /** @param n Short port name (no JACK client name) */
378 int
379 Port::set_name (std::string const & n)
380 {
381         if (n == _name) {
382                 return 0;
383         }
384
385         int const r = jack_port_set_name (_jack_port, n.c_str());
386
387         if (r == 0) {
388                 _name = n;
389         }
390
391         return r;
392 }
393
394 void
395 Port::request_monitor_input (bool yn)
396 {
397         jack_port_request_monitor (_jack_port, yn);
398 }
399
400 bool
401 Port::physically_connected () const
402 {
403         const char** jc = jack_port_get_connections (_jack_port);
404
405         if (jc) {
406                 for (int i = 0; jc[i]; ++i) {
407
408                         jack_port_t* port = jack_port_by_name (_engine->jack(), jc[i]);
409                         
410                         if (port && (jack_port_flags (port) & JackPortIsPhysical)) {
411                                 jack_free (jc);
412                                 return true;
413                         }
414                 }
415                 
416                 jack_free (jc);
417         }
418
419         return false;
420 }
421