ALSA backend: separate flags for is-running and should-be-running
[ardour.git] / libs / backends / jack / jack_audiobackend.cc
index a651f2522d3560392e5ae97c728eaa5391859417..d61d83bc66c491bd17ef23be54ccd4d801d5188c 100644 (file)
@@ -37,6 +37,7 @@
 #include "jack_audiobackend.h"
 #include "jack_connection.h"
 #include "jack_utils.h"
+#include "jack_session.h"
 
 #include "i18n.h"
 
@@ -49,14 +50,13 @@ using std::vector;
 #define GET_PRIVATE_JACK_POINTER(localvar)  jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return; }
 #define GET_PRIVATE_JACK_POINTER_RET(localvar,r) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return r; }
 
-JACKAudioBackend::JACKAudioBackend (AudioEngine& e, boost::shared_ptr<JackConnection> jc)
-       : AudioBackend (e)
+JACKAudioBackend::JACKAudioBackend (AudioEngine& e, AudioBackendInfo& info, boost::shared_ptr<JackConnection> jc)
+       : AudioBackend (e, info)
        , _jack_connection (jc)
        , _running (false)
        , _freewheeling (false)
        , _target_sample_rate (48000)
        , _target_buffer_size (1024)
-       , _target_sample_format (FormatFloat)
        , _target_interleaved (false)
        , _target_input_channels (0)
        , _target_output_channels (0)
@@ -64,6 +64,7 @@ JACKAudioBackend::JACKAudioBackend (AudioEngine& e, boost::shared_ptr<JackConnec
        , _target_systemic_output_latency (0)
        , _current_sample_rate (0)
        , _current_buffer_size (0)
+       , _session (0)
 {
        _jack_connection->Connected.connect_same_thread (jack_connection_connection, boost::bind (&JACKAudioBackend::when_connected_to_jack, this));
        _jack_connection->Disconnected.connect_same_thread (disconnect_connection, boost::bind (&JACKAudioBackend::disconnected, this, _1));
@@ -153,11 +154,11 @@ JACKAudioBackend::enumerate_devices () const
 }
 
 vector<float>
-JACKAudioBackend::available_sample_rates (const string& /*device*/) const
+JACKAudioBackend::available_sample_rates (const string& device) const
 {
        vector<float> f;
        
-       if (available()) {
+       if (device == _target_device && available()) {
                f.push_back (sample_rate());
                return f;
        }
@@ -181,11 +182,11 @@ JACKAudioBackend::available_sample_rates (const string& /*device*/) const
 }
 
 vector<uint32_t>
-JACKAudioBackend::available_buffer_sizes (const string& /*device*/) const
+JACKAudioBackend::available_buffer_sizes (const string& device) const
 {
        vector<uint32_t> s;
-       
-       if (available()) {
+               
+       if (device == _target_device && available()) {
                s.push_back (buffer_size());
                return s;
        }
@@ -265,18 +266,6 @@ JACKAudioBackend::set_buffer_size (uint32_t nframes)
        return jack_set_buffer_size (_priv_jack, nframes);
 }
 
-int
-JACKAudioBackend::set_sample_format (SampleFormat sf)
-{
-       /* as far as JACK clients are concerned, the hardware is always
-        * floating point format.
-        */
-       if (sf == FormatFloat) {
-               return 0;
-       }
-       return -1;
-}
-
 int
 JACKAudioBackend::set_interleaved (bool yn)
 {
@@ -395,18 +384,18 @@ JACKAudioBackend::buffer_size () const
        return _target_buffer_size;
 }
 
-SampleFormat
-JACKAudioBackend::sample_format () const
-{
-       return FormatFloat;
-}
-
 bool
 JACKAudioBackend::interleaved () const
 {
        return false;
 }
 
+string
+JACKAudioBackend::midi_option () const
+{
+       return _target_midi_option;
+}
+
 uint32_t
 JACKAudioBackend::input_channels () const
 {
@@ -463,7 +452,7 @@ JACKAudioBackend::raw_buffer_size(DataType t)
 }
 
 void
-JACKAudioBackend::setup_jack_startup_command ()
+JACKAudioBackend::setup_jack_startup_command (bool for_latency_measurement)
 {
        /* first we map the parameters that have been set onto a
         * JackCommandLineOptions object.
@@ -488,6 +477,8 @@ JACKAudioBackend::setup_jack_startup_command ()
        options.realtime = true;
        options.ports_max = 2048;
        
+       ARDOUR::set_midi_option (options, _target_midi_option);
+
        /* this must always be true for any server instance we start ourselves
         */
 
@@ -495,10 +486,11 @@ JACKAudioBackend::setup_jack_startup_command ()
 
        string cmdline;
 
-       if (!get_jack_command_line_string (options, cmdline)) {
+       if (!get_jack_command_line_string (options, cmdline, for_latency_measurement)) {
                /* error, somehow - we will still try to start JACK
                 * automatically but it will be without our preferred options
                 */
+               std::cerr << "get_jack_command_line_string () failed: using default settings." << std::endl;
                return;
        }
 
@@ -510,7 +502,7 @@ JACKAudioBackend::setup_jack_startup_command ()
 /* ---- BASIC STATE CONTROL API: start/stop/pause/freewheel --- */
 
 int
-JACKAudioBackend::start ()
+JACKAudioBackend::_start (bool for_latency_measurement)
 {
        if (!available()) {
 
@@ -518,7 +510,7 @@ JACKAudioBackend::start ()
                        /* we will be starting JACK, so set up the 
                           command that JACK will use when it (auto-)starts
                        */
-                       setup_jack_startup_command ();
+                       setup_jack_startup_command (for_latency_measurement);
                }
 
                if (_jack_connection->open ()) {
@@ -536,8 +528,11 @@ JACKAudioBackend::start ()
        /* Now that we have buffer size and sample rate established, the engine 
           can go ahead and do its stuff
        */
-       
-       engine.reestablish_ports ();
+
+       if (engine.reestablish_ports ()) {
+               error << _("Could not re-establish ports after connecting to JACK") << endmsg;
+               return -1;
+       }
 
        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;
@@ -571,18 +566,6 @@ JACKAudioBackend::stop ()
        return 0;
 }
 
-int
-JACKAudioBackend::pause ()
-{
-       GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
-
-       if (_priv_jack) {
-               jack_deactivate (_priv_jack);
-       }
-
-       return 0;
-}
-
 int
 JACKAudioBackend::freewheel (bool onoff)
 {
@@ -595,7 +578,7 @@ JACKAudioBackend::freewheel (bool onoff)
        }
 
        if (jack_set_freewheel (_priv_jack, onoff) == 0) {
-               _freewheeling = true;
+               _freewheeling = onoff;
                return 0;
        }
 
@@ -748,7 +731,8 @@ JACKAudioBackend::jack_timebase_callback (jack_transport_state_t state, pframes_
        ARDOUR::Session* session = engine.session();
 
        if (session) {
-               session->jack_timebase_callback (state, nframes, pos, new_position);
+               JACKSession jsession (session);
+               jsession.timebase_callback (state, nframes, pos, new_position);
        }
 }
 
@@ -762,11 +746,9 @@ int
 JACKAudioBackend::jack_sync_callback (jack_transport_state_t state, jack_position_t* pos)
 {
        TransportState tstate;
+       bool tstate_valid = true;
 
        switch (state) {
-       case JackTransportStopped:
-               tstate = TransportStopped;
-               break;
        case JackTransportRolling:
                tstate = TransportRolling;
                break;
@@ -776,9 +758,18 @@ JACKAudioBackend::jack_sync_callback (jack_transport_state_t state, jack_positio
        case JackTransportStarting:
                tstate = TransportStarting;
                break;
+       case JackTransportStopped:
+               tstate = TransportStopped;
+               break;
+       default:
+               // ignore "unofficial" states like JackTransportNetStarting (jackd2)
+               tstate_valid = false;
+               break;
        }
 
-       return engine.sync_callback (tstate, pos->frame);
+       if (tstate_valid) {
+               return engine.sync_callback (tstate, pos->frame);
+       }
 
        return true;
 }
@@ -793,7 +784,6 @@ JACKAudioBackend::_xrun_callback (void *arg)
        return 0;
 }
 
-#ifdef HAVE_JACK_SESSION
 void
 JACKAudioBackend::_session_callback (jack_session_event_t *event, void *arg)
 {
@@ -801,10 +791,10 @@ JACKAudioBackend::_session_callback (jack_session_event_t *event, void *arg)
        ARDOUR::Session* session = jab->engine.session();
 
        if (session) {
-               session->jack_session_event (event);
+               JACKSession jsession (session);
+               jsession.session_event (event);
        }
 }
-#endif
 
 void
 JACKAudioBackend::_freewheel_callback (int onoff, void *arg)
@@ -1013,7 +1003,7 @@ JACKAudioBackend::disconnected (const char* why)
 }
 
 float 
-JACKAudioBackend::cpu_load() const 
+JACKAudioBackend::dsp_load() const 
 {
        GET_PRIVATE_JACK_POINTER_RET(_priv_jack,0);
        return jack_cpu_load (_priv_jack);
@@ -1085,6 +1075,8 @@ JACKAudioBackend::control_app_name () const
                                appname = "hdspconf";
                        } else if (_target_device == "M Audio Delta 1010") {
                                appname = "mudita24";
+                       } else if (_target_device == "M2496") {
+                               appname = "mudita24";
                        }
                }
        } else {
@@ -1108,3 +1100,60 @@ JACKAudioBackend::launch_control_app ()
        args.push_back (appname);
        Glib::spawn_async ("", args, Glib::SPAWN_SEARCH_PATH);
 }
+
+vector<string>
+JACKAudioBackend::enumerate_midi_options () const
+{
+       return ARDOUR::enumerate_midi_options ();
+}
+
+int
+JACKAudioBackend::set_midi_option (const string& opt)
+{
+       _target_midi_option = opt;
+       return 0;
+}
+
+bool
+JACKAudioBackend::speed_and_position (double& speed, framepos_t& position)
+{
+       jack_position_t pos;
+       jack_transport_state_t state;
+       bool starting;
+
+       /* this won't be called if the port engine in use is not JACK, so we do 
+          not have to worry about the type of PortEngine::private_handle()
+       */
+
+       speed = 0;
+       position = 0;
+
+       GET_PRIVATE_JACK_POINTER_RET (_priv_jack, true);
+
+       state = jack_transport_query (_priv_jack, &pos);
+
+       switch (state) {
+       case JackTransportStopped:
+               speed = 0;
+               starting = false;
+               break;
+       case JackTransportRolling:
+               speed = 1.0;
+               starting = false;
+               break;
+       case JackTransportLooping:
+               speed = 1.0;
+               starting = false;
+               break;
+       case JackTransportStarting:
+               starting = true;
+               // don't adjust speed here, just leave it as it was
+               break;
+       default:
+               starting = true; // jack2: JackTransportNetStarting
+               std::cerr << "WARNING: Unknown JACK transport state: " << state << std::endl;
+       }
+
+       position = pos.frame;
+       return starting;
+}