rationalize (a bit) engine start/stop/restart so that it is possible to start up, disconnect from JACK and then reconnect

This commit is contained in:
Paul Davis 2013-08-08 16:31:08 -04:00
parent ea7d89dd51
commit d90e2b4221
14 changed files with 214 additions and 183 deletions

View File

@ -161,6 +161,7 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
, nsm (0)
, _was_dirty (false)
, _mixer_on_top (false)
, first_time_engine_run (true)
/* transport */
@ -414,10 +415,122 @@ ARDOUR_UI::attach_to_engine ()
}
}
void
ARDOUR_UI::engine_stopped ()
{
ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
}
void
ARDOUR_UI::engine_running ()
{
if (first_time_engine_run) {
post_engine();
first_time_engine_run = false;
}
ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
Glib::RefPtr<Action> action;
const char* action_name = 0;
switch (engine->samples_per_cycle()) {
case 32:
action_name = X_("JACKLatency32");
break;
case 64:
action_name = X_("JACKLatency64");
break;
case 128:
action_name = X_("JACKLatency128");
break;
case 512:
action_name = X_("JACKLatency512");
break;
case 1024:
action_name = X_("JACKLatency1024");
break;
case 2048:
action_name = X_("JACKLatency2048");
break;
case 4096:
action_name = X_("JACKLatency4096");
break;
case 8192:
action_name = X_("JACKLatency8192");
break;
default:
/* XXX can we do anything useful ? */
break;
}
if (action_name) {
action = ActionManager::get_action (X_("JACK"), action_name);
if (action) {
Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
ract->set_active ();
}
update_disk_space ();
update_cpu_load ();
update_sample_rate (engine->sample_rate());
update_timecode_format ();
}
}
void
ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
{
if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
/* we can't rely on the original string continuing to exist when we are called
again in the GUI thread, so make a copy and note that we need to
free it later.
*/
char *copy = strdup (reason);
Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
return;
}
ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
update_sample_rate (0);
string msgstr;
/* if the reason is a non-empty string, it means that the backend was shutdown
rather than just Ardour.
*/
if (strlen (reason)) {
msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
} else {
msgstr = string_compose (_("\
JACK has either been shutdown or it\n\
disconnected %1 because %1\n\
was not fast enough. Try to restart\n\
JACK, reconnect and save the session."), PROGRAM_NAME);
}
MessageDialog msg (*editor, msgstr);
pop_back_splash (msg);
msg.set_keep_above (true);
msg.run ();
if (free_reason) {
free (const_cast<char*> (reason));
}
}
void
ARDOUR_UI::post_engine ()
{
/* Things to be done once we have a backend running in the AudioEngine
/* Things to be done once (and once ONLY) after we have a backend running in the AudioEngine
*/
ARDOUR::init_post_engine ();
@ -483,11 +596,6 @@ ARDOUR_UI::post_engine ()
Glib::signal_timeout().connect_seconds (sigc::mem_fun(*this, &ARDOUR_UI::update_wall_clock), 1);
#endif
update_disk_space ();
update_cpu_load ();
update_sample_rate (engine->sample_rate());
update_timecode_format ();
Config->ParameterChanged.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::parameter_changed, this, _1), gui_context());
boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
Config->map_parameters (pc);
@ -1042,7 +1150,7 @@ ARDOUR_UI::update_sample_rate (framecnt_t)
if (!engine->connected()) {
snprintf (buf, sizeof (buf), "%s", _("disconnected"));
snprintf (buf, sizeof (buf), _("Audio: <span foreground=\"red\">none</span>"));
} else {
@ -2041,110 +2149,6 @@ ARDOUR_UI::map_transport_state ()
}
}
void
ARDOUR_UI::engine_stopped ()
{
ENSURE_GUI_THREAD (*this, &ARDOUR_UI::engine_stopped)
ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
}
void
ARDOUR_UI::engine_running ()
{
post_engine();
ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true);
ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
Glib::RefPtr<Action> action;
const char* action_name = 0;
switch (engine->samples_per_cycle()) {
case 32:
action_name = X_("JACKLatency32");
break;
case 64:
action_name = X_("JACKLatency64");
break;
case 128:
action_name = X_("JACKLatency128");
break;
case 512:
action_name = X_("JACKLatency512");
break;
case 1024:
action_name = X_("JACKLatency1024");
break;
case 2048:
action_name = X_("JACKLatency2048");
break;
case 4096:
action_name = X_("JACKLatency4096");
break;
case 8192:
action_name = X_("JACKLatency8192");
break;
default:
/* XXX can we do anything useful ? */
break;
}
if (action_name) {
action = ActionManager::get_action (X_("JACK"), action_name);
if (action) {
Glib::RefPtr<RadioAction> ract = Glib::RefPtr<RadioAction>::cast_dynamic (action);
ract->set_active ();
}
}
}
void
ARDOUR_UI::engine_halted (const char* reason, bool free_reason)
{
if (!Gtkmm2ext::UI::instance()->caller_is_ui_thread()) {
/* we can't rely on the original string continuing to exist when we are called
again in the GUI thread, so make a copy and note that we need to
free it later.
*/
char *copy = strdup (reason);
Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&ARDOUR_UI::engine_halted, this, copy, true));
return;
}
ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false);
ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true);
update_sample_rate (0);
string msgstr;
/* if the reason is a non-empty string, it means that the backend was shutdown
rather than just Ardour.
*/
if (strlen (reason)) {
msgstr = string_compose (_("The audio backend (JACK) was shutdown because:\n\n%1"), reason);
} else {
msgstr = string_compose (_("\
JACK has either been shutdown or it\n\
disconnected %1 because %1\n\
was not fast enough. Try to restart\n\
JACK, reconnect and save the session."), PROGRAM_NAME);
}
MessageDialog msg (*editor, msgstr);
pop_back_splash (msg);
msg.set_keep_above (true);
msg.run ();
if (free_reason) {
free (const_cast<char*> (reason));
}
}
void
ARDOUR_UI::update_clocks ()
{

View File

@ -315,6 +315,7 @@ class ARDOUR_UI : public Gtkmm2ext::UI, public ARDOUR::SessionHandlePtr
NSM_Client *nsm;
bool _was_dirty;
bool _mixer_on_top;
bool first_time_engine_run;
void goto_editor_window ();
void goto_mixer_window ();

View File

@ -10,5 +10,6 @@ LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
export ARDOUR_RUNNING_UNDER_VALGRIND=TRUE
exec valgrind --tool=memcheck \
$VALGRIND_OPTIONS \
--track-origins=yes \
--suppressions=`dirname "$0"`/../tools/valgrind.supp \
$TOP/$EXECUTABLE --novst "$@"

View File

@ -165,14 +165,10 @@ class JACKAudioBackend : public AudioBackend {
bool _target_interleaved;
uint32_t _target_input_channels;
uint32_t _target_output_channels;
uint32_t _target_systemic_input_latency;
uint32_t _target_systemic_output_latency;
uint32_t _current_sample_rate;
uint32_t _current_buffer_size;
uint32_t _current_usecs_per_cycle;
uint32_t _current_systemic_input_latency;
uint32_t _current_systemic_output_latency;
uint32_t _target_systemic_input_latency;
uint32_t _target_systemic_output_latency;
uint32_t _current_sample_rate;
uint32_t _current_buffer_size;
typedef std::set<std::string> DeviceList;
typedef std::map<std::string,DeviceList> DriverDeviceMap;

View File

@ -43,6 +43,7 @@ class JACKPortEngine : public PortEngine
~JACKPortEngine();
void* private_handle() const;
bool connected() const;
const std::string& my_name() const;

View File

@ -98,6 +98,8 @@ class PortEngine {
*/
virtual void* private_handle() const = 0;
virtual bool connected() const = 0;
/** Return the name of this process as used by the port manager
* when naming ports.
*/

View File

@ -346,8 +346,6 @@ AudioEngine::set_session (Session *s)
if (_session) {
start_metering_thread ();
pframes_t blocksize = _backend->buffer_size ();
/* page in as much of the session process code as we
@ -567,32 +565,30 @@ AudioEngine::start ()
_processed_frames = 0;
last_monitor_check = 0;
if (_backend->start() == 0) {
if (_backend->start()) {
return -1;
}
_running = true;
last_monitor_check = 0;
_running = true;
if (_session) {
_session->set_frame_rate (_backend->sample_rate());
if (_session) {
_session->set_frame_rate (_backend->sample_rate());
if (_session->config.get_jack_time_master()) {
_backend->set_time_master (true);
}
if (_session->config.get_jack_time_master()) {
_backend->set_time_master (true);
}
if (!have_ports) {
PortManager::create_ports ();
}
}
if (!have_ports) {
PortManager::create_ports ();
_mmc.set_ports (mmc_input_port(), mmc_output_port());
Running(); /* EMIT SIGNAL */
return 0;
}
/* should report error ... */
return -1;
}
start_metering_thread ();
Running(); /* EMIT SIGNAL */
return 0;
}
int
@ -604,17 +600,18 @@ AudioEngine::stop ()
Glib::Threads::Mutex::Lock lm (_process_lock);
if (_backend->stop () == 0) {
_running = false;
_processed_frames = 0;
stop_metering_thread ();
Stopped (); /* EMIT SIGNAL */
return 0;
if (_backend->stop ()) {
return -1;
}
return -1;
_running = false;
_processed_frames = 0;
stop_metering_thread ();
Port::PortDrop ();
Stopped (); /* EMIT SIGNAL */
return 0;
}
int
@ -624,13 +621,14 @@ AudioEngine::pause ()
return 0;
}
if (_backend->pause () == 0) {
_running = false;
Stopped(); /* EMIT SIGNAL */
return 0;
if (_backend->pause ()) {
return -1;
}
return -1;
_running = false;
Stopped(); /* EMIT SIGNAL */
return 0;
}
int
@ -957,7 +955,9 @@ void
AudioEngine::halted_callback (const char* why)
{
stop_metering_thread ();
Halted (why); /* EMIT SIGNAL */
Port::PortDrop (); /* EMIT SIGNAL */
Halted (why); /* EMIT SIGNAL */
}
bool

View File

@ -40,6 +40,8 @@ using namespace ARDOUR;
using namespace PBD;
using std::string;
using std::vector;
using std::cerr;
using std::endl;
#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; }
@ -57,6 +59,8 @@ JACKAudioBackend::JACKAudioBackend (AudioEngine& e, boost::shared_ptr<JackConnec
, _target_output_channels (-1)
, _target_systemic_input_latency (0)
, _target_systemic_output_latency (0)
, _current_sample_rate (0)
, _current_buffer_size (0)
{
_jack_connection->Disconnected.connect_same_thread (disconnect_connection, boost::bind (&JACKAudioBackend::disconnected, this, _1));
}
@ -388,13 +392,13 @@ JACKAudioBackend::output_channels () const
uint32_t
JACKAudioBackend::systemic_input_latency () const
{
return _current_systemic_output_latency;
return _target_systemic_output_latency;
}
uint32_t
JACKAudioBackend::systemic_output_latency () const
{
return _current_systemic_output_latency;
return _target_systemic_output_latency;
}
size_t
@ -455,28 +459,26 @@ JACKAudioBackend::start ()
setup_jack_startup_command ();
}
_jack_connection->open ();
}
engine.reestablish_ports ();
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 (_jack_connection->open ()) {
return -1;
}
}
GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
engine.sample_rate_change (jack_get_sample_rate (_priv_jack));
/* get the buffer size and sample rates established */
jack_sample_rate_callback (jack_get_sample_rate (_priv_jack));
jack_bufsize_callback (jack_get_buffer_size (_priv_jack));
/* testing the nullity of this function name is 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 sort of reliable, but not clean since
* weak symbol support is highly platform and compiler
* specific.
*/
/* Now that we have buffer size and sample rate established, the engine
can go ahead and do its stuff
*/
engine.reestablish_ports ();
if (!jack_port_type_get_buffer_size) {
jack_bufsize_callback (jack_get_buffer_size (_priv_jack));
warning << _("This version of JACK is old - you should upgrade to a newer version that supports jack_port_type_get_buffer_size()") << endmsg;
}
set_jack_callbacks ();
@ -486,7 +488,7 @@ JACKAudioBackend::start ()
} else {
// error << _("cannot activate JACK client") << endmsg;
}
engine.reconnect_ports ();
return 0;
@ -869,7 +871,6 @@ JACKAudioBackend::jack_bufsize_callback (pframes_t nframes)
GET_PRIVATE_JACK_POINTER_RET (_priv_jack, 1);
_current_buffer_size = nframes;
_current_usecs_per_cycle = (int) floor ((((double) nframes / sample_rate())) * 1000000.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);

View File

@ -124,6 +124,12 @@ JACKPortEngine::private_handle() const
return _jack_connection->jack();
}
bool
JACKPortEngine::connected() const
{
return _jack_connection->connected();
}
int
JACKPortEngine::set_port_name (PortHandle port, const std::string& name)
{

View File

@ -112,7 +112,9 @@ LadspaPlugin::init (void *mod, uint32_t index, framecnt_t rate)
port_cnt = parameter_count();
_control_data = new LADSPA_Data[port_cnt];
memset (_control_data, 0, sizeof (LADSPA_Data) * port_cnt);
_shadow_data = new LADSPA_Data[port_cnt];
memset (_shadow_data, 0, sizeof (LADSPA_Data) * port_cnt);
for (i = 0; i < port_cnt; ++i) {
if (LADSPA_IS_PORT_CONTROL(port_descriptor (i))) {

View File

@ -22,6 +22,7 @@
#include "pbd/malign.h"
#include "pbd/compose.h"
#include "pbd/debug.h"
#include "pbd/stacktrace.h"
#include "ardour/debug.h"
#include "ardour/midi_buffer.h"
@ -133,6 +134,7 @@ MidiBuffer::push_back(const Evoral::MIDIEvent<TimeType>& ev)
if (_size + stamp_size + ev.size() >= _capacity) {
cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
PBD::stacktrace (cerr, 20);
return false;
}
@ -171,7 +173,9 @@ MidiBuffer::push_back(TimeType time, size_t size, const uint8_t* data)
#endif
if (_size + stamp_size + size >= _capacity) {
cerr << "MidiBuffer::push_back failed (buffer is full)" << endl;
cerr << "MidiBuffer::push_back2 failed (buffer is full; _size = " << _size << " capacity "
<< _capacity << " stamp " << stamp_size << " size = " << size << ")" << endl;
PBD::stacktrace (cerr, 20);
return false;
}

View File

@ -206,6 +206,7 @@ MidiPort::reset ()
{
Port::reset ();
delete _buffer;
cerr << name() << " new MIDI buffer of size " << AudioEngine::instance()->raw_buffer_size (DataType::MIDI) << endl;
_buffer = new MidiBuffer (AudioEngine::instance()->raw_buffer_size (DataType::MIDI));
}

View File

@ -88,6 +88,7 @@ void
Port::drop ()
{
if (_port_handle) {
DEBUG_TRACE (DEBUG::Ports, string_compose ("drop handle for port %1\n", name()));
port_engine.unregister_port (_port_handle);
_port_handle = 0;
}
@ -120,12 +121,21 @@ Port::disconnect_all ()
bool
Port::connected_to (std::string const & o) const
{
if (!port_engine.connected()) {
return false;
}
return port_engine.connected_to (_port_handle, AudioEngine::instance()->make_port_name_non_relative (o));
}
int
Port::get_connections (std::vector<std::string> & c) const
{
if (!port_engine.connected()) {
c.insert (c.end(), _connections.begin(), _connections.end());
return c.size();
}
return port_engine.get_connections (_port_handle, c);
}
@ -142,9 +152,9 @@ Port::connect (std::string const & other)
}
if (sends_output ()) {
port_engine.connect (our_name, other_name);
r = port_engine.connect (our_name, other_name);
} else {
port_engine.connect (other_name, our_name);
r = port_engine.connect (other_name, our_name);
}
if (r == 0) {

View File

@ -439,6 +439,8 @@ PortManager::reestablish_ports ()
for (i = p->begin(); i != p->end(); ++i) {
if (i->second->reestablish ()) {
error << string_compose (_("Re-establising port %1 failed"), i->second->name()) << endmsg;
cerr << string_compose (_("Re-establising port %1 failed"), i->second->name()) << endl;
break;
}
}
@ -458,7 +460,7 @@ PortManager::reconnect_ports ()
boost::shared_ptr<Ports> p = ports.reader ();
/* re-establish connections */
DEBUG_TRACE (DEBUG::Ports, string_compose ("reconnect %1 ports\n", p->size()));
for (Ports::iterator i = p->begin(); i != p->end(); ++i) {