1 /*
2  * Copyright (C) 2006-2012 David Robillard <d@drobilla.net>
3  * Copyright (C) 2006-2019 Paul Davis <paul@linuxaudiosystems.com>
4  * Copyright (C) 2007-2011 Carl Hetherington <carl@carlh.net>
5  * Copyright (C) 2015-2019 Robin Gareus <robin@gareus.org>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21 
22 #ifdef WAF_BUILD
23 #include "libardour-config.h"
24 #endif
25 
26 #include "pbd/compose.h"
27 #include "pbd/error.h"
28 #include "pbd/failed_constructor.h"
29 
30 #include "ardour/audioengine.h"
31 #include "ardour/debug.h"
32 #include "ardour/port.h"
33 #include "ardour/port_engine.h"
34 #include "ardour/rc_configuration.h"
35 
36 #include "pbd/i18n.h"
37 
38 using namespace std;
39 using namespace ARDOUR;
40 using namespace PBD;
41 
42 PBD::Signal0<void> Port::PortDrop;
43 PBD::Signal0<void> Port::PortSignalDrop;
44 
45 bool         Port::_connecting_blocked = false;
46 pframes_t    Port::_global_port_buffer_offset = 0;
47 pframes_t    Port::_cycle_nframes = 0;
48 double       Port::_speed_ratio = 1.0;
49 std::string  Port::state_node_name = X_("Port");
50 const uint32_t Port::_resampler_quality = 17;
51 
52 /* a handy define to shorten what would otherwise be a needlessly verbose
53  * repeated phrase
54  */
55 #define port_engine AudioEngine::instance()->port_engine()
56 #define port_manager AudioEngine::instance()
57 
58 /** @param n Port short name */
Port(std::string const & n,DataType t,PortFlags f)59 Port::Port (std::string const & n, DataType t, PortFlags f)
60 	: _name (n)
61 	, _flags (f)
62 	, _last_monitor (false)
63 	, _externally_connected (0)
64 {
65 	_private_playback_latency.min = 0;
66 	_private_playback_latency.max = 0;
67 	_private_capture_latency.min = 0;
68 	_private_capture_latency.max = 0;
69 
70 	/* Unfortunately we have to pass the DataType into this constructor so that
71 	   we can create the right kind of port; aside from this we'll use the
72 	   virtual function type () to establish type.
73 	*/
74 
75 	assert (_name.find_first_of (':') == std::string::npos);
76 
77 	if (!port_manager->running ()) {
78 		DEBUG_TRACE (DEBUG::Ports, string_compose ("port-engine n/a postpone registering %1\n", name()));
79 		_port_handle.reset (); // created during ::reestablish() later
80 	} else if ((_port_handle = port_engine.register_port (_name, t, _flags)) == 0) {
81 		cerr << "Failed to register port \"" << _name << "\", reason is unknown from here\n";
82 		throw failed_constructor ();
83 	}
84 	DEBUG_TRACE (DEBUG::Ports, string_compose ("registed port %1 handle %2\n", name(), _port_handle));
85 
86 	PortDrop.connect_same_thread (drop_connection, boost::bind (&Port::session_global_drop, this));
87 	PortSignalDrop.connect_same_thread (drop_connection, boost::bind (&Port::signal_drop, this));
88 	port_manager->PortConnectedOrDisconnected.connect_same_thread (engine_connection, boost::bind (&Port::port_connected_or_disconnected, this, _1, _3, _5));
89 }
90 
91 /** Port destructor */
~Port()92 Port::~Port ()
93 {
94 	DEBUG_TRACE (PBD::DebugBits (DEBUG::Destruction|DEBUG::Ports), string_compose ("destroying port @ %1 named %2\n", this, name()));
95 	drop ();
96 }
97 
98 std::string
pretty_name(bool fallback_to_name) const99 Port::pretty_name(bool fallback_to_name) const
100 {
101 	if (_port_handle) {
102 		std::string value;
103 		std::string type;
104 		if (0 == port_engine.get_port_property (_port_handle,
105 					"http://jackaudio.org/metadata/pretty-name",
106 					value, type))
107 		{
108 			return value;
109 		}
110 	}
111 	if (fallback_to_name) {
112 		return name ();
113 	}
114 	return "";
115 }
116 
117 bool
set_pretty_name(const std::string & n)118 Port::set_pretty_name(const std::string& n)
119 {
120 	if (_port_handle) {
121 		if (0 == port_engine.set_port_property (_port_handle,
122 					"http://jackaudio.org/metadata/pretty-name", n, ""))
123 		{
124 			return true;
125 		}
126 	}
127 	return false;
128 }
129 
130 void
session_global_drop()131 Port::session_global_drop()
132 {
133 	if (_flags & TransportMasterPort) {
134 		return;
135 	}
136 
137 	drop ();
138 }
139 
140 void
signal_drop()141 Port::signal_drop ()
142 {
143 	engine_connection.disconnect ();
144 }
145 
146 void
drop()147 Port::drop ()
148 {
149 	if (_port_handle) {
150 		DEBUG_TRACE (DEBUG::Ports, string_compose ("drop handle for port %1\n", name()));
151 		port_engine.unregister_port (_port_handle);
152 		_port_handle.reset ();;
153 	}
154 }
155 
156 void
port_connected_or_disconnected(boost::weak_ptr<Port> w0,boost::weak_ptr<Port> w1,bool con)157 Port::port_connected_or_disconnected (boost::weak_ptr<Port> w0, boost::weak_ptr<Port> w1, bool con)
158 {
159 	boost::shared_ptr<Port> p0 = w0.lock ();
160 	boost::shared_ptr<Port> p1 = w1.lock ();
161 	/* a cheaper, less hacky way to do boost::shared_from_this() ...  */
162 	boost::shared_ptr<Port> pself = AudioEngine::instance()->get_port_by_name (name());
163 
164 	if (p0 == pself) {
165 		ConnectedOrDisconnected (p0, p1, con); // emit signal
166 	}
167 	if (p1 == pself) {
168 		ConnectedOrDisconnected (p1, p0, con); // emit signal
169 	}
170 }
171 
172 /** @return true if this port is connected to anything */
173 bool
connected() const174 Port::connected () const
175 {
176 	if (_port_handle) {
177 		return (port_engine.connected (_port_handle) != 0);
178 	}
179 	return false;
180 }
181 
182 int
disconnect_all()183 Port::disconnect_all ()
184 {
185 	if (_port_handle) {
186 
187 		std::vector<std::string> connections;
188 		get_connections (connections);
189 
190 		port_engine.disconnect_all (_port_handle);
191 		_connections.clear ();
192 
193 		/* a cheaper, less hacky way to do boost::shared_from_this() ...
194 		 */
195 		boost::shared_ptr<Port> pself = port_manager->get_port_by_name (name());
196 		for (vector<string>::const_iterator c = connections.begin(); c != connections.end() && pself; ++c) {
197 			boost::shared_ptr<Port> pother = AudioEngine::instance()->get_port_by_name (*c);
198 			if (pother) {
199 				ConnectedOrDisconnected (pself, pother, false); // emit signal
200 			}
201 		}
202 	}
203 
204 	return 0;
205 }
206 
207 /** @param o Port name
208  * @return true if this port is connected to o, otherwise false.
209  */
210 bool
connected_to(std::string const & o) const211 Port::connected_to (std::string const & o) const
212 {
213 	if (!_port_handle) {
214 		return false;
215 	}
216 
217 	if (!port_manager->running()) {
218 		return false;
219 	}
220 
221 	return port_engine.connected_to (_port_handle, AudioEngine::instance()->make_port_name_non_relative (o));
222 }
223 
224 int
get_connections(std::vector<std::string> & c) const225 Port::get_connections (std::vector<std::string> & c) const
226 {
227 	if (!port_manager->running()) {
228 		c.insert (c.end(), _connections.begin(), _connections.end());
229 		return c.size();
230 	}
231 
232 	if (_port_handle) {
233 		return port_engine.get_connections (_port_handle, c);
234 	}
235 
236 	return 0;
237 }
238 
239 int
connect(std::string const & other)240 Port::connect (std::string const & other)
241 {
242 	std::string const other_name = AudioEngine::instance()->make_port_name_non_relative (other);
243 	std::string const our_name = AudioEngine::instance()->make_port_name_non_relative (_name);
244 
245 	int r = 0;
246 
247 	if (_connecting_blocked) {
248 		return r;
249 	}
250 
251 	if (sends_output ()) {
252 		DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2\n", our_name, other_name));
253 		r = port_engine.connect (our_name, other_name);
254 	} else {
255 		DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2\n", other_name, our_name));
256 		r = port_engine.connect (other_name, our_name);
257 	}
258 
259 	if (r == 0) {
260 		_connections.insert (other);
261 	}
262 
263 	return r;
264 }
265 
266 int
disconnect(std::string const & other)267 Port::disconnect (std::string const & other)
268 {
269 	std::string const other_fullname = port_manager->make_port_name_non_relative (other);
270 	std::string const this_fullname = port_manager->make_port_name_non_relative (_name);
271 
272 	int r = 0;
273 
274 	if (sends_output ()) {
275 		r = port_engine.disconnect (this_fullname, other_fullname);
276 	} else {
277 		r = port_engine.disconnect (other_fullname, this_fullname);
278 	}
279 
280 	if (r == 0) {
281 		_connections.erase (other);
282 	}
283 
284 	/* a cheaper, less hacky way to do boost::shared_from_this() ...  */
285 	boost::shared_ptr<Port> pself = AudioEngine::instance()->get_port_by_name (name());
286 	boost::shared_ptr<Port> pother = AudioEngine::instance()->get_port_by_name (other);
287 
288 	if (pself && pother) {
289 		/* Disconnecting from another Ardour port: need to allow
290 		   a check on whether this may affect anything that we
291 		   need to know about.
292 		*/
293 		ConnectedOrDisconnected (pself, pother, false); // emit signal
294 	}
295 
296 	return r;
297 }
298 
299 
300 bool
connected_to(Port * o) const301 Port::connected_to (Port* o) const
302 {
303 	return connected_to (o->name ());
304 }
305 
306 int
connect(Port * o)307 Port::connect (Port* o)
308 {
309 	return connect (o->name ());
310 }
311 
312 int
disconnect(Port * o)313 Port::disconnect (Port* o)
314 {
315 	return disconnect (o->name ());
316 }
317 
318 void
request_input_monitoring(bool yn)319 Port::request_input_monitoring (bool yn)
320 {
321 	if (_port_handle) {
322 		port_engine.request_input_monitoring (_port_handle, yn);
323 	}
324 }
325 
326 void
ensure_input_monitoring(bool yn)327 Port::ensure_input_monitoring (bool yn)
328 {
329 	if (_port_handle) {
330 		port_engine.ensure_input_monitoring (_port_handle, yn);
331 	}
332 }
333 
334 bool
monitoring_input() const335 Port::monitoring_input () const
336 {
337 	if (_port_handle) {
338 		return port_engine.monitoring_input (_port_handle);
339 	}
340 	return false;
341 }
342 
343 void
reset()344 Port::reset ()
345 {
346 	_last_monitor = false;
347 	_externally_connected = 0;
348 }
349 
350 void
cycle_start(pframes_t)351 Port::cycle_start (pframes_t)
352 {
353 }
354 
355 void
set_public_latency_range(LatencyRange const & range,bool playback) const356 Port::set_public_latency_range (LatencyRange const& range, bool playback) const
357 {
358 	/* this sets the visible latency that the rest of the port system
359 	   sees. because we do latency compensation, all (most) of our visible
360 	   port latency values are identical.
361 	*/
362 
363 	DEBUG_TRACE (DEBUG::LatencyIO,
364 	             string_compose ("SET PORT %1 %4 PUBLIC latency now [%2 - %3]\n",
365 	                             name(), range.min, range.max,
366 	                             (playback ? "PLAYBACK" : "CAPTURE")));;
367 
368 	if (_port_handle) {
369 		LatencyRange r (range);
370 		if (externally_connected () && 0 == (_flags & TransportSyncPort)) {
371 #if 0
372 			r.min *= _speed_ratio;
373 			r.max *= _speed_ratio;
374 #endif
375 			if (type () == DataType::AUDIO) {
376 				r.min += (_resampler_quality - 1);
377 				r.max += (_resampler_quality - 1);
378 			}
379 		}
380 		port_engine.set_latency_range (_port_handle, playback, r);
381 	}
382 }
383 
384 void
set_private_latency_range(LatencyRange & range,bool playback)385 Port::set_private_latency_range (LatencyRange& range, bool playback)
386 {
387 	if (playback) {
388 		_private_playback_latency = range;
389 		DEBUG_TRACE (DEBUG::LatencyIO, string_compose (
390 			             "SET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
391 			             name(),
392 			             _private_playback_latency.min,
393 			             _private_playback_latency.max));
394 	} else {
395 		_private_capture_latency = range;
396 		DEBUG_TRACE (DEBUG::LatencyIO, string_compose (
397 			             "SET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
398 			             name(),
399 			             _private_capture_latency.min,
400 			             _private_capture_latency.max));
401 	}
402 
403 	/* push to public (port system) location so that everyone else can see it */
404 
405 	set_public_latency_range (range, playback);
406 }
407 
408 const LatencyRange&
private_latency_range(bool playback) const409 Port::private_latency_range (bool playback) const
410 {
411 	if (playback) {
412 		DEBUG_TRACE (DEBUG::LatencyIO, string_compose (
413 			             "GET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
414 			             name(),
415 			             _private_playback_latency.min,
416 			             _private_playback_latency.max));
417 		return _private_playback_latency;
418 	} else {
419 		DEBUG_TRACE (DEBUG::LatencyIO, string_compose (
420 			             "GET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
421 			             name(),
422 			             _private_playback_latency.min,
423 			             _private_playback_latency.max));
424 		return _private_capture_latency;
425 	}
426 }
427 
428 LatencyRange
public_latency_range(bool) const429 Port::public_latency_range (bool /*playback*/) const
430 {
431 	/*Note: this method is no longer used. It exists purely for debugging reasons */
432 	LatencyRange r;
433 
434 	if (_port_handle) {
435 		r = port_engine.get_latency_range (_port_handle, sends_output() ? true : false);
436 		if (externally_connected () && 0 == (_flags & TransportSyncPort)) {
437 #if 0
438 			r.min /= _speed_ratio;
439 			r.max /= _speed_ratio;
440 #endif
441 #if 0
442 			/* use value as set by set_public_latency_range */
443 			if (type () == DataType::AUDIO) {
444 				r.min += (_resampler_quality - 1);
445 				r.max += (_resampler_quality - 1);
446 			}
447 #endif
448 		}
449 
450 		DEBUG_TRACE (DEBUG::LatencyIO, string_compose (
451 				     "GET PORT %1: %4 PUBLIC latency range %2 .. %3\n",
452 				     name(), r.min, r.max,
453 				     sends_output() ? "PLAYBACK" : "CAPTURE"));
454 	}
455 
456 	return r;
457 }
458 
459 void
get_connected_latency_range(LatencyRange & range,bool playback) const460 Port::get_connected_latency_range (LatencyRange& range, bool playback) const
461 {
462 	vector<string> connections;
463 
464 	get_connections (connections);
465 
466 	if (!connections.empty()) {
467 
468 		range.min = ~((pframes_t) 0);
469 		range.max = 0;
470 
471 		DEBUG_TRACE (DEBUG::LatencyIO, string_compose ("%1: %2 connections to check for latency range\n", name(), connections.size()));
472 
473 		for (vector<string>::const_iterator c = connections.begin();
474 				c != connections.end(); ++c) {
475 
476 			LatencyRange lr;
477 
478 			if (!AudioEngine::instance()->port_is_mine (*c)) {
479 
480 				/* port belongs to some other port-system client, use
481 				 * the port engine to lookup its latency information.
482 				 */
483 
484 				PortEngine::PortHandle remote_port = port_engine.get_port_by_name (*c);
485 
486 				if (remote_port) {
487 					lr = port_engine.get_latency_range (remote_port, playback);
488 					if (externally_connected () && 0 == (_flags & TransportSyncPort)) {
489 #if 0
490 						lr.min /= _speed_ratio;
491 						lr.max /= _speed_ratio;
492 #endif
493 						if (type () == DataType::AUDIO) {
494 							lr.min += (_resampler_quality - 1);
495 							lr.max += (_resampler_quality - 1);
496 						}
497 					}
498 
499 					DEBUG_TRACE (DEBUG::LatencyIO, string_compose (
500 								"\t%1 <-> %2 : latter has latency range %3 .. %4\n",
501 								name(), *c, lr.min, lr.max));
502 
503 					range.min = min (range.min, lr.min);
504 					range.max = max (range.max, lr.max);
505 				}
506 
507 			} else {
508 
509 				/* port belongs to this instance of ardour,
510 				 * so look up its latency information
511 				 * internally, because our published/public
512 				 * values already contain our plugin
513 				 * latency compensation.
514 				 */
515 
516 				boost::shared_ptr<Port> remote_port = AudioEngine::instance()->get_port_by_name (*c);
517 				if (remote_port) {
518 					lr = remote_port->private_latency_range ((playback ? true : false));
519 					DEBUG_TRACE (DEBUG::LatencyIO, string_compose (
520 								"\t%1 <-LOCAL-> %2 : latter has latency range %3 .. %4\n",
521 								name(), *c, lr.min, lr.max));
522 
523 					range.min = min (range.min, lr.min);
524 					range.max = max (range.max, lr.max);
525 				}
526 			}
527 		}
528 
529 	} else {
530 		DEBUG_TRACE (DEBUG::LatencyIO, string_compose ("%1: not connected to anything\n", name()));
531 		range.min = 0;
532 		range.max = 0;
533 	}
534 
535 	DEBUG_TRACE (DEBUG::LatencyIO, string_compose ("%1: final connected latency range [ %2 .. %3 ] \n", name(), range.min, range.max));
536 }
537 
538 int
reestablish()539 Port::reestablish ()
540 {
541 	DEBUG_TRACE (DEBUG::Ports, string_compose ("re-establish %1 port %2\n", type().to_string(), _name));
542 	_port_handle = port_engine.register_port (_name, type(), _flags);
543 
544 	if (_port_handle == 0) {
545 		PBD::error << string_compose (_("could not reregister %1"), _name) << endmsg;
546 		return -1;
547 	}
548 
549 	DEBUG_TRACE (DEBUG::Ports, string_compose ("Port::reestablish %1 handle %2\n", name(), _port_handle));
550 
551 	reset ();
552 
553 	port_manager->PortConnectedOrDisconnected.connect_same_thread (engine_connection, boost::bind (&Port::port_connected_or_disconnected, this, _1, _3, _5));
554 	return 0;
555 }
556 
557 
558 int
reconnect()559 Port::reconnect ()
560 {
561 	/* caller must hold process lock; intended to be used only after reestablish() */
562 
563 	DEBUG_TRACE (DEBUG::Ports, string_compose ("Connect %1 to %2 destinations\n",name(), _connections.size()));
564 
565 	for (std::set<string>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
566 		if (connect (*i)) {
567 			_connections.clear ();
568 			return -1;
569 		}
570 	}
571 
572 	return 0;
573 }
574 
575 /** @param n Short port name (no port-system client name) */
576 int
set_name(std::string const & n)577 Port::set_name (std::string const & n)
578 {
579 	if (n == _name || !_port_handle) {
580 		return 0;
581 	}
582 
583 	int const r = port_engine.set_port_name (_port_handle, n);
584 
585 	if (r == 0) {
586 		AudioEngine::instance()->port_renamed (_name, n);
587 		_name = n;
588 	}
589 
590 
591 	return r;
592 }
593 
594 bool
physically_connected() const595 Port::physically_connected () const
596 {
597 	if (!_port_handle) {
598 		return false;
599 	}
600 
601 	return port_engine.physically_connected (_port_handle);
602 }
603 
604 XMLNode&
get_state() const605 Port::get_state () const
606 {
607 	XMLNode* root = new XMLNode (state_node_name);
608 
609 	root->set_property (X_("name"), AudioEngine::instance()->make_port_name_relative (name()));
610 
611 	if (receives_input()) {
612 		root->set_property (X_("direction"), X_("input"));
613 	} else {
614 		root->set_property (X_("direction"), X_("output"));
615 	}
616 
617 	vector<string> c;
618 
619 	get_connections (c);
620 
621 	for (vector<string>::const_iterator i = c.begin(); i != c.end(); ++i) {
622 		XMLNode* child = new XMLNode (X_("Connection"));
623 		child->set_property (X_("other"), *i);
624 		root->add_child_nocopy (*child);
625 	}
626 
627 	return *root;
628 }
629 
630 int
set_state(const XMLNode & node,int)631 Port::set_state (const XMLNode& node, int)
632 {
633 	if (node.name() != state_node_name) {
634 		return -1;
635 	}
636 
637 	std::string str;
638 	if (node.get_property (X_("name"), str)) {
639 		set_name (str);
640 	}
641 
642 	const XMLNodeList& children (node.children());
643 
644 	_connections.clear ();
645 
646 	for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
647 
648 		if ((*c)->name() != X_("Connection")) {
649 			continue;
650 		}
651 
652 		if (!(*c)->get_property (X_("other"), str)) {
653 			continue;
654 		}
655 
656 		_connections.insert (str);
657 	}
658 
659 	return 0;
660 }
661 
662 /*static*/ void
set_speed_ratio(double s)663 Port::set_speed_ratio (double s) {
664 	/* see VMResampler::set_rratio() for min/max range */
665 	if (s == 0.0) {
666 		/* no resampling when stopped */
667 		_speed_ratio = 1.0;
668 	} else {
669 		_speed_ratio = std::min ((double) Config->get_max_transport_speed(), std::max (0.02, fabs (s)));
670 	}
671 }
672 
673 /*static*/ void
set_cycle_samplecnt(pframes_t n)674 Port::set_cycle_samplecnt (pframes_t n)
675 {
676 	_cycle_nframes = floor (n * _speed_ratio);
677 }
678