Browse Source

Add option to add-jack for using externally started applications

tags/v2.1-rc1
falkTX 5 years ago
parent
commit
84c69c851c
6 changed files with 150 additions and 65 deletions
  1. +10
    -3
      resources/ui/carla_add_jack.ui
  2. +3
    -1
      source/backend/engine/CarlaEngineJuce.cpp
  3. +111
    -54
      source/backend/plugin/CarlaPluginJack.cpp
  4. +7
    -3
      source/frontend/carla_database.py
  5. +6
    -4
      source/includes/CarlaLibJackHints.h
  6. +13
    -0
      source/utils/CarlaString.hpp

+ 10
- 3
resources/ui/carla_add_jack.ui View File

@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>496</width>
<height>438</height>
<width>540</width>
<height>514</height>
</rect>
</property>
<property name="windowTitle">
@@ -488,13 +488,20 @@
</property>
</spacer>
</item>
<item row="1" column="1">
<item row="2" column="1">
<widget class="QCheckBox" name="cb_buffers_addition_mode">
<property name="text">
<string>Use previous client output buffer as input for the next client</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="cb_external_start">
<property name="text">
<string>Wait for external application start (Advanced)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>


+ 3
- 1
source/backend/engine/CarlaEngineJuce.cpp View File

@@ -25,7 +25,6 @@
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wcast-qual"
# pragma GCC diagnostic ignored "-Wclass-memaccess"
# pragma GCC diagnostic ignored "-Wconversion"
# pragma GCC diagnostic ignored "-Wdouble-promotion"
# pragma GCC diagnostic ignored "-Weffc++"
@@ -33,6 +32,9 @@
# pragma GCC diagnostic ignored "-Wsign-conversion"
# pragma GCC diagnostic ignored "-Wundef"
# pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
# if __GNUC__ > 7
# pragma GCC diagnostic ignored "-Wclass-memaccess"
# endif
#endif

#include "AppConfig.h"


+ 111
- 54
source/backend/plugin/CarlaPluginJack.cpp View File

@@ -126,6 +126,40 @@ public:
}
#endif

char* getEnvVarsToExport()
{
const EngineOptions& options(kEngine->getOptions());
CarlaString binaryDir(options.binaryDir);
#ifdef HAVE_LIBLO
const int sessionManager = fSetupLabel[4] - '0';
#endif

CarlaString ret;
ret += "export LD_LIBRARY_PATH=" + binaryDir + "/jack\n";
#ifdef HAVE_X11
ret += "export LD_PRELOAD=" + binaryDir + "/libcarla_interposer-jack-x11.so\n";
#endif
#ifdef HAVE_LIBLO
if (sessionManager == LIBJACK_SESSION_MANAGER_NSM)
{
for (int i=50; fOscServer == nullptr && --i>=0;)
carla_msleep(100);

ret += "export NSM_URL=";
ret += lo_server_get_url(fOscServer);
ret += "\n";
}
#endif

if (kPlugin->getHints() & PLUGIN_HAS_CUSTOM_UI)
ret += "export CARLA_FRONTEND_WIN_ID=" + CarlaString(options.frontendWinId) + "\n";

ret += "export CARLA_LIBJACK_SETUP=" + fSetupLabel + "\n";
ret += "export CARLA_SHM_IDS=" + fShmIds + "\n";

return ret.releaseBufferPointer();
}

protected:
#ifdef HAVE_LIBLO
static void _osc_error_handler(int num, const char* msg, const char* path)
@@ -250,31 +284,32 @@ protected:
}
#endif

if (fProcess == nullptr)
{
fProcess = new ChildProcess();
}
else if (fProcess->isRunning())
{
carla_stderr("CarlaPluginJackThread::run() - already running");
}
const bool externalProcess = (fSetupLabel[5] - '0') & LIBJACK_FLAG_EXTERNAL_START;

String name(kPlugin->getName());
String filename(kPlugin->getFilename());
if (! externalProcess)
{
if (fProcess == nullptr)
{
fProcess = new ChildProcess();
}
else if (fProcess->isRunning())
{
carla_stderr("CarlaPluginJackThread::run() - already running");
}

if (name.isEmpty())
name = "(none)";
String name(kPlugin->getName());
String filename(kPlugin->getFilename());

CARLA_SAFE_ASSERT_RETURN(filename.isNotEmpty(),);
if (name.isEmpty())
name = "(none)";

StringArray arguments;
CARLA_SAFE_ASSERT_RETURN(filename.isNotEmpty(),);

// binary
arguments.addTokens(filename, true);
StringArray arguments;

bool started;
// binary
arguments.addTokens(filename, true);

{
const EngineOptions& options(kEngine->getOptions());

char winIdStr[STR_MAX+1];
@@ -287,7 +322,7 @@ protected:
CarlaString ldpreload;
#ifdef HAVE_X11
ldpreload = (CarlaString(options.binaryDir)
+ "/libcarla_interposer-jack-x11.so");
+ "/libcarla_interposer-jack-x11.so");
#endif

const ScopedEngineEnvironmentLocker _seel(kEngine);
@@ -306,17 +341,15 @@ protected:
carla_setenv("CARLA_LIBJACK_SETUP", fSetupLabel.buffer());
carla_setenv("CARLA_SHM_IDS", fShmIds.buffer());

started = fProcess->start(arguments);
}

if (! started)
{
carla_stdout("failed!");
fProcess = nullptr;
return;
if (! fProcess->start(arguments))
{
carla_stdout("failed!");
fProcess = nullptr;
return;
}
}

for (; fProcess->isRunning() && ! shouldThreadExit();)
for (; (externalProcess || fProcess->isRunning()) && ! shouldThreadExit();)
{
#ifdef HAVE_LIBLO
if (sessionManager == LIBJACK_SESSION_MANAGER_NSM)
@@ -344,32 +377,35 @@ protected:
}
#endif

// we only get here if bridge crashed or thread asked to exit
if (fProcess->isRunning() && shouldThreadExit())
if (! externalProcess)
{
fProcess->waitForProcessToFinish(2000);

if (fProcess->isRunning())
// we only get here if bridge crashed or thread asked to exit
if (fProcess->isRunning() && shouldThreadExit())
{
carla_stdout("CarlaPluginJackThread::run() - application refused to close, force kill now");
fProcess->kill();
fProcess->waitForProcessToFinish(2000);

if (fProcess->isRunning())
{
carla_stdout("CarlaPluginJackThread::run() - application refused to close, force kill now");
fProcess->kill();
}
}
}
else
{
// forced quit, may have crashed
if (fProcess->getExitCode() != 0 /*|| fProcess->exitStatus() == QProcess::CrashExit*/)
else
{
carla_stderr("CarlaPluginJackThread::run() - application crashed");

CarlaString errorString("Plugin '" + CarlaString(kPlugin->getName()) + "' has crashed!\n"
"Saving now will lose its current settings.\n"
"Please remove this plugin, and not rely on it from this point.");
kEngine->callback(true, true,
ENGINE_CALLBACK_ERROR,
kPlugin->getId(),
0, 0, 0, 0.0f,
errorString);
// forced quit, may have crashed
if (fProcess->getExitCode() != 0 /*|| fProcess->exitStatus() == QProcess::CrashExit*/)
{
carla_stderr("CarlaPluginJackThread::run() - application crashed");

CarlaString errorString("Plugin '" + CarlaString(kPlugin->getName()) + "' has crashed!\n"
"Saving now will lose its current settings.\n"
"Please remove this plugin, and not rely on it from this point.");
kEngine->callback(true, true,
ENGINE_CALLBACK_ERROR,
kPlugin->getId(),
0, 0, 0, 0.0f,
errorString);
}
}
}

@@ -437,6 +473,7 @@ public:
fProcCanceled(false),
fBufferSize(engine->getBufferSize()),
fProcWaitTime(0),
fSetupHints(0x0),
fBridgeThread(engine, this),
fShmAudioPool(),
fShmRtClientControl(),
@@ -1574,7 +1611,7 @@ public:
// ---------------------------------------------------------------
// setup hints and options

const int setupHints = label[5] - '0';
fSetupHints = static_cast<uint>(label[5] - '0');

// FIXME dryWet broken
pData->hints = PLUGIN_IS_BRIDGE | PLUGIN_OPTION_FIXED_BUFFERS;
@@ -1583,7 +1620,7 @@ public:
#endif
//fInfo.optionsAvailable = optionAv;

if (setupHints & LIBJACK_FLAG_CONTROL_WINDOW)
if (fSetupHints & LIBJACK_FLAG_CONTROL_WINDOW)
pData->hints |= PLUGIN_HAS_CUSTOM_UI;

// ---------------------------------------------------------------
@@ -1629,6 +1666,7 @@ private:
bool fProcCanceled;
uint fBufferSize;
uint fProcWaitTime;
uint fSetupHints;

CarlaPluginJackThread fBridgeThread;

@@ -1780,15 +1818,34 @@ private:
const bool needsCancelableAction = ! pData->engine->isLoadingProject();
const bool needsEngineIdle = pData->engine->getType() != kEngineTypePlugin;

CarlaString actionName;

if (needsCancelableAction)
{
if (fSetupHints & LIBJACK_FLAG_EXTERNAL_START)
{
const EngineOptions& options(pData->engine->getOptions());
CarlaString binaryDir(options.binaryDir);

char* const hwVars = fBridgeThread.getEnvVarsToExport();

actionName = "Waiting for external JACK application start, please use the following environment variables:\n";
actionName += hwVars;

delete[] hwVars;
}
else
{
actionName = "Loading JACK application";
}

pData->engine->setActionCanceled(false);
pData->engine->callback(true, true,
ENGINE_CALLBACK_CANCELABLE_ACTION,
pData->id,
1,
0, 0, 0.0f,
"Loading JACK application");
actionName.buffer());
}

for (;fBridgeThread.isThreadRunning();)
@@ -1815,7 +1872,7 @@ private:
pData->id,
0,
0, 0, 0.0f,
"Loading JACK application");
actionName.buffer());
}

if (fInitError || ! fInitiated)


+ 7
- 3
source/frontend/carla_database.py View File

@@ -1964,9 +1964,11 @@ class JackApplicationW(QDialog):
UI_SESSION_LADISH = 1
UI_SESSION_NSM = 2

FLAG_CONTROL_WINDOW = 0x01
FLAG_CAPTURE_FIRST_WINDOW = 0x02
FLAG_BUFFERS_ADDITION_MODE = 0x10
FLAG_CONTROL_WINDOW = 0x01
FLAG_CAPTURE_FIRST_WINDOW = 0x02
FLAG_BUFFERS_ADDITION_MODE = 0x10
FLAG_MIDI_OUTPUT_CHANNEL_MIXDOWN = 0x20
FLAG_EXTERNAL_START = 0x40

def __init__(self, parent, host):
QDialog.__init__(self, parent)
@@ -2015,6 +2017,8 @@ class JackApplicationW(QDialog):
flags |= self.FLAG_CAPTURE_FIRST_WINDOW
if self.ui.cb_buffers_addition_mode.isChecked():
flags |= self.FLAG_BUFFERS_ADDITION_MODE
if self.ui.cb_external_start.isChecked():
flags |= self.FLAG_EXTERNAL_START

baseIntVal = ord('0')
labelSetup = "%s%s%s%s%s%s" % (chr(baseIntVal+self.ui.sb_audio_ins.value()),


+ 6
- 4
source/includes/CarlaLibJackHints.h View File

@@ -26,11 +26,13 @@ extern "C" {

enum SetupHints {
// Application Window management
LIBJACK_FLAG_CONTROL_WINDOW = 0x01,
LIBJACK_FLAG_CAPTURE_FIRST_WINDOW = 0x02,
LIBJACK_FLAG_CONTROL_WINDOW = 0x01,
LIBJACK_FLAG_CAPTURE_FIRST_WINDOW = 0x02,
// Audio/MIDI Buffers management
LIBJACK_FLAG_AUDIO_BUFFERS_ADDITION = 0x10,
LIBJACK_FLAG_MIDI_OUTPUT_BUFFERS_CHANNEL_MIXDOWN = 0x20,
LIBJACK_FLAG_AUDIO_BUFFERS_ADDITION = 0x10,
LIBJACK_FLAG_MIDI_OUTPUT_CHANNEL_MIXDOWN = 0x20,
// Developer options
LIBJACK_FLAG_EXTERNAL_START = 0x40,
};

enum SessionManager {


+ 13
- 0
source/utils/CarlaString.hpp View File

@@ -597,6 +597,19 @@ public:
return carla_strdup_safe(fBuffer);
}

/*
* Release the buffer pointer while clearing this string.
* This allows to keep a pointer to the buffer after this object is deleted.
*/
char* releaseBufferPointer() noexcept
{
char* ret = fBufferLen > 0 ? fBuffer : nullptr;
fBuffer = _null();
fBufferLen = 0;
fBufferAlloc = false;
return ret;
}

// -------------------------------------------------------------------
// base64 stuff, based on http://www.adp-gmbh.ch/cpp/common/base64.html
// Copyright (C) 2004-2008 René Nyffenegger


Loading…
Cancel
Save