sorta-kinda working latency compensation, latency reporting and capture alignment...
[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
270 const jack_latency_range_t&
271 Port::private_latency_range (bool playback) const
272 {
273         if (playback) {
274                 return _private_playback_latency;
275         } else {
276                 return _private_capture_latency;
277         }
278 }
279
280 jack_latency_range_t
281 Port::public_latency_range (bool playback) const
282 {
283         jack_latency_range_t r;
284
285         jack_port_get_latency_range (_jack_port, 
286                                      sends_output() ? JackPlaybackLatency : JackCaptureLatency,
287                                      &r);
288         DEBUG_TRACE (DEBUG::Latency, string_compose ("PORT %1: %4 public latency range %2 .. %3\n", 
289                                                      name(), r.min, r.max,
290                                                      sends_output() ? "PLAYBACK" : "CAPTURE"));
291         return r;
292 }
293
294 void
295 Port::get_connected_latency_range (jack_latency_range_t& range, bool playback) const
296 {
297         if (!jack_port_get_latency_range) {
298                 return;
299         }
300
301         vector<string> connections;
302         jack_client_t* jack = _engine->jack();
303         
304         if (!jack) {
305                 range.min = 0;
306                 range.max = 0;
307                 PBD::warning << _("get_connected_latency_range() called while disconnected from JACK") << endmsg;
308                 return;
309         }
310
311         get_connections (connections);
312
313         if (!connections.empty()) {
314                 
315                 range.min = ~((jack_nframes_t) 0);
316                 range.max = 0;
317
318                 for (vector<string>::iterator c = connections.begin(); c != connections.end(); ++c) {
319                         jack_port_t* remote_port = jack_port_by_name (_engine->jack(), (*c).c_str());
320                         jack_latency_range_t lr;
321
322                         if (remote_port) {
323                                 jack_port_get_latency_range (remote_port, (playback ? JackPlaybackLatency : JackCaptureLatency), &lr);
324                                 DEBUG_TRACE (DEBUG::Latency, string_compose ("\t\%1 has latency range %2 .. %3\n", *c, lr.min, lr.max));
325                                 range.min = min (range.min, lr.min);
326                                 range.max = max (range.max, lr.max);
327                         }
328                 }
329
330         } else {
331
332                 range.min = 0;
333                 range.max = 0;
334         }
335 }
336
337 int
338 Port::reestablish ()
339 {
340         jack_client_t* jack = _engine->jack();
341
342         if (!jack) {
343                 return -1;
344         }
345
346         _jack_port = jack_port_register (jack, _name.c_str(), type().to_jack_type(), _flags, 0);
347
348         if (_jack_port == 0) {
349                 PBD::error << string_compose (_("could not reregister %1"), _name) << endmsg;
350                 return -1;
351         }
352
353         reset ();
354
355         return 0;
356 }
357
358
359 int
360 Port::reconnect ()
361 {
362         /* caller must hold process lock; intended to be used only after reestablish() */
363
364         for (std::set<string>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
365                 if (connect (*i)) {
366                         return -1;
367                 }
368         }
369
370         return 0;
371 }
372
373 /** @param n Short port name (no JACK client name) */
374 int
375 Port::set_name (std::string const & n)
376 {
377         if (n == _name) {
378                 return 0;
379         }
380
381         int const r = jack_port_set_name (_jack_port, n.c_str());
382
383         if (r == 0) {
384                 _name = n;
385         }
386
387         return r;
388 }
389
390 void
391 Port::request_monitor_input (bool yn)
392 {
393         jack_port_request_monitor (_jack_port, yn);
394 }
395
396 bool
397 Port::physically_connected () const
398 {
399         const char** jc = jack_port_get_connections (_jack_port);
400
401         if (jc) {
402                 for (int i = 0; jc[i]; ++i) {
403
404                         jack_port_t* port = jack_port_by_name (_engine->jack(), jc[i]);
405                         
406                         if (port && (jack_port_flags (port) & JackPortIsPhysical)) {
407                                 jack_free (jc);
408                                 return true;
409                         }
410                 }
411                 
412                 jack_free (jc);
413         }
414
415         return false;
416 }
417