diff options
author | Robin Gareus <robin@gareus.org> | 2013-08-02 23:02:13 +0200 |
---|---|---|
committer | Robin Gareus <robin@gareus.org> | 2013-08-03 00:51:07 +0200 |
commit | 23eba1cc392aa5b583ddb4229a227557a88ef1cd (patch) | |
tree | 48a722925856840c9d6c23a0345994f1452468c7 /libs | |
parent | 94f366190e044462bd907de2d96f0d34b275b080 (diff) |
disallow invalid port-removal
do not allow port-removal if the port would be re-added immediately
after that again because the main-delivery actually needs it.
As a side effect this prevents this crash:
* create a stereo-track, then remove one output
-> unhandled exception "AudioEngine::PortRegistrationFailure&"
The problem:
- the port is removed from the RCU ports list,
but Port::drop() (which calls jack_port_unregister) is only called
from the Port's destructor at some later time.
(because a reference to the port still exists elsewhere)
- the jack-port is not yet removed.
- meanwhile Delivery::configure_io comes along and notices that
there are more audio-buffers than ports and tries to re-register the port.
- but the port still exists in jack, so it fails and throws an exception
...which is not handled.
Diffstat (limited to 'libs')
-rw-r--r-- | libs/ardour/ardour/route.h | 2 | ||||
-rw-r--r-- | libs/ardour/route.cc | 29 |
2 files changed, 31 insertions, 0 deletions
diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index 2e44d00984..f0987fa77e 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -530,6 +530,7 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember, void silence_unlocked (framecnt_t); ChanCount processor_max_streams; + ChanCount processor_out_streams; uint32_t pans_required() const; ChanCount n_process_buffers (); @@ -553,6 +554,7 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember, void output_change_handler (IOChange, void *src); bool input_port_count_changing (ChanCount); + bool output_port_count_changing (ChanCount); bool _in_configure_processors; diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index b78217ff49..125bcf12d6 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -136,6 +136,7 @@ Route::init () _input->PortCountChanging.connect_same_thread (*this, boost::bind (&Route::input_port_count_changing, this, _1)); _output->changed.connect_same_thread (*this, boost::bind (&Route::output_change_handler, this, _1, _2)); + _output->PortCountChanging.connect_same_thread (*this, boost::bind (&Route::output_port_count_changing, this, _1)); /* add amp processor */ @@ -1704,6 +1705,8 @@ Route::configure_processors_unlocked (ProcessorStreams* err) } ChanCount out; + bool seen_mains_out = false; + processor_out_streams = _input->n_ports(); list< pair<ChanCount,ChanCount> >::iterator c = configuration.begin(); for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++c) { @@ -1716,8 +1719,21 @@ Route::configure_processors_unlocked (ProcessorStreams* err) processor_max_streams = ChanCount::max(processor_max_streams, c->first); processor_max_streams = ChanCount::max(processor_max_streams, c->second); out = c->second; + + if (boost::dynamic_pointer_cast<Delivery> (*p) + && boost::dynamic_pointer_cast<Delivery> (*p)->role() == Delivery::Main) { + /* main delivery will increase port count to match input. + * the Delivery::Main is usually the last processor - followed only by + * 'MeterOutput'. + */ + seen_mains_out = true; + } + if (!seen_mains_out) { + processor_out_streams = out; + } } + if (_meter) { _meter->reset_max_channels (processor_max_streams); } @@ -3754,6 +3770,19 @@ Route::input_port_count_changing (ChanCount to) return false; } +/** Called when there is a proposed change to the output port count */ +bool +Route::output_port_count_changing (ChanCount to) +{ + for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) { + if (processor_out_streams.get(*t) > to.get(*t)) { + return true; + } + } + /* The change is ok */ + return false; +} + list<string> Route::unknown_processors () const { |