reverse prior commit, which causes a deadlock between IO::enable_connecting() and...
[ardour.git] / libs / ardour / route.cc
index f39b094ccd97ffc4143e6db906d1b01b1a51a36c..6a7ddde48b9e6324798515d486a865cc10260cb7 100644 (file)
@@ -108,6 +108,13 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
 {
        processor_max_streams.reset();
        order_keys[N_("signal")] = order_key_cnt++;
+
+       if (is_master()) {
+               set_remote_control_id (MasterBusRemoteControlID);
+       } else if (is_monitor()) {
+               set_remote_control_id (MonitorBusRemoteControlID);
+       }
+               
 }
 
 int
@@ -207,6 +214,26 @@ Route::~Route ()
 void
 Route::set_remote_control_id (uint32_t id, bool notify_class_listeners)
 {
+       /* force IDs for master/monitor busses and prevent 
+          any other route from accidentally getting these IDs
+          (i.e. legacy sessions)
+       */
+
+       if (is_master() && id != MasterBusRemoteControlID) {
+               id = MasterBusRemoteControlID;
+       }
+
+       if (is_monitor() && id != MonitorBusRemoteControlID) {
+               id = MonitorBusRemoteControlID;
+       }
+
+       /* don't allow it to collide */
+
+       if (!is_master () && !is_monitor() && 
+           (id == MasterBusRemoteControlID || id == MonitorBusRemoteControlID)) {
+               id += MonitorBusRemoteControlID;
+       }
+
        if (id != _remote_control_id) {
                _remote_control_id = id;
                RemoteControlIDChanged ();
@@ -400,8 +427,6 @@ Route::process_output_buffers (BufferSet& bufs,
                               framepos_t start_frame, framepos_t end_frame, pframes_t nframes,
                               int declick, bool gain_automation_ok)
 {
-       bool monitor = should_monitor ();
-
        bufs.set_is_silent (false);
 
        /* figure out if we're going to use gain automation */
@@ -411,8 +436,11 @@ Route::process_output_buffers (BufferSet& bufs,
                _amp->apply_gain_automation (false);
        }
 
-       /* tell main outs what to do about monitoring */
-       _main_outs->no_outs_cuz_we_no_monitor (!monitor);
+       /* Tell main outs what to do about monitoring.  We do this so that
+          on a transition between monitoring states we get a de-clicking gain
+          change in the _main_outs delivery.
+       */
+       _main_outs->no_outs_cuz_we_no_monitor (monitoring_state () == MonitoringSilence);
 
 
        /* -------------------------------------------------------------------------------------------
@@ -478,12 +506,20 @@ Route::process_output_buffers (BufferSet& bufs,
           and go ....
           ----------------------------------------------------------------------------------------- */
 
+       /* set this to be true if the meter will already have been ::run() earlier */
+       bool const meter_already_run = metering_state() == MeteringInput;
+
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
 
                if (boost::dynamic_pointer_cast<UnknownProcessor> (*i)) {
                        break;
                }
 
+               if (boost::dynamic_pointer_cast<PeakMeter> (*i) && meter_already_run) {
+                       /* don't ::run() the meter, otherwise it will have its previous peak corrupted */
+                       continue;
+               }
+               
 #ifndef NDEBUG
                /* if it has any inputs, make sure they match */
                if ((*i)->input_streams() != ChanCount::ZERO) {
@@ -495,6 +531,7 @@ Route::process_output_buffers (BufferSet& bufs,
                        }
                }
 #endif
+
                /* should we NOT run plugins here if the route is inactive?
                   do we catch route != active somewhere higher?
                */
@@ -1320,7 +1357,7 @@ Route::clear_processors (Placement p)
 }
 
 int
-Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* err)
+Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStreams* err, bool need_process_lock)
 {
        /* these can never be removed */
 
@@ -1378,11 +1415,18 @@ Route::remove_processor (boost::shared_ptr<Processor> processor, ProcessorStream
                if (!removed) {
                        /* what? */
                        return 1;
-               }
+               } 
 
-               {
+               if (need_process_lock) {
                        Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
 
+                       if (configure_processors_unlocked (err)) {
+                               pstate.restore ();
+                               /* we know this will work, because it worked before :) */
+                               configure_processors_unlocked (0);
+                               return -1;
+                       }
+               } else {
                        if (configure_processors_unlocked (err)) {
                                pstate.restore ();
                                /* we know this will work, because it worked before :) */
@@ -2521,6 +2565,7 @@ Route::add_send_to_internal_return (InternalSend* send)
 void
 Route::remove_send_from_internal_return (InternalSend* send)
 {
+       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
        Glib::RWLock::ReaderLock rm (_processor_lock);
 
        for (ProcessorList::const_iterator x = _processors.begin(); x != _processors.end(); ++x) {
@@ -2532,11 +2577,13 @@ Route::remove_send_from_internal_return (InternalSend* send)
        }
 }
 
-/** Add a monitor send (if we don't already have one) but don't activate it */
-int
-Route::listen_via_monitor ()
+void
+Route::enable_monitor_send ()
 {
-       /* master never sends to control outs */
+       /* Caller must hold process lock */
+       assert (!AudioEngine::instance()->process_lock().trylock());
+
+       /* master never sends to monitor section via the normal mechanism */
        assert (!is_master ());
 
        /* make sure we have one */
@@ -2546,18 +2593,15 @@ Route::listen_via_monitor ()
        }
 
        /* set it up */
-       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
        configure_processors (0);
-
-       return 0;
 }
 
-/** Add an internal send to a route.
+/** Add an aux send to a route.
  *  @param route route to send to.
  *  @param placement placement for the send.
  */
 int
-Route::listen_via (boost::shared_ptr<Route> route, Placement placement)
+Route::add_aux_send (boost::shared_ptr<Route> route, Placement placement)
 {
        assert (route != _session.monitor_out ());
 
@@ -2576,7 +2620,14 @@ Route::listen_via (boost::shared_ptr<Route> route, Placement placement)
        }
 
        try {
-               boost::shared_ptr<InternalSend> listener (new InternalSend (_session, _pannable, _mute_master, route, Delivery::Aux));
+
+               boost::shared_ptr<InternalSend> listener;
+
+               {
+                       Glib::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                       listener.reset (new InternalSend (_session, _pannable, _mute_master, route, Delivery::Aux));
+               }
+
                add_processor (listener, placement);
 
        } catch (failed_constructor& err) {
@@ -2587,36 +2638,39 @@ Route::listen_via (boost::shared_ptr<Route> route, Placement placement)
 }
 
 void
-Route::drop_listen (boost::shared_ptr<Route> route)
+Route::remove_aux_or_listen (boost::shared_ptr<Route> route)
 {
        ProcessorStreams err;
        ProcessorList::iterator tmp;
 
-       Glib::RWLock::ReaderLock rl(_processor_lock);
-       rl.acquire ();
-
-  again:
-       for (ProcessorList::iterator x = _processors.begin(); x != _processors.end(); ) {
-
-               boost::shared_ptr<InternalSend> d = boost::dynamic_pointer_cast<InternalSend>(*x);
-
-               if (d && d->target_route() == route) {
-                       rl.release ();
-                       remove_processor (*x, &err);
-                       rl.acquire ();
+       {
+               Glib::RWLock::ReaderLock rl(_processor_lock);
 
-                       /* list could have been demolished while we dropped the lock
-                          so start over.
-                       */
+               /* have to do this early because otherwise processor reconfig
+                * will put _monitor_send back in the list
+                */
 
-                       goto again;
+               if (route == _session.monitor_out()) {
+                       _monitor_send.reset ();
                }
-       }
 
-       rl.release ();
+         again:
+               for (ProcessorList::iterator x = _processors.begin(); x != _processors.end(); ++x) {
+                       
+                       boost::shared_ptr<InternalSend> d = boost::dynamic_pointer_cast<InternalSend>(*x);
+                       
+                       if (d && d->target_route() == route) {
+                               rl.release ();
+                               remove_processor (*x, &err, false);
+                               rl.acquire ();
 
-       if (route == _session.monitor_out()) {
-               _monitor_send.reset ();
+                               /* list could have been demolished while we dropped the lock
+                                  so start over.
+                               */
+                               
+                               goto again;
+                       }
+               }
        }
 }
 
@@ -3846,21 +3900,6 @@ Route::setup_invisible_processors ()
        }
 }
 
-bool
-Route::should_monitor () const
-{
-       switch (Config->get_monitoring_model()) {
-       case HardwareMonitoring:
-       case ExternalMonitoring:
-               return !record_enabled() || (_session.config.get_auto_input() && !_session.actively_recording());
-               break;
-       default:
-               break;
-       }
-
-       return true;
-}
-
 void
 Route::unpan ()
 {
@@ -3918,3 +3957,21 @@ Route::processor_by_id (PBD::ID id) const
 
        return boost::shared_ptr<Processor> ();
 }
+
+/** @return the monitoring state, or in other words what data we are pushing
+ *  into the route (data from the inputs, data from disk or silence)
+ */
+MonitorState
+Route::monitoring_state () const
+{
+       return MonitoringInput;
+}
+
+/** @return what we should be metering; either the data coming from the input
+ *  IO or the data that is flowing through the route.
+ */
+MeterState
+Route::metering_state () const
+{
+       return MeteringRoute;
+}