+
+int
+AudioEngine::prepare_for_latency_measurement ()
+{
+ if (!_backend) {
+ return -1;
+ }
+
+ if (running() && _started_for_latency) {
+ return 0;
+ }
+
+ if (_backend->can_change_systemic_latency_when_running()) {
+ if (_running) {
+ _backend->start (true); // zero latency reporting of running backend
+ } else if (start (true)) {
+ return -1;
+ }
+ _started_for_latency = true;
+ return 0;
+ }
+
+ if (running()) {
+ stop (true);
+ }
+
+ if (start (true)) {
+ return -1;
+ }
+ _started_for_latency = true;
+ return 0;
+}
+
+int
+AudioEngine::start_latency_detection (bool for_midi)
+{
+ if (prepare_for_latency_measurement ()) {
+ return -1;
+ }
+
+ PortEngine& pe (port_engine());
+
+ delete _mtdm;
+ _mtdm = 0;
+
+ delete _mididm;
+ _mididm = 0;
+
+ /* find the ports we will connect to */
+
+ PortEngine::PortHandle out = pe.get_port_by_name (_latency_output_name);
+ PortEngine::PortHandle in = pe.get_port_by_name (_latency_input_name);
+
+ if (!out || !in) {
+ stop (true);
+ return -1;
+ }
+
+ /* create the ports we will use to read/write data */
+ if (for_midi) {
+ if ((_latency_output_port = pe.register_port ("latency_out", DataType::MIDI, IsOutput)) == 0) {
+ stop (true);
+ return -1;
+ }
+ if (pe.connect (_latency_output_port, _latency_output_name)) {
+ pe.unregister_port (_latency_output_port);
+ stop (true);
+ return -1;
+ }
+
+ const string portname ("latency_in");
+ if ((_latency_input_port = pe.register_port (portname, DataType::MIDI, IsInput)) == 0) {
+ pe.unregister_port (_latency_input_port);
+ pe.unregister_port (_latency_output_port);
+ stop (true);
+ return -1;
+ }
+ if (pe.connect (_latency_input_name, make_port_name_non_relative (portname))) {
+ pe.unregister_port (_latency_input_port);
+ pe.unregister_port (_latency_output_port);
+ stop (true);
+ return -1;
+ }
+
+ _mididm = new MIDIDM (sample_rate());
+
+ } else {
+
+ if ((_latency_output_port = pe.register_port ("latency_out", DataType::AUDIO, IsOutput)) == 0) {
+ stop (true);
+ return -1;
+ }
+ if (pe.connect (_latency_output_port, _latency_output_name)) {
+ pe.unregister_port (_latency_output_port);
+ stop (true);
+ return -1;
+ }
+
+ const string portname ("latency_in");
+ if ((_latency_input_port = pe.register_port (portname, DataType::AUDIO, IsInput)) == 0) {
+ pe.unregister_port (_latency_input_port);
+ pe.unregister_port (_latency_output_port);
+ stop (true);
+ return -1;
+ }
+ if (pe.connect (_latency_input_name, make_port_name_non_relative (portname))) {
+ pe.unregister_port (_latency_input_port);
+ pe.unregister_port (_latency_output_port);
+ stop (true);
+ return -1;
+ }
+
+ _mtdm = new MTDM (sample_rate());
+
+ }
+
+ LatencyRange lr;
+ _latency_signal_latency = 0;
+ lr = pe.get_latency_range (in, false);
+ _latency_signal_latency = lr.max;
+ lr = pe.get_latency_range (out, true);
+ _latency_signal_latency += lr.max;
+
+ /* all created and connected, lets go */
+ _latency_flush_samples = samples_per_cycle();
+ _measuring_latency = for_midi ? MeasureMIDI : MeasureAudio;
+
+ return 0;
+}
+
+void
+AudioEngine::stop_latency_detection ()
+{
+ _measuring_latency = MeasureNone;
+
+ if (_latency_output_port) {
+ port_engine().unregister_port (_latency_output_port);
+ _latency_output_port = 0;
+ }
+ if (_latency_input_port) {
+ port_engine().unregister_port (_latency_input_port);
+ _latency_input_port = 0;
+ }
+
+ if (_running && _backend->can_change_systemic_latency_when_running()) {
+ if (_started_for_latency) {
+ _running = false; // force reload: reset latencies and emit Running()
+ start ();
+ }
+ }
+
+ if (_running && !_started_for_latency) {
+ assert (!_stopped_for_latency);
+ return;
+ }
+
+ if (!_backend->can_change_systemic_latency_when_running()) {
+ stop (true);
+ }
+
+ if (_stopped_for_latency) {
+ start ();
+ }
+
+ _stopped_for_latency = false;
+ _started_for_latency = false;
+}
+
+void
+AudioEngine::set_latency_output_port (const string& name)
+{
+ _latency_output_name = name;
+}
+
+void
+AudioEngine::set_latency_input_port (const string& name)
+{
+ _latency_input_name = name;
+}
+
+void
+AudioEngine::add_pending_port_deletion (Port* p)
+{
+ if (_session) {
+ DEBUG_TRACE (DEBUG::Ports, string_compose ("adding %1 to pending port deletion list\n", p->name()));
+ if (_port_deletions_pending.write (&p, 1) != 1) {
+ error << string_compose (_("programming error: port %1 could not be placed on the pending deletion queue\n"), p->name()) << endmsg;
+ }
+ _session->auto_connect_thread_wakeup ();
+ } else {
+ DEBUG_TRACE (DEBUG::Ports, string_compose ("Directly delete port %1\n", p->name()));
+ delete p;
+ }
+}