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, DataType type, uint32_t flags)
268 GET_PRIVATE_JACK_POINTER_RET (_jack,0);
271 fatal << _("get_ports called before engine was started") << endmsg;
278 const char* jack_type_string;
281 case DataType::AUDIO:
282 jack_type_string = JACK_DEFAULT_AUDIO_TYPE;
284 case DataType::AUDIO:
285 jack_type_string = JACK_DEFAULT_MIDI_TYPE;
291 return jack_get_ports (_priv_jack, port_name_pattern.c_str(), jack_type_string, flags);
295 AudioEngine::port_registration_failure (const std::string& portname)
297 GET_PRIVATE_JACK_POINTER (_jack);
298 string full_portname = jack_client_name;
299 full_portname += ':';
300 full_portname += portname;
303 jack_port_t* p = jack_port_by_name (_priv_jack, full_portname.c_str());
307 reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname);
309 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);
312 throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
315 boost::shared_ptr<Port>
316 AudioEngine::register_port (DataType dtype, const string& portname, bool input)
318 boost::shared_ptr<Port> newport;
321 if (dtype == DataType::AUDIO) {
322 newport.reset (new AudioPort (portname, (input ? Port::IsInput : Port::IsOutput)));
323 } else if (dtype == DataType::MIDI) {
324 newport.reset (new MidiPort (portname, (input ? Port::IsInput : Port::IsOutput)));
326 throw PortRegistrationFailure("unable to create port (unknown type)");
329 RCUWriter<Ports> writer (ports);
330 boost::shared_ptr<Ports> ps = writer.get_copy ();
331 ps->insert (make_pair (make_port_name_relative (portname), newport));
333 /* writer goes out of scope, forces update */
338 catch (PortRegistrationFailure& err) {
340 } catch (std::exception& e) {
341 throw PortRegistrationFailure(string_compose(
342 _("unable to create port: %1"), e.what()).c_str());
344 throw PortRegistrationFailure("unable to create port (unknown error)");
348 boost::shared_ptr<Port>
349 AudioEngine::register_input_port (DataType type, const string& portname)
351 return register_port (type, portname, true);
354 boost::shared_ptr<Port>
355 AudioEngine::register_output_port (DataType type, const string& portname)
357 return register_port (type, portname, false);
361 AudioEngine::unregister_port (boost::shared_ptr<Port> port)
363 /* caller must hold process lock */
366 /* probably happening when the engine has been halted by JACK,
367 in which case, there is nothing we can do here.
373 RCUWriter<Ports> writer (ports);
374 boost::shared_ptr<Ports> ps = writer.get_copy ();
375 Ports::iterator x = ps->find (make_port_name_relative (port->name()));
377 if (x != ps->end()) {
381 /* writer goes out of scope, forces update */
390 PortManager::connected (const string& port_name)
392 PortEngine::PortHandle handle = _impl->get_port_by_name (port_name);
398 return _impl->connected (handle);
402 AudioEngine::connect (const string& source, const string& destination)
408 fatal << _("connect called before engine was started") << endmsg;
415 string s = make_port_name_non_relative (source);
416 string d = make_port_name_non_relative (destination);
419 boost::shared_ptr<Port> src = get_port_by_name (s);
420 boost::shared_ptr<Port> dst = get_port_by_name (d);
423 ret = src->connect (d);
425 ret = dst->connect (s);
427 /* neither port is known to us, and this API isn't intended for use as a general patch bay */
432 /* already exists - no error, no warning */
433 } else if (ret < 0) {
434 error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
435 source, s, destination, d)
443 AudioEngine::disconnect (const string& source, const string& destination)
449 fatal << _("disconnect called before engine was started") << endmsg;
456 string s = make_port_name_non_relative (source);
457 string d = make_port_name_non_relative (destination);
459 boost::shared_ptr<Port> src = get_port_by_name (s);
460 boost::shared_ptr<Port> dst = get_port_by_name (d);
463 ret = src->disconnect (d);
465 ret = dst->disconnect (s);
467 /* neither port is known to us, and this API isn't intended for use as a general patch bay */
474 AudioEngine::disconnect (boost::shared_ptr<Port> port)
476 GET_PRIVATE_JACK_POINTER_RET (_jack,-1);
480 fatal << _("disconnect called before engine was started") << endmsg;
487 return port->disconnect_all ();
491 PortManager::reestablish_ports ()
495 boost::shared_ptr<Ports> p = ports.reader ();
497 for (i = p->begin(); i != p->end(); ++i) {
498 if (i->second->reestablish ()) {
509 MIDI::Manager::instance()->reestablish ();
515 PortManager::reconnect_ports ()
517 boost::shared_ptr<Ports> p = ports.reader ();
519 /* re-establish connections */
521 for (i = p->begin(); i != p->end(); ++i) {
522 i->second->reconnect ();
525 MIDI::Manager::instance()->reconnect ();