1 /*
2  * Copyright (C) 2013-2018 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2014-2017 Robin Gareus <robin@gareus.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #include <string.h>
21 #include <stdint.h>
22 
23 #include "pbd/error.h"
24 
25 #include "jack_audiobackend.h"
26 #include "jack_connection.h"
27 
28 #include "ardour/port_manager.h"
29 
30 #include "pbd/i18n.h"
31 
32 using namespace ARDOUR;
33 using namespace PBD;
34 using std::string;
35 using std::vector;
36 
37 #define GET_PRIVATE_JACK_POINTER(localvar)  jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return; }
38 #define GET_PRIVATE_JACK_POINTER_RET(localvar,r) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return r; }
39 
40 static uint32_t
ardour_port_flags_to_jack_flags(PortFlags flags)41 ardour_port_flags_to_jack_flags (PortFlags flags)
42 {
43 	uint32_t jack_flags = 0;
44 
45 	if (flags & IsInput) {
46 		jack_flags |= JackPortIsInput;
47 	}
48 	if (flags & IsOutput) {
49 		jack_flags |= JackPortIsOutput;
50 	}
51 	if (flags & IsTerminal) {
52 		jack_flags |= JackPortIsTerminal;
53 	}
54 	if (flags & IsPhysical) {
55 		jack_flags |= JackPortIsPhysical;
56 	}
57 	if (flags & CanMonitor) {
58 		jack_flags |= JackPortCanMonitor;
59 	}
60 
61 	return jack_flags;
62 }
63 
64 static DataType
jack_port_type_to_ardour_data_type(const char * jack_type)65 jack_port_type_to_ardour_data_type (const char* jack_type)
66 {
67 	if (strcmp (jack_type, JACK_DEFAULT_AUDIO_TYPE) == 0) {
68 		return DataType::AUDIO;
69 	} else if (strcmp (jack_type, JACK_DEFAULT_MIDI_TYPE) == 0) {
70 		return DataType::MIDI;
71 	}
72 	return DataType::NIL;
73 }
74 
75 static const char*
ardour_data_type_to_jack_port_type(DataType d)76 ardour_data_type_to_jack_port_type (DataType d)
77 {
78 	switch (d) {
79 	case DataType::AUDIO:
80 		return JACK_DEFAULT_AUDIO_TYPE;
81 	case DataType::MIDI:
82 		return JACK_DEFAULT_MIDI_TYPE;
83 	}
84 
85 	return "";
86 }
87 
88 void
when_connected_to_jack()89 JACKAudioBackend::when_connected_to_jack ()
90 {
91 	/* register callbacks for stuff that is our responsibility */
92 
93 	jack_client_t* client = _jack_connection->jack();
94 
95 	if (!client) {
96 		/* how could this happen? it could ... */
97 		error << _("Already disconnected from JACK before PortEngine could register callbacks") << endmsg;
98 		return;
99 	}
100 
101         jack_set_port_registration_callback (client, _registration_callback, this);
102         jack_set_port_connect_callback (client, _connect_callback, this);
103         jack_set_graph_order_callback (client, _graph_order_callback, this);
104 }
105 
106 int
set_port_name(PortHandle port,const std::string & name)107 JACKAudioBackend::set_port_name (PortHandle port, const std::string& name)
108 {
109 #if HAVE_JACK_PORT_RENAME
110 	jack_client_t* client = _jack_connection->jack();
111 	if (client) {
112 		return jack_port_rename (client, boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr, name.c_str());
113 	} else {
114 		return -1;
115 	}
116 #else
117 	return jack_port_set_name (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr, name.c_str());
118 #endif
119 }
120 
121 string
get_port_name(PortHandle port) const122 JACKAudioBackend::get_port_name (PortHandle port) const
123 {
124 	return jack_port_name (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr);
125 }
126 
127 PortFlags
get_port_flags(PortHandle port) const128 JACKAudioBackend::get_port_flags (PortHandle port) const
129 {
130 	return PortFlags (jack_port_flags (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr));
131 }
132 
133 int
get_port_property(PortHandle port,const std::string & key,std::string & value,std::string & type) const134 JACKAudioBackend::get_port_property (PortHandle port, const std::string& key, std::string& value, std::string& type) const
135 {
136 #ifdef HAVE_JACK_METADATA // really everyone ought to have this by now.
137 	int rv = -1;
138 	char *cvalue = NULL;
139 	char *ctype = NULL;
140 
141 	jack_uuid_t uuid = jack_port_uuid (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr);
142 	rv = jack_get_property (uuid, key.c_str(), &cvalue, &ctype);
143 
144 	if (0 == rv && cvalue) {
145 		value = cvalue;
146 		if (ctype) {
147 			type = ctype;
148 		}
149 	} else {
150 		rv = -1;
151 	}
152 
153 	jack_free(cvalue);
154 	jack_free(ctype);
155 	return rv;
156 #else
157 	return -1;
158 #endif
159 }
160 
161 int
set_port_property(PortHandle port,const std::string & key,const std::string & value,const std::string & type)162 JACKAudioBackend::set_port_property (PortHandle port, const std::string& key, const std::string& value, const std::string& type)
163 {
164 #ifdef HAVE_JACK_METADATA // really everyone ought to have this by now.
165 	int rv = -1;
166 	jack_client_t* client = _jack_connection->jack();
167 	jack_uuid_t uuid = jack_port_uuid (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr);
168 	return jack_set_property(client, uuid, key.c_str(), value.c_str(), type.c_str());
169 	return rv;
170 #else
171 	return -1;
172 #endif
173 }
174 
175 PortEngine::PortPtr
get_port_by_name(const std::string & name) const176 JACKAudioBackend::get_port_by_name (const std::string& name) const
177 {
178 	{
179 		boost::shared_ptr<JackPorts> ports = _jack_ports.reader ();
180 		JackPorts::iterator p = ports->find (name);
181 
182 		if (p != ports->end()) {
183 			return p->second;
184 		}
185 	}
186 
187 	/* Port not known to us yet, so look it up via JACK (slow) */
188 
189 	GET_PRIVATE_JACK_POINTER_RET (_priv_jack, PortEngine::PortPtr());
190 	jack_port_t * jack_port = jack_port_by_name (_priv_jack, name.c_str());
191 
192 	if (!jack_port) {
193 		/* No such port ... return nothering */
194 		return PortEngine::PortPtr();
195 	}
196 
197 	boost::shared_ptr<JackPort> jp;
198 
199 	{
200 		RCUWriter<JackPorts> writer (_jack_ports);
201 		boost::shared_ptr<JackPorts> ports = writer.get_copy();
202 		jp.reset (new JackPort (jack_port));
203 		ports->insert (std::make_pair (name, jp));
204 	}
205 
206 	_jack_ports.flush ();
207 
208 	return jp;
209 }
210 
211 void
_registration_callback(jack_port_id_t id,int reg,void * arg)212 JACKAudioBackend::_registration_callback (jack_port_id_t id, int reg, void* arg)
213 {
214 	/* we don't use a virtual method for the registration callback, because
215 	   JACK is the only backend that delivers the arguments shown above. So
216 	   call our own JACK-centric registration callback, then the generic
217 	   one.
218 	*/
219 	static_cast<JACKAudioBackend*> (arg)->jack_registration_callback (id, reg);
220 	static_cast<JACKAudioBackend*> (arg)->manager.registration_callback ();
221 	static_cast<JACKAudioBackend*> (arg)->engine.latency_callback (false);
222 	static_cast<JACKAudioBackend*> (arg)->engine.latency_callback (true);
223 }
224 
225 void
jack_registration_callback(jack_port_id_t id,int reg)226 JACKAudioBackend::jack_registration_callback (jack_port_id_t id, int reg)
227 {
228 	GET_PRIVATE_JACK_POINTER (_priv_jack);
229 	jack_port_t* jack_port = jack_port_by_id (_priv_jack, id);
230 
231 	if (!jack_port) {
232 		return;
233 	}
234 
235 	/* We only need to care about ports that we do not register/unregister
236 	 * ourselves. Our own ports will added/removed from _jack_ports at the
237 	 * appropriate time.
238 	 *
239 	 * But for the input meters, we'll be looking up ports not created by
240 	 * us, and they may also go away at arbitrary times too. We want to
241 	 * make sure we can look up these ports by name only (in _jack_ports)
242 	 * because jack_port_by_name() is unacceptably slow for RT contexts
243 	 * (like run_input_meters()). So we catch these ports at registration
244 	 * time, and put a suitable entry in _jack_ports.
245 	 *
246 	 * It isn't critical that we keep _jack_ports current if any of these
247 	 * ports goes away, but since we get told about that here, we do that
248 	 * just to keep things clean. This will happen if someone disconnects a
249 	 * USB MIDI device, for example.
250 	 */
251 
252 	if (!jack_port_is_mine (_priv_jack, jack_port)) {
253 
254 		const char* name = jack_port_name (jack_port);
255 
256 		boost::shared_ptr<JackPorts> ports = _jack_ports.write_copy();
257 
258 		if (!reg) {
259 			if (ports->erase (name)) {
260 				_jack_ports.update (ports);
261 			} else {
262 				_jack_ports.no_update();
263 			}
264 		} else {
265 			if (ports->find (name) != ports->end()) {
266 				/* hmmm, we already have this port */
267 				std::cout << "re-registration of JACK port named " << name << std::endl;
268 				ports->erase (name);
269 			}
270 
271 			boost::shared_ptr<JackPort> jp (new JackPort (jack_port));
272 			ports->insert (std::make_pair (name, jp));
273 
274 			_jack_ports.update (ports);
275 		}
276 	}
277 }
278 
279 int
_graph_order_callback(void * arg)280 JACKAudioBackend::_graph_order_callback (void *arg)
281 {
282 	return static_cast<JACKAudioBackend*> (arg)->manager.graph_order_callback ();
283 }
284 
285 void
_connect_callback(jack_port_id_t id_a,jack_port_id_t id_b,int conn,void * arg)286 JACKAudioBackend::_connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, int conn, void* arg)
287 {
288 	static_cast<JACKAudioBackend*> (arg)->connect_callback (id_a, id_b, conn);
289 }
290 
291 void
connect_callback(jack_port_id_t id_a,jack_port_id_t id_b,int conn)292 JACKAudioBackend::connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, int conn)
293 {
294 	if (manager.port_remove_in_progress()) {
295 		return;
296 	}
297 
298 	GET_PRIVATE_JACK_POINTER (_priv_jack);
299 
300 	jack_port_t* a = jack_port_by_id (_priv_jack, id_a);
301 	jack_port_t* b = jack_port_by_id (_priv_jack, id_b);
302 
303 	manager.connect_callback (jack_port_name (a), jack_port_name (b), conn == 0 ? false : true);
304 }
305 
306 bool
connected(PortHandle p,bool process_callback_safe)307 JACKAudioBackend::connected (PortHandle p, bool process_callback_safe)
308 {
309 	bool ret = false;
310 	jack_port_t* port = boost::dynamic_pointer_cast<JackPort>(p)->jack_ptr;
311 	const char** ports;
312 
313 	if (process_callback_safe) {
314 		ports = jack_port_get_connections (port);
315 	} else {
316 		GET_PRIVATE_JACK_POINTER_RET (_priv_jack, false);
317 		ports = jack_port_get_all_connections (_priv_jack, port);
318 	}
319 
320 	if (ports) {
321 		ret = true;
322 	}
323 
324 	jack_free (ports);
325 
326 	return ret;
327 }
328 
329 bool
connected_to(PortHandle p,const std::string & other,bool process_callback_safe)330 JACKAudioBackend::connected_to (PortHandle p, const std::string& other, bool process_callback_safe)
331 {
332 	bool ret = false;
333 	const char** ports;
334 	jack_port_t* port = boost::dynamic_pointer_cast<JackPort>(p)->jack_ptr;
335 
336 	if (process_callback_safe) {
337 		ports = jack_port_get_connections (port);
338 	} else {
339 		GET_PRIVATE_JACK_POINTER_RET (_priv_jack, false);
340 		ports = jack_port_get_all_connections (_priv_jack, port);
341 	}
342 
343 	if (ports) {
344 		for (int i = 0; ports[i]; ++i) {
345 			if (other == ports[i]) {
346 				ret = true;
347 			}
348 		}
349 		jack_free (ports);
350 	}
351 
352 	return ret;
353 }
354 
355 bool
physically_connected(PortHandle p,bool process_callback_safe)356 JACKAudioBackend::physically_connected (PortHandle p, bool process_callback_safe)
357 {
358 	GET_PRIVATE_JACK_POINTER_RET (_priv_jack, false);
359 	jack_port_t* port = boost::dynamic_pointer_cast<JackPort>(p)->jack_ptr;
360 
361 	const char** ports;
362 
363 	if (process_callback_safe) {
364 		ports = jack_port_get_connections ((jack_port_t*)port);
365 	} else {
366 		GET_PRIVATE_JACK_POINTER_RET (_priv_jack, false);
367 		ports = jack_port_get_all_connections (_priv_jack, (jack_port_t*)port);
368 	}
369 
370 	if (ports) {
371 		for (int i = 0; ports[i]; ++i) {
372 
373 			jack_port_t* other = jack_port_by_name (_priv_jack, ports[i]);
374 
375 			if (other && (jack_port_flags (other) & JackPortIsPhysical)) {
376 				jack_free (ports);
377 				return true;
378 			}
379 		}
380 		jack_free (ports);
381 	}
382 
383 	return false;
384 }
385 
386 bool
externally_connected(PortHandle p,bool process_callback_safe)387 JACKAudioBackend::externally_connected (PortHandle p, bool process_callback_safe)
388 {
389 	GET_PRIVATE_JACK_POINTER_RET (_priv_jack, false);
390 	jack_port_t* port = boost::dynamic_pointer_cast<JackPort>(p)->jack_ptr;
391 
392 	const char** ports;
393 
394 	if (process_callback_safe) {
395 		ports = jack_port_get_connections ((jack_port_t*)port);
396 	} else {
397 		GET_PRIVATE_JACK_POINTER_RET (_priv_jack, false);
398 		ports = jack_port_get_all_connections (_priv_jack, (jack_port_t*)port);
399 	}
400 
401 	if (ports) {
402 		for (int i = 0; ports[i]; ++i) {
403 			jack_port_t* other = jack_port_by_name (_priv_jack, ports[i]);
404 
405 			if (other && (jack_port_flags (other) & JackPortIsPhysical)) {
406 				jack_free (ports);
407 				return true;
408 			}
409 			if (other && !jack_port_is_mine (_priv_jack, other)) {
410 				jack_free (ports);
411 				return true;
412 			}
413 		}
414 		jack_free (ports);
415 	}
416 	return false;
417 }
418 
419 int
get_connections(PortHandle p,vector<string> & s,bool process_callback_safe)420 JACKAudioBackend::get_connections (PortHandle p, vector<string>& s, bool process_callback_safe)
421 {
422 	const char** ports;
423 	jack_port_t* port = boost::dynamic_pointer_cast<JackPort>(p)->jack_ptr;
424 
425 	if (process_callback_safe) {
426 		ports = jack_port_get_connections (port);
427 	} else {
428 		GET_PRIVATE_JACK_POINTER_RET (_priv_jack, 0);
429 		ports = jack_port_get_all_connections (_priv_jack, port);
430 	}
431 
432 	if (ports) {
433 		for (int i = 0; ports[i]; ++i) {
434 			s.push_back (ports[i]);
435 		}
436 		jack_free (ports);
437 	}
438 
439 	return s.size();
440 }
441 
442 DataType
port_data_type(PortHandle port) const443 JACKAudioBackend::port_data_type (PortHandle port) const
444 {
445 	return jack_port_type_to_ardour_data_type (jack_port_type (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr));
446 }
447 
448 const string&
my_name() const449 JACKAudioBackend::my_name() const
450 {
451 	return _jack_connection->client_name();
452 }
453 
454 bool
port_is_physical(PortHandle port) const455 JACKAudioBackend::port_is_physical (PortHandle port) const
456 {
457 	if (!port) {
458                 return false;
459         }
460 
461 	return jack_port_flags (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr) & JackPortIsPhysical;
462 }
463 
464 int
get_ports(const string & port_name_pattern,DataType type,PortFlags flags,vector<string> & s) const465 JACKAudioBackend::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector<string>& s) const
466 {
467 
468 	GET_PRIVATE_JACK_POINTER_RET (_priv_jack,0);
469 
470 	const char** ports =  jack_get_ports (_priv_jack, port_name_pattern.c_str(),
471 					      ardour_data_type_to_jack_port_type (type),
472 					      ardour_port_flags_to_jack_flags (flags));
473 
474 	if (ports == 0) {
475 		return 0;
476 	}
477 
478 	for (uint32_t i = 0; ports[i]; ++i) {
479 		s.push_back (ports[i]);
480 	}
481 
482 	jack_free (ports);
483 
484 	return s.size();
485 }
486 
487 ChanCount
n_physical_inputs() const488 JACKAudioBackend::n_physical_inputs () const
489 {
490 	return n_physical (JackPortIsInput);
491 }
492 
493 ChanCount
n_physical_outputs() const494 JACKAudioBackend::n_physical_outputs () const
495 {
496 	return n_physical (JackPortIsOutput);
497 }
498 
499 void
get_physical(DataType type,unsigned long flags,vector<string> & phy) const500 JACKAudioBackend::get_physical (DataType type, unsigned long flags, vector<string>& phy) const
501 {
502 	GET_PRIVATE_JACK_POINTER (_priv_jack);
503 	const char ** ports;
504 
505 	if ((ports = jack_get_ports (_priv_jack, NULL, ardour_data_type_to_jack_port_type (type), JackPortIsPhysical | flags)) == 0) {
506 		return;
507 	}
508 
509 	if (ports) {
510 		for (uint32_t i = 0; ports[i]; ++i) {
511                         if (strstr (ports[i], "Midi-Through")) {
512                                 continue;
513                         }
514 			phy.push_back (ports[i]);
515 		}
516 		jack_free (ports);
517 	}
518 }
519 
520 /** Get physical ports for which JackPortIsOutput is set; ie those that correspond to
521  *  a physical input connector.
522  */
523 void
get_physical_inputs(DataType type,vector<string> & ins)524 JACKAudioBackend::get_physical_inputs (DataType type, vector<string>& ins)
525 {
526 	get_physical (type, JackPortIsOutput, ins);
527 }
528 
529 /** Get physical ports for which JackPortIsInput is set; ie those that correspond to
530  *  a physical output connector.
531  */
532 void
get_physical_outputs(DataType type,vector<string> & outs)533 JACKAudioBackend::get_physical_outputs (DataType type, vector<string>& outs)
534 {
535 	get_physical (type, JackPortIsInput, outs);
536 }
537 
538 
539 bool
can_monitor_input() const540 JACKAudioBackend::can_monitor_input () const
541 {
542 	GET_PRIVATE_JACK_POINTER_RET (_priv_jack,false);
543 	const char ** ports;
544 
545 	if ((ports = jack_get_ports (_priv_jack, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortCanMonitor)) == 0) {
546 		return false;
547 	}
548 
549 	jack_free (ports);
550 
551 	return true;
552 }
553 
554 int
request_input_monitoring(PortHandle port,bool yn)555 JACKAudioBackend::request_input_monitoring (PortHandle port, bool yn)
556 {
557 	return jack_port_request_monitor (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr, yn);
558 }
559 int
ensure_input_monitoring(PortHandle port,bool yn)560 JACKAudioBackend::ensure_input_monitoring (PortHandle port, bool yn)
561 {
562 	return jack_port_ensure_monitor (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr, yn);
563 }
564 bool
monitoring_input(PortHandle port)565 JACKAudioBackend::monitoring_input (PortHandle port)
566 {
567 	return jack_port_monitoring_input (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr);
568 }
569 
570 PortEngine::PortPtr
register_port(const std::string & shortname,ARDOUR::DataType type,ARDOUR::PortFlags flags)571 JACKAudioBackend::register_port (const std::string& shortname, ARDOUR::DataType type, ARDOUR::PortFlags flags)
572 {
573 	GET_PRIVATE_JACK_POINTER_RET (_priv_jack, PortEngine::PortPtr());
574 	jack_port_t* jack_port = jack_port_register (_priv_jack, shortname.c_str(),
575 	                                             ardour_data_type_to_jack_port_type (type),
576 	                                             ardour_port_flags_to_jack_flags (flags),
577 	                                             0);
578 	if (!jack_port) {
579 		return PortEngine::PortPtr();
580 	}
581 
582 	boost::shared_ptr<JackPort> jp;
583 
584 	{
585 		RCUWriter<JackPorts> writer (_jack_ports);
586 		boost::shared_ptr<JackPorts> ports = writer.get_copy();
587 
588 		jp.reset (new JackPort (jack_port));
589 
590 		ports->insert (std::make_pair (jack_port_name (jack_port), jp));
591 	}
592 
593 	_jack_ports.flush();
594 
595 	 return jp;
596 }
597 
598 void
unregister_port(PortHandle port)599 JACKAudioBackend::unregister_port (PortHandle port)
600 {
601 	GET_PRIVATE_JACK_POINTER (_priv_jack);
602 	boost::shared_ptr<JackPort> jp = boost::dynamic_pointer_cast<JackPort>(port);
603 	const std::string name = jack_port_name (jp->jack_ptr);
604 
605 	{
606 		RCUWriter<JackPorts> writer (_jack_ports);
607 		boost::shared_ptr<JackPorts> ports = writer.get_copy();
608 		ports->erase (name);
609 	}
610 
611 	_jack_ports.flush ();
612 
613 	(void) jack_port_unregister (_priv_jack, jp->jack_ptr);
614 }
615 
616 int
connect(PortHandle port,const std::string & other)617 JACKAudioBackend::connect (PortHandle port, const std::string& other)
618 {
619 	GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
620 	return jack_connect (_priv_jack, jack_port_name (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr), other.c_str());
621 }
622 int
connect(const std::string & src,const std::string & dst)623 JACKAudioBackend::connect (const std::string& src, const std::string& dst)
624 {
625 	GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
626 
627 	int r = jack_connect (_priv_jack, src.c_str(), dst.c_str());
628 	return r;
629 }
630 
631 int
disconnect(PortHandle port,const std::string & other)632 JACKAudioBackend::disconnect (PortHandle port, const std::string& other)
633 {
634 	GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
635 	return jack_disconnect (_priv_jack, jack_port_name (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr), other.c_str());
636 }
637 
638 int
disconnect(const std::string & src,const std::string & dst)639 JACKAudioBackend::disconnect (const std::string& src, const std::string& dst)
640 {
641 	GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
642 	return jack_disconnect (_priv_jack, src.c_str(), dst.c_str());
643 }
644 
645 int
disconnect_all(PortHandle port)646 JACKAudioBackend::disconnect_all (PortHandle port)
647 {
648 	GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
649 	return jack_port_disconnect (_priv_jack, boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr);
650 }
651 
652 int
midi_event_get(pframes_t & timestamp,size_t & size,uint8_t const ** buf,void * port_buffer,uint32_t event_index)653 JACKAudioBackend::midi_event_get (pframes_t& timestamp, size_t& size, uint8_t const** buf, void* port_buffer, uint32_t event_index)
654 {
655 	jack_midi_event_t ev;
656 	int ret;
657 
658 	if ((ret = jack_midi_event_get (&ev, port_buffer, event_index)) == 0) {
659 		timestamp = ev.time;
660 		size = ev.size;
661 		*buf = ev.buffer;
662 	}
663 
664 	return ret;
665 }
666 
667 int
midi_event_put(void * port_buffer,pframes_t timestamp,const uint8_t * buffer,size_t size)668 JACKAudioBackend::midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size)
669 {
670 	return jack_midi_event_write (port_buffer, timestamp, buffer, size);
671 }
672 
673 uint32_t
get_midi_event_count(void * port_buffer)674 JACKAudioBackend::get_midi_event_count (void* port_buffer)
675 {
676 	return jack_midi_get_event_count (port_buffer);
677 }
678 
679 void
midi_clear(void * port_buffer)680 JACKAudioBackend::midi_clear (void* port_buffer)
681 {
682 	jack_midi_clear_buffer (port_buffer);
683 }
684 
685 void
set_latency_range(PortHandle port,bool for_playback,LatencyRange r)686 JACKAudioBackend::set_latency_range (PortHandle port, bool for_playback, LatencyRange r)
687 {
688 	jack_latency_range_t range;
689 
690 	range.min = r.min;
691 	range.max = r.max;
692 
693 	jack_port_set_latency_range (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr, for_playback ? JackPlaybackLatency : JackCaptureLatency, &range);
694 }
695 
696 LatencyRange
get_latency_range(PortHandle port,bool for_playback)697 JACKAudioBackend::get_latency_range (PortHandle port, bool for_playback)
698 {
699 	jack_latency_range_t range;
700 	LatencyRange ret;
701 
702 	jack_port_get_latency_range (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr, for_playback ? JackPlaybackLatency : JackCaptureLatency, &range);
703 
704 	ret.min = range.min;
705 	ret.max = range.max;
706 
707 	return ret;
708 }
709 
710 void*
get_buffer(PortHandle port,pframes_t nframes)711 JACKAudioBackend::get_buffer (PortHandle port, pframes_t nframes)
712 {
713 	return jack_port_get_buffer (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr, nframes);
714 }
715 
716 uint32_t
port_name_size() const717 JACKAudioBackend::port_name_size() const
718 {
719 	return jack_port_name_size ();
720 }
721