Prevent removal of route inputs when the plugins cannot be configured with the new number. Rework locking so that the process lock is held from the point that a route input is removed until after the processors are reconfigured; fixes #3548.

git-svn-id: svn://localhost/ardour2/branches/3.0@8089 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Carl Hetherington 2010-11-25 23:46:24 +00:00
parent 28c004f4fb
commit 54cbc45a5a
13 changed files with 335 additions and 158 deletions

View File

@ -25,6 +25,7 @@
#include <gtkmm/menushell.h>
#include <gtkmm/menu_elems.h>
#include <gtkmm/window.h>
#include <gtkmm/stock.h>
#include "ardour/bundle.h"
#include "ardour/types.h"
#include "ardour/session.h"
@ -33,6 +34,7 @@
#include "port_matrix.h"
#include "port_matrix_body.h"
#include "port_matrix_component.h"
#include "ardour_dialog.h"
#include "i18n.h"
#include "gui_thread.h"
#include "utils.h"
@ -686,7 +688,16 @@ PortMatrix::remove_channel (ARDOUR::BundleChannel b)
if (io) {
Port* p = io->nth (b.channel);
if (p) {
io->remove_port (p, this);
int const r = io->remove_port (p, this);
if (r == -1) {
ArdourDialog d (_("Port removal not allowed"));
Label l (_("This port cannot be removed, as the first plugin in the track or buss cannot accept the new number of inputs."));
d.get_vbox()->pack_start (l);
d.add_button (Stock::OK, RESPONSE_ACCEPT);
d.set_modal (true);
d.show_all ();
d.run ();
}
}
}
}

View File

@ -801,6 +801,7 @@ ProcessorBox::choose_insert ()
_route->add_processor (processor, _placement);
}
/* Caller must not hold process lock */
void
ProcessorBox::choose_send ()
{
@ -813,6 +814,7 @@ ProcessorBox::choose_send ()
/* XXX need processor lock on route */
try {
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock());
send->output()->ensure_io (outs, false, this);
} catch (AudioEngine::PortRegistrationFailure& err) {
error << string_compose (_("Cannot set up new send: %1"), err.what()) << endmsg;

View File

@ -133,6 +133,7 @@ class IO : public SessionObject, public Latent
const ChanCount& n_ports () const { return _ports.count(); }
/** Emitted with the process lock held */
PBD::Signal2<void,IOChange,void*> changed;
virtual XMLNode& state (bool full);
@ -140,6 +141,31 @@ class IO : public SessionObject, public Latent
int set_state (const XMLNode&, int version);
int set_state_2X (const XMLNode&, int, bool);
class BoolCombiner {
public:
typedef bool result_type;
template <typename Iter>
bool operator() (Iter first, Iter last) const {
bool r = false;
while (first != last) {
if (*first) {
r = true;
}
++first;
}
return r;
}
};
/** Emitted when the port count is about to change. Objects
* can attach to this, and return `true' if they want to prevent
* the change from happening.
*/
PBD::Signal1<bool, ChanCount, BoolCombiner> PortCountChanging;
static int disable_connecting (void);
static int enable_connecting (void);
static int disable_ports (void);

View File

@ -261,6 +261,8 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
PBD::Signal0<void> signal_latency_changed;
PBD::Signal0<void> initial_delay_changed;
PBD::Signal0<void> order_key_changed;
/** Emitted with the process lock held */
PBD::Signal0<void> io_changed;
/* gui's call this for their own purposes. */
@ -473,9 +475,13 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
void input_change_handler (IOChange, void *src);
void output_change_handler (IOChange, void *src);
bool input_port_count_changing (ChanCount);
bool _in_configure_processors;
int configure_processors_unlocked (ProcessorStreams*);
std::list<std::pair<ChanCount, ChanCount> > try_configure_processors (ChanCount, ProcessorStreams *);
std::list<std::pair<ChanCount, ChanCount> > try_configure_processors_unlocked (ChanCount, ProcessorStreams *);
bool add_processor_from_xml_2X (const XMLNode&, int);

View File

@ -176,11 +176,15 @@ Auditioner::audition_region (boost::shared_ptr<Region> region)
}
ProcessorStreams ps;
if (configure_processors (&ps)) {
error << string_compose (_("Cannot setup auditioner processing flow for %1 channels"),
_diskstream->n_channels()) << endmsg;
return;
}
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
if (configure_processors (&ps)) {
error << string_compose (_("Cannot setup auditioner processing flow for %1 channels"),
_diskstream->n_channels()) << endmsg;
return;
}
}
/* force a panner reset now that we have all channels */

View File

@ -35,6 +35,7 @@
#include "ardour/panner.h"
#include "ardour/port.h"
#include "ardour/session.h"
#include "ardour/audioengine.h"
#include "i18n.h"
@ -178,9 +179,12 @@ Delivery::can_support_io_configuration (const ChanCount& in, ChanCount& out) con
return false;
}
/** Caller must hold process lock */
bool
Delivery::configure_io (ChanCount in, ChanCount out)
{
assert (!AudioEngine::instance()->process_lock().trylock());
/* check configuration by comparison with our I/O port configuration, if appropriate.
see ::can_support_io_configuration() for comments
*/

View File

@ -184,38 +184,38 @@ IO::disconnect (Port* our_port, string other_port, void* src)
check_bundles_connected ();
}
changed (IOChange (IOChange::ConnectionsChanged), src); /* EMIT SIGNAL */
}
changed (IOChange (IOChange::ConnectionsChanged), src); /* EMIT SIGNAL */
_session.set_dirty ();
return 0;
}
/** Caller must hold process lock */
int
IO::connect (Port* our_port, string other_port, void* src)
{
assert (!AudioEngine::instance()->process_lock().trylock());
if (other_port.length() == 0 || our_port == 0) {
return 0;
}
{
BLOCK_PROCESS_CALLBACK ();
{
Glib::Mutex::Lock lm (io_lock);
/* check that our_port is really one of ours */
if ( ! _ports.contains(our_port) ) {
return -1;
}
/* connect it to the source */
if (our_port->connect (other_port)) {
return -1;
}
Glib::Mutex::Lock lm (io_lock);
/* check that our_port is really one of ours */
if ( ! _ports.contains(our_port) ) {
return -1;
}
/* connect it to the source */
if (our_port->connect (other_port)) {
return -1;
}
}
@ -227,6 +227,15 @@ IO::connect (Port* our_port, string other_port, void* src)
int
IO::remove_port (Port* port, void* src)
{
ChanCount before = _ports.count ();
ChanCount after = before;
after.set (port->type(), after.get (port->type()) - 1);
bool const r = PortCountChanging (after); /* EMIT SIGNAL */
if (r) {
return -1;
}
IOChange change;
{
@ -235,8 +244,6 @@ IO::remove_port (Port* port, void* src)
{
Glib::Mutex::Lock lm (io_lock);
ChanCount before = _ports.count ();
if (_ports.remove(port)) {
change.type = IOChange::Type (change.type | IOChange::ConfigurationChanged);
change.before = before;
@ -252,19 +259,22 @@ IO::remove_port (Port* port, void* src)
}
PortCountChanged (n_ports()); /* EMIT SIGNAL */
if (change.type != IOChange::NoChange) {
changed (change, src);
_session.set_dirty ();
}
}
if (change.type & IOChange::ConfigurationChanged) {
setup_bundle ();
}
if (change.type != IOChange::NoChange) {
changed (change, src);
_session.set_dirty ();
return 0;
if (change.type == IOChange::NoChange) {
return -1;
}
return -1;
return 0;
}
/** Add a port.
@ -312,6 +322,11 @@ IO::add_port (string destination, void* src, DataType type)
}
PortCountChanged (n_ports()); /* EMIT SIGNAL */
// pan_changed (src); /* EMIT SIGNAL */
change.type = IOChange::ConfigurationChanged;
change.after = _ports.count ();
changed (change, src); /* EMIT SIGNAL */
}
if (destination.length()) {
@ -320,10 +335,6 @@ IO::add_port (string destination, void* src, DataType type)
}
}
// pan_changed (src); /* EMIT SIGNAL */
change.type = IOChange::ConfigurationChanged;
change.after = _ports.count ();
changed (change, src); /* EMIT SIGNAL */
setup_bundle ();
_session.set_dirty ();
@ -333,28 +344,29 @@ IO::add_port (string destination, void* src, DataType type)
int
IO::disconnect (void* src)
{
BLOCK_PROCESS_CALLBACK ();
{
BLOCK_PROCESS_CALLBACK ();
{
Glib::Mutex::Lock lm (io_lock);
for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
i->disconnect_all ();
}
check_bundles_connected ();
Glib::Mutex::Lock lm (io_lock);
for (PortSet::iterator i = _ports.begin(); i != _ports.end(); ++i) {
i->disconnect_all ();
}
check_bundles_connected ();
}
changed (IOChange (IOChange::ConnectionsChanged), src); /* EMIT SIGNAL */
return 0;
}
/** Caller must hold process lock */
bool
IO::ensure_ports_locked (ChanCount count, bool clear, void* /*src*/)
{
assert (!AudioEngine::instance()->process_lock().trylock());
Port* port = 0;
bool changed = false;
@ -419,10 +431,12 @@ IO::ensure_ports_locked (ChanCount count, bool clear, void* /*src*/)
return changed;
}
/** Caller must hold process lock */
int
IO::ensure_ports (ChanCount count, bool clear, void* src)
{
assert (!AudioEngine::instance()->process_lock().trylock());
bool changed = false;
if (count == n_ports() && !clear) {
@ -434,7 +448,6 @@ IO::ensure_ports (ChanCount count, bool clear, void* src)
change.before = _ports.count ();
{
BLOCK_PROCESS_CALLBACK ();
Glib::Mutex::Lock im (io_lock);
changed = ensure_ports_locked (count, clear, src);
}
@ -450,9 +463,12 @@ IO::ensure_ports (ChanCount count, bool clear, void* src)
return 0;
}
/** Caller must hold process lock */
int
IO::ensure_io (ChanCount count, bool clear, void* src)
{
assert (!AudioEngine::instance()->process_lock().trylock());
return ensure_ports (count, clear, src);
}
@ -830,9 +846,13 @@ IO::create_ports (const XMLNode& node, int version)
get_port_counts (node, version, n, c);
if (ensure_ports (n, true, this)) {
error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
return -1;
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
if (ensure_ports (n, true, this)) {
error << string_compose(_("%1: cannot create I/O ports"), _name) << endmsg;
return -1;
}
}
/* XXX use c */
@ -1004,9 +1024,13 @@ IO::set_ports (const string& str)
return 0;
}
// FIXME: audio-only
if (ensure_ports (ChanCount(DataType::AUDIO, nports), true, this)) {
return -1;
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
// FIXME: audio-only
if (ensure_ports (ChanCount(DataType::AUDIO, nports), true, this)) {
return -1;
}
}
string::size_type start, end, ostart;
@ -1158,8 +1182,9 @@ IO::update_port_total_latencies ()
int
IO::connect_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
{
BLOCK_PROCESS_CALLBACK ();
{
BLOCK_PROCESS_CALLBACK ();
Glib::Mutex::Lock lm2 (io_lock);
c->connect (_bundle, _session.engine());
@ -1189,8 +1214,9 @@ IO::connect_ports_to_bundle (boost::shared_ptr<Bundle> c, void* src)
int
IO::disconnect_ports_from_bundle (boost::shared_ptr<Bundle> c, void* src)
{
BLOCK_PROCESS_CALLBACK ();
{
BLOCK_PROCESS_CALLBACK ();
Glib::Mutex::Lock lm2 (io_lock);
c->disconnect (_bundle, _session.engine());

View File

@ -244,17 +244,22 @@ PortInsert::signal_latency() const
}
}
/** Caller must not hold process lock */
bool
PortInsert::configure_io (ChanCount in, ChanCount out)
{
/* for an insert, processor input corresponds to IO output, and vice versa */
if (_input->ensure_io (in, false, this) != 0) {
return false;
}
if (_output->ensure_io (out, false, this) != 0) {
return false;
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
if (_input->ensure_io (in, false, this) != 0) {
return false;
}
if (_output->ensure_io (out, false, this) != 0) {
return false;
}
}
return Processor::configure_io (in, out);

View File

@ -120,6 +120,8 @@ Route::init ()
_input->changed.connect_same_thread (*this, boost::bind (&Route::input_change_handler, this, _1, _2));
_output->changed.connect_same_thread (*this, boost::bind (&Route::output_change_handler, this, _1, _2));
_input->PortCountChanging.connect_same_thread (*this, boost::bind (&Route::input_port_count_changing, this, _1));
/* add amp processor */
_amp.reset (new Amp (_session));
@ -876,13 +878,17 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
// Set up processor list channels. This will set processor->[input|output]_streams(),
// configure redirect ports properly, etc.
if (configure_processors_unlocked (err)) {
ProcessorList::iterator ploc = loc;
--ploc;
_processors.erase(ploc);
configure_processors_unlocked (0); // it worked before we tried to add it ...
cerr << "configure failed\n";
return -1;
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
if (configure_processors_unlocked (err)) {
ProcessorList::iterator ploc = loc;
--ploc;
_processors.erase(ploc);
configure_processors_unlocked (0); // it worked before we tried to add it ...
cerr << "configure failed\n";
return -1;
}
}
if ((pi = boost::dynamic_pointer_cast<PluginInsert>(processor)) != 0) {
@ -1051,10 +1057,13 @@ Route::add_processors (const ProcessorList& others, ProcessorList::iterator iter
(*i)->activate ();
}
if (configure_processors_unlocked (err)) {
_processors.erase (inserted);
configure_processors_unlocked (0); // it worked before we tried to add it ...
return -1;
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
if (configure_processors_unlocked (err)) {
_processors.erase (inserted);
configure_processors_unlocked (0); // it worked before we tried to add it ...
return -1;
}
}
(*i)->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false, false));
@ -1259,7 +1268,11 @@ Route::clear_processors (Placement p)
}
_processors = new_list;
configure_processors_unlocked (&err); // this can't fail
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
configure_processors_unlocked (&err); // this can't fail
}
}
processor_max_streams.reset();
@ -1333,12 +1346,16 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
return 1;
}
if (configure_processors_unlocked (err)) {
/* get back to where we where */
_processors.insert (i, processor);
/* we know this will work, because it worked before :) */
configure_processors_unlocked (0);
return -1;
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
if (configure_processors_unlocked (err)) {
/* get back to where we where */
_processors.insert (i, processor);
/* we know this will work, because it worked before :) */
configure_processors_unlocked (0);
return -1;
}
}
_have_internal_generator = false;
@ -1420,12 +1437,16 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
_output->set_user_latency (0);
if (configure_processors_unlocked (err)) {
/* get back to where we where */
_processors = as_we_were;
/* we know this will work, because it worked before :) */
configure_processors_unlocked (0);
return -1;
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
if (configure_processors_unlocked (err)) {
/* get back to where we where */
_processors = as_we_were;
/* we know this will work, because it worked before :) */
configure_processors_unlocked (0);
return -1;
}
}
_have_internal_generator = false;
@ -1454,10 +1475,12 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams*
return 0;
}
/** Caller must hold process lock */
int
Route::configure_processors (ProcessorStreams* err)
{
assert (!AudioEngine::instance()->process_lock().trylock());
if (!_in_configure_processors) {
Glib::RWLock::WriterLock lm (_processor_lock);
return configure_processors_unlocked (err);
@ -1471,22 +1494,20 @@ Route::input_streams () const
return _input->n_ports ();
}
/** Configure the input/output configuration of each processor in the processors list.
* Return 0 on success, otherwise configuration is impossible.
*/
int
Route::configure_processors_unlocked (ProcessorStreams* err)
list<pair<ChanCount, ChanCount> >
Route::try_configure_processors (ChanCount in, ProcessorStreams* err)
{
if (_in_configure_processors) {
return 0;
}
Glib::RWLock::ReaderLock lm (_processor_lock);
_in_configure_processors = true;
return try_configure_processors_unlocked (in, err);
}
list<pair<ChanCount, ChanCount> >
Route::try_configure_processors_unlocked (ChanCount in, ProcessorStreams* err)
{
// Check each processor in order to see if we can configure as requested
ChanCount in = input_streams ();
ChanCount out;
list< pair<ChanCount,ChanCount> > configuration;
list<pair<ChanCount, ChanCount> > configuration;
uint32_t index = 0;
DEBUG_TRACE (DEBUG::Processors, string_compose ("%1: configure processors\n", _name));
@ -1507,12 +1528,37 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
err->index = index;
err->count = in;
}
_in_configure_processors = false;
return -1;
return list<pair<ChanCount, ChanCount> > ();
}
}
// We can, so configure everything
return configuration;
}
/** Set the input/output configuration of each processor in the processors list.
* Caller must hold process lock.
* Return 0 on success, otherwise configuration is impossible.
*/
int
Route::configure_processors_unlocked (ProcessorStreams* err)
{
assert (!AudioEngine::instance()->process_lock().trylock());
if (_in_configure_processors) {
return 0;
}
_in_configure_processors = true;
list<pair<ChanCount, ChanCount> > configuration = try_configure_processors_unlocked (input_streams (), err);
if (configuration.empty ()) {
_in_configure_processors = false;
return -1;
}
ChanCount out;
list< pair<ChanCount,ChanCount> >::iterator c = configuration.begin();
for (ProcessorList::iterator p = _processors.begin(); p != _processors.end(); ++p, ++c) {
(*p)->configure_io(c->first, c->second);
@ -1527,10 +1573,7 @@ Route::configure_processors_unlocked (ProcessorStreams* err)
/* make sure we have sufficient scratch buffers to cope with the new processor
configuration */
{
Glib::Mutex::Lock em (_session.engine().process_lock ());
_session.ensure_buffers (n_process_buffers ());
}
_session.ensure_buffers (n_process_buffers ());
DEBUG_TRACE (DEBUG::Processors, string_compose ("%1: configuration complete\n", _name));
@ -1686,10 +1729,14 @@ Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err
_processors.insert (oiter, as_it_will_be.begin(), as_it_will_be.end());
if (configure_processors_unlocked (err)) {
_processors = as_it_was_before;
processor_max_streams = old_pms;
return -1;
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
if (configure_processors_unlocked (err)) {
_processors = as_it_was_before;
processor_max_streams = old_pms;
return -1;
}
}
}
@ -2335,6 +2382,7 @@ Route::set_processor_state (const XMLNode& node)
Glib::RWLock::WriterLock lm (_processor_lock);
_processors = new_order;
if (must_configure) {
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
configure_processors_unlocked (0);
}
}
@ -2647,6 +2695,7 @@ Route::handle_transport_stopped (bool /*abort_ignored*/, bool did_locate, bool c
_roll_delay = _initial_delay;
}
/** Called with the process lock held */
void
Route::input_change_handler (IOChange change, void * /*src*/)
{
@ -2657,6 +2706,7 @@ Route::input_change_handler (IOChange change, void * /*src*/)
}
}
/** Called with the process lock held */
void
Route::output_change_handler (IOChange change, void * /*src*/)
{
@ -2958,10 +3008,14 @@ Route::put_monitor_send_at (Placement p)
_processors.insert (loc, _monitor_send);
if (configure_processors_unlocked (0)) {
_processors = as_it_was;
configure_processors_unlocked (0); // it worked before we tried to add it ...
return;
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
if (configure_processors_unlocked (0)) {
_processors = as_it_was;
configure_processors_unlocked (0); // it worked before we tried to add it ...
return;
}
}
}
@ -3456,3 +3510,20 @@ Route::set_processor_positions ()
}
}
/** Called when there is a proposed change to the input port count */
bool
Route::input_port_count_changing (ChanCount to)
{
list<pair<ChanCount, ChanCount> > c = try_configure_processors (to, 0);
if (c.empty()) {
/* The processors cannot be configured with the new input arrangement, so
block the change.
*/
return true;
}
/* The change is ok */
return false;
}

View File

@ -217,6 +217,7 @@ Send::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
return true;
}
/** Caller must not hold process lock */
bool
Send::configure_io (ChanCount in, ChanCount out)
{
@ -225,6 +226,7 @@ Send::configure_io (ChanCount in, ChanCount out)
}
if (_output) {
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock());
_output->ensure_io (out, false, 0);
}

View File

@ -1504,6 +1504,7 @@ Session::count_existing_route_channels (ChanCount& in, ChanCount& out)
}
}
/** Caller must not hold process lock */
list<boost::shared_ptr<MidiTrack> >
Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_many)
{
@ -1541,15 +1542,17 @@ Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_m
boost_debug_shared_ptr_mark_interesting (mt, "Track");
track = boost::shared_ptr<MidiTrack>(mt);
if (track->input()->ensure_io (ChanCount(DataType::MIDI, 1), false, this)) {
error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg;
goto failed;
}
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
if (track->input()->ensure_io (ChanCount(DataType::MIDI, 1), false, this)) {
error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg;
goto failed;
}
if (track->output()->ensure_io (ChanCount(DataType::MIDI, 1), false, this)) {
error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg;
goto failed;
if (track->output()->ensure_io (ChanCount(DataType::MIDI, 1), false, this)) {
error << "cannot configure 1 in/1 out configuration for new midi track" << endmsg;
goto failed;
}
}
auto_connect_route (track.get(), existing_inputs, existing_outputs);
@ -1590,7 +1593,8 @@ Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_m
return ret;
}
/** @param connect_inputs true to connect inputs as well as outputs, false to connect just outputs.
/** Caller must hold process lock.
* @param connect_inputs true to connect inputs as well as outputs, false to connect just outputs.
* @param input_start Where to start from when auto-connecting inputs; e.g. if this is 0, auto-connect starting from input 0.
* @param output_start As \a input_start, but for outputs.
*/
@ -1669,6 +1673,7 @@ Session::auto_connect_route (
existing_outputs += route->n_outputs();
}
/** Caller must not hold process lock */
list< boost::shared_ptr<AudioTrack> >
Session::new_audio_track (int input_channels, int output_channels, TrackMode mode, RouteGroup* route_group, uint32_t how_many)
{
@ -1706,23 +1711,27 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
boost_debug_shared_ptr_mark_interesting (at, "Track");
track = boost::shared_ptr<AudioTrack>(at);
if (track->input()->ensure_io (ChanCount(DataType::AUDIO, input_channels), false, this)) {
error << string_compose (
_("cannot configure %1 in/%2 out configuration for new audio track"),
input_channels, output_channels)
<< endmsg;
goto failed;
}
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
if (track->output()->ensure_io (ChanCount(DataType::AUDIO, output_channels), false, this)) {
error << string_compose (
_("cannot configure %1 in/%2 out configuration for new audio track"),
input_channels, output_channels)
<< endmsg;
goto failed;
}
if (track->input()->ensure_io (ChanCount(DataType::AUDIO, input_channels), false, this)) {
error << string_compose (
_("cannot configure %1 in/%2 out configuration for new audio track"),
input_channels, output_channels)
<< endmsg;
goto failed;
}
if (track->output()->ensure_io (ChanCount(DataType::AUDIO, output_channels), false, this)) {
error << string_compose (
_("cannot configure %1 in/%2 out configuration for new audio track"),
input_channels, output_channels)
<< endmsg;
goto failed;
}
auto_connect_route (track.get(), existing_inputs, existing_outputs);
auto_connect_route (track.get(), existing_inputs, existing_outputs);
}
if (route_group) {
route_group->add (track);
@ -1787,7 +1796,7 @@ Session::set_remote_control_ids ()
}
}
/** Caller must not hold process lock */
RouteList
Session::new_audio_route (bool aux, int input_channels, int output_channels, RouteGroup* route_group, uint32_t how_many)
{
@ -1820,23 +1829,27 @@ Session::new_audio_route (bool aux, int input_channels, int output_channels, Rou
boost_debug_shared_ptr_mark_interesting (rt, "Route");
shared_ptr<Route> bus (rt);
if (bus->input()->ensure_io (ChanCount(DataType::AUDIO, input_channels), false, this)) {
error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
input_channels, output_channels)
<< endmsg;
goto failure;
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
if (bus->input()->ensure_io (ChanCount(DataType::AUDIO, input_channels), false, this)) {
error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
input_channels, output_channels)
<< endmsg;
goto failure;
}
if (bus->output()->ensure_io (ChanCount(DataType::AUDIO, output_channels), false, this)) {
error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
input_channels, output_channels)
<< endmsg;
goto failure;
}
auto_connect_route (bus.get(), existing_inputs, existing_outputs, false);
}
if (bus->output()->ensure_io (ChanCount(DataType::AUDIO, output_channels), false, this)) {
error << string_compose (_("cannot configure %1 in/%2 out configuration for new audio track"),
input_channels, output_channels)
<< endmsg;
goto failure;
}
auto_connect_route (bus.get(), existing_inputs, existing_outputs, false);
if (route_group) {
route_group->add (bus);
}

View File

@ -510,6 +510,7 @@ Session::ensure_subdirs ()
return 0;
}
/** Caller must not hold process lock */
int
Session::create (const string& mix_template, BusProfile* bus_profile)
{
@ -578,8 +579,11 @@ Session::create (const string& mix_template, BusProfile* bus_profile)
}
boost_debug_shared_ptr_mark_interesting (rt, "Route");
boost::shared_ptr<Route> r (rt);
r->input()->ensure_io (count, false, this);
r->output()->ensure_io (count, false, this);
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
r->input()->ensure_io (count, false, this);
r->output()->ensure_io (count, false, this);
}
r->set_remote_control_id (control_id++);
rl.push_back (r);
@ -592,8 +596,11 @@ Session::create (const string& mix_template, BusProfile* bus_profile)
}
boost_debug_shared_ptr_mark_interesting (rt, "Route");
boost::shared_ptr<Route> r (rt);
r->input()->ensure_io (count, false, this);
r->output()->ensure_io (count, false, this);
{
Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
r->input()->ensure_io (count, false, this);
r->output()->ensure_io (count, false, this);
}
r->set_remote_control_id (control_id);
rl.push_back (r);

View File

@ -110,11 +110,11 @@ private:
SignalType _signal;
};
template<typename R, typename A>
template<typename R, typename A, typename C = boost::signals2::optional_last_value<R> >
class Signal1 {
public:
Signal1 () {}
typedef boost::signals2::signal<R(A)> SignalType;
typedef boost::signals2::signal<R(A), C> SignalType;
void connect_same_thread (ScopedConnectionList& clist,
const typename SignalType::slot_function_type& slot) {