1 /*
2  * Copyright (C) 2014-2019 Robin Gareus <robin@gareus.org>
3  * Copyright (C) 2015-2020 Paul Davis <paul@linuxaudiosystems.com>
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 #ifndef _libardour_port_engine_shared_h_
21 #define _libardour_port_engine_shared_h_
22 
23 #include <map>
24 #include <set>
25 #include <string>
26 #include <vector>
27 
28 #include <boost/shared_ptr.hpp>
29 
30 #include "pbd/natsort.h"
31 #include "pbd/rcu.h"
32 
33 #include "ardour/libardour_visibility.h"
34 #include "ardour/port_engine.h"
35 #include "ardour/types.h"
36 
37 namespace ARDOUR {
38 
39 class PortEngineSharedImpl;
40 class PortManager;
41 
42 class BackendPort;
43 
44 typedef boost::shared_ptr<BackendPort> BackendPortPtr;
45 typedef boost::shared_ptr<BackendPort> const & BackendPortHandle;
46 
47 class LIBARDOUR_API BackendPort : public ProtoPort
48 {
49   protected:
50 	BackendPort (PortEngineSharedImpl& b, const std::string&, PortFlags);
51 
52   public:
53 	virtual ~BackendPort ();
54 
name()55 	const std::string& name ()        const { return _name; }
pretty_name()56 	const std::string& pretty_name () const { return _pretty_name; }
hw_port_name()57 	const std::string& hw_port_name () const { return _hw_port_name; }
58 
set_name(const std::string & name)59 	int set_name (const std::string& name) {
60 		_name = name;
61 		return 0;
62 	}
63 
64 	/* called from PortEngineSharedImpl */
set_pretty_name(const std::string & name)65 	int set_pretty_name (const std::string& name) {
66 		_pretty_name = name;
67 		return 0;
68 	}
69 
70 	/* called from backends only */
set_hw_port_name(const std::string & name)71 	int set_hw_port_name (const std::string& name) {
72 		_hw_port_name = name;
73 		return 0;
74 	}
75 
76 	virtual DataType type () const = 0;
77 
flags()78 	PortFlags flags ()   const { return _flags; }
is_input()79 	bool is_input ()     const { return flags () & IsInput; }
is_output()80 	bool is_output ()    const { return flags () & IsOutput; }
is_physical()81 	bool is_physical ()  const { return flags () & IsPhysical; }
is_terminal()82 	bool is_terminal ()  const { return flags () & IsTerminal; }
is_connected()83 	bool is_connected () const { return _connections.size () != 0; }
84 
85 	bool is_connected (BackendPortHandle port) const;
86 	bool is_physically_connected () const;
87 
get_connections()88 	const std::set<BackendPortPtr>& get_connections () const {
89 		return _connections;
90 	}
91 
92 	int  connect (BackendPortHandle port, BackendPortHandle self);
93 	int  disconnect (BackendPortHandle port, BackendPortHandle self);
94 	void disconnect_all (BackendPortHandle self);
95 
96 	virtual void* get_buffer (pframes_t nframes) = 0;
97 
latency_range(bool for_playback)98 	const LatencyRange latency_range (bool for_playback) const
99 	{
100 		return for_playback ? _playback_latency_range : _capture_latency_range;
101 	}
102 
103 	void set_latency_range (const LatencyRange& latency_range, bool for_playback);
104 
105 	void update_connected_latency (bool for_playback);
106 
107 protected:
108 	PortEngineSharedImpl& _backend;
109 
110 private:
111 	std::string            _name;
112 	std::string            _pretty_name;
113 	std::string            _hw_port_name;
114 	const PortFlags        _flags;
115 	LatencyRange           _capture_latency_range;
116 	LatencyRange           _playback_latency_range;
117 	std::set<BackendPortPtr> _connections;
118 
119 	void store_connection (BackendPortHandle);
120 	void remove_connection (BackendPortHandle);
121 
122 }; // class BackendPort
123 
124 class LIBARDOUR_API PortEngineSharedImpl
125 {
126 public:
127 	PortEngineSharedImpl (PortManager& mgr, std::string const& instance_name);
128 	virtual ~PortEngineSharedImpl ();
129 
130 	/* Discovering physical ports */
131 
132 	bool      port_is_physical (PortEngine::PortHandle) const;
133 	void      get_physical_outputs (DataType type, std::vector<std::string>&);
134 	void      get_physical_inputs (DataType type, std::vector<std::string>&);
135 	ChanCount n_physical_outputs () const;
136 	ChanCount n_physical_inputs () const;
137 
138 	uint32_t port_name_size () const;
139 
140 	int                    set_port_name (PortEngine::PortHandle, const std::string&);
141 	std::string            get_port_name (PortEngine::PortHandle) const;
142 	PortFlags              get_port_flags (PortEngine::PortHandle) const;
143 	PortEngine::PortPtr    get_port_by_name (const std::string&) const;
144 
145 	int get_port_property (PortEngine::PortHandle, const std::string& key, std::string& value, std::string& type) const;
146 	int set_port_property (PortEngine::PortHandle, const std::string& key, const std::string& value, const std::string& type);
147 
148 	int get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector<std::string>&) const;
149 
150 	DataType port_data_type (PortEngine::PortHandle) const;
151 
152 	PortEngine::PortPtr register_port (const std::string& shortname, ARDOUR::DataType, ARDOUR::PortFlags);
153 	virtual void        unregister_port (PortEngine::PortHandle);
154 
155 	int connect (const std::string& src, const std::string& dst);
156 	int disconnect (const std::string& src, const std::string& dst);
157 	int connect (PortEngine::PortHandle, const std::string&);
158 	int disconnect (PortEngine::PortHandle, const std::string&);
159 	int disconnect_all (PortEngine::PortHandle);
160 
161 	bool connected (PortEngine::PortHandle, bool process_callback_safe);
162 	bool connected_to (PortEngine::PortHandle, const std::string&, bool process_callback_safe);
163 	bool physically_connected (PortEngine::PortHandle, bool process_callback_safe);
164 	int  get_connections (PortEngine::PortHandle, std::vector<std::string>&, bool process_callback_safe);
165 
166 protected:
167 	friend class BackendPort;
168 	std::string _instance_name;
169 
170 	std::vector<BackendPortPtr> _system_inputs;
171 	std::vector<BackendPortPtr> _system_outputs;
172 	std::vector<BackendPortPtr> _system_midi_in;
173 	std::vector<BackendPortPtr> _system_midi_out;
174 
175 	struct PortConnectData {
176 		std::string a;
177 		std::string b;
178 		bool c;
179 
PortConnectDataPortConnectData180 		PortConnectData (const std::string& a, const std::string& b, bool c)
181 			: a (a) , b (b) , c (c) {}
182 	};
183 
184 	std::vector<PortConnectData *> _port_connection_queue;
185 	pthread_mutex_t _port_callback_mutex;
186 
187 	GATOMIC_QUAL gint _port_change_flag; /* atomic */
188 
port_connect_callback(const std::string & a,const std::string & b,bool conn)189 	void port_connect_callback (const std::string& a, const std::string& b, bool conn) {
190 		pthread_mutex_lock (&_port_callback_mutex);
191 		_port_connection_queue.push_back(new PortConnectData(a, b, conn));
192 		pthread_mutex_unlock (&_port_callback_mutex);
193 	}
194 
port_connect_add_remove_callback()195 	void port_connect_add_remove_callback () {
196 		g_atomic_int_set (&_port_change_flag, 1);
197 	}
198 
199 	virtual void update_system_port_latencies ();
200 
201 	void clear_ports ();
202 
203 	BackendPortPtr add_port (const std::string& shortname, ARDOUR::DataType, ARDOUR::PortFlags);
204 	void                unregister_ports (bool system_only = false);
205 
206 	struct SortByPortName {
operatorSortByPortName207 		bool operator() (BackendPortHandle lhs, BackendPortHandle rhs) const {
208 			return PBD::naturally_less (lhs->name ().c_str (), rhs->name ().c_str ());
209 		}
210 	};
211 
212 	typedef std::map<std::string, BackendPortPtr>    PortMap;   // fast lookup in _ports
213 	typedef std::set<BackendPortPtr, SortByPortName> PortIndex; // fast lookup in _ports
214 	SerializedRCUManager<PortMap>                  _portmap;
215 	SerializedRCUManager<PortIndex>                _ports;
216 
valid_port(BackendPortHandle port)217 	bool valid_port (BackendPortHandle port) const {
218 		boost::shared_ptr<PortIndex> p = _ports.reader ();
219 		return std::find (p->begin (), p->end (), port) != p->end ();
220 	}
221 
find_port(const std::string & port_name)222 	BackendPortPtr find_port (const std::string& port_name) const {
223 		boost::shared_ptr<PortMap> p  = _portmap.reader ();
224 		PortMap::const_iterator    it = p->find (port_name);
225 		if (it == p->end ()) {
226 			return BackendPortPtr();
227 		}
228 		return (*it).second;
229 	}
230 
231 	virtual BackendPort* port_factory (std::string const& name, ARDOUR::DataType dt, ARDOUR::PortFlags flags) = 0;
232 
233 #ifndef NDEBUG
234 	void list_ports () const;
235 #endif
236 };
237 
238 } /* namespace ARDOUR */
239 
240 #endif
241