+void
+Session::update_latency (bool playback)
+{
+ DEBUG_TRACE (DEBUG::Latency, string_compose ("JACK latency callback: %1\n", (playback ? "PLAYBACK" : "CAPTURE")));
+
+ if (_state_of_the_state & (InitialConnecting|Deletion)) {
+ return;
+ }
+
+ boost::shared_ptr<RouteList> r = routes.reader ();
+ framecnt_t max_latency = 0;
+
+ if (playback) {
+ /* reverse the list so that we work backwards from the last route to run to the first */
+ reverse (r->begin(), r->end());
+ }
+
+ /* compute actual latency values for the given direction and store them all in per-port
+ structures. this will also publish the same values (to JACK) so that computation of latency
+ for routes can consistently use public latency values.
+ */
+
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ max_latency = max (max_latency, (*i)->set_private_port_latencies (playback));
+ }
+
+ /* because we latency compensate playback, our published playback latencies should
+ be the same for all output ports - all material played back by ardour has
+ the same latency, whether its caused by plugins or by latency compensation. since
+ these may differ from the values computed above, reset all playback port latencies
+ to the same value.
+ */
+
+ DEBUG_TRACE (DEBUG::Latency, string_compose ("Set public port latencies to %1\n", max_latency));
+
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ (*i)->set_public_port_latencies (max_latency, playback);
+ }
+
+ if (playback) {
+
+ post_playback_latency ();
+
+ } else {
+
+ post_capture_latency ();
+ }
+
+ DEBUG_TRACE (DEBUG::Latency, "JACK latency callback: DONE\n");
+}
+
+void
+Session::post_playback_latency ()
+{
+ set_worst_playback_latency ();
+
+ boost::shared_ptr<RouteList> r = routes.reader ();
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ if (!(*i)->is_hidden() && ((*i)->active())) {
+ _worst_track_latency = max (_worst_track_latency, (*i)->update_signal_latency ());
+ }
+
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ (*i)->set_latency_compensation (_worst_track_latency);
+ }
+ }
+}
+
+void
+Session::post_capture_latency ()
+{
+ set_worst_capture_latency ();
+
+ /* reflect any changes in capture latencies into capture offsets
+ */
+
+ boost::shared_ptr<RouteList> rl = routes.reader();
+ for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+ boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+ if (tr) {
+ tr->set_capture_offset ();
+ }
+ }
+}
+
+void
+Session::set_worst_io_latencies ()
+{
+ set_worst_playback_latency ();
+ set_worst_capture_latency ();
+}
+
+void
+Session::set_worst_playback_latency ()
+{
+ if (_state_of_the_state & (InitialConnecting|Deletion)) {
+ return;
+ }
+
+ _worst_output_latency = 0;
+
+ if (!_engine.connected()) {
+ return;
+ }
+
+ boost::shared_ptr<RouteList> r = routes.reader ();
+
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ _worst_output_latency = max (_worst_output_latency, (*i)->output()->latency());
+ }
+
+ DEBUG_TRACE (DEBUG::Latency, string_compose ("Worst output latency: %1\n", _worst_output_latency));
+}
+
+void
+Session::set_worst_capture_latency ()
+{
+ if (_state_of_the_state & (InitialConnecting|Deletion)) {
+ return;
+ }
+
+ _worst_input_latency = 0;
+
+ if (!_engine.connected()) {
+ return;
+ }
+
+ boost::shared_ptr<RouteList> r = routes.reader ();
+
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ _worst_input_latency = max (_worst_input_latency, (*i)->input()->latency());
+ }
+
+ DEBUG_TRACE (DEBUG::Latency, string_compose ("Worst input latency: %1\n", _worst_input_latency));
+}
+
+void
+Session::update_latency_compensation (bool force_whole_graph)
+{
+ bool some_track_latency_changed = false;
+
+ if (_state_of_the_state & (InitialConnecting|Deletion)) {
+ return;
+ }
+
+ DEBUG_TRACE(DEBUG::Latency, "---------------------------- update latency compensation\n\n");
+
+ _worst_track_latency = 0;
+
+ boost::shared_ptr<RouteList> r = routes.reader ();
+
+ for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+ if (!(*i)->is_hidden() && ((*i)->active())) {
+ framecnt_t tl;
+ if ((*i)->signal_latency () != (tl = (*i)->update_signal_latency ())) {
+ some_track_latency_changed = true;
+ }
+ _worst_track_latency = max (tl, _worst_track_latency);
+ }
+ }
+
+ DEBUG_TRACE (DEBUG::Latency, string_compose ("worst signal processing latency: %1 (changed ? %2)\n", _worst_track_latency,
+ (some_track_latency_changed ? "yes" : "no")));
+
+ if (force_whole_graph || some_track_latency_changed) {
+ /* trigger a full recompute of latency numbers for the graph.
+ everything else that we need to do will be done in the latency
+ callback.
+ */
+ _engine.update_total_latencies ();
+ return; // everything else will be done in the latency callback
+ }
+
+ DEBUG_TRACE(DEBUG::Latency, "---------------------------- DONE update latency compensation\n\n")
+}
+