#include <fstream>
#include <algorithm>
#include <cmath>
+#include <vector>
#include <unistd.h>
#include <locale.h>
#include <errno.h>
#include <glibmm.h>
-#include <glibmm/thread.h>
+#include <glibmm/threads.h>
#include "pbd/xml++.h"
#include "pbd/replace_all.h"
#include "ardour/audioengine.h"
#include "ardour/buffer.h"
+#include "ardour/buffer_set.h"
#include "ardour/debug.h"
#include "ardour/io.h"
-#include "ardour/route.h"
#include "ardour/port.h"
-#include "ardour/audio_port.h"
-#include "ardour/midi_port.h"
+#include "ardour/route.h"
#include "ardour/session.h"
-#include "ardour/cycle_timer.h"
-#include "ardour/buffer_set.h"
-#include "ardour/meter.h"
-#include "ardour/amp.h"
#include "ardour/user_bundle.h"
#include "i18n.h"
-#define BLOCK_PROCESS_CALLBACK() Glib::Mutex::Lock em (AudioEngine::instance()->process_lock())
+#define BLOCK_PROCESS_CALLBACK() Glib::Threads::Mutex::Lock em (AudioEngine::instance()->process_lock())
using namespace std;
using namespace ARDOUR;
/** @param default_type The type of port that will be created by ensure_io
* and friends if no type is explicitly requested (to avoid breakage).
*/
-IO::IO (Session& s, const string& name, Direction dir, DataType default_type)
+IO::IO (Session& s, const string& name, Direction dir, DataType default_type, bool sendish)
: SessionObject (s, name)
, _direction (dir)
, _default_type (default_type)
+ , _sendish (sendish)
{
_active = true;
+ Port::PostDisconnect.connect_same_thread (*this, boost::bind (&IO::disconnect_check, this, _1, _2));
pending_state_node = 0;
setup_bundle ();
}
-IO::IO (Session& s, const XMLNode& node, DataType dt)
+IO::IO (Session& s, const XMLNode& node, DataType dt, bool sendish)
: SessionObject(s, "unnamed io")
, _direction (Input)
, _default_type (dt)
+ , _sendish (sendish)
{
_active = true;
pending_state_node = 0;
+ Port::PostDisconnect.connect_same_thread (*this, boost::bind (&IO::disconnect_check, this, _1, _2));
set_state (node, Stateful::loading_state_version);
setup_bundle ();
IO::~IO ()
{
- Glib::Mutex::Lock lm (io_lock);
+ Glib::Threads::Mutex::Lock lm (io_lock);
BLOCK_PROCESS_CALLBACK ();
}
}
+void
+IO::disconnect_check (boost::shared_ptr<Port> a, boost::shared_ptr<Port> b)
+{
+ /* this could be called from within our own ::disconnect() method(s)
+ or from somewhere that operates directly on a port. so, we don't
+ know for sure if we can take this lock or not. if we fail,
+ we assume that its safely locked by our own ::disconnect().
+ */
+
+ Glib::Threads::Mutex::Lock tm (io_lock, Glib::Threads::TRY_LOCK);
+
+ if (tm.locked()) {
+ /* we took the lock, so we cannot be here from inside
+ * ::disconnect()
+ */
+ if (_ports.contains (a) || _ports.contains (b)) {
+ changed (IOChange (IOChange::ConnectionsChanged), this); /* EMIT SIGNAL */
+ }
+ } else {
+ /* we didn't get the lock, so assume that we're inside
+ * ::disconnect(), and it will call changed() appropriately.
+ */
+ }
+}
+
void
IO::increment_port_buffer_offset (pframes_t offset)
{
}
{
- Glib::Mutex::Lock lm (io_lock);
+ Glib::Threads::Mutex::Lock lm (io_lock);
/* check that our_port is really one of ours */
}
{
- Glib::Mutex::Lock lm (io_lock);
+ Glib::Threads::Mutex::Lock lm (io_lock);
/* check that our_port is really one of ours */
ChanCount after = before;
after.set (port->type(), after.get (port->type()) - 1);
- bool const r = PortCountChanging (after); /* EMIT SIGNAL */
- if (r) {
+ boost::optional<bool> const r = PortCountChanging (after); /* EMIT SIGNAL */
+ if (r.get_value_or (false)) {
return -1;
}
BLOCK_PROCESS_CALLBACK ();
{
- Glib::Mutex::Lock lm (io_lock);
+ Glib::Threads::Mutex::Lock lm (io_lock);
if (_ports.remove(port)) {
change.type = IOChange::Type (change.type | IOChange::ConfigurationChanged);
{
- Glib::Mutex::Lock lm (io_lock);
+ Glib::Threads::Mutex::Lock lm (io_lock);
/* Create a new port */
IO::disconnect (void* src)
{
{
- Glib::Mutex::Lock lm (io_lock);
+ Glib::Threads::Mutex::Lock lm (io_lock);
for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
i->disconnect_all ();
int
IO::ensure_ports_locked (ChanCount count, bool clear, bool& changed)
{
+#ifndef PLATFORM_WINDOWS
assert (!AudioEngine::instance()->process_lock().trylock());
+#endif
boost::shared_ptr<Port> port;
int
IO::ensure_ports (ChanCount count, bool clear, void* src)
{
+#ifndef PLATFORM_WINDOWS
assert (!AudioEngine::instance()->process_lock().trylock());
+#endif
bool changed = false;
change.before = _ports.count ();
{
- Glib::Mutex::Lock im (io_lock);
+ Glib::Threads::Mutex::Lock im (io_lock);
if (ensure_ports_locked (count, clear, changed)) {
return -1;
}
int
IO::ensure_io (ChanCount count, bool clear, void* src)
{
+#ifndef PLATFORM_WINDOWS
assert (!AudioEngine::instance()->process_lock().trylock());
+#endif
return ensure_ports (count, clear, src);
}
vector<string>::iterator ci;
int n;
LocaleGuard lg (X_("POSIX"));
- Glib::Mutex::Lock lm (io_lock);
+ Glib::Threads::Mutex::Lock lm (io_lock);
node->add_property("name", _name);
id().print (buf, sizeof (buf));
get_port_counts (node, version, n, c);
{
- Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+ Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
if (ensure_ports (n, true, this)) {
error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
if (prop) {
boost::shared_ptr<Bundle> b = find_possible_bundle (prop->value());
if (b) {
- connect_ports_to_bundle (b, this);
+ connect_ports_to_bundle (b, true, this);
}
}
return 0;
}
+void
+IO::prepare_for_reset (XMLNode& node, const std::string& name)
+{
+ /* reset name */
+ node.add_property ("name", name);
+
+ /* now find connections and reset the name of the port
+ in one so that when we re-use it it will match
+ the name of the thing we're applying it to.
+ */
+
+ XMLProperty* prop;
+ XMLNodeList children = node.children();
+
+ for (XMLNodeIterator i = children.begin(); i != children.end(); ++i) {
+
+ if ((*i)->name() == "Port") {
+
+ prop = (*i)->property (X_("name"));
+
+ if (prop) {
+ string new_name;
+ string old = prop->value();
+ string::size_type slash = old.find ('/');
+
+ if (slash != string::npos) {
+ /* port name is of form: <IO-name>/<port-name> */
+
+ new_name = name;
+ new_name += old.substr (old.find ('/'));
+
+ prop->set_value (new_name);
+ }
+ }
+ }
+ }
+}
+
int
IO::make_connections_2X (const XMLNode& node, int /*version*/, bool in)
}
{
- Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+ Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
// FIXME: audio-only
if (ensure_ports (ChanCount(DataType::AUDIO, nports), true, this)) {
}
int
-IO::connect_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
+IO::connect_ports_to_bundle (boost::shared_ptr<Bundle> c, bool exclusive, void* src)
{
BLOCK_PROCESS_CALLBACK ();
{
- Glib::Mutex::Lock lm2 (io_lock);
+ Glib::Threads::Mutex::Lock lm2 (io_lock);
+
+ if (exclusive) {
+ for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
+ i->disconnect_all ();
+ }
+ }
c->connect (_bundle, _session.engine());
BLOCK_PROCESS_CALLBACK ();
{
- Glib::Mutex::Lock lm2 (io_lock);
+ Glib::Threads::Mutex::Lock lm2 (io_lock);
c->disconnect (_bundle, _session.engine());
int
IO::enable_connecting ()
{
+ Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
connecting_legal = true;
boost::optional<int> r = ConnectingLegal ();
return r.get_value_or (0);
string
IO::build_legal_port_name (DataType type)
{
- const int name_size = jack_port_name_size();
+ const int name_size = AudioEngine::instance()->port_name_size();
int limit;
string suffix;
if (type == DataType::AUDIO) {
- suffix = _("audio");
+ suffix = X_("audio");
} else if (type == DataType::MIDI) {
- suffix = _("midi");
+ suffix = X_("midi");
} else {
throw unknown_type();
}
use the (new) translated name.
*/
- if (_direction == Input) {
- suffix += X_("_in");
+ if (_sendish) {
+ if (_direction == Input) {
+ suffix += X_("_return");
+ } else {
+ suffix += X_("_send");
+ }
} else {
- suffix += X_("_out");
+ if (_direction == Input) {
+ suffix += X_("_in");
+ } else {
+ suffix += X_("_out");
+ }
}
// allow up to 4 digits for the output port number, plus the slash, suffix and extra space
- limit = name_size - _session.engine().client_name().length() - (suffix.length() + 5);
+ limit = name_size - AudioEngine::instance()->my_name().length() - (suffix.length() + 5);
- char buf1[name_size+1];
- char buf2[name_size+1];
+ std::vector<char> buf1(name_size+1);
+ std::vector<char> buf2(name_size+1);
/* colons are illegal in port names, so fix that */
string nom = _name.val();
replace_all (nom, ":", ";");
- snprintf (buf1, name_size+1, ("%.*s/%s"), limit, nom.c_str(), suffix.c_str());
+ snprintf (&buf1[0], name_size+1, ("%.*s/%s"), limit, nom.c_str(), suffix.c_str());
- int port_number = find_port_hole (buf1);
- snprintf (buf2, name_size+1, "%s %d", buf1, port_number);
+ int port_number = find_port_hole (&buf1[0]);
+ snprintf (&buf2[0], name_size+1, "%s %d", &buf1[0], port_number);
- return string (buf2);
+ return string (&buf2[0]);
}
int32_t
*/
for (n = 1; n < 9999; ++n) {
- char buf[jack_port_name_size()];
+ std::vector<char> buf (AudioEngine::instance()->port_name_size());
PortSet::iterator i = _ports.begin();
- snprintf (buf, jack_port_name_size(), _("%s %u"), base, n);
+ snprintf (&buf[0], buf.size()+1, _("%s %u"), base, n);
for ( ; i != _ports.end(); ++i) {
- if (i->name() == buf) {
+ if (string(i->name()) == string(&buf[0])) {
break;
}
}
return;
}
- _buffers.get_jack_port_addresses (_ports, nframes);
- proc->run (_buffers, start_frame, end_frame, nframes, true);
+ _buffers.get_backend_port_addresses (_ports, nframes);
+ if (proc) {
+ proc->run (_buffers, start_frame, end_frame, nframes, true);
+ }
}
void
bool
IO::has_port (boost::shared_ptr<Port> p) const
{
- Glib::Mutex::Lock lm (io_lock);
+ Glib::Threads::Mutex::Lock lm (io_lock);
return _ports.contains (p);
}