Fix latency compensation race-condition
authorRobin Gareus <robin@gareus.org>
Fri, 25 Oct 2019 23:06:04 +0000 (01:06 +0200)
committerRobin Gareus <robin@gareus.org>
Fri, 25 Oct 2019 23:06:04 +0000 (01:06 +0200)
Remove need for explicit `initialize_latencies` call that used
to be called from GUI-thread post_engine_init(), as well as
Session::engine_running().

Further reduce calls, `graph_reordered` implies a latency-update
and fix ordering issue. update_latency_compensation() must be called
*after* resort_routes().

libs/ardour/ardour/session.h
libs/ardour/session.cc
libs/ardour/session_state.cc
libs/ardour/session_transport.cc

index 09d1c60a2bcb9487efc5b5a184e756c4297bc9b2..cb2e781ecf4b7112975fbd6b3b5e8eb0fb3c3fa5 100644 (file)
@@ -1314,7 +1314,6 @@ private:
        void add_monitor_section ();
        void remove_monitor_section ();
 
-       void initialize_latencies ();
        void update_latency (bool playback);
        bool update_route_latency (bool reverse, bool apply_to_delayline);
 
index 13b1abfdf79f17b5db5543e52c82ae80f53396ea..6d698988f3400a13d61c0e55bb5ea74d27cedee1 100644 (file)
@@ -3016,9 +3016,6 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output
 
        graph_reordered ();
 
-       update_latency (false);
-       update_latency (true);
-
        set_dirty();
 
        if (save) {
@@ -5222,7 +5219,7 @@ Session::graph_reordered ()
        /* force all diskstreams to update their capture offset values to
         * reflect any changes in latencies within the graph.
         */
-       update_route_latency (false, true);
+       update_latency_compensation (true);
 }
 
 /** @return Number of samples that there is disk space available to write,
@@ -6387,7 +6384,11 @@ restart:
 void
 Session::update_latency (bool playback)
 {
-       DEBUG_TRACE (DEBUG::Latency, string_compose ("JACK latency callback: %1\n", (playback ? "PLAYBACK" : "CAPTURE")));
+       /* called only from AudioEngine::latency_callback.
+        * but may indirectly be triggered from
+        * Session::update_latency_compensation -> _engine.update_latencies
+        */
+       DEBUG_TRACE (DEBUG::LatencyCompensation, string_compose ("Engine latency callback: %1\n", (playback ? "PLAYBACK" : "CAPTURE")));
 
        if (inital_connect_or_deletion_in_progress () || _adding_routes_in_progress || _route_deletion_in_progress) {
                return;
@@ -6412,32 +6413,24 @@ Session::update_latency (bool playback)
        }
 
        if (playback) {
+               Glib::Threads::Mutex::Lock lx (_update_latency_lock);
                set_worst_output_latency ();
                update_route_latency (true, true);
        } else {
+               Glib::Threads::Mutex::Lock lx (_update_latency_lock);
                set_worst_input_latency ();
                update_route_latency (false, false);
        }
 
-       DEBUG_TRACE (DEBUG::Latency, "JACK latency callback: DONE\n");
+       DEBUG_TRACE (DEBUG::LatencyCompensation, "Engine latency callback: DONE\n");
        LatencyUpdated (); /* EMIT SIGNAL */
 }
 
-void
-Session::initialize_latencies ()
-{
-       {
-               Glib::Threads::Mutex::Lock lm (_engine.process_lock());
-               update_latency (false);
-               update_latency (true);
-       }
-
-       set_worst_io_latencies ();
-}
-
 void
 Session::set_worst_io_latencies ()
 {
+       DEBUG_TRACE (DEBUG::LatencyCompensation, "Session::set_worst_io_latencies\n");
+       Glib::Threads::Mutex::Lock lx (_update_latency_lock);
        set_worst_output_latency ();
        set_worst_input_latency ();
 }
@@ -6463,7 +6456,7 @@ Session::set_worst_output_latency ()
 
        _worst_output_latency = max (_worst_output_latency, _click_io->latency());
 
-       DEBUG_TRACE (DEBUG::Latency, string_compose ("Worst output latency: %1\n", _worst_output_latency));
+       DEBUG_TRACE (DEBUG::LatencyCompensation, string_compose ("Worst output latency: %1\n", _worst_output_latency));
 }
 
 void
@@ -6485,7 +6478,7 @@ Session::set_worst_input_latency ()
                _worst_input_latency = max (_worst_input_latency, (*i)->input()->latency());
        }
 
-       DEBUG_TRACE (DEBUG::Latency, string_compose ("Worst input latency: %1\n", _worst_input_latency));
+       DEBUG_TRACE (DEBUG::LatencyCompensation, string_compose ("Worst input latency: %1\n", _worst_input_latency));
 }
 
 void
@@ -6506,20 +6499,25 @@ Session::update_latency_compensation (bool force_whole_graph)
                return;
        }
 
+       DEBUG_TRACE (DEBUG::LatencyCompensation, string_compose ("update_latency_compensation %1\n", (force_whole_graph ? "of whole graph" : "")));
+
        bool some_track_latency_changed = update_route_latency (false, false);
 
        if (some_track_latency_changed || force_whole_graph)  {
+               DEBUG_TRACE (DEBUG::LatencyCompensation, "update_latency_compensation: delegate to engine\n");
                _engine.update_latencies ();
                /* above call will ask the backend up update its latencies, which
                 * eventually will trigger  AudioEngine::latency_callback () and
                 * call Session::update_latency ()
                 */
        } else {
+               DEBUG_TRACE (DEBUG::LatencyCompensation, "update_latency_compensation: directly apply to routes\n");
                boost::shared_ptr<RouteList> r = routes.reader ();
                for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
                        (*i)->apply_latency_compensation ();
                }
        }
+       DEBUG_TRACE (DEBUG::LatencyCompensation, "update_latency_compensation: DONE\n");
 }
 
 char
index ebb3dd429256375706bd00e6f4dc443969aa33fd..dacda4d9ae8936eccc98da2e92c4fcd634cb599c 100644 (file)
@@ -365,10 +365,6 @@ Session::post_engine_init ()
 
                _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave | Dirty));
 
-               /* update latencies */
-
-               initialize_latencies ();
-
                _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
                _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
                _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
index b613b35f82c5881795b467e7218c59701067edea..03f93b85569bd24e32729108e938b9d3324248fe 100644 (file)
@@ -1869,7 +1869,6 @@ Session::engine_halted ()
 void
 Session::engine_running ()
 {
-       initialize_latencies ();
        _transport_fsm->start ();
 }
 
@@ -1907,8 +1906,8 @@ Session::route_processors_changed (RouteProcessorChange c)
                return;
        }
 
-       update_latency_compensation ();
        resort_routes ();
+       update_latency_compensation ();
 
        set_dirty ();
 }