Auto-connect master/monitor when switching backends
This commit is contained in:
parent
aaf3013211
commit
d5cc5b0586
@ -118,6 +118,7 @@ public:
|
||||
bool connected_to (const std::string&) const;
|
||||
bool connected () const;
|
||||
bool physically_connected () const;
|
||||
bool has_ext_connection () const;
|
||||
|
||||
samplecnt_t latency () const;
|
||||
samplecnt_t connected_latency (bool for_playback) const;
|
||||
|
@ -128,6 +128,7 @@ public:
|
||||
virtual void realtime_locate (bool for_loop_end) {}
|
||||
virtual void set_buffer_size (pframes_t) {}
|
||||
|
||||
bool has_ext_connection () const;
|
||||
bool physically_connected () const;
|
||||
bool in_cycle () const { return _in_cycle; }
|
||||
|
||||
|
@ -161,6 +161,7 @@ class PluginInsert;
|
||||
class PluginInfo;
|
||||
class Port;
|
||||
class PortInsert;
|
||||
class PortManager;
|
||||
class ProcessThread;
|
||||
class Processor;
|
||||
class Region;
|
||||
@ -2192,7 +2193,9 @@ private:
|
||||
std::shared_ptr<Route> _master_out;
|
||||
std::shared_ptr<Route> _monitor_out;
|
||||
|
||||
friend class PortManager;
|
||||
void auto_connect_master_bus ();
|
||||
void auto_connect_monitor_bus ();
|
||||
|
||||
void setup_route_monitor_sends (bool enable, bool need_process_lock);
|
||||
|
||||
|
@ -1717,6 +1717,18 @@ IO::physically_connected () const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
IO::has_ext_connection () const
|
||||
{
|
||||
for (PortSet::const_iterator i = _ports.begin(); i != _ports.end(); ++i) {
|
||||
if (i->has_ext_connection()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
IO::has_port (std::shared_ptr<Port> p) const
|
||||
{
|
||||
|
@ -215,7 +215,9 @@ Port::erase_connection (std::string const& pn)
|
||||
{
|
||||
std::string const bid (AudioEngine::instance()->backend_id (receives_input ()));
|
||||
Glib::Threads::RWLock::WriterLock lm (_connections_lock);
|
||||
_ext_connections[bid].erase (pn);
|
||||
if (_ext_connections.find (bid) != _ext_connections.end ()) {
|
||||
_ext_connections[bid].erase (pn);
|
||||
}
|
||||
} else {
|
||||
Glib::Threads::RWLock::WriterLock lm (_connections_lock);
|
||||
_int_connections.erase (pn);
|
||||
@ -273,7 +275,9 @@ Port::disconnect_all ()
|
||||
std::string const bid (AudioEngine::instance()->backend_id (receives_input ()));
|
||||
Glib::Threads::RWLock::WriterLock lm (_connections_lock);
|
||||
_int_connections.clear ();
|
||||
_ext_connections[bid].clear ();
|
||||
if (_ext_connections.find (bid) != _ext_connections.end ()) {
|
||||
_ext_connections[bid].clear ();
|
||||
}
|
||||
}
|
||||
|
||||
/* a cheaper, less hacky way to do boost::shared_from_this() ...
|
||||
@ -315,9 +319,8 @@ Port::get_connections (std::vector<std::string>& c) const
|
||||
std::string const bid (AudioEngine::instance()->backend_id (receives_input ()));
|
||||
Glib::Threads::RWLock::ReaderLock lm (_connections_lock);
|
||||
c.insert (c.end(), _int_connections.begin(), _int_connections.end());
|
||||
try {
|
||||
if (_ext_connections.find (bid) != _ext_connections.end ()) {
|
||||
c.insert (c.end(), _ext_connections.at(bid).begin(), _ext_connections.at(bid).end());
|
||||
} catch (std::out_of_range&) {
|
||||
}
|
||||
return c.size ();
|
||||
}
|
||||
@ -698,23 +701,42 @@ Port::reestablish ()
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
Port::has_ext_connection () const
|
||||
{
|
||||
std::string const bid (AudioEngine::instance()->backend_id (receives_input ()));
|
||||
|
||||
Glib::Threads::RWLock::ReaderLock lm (_connections_lock);
|
||||
|
||||
return _ext_connections.find (bid) != _ext_connections.end ();
|
||||
}
|
||||
|
||||
int
|
||||
Port::reconnect ()
|
||||
{
|
||||
/* caller must hold process lock; intended to be used only after reestablish() */
|
||||
|
||||
int count = 0;
|
||||
|
||||
std::string const bid (AudioEngine::instance()->backend_id (receives_input ()));
|
||||
|
||||
Glib::Threads::RWLock::WriterLock lm (_connections_lock);
|
||||
|
||||
if (_int_connections.empty () && _ext_connections[bid].empty ()) {
|
||||
return 0; /* OK */
|
||||
if (_ext_connections.find (bid) != _ext_connections.end ()) {
|
||||
if (_int_connections.empty () && _ext_connections[bid].empty ()) {
|
||||
return 0; /* OK */
|
||||
}
|
||||
count = _int_connections.size() + _ext_connections[bid].size();
|
||||
} else {
|
||||
if (_int_connections.empty ()) {
|
||||
return 0; /* OK */
|
||||
}
|
||||
count = _int_connections.size();
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::Ports, string_compose ("Port::reconnect() Connect %1 to %2 destinations\n",name(), _int_connections.size() + _ext_connections[bid].size()));
|
||||
DEBUG_TRACE (DEBUG::Ports, string_compose ("Port::reconnect() Connect %1 to %2 destinations\n",name(), count));
|
||||
|
||||
int count = 0;
|
||||
count = 0;
|
||||
|
||||
ConnectionSet::iterator i = _int_connections.begin();
|
||||
while (i != _int_connections.end()) {
|
||||
@ -727,14 +749,16 @@ Port::reconnect ()
|
||||
}
|
||||
}
|
||||
|
||||
i = _ext_connections[bid].begin();
|
||||
while (i != _ext_connections[bid].end()) {
|
||||
ConnectionSet::iterator current = i++;
|
||||
if (connect_internal (*current)) {
|
||||
DEBUG_TRACE (DEBUG::Ports, string_compose ("Port::reconnect() failed to connect %1 to %2\n", name(), (*current)));
|
||||
_ext_connections[bid].erase (current);
|
||||
} else {
|
||||
++count;
|
||||
if (_ext_connections.find (bid) != _ext_connections.end ()) {
|
||||
i = _ext_connections[bid].begin();
|
||||
while (i != _ext_connections[bid].end()) {
|
||||
ConnectionSet::iterator current = i++;
|
||||
if (connect_internal (*current)) {
|
||||
DEBUG_TRACE (DEBUG::Ports, string_compose ("Port::reconnect() failed to connect %1 to %2\n", name(), (*current)));
|
||||
_ext_connections[bid].erase (current);
|
||||
} else {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -792,6 +816,9 @@ Port::get_state () const
|
||||
}
|
||||
|
||||
for (auto const& hwc : _ext_connections) {
|
||||
XMLNode* child = new XMLNode (X_("ExtConnection"));
|
||||
child->set_property (X_("for"), hwc.first);
|
||||
root->add_child_nocopy (*child);
|
||||
for (auto const& c : hwc.second) {
|
||||
XMLNode* child = new XMLNode (X_("ExtConnection"));
|
||||
child->set_property (X_("for"), hwc.first);
|
||||
@ -828,8 +855,12 @@ Port::set_state (const XMLNode& node, int)
|
||||
}
|
||||
|
||||
std::string hw;
|
||||
if ((*c)->name() == X_("ExtConnection") && (*c)->get_property (X_("for"), hw) && (*c)->get_property (X_("other"), str)) {
|
||||
if ((*c)->name() == X_("ExtConnection") && (*c)->get_property (X_("for"), hw)) {
|
||||
if ((*c)->get_property (X_("other"), str)) {
|
||||
_ext_connections[hw].insert (str);
|
||||
} else {
|
||||
_ext_connections[hw]; // create
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -918,6 +918,14 @@ PortManager::reconnect_ports ()
|
||||
|
||||
DEBUG_TRACE (DEBUG::Ports, string_compose ("reconnect %1 ports\n", p->size ()));
|
||||
|
||||
Session* s = AudioEngine::instance ()->session ();
|
||||
if (s && s->master_out() && !s->master_out ()->output()->has_ext_connection()) {
|
||||
s->auto_connect_master_bus ();
|
||||
}
|
||||
if (s && s->monitor_out() && !s->monitor_out ()->output()->has_ext_connection()) {
|
||||
s->auto_connect_monitor_bus ();
|
||||
}
|
||||
|
||||
for (auto const& i : *p) {
|
||||
if (i.second->reconnect ()) {
|
||||
PortConnectedOrDisconnected (i.second, i.first, std::weak_ptr<Port> (), "", false);
|
||||
|
@ -1149,58 +1149,7 @@ Session::add_monitor_section ()
|
||||
}
|
||||
}
|
||||
|
||||
/* if monitor section is not connected, connect it to physical outs */
|
||||
|
||||
if ((Config->get_auto_connect_standard_busses () || Profile->get_mixbus ()) && !_monitor_out->output()->connected ()) {
|
||||
|
||||
if (!Config->get_monitor_bus_preferred_bundle().empty()) {
|
||||
|
||||
std::shared_ptr<Bundle> b = bundle_by_name (Config->get_monitor_bus_preferred_bundle());
|
||||
|
||||
if (b) {
|
||||
_monitor_out->output()->connect_ports_to_bundle (b, true, this);
|
||||
} else {
|
||||
warning << string_compose (_("The preferred I/O for the monitor bus (%1) cannot be found"),
|
||||
Config->get_monitor_bus_preferred_bundle())
|
||||
<< endmsg;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* Monitor bus is audio only */
|
||||
|
||||
vector<string> outputs[DataType::num_types];
|
||||
|
||||
for (uint32_t i = 0; i < DataType::num_types; ++i) {
|
||||
_engine.get_physical_outputs (DataType (DataType::Symbol (i)), outputs[i]);
|
||||
}
|
||||
|
||||
uint32_t mod = outputs[DataType::AUDIO].size();
|
||||
uint32_t limit = _monitor_out->n_outputs().get (DataType::AUDIO);
|
||||
|
||||
if (mod != 0) {
|
||||
|
||||
for (uint32_t n = 0; n < limit; ++n) {
|
||||
|
||||
std::shared_ptr<Port> p = _monitor_out->output()->ports().port(DataType::AUDIO, n);
|
||||
string connect_to;
|
||||
if (outputs[DataType::AUDIO].size() > (n % mod)) {
|
||||
connect_to = outputs[DataType::AUDIO][n % mod];
|
||||
}
|
||||
|
||||
if (!connect_to.empty()) {
|
||||
if (_monitor_out->output()->connect (p, connect_to, this)) {
|
||||
error << string_compose (
|
||||
_("cannot connect control output %1 to %2"),
|
||||
n, connect_to)
|
||||
<< endmsg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
auto_connect_monitor_bus ();
|
||||
|
||||
/* Hold process lock while doing this so that we don't hear bits and
|
||||
* pieces of audio as we work on each route.
|
||||
@ -1211,6 +1160,68 @@ Session::add_monitor_section ()
|
||||
MonitorBusAddedOrRemoved (); /* EMIT SIGNAL */
|
||||
}
|
||||
|
||||
void
|
||||
Session::auto_connect_monitor_bus ()
|
||||
{
|
||||
if (!_master_out || !_monitor_out) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((!Config->get_auto_connect_standard_busses () && !Profile->get_mixbus ()) || _monitor_out->output()->connected ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* if monitor section is not connected, connect it to physical outs */
|
||||
|
||||
if (!Config->get_monitor_bus_preferred_bundle().empty()) {
|
||||
|
||||
std::shared_ptr<Bundle> b = bundle_by_name (Config->get_monitor_bus_preferred_bundle());
|
||||
|
||||
if (b) {
|
||||
_monitor_out->output()->connect_ports_to_bundle (b, true, this);
|
||||
} else {
|
||||
warning << string_compose (_("The preferred I/O for the monitor bus (%1) cannot be found"),
|
||||
Config->get_monitor_bus_preferred_bundle())
|
||||
<< endmsg;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* Monitor bus is audio only */
|
||||
|
||||
vector<string> outputs[DataType::num_types];
|
||||
|
||||
for (uint32_t i = 0; i < DataType::num_types; ++i) {
|
||||
_engine.get_physical_outputs (DataType (DataType::Symbol (i)), outputs[i]);
|
||||
}
|
||||
|
||||
uint32_t mod = outputs[DataType::AUDIO].size();
|
||||
uint32_t limit = _monitor_out->n_outputs().get (DataType::AUDIO);
|
||||
|
||||
if (mod != 0) {
|
||||
|
||||
for (uint32_t n = 0; n < limit; ++n) {
|
||||
|
||||
std::shared_ptr<Port> p = _monitor_out->output()->ports().port(DataType::AUDIO, n);
|
||||
string connect_to;
|
||||
if (outputs[DataType::AUDIO].size() > (n % mod)) {
|
||||
connect_to = outputs[DataType::AUDIO][n % mod];
|
||||
}
|
||||
|
||||
if (!connect_to.empty()) {
|
||||
if (_monitor_out->output()->connect (p, connect_to, this)) {
|
||||
error << string_compose (
|
||||
_("cannot connect control output %1 to %2"),
|
||||
n, connect_to)
|
||||
<< endmsg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Session::setup_route_monitor_sends (bool enable, bool need_process_lock)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user