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