2 Copyright (C) 2013 Paul Davis
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.
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.
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.
21 #include "ardour/port_manager.h"
23 using namespace ARDOUR;
25 PortManager::PortManager ()
31 AudioEngine::remove_all_ports ()
33 /* make sure that JACK callbacks that will be invoked as we cleanup
34 * ports know that they have nothing to do.
37 port_remove_in_progress = true;
39 /* process lock MUST be held by caller
43 RCUWriter<Ports> writer (ports);
44 boost::shared_ptr<Ports> ps = writer.get_copy ();
48 /* clear dead wood list in RCU */
52 port_remove_in_progress = false;
57 AudioEngine::make_port_name_relative (const string& portname) const
59 string::size_type len;
62 len = portname.length();
64 for (n = 0; n < len; ++n) {
65 if (portname[n] == ':') {
70 if ((n != len) && (portname.substr (0, n) == jack_client_name)) {
71 return portname.substr (n+1);
78 AudioEngine::make_port_name_non_relative (const string& portname) const
82 if (portname.find_first_of (':') != string::npos) {
86 str = jack_client_name;
94 AudioEngine::port_is_mine (const string& portname) const
96 if (portname.find_first_of (':') != string::npos) {
97 if (portname.substr (0, jack_client_name.length ()) != jack_client_name) {
105 AudioEngine::port_is_physical (const std::string& portname) const
107 GET_PRIVATE_JACK_POINTER_RET(_jack, false);
109 jack_port_t *port = jack_port_by_name (_priv_jack, portname.c_str());
115 return jack_port_flags (port) & JackPortIsPhysical;
119 AudioEngine::n_physical (unsigned long flags) const
123 GET_PRIVATE_JACK_POINTER_RET (_jack, c);
125 const char ** ports = jack_get_ports (_priv_jack, NULL, NULL, JackPortIsPhysical | flags);
130 for (uint32_t i = 0; ports[i]; ++i) {
131 if (!strstr (ports[i], "Midi-Through")) {
132 DataType t (jack_port_type (jack_port_by_name (_jack, ports[i])));
133 c.set (t, c.get (t) + 1);
143 AudioEngine::n_physical_inputs () const
145 return n_physical (JackPortIsInput);
149 AudioEngine::n_physical_outputs () const
151 return n_physical (JackPortIsOutput);
155 AudioEngine::get_physical (DataType type, unsigned long flags, vector<string>& phy)
157 GET_PRIVATE_JACK_POINTER (_jack);
160 if ((ports = jack_get_ports (_priv_jack, NULL, type.to_jack_type(), JackPortIsPhysical | flags)) == 0) {
165 for (uint32_t i = 0; ports[i]; ++i) {
166 if (strstr (ports[i], "Midi-Through")) {
169 phy.push_back (ports[i]);
175 /** Get physical ports for which JackPortIsOutput is set; ie those that correspond to
176 * a physical input connector.
179 AudioEngine::get_physical_inputs (DataType type, vector<string>& ins)
181 get_physical (type, JackPortIsOutput, ins);
184 /** Get physical ports for which JackPortIsInput is set; ie those that correspond to
185 * a physical output connector.
188 AudioEngine::get_physical_outputs (DataType type, vector<string>& outs)
190 get_physical (type, JackPortIsInput, outs);
195 AudioEngine::can_request_hardware_monitoring ()
197 GET_PRIVATE_JACK_POINTER_RET (_jack,false);
200 if ((ports = jack_get_ports (_priv_jack, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortCanMonitor)) == 0) {
210 /** @param name Full or short name of port
211 * @return Corresponding Port or 0.
214 boost::shared_ptr<Port>
215 AudioEngine::get_port_by_name (const string& portname)
219 fatal << _("get_port_by_name() called before engine was started") << endmsg;
222 boost::shared_ptr<Port> ();
226 if (!port_is_mine (portname)) {
227 /* not an ardour port */
228 return boost::shared_ptr<Port> ();
231 boost::shared_ptr<Ports> pr = ports.reader();
232 std::string rel = make_port_name_relative (portname);
233 Ports::iterator x = pr->find (rel);
235 if (x != pr->end()) {
236 /* its possible that the port was renamed by some 3rd party and
237 we don't know about it. check for this (the check is quick
238 and cheap), and if so, rename the port (which will alter
239 the port map as a side effect).
241 const std::string check = make_port_name_relative (jack_port_name (x->second->jack_port()));
243 x->second->set_name (check);
248 return boost::shared_ptr<Port> ();
252 AudioEngine::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
254 RCUWriter<Ports> writer (ports);
255 boost::shared_ptr<Ports> p = writer.get_copy();
256 Ports::iterator x = p->find (old_relative_name);
259 boost::shared_ptr<Port> port = x->second;
261 p->insert (make_pair (new_relative_name, port));
266 AudioEngine::get_ports (const string& port_name_pattern, const string& type_name_pattern, uint32_t flags)
268 GET_PRIVATE_JACK_POINTER_RET (_jack,0);
271 fatal << _("get_ports called before engine was started") << endmsg;
277 return jack_get_ports (_priv_jack, port_name_pattern.c_str(), type_name_pattern.c_str(), flags);
281 AudioEngine::port_registration_failure (const std::string& portname)
283 GET_PRIVATE_JACK_POINTER (_jack);
284 string full_portname = jack_client_name;
285 full_portname += ':';
286 full_portname += portname;
289 jack_port_t* p = jack_port_by_name (_priv_jack, full_portname.c_str());
293 reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname);
295 reason = string_compose (_("No more JACK ports are available. You will need to stop %1 and restart JACK with more ports if you need this many tracks."), PROGRAM_NAME);
298 throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
301 boost::shared_ptr<Port>
302 AudioEngine::register_port (DataType dtype, const string& portname, bool input)
304 boost::shared_ptr<Port> newport;
307 if (dtype == DataType::AUDIO) {
308 newport.reset (new AudioPort (portname, (input ? Port::IsInput : Port::IsOutput)));
309 } else if (dtype == DataType::MIDI) {
310 newport.reset (new MidiPort (portname, (input ? Port::IsInput : Port::IsOutput)));
312 throw PortRegistrationFailure("unable to create port (unknown type)");
315 RCUWriter<Ports> writer (ports);
316 boost::shared_ptr<Ports> ps = writer.get_copy ();
317 ps->insert (make_pair (make_port_name_relative (portname), newport));
319 /* writer goes out of scope, forces update */
324 catch (PortRegistrationFailure& err) {
326 } catch (std::exception& e) {
327 throw PortRegistrationFailure(string_compose(
328 _("unable to create port: %1"), e.what()).c_str());
330 throw PortRegistrationFailure("unable to create port (unknown error)");
334 boost::shared_ptr<Port>
335 AudioEngine::register_input_port (DataType type, const string& portname)
337 return register_port (type, portname, true);
340 boost::shared_ptr<Port>
341 AudioEngine::register_output_port (DataType type, const string& portname)
343 return register_port (type, portname, false);
347 AudioEngine::unregister_port (boost::shared_ptr<Port> port)
349 /* caller must hold process lock */
352 /* probably happening when the engine has been halted by JACK,
353 in which case, there is nothing we can do here.
359 RCUWriter<Ports> writer (ports);
360 boost::shared_ptr<Ports> ps = writer.get_copy ();
361 Ports::iterator x = ps->find (make_port_name_relative (port->name()));
363 if (x != ps->end()) {
367 /* writer goes out of scope, forces update */
376 PortManager::connected (const string& port_name)
378 PortEngine::PortHandle handle = _impl->get_port_by_name (port_name);
384 return _impl->connected (handle);
388 AudioEngine::connect (const string& source, const string& destination)
394 fatal << _("connect called before engine was started") << endmsg;
401 string s = make_port_name_non_relative (source);
402 string d = make_port_name_non_relative (destination);
405 boost::shared_ptr<Port> src = get_port_by_name (s);
406 boost::shared_ptr<Port> dst = get_port_by_name (d);
409 ret = src->connect (d);
411 ret = dst->connect (s);
413 /* neither port is known to us, and this API isn't intended for use as a general patch bay */
418 /* already exists - no error, no warning */
419 } else if (ret < 0) {
420 error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
421 source, s, destination, d)
429 AudioEngine::disconnect (const string& source, const string& destination)
435 fatal << _("disconnect called before engine was started") << endmsg;
442 string s = make_port_name_non_relative (source);
443 string d = make_port_name_non_relative (destination);
445 boost::shared_ptr<Port> src = get_port_by_name (s);
446 boost::shared_ptr<Port> dst = get_port_by_name (d);
449 ret = src->disconnect (d);
451 ret = dst->disconnect (s);
453 /* neither port is known to us, and this API isn't intended for use as a general patch bay */
460 AudioEngine::disconnect (boost::shared_ptr<Port> port)
462 GET_PRIVATE_JACK_POINTER_RET (_jack,-1);
466 fatal << _("disconnect called before engine was started") << endmsg;
473 return port->disconnect_all ();