Merge branch 'master' into cairocanvas
[ardour.git] / libs / ardour / audioengine.cc
index 5e3e5ba9e2c10882218fa8b56b37e75d5d104086..cb167c959579dfddc96348fca598fae5e3b6b707 100644 (file)
 #include <sstream>
 
 #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/backend_search_path.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/mtdm.h"
 #include "ardour/port.h"
 #include "ardour/process_thread.h"
 #include "ardour/session.h"
@@ -56,60 +62,46 @@ 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; }
-
-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)
+       , _measuring_latency (false)
+       , _latency_input_port (0)
+       , _latency_output_port (0)
+       , _latency_flush_frames (0)
+       , _latency_signal_latency (0)
+       , _stopped_for_latency (false)
+       , _in_destructor (false)
 {
-       _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);
+       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_metering_thread ();
+       drop_backend ();
 }
 
-jack_client_t*
-AudioEngine::jack() const
+AudioEngine*
+AudioEngine::create ()
 {
-       return _jack;
+       if (_instance) {
+               return _instance;
+       }
+
+       _instance = new AudioEngine ();
+       
+       return _instance;
 }
 
 void
@@ -126,290 +118,7 @@ _thread_init_callback (void * /*arg*/)
 
        SessionEvent::create_per_thread_pool (X_("Audioengine"), 512);
 
-       MIDI::JackMIDIPort::set_process_thread (pthread_self());
-}
-
-static void
-ardour_jack_error (const char* msg)
-{
-       error << "JACK: " << msg << endmsg;
-}
-
-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 ()
-{
-       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));
-               }
-
-                /* 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.
-                 */
-
-                if (!jack_port_type_get_buffer_size) {
-                       jack_bufsize_callback (jack_get_buffer_size (_priv_jack));
-                }
-               
-               _processed_frames = 0;
-               last_monitor_check = 0;
-
-                set_jack_callbacks ();
-
-               if (jack_activate (_priv_jack) == 0) {
-                       _running = true;
-                       _has_run = true;
-                       Running(); /* EMIT SIGNAL */
-               } else {
-                       // error << _("cannot activate JACK client") << endmsg;
-               }
-       }
-               
-       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
-{
-
-#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);
-
-               if (pos.valid & JackVideoFrameOffset) {
-                       offset = pos.video_offset;
-                       return true;
-               }
-       }
-#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);
-}
-
-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);
-       }
-}
-
-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);
-}
-
-int
-AudioEngine::jack_sync_callback (jack_transport_state_t state, jack_position_t* pos)
-{
-       if (_jack && _session) {
-               return _session->jack_sync_callback (state, pos);
-       }
-
-       return true;
-}
-
-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 */
-       }
-}
-#endif
-
-int
-AudioEngine::_graph_order_callback (void *arg)
-{
-       AudioEngine* ae = static_cast<AudioEngine*> (arg);
-
-       if (ae->connected() && !ae->port_remove_in_progress) {
-               ae->GraphReordered (); /* EMIT SIGNAL */
-       }
-       
-       return 0;
-}
-
-void*
-AudioEngine::_process_thread (void *arg)
-{
-       return static_cast<AudioEngine *> (arg)->process_thread ();
-}
-
-void
-AudioEngine::_freewheel_callback (int onoff, void *arg)
-{
-       static_cast<AudioEngine*>(arg)->freewheel_callback (onoff);
-}
-
-void
-AudioEngine::freewheel_callback (int onoff)
-{
-       _freewheeling = onoff;
-
-       if (onoff) {
-               _pre_freewheel_mmc_enabled = MIDI::Manager::instance()->mmc()->send_enabled ();
-               MIDI::Manager::instance()->mmc()->enable_send (false);
-       } else {
-               MIDI::Manager::instance()->mmc()->enable_send (_pre_freewheel_mmc_enabled);
-       }
-}
-
-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 */
-       }
-}
-
-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;
-       }
-
-       GET_PRIVATE_JACK_POINTER (_jack);
-
-       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);
-
-       boost::shared_ptr<Port> port_a;
-       boost::shared_ptr<Port> port_b;
-       Ports::iterator x;
-       boost::shared_ptr<Ports> pr = ports.reader ();
-
-
-       x = pr->find (make_port_name_relative (jack_port_name (jack_port_a)));
-       if (x != pr->end()) {
-               port_a = x->second;
-       }
-
-       x = pr->find (make_port_name_relative (jack_port_name (jack_port_b)));
-       if (x != pr->end()) {
-               port_b = x->second;
-       }
-
-       PortConnectedOrDisconnected (
-               port_a, jack_port_name (jack_port_a),
-               port_b, jack_port_name (jack_port_b),
-               conn == 0 ? false : true
-               ); /* EMIT SIGNAL */
+       AsyncMIDIPort::set_process_thread (pthread_self());
 }
 
 void
@@ -428,29 +137,32 @@ AudioEngine::split_cycle (pframes_t offset)
        }
 }
 
-void*
-AudioEngine::process_thread ()
+int
+AudioEngine::sample_rate_change (pframes_t nframes)
 {
-        /* JACK doesn't do this for us when we use the wait API
-         */
-
-        _thread_init_callback (0);
+       /* check for monitor input change every 1/10th of second */
 
-        _main_thread = new ProcessThread;
+       monitor_check_interval = nframes / 10;
+       last_monitor_check = 0;
 
-        while (1) {
-                GET_PRIVATE_JACK_POINTER_RET(_jack,0);
+       if (_session) {
+               _session->set_frame_rate (nframes);
+       }
 
-                pframes_t nframes = jack_cycle_wait (_priv_jack);
+       SampleRateChanged (nframes); /* EMIT SIGNAL */
 
-                if (process_callback (nframes)) {
-                        return 0;
-                }
+       return 0;
+}
 
-               jack_cycle_signal (_priv_jack, 0);
-        }
+int 
+AudioEngine::buffer_size_change (pframes_t bufsiz)
+{
+       if (_session) {
+               _session->set_block_size (bufsiz);
+               last_monitor_check = 0;
+       }
 
-        return 0;
+       return 0;
 }
 
 /** Method called by our ::process_thread when there is work to be done.
@@ -459,7 +171,6 @@ AudioEngine::process_thread ()
 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;
@@ -482,6 +193,50 @@ AudioEngine::process_callback (pframes_t nframes)
                return 0;
        }
 
+       bool return_after_remove_check = false;
+
+       if (_measuring_latency && _mtdm) {
+               /* run a normal cycle from the perspective of the PortManager
+                  so that we get silence on all registered ports.
+                  
+                  we overwrite the silence on the two ports used for latency
+                  measurement.
+               */
+               
+               PortManager::cycle_start (nframes);
+               PortManager::silence (nframes);
+
+               if (_latency_input_port && _latency_output_port) {
+                       PortEngine& pe (port_engine());
+
+                       Sample* in = (Sample*) pe.get_buffer (_latency_input_port, nframes);
+                       Sample* out = (Sample*) pe.get_buffer (_latency_output_port, nframes);
+
+                       _mtdm->process (nframes, in, out);
+               }
+
+               PortManager::cycle_end (nframes);
+               return_after_remove_check = true;
+
+       } else if (_latency_flush_frames) {
+               
+               /* wait for the appropriate duration for the MTDM signal to
+                * drain from the ports before we revert to normal behaviour.
+                */
+
+               PortManager::cycle_start (nframes);
+               PortManager::silence (nframes);
+               PortManager::cycle_end (nframes);
+               
+                if (_latency_flush_frames > nframes) {
+                        _latency_flush_frames -= nframes;
+                } else {
+                        _latency_flush_frames = 0;
+                }
+
+               return_after_remove_check = true;
+       }
+
        if (session_remove_pending) {
 
                /* perform the actual session removal */
@@ -489,7 +244,7 @@ AudioEngine::process_callback (pframes_t nframes)
                if (session_removal_countdown < 0) {
 
                        /* fade out over 1 second */
-                       session_removal_countdown = _frame_rate/2;
+                       session_removal_countdown = sample_rate()/2;
                        session_removal_gain = 1.0;
                        session_removal_gain_step = 1.0/session_removal_countdown;
 
@@ -518,11 +273,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,34 +292,22 @@ 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);
-
        } else {
-               MIDI::Manager::instance()->cycle_start(nframes);
-
                if (_session) {
                        _session->process (nframes);
                }
-
-               MIDI::Manager::instance()->cycle_end();
        }
 
        if (_freewheeling) {
@@ -573,52 +320,18 @@ AudioEngine::process_callback (pframes_t nframes)
        }
 
        if (last_monitor_check + monitor_check_interval < next_processed_frames) {
-
-               boost::shared_ptr<Ports> p = ports.reader();
-
-               for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
-
-                       bool x;
-
-                       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 */
-                       }
-               }
+               
+               PortManager::check_monitoring ();
                last_monitor_check = next_processed_frames;
        }
 
        if (_session->silent()) {
-
-               for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
-
-                       if (i->second->sends_output()) {
-                               i->second->get_buffer(nframes).silence(nframes);
-                       }
-               }
+               PortManager::silence (nframes);
        }
 
        if (session_remove_pending && session_removal_countdown) {
 
-               for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
-
-                       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;
-                                       }
-                               }
-                       }
-               }
+               PortManager::fade_out (session_removal_gain, session_removal_gain_step, nframes);
                
                if (session_removal_countdown > nframes) {
                        session_removal_countdown -= nframes;
@@ -629,11 +342,7 @@ 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;
 
@@ -642,110 +351,19 @@ AudioEngine::process_callback (pframes_t nframes)
        return 0;
 }
 
-int
-AudioEngine::_sample_rate_callback (pframes_t nframes, void *arg)
-{
-       return static_cast<AudioEngine *> (arg)->jack_sample_rate_callback (nframes);
-}
 
-int
-AudioEngine::jack_sample_rate_callback (pframes_t nframes)
+void
+AudioEngine::stop_metering_thread ()
 {
-       _frame_rate = nframes;
-       _usecs_per_cycle = (int) floor ((((double) frames_per_cycle() / nframes)) * 1000000.0);
-
-       /* check for monitor input change every 1/10th of second */
-
-       monitor_check_interval = nframes / 10;
-       last_monitor_check = 0;
-
-       if (_session) {
-               _session->set_frame_rate (nframes);
+       if (m_meter_thread) {
+               g_atomic_int_set (&m_meter_exit, 1);
+               m_meter_thread->join ();
+               m_meter_thread = 0;
        }
-
-       SampleRateChanged (nframes); /* EMIT SIGNAL */
-
-       return 0;
 }
 
 void
-AudioEngine::jack_latency_callback (jack_latency_callback_mode_t mode)
-{
-        if (_session) {
-                _session->update_latency (mode == JackPlaybackLatency);
-        }
-}
-
-int
-AudioEngine::_bufsize_callback (pframes_t nframes, void *arg)
-{
-       return static_cast<AudioEngine *> (arg)->jack_bufsize_callback (nframes);
-}
-
-int
-AudioEngine::jack_bufsize_callback (pframes_t nframes)
-{
-        /* if the size has not changed, this should be a no-op */
-
-        if (nframes == _buffer_size) {
-                return 0;
-        }
-
-       GET_PRIVATE_JACK_POINTER_RET (_jack, 1);
-
-       _buffer_size = nframes;
-       _usecs_per_cycle = (int) floor ((((double) nframes / frame_rate())) * 1000000.0);
-       last_monitor_check = 0;
-
-        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 {
-
-                /* Old version of JACK.
-
-                   These crude guesses, see below where we try to get the right answers.
-
-                   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.
-                */
-
-                _raw_buffer_sizes[DataType::AUDIO] = nframes * sizeof (Sample);
-                _raw_buffer_sizes[DataType::MIDI] = nframes * 4 - (nframes/2);
-        }
-
-       {
-               Glib::Threads::Mutex::Lock lm (_process_lock);
-
-               boost::shared_ptr<Ports> p = ports.reader();
-
-               for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
-                       i->second->reset();
-               }
-       }
-
-       if (_session) {
-               _session->set_block_size (_buffer_size);
-       }
-
-       return 0;
-}
-
-void
-AudioEngine::stop_metering_thread ()
-{
-       if (m_meter_thread) {
-               g_atomic_int_set (&m_meter_exit, 1);
-               m_meter_thread->join ();
-               m_meter_thread = 0;
-       }
-}
-
-void
-AudioEngine::start_metering_thread ()
+AudioEngine::start_metering_thread ()
 {
        if (m_meter_thread == 0) {
                g_atomic_int_set (&m_meter_exit, 0);
@@ -757,8 +375,9 @@ void
 AudioEngine::meter_thread ()
 {
        pthread_set_name (X_("meter"));
+
        while (true) {
-               Glib::usleep (10000);
+               Glib::usleep (10000); /* 1/100th sec interval */
                if (g_atomic_int_get(&m_meter_exit)) {
                        break;
                }
@@ -775,19 +394,9 @@ AudioEngine::set_session (Session *s)
 
        if (_session) {
 
-               start_metering_thread ();
+               pframes_t blocksize = samples_per_cycle ();
 
-               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();
-
-               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 +407,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 +418,9 @@ AudioEngine::remove_session ()
 
        if (_running) {
 
-               stop_metering_thread ();
-
                if (_session) {
                        session_remove_pending = true;
+                       session_removal_countdown = 0;
                        session_removed.wait(_process_lock);
                }
 
@@ -825,813 +431,727 @@ AudioEngine::remove_session ()
        remove_all_ports ();
 }
 
+
 void
-AudioEngine::port_registration_failure (const std::string& portname)
+AudioEngine::died ()
 {
-       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;
+        /* called from a signal handler for SIGPIPE */
 
-       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);
-       }
+       stop_metering_thread ();
 
-       throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
+        _running = false;
 }
 
-boost::shared_ptr<Port>
-AudioEngine::register_port (DataType dtype, const string& portname, bool input)
+int
+AudioEngine::reset_timebase ()
 {
-       boost::shared_ptr<Port> newport;
-
-       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)));
+       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);
-               }
+#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
+       
+       find_matching_files_in_search_path (backend_search_path (),
+                                           so_extension_pattern, backend_modules);
 
-               /* writer goes out of scope, forces update */
-       }
+       find_matching_files_in_search_path (backend_search_path (),
+                                           dylib_extension_pattern, backend_modules);
 
-       ports.flush ();
+       find_matching_files_in_search_path (backend_search_path (),
+                                           dll_extension_pattern, backend_modules);
 
-       return 0;
-}
+       DEBUG_TRACE (DEBUG::Panning, string_compose (_("looking for backends in %1\n"), backend_search_path().to_string()));
 
-int
-AudioEngine::connect (const string& source, const string& destination)
-{
-       int ret;
+       for (vector<std::string>::iterator i = backend_modules.begin(); i != backend_modules.end(); ++i) {
 
-       if (!_running) {
-               if (!_has_run) {
-                       fatal << _("connect called before engine was started") << endmsg;
-                       /*NOTREACHED*/
-               } else {
-                       return -1;
-               }
-       }
+               AudioBackendInfo* info;
 
-       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 (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 (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;
+               if ((info = backend_discover (*i)) != 0) {
+                       _backends.insert (make_pair (info->name, info));
+               }
        }
 
-       return ret;
+       return _backends.size();
 }
 
-int
-AudioEngine::disconnect (const string& source, const string& destination)
+AudioBackendInfo*
+AudioEngine::backend_discover (const string& path)
 {
-       int ret;
+       Glib::Module module (path);
+       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 (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;
+       
+       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;
        }
-       return ret;
+
+       module.make_resident ();
+       
+       dfunc = (AudioBackendInfo* (*)(void))func;
+       info = dfunc();
+       
+       return info;
 }
 
-int
-AudioEngine::disconnect (boost::shared_ptr<Port> port)
+vector<const AudioBackendInfo*>
+AudioEngine::available_backends() const
 {
-       GET_PRIVATE_JACK_POINTER_RET (_jack,-1);
-
-       if (!_running) {
-               if (!_has_run) {
-                       fatal << _("disconnect called before engine was started") << endmsg;
-                       /*NOTREACHED*/
-               } else {
-                       return -1;
-               }
+       vector<const AudioBackendInfo*> r;
+       
+       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)
+void
+AudioEngine::drop_backend ()
 {
-       std::map<DataType,size_t>::const_iterator s = _raw_buffer_sizes.find(t);
-       return (s != _raw_buffer_sizes.end()) ? s->second : 0;
+       if (_backend) {
+               _backend->stop ();
+               _backend.reset ();
+       }
 }
 
-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 (b == _backends.end()) {
+               return boost::shared_ptr<AudioBackend>();
        }
 
-        if (!port_is_mine (portname)) {
-                /* not an ardour port */
-                return boost::shared_ptr<Port> ();
-        }
+       drop_backend ();
+       
+       try {
+               if (b->second->instantiate (arg1, arg2)) {
+                       throw failed_constructor ();
+               }
 
-       boost::shared_ptr<Ports> pr = ports.reader();
-       std::string rel = make_port_name_relative (portname);
-       Ports::iterator x = pr->find (rel);
+               _backend = b->second->factory (*this);
 
-       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);
-               }
-               return x->second;
+       } catch (exception& e) {
+               error << string_compose (_("Could not create backend for %1: %2"), name, e.what()) << endmsg;
+               return boost::shared_ptr<AudioBackend>();
        }
 
-        return boost::shared_ptr<Port> ();
+       return _backend;
 }
 
-void
-AudioEngine::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
+/* BACKEND PROXY WRAPPERS */
+
+int
+AudioEngine::start (bool for_latency)
 {
-       RCUWriter<Ports> writer (ports);
-       boost::shared_ptr<Ports> p = writer.get_copy();
-       Ports::iterator x = p->find (old_relative_name);
+       if (!_backend) {
+               return -1;
+       }
+
+       if (_running) {
+               return 0;
+       }
+
+       _processed_frames = 0;
+       last_monitor_check = 0;
        
-       if (x != p->end()) {
-               boost::shared_ptr<Port> port = x->second;
-               p->erase (x);
-               p->insert (make_pair (new_relative_name, port));
+       if (_backend->start (for_latency)) {
+               return -1;
        }
-}
 
-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;
+       _running = true;
+       
+       if (_session) {
+               _session->set_frame_rate (_backend->sample_rate());
+               
+               if (_session->config.get_jack_time_master()) {
+                       _backend->set_time_master (true);
                }
        }
-       return jack_get_ports (_priv_jack, port_name_pattern.c_str(), type_name_pattern.c_str(), flags);
+       
+       start_metering_thread ();
+       
+       if (!for_latency) {
+               Running(); /* EMIT SIGNAL */
+       }
+       
+       return 0;
 }
 
-void
-AudioEngine::halted_info (jack_status_t code, const char* reason, void *arg)
+int
+AudioEngine::stop (bool for_latency)
 {
-        /* called from jack shutdown handler  */
-
-        AudioEngine* ae = static_cast<AudioEngine *> (arg);
-        bool was_running = ae->_running;
+       if (!_backend) {
+               return 0;
+       }
 
-        ae->stop_metering_thread ();
+       Glib::Threads::Mutex::Lock lm (_process_lock);
 
-        ae->_running = false;
-        ae->_buffer_size = 0;
-        ae->_frame_rate = 0;
-        ae->_jack = 0;
+       if (_backend->stop ()) {
+               return -1;
+       }
+       
+       _running = false;
+       _processed_frames = 0;
+       _measuring_latency = false;
+       _latency_output_port = 0;
+       _latency_input_port = 0;
+       _started_for_latency = false;
+       stop_metering_thread ();
+       
+       Port::PortDrop ();
 
-        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
-        }
+       if (!for_latency) {
+               Stopped (); /* EMIT SIGNAL */
+       }
+       
+       return 0;
 }
 
-void
-AudioEngine::halted (void *arg)
+int
+AudioEngine::freewheel (bool start_stop)
 {
-        cerr << "HALTED by JACK\n";
-
-        /* called from jack shutdown handler  */
-
-       AudioEngine* ae = static_cast<AudioEngine *> (arg);
-       bool was_running = ae->_running;
+       if (!_backend) {
+               return -1;
+       }
 
-       ae->stop_metering_thread ();
+       /* _freewheeling will be set when first Freewheel signal occurs */
 
-       ae->_running = false;
-       ae->_buffer_size = 0;
-       ae->_frame_rate = 0;
-        ae->_jack = 0;
+       return _backend->freewheel (start_stop);
+}
 
-       if (was_running) {
-               MIDI::JackMIDIPort::JackHalted (); /* EMIT SIGNAL */
-               ae->Halted(""); /* EMIT SIGNAL */
+float
+AudioEngine::get_dsp_load() const 
+{
+       if (!_backend) {
+               return 0.0;
        }
+       return _backend->dsp_load ();
 }
 
-void
-AudioEngine::died ()
+bool
+AudioEngine::is_realtime() const 
 {
-        /* called from a signal handler for SIGPIPE */
-
-       stop_metering_thread ();
+       if (!_backend) {
+               return false;
+       }
 
-        _running = false;
-       _buffer_size = 0;
-       _frame_rate = 0;
-       _jack = 0;
+       return _backend->is_realtime();
 }
 
 bool
-AudioEngine::can_request_hardware_monitoring ()
+AudioEngine::connected() const 
 {
-       GET_PRIVATE_JACK_POINTER_RET (_jack,false);
-       const char ** ports;
-
-       if ((ports = jack_get_ports (_priv_jack, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortCanMonitor)) == 0) {
+       if (!_backend) {
                return false;
        }
 
-       free (ports);
-
-       return true;
+       return _backend->available();
 }
 
-ChanCount
-AudioEngine::n_physical (unsigned long flags) const
+void
+AudioEngine::transport_start ()
 {
-       ChanCount c;
-
-       GET_PRIVATE_JACK_POINTER_RET (_jack, c);
-
-       const char ** ports = jack_get_ports (_priv_jack, NULL, NULL, JackPortIsPhysical | flags);
-       if (ports == 0) {
-               return c;
-       }
-
-       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);
-               }
+       if (!_backend) {
+               return;
        }
-
-       free (ports);
-
-       return c;
+       return _backend->transport_start ();
 }
 
-ChanCount
-AudioEngine::n_physical_inputs () const
+void
+AudioEngine::transport_stop ()
 {
-       return n_physical (JackPortIsInput);
+       if (!_backend) {
+               return;
+       }
+       return _backend->transport_stop ();
 }
 
-ChanCount
-AudioEngine::n_physical_outputs () const
+TransportState
+AudioEngine::transport_state ()
 {
-       return n_physical (JackPortIsOutput);
+       if (!_backend) {
+               return TransportStopped;
+       }
+       return _backend->transport_state ();
 }
 
 void
-AudioEngine::get_physical (DataType type, unsigned long flags, vector<string>& phy)
+AudioEngine::transport_locate (framepos_t pos)
 {
-       GET_PRIVATE_JACK_POINTER (_jack);
-       const char ** ports;
-
-       if ((ports = jack_get_ports (_priv_jack, NULL, type.to_jack_type(), JackPortIsPhysical | flags)) == 0) {
+       if (!_backend) {
                return;
        }
+       return _backend->transport_locate (pos);
+}
 
-       if (ports) {
-               for (uint32_t i = 0; ports[i]; ++i) {
-                        if (strstr (ports[i], "Midi-Through")) {
-                                continue;
-                        }
-                       phy.push_back (ports[i]);
-               }
-               free (ports);
+framepos_t
+AudioEngine::transport_frame()
+{
+       if (!_backend) {
+               return 0;
        }
+       return _backend->transport_frame ();
 }
 
-/** 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)
+framecnt_t
+AudioEngine::sample_rate () const
 {
-       get_physical (type, JackPortIsOutput, ins);
+       if (!_backend) {
+               return 0;
+       }
+       return _backend->sample_rate ();
 }
 
-/** 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)
+pframes_t
+AudioEngine::samples_per_cycle () const
 {
-       get_physical (type, JackPortIsInput, outs);
+       if (!_backend) {
+               return 0;
+       }
+       return _backend->buffer_size ();
 }
 
-void
-AudioEngine::transport_stop ()
+int
+AudioEngine::usecs_per_cycle () const
 {
-       GET_PRIVATE_JACK_POINTER (_jack);
-       jack_transport_stop (_priv_jack);
+       if (!_backend) {
+               return -1;
+       }
+       return _backend->usecs_per_cycle ();
 }
 
-void
-AudioEngine::transport_start ()
+size_t
+AudioEngine::raw_buffer_size (DataType t)
 {
-       GET_PRIVATE_JACK_POINTER (_jack);
-       jack_transport_start (_priv_jack);
+       if (!_backend) {
+               return -1;
+       }
+       return _backend->raw_buffer_size (t);
 }
 
-void
-AudioEngine::transport_locate (framepos_t where)
+pframes_t
+AudioEngine::sample_time ()
 {
-       GET_PRIVATE_JACK_POINTER (_jack);
-       jack_transport_locate (_priv_jack, where);
+       if (!_backend) {
+               return 0;
+       }
+       return _backend->sample_time ();
 }
 
-AudioEngine::TransportState
-AudioEngine::transport_state ()
+pframes_t
+AudioEngine::sample_time_at_cycle_start ()
 {
-       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_time_at_cycle_start ();
 }
 
-int
-AudioEngine::reset_timebase ()
+pframes_t
+AudioEngine::samples_since_cycle_start ()
 {
-       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->samples_since_cycle_start ();
 }
 
-int
-AudioEngine::freewheel (bool onoff)
+bool
+AudioEngine::get_sync_offset (pframes_t& offset) 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 false;
        }
+       return _backend->get_sync_offset (offset);
 }
 
-void
-AudioEngine::remove_all_ports ()
+int
+AudioEngine::create_process_thread (boost::function<void()> func)
 {
-       /* 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
-       */
-
-       {
-               RCUWriter<Ports> writer (ports);
-               boost::shared_ptr<Ports> ps = writer.get_copy ();
-               ps->clear ();
+       if (!_backend) {
+               return -1;
        }
-
-       /* clear dead wood list in RCU */
-
-       ports.flush ();
-
-       port_remove_in_progress = false;
+       return _backend->create_process_thread (func);
 }
 
 int
-AudioEngine::connect_to_jack (string client_name, string session_uuid)
+AudioEngine::join_process_threads ()
 {
-        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;
        }
+       return _backend->join_process_threads ();
+}
 
-       GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
-
-       if (status & JackNameNotUnique) {
-               jack_client_name = jack_get_client_name (_priv_jack);
+bool
+AudioEngine::in_process_thread ()
+{
+       if (!_backend) {
+               return false;
        }
+       return _backend->in_process_thread ();
+}
 
-       return 0;
+uint32_t
+AudioEngine::process_thread_count ()
+{
+       if (!_backend) {
+               return 0;
+       }
+       return _backend->process_thread_count ();
 }
 
 int
-AudioEngine::disconnect_from_jack ()
+AudioEngine::set_device_name (const std::string& name)
 {
-       GET_PRIVATE_JACK_POINTER_RET (_jack, 0);
-
-       if (_running) {
-               stop_metering_thread ();
+       if (!_backend) {
+               return -1;
        }
+       return _backend->set_device_name  (name);
+}
 
-       {
-               Glib::Threads::Mutex::Lock lm (_process_lock);
-               jack_client_close (_priv_jack);
-               _jack = 0;
+int
+AudioEngine::set_sample_rate (float sr)
+{
+       if (!_backend) {
+               return -1;
        }
+       return _backend->set_sample_rate  (sr);
+}
 
-       _buffer_size = 0;
-       _frame_rate = 0;
-       _raw_buffer_sizes.clear();
-
-       if (_running) {
-               _running = false;
-               MIDI::JackMIDIPort::JackHalted (); /* EMIT SIGNAL */
-               Stopped(); /* EMIT SIGNAL */
+int
+AudioEngine::set_buffer_size (uint32_t bufsiz)
+{
+       if (!_backend) {
+               return -1;
        }
-
-       return 0;
+       return _backend->set_buffer_size  (bufsiz);
 }
 
 int
-AudioEngine::reconnect_to_jack ()
+AudioEngine::set_sample_format (SampleFormat sf)
 {
-       if (_running) {
-               disconnect_from_jack ();
-               /* XXX give jackd a chance */
-               Glib::usleep (250000);
+       if (!_backend) {
+               return -1;
        }
+       return _backend->set_sample_format  (sf);
+}
 
-       if (connect_to_jack (jack_client_name, "")) {
-               error << _("failed to connect to JACK") << endmsg;
+int
+AudioEngine::set_interleaved (bool yn)
+{
+       if (!_backend) {
                return -1;
        }
+       return _backend->set_interleaved  (yn);
+}
 
-       Ports::iterator i;
-
-       boost::shared_ptr<Ports> p = ports.reader ();
-
-       for (i = p->begin(); i != p->end(); ++i) {
-               if (i->second->reestablish ()) {
-                       break;
-               }
+int
+AudioEngine::set_input_channels (uint32_t ic)
+{
+       if (!_backend) {
+               return -1;
        }
+       return _backend->set_input_channels  (ic);
+}
 
-       if (i != p->end()) {
-               /* failed */
-               remove_all_ports ();
+int
+AudioEngine::set_output_channels (uint32_t oc)
+{
+       if (!_backend) {
                return -1;
        }
+       return _backend->set_output_channels (oc);
+}
 
-       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_systemic_input_latency (uint32_t il)
+{
+       if (!_backend) {
+               return -1;
        }
+       return _backend->set_systemic_input_latency  (il);
+}
 
-       last_monitor_check = 0;
-
-        set_jack_callbacks ();
-
-       if (jack_activate (_priv_jack) == 0) {
-               _running = true;
-               _has_run = true;
-       } else {
+int
+AudioEngine::set_systemic_output_latency (uint32_t ol)
+{
+       if (!_backend) {
                return -1;
        }
+       return _backend->set_systemic_output_latency  (ol);
+}
 
-       /* re-establish connections */
+/* END OF BACKEND PROXY API */
 
-       for (i = p->begin(); i != p->end(); ++i) {
-               i->second->reconnect ();
-       }
+void
+AudioEngine::thread_init_callback (void* arg)
+{
+       /* make sure that anybody who needs to know about this thread
+          knows about it.
+       */
 
-       MIDI::Manager::instance()->reconnect ();
+       pthread_set_name (X_("audioengine"));
 
-       Running (); /* EMIT SIGNAL*/
+       PBD::notify_gui_about_thread_creation ("gui", pthread_self(), X_("AudioEngine"), 4096);
+       PBD::notify_gui_about_thread_creation ("midiui", pthread_self(), X_("AudioEngine"), 128);
 
-       start_metering_thread ();
+       SessionEvent::create_per_thread_pool (X_("AudioEngine"), 512);
 
-       return 0;
+       AsyncMIDIPort::set_process_thread (pthread_self());
+
+       if (arg) {
+               /* the special thread created/managed by the backend */
+               AudioEngine::instance()->_main_thread = new ProcessThread;
+       }
 }
 
 int
-AudioEngine::request_buffer_size (pframes_t nframes)
+AudioEngine::sync_callback (TransportState state, framepos_t position)
 {
-       GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
-
-       if (nframes == jack_get_buffer_size (_priv_jack)) {
-                return 0;
+       if (_session) {
+               return _session->backend_sync_callback (state, position);
        }
-
-       return jack_set_buffer_size (_priv_jack, nframes);
+       return 0;
 }
 
-string
-AudioEngine::make_port_name_relative (string portname) const
+void
+AudioEngine::freewheel_callback (bool onoff)
 {
-       string::size_type len;
-       string::size_type n;
-
-       len = portname.length();
+       _freewheeling = onoff;
+}
 
-       for (n = 0; n < len; ++n) {
-               if (portname[n] == ':') {
-                       break;
-               }
-       }
+void
+AudioEngine::latency_callback (bool for_playback)
+{
+        if (_session) {
+                _session->update_latency (for_playback);
+        }
+}
 
-       if ((n != len) && (portname.substr (0, n) == jack_client_name)) {
-               return portname.substr (n+1);
+void
+AudioEngine::update_latencies ()
+{
+       if (_backend) {
+               _backend->update_latencies ();
        }
-
-       return portname;
 }
 
-string
-AudioEngine::make_port_name_non_relative (string portname) const
+void
+AudioEngine::halted_callback (const char* why)
 {
-       string str;
-
-       if (portname.find_first_of (':') != string::npos) {
-               return portname;
+       if (_in_destructor) {
+               /* everything is under control */
+               return;
        }
 
-       str  = jack_client_name;
-       str += ':';
-       str += portname;
+        stop_metering_thread ();
+       _running = false;
+
+       Port::PortDrop (); /* EMIT SIGNAL */
 
-       return str;
+       if (!_started_for_latency) {
+               Halted (why);      /* EMIT SIGNAL */
+       }
 }
 
 bool
-AudioEngine::port_is_mine (const string& portname) const
+AudioEngine::setup_required () const
 {
-       if (portname.find_first_of (':') != string::npos) {
-               if (portname.substr (0, jack_client_name.length ()) != jack_client_name) {
-                        return false;
-                }
-        }
-        return true;
+       /* If there is only a single backend and it claims to be configured
+        * already there is no setup to be done.
+        *
+        * Primarily for a case where there is only a JACK backend and
+        * JACK is already running.
+        */
+        
+       if (_backends.size() == 1 && _backends.begin()->second->already_configured()) {
+               return false;
+       }
+
+       return true;
 }
 
-bool
-AudioEngine::is_realtime () const
+MTDM*
+AudioEngine::mtdm() 
 {
-       GET_PRIVATE_JACK_POINTER_RET (_jack,false);
-       return jack_is_realtime (_priv_jack);
+       return _mtdm;
 }
 
 int
-AudioEngine::create_process_thread (boost::function<void()> f, jack_native_thread_t* thread, size_t stacksize)
+AudioEngine::prepare_for_latency_measurement ()
 {
-        GET_PRIVATE_JACK_POINTER_RET (_jack, 0);
-        ThreadData* td = new ThreadData (this, f, stacksize);
+       if (running()) {
+               _stopped_for_latency = true;
+               stop (true);
+       }
 
-        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;
-        }
+       if (start (true)) {
+               _started_for_latency = true;
+               return -1;
+       }
 
-        return 0;
+       return 0;
 }
 
-bool
-AudioEngine::stop_process_thread (jack_native_thread_t thread)
+int
+AudioEngine::start_latency_detection ()
 {
-       /**
-        * 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
-        */
-
-#if defined(USING_JACK2_EXPANSION_OF_JACK_API) || defined(PLATFORM_WINDOWS)
-       if (jack_client_stop_thread (_jack, thread) != 0) {
-               error << "AudioEngine: cannot stop process thread" << endmsg;
-               return false;
+       if (!running()) {
+               if (prepare_for_latency_measurement ()) {
+                       return -1;
+               }
        }
-#else
-       void* status;
-       pthread_join (thread, &status);
-#endif
 
-       return true;
-}
+       PortEngine& pe (port_engine());
 
-void*
-AudioEngine::_start_process_thread (void* arg)
-{
-        ThreadData* td = reinterpret_cast<ThreadData*> (arg);
-        boost::function<void()> f = td->f;
-        delete td;
+       delete _mtdm;
+       _mtdm = 0;
 
-        f ();
+       /* find the ports we will connect to */
 
-        return 0;
-}
+       PortEngine::PortHandle out = pe.get_port_by_name (_latency_output_name);
+       PortEngine::PortHandle in = pe.get_port_by_name (_latency_input_name);
 
-bool
-AudioEngine::port_is_physical (const std::string& portname) const
-{
-        GET_PRIVATE_JACK_POINTER_RET(_jack, false);
+       if (!out || !in) {
+               stop (true);
+               return -1;
+       }
+
+       /* create the ports we will use to read/write data */
+       
+       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;
+       }
 
-        jack_port_t *port = jack_port_by_name (_priv_jack, portname.c_str());
+       const string portname ("latency_in");
+       if ((_latency_input_port = pe.register_port (portname, DataType::AUDIO, IsInput)) == 0) {
+               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_output_port);
+               stop (true);
+               return -1;
+       }
 
-        if (!port) {
-                return false;
-        }
+       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;
 
-        return jack_port_flags (port) & JackPortIsPhysical;
+       /* all created and connected, lets go */
+
+       _mtdm = new MTDM (sample_rate());
+       _measuring_latency = true;
+        _latency_flush_frames = samples_per_cycle();
+
+       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 = false;
 
-        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;
-        }
+       stop (true);
 
-        jack_port_request_monitor (port, yn);
+       if (_stopped_for_latency) {
+               start ();
+       }
+
+       _stopped_for_latency = false;
+       _started_for_latency = false;
 }
 
 void
-AudioEngine::update_latencies ()
+AudioEngine::set_latency_output_port (const string& name)
 {
-       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;
 }
-