| 
							- /*
 -  * Carla Plugin
 -  * Copyright (C) 2011-2014 Filipe Coelho <falktx@falktx.com>
 -  *
 -  * This program is free software; you can redistribute it and/or
 -  * modify it under the terms of the GNU General Public License as
 -  * published by the Free Software Foundation; either version 2 of
 -  * the License, or any later version.
 -  *
 -  * This program is distributed in the hope that it will be useful,
 -  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 -  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 -  * GNU General Public License for more details.
 -  *
 -  * For a full copy of the GNU General Public License see the doc/GPL.txt file.
 -  */
 - 
 - #include "CarlaPlugin.hpp"
 - #include "CarlaPluginThread.hpp"
 - #include "CarlaEngine.hpp"
 - 
 - #include "juce_core.h"
 - 
 - using juce::String;
 - using juce::StringArray;
 - 
 - CARLA_BACKEND_START_NAMESPACE
 - 
 - // -----------------------------------------------------------------------
 - 
 - #ifdef DEBUG
 - static inline
 - const char* PluginThreadMode2str(const CarlaPluginThread::Mode mode) noexcept
 - {
 -     switch (mode)
 -     {
 -     case CarlaPluginThread::PLUGIN_THREAD_NULL:
 -         return "PLUGIN_THREAD_NULL";
 -     case CarlaPluginThread::PLUGIN_THREAD_DSSI_GUI:
 -         return "PLUGIN_THREAD_DSSI_GUI";
 -     case CarlaPluginThread::PLUGIN_THREAD_LV2_GUI:
 -         return "PLUGIN_THREAD_LV2_GUI";
 -     case CarlaPluginThread::PLUGIN_THREAD_VST_GUI:
 -         return "PLUGIN_THREAD_VST_GUI";
 -     case CarlaPluginThread::PLUGIN_THREAD_BRIDGE:
 -         return "PLUGIN_THREAD_BRIDGE";
 -     }
 - 
 -     carla_stderr("CarlaPluginThread::PluginThreadMode2str(%i) - invalid mode", mode);
 -     return nullptr;
 - }
 - #endif
 - 
 - // -----------------------------------------------------------------------
 - 
 - CarlaPluginThread::CarlaPluginThread(CarlaBackend::CarlaEngine* const engine, CarlaBackend::CarlaPlugin* const plugin, const Mode mode) noexcept
 -     : CarlaThread("CarlaPluginThread"),
 -       fEngine(engine),
 -       fPlugin(plugin),
 -       fMode(mode),
 -       fBinary(),
 -       fLabel(),
 -       fExtra1(),
 -       fExtra2(),
 -       fProcess(nullptr),
 -       leakDetector_CarlaPluginThread()
 - {
 -     carla_debug("CarlaPluginThread::CarlaPluginThread(%p, %p, %s)", engine, plugin, PluginThreadMode2str(mode));
 - }
 - 
 - CarlaPluginThread::~CarlaPluginThread() noexcept
 - {
 -     carla_debug("CarlaPluginThread::~CarlaPluginThread()");
 - 
 -     if (fProcess != nullptr)
 -     {
 -         //fProcess.release();
 -         //try {
 -             //delete fProcess;
 -         //} CARLA_SAFE_EXCEPTION("~CarlaPluginThread(): delete ChildProcess");
 -         fProcess = nullptr;
 -     }
 - }
 - 
 - void CarlaPluginThread::setMode(const CarlaPluginThread::Mode mode) noexcept
 - {
 -     CARLA_SAFE_ASSERT(! isThreadRunning());
 -     carla_debug("CarlaPluginThread::setMode(%s)", PluginThreadMode2str(mode));
 - 
 -     fMode = mode;
 - }
 - 
 - void CarlaPluginThread::setOscData(const char* const binary, const char* const label, const char* const extra1, const char* const extra2) noexcept
 - {
 -     CARLA_SAFE_ASSERT(! isThreadRunning());
 -     carla_debug("CarlaPluginThread::setOscData(\"%s\", \"%s\", \"%s\", \"%s\")", binary, label, extra1, extra2);
 - 
 -     fBinary = binary;
 -     fLabel  = label;
 -     fExtra1 = extra1;
 -     fExtra2 = extra2;
 - }
 - 
 - uintptr_t CarlaPluginThread::getPid() const
 - {
 -     CARLA_SAFE_ASSERT_RETURN(fProcess != nullptr, 0);
 - 
 -     return (uintptr_t)fProcess->getPID();
 - }
 - 
 - void CarlaPluginThread::run()
 - {
 -     carla_debug("CarlaPluginThread::run()");
 - 
 -     if (fProcess == nullptr)
 -     {
 -        fProcess = new ChildProcess;
 -        //fProcess->setProcessChannelMode(QProcess::ForwardedChannels);
 -     }
 -     else if (fProcess->isRunning())
 -     {
 -         carla_stderr("CarlaPluginThread::run() - already running, giving up...");
 - 
 -         switch (fMode)
 -         {
 -         case PLUGIN_THREAD_NULL:
 -         case PLUGIN_THREAD_BRIDGE:
 -             break;
 - 
 -         case PLUGIN_THREAD_DSSI_GUI:
 -         case PLUGIN_THREAD_LV2_GUI:
 -         case PLUGIN_THREAD_VST_GUI:
 -             fEngine->callback(CarlaBackend::ENGINE_CALLBACK_UI_STATE_CHANGED, fPlugin->getId(), 0, 0, 0.0f, nullptr);
 -             fProcess->kill();
 -             fProcess = nullptr;
 -             return;
 -         }
 -     }
 - 
 -     String name(fPlugin->getName());
 - 
 -     if (name.isEmpty())
 -         name = "(none)";
 - 
 -     if (fLabel.isEmpty())
 -         fLabel = "\"\"";
 - 
 -     StringArray arguments;
 - 
 - #ifndef CARLA_OS_WIN
 -     if (fBinary.endsWith(".exe"))
 -         arguments.add("wine");
 - #endif
 - 
 -     arguments.add(fBinary.buffer());
 - 
 -     // use a global mutex to ensure bridge environment is correct
 -     static CarlaMutex sEnvMutex;
 - 
 -     char strBuf[STR_MAX+1];
 -     strBuf[STR_MAX] = '\0';
 - 
 -     const EngineOptions& options(fEngine->getOptions());
 - 
 -     sEnvMutex.lock();
 - 
 -     std::snprintf(strBuf, STR_MAX, "%f", fEngine->getSampleRate());
 -     carla_setenv("CARLA_SAMPLE_RATE", strBuf);
 - 
 -     std::snprintf(strBuf, STR_MAX, "%u", options.maxParameters);
 -     carla_setenv("ENGINE_OPTION_MAX_PARAMETERS", strBuf);
 - 
 -     std::snprintf(strBuf, STR_MAX, "%u", options.uiBridgesTimeout);
 -     carla_setenv("ENGINE_OPTION_UI_BRIDGES_TIMEOUT",strBuf);
 - 
 -     carla_setenv("ENGINE_OPTION_UIS_ALWAYS_ON_TOP", bool2str(options.uisAlwaysOnTop));
 - 
 -     if (options.pathLADSPA != nullptr && options.pathLADSPA[0] != '\0')
 -         carla_setenv("ENGINE_OPTION_PLUGIN_PATH_LADSPA", options.pathLADSPA);
 - 
 -     if (options.pathDSSI != nullptr && options.pathDSSI[0] != '\0')
 -         carla_setenv("ENGINE_OPTION_PLUGIN_PATH_DSSI", options.pathDSSI);
 - 
 -     if (options.pathLV2 != nullptr && options.pathLV2[0] != '\0')
 -         carla_setenv("ENGINE_OPTION_PLUGIN_PATH_LV2", options.pathLV2);
 - 
 -     if (options.pathVST != nullptr && options.pathVST[0] != '\0')
 -         carla_setenv("ENGINE_OPTION_PLUGIN_PATH_VST", options.pathVST);
 - 
 -     if (options.pathVST3 != nullptr && options.pathVST3[0] != '\0')
 -         carla_setenv("ENGINE_OPTION_PLUGIN_PATH_VST3", options.pathVST3);
 - 
 -     if (options.pathAU != nullptr && options.pathAU[0] != '\0')
 -         carla_setenv("ENGINE_OPTION_PLUGIN_PATH_AU", options.pathAU);
 - 
 -     if (options.pathGIG != nullptr && options.pathGIG[0] != '\0')
 -         carla_setenv("ENGINE_OPTION_PLUGIN_PATH_GIG", options.pathGIG);
 - 
 -     if (options.pathSF2 != nullptr && options.pathSF2[0] != '\0')
 -         carla_setenv("ENGINE_OPTION_PLUGIN_PATH_SF2", options.pathSF2);
 - 
 -     if (options.pathSFZ != nullptr && options.pathSFZ[0] != '\0')
 -         carla_setenv("ENGINE_OPTION_PLUGIN_PATH_SFZ", options.pathSFZ);
 - 
 -     if (options.binaryDir != nullptr && options.binaryDir[0] != '\0')
 -         carla_setenv("ENGINE_OPTION_PATH_BINARIES", options.binaryDir);
 - 
 -     if (options.resourceDir != nullptr && options.resourceDir[0] != '\0')
 -         carla_setenv("ENGINE_OPTION_PATH_RESOURCES", options.resourceDir);
 - 
 -     std::snprintf(strBuf, STR_MAX, P_UINTPTR, options.frontendWinId);
 -     carla_setenv("ENGINE_OPTION_FRONTEND_WIN_ID", strBuf);
 - 
 -     switch (fMode)
 -     {
 -     case PLUGIN_THREAD_NULL:
 -         break;
 - 
 -     case PLUGIN_THREAD_DSSI_GUI:
 -         /* 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;
 - 
 -     case PLUGIN_THREAD_LV2_GUI:
 -         /* osc-url   */ arguments.add(String(fEngine->getOscServerPathUDP()) + String("/") + String(fPlugin->getId()));
 -         /* URI       */ arguments.add(fLabel.buffer());
 -         /* UI URI    */ arguments.add(fExtra1.buffer());
 -         /* UI Bundle */ arguments.add(fExtra2.buffer());
 -         /* UI Title  */ arguments.add(name + String(" (GUI)"));
 -         break;
 - 
 -     case PLUGIN_THREAD_VST_GUI:
 -         /* osc-url  */ arguments.add(String(fEngine->getOscServerPathUDP()) + String("/") + String(fPlugin->getId()));
 -         /* filename */ arguments.add(fPlugin->getFilename());
 -         /* ui-title */ arguments.add(name + String(" (GUI)"));
 -         break;
 - 
 -     case PLUGIN_THREAD_BRIDGE:
 -         /* 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())));
 - 
 -         carla_setenv("ENGINE_BRIDGE_SHM_IDS", fExtra2.buffer());
 -         carla_setenv("ENGINE_BRIDGE_CLIENT_NAME", name.toRawUTF8());
 -         carla_setenv("ENGINE_BRIDGE_OSC_URL", String(String(fEngine->getOscServerPathUDP()) + String("/") + String(fPlugin->getId())).toRawUTF8());
 -         carla_setenv("WINEDEBUG", "-all");
 -         break;
 -     }
 - 
 -     carla_stdout("starting app..");
 - 
 -     fProcess->start(arguments);
 - 
 -     sEnvMutex.unlock();
 - 
 -     switch (fMode)
 -     {
 -     case PLUGIN_THREAD_NULL:
 -         break;
 - 
 -     case PLUGIN_THREAD_DSSI_GUI:
 -     case PLUGIN_THREAD_LV2_GUI:
 -     case PLUGIN_THREAD_VST_GUI:
 -         if (fPlugin->waitForOscGuiShow())
 -         {
 -             while (fProcess->isRunning() && ! shouldThreadExit())
 -                 carla_sleep(1);
 - 
 -             // we only get here if UI was closed or thread asked to exit
 -             if (fProcess->isRunning() && shouldThreadExit())
 -             {
 -                 fProcess->waitForProcessToFinish(static_cast<int>(fEngine->getOptions().uiBridgesTimeout));
 - 
 -                 if (fProcess->isRunning())
 -                 {
 -                     carla_stdout("CarlaPluginThread::run() - UI refused to close, force kill now");
 -                     fProcess->kill();
 -                 }
 -                 else
 -                 {
 -                     carla_stdout("CarlaPluginThread::run() - UI auto-closed successfully");
 -                 }
 -             }
 -             else if (fProcess->getExitCode() != 0 /*|| fProcess->exitStatus() == QProcess::CrashExit*/)
 -                 carla_stderr("CarlaPluginThread::run() - UI crashed while running");
 -             else
 -                 carla_stdout("CarlaPluginThread::run() - UI closed cleanly");
 - 
 -             fEngine->callback(CarlaBackend::ENGINE_CALLBACK_UI_STATE_CHANGED, fPlugin->getId(), 0, 0, 0.0f, nullptr);
 -         }
 -         else
 -         {
 -             fProcess->kill();
 - 
 -             carla_stdout("CarlaPluginThread::run() - GUI timeout");
 -             fEngine->callback(CarlaBackend::ENGINE_CALLBACK_UI_STATE_CHANGED, fPlugin->getId(), 0, 0, 0.0f, nullptr);
 -         }
 -         break;
 - 
 -     case PLUGIN_THREAD_BRIDGE:
 -         //fProcess->waitForFinished(-1);
 - 
 -         while (fProcess->isRunning() && ! shouldThreadExit())
 -             carla_sleep(1);
 - 
 -         // we only get here if bridge crashed or thread asked to exit
 -         if (fProcess->isRunning() && shouldThreadExit())
 -         {
 -             fProcess->waitForProcessToFinish(2000);
 - 
 -             if (fProcess->isRunning())
 -             {
 -                 carla_stdout("CarlaPluginThread::run() - bridge refused to close, force kill now");
 -                 fProcess->kill();
 -             }
 -             else
 -             {
 -                 carla_stdout("CarlaPluginThread::run() - bridge auto-closed successfully");
 -             }
 -         }
 -         else
 -         {
 -             // forced quit, may have crashed
 -             if (fProcess->getExitCode() != 0 /*|| fProcess->exitStatus() == QProcess::CrashExit*/)
 -             {
 -                 carla_stderr("CarlaPluginThread::run() - bridge crashed");
 - 
 -                 CarlaString errorString("Plugin '" + CarlaString(fPlugin->getName()) + "' has crashed!\n"
 -                                         "Saving now will lose its current settings.\n"
 -                                         "Please remove this plugin, and not rely on it from this point.");
 -                 fEngine->callback(CarlaBackend::ENGINE_CALLBACK_ERROR, fPlugin->getId(), 0, 0, 0.0f, errorString);
 -             }
 -         }
 -         break;
 -     }
 - 
 -     carla_stdout("app finished");
 -     fProcess = nullptr;
 - }
 - 
 - // -----------------------------------------------------------------------
 - 
 - CARLA_BACKEND_END_NAMESPACE
 
 
  |