Auto-connect master/monitor when switching backends

This commit is contained in:
Robin Gareus 2023-05-26 22:30:46 +02:00
parent aaf3013211
commit d5cc5b0586
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
7 changed files with 136 additions and 69 deletions

View File

@ -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;

View File

@ -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; }

View File

@ -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);

View File

@ -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
{

View File

@ -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
}
}
}

View File

@ -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);

View File

@ -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)
{