|
@@ -19,12 +19,15 @@ |
|
|
#include "CarlaPluginThread.hpp" |
|
|
#include "CarlaPluginThread.hpp" |
|
|
#include "CarlaEngine.hpp" |
|
|
#include "CarlaEngine.hpp" |
|
|
|
|
|
|
|
|
// FIXME |
|
|
|
|
|
#include <QtCore/QDebug> |
|
|
|
|
|
#include <QtCore/QProcess> |
|
|
|
|
|
|
|
|
#include "juce_core.h" |
|
|
|
|
|
|
|
|
|
|
|
using juce::String; |
|
|
|
|
|
using juce::StringArray; |
|
|
|
|
|
|
|
|
CARLA_BACKEND_START_NAMESPACE |
|
|
CARLA_BACKEND_START_NAMESPACE |
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------- |
|
|
|
|
|
|
|
|
#ifdef DEBUG |
|
|
#ifdef DEBUG |
|
|
static inline |
|
|
static inline |
|
|
const char* PluginThreadMode2str(const CarlaPluginThread::Mode mode) noexcept |
|
|
const char* PluginThreadMode2str(const CarlaPluginThread::Mode mode) noexcept |
|
@@ -48,6 +51,8 @@ const char* PluginThreadMode2str(const CarlaPluginThread::Mode mode) noexcept |
|
|
} |
|
|
} |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------- |
|
|
|
|
|
|
|
|
CarlaPluginThread::CarlaPluginThread(CarlaBackend::CarlaEngine* const engine, CarlaBackend::CarlaPlugin* const plugin, const Mode mode) noexcept |
|
|
CarlaPluginThread::CarlaPluginThread(CarlaBackend::CarlaEngine* const engine, CarlaBackend::CarlaPlugin* const plugin, const Mode mode) noexcept |
|
|
: CarlaThread("CarlaPluginThread"), |
|
|
: CarlaThread("CarlaPluginThread"), |
|
|
fEngine(engine), |
|
|
fEngine(engine), |
|
@@ -64,9 +69,10 @@ CarlaPluginThread::~CarlaPluginThread() noexcept |
|
|
|
|
|
|
|
|
if (fProcess != nullptr) |
|
|
if (fProcess != nullptr) |
|
|
{ |
|
|
{ |
|
|
try { |
|
|
|
|
|
delete fProcess; |
|
|
|
|
|
} CARLA_SAFE_EXCEPTION("~CarlaPluginThread(): delete QProcess"); |
|
|
|
|
|
|
|
|
//fProcess.release(); |
|
|
|
|
|
//try { |
|
|
|
|
|
//delete fProcess; |
|
|
|
|
|
//} CARLA_SAFE_EXCEPTION("~CarlaPluginThread(): delete ChildProcess"); |
|
|
fProcess = nullptr; |
|
|
fProcess = nullptr; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@@ -94,7 +100,8 @@ uintptr_t CarlaPluginThread::getPid() const |
|
|
{ |
|
|
{ |
|
|
CARLA_SAFE_ASSERT_RETURN(fProcess != nullptr, 0); |
|
|
CARLA_SAFE_ASSERT_RETURN(fProcess != nullptr, 0); |
|
|
|
|
|
|
|
|
return (uintptr_t)fProcess->pid(); |
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
//return (uintptr_t)fProcess->pid(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void CarlaPluginThread::run() |
|
|
void CarlaPluginThread::run() |
|
@@ -103,10 +110,10 @@ void CarlaPluginThread::run() |
|
|
|
|
|
|
|
|
if (fProcess == nullptr) |
|
|
if (fProcess == nullptr) |
|
|
{ |
|
|
{ |
|
|
fProcess = new QProcess(nullptr); |
|
|
|
|
|
fProcess->setProcessChannelMode(QProcess::ForwardedChannels); |
|
|
|
|
|
|
|
|
fProcess = new ChildProcess; |
|
|
|
|
|
//fProcess->setProcessChannelMode(QProcess::ForwardedChannels); |
|
|
} |
|
|
} |
|
|
else if (fProcess->state() == QProcess::Running) |
|
|
|
|
|
|
|
|
else if (fProcess->isRunning()) |
|
|
{ |
|
|
{ |
|
|
carla_stderr("CarlaPluginThread::run() - already running, giving up..."); |
|
|
carla_stderr("CarlaPluginThread::run() - already running, giving up..."); |
|
|
|
|
|
|
|
@@ -119,7 +126,8 @@ void CarlaPluginThread::run() |
|
|
case PLUGIN_THREAD_LV2_GUI: |
|
|
case PLUGIN_THREAD_LV2_GUI: |
|
|
case PLUGIN_THREAD_VST_GUI: |
|
|
case PLUGIN_THREAD_VST_GUI: |
|
|
fEngine->callback(CarlaBackend::ENGINE_CALLBACK_UI_STATE_CHANGED, fPlugin->getId(), 0, 0, 0.0f, nullptr); |
|
|
fEngine->callback(CarlaBackend::ENGINE_CALLBACK_UI_STATE_CHANGED, fPlugin->getId(), 0, 0, 0.0f, nullptr); |
|
|
fProcess->terminate(); |
|
|
|
|
|
|
|
|
fProcess->kill(); |
|
|
|
|
|
fProcess = nullptr; |
|
|
return; |
|
|
return; |
|
|
|
|
|
|
|
|
case PLUGIN_THREAD_BRIDGE: |
|
|
case PLUGIN_THREAD_BRIDGE: |
|
@@ -127,41 +135,19 @@ void CarlaPluginThread::run() |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
QString name(fPlugin->getName()); |
|
|
|
|
|
|
|
|
String name(fPlugin->getName()); |
|
|
|
|
|
|
|
|
if (name.isEmpty()) |
|
|
if (name.isEmpty()) |
|
|
name = "(none)"; |
|
|
name = "(none)"; |
|
|
|
|
|
|
|
|
QStringList arguments; |
|
|
|
|
|
QProcessEnvironment env(QProcessEnvironment::systemEnvironment()); |
|
|
|
|
|
const EngineOptions& options(fEngine->getOptions()); |
|
|
|
|
|
|
|
|
|
|
|
char strBuf[STR_MAX+1]; |
|
|
|
|
|
env.insert("ENGINE_OPTION_UIS_ALWAYS_ON_TOP", options.uisAlwaysOnTop ? "true" : "false"); |
|
|
|
|
|
|
|
|
|
|
|
if (options.maxParameters != 0) |
|
|
|
|
|
{ |
|
|
|
|
|
std::sprintf(strBuf, "%u", options.maxParameters); |
|
|
|
|
|
env.insert("ENGINE_OPTION_MAX_PARAMETERS", strBuf); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (options.uiBridgesTimeout != 0) |
|
|
|
|
|
{ |
|
|
|
|
|
std::sprintf(strBuf, "%u", options.uiBridgesTimeout); |
|
|
|
|
|
env.insert("ENGINE_OPTION_UI_BRIDGES_TIMEOUT", strBuf); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (options.frontendWinId != 0) |
|
|
|
|
|
{ |
|
|
|
|
|
std::sprintf(strBuf, P_UINTPTR, options.frontendWinId); |
|
|
|
|
|
env.insert("ENGINE_OPTION_FRONTEND_WIN_ID", strBuf); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
StringArray arguments; |
|
|
|
|
|
|
|
|
if (options.binaryDir != nullptr) |
|
|
|
|
|
env.insert("ENGINE_OPTION_PATH_BINARIES", options.binaryDir); |
|
|
|
|
|
|
|
|
#ifndef CARLA_OS_WIN |
|
|
|
|
|
if (fBinary.endsWith(".exe")) |
|
|
|
|
|
arguments.add("wine"); |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
if (options.resourceDir != nullptr) |
|
|
|
|
|
env.insert("ENGINE_OPTION_PATH_RESOURCES", options.resourceDir); |
|
|
|
|
|
|
|
|
arguments.add(fBinary.buffer()); |
|
|
|
|
|
|
|
|
switch (fMode) |
|
|
switch (fMode) |
|
|
{ |
|
|
{ |
|
@@ -169,54 +155,45 @@ void CarlaPluginThread::run() |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
case PLUGIN_THREAD_DSSI_GUI: |
|
|
case PLUGIN_THREAD_DSSI_GUI: |
|
|
/* osc-url */ arguments << QString("%1/%2").arg(fEngine->getOscServerPathUDP()).arg(fPlugin->getId()); |
|
|
|
|
|
/* filename */ arguments << fPlugin->getFilename(); |
|
|
|
|
|
/* label */ arguments << fLabel.buffer(); |
|
|
|
|
|
/* ui-title */ arguments << QString("%1 (GUI)").arg(fPlugin->getName()); |
|
|
|
|
|
|
|
|
/* osc-url */ arguments.add(String(fEngine->getOscServerPathUDP()) + String("/") + String(fPlugin->getId())); |
|
|
|
|
|
/* filename */ arguments.add(fPlugin->getFilename()); |
|
|
|
|
|
/* label */ arguments.add(fLabel.buffer()); |
|
|
|
|
|
/* ui-title */ arguments.add(name + String(" (GUI)")); |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
case PLUGIN_THREAD_LV2_GUI: |
|
|
case PLUGIN_THREAD_LV2_GUI: |
|
|
/* osc-url */ arguments << QString("%1/%2").arg(fEngine->getOscServerPathUDP()).arg(fPlugin->getId()); |
|
|
|
|
|
/* URI */ arguments << fLabel.buffer(); |
|
|
|
|
|
/* ui-URI */ arguments << fExtra1.buffer(); |
|
|
|
|
|
/* ui-title */ arguments << QString("%1 (GUI)").arg(fPlugin->getName()); |
|
|
|
|
|
|
|
|
/* osc-url */ arguments.add(String(fEngine->getOscServerPathUDP()) + String("/") + String(fPlugin->getId())); |
|
|
|
|
|
/* URI */ arguments.add(fLabel.buffer()); |
|
|
|
|
|
/* ui-URI */ arguments.add(fExtra1.buffer()); |
|
|
|
|
|
/* ui-title */ arguments.add(name + String(" (GUI)")); |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
case PLUGIN_THREAD_VST_GUI: |
|
|
case PLUGIN_THREAD_VST_GUI: |
|
|
/* osc-url */ arguments << QString("%1/%2").arg(fEngine->getOscServerPathUDP()).arg(fPlugin->getId()); |
|
|
|
|
|
/* filename */ arguments << fPlugin->getFilename(); |
|
|
|
|
|
/* ui-title */ arguments << QString("%1 (GUI)").arg(fPlugin->getName()); |
|
|
|
|
|
|
|
|
/* osc-url */ arguments.add(String(fEngine->getOscServerPathUDP()) + String("/") + String(fPlugin->getId())); |
|
|
|
|
|
/* filename */ arguments.add(fPlugin->getFilename()); |
|
|
|
|
|
/* ui-title */ arguments.add(name + String(" (GUI)")); |
|
|
break; |
|
|
break; |
|
|
|
|
|
|
|
|
case PLUGIN_THREAD_BRIDGE: |
|
|
case PLUGIN_THREAD_BRIDGE: |
|
|
env.insert("ENGINE_BRIDGE_SHM_IDS", fExtra2.buffer()); |
|
|
|
|
|
env.insert("ENGINE_BRIDGE_CLIENT_NAME", name); |
|
|
|
|
|
env.insert("ENGINE_BRIDGE_OSC_URL", QString("%1/%2").arg(fEngine->getOscServerPathUDP()).arg(fPlugin->getId())); |
|
|
|
|
|
|
|
|
|
|
|
#ifndef CARLA_OS_WIN |
|
|
|
|
|
if (fBinary.endsWith(".exe")) |
|
|
|
|
|
{ |
|
|
|
|
|
env.insert("WINEDEBUG", "-all"); |
|
|
|
|
|
arguments << fBinary.buffer(); |
|
|
|
|
|
fBinary = "wine"; |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
/* osc-url */ arguments << QString("%1/%2").arg(fEngine->getOscServerPathUDP()).arg(fPlugin->getId()); |
|
|
|
|
|
/* stype */ arguments << fExtra1.buffer(); |
|
|
|
|
|
/* filename */ arguments << fPlugin->getFilename(); |
|
|
|
|
|
/* name */ arguments << name; |
|
|
|
|
|
/* label */ arguments << fLabel.buffer(); |
|
|
|
|
|
/* uniqueId */ arguments << QString("%1").arg(fPlugin->getUniqueId()); |
|
|
|
|
|
|
|
|
//env.insert("ENGINE_BRIDGE_SHM_IDS", fExtra2.buffer()); |
|
|
|
|
|
//env.insert("ENGINE_BRIDGE_CLIENT_NAME", name); |
|
|
|
|
|
//env.insert("ENGINE_BRIDGE_OSC_URL", QString("%1/%2").arg(fEngine->getOscServerPathUDP()).arg(fPlugin->getId())); |
|
|
|
|
|
//env.insert("WINEDEBUG", "-all"); |
|
|
|
|
|
|
|
|
|
|
|
/* osc-url */ arguments.add(String(fEngine->getOscServerPathUDP()) + String("/") + String(fPlugin->getId())); |
|
|
|
|
|
/* stype */ arguments.add(fExtra1.buffer()); |
|
|
|
|
|
/* filename */ arguments.add(fPlugin->getFilename()); |
|
|
|
|
|
/* name */ arguments.add(name); |
|
|
|
|
|
/* label */ arguments.add(fLabel.buffer()); |
|
|
|
|
|
/* uniqueId */ arguments.add(String(static_cast<juce::int64>(fPlugin->getUniqueId()))); |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
fProcess->setProcessEnvironment(env); |
|
|
|
|
|
|
|
|
|
|
|
carla_stdout("starting app.."); |
|
|
carla_stdout("starting app.."); |
|
|
qWarning() << arguments; |
|
|
|
|
|
|
|
|
//qWarning() << arguments; |
|
|
|
|
|
|
|
|
fProcess->start(fBinary.buffer(), arguments); |
|
|
|
|
|
fProcess->waitForStarted(); |
|
|
|
|
|
|
|
|
fProcess->start(arguments); |
|
|
|
|
|
//fProcess->waitForStarted(); |
|
|
|
|
|
|
|
|
switch (fMode) |
|
|
switch (fMode) |
|
|
{ |
|
|
{ |
|
@@ -228,18 +205,15 @@ void CarlaPluginThread::run() |
|
|
case PLUGIN_THREAD_VST_GUI: |
|
|
case PLUGIN_THREAD_VST_GUI: |
|
|
if (fPlugin->waitForOscGuiShow()) |
|
|
if (fPlugin->waitForOscGuiShow()) |
|
|
{ |
|
|
{ |
|
|
//fProcess->waitForFinished(-1); |
|
|
|
|
|
|
|
|
|
|
|
while (fProcess->state() != QProcess::NotRunning && ! shouldThreadExit()) |
|
|
|
|
|
|
|
|
while (fProcess->isRunning() && ! shouldThreadExit()) |
|
|
carla_sleep(1); |
|
|
carla_sleep(1); |
|
|
|
|
|
|
|
|
// we only get here if UI was closed or thread asked to exit |
|
|
// we only get here if UI was closed or thread asked to exit |
|
|
|
|
|
|
|
|
if (fProcess->state() != QProcess::NotRunning && shouldThreadExit()) |
|
|
|
|
|
|
|
|
if (fProcess->isRunning() && shouldThreadExit()) |
|
|
{ |
|
|
{ |
|
|
fProcess->waitForFinished(static_cast<int>(fEngine->getOptions().uiBridgesTimeout)); |
|
|
|
|
|
|
|
|
//fProcess->waitForFinished(static_cast<int>(fEngine->getOptions().uiBridgesTimeout)); |
|
|
|
|
|
|
|
|
if (fProcess->state() == QProcess::Running) |
|
|
|
|
|
|
|
|
if (fProcess->isRunning()) |
|
|
{ |
|
|
{ |
|
|
carla_stdout("CarlaPluginThread::run() - UI refused to close, force kill now"); |
|
|
carla_stdout("CarlaPluginThread::run() - UI refused to close, force kill now"); |
|
|
fProcess->kill(); |
|
|
fProcess->kill(); |
|
@@ -249,7 +223,7 @@ void CarlaPluginThread::run() |
|
|
carla_stdout("CarlaPluginThread::run() - UI auto-closed successfully"); |
|
|
carla_stdout("CarlaPluginThread::run() - UI auto-closed successfully"); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
else if (fProcess->exitCode() != 0 || fProcess->exitStatus() == QProcess::CrashExit) |
|
|
|
|
|
|
|
|
else if (fProcess->getExitCode() != 0 /*|| fProcess->exitStatus() == QProcess::CrashExit*/) |
|
|
carla_stderr("CarlaPluginThread::run() - UI crashed while running"); |
|
|
carla_stderr("CarlaPluginThread::run() - UI crashed while running"); |
|
|
else |
|
|
else |
|
|
carla_stdout("CarlaPluginThread::run() - UI closed cleanly"); |
|
|
carla_stdout("CarlaPluginThread::run() - UI closed cleanly"); |
|
@@ -258,14 +232,9 @@ void CarlaPluginThread::run() |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
{ |
|
|
{ |
|
|
fProcess->close(); |
|
|
|
|
|
CARLA_SAFE_ASSERT(fProcess->state() == QProcess::NotRunning); |
|
|
|
|
|
|
|
|
|
|
|
if (fProcess->exitCode() != 0 || fProcess->exitStatus() == QProcess::CrashExit) |
|
|
|
|
|
carla_stderr("CarlaPluginThread::run() - GUI crashed while opening"); |
|
|
|
|
|
else |
|
|
|
|
|
carla_stdout("CarlaPluginThread::run() - GUI timeout"); |
|
|
|
|
|
|
|
|
fProcess->kill(); |
|
|
|
|
|
|
|
|
|
|
|
carla_stdout("CarlaPluginThread::run() - GUI timeout"); |
|
|
fEngine->callback(CarlaBackend::ENGINE_CALLBACK_UI_STATE_CHANGED, fPlugin->getId(), 0, 0, 0.0f, nullptr); |
|
|
fEngine->callback(CarlaBackend::ENGINE_CALLBACK_UI_STATE_CHANGED, fPlugin->getId(), 0, 0, 0.0f, nullptr); |
|
|
} |
|
|
} |
|
|
break; |
|
|
break; |
|
@@ -273,22 +242,21 @@ void CarlaPluginThread::run() |
|
|
case PLUGIN_THREAD_BRIDGE: |
|
|
case PLUGIN_THREAD_BRIDGE: |
|
|
//fProcess->waitForFinished(-1); |
|
|
//fProcess->waitForFinished(-1); |
|
|
|
|
|
|
|
|
while (fProcess->state() != QProcess::NotRunning && ! shouldThreadExit()) |
|
|
|
|
|
|
|
|
while (fProcess->isRunning() && ! shouldThreadExit()) |
|
|
carla_sleep(1); |
|
|
carla_sleep(1); |
|
|
|
|
|
|
|
|
// we only get here if bridge crashed or thread asked to exit |
|
|
// we only get here if bridge crashed or thread asked to exit |
|
|
|
|
|
|
|
|
if (shouldThreadExit()) |
|
|
if (shouldThreadExit()) |
|
|
{ |
|
|
{ |
|
|
fProcess->waitForFinished(500); |
|
|
|
|
|
|
|
|
fProcess->getExitCode(); // TEST |
|
|
|
|
|
|
|
|
if (fProcess->state() == QProcess::Running) |
|
|
|
|
|
fProcess->close(); |
|
|
|
|
|
|
|
|
if (fProcess->isRunning()) |
|
|
|
|
|
fProcess->kill(); |
|
|
} |
|
|
} |
|
|
else |
|
|
else |
|
|
{ |
|
|
{ |
|
|
// forced quit, may have crashed |
|
|
// forced quit, may have crashed |
|
|
if (fProcess->exitCode() != 0 || fProcess->exitStatus() == QProcess::CrashExit) |
|
|
|
|
|
|
|
|
if (fProcess->getExitCode() != 0 /*|| fProcess->exitStatus() == QProcess::CrashExit*/) |
|
|
{ |
|
|
{ |
|
|
carla_stderr("CarlaPluginThread::run() - bridge crashed"); |
|
|
carla_stderr("CarlaPluginThread::run() - bridge crashed"); |
|
|
|
|
|
|
|
@@ -302,6 +270,45 @@ void CarlaPluginThread::run() |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
carla_stdout("app finished"); |
|
|
carla_stdout("app finished"); |
|
|
|
|
|
fProcess = nullptr; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------- |
|
|
|
|
|
|
|
|
|
|
|
#if 0 |
|
|
|
|
|
QProcessEnvironment env(QProcessEnvironment::systemEnvironment()); |
|
|
|
|
|
const EngineOptions& options(fEngine->getOptions()); |
|
|
|
|
|
|
|
|
|
|
|
char strBuf[STR_MAX+1]; |
|
|
|
|
|
env.insert("ENGINE_OPTION_UIS_ALWAYS_ON_TOP", options.uisAlwaysOnTop ? "true" : "false"); |
|
|
|
|
|
|
|
|
|
|
|
if (options.maxParameters != 0) |
|
|
|
|
|
{ |
|
|
|
|
|
std::sprintf(strBuf, "%u", options.maxParameters); |
|
|
|
|
|
env.insert("ENGINE_OPTION_MAX_PARAMETERS", strBuf); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (options.uiBridgesTimeout != 0) |
|
|
|
|
|
{ |
|
|
|
|
|
std::sprintf(strBuf, "%u", options.uiBridgesTimeout); |
|
|
|
|
|
env.insert("ENGINE_OPTION_UI_BRIDGES_TIMEOUT", strBuf); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (options.frontendWinId != 0) |
|
|
|
|
|
{ |
|
|
|
|
|
std::sprintf(strBuf, P_UINTPTR, options.frontendWinId); |
|
|
|
|
|
env.insert("ENGINE_OPTION_FRONTEND_WIN_ID", strBuf); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (options.binaryDir != nullptr) |
|
|
|
|
|
env.insert("ENGINE_OPTION_PATH_BINARIES", options.binaryDir); |
|
|
|
|
|
|
|
|
|
|
|
if (options.resourceDir != nullptr) |
|
|
|
|
|
env.insert("ENGINE_OPTION_PATH_RESOURCES", options.resourceDir); |
|
|
|
|
|
|
|
|
|
|
|
fProcess->setProcessEnvironment(env); |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------- |
|
|
|
|
|
|
|
|
CARLA_BACKEND_END_NAMESPACE |
|
|
CARLA_BACKEND_END_NAMESPACE |