correct name of Midi-UI thread memory-pool and request-queue
[ardour.git] / libs / ardour / audioengine.cc
index a69e98283eab82adde62ad0a0ce651e5d9ba16e9..3452d1d14c313d16443b70d52055b3cba400b1ea 100644 (file)
 #include <exception>
 #include <stdexcept>
 #include <sstream>
+#include <cmath>
 
 #include <glibmm/timer.h>
+#include <glibmm/pattern.h>
+#include <glibmm/module.h>
 
+#include "pbd/epa.h"
+#include "pbd/file_utils.h"
 #include "pbd/pthread_utils.h"
 #include "pbd/stacktrace.h"
 #include "pbd/unknown_type.h"
-#include "pbd/epa.h"
 
 #include "midi++/port.h"
-#include "midi++/jack_midi_port.h"
 #include "midi++/mmc.h"
-#include "midi++/manager.h"
 
+#include "ardour/async_midi_port.h"
 #include "ardour/audio_port.h"
+#include "ardour/audio_backend.h"
 #include "ardour/audioengine.h"
+#include "ardour/search_paths.h"
 #include "ardour/buffer.h"
 #include "ardour/cycle_timer.h"
 #include "ardour/internal_send.h"
 #include "ardour/meter.h"
 #include "ardour/midi_port.h"
+#include "ardour/midiport_manager.h"
+#include "ardour/mididm.h"
+#include "ardour/mtdm.h"
 #include "ardour/port.h"
 #include "ardour/process_thread.h"
 #include "ardour/session.h"
@@ -53,433 +61,244 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-gint AudioEngine::m_meter_exit;
 AudioEngine* AudioEngine::_instance = 0;
 
-#define GET_PRIVATE_JACK_POINTER(j)  jack_client_t* _priv_jack = (jack_client_t*) (j); if (!_priv_jack) { return; }
-#define GET_PRIVATE_JACK_POINTER_RET(j,r) jack_client_t* _priv_jack = (jack_client_t*) (j); if (!_priv_jack) { return r; }
+#ifdef SILENCE_AFTER
+#define SILENCE_AFTER_SECONDS 600
+#endif
 
-AudioEngine::AudioEngine (string client_name, string session_uuid)
-       : _jack (0)
-       , session_remove_pending (false)
+AudioEngine::AudioEngine ()
+       : session_remove_pending (false)
        , session_removal_countdown (-1)
        , _running (false)
-       , _has_run (false)
-       , _buffer_size (0)
-       , _frame_rate (0)
+       , _freewheeling (false)
        , monitor_check_interval (INT32_MAX)
        , last_monitor_check (0)
        , _processed_frames (0)
-       , _freewheeling (false)
-       , _pre_freewheel_mmc_enabled (false)
-       , _usecs_per_cycle (0)
-       , port_remove_in_progress (false)
        , m_meter_thread (0)
        , _main_thread (0)
-       , ports (new Ports)
+       , _mtdm (0)
+       , _mididm (0)
+       , _measuring_latency (MeasureNone)
+       , _latency_input_port (0)
+       , _latency_output_port (0)
+       , _latency_flush_frames (0)
+       , _latency_signal_latency (0)
+       , _stopped_for_latency (false)
+       , _started_for_latency (false)
+       , _in_destructor (false)
+       , _last_backend_error_string(AudioBackend::get_error_string((AudioBackend::ErrorCode)-1))
+    , _hw_reset_event_thread(0)
+    , _hw_reset_request_count(0)
+    , _stop_hw_reset_processing(0)
+    , _hw_devicelist_update_thread(0)
+    , _hw_devicelist_update_count(0)
+    , _stop_hw_devicelist_processing(0)
+#ifdef SILENCE_AFTER_SECONDS
+       , _silence_countdown (0)
+       , _silence_hit_cnt (0)
+#endif
 {
-       _instance = this; /* singleton */
-
-       g_atomic_int_set (&m_meter_exit, 0);
-
-       if (connect_to_jack (client_name, session_uuid)) {
-               throw NoBackendAvailable ();
-       }
-
-       Port::set_engine (this);
+       reset_silence_countdown ();
+       start_hw_event_processing();
+       discover_backends ();
 }
 
 AudioEngine::~AudioEngine ()
 {
-       config_connection.disconnect ();
-
-       {
-               Glib::Threads::Mutex::Lock tm (_process_lock);
-               session_removed.signal ();
-
-               if (_running) {
-                       jack_client_close (_jack);
-                       _jack = 0;
-               }
-
-               stop_metering_thread ();
+       _in_destructor = true;
+       stop_hw_event_processing();
+       drop_backend ();
+       for (BackendMap::const_iterator i = _backends.begin(); i != _backends.end(); ++i) {
+               i->second->deinstantiate();
        }
 }
 
-jack_client_t*
-AudioEngine::jack() const
-{
-       return _jack;
-}
-
-void
-_thread_init_callback (void * /*arg*/)
+AudioEngine*
+AudioEngine::create ()
 {
-       /* make sure that anybody who needs to know about this thread
-          knows about it.
-       */
-
-       pthread_set_name (X_("audioengine"));
-
-       PBD::notify_gui_about_thread_creation ("gui", pthread_self(), X_("Audioengine"), 4096);
-       PBD::notify_gui_about_thread_creation ("midiui", pthread_self(), X_("Audioengine"), 128);
-
-       SessionEvent::create_per_thread_pool (X_("Audioengine"), 512);
+       if (_instance) {
+               return _instance;
+       }
 
-       MIDI::JackMIDIPort::set_process_thread (pthread_self());
-}
+       _instance = new AudioEngine ();
 
-static void
-ardour_jack_error (const char* msg)
-{
-       error << "JACK: " << msg << endmsg;
+       return _instance;
 }
 
 void
-AudioEngine::set_jack_callbacks ()
-{
-       GET_PRIVATE_JACK_POINTER (_jack);
-
-        if (jack_on_info_shutdown) {
-                jack_on_info_shutdown (_priv_jack, halted_info, this);
-        } else {
-                jack_on_shutdown (_priv_jack, halted, this);
-        }
-
-        jack_set_thread_init_callback (_priv_jack, _thread_init_callback, this);
-        jack_set_process_thread (_priv_jack, _process_thread, this);
-        jack_set_sample_rate_callback (_priv_jack, _sample_rate_callback, this);
-        jack_set_buffer_size_callback (_priv_jack, _bufsize_callback, this);
-        jack_set_graph_order_callback (_priv_jack, _graph_order_callback, this);
-        jack_set_port_registration_callback (_priv_jack, _registration_callback, this);
-        jack_set_port_connect_callback (_priv_jack, _connect_callback, this);
-        jack_set_xrun_callback (_priv_jack, _xrun_callback, this);
-        jack_set_sync_callback (_priv_jack, _jack_sync_callback, this);
-        jack_set_freewheel_callback (_priv_jack, _freewheel_callback, this);
-
-        if (_session && _session->config.get_jack_time_master()) {
-                jack_set_timebase_callback (_priv_jack, 0, _jack_timebase_callback, this);
-        }
-
-#ifdef HAVE_JACK_SESSION
-        if( jack_set_session_callback)
-                jack_set_session_callback (_priv_jack, _session_callback, this);
-#endif
-
-        if (jack_set_latency_callback) {
-                jack_set_latency_callback (_priv_jack, _latency_callback, this);
-        }
-
-        jack_set_error_function (ardour_jack_error);
-}
-
-int
-AudioEngine::start ()
+AudioEngine::split_cycle (pframes_t offset)
 {
-       GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
-
-       if (!_running) {
-
-                if (!jack_port_type_get_buffer_size) {
-                        warning << _("This version of JACK is old - you should upgrade to a newer version that supports jack_port_type_get_buffer_size()") << endmsg;
-               }
-
-               if (_session) {
-                       BootMessage (_("Connect session to engine"));
-                       _session->set_frame_rate (jack_get_sample_rate (_priv_jack));
-               }
+       /* caller must hold process lock */
 
-                /* a proxy for whether jack_activate() will definitely call the buffer size
-                 * callback. with older versions of JACK, this function symbol will be null.
-                 * this is reliable, but not clean.
-                 */
+       Port::increment_global_port_buffer_offset (offset);
 
-                if (!jack_port_type_get_buffer_size) {
-                       jack_bufsize_callback (jack_get_buffer_size (_priv_jack));
-                }
-               
-               _processed_frames = 0;
-               last_monitor_check = 0;
+       /* tell all Ports that we're going to start a new (split) cycle */
 
-                set_jack_callbacks ();
+       boost::shared_ptr<Ports> p = ports.reader();
 
-               if (jack_activate (_priv_jack) == 0) {
-                       _running = true;
-                       _has_run = true;
-                       Running(); /* EMIT SIGNAL */
-               } else {
-                       // error << _("cannot activate JACK client") << endmsg;
-               }
+       for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
+               i->second->cycle_split ();
        }
-               
-       return _running ? 0 : -1;
 }
 
 int
-AudioEngine::stop (bool forever)
-{
-       GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
-
-       if (_priv_jack) {
-               if (forever) {
-                       disconnect_from_jack ();
-               } else {
-                       jack_deactivate (_priv_jack);
-                       MIDI::JackMIDIPort::JackHalted (); /* EMIT SIGNAL */
-                       Stopped(); /* EMIT SIGNAL */
-               }
-       }
-
-        if (forever) {
-                stop_metering_thread ();
-        }
-
-       return _running ? -1 : 0;
-}
-
-
-bool
-AudioEngine::get_sync_offset (pframes_t& offset) const
+AudioEngine::sample_rate_change (pframes_t nframes)
 {
+       /* check for monitor input change every 1/10th of second */
 
-#ifdef HAVE_JACK_VIDEO_SUPPORT
-
-       GET_PRIVATE_JACK_POINTER_RET (_jack, false);
-
-       jack_position_t pos;
-
-       if (_priv_jack) {
-               (void) jack_transport_query (_priv_jack, &pos);
+       monitor_check_interval = nframes / 10;
+       last_monitor_check = 0;
 
-               if (pos.valid & JackVideoFrameOffset) {
-                       offset = pos.video_offset;
-                       return true;
-               }
+       if (_session) {
+               _session->set_frame_rate (nframes);
        }
-#else
-       /* keep gcc happy */
-       offset = 0;
-#endif
 
-       return false;
-}
-
-void
-AudioEngine::_jack_timebase_callback (jack_transport_state_t state, pframes_t nframes,
-                                     jack_position_t* pos, int new_position, void *arg)
-{
-       static_cast<AudioEngine*> (arg)->jack_timebase_callback (state, nframes, pos, new_position);
-}
+       SampleRateChanged (nframes); /* EMIT SIGNAL */
 
-void
-AudioEngine::jack_timebase_callback (jack_transport_state_t state, pframes_t nframes,
-                                    jack_position_t* pos, int new_position)
-{
-       if (_jack && _session && _session->synced_to_jack()) {
-               _session->jack_timebase_callback (state, nframes, pos, new_position);
-       }
-}
+#ifdef SILENCE_AFTER_SECONDS
+       _silence_countdown = nframes * SILENCE_AFTER_SECONDS;
+#endif
 
-int
-AudioEngine::_jack_sync_callback (jack_transport_state_t state, jack_position_t* pos, void* arg)
-{
-       return static_cast<AudioEngine*> (arg)->jack_sync_callback (state, pos);
+       return 0;
 }
 
 int
-AudioEngine::jack_sync_callback (jack_transport_state_t state, jack_position_t* pos)
+AudioEngine::buffer_size_change (pframes_t bufsiz)
 {
-       if (_jack && _session) {
-               return _session->jack_sync_callback (state, pos);
+       if (_session) {
+               _session->set_block_size (bufsiz);
+               last_monitor_check = 0;
        }
 
-       return true;
-}
+       BufferSizeChanged (bufsiz); /* EMIT SIGNAL */
 
-int
-AudioEngine::_xrun_callback (void *arg)
-{
-       AudioEngine* ae = static_cast<AudioEngine*> (arg);
-       if (ae->connected()) {
-               ae->Xrun (); /* EMIT SIGNAL */
-       }
        return 0;
 }
 
-#ifdef HAVE_JACK_SESSION
-void
-AudioEngine::_session_callback (jack_session_event_t *event, void *arg)
-{
-       AudioEngine* ae = static_cast<AudioEngine*> (arg);
-       if (ae->connected()) {
-               ae->JackSessionEvent ( event ); /* EMIT SIGNAL */
-       }
-}
+/** Method called by our ::process_thread when there is work to be done.
+ *  @param nframes Number of frames to process.
+ */
+#ifdef __clang__
+__attribute__((annotate("realtime")))
 #endif
-
 int
-AudioEngine::_graph_order_callback (void *arg)
+AudioEngine::process_callback (pframes_t nframes)
 {
-       AudioEngine* ae = static_cast<AudioEngine*> (arg);
-
-       if (ae->connected() && !ae->port_remove_in_progress) {
-               ae->GraphReordered (); /* EMIT SIGNAL */
-       }
-       
-       return 0;
-}
+       Glib::Threads::Mutex::Lock tm (_process_lock, Glib::Threads::TRY_LOCK);
 
-void*
-AudioEngine::_process_thread (void *arg)
-{
-       return static_cast<AudioEngine *> (arg)->process_thread ();
-}
+       PT_TIMING_REF;
+       PT_TIMING_CHECK (1);
 
-void
-AudioEngine::_freewheel_callback (int onoff, void *arg)
-{
-       static_cast<AudioEngine*>(arg)->freewheel_callback (onoff);
-}
+       /// The number of frames that will have been processed when we've finished
+       pframes_t next_processed_frames;
 
-void
-AudioEngine::freewheel_callback (int onoff)
-{
-       _freewheeling = onoff;
+       /* handle wrap around of total frames counter */
 
-       if (onoff) {
-               _pre_freewheel_mmc_enabled = MIDI::Manager::instance()->mmc()->send_enabled ();
-               MIDI::Manager::instance()->mmc()->enable_send (false);
+       if (max_framepos - _processed_frames < nframes) {
+               next_processed_frames = nframes - (max_framepos - _processed_frames);
        } else {
-               MIDI::Manager::instance()->mmc()->enable_send (_pre_freewheel_mmc_enabled);
+               next_processed_frames = _processed_frames + nframes;
        }
-}
 
-void
-AudioEngine::_registration_callback (jack_port_id_t /*id*/, int /*reg*/, void* arg)
-{
-       AudioEngine* ae = static_cast<AudioEngine*> (arg);
-
-       if (!ae->port_remove_in_progress) {
-               ae->PortRegisteredOrUnregistered (); /* EMIT SIGNAL */
+       if (!tm.locked()) {
+               /* return having done nothing */
+               if (_session) {
+                       Xrun();
+               }
+               /* really only JACK requires this
+                * (other backends clear the output buffers
+                * before the process_callback. it may even be
+                * jack/alsa only). but better safe than sorry.
+                */
+               PortManager::silence_outputs (nframes);
+               return 0;
        }
-}
-
-void
-AudioEngine::_latency_callback (jack_latency_callback_mode_t mode, void* arg)
-{
-       return static_cast<AudioEngine *> (arg)->jack_latency_callback (mode);
-}
-
-void
-AudioEngine::_connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, int conn, void* arg)
-{
-       AudioEngine* ae = static_cast<AudioEngine*> (arg);
-       ae->connect_callback (id_a, id_b, conn);
-}
 
-void
-AudioEngine::connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, int conn)
-{
-       if (port_remove_in_progress) {
-               return;
+       /* The coreaudio-backend calls thread_init_callback() if
+        * the hardware changes or pthread_self() changes.
+        *
+        * However there are cases when neither holds true, yet
+        * the thread-pool changes: e.g. connect a headphone to
+        * a shared mic/headphone jack.
+        * It's probably related to, or caused by clocksource changes.
+        *
+        * For reasons yet unknown Glib::Threads::Private() can
+        * use a different thread-private in the same pthread
+        * (coreaudio render callback).
+        *
+        * Coreaudio must set something which influences
+        * pthread_key_t uniqness or reset the key using
+        * pthread_getspecific().
+        */
+       if (! SessionEvent::has_per_thread_pool ()) {
+               thread_init_callback (NULL);
        }
 
-       GET_PRIVATE_JACK_POINTER (_jack);
+       bool return_after_remove_check = false;
 
-       jack_port_t* jack_port_a = jack_port_by_id (_priv_jack, id_a);
-       jack_port_t* jack_port_b = jack_port_by_id (_priv_jack, id_b);
+       if (_measuring_latency == MeasureAudio && _mtdm) {
+               /* run a normal cycle from the perspective of the PortManager
+                  so that we get silence on all registered ports.
 
-       boost::shared_ptr<Port> port_a;
-       boost::shared_ptr<Port> port_b;
-       Ports::iterator x;
-       boost::shared_ptr<Ports> pr = ports.reader ();
+                  we overwrite the silence on the two ports used for latency
+                  measurement.
+               */
 
+               PortManager::cycle_start (nframes);
+               PortManager::silence (nframes);
 
-       x = pr->find (make_port_name_relative (jack_port_name (jack_port_a)));
-       if (x != pr->end()) {
-               port_a = x->second;
-       }
+               if (_latency_input_port && _latency_output_port) {
+                       PortEngine& pe (port_engine());
 
-       x = pr->find (make_port_name_relative (jack_port_name (jack_port_b)));
-       if (x != pr->end()) {
-               port_b = x->second;
-       }
+                       Sample* in = (Sample*) pe.get_buffer (_latency_input_port, nframes);
+                       Sample* out = (Sample*) pe.get_buffer (_latency_output_port, nframes);
 
-       PortConnectedOrDisconnected (
-               port_a, jack_port_name (jack_port_a),
-               port_b, jack_port_name (jack_port_b),
-               conn == 0 ? false : true
-               ); /* EMIT SIGNAL */
-}
+                       _mtdm->process (nframes, in, out);
+               }
 
-void
-AudioEngine::split_cycle (pframes_t offset)
-{
-       /* caller must hold process lock */
+               PortManager::cycle_end (nframes);
+               return_after_remove_check = true;
 
-       Port::increment_global_port_buffer_offset (offset);
+       } else if (_measuring_latency == MeasureMIDI && _mididm) {
+               /* run a normal cycle from the perspective of the PortManager
+                  so that we get silence on all registered ports.
 
-       /* tell all Ports that we're going to start a new (split) cycle */
+                  we overwrite the silence on the two ports used for latency
+                  measurement.
+               */
 
-       boost::shared_ptr<Ports> p = ports.reader();
+               PortManager::cycle_start (nframes);
+               PortManager::silence (nframes);
 
-       for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
-               i->second->cycle_split ();
-       }
-}
+               if (_latency_input_port && _latency_output_port) {
+                       PortEngine& pe (port_engine());
 
-void*
-AudioEngine::process_thread ()
-{
-        /* JACK doesn't do this for us when we use the wait API
-         */
+                       _mididm->process (nframes, pe,
+                                       pe.get_buffer (_latency_input_port, nframes),
+                                       pe.get_buffer (_latency_output_port, nframes));
+               }
 
-        _thread_init_callback (0);
+               PortManager::cycle_end (nframes);
+               return_after_remove_check = true;
 
-        _main_thread = new ProcessThread;
+       } else if (_latency_flush_frames) {
 
-        while (1) {
-                GET_PRIVATE_JACK_POINTER_RET(_jack,0);
+               /* wait for the appropriate duration for the MTDM signal to
+                * drain from the ports before we revert to normal behaviour.
+                */
 
-                pframes_t nframes = jack_cycle_wait (_priv_jack);
+               PortManager::cycle_start (nframes);
+               PortManager::silence (nframes);
+               PortManager::cycle_end (nframes);
 
-                if (process_callback (nframes)) {
-                        return 0;
+                if (_latency_flush_frames > nframes) {
+                        _latency_flush_frames -= nframes;
+                } else {
+                        _latency_flush_frames = 0;
                 }
 
-               jack_cycle_signal (_priv_jack, 0);
-        }
-
-        return 0;
-}
-
-/** Method called by our ::process_thread when there is work to be done.
- *  @param nframes Number of frames to process.
- */
-int
-AudioEngine::process_callback (pframes_t nframes)
-{
-       GET_PRIVATE_JACK_POINTER_RET(_jack,0);
-       Glib::Threads::Mutex::Lock tm (_process_lock, Glib::Threads::TRY_LOCK);
-
-       PT_TIMING_REF;
-       PT_TIMING_CHECK (1);
-
-       /// The number of frames that will have been processed when we've finished
-       pframes_t next_processed_frames;
-
-       /* handle wrap around of total frames counter */
-
-       if (max_framepos - _processed_frames < nframes) {
-               next_processed_frames = nframes - (max_framepos - _processed_frames);
-       } else {
-               next_processed_frames = _processed_frames + nframes;
-       }
-
-       if (!tm.locked()) {
-               /* return having done nothing */
-               _processed_frames = next_processed_frames;
-               return 0;
+               return_after_remove_check = true;
        }
 
        if (session_remove_pending) {
@@ -489,19 +308,19 @@ AudioEngine::process_callback (pframes_t nframes)
                if (session_removal_countdown < 0) {
 
                        /* fade out over 1 second */
-                       session_removal_countdown = _frame_rate/2;
-                       session_removal_gain = 1.0;
+                       session_removal_countdown = sample_rate()/2;
+                       session_removal_gain = GAIN_COEFF_UNITY;
                        session_removal_gain_step = 1.0/session_removal_countdown;
 
                } else if (session_removal_countdown > 0) {
 
                        /* we'll be fading audio out.
-                          
-                          if this is the last time we do this as part 
+
+                          if this is the last time we do this as part
                           of session removal, do a MIDI panic now
                           to get MIDI stopped. This relies on the fact
                           that "immediate data" (aka "out of band data") from
-                          MIDI tracks is *appended* after any other data, 
+                          MIDI tracks is *appended* after any other data,
                           so that it emerges after any outbound note ons, etc.
                        */
 
@@ -518,11 +337,15 @@ AudioEngine::process_callback (pframes_t nframes)
                }
        }
 
+       if (return_after_remove_check) {
+               return 0;
+       }
+
        if (_session == 0) {
 
                if (!_freewheeling) {
-                       MIDI::Manager::instance()->cycle_start(nframes);
-                       MIDI::Manager::instance()->cycle_end();
+                       PortManager::cycle_start (nframes);
+                       PortManager::cycle_end (nframes);
                }
 
                _processed_frames = next_processed_frames;
@@ -533,37 +356,24 @@ AudioEngine::process_callback (pframes_t nframes)
        /* tell all relevant objects that we're starting a new cycle */
 
        InternalSend::CycleStart (nframes);
-       Port::set_global_port_buffer_offset (0);
-        Port::set_cycle_framecnt (nframes);
 
        /* tell all Ports that we're starting a new cycle */
 
-       boost::shared_ptr<Ports> p = ports.reader();
-
-       for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
-               i->second->cycle_start (nframes);
-       }
+       PortManager::cycle_start (nframes);
 
        /* test if we are freewheeling and there are freewheel signals connected.
            ardour should act normally even when freewheeling unless /it/ is
-           exporting 
+           exporting (which is what Freewheel.empty() tests for).
        */
 
        if (_freewheeling && !Freewheel.empty()) {
-
-                Freewheel (nframes);
-
+               Freewheel (nframes);
        } else {
-               MIDI::Manager::instance()->cycle_start(nframes);
-
-               if (_session) {
-                       _session->process (nframes);
-               }
-
-               MIDI::Manager::instance()->cycle_end();
+               _session->process (nframes);
        }
 
        if (_freewheeling) {
+               PortManager::cycle_end (nframes);
                return 0;
        }
 
@@ -574,52 +384,39 @@ AudioEngine::process_callback (pframes_t nframes)
 
        if (last_monitor_check + monitor_check_interval < next_processed_frames) {
 
-               boost::shared_ptr<Ports> p = ports.reader();
+               PortManager::check_monitoring ();
+               last_monitor_check = next_processed_frames;
+       }
 
-               for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
+#ifdef SILENCE_AFTER_SECONDS
 
-                       bool x;
+       bool was_silent = (_silence_countdown == 0);
 
-                       if (i->second->last_monitor() != (x = i->second->jack_monitoring_input ())) {
-                               i->second->set_last_monitor (x);
-                               /* XXX I think this is dangerous, due to
-                                  a likely mutex in the signal handlers ...
-                               */
-                               i->second->MonitorInputChanged (x); /* EMIT SIGNAL */
-                       }
-               }
-               last_monitor_check = next_processed_frames;
+       if (_silence_countdown >= nframes) {
+               _silence_countdown -= nframes;
+       } else {
+               _silence_countdown = 0;
        }
 
-       if (_session->silent()) {
+       if (!was_silent && _silence_countdown == 0) {
+               _silence_hit_cnt++;
+               BecameSilent (); /* EMIT SIGNAL */
+       }
 
-               for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
+       if (_silence_countdown == 0 || _session->silent()) {
+               PortManager::silence (nframes);
+       }
 
-                       if (i->second->sends_output()) {
-                               i->second->get_buffer(nframes).silence(nframes);
-                       }
-               }
+#else
+       if (_session->silent()) {
+               PortManager::silence (nframes);
        }
+#endif
 
        if (session_remove_pending && session_removal_countdown) {
 
-               for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
+               PortManager::fade_out (session_removal_gain, session_removal_gain_step, nframes);
 
-                       if (i->second->sends_output()) {
-
-                               boost::shared_ptr<AudioPort> ap = boost::dynamic_pointer_cast<AudioPort> (i->second);
-                               if (ap) {
-                                       Sample* s = ap->engine_get_whole_audio_buffer ();
-                                       gain_t g = session_removal_gain;
-                                       
-                                       for (pframes_t n = 0; n < nframes; ++n) {
-                                               *s++ *= g;
-                                               g -= session_removal_gain_step;
-                                       }
-                               }
-                       }
-               }
-               
                if (session_removal_countdown > nframes) {
                        session_removal_countdown -= nframes;
                } else {
@@ -629,143 +426,179 @@ AudioEngine::process_callback (pframes_t nframes)
                session_removal_gain -= (nframes * session_removal_gain_step);
        }
 
-       // Finalize ports
-
-       for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
-               i->second->cycle_end (nframes);
-       }
+       PortManager::cycle_end (nframes);
 
        _processed_frames = next_processed_frames;
 
        PT_TIMING_CHECK (2);
-       
+
        return 0;
 }
 
-int
-AudioEngine::_sample_rate_callback (pframes_t nframes, void *arg)
+void
+AudioEngine::reset_silence_countdown ()
 {
-       return static_cast<AudioEngine *> (arg)->jack_sample_rate_callback (nframes);
-}
+#ifdef SILENCE_AFTER_SECONDS
+       double sr = 48000; /* default in case there is no backend */
 
-int
-AudioEngine::jack_sample_rate_callback (pframes_t nframes)
-{
-       _frame_rate = nframes;
-       _usecs_per_cycle = (int) floor ((((double) frames_per_cycle() / nframes)) * 1000000.0);
+       sr = sample_rate();
 
-       /* check for monitor input change every 1/10th of second */
+       _silence_countdown = max (60 * sr, /* 60 seconds */
+                                 sr * (SILENCE_AFTER_SECONDS / ::pow (2.0, (double) _silence_hit_cnt)));
 
-       monitor_check_interval = nframes / 10;
-       last_monitor_check = 0;
+#endif
+}
 
-       if (_session) {
-               _session->set_frame_rate (nframes);
+void
+AudioEngine::launch_device_control_app()
+{
+       if (_state_lock.trylock () ) {
+               _backend->launch_control_app ();
+               _state_lock.unlock ();
        }
+}
 
-       SampleRateChanged (nframes); /* EMIT SIGNAL */
-
-       return 0;
-}
 
 void
-AudioEngine::jack_latency_callback (jack_latency_callback_mode_t mode)
+AudioEngine::request_backend_reset()
 {
-        if (_session) {
-                _session->update_latency (mode == JackPlaybackLatency);
-        }
+    Glib::Threads::Mutex::Lock guard (_reset_request_lock);
+    g_atomic_int_inc (&_hw_reset_request_count);
+    _hw_reset_condition.signal ();
 }
 
 int
-AudioEngine::_bufsize_callback (pframes_t nframes, void *arg)
+AudioEngine::backend_reset_requested()
 {
-       return static_cast<AudioEngine *> (arg)->jack_bufsize_callback (nframes);
+       return g_atomic_int_get (&_hw_reset_request_count);
 }
 
-int
-AudioEngine::jack_bufsize_callback (pframes_t nframes)
+void
+AudioEngine::do_reset_backend()
 {
-        /* if the size has not changed, this should be a no-op */
+       SessionEvent::create_per_thread_pool (X_("Backend reset processing thread"), 1024);
 
-        if (nframes == _buffer_size) {
-                return 0;
-        }
+       Glib::Threads::Mutex::Lock guard (_reset_request_lock);
 
-       GET_PRIVATE_JACK_POINTER_RET (_jack, 1);
+       while (!_stop_hw_reset_processing) {
 
-       _buffer_size = nframes;
-       _usecs_per_cycle = (int) floor ((((double) nframes / frame_rate())) * 1000000.0);
-       last_monitor_check = 0;
+               if (g_atomic_int_get (&_hw_reset_request_count) != 0 && _backend) {
 
-        if (jack_port_type_get_buffer_size) {
-                _raw_buffer_sizes[DataType::AUDIO] = jack_port_type_get_buffer_size (_priv_jack, JACK_DEFAULT_AUDIO_TYPE);
-                _raw_buffer_sizes[DataType::MIDI] = jack_port_type_get_buffer_size (_priv_jack, JACK_DEFAULT_MIDI_TYPE);
-        } else {
+                       _reset_request_lock.unlock();
 
-                /* Old version of JACK.
+                       Glib::Threads::RecMutex::Lock pl (_state_lock);
+                       g_atomic_int_dec_and_test (&_hw_reset_request_count);
 
-                   These crude guesses, see below where we try to get the right answers.
+            std::cout << "AudioEngine::RESET::Reset request processing. Requests left: " << _hw_reset_request_count << std::endl;
+                        DeviceResetStarted(); // notify about device reset to be started
 
-                   Note that our guess for MIDI deliberatey tries to overestimate
-                   by a little. It would be nicer if we could get the actual
-                   size from a port, but we have to use this estimate in the
-                   event that there are no MIDI ports currently. If there are
-                   the value will be adjusted below.
-                */
+                        // backup the device name
+                        std::string name = _backend->device_name ();
 
-                _raw_buffer_sizes[DataType::AUDIO] = nframes * sizeof (Sample);
-                _raw_buffer_sizes[DataType::MIDI] = nframes * 4 - (nframes/2);
-        }
+            std::cout << "AudioEngine::RESET::Reseting device..." << std::endl;
+                       if ( ( 0 == stop () ) &&
+                 ( 0 == _backend->reset_device () ) &&
+                 ( 0 == start () ) ) {
 
-       {
-               Glib::Threads::Mutex::Lock lm (_process_lock);
+                               std::cout << "AudioEngine::RESET::Engine started..." << std::endl;
 
-               boost::shared_ptr<Ports> p = ports.reader();
+                               // inform about possible changes
+                               BufferSizeChanged (_backend->buffer_size() );
+                DeviceResetFinished(); // notify about device reset finish
 
-               for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
-                       i->second->reset();
-               }
-       }
+            } else {
 
-       if (_session) {
-               _session->set_block_size (_buffer_size);
-       }
+                DeviceResetFinished(); // notify about device reset finish
+                               // we've got an error
+                DeviceError();
+                       }
 
-       return 0;
+                       std::cout << "AudioEngine::RESET::Done." << std::endl;
+
+                       _reset_request_lock.lock();
+
+               } else {
+
+                       _hw_reset_condition.wait (_reset_request_lock);
+
+               }
+       }
 }
+void
+AudioEngine::request_device_list_update()
+{
+    Glib::Threads::Mutex::Lock guard (_devicelist_update_lock);
+    g_atomic_int_inc (&_hw_devicelist_update_count);
+    _hw_devicelist_update_condition.signal ();
+}
+
 
 void
-AudioEngine::stop_metering_thread ()
+AudioEngine::do_devicelist_update()
 {
-       if (m_meter_thread) {
-               g_atomic_int_set (&m_meter_exit, 1);
-               m_meter_thread->join ();
-               m_meter_thread = 0;
-       }
+    SessionEvent::create_per_thread_pool (X_("Device list update processing thread"), 512);
+
+    Glib::Threads::Mutex::Lock guard (_devicelist_update_lock);
+
+    while (!_stop_hw_devicelist_processing) {
+
+        if (_hw_devicelist_update_count) {
+
+            _devicelist_update_lock.unlock();
+
+            Glib::Threads::RecMutex::Lock pl (_state_lock);
+
+            g_atomic_int_dec_and_test (&_hw_devicelist_update_count);
+            DeviceListChanged (); /* EMIT SIGNAL */
+
+            _devicelist_update_lock.lock();
+
+        } else {
+            _hw_devicelist_update_condition.wait (_devicelist_update_lock);
+        }
+    }
 }
 
+
 void
-AudioEngine::start_metering_thread ()
+AudioEngine::start_hw_event_processing()
 {
-       if (m_meter_thread == 0) {
-               g_atomic_int_set (&m_meter_exit, 0);
-               m_meter_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::meter_thread, this));
-       }
+    if (_hw_reset_event_thread == 0) {
+        g_atomic_int_set(&_hw_reset_request_count, 0);
+        g_atomic_int_set(&_stop_hw_reset_processing, 0);
+        _hw_reset_event_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::do_reset_backend, this));
+    }
+
+    if (_hw_devicelist_update_thread == 0) {
+        g_atomic_int_set(&_hw_devicelist_update_count, 0);
+        g_atomic_int_set(&_stop_hw_devicelist_processing, 0);
+        _hw_devicelist_update_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::do_devicelist_update, this));
+    }
 }
 
+
 void
-AudioEngine::meter_thread ()
+AudioEngine::stop_hw_event_processing()
 {
-       pthread_set_name (X_("meter"));
-       while (true) {
-               Glib::usleep (10000);
-               if (g_atomic_int_get(&m_meter_exit)) {
-                       break;
-               }
-               Metering::Meter ();
-       }
+    if (_hw_reset_event_thread) {
+        g_atomic_int_set(&_stop_hw_reset_processing, 1);
+        g_atomic_int_set(&_hw_reset_request_count, 0);
+        _hw_reset_condition.signal ();
+        _hw_reset_event_thread->join ();
+        _hw_reset_event_thread = 0;
+    }
+
+    if (_hw_devicelist_update_thread) {
+        g_atomic_int_set(&_stop_hw_devicelist_processing, 1);
+        g_atomic_int_set(&_hw_devicelist_update_count, 0);
+        _hw_devicelist_update_condition.signal ();
+        _hw_devicelist_update_thread->join ();
+        _hw_devicelist_update_thread = 0;
+    }
+
 }
 
+
 void
 AudioEngine::set_session (Session *s)
 {
@@ -775,19 +608,9 @@ AudioEngine::set_session (Session *s)
 
        if (_session) {
 
-               start_metering_thread ();
-
-               pframes_t blocksize = jack_get_buffer_size (_jack);
-
-               /* page in as much of the session process code as we
-                  can before we really start running.
-               */
-
-               boost::shared_ptr<Ports> p = ports.reader();
+               pframes_t blocksize = samples_per_cycle ();
 
-               for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
-                       i->second->cycle_start (blocksize);
-               }
+               PortManager::cycle_start (blocksize);
 
                _session->process (blocksize);
                _session->process (blocksize);
@@ -798,9 +621,7 @@ AudioEngine::set_session (Session *s)
                _session->process (blocksize);
                _session->process (blocksize);
 
-               for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
-                       i->second->cycle_end (blocksize);
-               }
+               PortManager::cycle_end (blocksize);
        }
 }
 
@@ -811,10 +632,10 @@ AudioEngine::remove_session ()
 
        if (_running) {
 
-               stop_metering_thread ();
-
                if (_session) {
                        session_remove_pending = true;
+                       /* signal the start of the fade out countdown */
+                       session_removal_countdown = -1;
                        session_removed.wait(_process_lock);
                }
 
@@ -825,815 +646,820 @@ AudioEngine::remove_session ()
        remove_all_ports ();
 }
 
+
 void
-AudioEngine::port_registration_failure (const std::string& portname)
+AudioEngine::reconnect_session_routes (bool reconnect_inputs, bool reconnect_outputs)
 {
-       GET_PRIVATE_JACK_POINTER (_jack);
-       string full_portname = jack_client_name;
-       full_portname += ':';
-       full_portname += portname;
-
-
-       jack_port_t* p = jack_port_by_name (_priv_jack, full_portname.c_str());
-       string reason;
-
-       if (p) {
-               reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname);
-       } else {
-               reason = string_compose (_("No more JACK ports are available. You will need to stop %1 and restart JACK with more ports if you need this many tracks."), PROGRAM_NAME);
+#ifdef USE_TRACKS_CODE_FEATURES
+       if (_session) {
+               _session->reconnect_existing_routes(true, true, reconnect_inputs, reconnect_outputs);
        }
-
-       throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
+#endif
 }
 
-boost::shared_ptr<Port>
-AudioEngine::register_port (DataType dtype, const string& portname, bool input)
+
+void
+AudioEngine::died ()
 {
-       boost::shared_ptr<Port> newport;
+       /* called from a signal handler for SIGPIPE */
+       _running = false;
+}
 
-       try {
-               if (dtype == DataType::AUDIO) {
-                       newport.reset (new AudioPort (portname, (input ? Port::IsInput : Port::IsOutput)));
-               } else if (dtype == DataType::MIDI) {
-                       newport.reset (new MidiPort (portname, (input ? Port::IsInput : Port::IsOutput)));
+int
+AudioEngine::reset_timebase ()
+{
+       if (_session) {
+               if (_session->config.get_jack_time_master()) {
+                       _backend->set_time_master (true);
                } else {
-                       throw PortRegistrationFailure("unable to create port (unknown type)");
+                       _backend->set_time_master (false);
                }
-
-               RCUWriter<Ports> writer (ports);
-               boost::shared_ptr<Ports> ps = writer.get_copy ();
-               ps->insert (make_pair (make_port_name_relative (portname), newport));
-
-               /* writer goes out of scope, forces update */
-
-               return newport;
-       }
-
-       catch (PortRegistrationFailure& err) {
-               throw err;
-       } catch (std::exception& e) {
-               throw PortRegistrationFailure(string_compose(
-                               _("unable to create port: %1"), e.what()).c_str());
-       } catch (...) {
-               throw PortRegistrationFailure("unable to create port (unknown error)");
        }
+       return 0;
 }
 
-boost::shared_ptr<Port>
-AudioEngine::register_input_port (DataType type, const string& portname)
-{
-       return register_port (type, portname, true);
-}
 
-boost::shared_ptr<Port>
-AudioEngine::register_output_port (DataType type, const string& portname)
+void
+AudioEngine::destroy ()
 {
-       return register_port (type, portname, false);
+       delete _instance;
+       _instance = 0;
 }
 
 int
-AudioEngine::unregister_port (boost::shared_ptr<Port> port)
+AudioEngine::discover_backends ()
 {
-       /* caller must hold process lock */
+       vector<std::string> backend_modules;
 
-       if (!_running) {
-               /* probably happening when the engine has been halted by JACK,
-                  in which case, there is nothing we can do here.
-                  */
-               return 0;
-       }
+       _backends.clear ();
 
-       {
-               RCUWriter<Ports> writer (ports);
-               boost::shared_ptr<Ports> ps = writer.get_copy ();
-               Ports::iterator x = ps->find (make_port_name_relative (port->name()));
+       Glib::PatternSpec so_extension_pattern("*backend.so");
+       Glib::PatternSpec dylib_extension_pattern("*backend.dylib");
 
-               if (x != ps->end()) {
-                       ps->erase (x);
-               }
-
-               /* writer goes out of scope, forces update */
-       }
+#if defined(PLATFORM_WINDOWS) && defined(DEBUGGABLE_BACKENDS)
+       #if defined(DEBUG) || defined(_DEBUG)
+               Glib::PatternSpec dll_extension_pattern("*backendD.dll");
+       #else
+               Glib::PatternSpec dll_extension_pattern("*backendRDC.dll");
+       #endif
+#else
+       Glib::PatternSpec dll_extension_pattern("*backend.dll");
+#endif
 
-       ports.flush ();
+       find_files_matching_pattern (backend_modules, backend_search_path (),
+                                    so_extension_pattern);
 
-       return 0;
-}
+       find_files_matching_pattern (backend_modules, backend_search_path (),
+                                    dylib_extension_pattern);
 
-int
-AudioEngine::connect (const string& source, const string& destination)
-{
-       int ret;
+       find_files_matching_pattern (backend_modules, backend_search_path (),
+                                    dll_extension_pattern);
 
-       if (!_running) {
-               if (!_has_run) {
-                       fatal << _("connect called before engine was started") << endmsg;
-                       /*NOTREACHED*/
-               } else {
-                       return -1;
-               }
-       }
+       DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("looking for backends in %1\n", backend_search_path().to_string()));
 
-       string s = make_port_name_non_relative (source);
-       string d = make_port_name_non_relative (destination);
+       for (vector<std::string>::iterator i = backend_modules.begin(); i != backend_modules.end(); ++i) {
 
+               AudioBackendInfo* info;
 
-       boost::shared_ptr<Port> src = get_port_by_name (s);
-       boost::shared_ptr<Port> dst = get_port_by_name (d);
+               DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("Checking possible backend in %1\n", *i));
 
-       if (src) {
-               ret = src->connect (d);
-       } else if (dst) {
-               ret = dst->connect (s);
-       } else {
-               /* neither port is known to us, and this API isn't intended for use as a general patch bay */
-               ret = -1;
+               if ((info = backend_discover (*i)) != 0) {
+                       _backends.insert (make_pair (info->name, info));
+               }
        }
 
-       if (ret > 0) {
-               /* already exists - no error, no warning */
-       } else if (ret < 0) {
-               error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
-                                       source, s, destination, d)
-                     << endmsg;
-       }
+       DEBUG_TRACE (DEBUG::AudioEngine, string_compose ("Found %1 backends\n", _backends.size()));
 
-       return ret;
+       return _backends.size();
 }
 
-int
-AudioEngine::disconnect (const string& source, const string& destination)
+AudioBackendInfo*
+AudioEngine::backend_discover (const string& path)
 {
-       int ret;
+#ifdef PLATFORM_WINDOWS
+       // do not show popup dialog (e.g. missing libjack.dll)
+       // win7+ should use SetThreadErrorMode()
+       SetErrorMode(SEM_FAILCRITICALERRORS);
+#endif
+       Glib::Module module (path);
+#ifdef PLATFORM_WINDOWS
+       SetErrorMode(0); // reset to system default
+#endif
+       AudioBackendInfo* info;
+       AudioBackendInfo* (*dfunc)(void);
+       void* func = 0;
 
-       if (!_running) {
-               if (!_has_run) {
-                       fatal << _("disconnect called before engine was started") << endmsg;
-                       /*NOTREACHED*/
-               } else {
-                       return -1;
-               }
+       if (!module) {
+               error << string_compose(_("AudioEngine: cannot load module \"%1\" (%2)"), path,
+                                       Glib::Module::get_last_error()) << endmsg;
+               return 0;
        }
 
-       string s = make_port_name_non_relative (source);
-       string d = make_port_name_non_relative (destination);
-
-       boost::shared_ptr<Port> src = get_port_by_name (s);
-       boost::shared_ptr<Port> dst = get_port_by_name (d);
+       if (!module.get_symbol ("descriptor", func)) {
+               error << string_compose(_("AudioEngine: backend at \"%1\" has no descriptor function."), path) << endmsg;
+               error << Glib::Module::get_last_error() << endmsg;
+               return 0;
+       }
 
-       if (src) {
-                       ret = src->disconnect (d);
-       } else if (dst) {
-                       ret = dst->disconnect (s);
-       } else {
-               /* neither port is known to us, and this API isn't intended for use as a general patch bay */
-               ret = -1;
+       dfunc = (AudioBackendInfo* (*)(void))func;
+       info = dfunc();
+       if (!info->available()) {
+               return 0;
        }
-       return ret;
+
+       module.make_resident ();
+
+       return info;
 }
 
-int
-AudioEngine::disconnect (boost::shared_ptr<Port> port)
+vector<const AudioBackendInfo*>
+AudioEngine::available_backends() const
 {
-       GET_PRIVATE_JACK_POINTER_RET (_jack,-1);
+       vector<const AudioBackendInfo*> r;
 
-       if (!_running) {
-               if (!_has_run) {
-                       fatal << _("disconnect called before engine was started") << endmsg;
-                       /*NOTREACHED*/
-               } else {
-                       return -1;
-               }
+       for (BackendMap::const_iterator i = _backends.begin(); i != _backends.end(); ++i) {
+               r.push_back (i->second);
        }
 
-       return port->disconnect_all ();
+       return r;
 }
 
-ARDOUR::framecnt_t
-AudioEngine::frame_rate () const
+string
+AudioEngine::current_backend_name() const
 {
-       GET_PRIVATE_JACK_POINTER_RET (_jack, 0);
-       if (_frame_rate == 0) {
-               return (_frame_rate = jack_get_sample_rate (_priv_jack));
-       } else {
-               return _frame_rate;
+       if (_backend) {
+               return _backend->name();
        }
+       return string();
 }
 
-size_t
-AudioEngine::raw_buffer_size (DataType t)
-{
-       std::map<DataType,size_t>::const_iterator s = _raw_buffer_sizes.find(t);
-       return (s != _raw_buffer_sizes.end()) ? s->second : 0;
+void
+AudioEngine::drop_backend ()
+{
+       if (_backend) {
+               _backend->stop ();
+               // Stopped is needed for Graph to explicitly terminate threads
+               Stopped (); /* EMIT SIGNAL */
+               _backend->drop_device ();
+               _backend.reset ();
+               _running = false;
+       }
 }
 
-ARDOUR::pframes_t
-AudioEngine::frames_per_cycle () const
+boost::shared_ptr<AudioBackend>
+AudioEngine::set_default_backend ()
 {
-       GET_PRIVATE_JACK_POINTER_RET (_jack,0);
-       if (_buffer_size == 0) {
-               return jack_get_buffer_size (_jack);
-       } else {
-               return _buffer_size;
+       if (_backends.empty()) {
+               return boost::shared_ptr<AudioBackend>();
        }
-}
 
-/** @param name Full or short name of port
- *  @return Corresponding Port or 0.
- */
+       return set_backend (_backends.begin()->first, "", "");
+}
 
-boost::shared_ptr<Port>
-AudioEngine::get_port_by_name (const string& portname)
+boost::shared_ptr<AudioBackend>
+AudioEngine::set_backend (const std::string& name, const std::string& arg1, const std::string& arg2)
 {
-       if (!_running) {
-               if (!_has_run) {
-                       fatal << _("get_port_by_name() called before engine was started") << endmsg;
-                       /*NOTREACHED*/
-               } else {
-                       boost::shared_ptr<Port> ();
-               }
-       }
+       BackendMap::iterator b = _backends.find (name);
 
-        if (!port_is_mine (portname)) {
-                /* not an ardour port */
-                return boost::shared_ptr<Port> ();
-        }
+       if (b == _backends.end()) {
+               return boost::shared_ptr<AudioBackend>();
+       }
 
-       boost::shared_ptr<Ports> pr = ports.reader();
-       std::string rel = make_port_name_relative (portname);
-       Ports::iterator x = pr->find (rel);
+       drop_backend ();
 
-       if (x != pr->end()) {
-               /* its possible that the port was renamed by some 3rd party and
-                  we don't know about it. check for this (the check is quick
-                  and cheap), and if so, rename the port (which will alter
-                  the port map as a side effect).
-               */
-               const std::string check = make_port_name_relative (jack_port_name (x->second->jack_port()));
-               if (check != rel) {
-                       x->second->set_name (check);
+       try {
+               if (b->second->instantiate (arg1, arg2)) {
+                       throw failed_constructor ();
                }
-               return x->second;
-       }
 
-        return boost::shared_ptr<Port> ();
-}
+               _backend = b->second->factory (*this);
 
-void
-AudioEngine::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
-{
-       RCUWriter<Ports> writer (ports);
-       boost::shared_ptr<Ports> p = writer.get_copy();
-       Ports::iterator x = p->find (old_relative_name);
-       
-       if (x != p->end()) {
-               boost::shared_ptr<Port> port = x->second;
-               p->erase (x);
-               p->insert (make_pair (new_relative_name, port));
+       } catch (exception& e) {
+               error << string_compose (_("Could not create backend for %1: %2"), name, e.what()) << endmsg;
+               return boost::shared_ptr<AudioBackend>();
        }
-}
 
-const char **
-AudioEngine::get_ports (const string& port_name_pattern, const string& type_name_pattern, uint32_t flags)
-{
-       GET_PRIVATE_JACK_POINTER_RET (_jack,0);
-       if (!_running) {
-               if (!_has_run) {
-                       fatal << _("get_ports called before engine was started") << endmsg;
-                       /*NOTREACHED*/
-               } else {
-                       return 0;
-               }
-       }
-       return jack_get_ports (_priv_jack, port_name_pattern.c_str(), type_name_pattern.c_str(), flags);
+       return _backend;
 }
 
-void
-AudioEngine::halted_info (jack_status_t code, const char* reason, void *arg)
-{
-        /* called from jack shutdown handler  */
+/* BACKEND PROXY WRAPPERS */
 
-        AudioEngine* ae = static_cast<AudioEngine *> (arg);
-        bool was_running = ae->_running;
+int
+AudioEngine::start (bool for_latency)
+{
+       if (!_backend) {
+               return -1;
+       }
 
-        ae->stop_metering_thread ();
+       if (_running) {
+               return 0;
+       }
 
-        ae->_running = false;
-        ae->_buffer_size = 0;
-        ae->_frame_rate = 0;
-        ae->_jack = 0;
+       _processed_frames = 0;
+       last_monitor_check = 0;
 
-        if (was_running) {
-               MIDI::JackMIDIPort::JackHalted (); /* EMIT SIGNAL */
-#ifdef HAVE_JACK_ON_INFO_SHUTDOWN
-                switch (code) {
-                case JackBackendError:
-                        ae->Halted(reason); /* EMIT SIGNAL */
-                        break;
-                default:
-                        ae->Halted(""); /* EMIT SIGNAL */
-                }
-#else
-                ae->Halted(""); /* EMIT SIGNAL */
-#endif
-        }
-}
+       int error_code = _backend->start (for_latency);
 
-void
-AudioEngine::halted (void *arg)
-{
-        cerr << "HALTED by JACK\n";
+       if (error_code != 0) {
+               _last_backend_error_string =
+                   AudioBackend::get_error_string((AudioBackend::ErrorCode)error_code);
+               return -1;
+       }
 
-        /* called from jack shutdown handler  */
+       _running = true;
 
-       AudioEngine* ae = static_cast<AudioEngine *> (arg);
-       bool was_running = ae->_running;
+       if (_session) {
+               _session->set_frame_rate (_backend->sample_rate());
 
-       ae->stop_metering_thread ();
+               if (_session->config.get_jack_time_master()) {
+                       _backend->set_time_master (true);
+               }
 
-       ae->_running = false;
-       ae->_buffer_size = 0;
-       ae->_frame_rate = 0;
-        ae->_jack = 0;
+       }
 
-       if (was_running) {
-               MIDI::JackMIDIPort::JackHalted (); /* EMIT SIGNAL */
-               ae->Halted(""); /* EMIT SIGNAL */
+       if (!for_latency) {
+               Running(); /* EMIT SIGNAL */
        }
+
+       return 0;
 }
 
-void
-AudioEngine::died ()
+int
+AudioEngine::stop (bool for_latency)
 {
-        /* called from a signal handler for SIGPIPE */
+       bool stop_engine = true;
 
-       stop_metering_thread ();
+       if (!_backend) {
+               return 0;
+       }
 
-        _running = false;
-       _buffer_size = 0;
-       _frame_rate = 0;
-       _jack = 0;
-}
+       Glib::Threads::Mutex::Lock pl (_process_lock, Glib::Threads::NOT_LOCK);
 
-bool
-AudioEngine::can_request_hardware_monitoring ()
-{
-       GET_PRIVATE_JACK_POINTER_RET (_jack,false);
-       const char ** ports;
+       if (running()) {
+               pl.acquire ();
+       }
 
-       if ((ports = jack_get_ports (_priv_jack, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortCanMonitor)) == 0) {
-               return false;
+       if (for_latency && _backend->can_change_systemic_latency_when_running()) {
+               stop_engine = false;
+       } else {
+               if (_backend->stop ()) {
+                       pl.release ();
+                       return -1;
+               }
        }
 
-       free (ports);
+       if (pl.locked ()) {
+               pl.release ();
+       }
 
-       return true;
-}
+       if (_session && _running && stop_engine &&
+           (_session->state_of_the_state() & Session::Loading) == 0 &&
+           (_session->state_of_the_state() & Session::Deletion) == 0) {
+               // it's not a halt, but should be handled the same way:
+               // disable record, stop transport and I/O processign but save the data.
+               _session->engine_halted ();
+       }
 
-ChanCount
-AudioEngine::n_physical (unsigned long flags) const
-{
-       ChanCount c;
+       if (stop_engine) {
+               _running = false;
+       }
+       _processed_frames = 0;
+       _measuring_latency = MeasureNone;
+       _latency_output_port = 0;
+       _latency_input_port = 0;
+       _started_for_latency = false;
 
-       GET_PRIVATE_JACK_POINTER_RET (_jack, c);
+       if (stop_engine) {
+               Port::PortDrop ();
+       }
 
-       const char ** ports = jack_get_ports (_priv_jack, NULL, NULL, JackPortIsPhysical | flags);
-       if (ports == 0) {
-               return c;
+       if (!for_latency && stop_engine) {
+               Stopped (); /* EMIT SIGNAL */
        }
 
-       for (uint32_t i = 0; ports[i]; ++i) {
-               if (!strstr (ports[i], "Midi-Through")) {
-                       DataType t (jack_port_type (jack_port_by_name (_jack, ports[i])));
-                       c.set (t, c.get (t) + 1);
-               }
+       return 0;
+}
+
+int
+AudioEngine::freewheel (bool start_stop)
+{
+       if (!_backend) {
+               return -1;
        }
 
-       free (ports);
+       /* _freewheeling will be set when first Freewheel signal occurs */
 
-       return c;
+       return _backend->freewheel (start_stop);
 }
 
-ChanCount
-AudioEngine::n_physical_inputs () const
+float
+AudioEngine::get_dsp_load() const
 {
-       return n_physical (JackPortIsInput);
+       if (!_backend || !_running) {
+               return 0.0;
+       }
+       return _backend->dsp_load ();
 }
 
-ChanCount
-AudioEngine::n_physical_outputs () const
+bool
+AudioEngine::is_realtime() const
 {
-       return n_physical (JackPortIsOutput);
+       if (!_backend) {
+               return false;
+       }
+
+       return _backend->is_realtime();
 }
 
-void
-AudioEngine::get_physical (DataType type, unsigned long flags, vector<string>& phy)
+bool
+AudioEngine::connected() const
 {
-       GET_PRIVATE_JACK_POINTER (_jack);
-       const char ** ports;
-
-       if ((ports = jack_get_ports (_priv_jack, NULL, type.to_jack_type(), JackPortIsPhysical | flags)) == 0) {
-               return;
+       if (!_backend) {
+               return false;
        }
 
-       if (ports) {
-               for (uint32_t i = 0; ports[i]; ++i) {
-                        if (strstr (ports[i], "Midi-Through")) {
-                                continue;
-                        }
-                       phy.push_back (ports[i]);
-               }
-               free (ports);
-       }
+       return _backend->available();
 }
 
-/** Get physical ports for which JackPortIsOutput is set; ie those that correspond to
- *  a physical input connector.
- */
 void
-AudioEngine::get_physical_inputs (DataType type, vector<string>& ins)
+AudioEngine::transport_start ()
 {
-       get_physical (type, JackPortIsOutput, ins);
+       if (!_backend) {
+               return;
+       }
+       return _backend->transport_start ();
 }
 
-/** Get physical ports for which JackPortIsInput is set; ie those that correspond to
- *  a physical output connector.
- */
 void
-AudioEngine::get_physical_outputs (DataType type, vector<string>& outs)
+AudioEngine::transport_stop ()
 {
-       get_physical (type, JackPortIsInput, outs);
+       if (!_backend) {
+               return;
+       }
+       return _backend->transport_stop ();
 }
 
-void
-AudioEngine::transport_stop ()
+TransportState
+AudioEngine::transport_state ()
 {
-       GET_PRIVATE_JACK_POINTER (_jack);
-       jack_transport_stop (_priv_jack);
+       if (!_backend) {
+               return TransportStopped;
+       }
+       return _backend->transport_state ();
 }
 
 void
-AudioEngine::transport_start ()
+AudioEngine::transport_locate (framepos_t pos)
 {
-       GET_PRIVATE_JACK_POINTER (_jack);
-       jack_transport_start (_priv_jack);
+       if (!_backend) {
+               return;
+       }
+       return _backend->transport_locate (pos);
 }
 
-void
-AudioEngine::transport_locate (framepos_t where)
+framepos_t
+AudioEngine::transport_frame()
 {
-       GET_PRIVATE_JACK_POINTER (_jack);
-       jack_transport_locate (_priv_jack, where);
+       if (!_backend) {
+               return 0;
+       }
+       return _backend->transport_frame ();
 }
 
-AudioEngine::TransportState
-AudioEngine::transport_state ()
+framecnt_t
+AudioEngine::sample_rate () const
 {
-       GET_PRIVATE_JACK_POINTER_RET (_jack, ((TransportState) JackTransportStopped));
-       jack_position_t pos;
-       return (TransportState) jack_transport_query (_priv_jack, &pos);
+       if (!_backend) {
+               return 0;
+       }
+       return _backend->sample_rate ();
 }
 
-int
-AudioEngine::reset_timebase ()
+pframes_t
+AudioEngine::samples_per_cycle () const
 {
-       GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
-       if (_session) {
-               if (_session->config.get_jack_time_master()) {
-                       return jack_set_timebase_callback (_priv_jack, 0, _jack_timebase_callback, this);
-               } else {
-                       return jack_release_timebase (_jack);
-               }
+       if (!_backend) {
+               return 0;
        }
-       return 0;
+       return _backend->buffer_size ();
 }
 
 int
-AudioEngine::freewheel (bool onoff)
+AudioEngine::usecs_per_cycle () const
 {
-       GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
-
-       if (onoff != _freewheeling) {
-                return jack_set_freewheel (_priv_jack, onoff);
-
-       } else {
-                /* already doing what has been asked for */
-                return 0;
+       if (!_backend) {
+               return -1;
        }
+       return _backend->usecs_per_cycle ();
 }
 
-void
-AudioEngine::remove_all_ports ()
+size_t
+AudioEngine::raw_buffer_size (DataType t)
 {
-       /* make sure that JACK callbacks that will be invoked as we cleanup
-        * ports know that they have nothing to do.
-        */
-
-       port_remove_in_progress = true;
-
-       /* process lock MUST be held by caller
-       */
+       if (!_backend) {
+               return -1;
+       }
+       return _backend->raw_buffer_size (t);
+}
 
-       {
-               RCUWriter<Ports> writer (ports);
-               boost::shared_ptr<Ports> ps = writer.get_copy ();
-               ps->clear ();
+framepos_t
+AudioEngine::sample_time ()
+{
+       if (!_backend) {
+               return 0;
        }
+       return _backend->sample_time ();
+}
 
-       /* clear dead wood list in RCU */
+framepos_t
+AudioEngine::sample_time_at_cycle_start ()
+{
+       if (!_backend) {
+               return 0;
+       }
+       return _backend->sample_time_at_cycle_start ();
+}
 
-       ports.flush ();
+pframes_t
+AudioEngine::samples_since_cycle_start ()
+{
+       if (!_backend) {
+               return 0;
+       }
+       return _backend->samples_since_cycle_start ();
+}
 
-       port_remove_in_progress = false;
+bool
+AudioEngine::get_sync_offset (pframes_t& offset) const
+{
+       if (!_backend) {
+               return false;
+       }
+       return _backend->get_sync_offset (offset);
 }
 
 int
-AudioEngine::connect_to_jack (string client_name, string session_uuid)
+AudioEngine::create_process_thread (boost::function<void()> func)
 {
-        EnvironmentalProtectionAgency* global_epa = EnvironmentalProtectionAgency::get_global_epa ();
-        boost::scoped_ptr<EnvironmentalProtectionAgency> current_epa;
-       jack_status_t status;
-
-        /* revert all environment settings back to whatever they were when ardour started
-         */
-
-        if (global_epa) {
-                current_epa.reset (new EnvironmentalProtectionAgency(true)); /* will restore settings when we leave scope */
-                global_epa->restore ();
-        }
-
-       jack_client_name = client_name; /* might be reset below */
-#ifdef HAVE_JACK_SESSION
-       if (! session_uuid.empty())
-           _jack = jack_client_open (jack_client_name.c_str(), JackSessionID, &status, session_uuid.c_str());
-       else
-#endif
-       _jack = jack_client_open (jack_client_name.c_str(), JackNullOption, &status, 0);
-
-       if (_jack == NULL) {
-               // error message is not useful here
+       if (!_backend) {
                return -1;
        }
-
-       GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
-
-       if (status & JackNameNotUnique) {
-               jack_client_name = jack_get_client_name (_priv_jack);
-       }
-
-       return 0;
+       return _backend->create_process_thread (func);
 }
 
 int
-AudioEngine::disconnect_from_jack ()
+AudioEngine::join_process_threads ()
 {
-       GET_PRIVATE_JACK_POINTER_RET (_jack, 0);
-
-       if (_running) {
-               stop_metering_thread ();
+       if (!_backend) {
+               return -1;
        }
+       return _backend->join_process_threads ();
+}
 
-       {
-               Glib::Threads::Mutex::Lock lm (_process_lock);
-               jack_client_close (_priv_jack);
-               _jack = 0;
+bool
+AudioEngine::in_process_thread ()
+{
+       if (!_backend) {
+               return false;
        }
+       return _backend->in_process_thread ();
+}
 
-       _buffer_size = 0;
-       _frame_rate = 0;
-       _raw_buffer_sizes.clear();
-
-       if (_running) {
-               _running = false;
-               MIDI::JackMIDIPort::JackHalted (); /* EMIT SIGNAL */
-               Stopped(); /* EMIT SIGNAL */
+uint32_t
+AudioEngine::process_thread_count ()
+{
+       if (!_backend) {
+               return 0;
        }
-
-       return 0;
+       return _backend->process_thread_count ();
 }
 
 int
-AudioEngine::reconnect_to_jack ()
+AudioEngine::set_device_name (const std::string& name)
 {
-       if (_running) {
-               disconnect_from_jack ();
-               /* XXX give jackd a chance */
-               Glib::usleep (250000);
+       if (!_backend) {
+               return -1;
        }
+       return _backend->set_device_name  (name);
+}
 
-       if (connect_to_jack (jack_client_name, "")) {
-               error << _("failed to connect to JACK") << endmsg;
+int
+AudioEngine::set_sample_rate (float sr)
+{
+       if (!_backend) {
                return -1;
        }
 
-       Ports::iterator i;
-
-       boost::shared_ptr<Ports> p = ports.reader ();
+       return _backend->set_sample_rate  (sr);
+}
 
-       for (i = p->begin(); i != p->end(); ++i) {
-               if (i->second->reestablish ()) {
-                       break;
-               }
+int
+AudioEngine::set_buffer_size (uint32_t bufsiz)
+{
+       if (!_backend) {
+               return -1;
        }
+       return _backend->set_buffer_size  (bufsiz);
+}
 
-       if (i != p->end()) {
-               /* failed */
-               remove_all_ports ();
+int
+AudioEngine::set_interleaved (bool yn)
+{
+       if (!_backend) {
                return -1;
        }
+       return _backend->set_interleaved  (yn);
+}
 
-       GET_PRIVATE_JACK_POINTER_RET (_jack,-1);
-
-       MIDI::Manager::instance()->reestablish (_priv_jack);
-
-       if (_session) {
-               _session->reset_jack_connection (_priv_jack);
-                jack_bufsize_callback (jack_get_buffer_size (_priv_jack));
-               _session->set_frame_rate (jack_get_sample_rate (_priv_jack));
+int
+AudioEngine::set_input_channels (uint32_t ic)
+{
+       if (!_backend) {
+               return -1;
        }
+       return _backend->set_input_channels  (ic);
+}
 
-       last_monitor_check = 0;
-
-        set_jack_callbacks ();
-
-       if (jack_activate (_priv_jack) == 0) {
-               _running = true;
-               _has_run = true;
-       } else {
+int
+AudioEngine::set_output_channels (uint32_t oc)
+{
+       if (!_backend) {
                return -1;
        }
+       return _backend->set_output_channels (oc);
+}
 
-       /* re-establish connections */
-
-       for (i = p->begin(); i != p->end(); ++i) {
-               i->second->reconnect ();
+int
+AudioEngine::set_systemic_input_latency (uint32_t il)
+{
+       if (!_backend) {
+               return -1;
        }
-
-       MIDI::Manager::instance()->reconnect ();
-
-       Running (); /* EMIT SIGNAL*/
-
-       start_metering_thread ();
-
-       return 0;
+       return _backend->set_systemic_input_latency  (il);
 }
 
 int
-AudioEngine::request_buffer_size (pframes_t nframes)
+AudioEngine::set_systemic_output_latency (uint32_t ol)
 {
-       GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
-
-       if (nframes == jack_get_buffer_size (_priv_jack)) {
-                return 0;
+       if (!_backend) {
+               return -1;
        }
+       return _backend->set_systemic_output_latency  (ol);
+}
 
-       return jack_set_buffer_size (_priv_jack, nframes);
+bool
+AudioEngine::thread_initialised_for_audio_processing ()
+{
+    return SessionEvent::has_per_thread_pool () && AsyncMIDIPort::is_process_thread();
 }
 
-string
-AudioEngine::make_port_name_relative (string portname) const
+/* END OF BACKEND PROXY API */
+
+void
+AudioEngine::thread_init_callback (void* arg)
 {
-       string::size_type len;
-       string::size_type n;
+       /* make sure that anybody who needs to know about this thread
+          knows about it.
+       */
 
-       len = portname.length();
+       pthread_set_name (X_("audioengine"));
 
-       for (n = 0; n < len; ++n) {
-               if (portname[n] == ':') {
-                       break;
-               }
-       }
+       SessionEvent::create_per_thread_pool (X_("AudioEngine"), 512);
 
-       if ((n != len) && (portname.substr (0, n) == jack_client_name)) {
-               return portname.substr (n+1);
-       }
+       PBD::notify_gui_about_thread_creation ("gui", pthread_self(), X_("AudioEngine"), 4096);
+       PBD::notify_gui_about_thread_creation ("midiUI", pthread_self(), X_("AudioEngine"), 128);
 
-       return portname;
+       AsyncMIDIPort::set_process_thread (pthread_self());
+
+       if (arg) {
+               /* the special thread created/managed by the backend */
+               AudioEngine::instance()->_main_thread = new ProcessThread;
+       }
 }
 
-string
-AudioEngine::make_port_name_non_relative (string portname) const
+int
+AudioEngine::sync_callback (TransportState state, framepos_t position)
 {
-       string str;
-
-       if (portname.find_first_of (':') != string::npos) {
-               return portname;
+       if (_session) {
+               return _session->backend_sync_callback (state, position);
        }
+       return 0;
+}
 
-       str  = jack_client_name;
-       str += ':';
-       str += portname;
-
-       return str;
+void
+AudioEngine::freewheel_callback (bool onoff)
+{
+       _freewheeling = onoff;
 }
 
-bool
-AudioEngine::port_is_mine (const string& portname) const
+void
+AudioEngine::latency_callback (bool for_playback)
 {
-       if (portname.find_first_of (':') != string::npos) {
-               if (portname.substr (0, jack_client_name.length ()) != jack_client_name) {
-                        return false;
-                }
+        if (_session) {
+                _session->update_latency (for_playback);
         }
-        return true;
 }
 
-bool
-AudioEngine::is_realtime () const
+void
+AudioEngine::update_latencies ()
 {
-       GET_PRIVATE_JACK_POINTER_RET (_jack,false);
-       return jack_is_realtime (_priv_jack);
+       if (_backend) {
+               _backend->update_latencies ();
+       }
 }
 
-int
-AudioEngine::create_process_thread (boost::function<void()> f, jack_native_thread_t* thread, size_t stacksize)
+void
+AudioEngine::halted_callback (const char* why)
 {
-        GET_PRIVATE_JACK_POINTER_RET (_jack, 0);
-        ThreadData* td = new ThreadData (this, f, stacksize);
+       if (_in_destructor) {
+               /* everything is under control */
+               return;
+       }
 
-        if (jack_client_create_thread (_priv_jack, thread, jack_client_real_time_priority (_priv_jack),
-                                       jack_is_realtime (_priv_jack), _start_process_thread, td)) {
-                return -1;
-        }
+       _running = false;
 
-        return 0;
+       Port::PortDrop (); /* EMIT SIGNAL */
+
+       if (!_started_for_latency) {
+               Halted (why);      /* EMIT SIGNAL */
+       }
 }
 
 bool
-AudioEngine::stop_process_thread (jack_native_thread_t thread)
+AudioEngine::setup_required () const
 {
-       /**
-        * can't use GET_PRIVATE_JACK_POINTER_RET (_jack, 0) here
-        * because _jack is 0 when this is called. At least for
-        * Jack 2 _jack arg is not used so it should be OK
-        */
-
-#ifdef USING_JACK2_EXPANSION_OF_JACK_API
-       if (jack_client_stop_thread (_jack, thread) != 0) {
-               error << "AudioEngine: cannot stop process thread" << endmsg;
-               return false;
+       if (_backend) {
+               if (_backend->info().already_configured())
+                       return false;
+       } else {
+               if (_backends.size() == 1 && _backends.begin()->second->already_configured()) {
+                       return false;
+               }
        }
-#else
-       void* status;
-       pthread_join (thread, &status);
-#endif
 
        return true;
 }
 
-void*
-AudioEngine::_start_process_thread (void* arg)
+int
+AudioEngine::prepare_for_latency_measurement ()
 {
-        ThreadData* td = reinterpret_cast<ThreadData*> (arg);
-        boost::function<void()> f = td->f;
-        delete td;
+       if (!_backend) {
+               return -1;
+       }
+
+       if (_backend->can_change_systemic_latency_when_running()) {
+               if (start()) {
+                       return -1;
+               }
+               _backend->set_systemic_input_latency (0);
+               _backend->set_systemic_output_latency (0);
+               return 0;
+       }
 
-        f ();
+       if (running()) {
+               _stopped_for_latency = true;
+               stop (true);
+       }
+
+       if (start (true)) {
+               return -1;
+       }
+       _started_for_latency = true;
 
-        return 0;
+       return 0;
 }
 
-bool
-AudioEngine::port_is_physical (const std::string& portname) const
+int
+AudioEngine::start_latency_detection (bool for_midi)
 {
-        GET_PRIVATE_JACK_POINTER_RET(_jack, false);
+       if (prepare_for_latency_measurement ()) {
+               return -1;
+       }
 
-        jack_port_t *port = jack_port_by_name (_priv_jack, portname.c_str());
+       PortEngine& pe (port_engine());
 
-        if (!port) {
-                return false;
-        }
+       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 {
 
-        return jack_port_flags (port) & JackPortIsPhysical;
+               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_frames = samples_per_cycle();
+       _measuring_latency = for_midi ? MeasureMIDI : MeasureAudio;
+
+       return 0;
 }
 
 void
-AudioEngine::request_jack_monitors_input (const std::string& portname, bool yn) const
+AudioEngine::stop_latency_detection ()
 {
-        GET_PRIVATE_JACK_POINTER(_jack);
+       _measuring_latency = MeasureNone;
 
-        jack_port_t *port = jack_port_by_name (_priv_jack, portname.c_str());
+       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 (!port) {
-                return;
-        }
+       if (!_backend->can_change_systemic_latency_when_running()) {
+               stop (true);
+       }
+
+       if (_stopped_for_latency) {
+               start ();
+       }
 
-        jack_port_request_monitor (port, yn);
+       _stopped_for_latency = false;
+       _started_for_latency = false;
 }
 
 void
-AudioEngine::update_latencies ()
+AudioEngine::set_latency_output_port (const string& name)
 {
-        if (jack_recompute_total_latencies) {
-                GET_PRIVATE_JACK_POINTER (_jack);
-                jack_recompute_total_latencies (_priv_jack);
-        }
+       _latency_output_name = name;
 }
 
 void
-AudioEngine::destroy ()
+AudioEngine::set_latency_input_port (const string& name)
 {
-       delete _instance;
-       _instance = 0;
+       _latency_input_name = name;
 }
-