13
0

WebSockets: properly release strips and plugins when removed

This should fix some crashes reported by the beta testing team
This commit is contained in:
Luciano Iam 2020-08-02 15:41:36 +02:00 committed by Robin Gareus
parent b298f44468
commit f007ba6b46
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
2 changed files with 76 additions and 13 deletions

View File

@ -115,7 +115,20 @@ int
ArdourFeedback::stop ()
{
_periodic_connection.disconnect ();
_signal_connections.drop_connections ();
_transport_connections.drop_connections ();
for (StripConnectionMap::iterator it = _strip_connections.begin (); it != _strip_connections.end(); ++it) {
it->second->drop_connections ();
}
_strip_connections.clear();
for (PluginConnectionMap::iterator it = _plugin_connections.begin (); it != _plugin_connections.end(); ++it) {
it->second->drop_connections ();
}
_plugin_connections.clear();
return 0;
}
@ -182,11 +195,11 @@ void
ArdourFeedback::observe_transport ()
{
ARDOUR::Session& sess = session ();
sess.TransportStateChange.connect (_signal_connections, MISSING_INVALIDATOR,
sess.TransportStateChange.connect (_transport_connections, MISSING_INVALIDATOR,
boost::bind<void> (TransportObserver (), this), event_loop ());
sess.RecordStateChanged.connect (_signal_connections, MISSING_INVALIDATOR,
sess.RecordStateChanged.connect (_transport_connections, MISSING_INVALIDATOR,
boost::bind<void> (RecordStateObserver (), this), event_loop ());
sess.tempo_map ().PropertyChanged.connect (_signal_connections, MISSING_INVALIDATOR,
sess.tempo_map ().PropertyChanged.connect (_transport_connections, MISSING_INVALIDATOR,
boost::bind<void> (TempoObserver (), this), event_loop ());
}
@ -196,16 +209,23 @@ ArdourFeedback::observe_mixer ()
for (uint32_t strip_n = 0; strip_n < mixer ().strip_count (); ++strip_n) {
boost::shared_ptr<Stripable> strip = mixer ().nth_strip (strip_n);
strip->gain_control ()->Changed.connect (_signal_connections, MISSING_INVALIDATOR,
std::unique_ptr<PBD::ScopedConnectionList> connections (new PBD::ScopedConnectionList());
strip->gain_control ()->Changed.connect (*connections, MISSING_INVALIDATOR,
boost::bind<void> (StripGainObserver (), this, strip_n), event_loop ());
if (strip->pan_azimuth_control ()) {
strip->pan_azimuth_control ()->Changed.connect (_signal_connections, MISSING_INVALIDATOR,
strip->pan_azimuth_control ()->Changed.connect (*connections, MISSING_INVALIDATOR,
boost::bind<void> (StripPanObserver (), this, strip_n), event_loop ());
}
strip->mute_control ()->Changed.connect (_signal_connections, MISSING_INVALIDATOR,
strip->mute_control ()->Changed.connect (*connections, MISSING_INVALIDATOR,
boost::bind<void> (StripMuteObserver (), this, strip_n), event_loop ());
strip->DropReferences.connect (*connections, MISSING_INVALIDATOR,
boost::bind (&ArdourFeedback::on_drop_strip, this, strip_n), event_loop ());
_strip_connections[strip_n] = std::move (connections);
observe_strip_plugins (strip_n, strip);
}
@ -220,15 +240,22 @@ ArdourFeedback::observe_strip_plugins (uint32_t strip_n, boost::shared_ptr<ARDOU
break;
}
uint32_t bypass = insert->plugin ()->designated_bypass_port ();
Evoral::Parameter param = Evoral::Parameter (PluginAutomation, 0, bypass);
boost::shared_ptr<AutomationControl> control = insert->automation_control (param);
uint32_t bypass = insert->plugin ()->designated_bypass_port ();
Evoral::Parameter param = Evoral::Parameter (PluginAutomation, 0, bypass);
boost::shared_ptr<AutomationControl> control = insert->automation_control (param);
std::unique_ptr<PBD::ScopedConnectionList> connections (new PBD::ScopedConnectionList());
if (control) {
control->Changed.connect (_signal_connections, MISSING_INVALIDATOR,
control->Changed.connect (*connections, MISSING_INVALIDATOR,
boost::bind<void> (PluginBypassObserver (), this, strip_n, plugin_n), event_loop ());
}
insert->DropReferences.connect (*connections, MISSING_INVALIDATOR,
boost::bind (&ArdourFeedback::on_drop_plugin, this, strip_n, plugin_n), event_loop ());
// assume each strip can hold up to 65535 plugins
_plugin_connections[(strip_n << 16) | plugin_n] = std::move (connections);
observe_strip_plugin_param_values (strip_n, plugin_n, insert);
}
}
@ -247,9 +274,35 @@ ArdourFeedback::observe_strip_plugin_param_values (uint32_t strip_n,
continue;
}
control->Changed.connect (_signal_connections, MISSING_INVALIDATOR,
PBD::ScopedConnectionList *connections = _plugin_connections[(strip_n << 16) | plugin_n].get();
control->Changed.connect (*connections, MISSING_INVALIDATOR,
boost::bind<void> (PluginParamValueObserver (), this, strip_n, plugin_n, param_n,
boost::weak_ptr<AutomationControl>(control)),
event_loop ());
}
}
void
ArdourFeedback::on_drop_strip (uint32_t strip_n)
{
for (uint32_t plugin_n = 0;; ++plugin_n) {
boost::shared_ptr<PluginInsert> insert = mixer ().strip_plugin_insert (strip_n, plugin_n);
if (!insert) {
break;
}
on_drop_plugin (strip_n, plugin_n);
}
_strip_connections[strip_n]->drop_connections ();
_strip_connections.erase (strip_n);
}
void
ArdourFeedback::on_drop_plugin (uint32_t strip_n, uint32_t plugin_n)
{
uint32_t key = (strip_n << 16) | plugin_n;
_plugin_connections[key]->drop_connections ();
_plugin_connections.erase (key);
}

View File

@ -20,6 +20,7 @@
#define _ardour_surface_websockets_feedback_h_
#include <boost/shared_ptr.hpp>
#include <boost/unordered_map.hpp>
#include <glibmm/main.h>
#include "component.h"
@ -42,9 +43,15 @@ public:
private:
Glib::Threads::Mutex _client_state_lock;
PBD::ScopedConnectionList _signal_connections;
PBD::ScopedConnectionList _transport_connections;
sigc::connection _periodic_connection;
typedef boost::unordered_map<uint32_t, std::unique_ptr<PBD::ScopedConnectionList>> StripConnectionMap;
StripConnectionMap _strip_connections;
typedef boost::unordered_map<uint32_t, std::unique_ptr<PBD::ScopedConnectionList>> PluginConnectionMap;
StripConnectionMap _plugin_connections; // also holds connections to parameters
bool poll () const;
void observe_transport ();
@ -52,6 +59,9 @@ private:
void observe_strip_plugins (uint32_t, boost::shared_ptr<ARDOUR::Stripable>);
void observe_strip_plugin_param_values (uint32_t, uint32_t,
boost::shared_ptr<ARDOUR::PluginInsert>);
void on_drop_strip (uint32_t);
void on_drop_plugin (uint32_t, uint32_t);
};
#endif // _ardour_surface_websockets_feedback_h_