diff --git a/source/backend/CarlaStandalone.cpp b/source/backend/CarlaStandalone.cpp index 6a268e217..094289c02 100644 --- a/source/backend/CarlaStandalone.cpp +++ b/source/backend/CarlaStandalone.cpp @@ -48,32 +48,27 @@ struct CarlaBackendStandalone { CarlaEngine* engine; EngineCallbackFunc engineCallback; void* engineCallbackPtr; +#ifndef BUILD_BRIDGE EngineOptions engineOptions; +#endif FileCallbackFunc fileCallback; void* fileCallbackPtr; CarlaString lastError; - CarlaBackendStandalone() + CarlaBackendStandalone() noexcept : engine(nullptr), engineCallback(nullptr), engineCallbackPtr(nullptr), +#ifndef BUILD_BRIDGE engineOptions(), +#endif fileCallback(nullptr), fileCallbackPtr(nullptr), - lastError() - { -#ifdef BUILD_BRIDGE - engineOptions.processMode = CB::ENGINE_PROCESS_MODE_BRIDGE; - engineOptions.transportMode = CB::ENGINE_TRANSPORT_MODE_BRIDGE; - engineOptions.forceStereo = false; - engineOptions.preferPluginBridges = false; - engineOptions.preferUiBridges = false; -#endif - } + lastError() {} - ~CarlaBackendStandalone() + ~CarlaBackendStandalone() noexcept { CARLA_SAFE_ASSERT(engine == nullptr); } @@ -192,6 +187,7 @@ protected: #endif } + // FIXME int handleOpen(const char* const path, const char* const types, lo_arg** const argv, const int argc, const lo_message msg) { CARLA_SAFE_ASSERT_RETURN(fOscServer != nullptr, 0); @@ -203,8 +199,10 @@ protected: if (! carla_is_engine_running()) { +#ifndef BUILD_BRIDGE gStandalone.engineOptions.processMode = CB::ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS; gStandalone.engineOptions.transportMode = CB::ENGINE_TRANSPORT_MODE_JACK; +#endif carla_engine_init("JACK", clientId); } @@ -414,10 +412,9 @@ static void carla_engine_init_common() #ifdef BUILD_BRIDGE using juce::File; - File binaryDir(File::getSpecialLocation(File::currentExecutableFile).getParentDirectory()); - gStandalone.engineOptions.binaryDir = carla_strdup_safe(binaryDir.getFullPathName().toRawUTF8()); - gStandalone.engineOptions.resourceDir = carla_strdup_safe(binaryDir.getChildFile("resources").getFullPathName().toRawUTF8()); + File juceBinaryDir(File::getSpecialLocation(File::currentExecutableFile).getParentDirectory()); + /* if (const char* const uisAlwaysOnTop = std::getenv("ENGINE_OPTION_FORCE_STEREO")) gStandalone.engine->setOption(CB::ENGINE_OPTION_FORCE_STEREO, (std::strcmp(uisAlwaysOnTop, "true") == 0) ? 1 : 0, nullptr); @@ -426,6 +423,7 @@ static void carla_engine_init_common() if (const char* const uisAlwaysOnTop = std::getenv("ENGINE_OPTION_PREFER_UI_BRIDGES")) gStandalone.engine->setOption(CB::ENGINE_OPTION_PREFER_UI_BRIDGES, (std::strcmp(uisAlwaysOnTop, "true") == 0) ? 1 : 0, nullptr); + */ if (const char* const uisAlwaysOnTop = std::getenv("ENGINE_OPTION_UIS_ALWAYS_ON_TOP")) gStandalone.engine->setOption(CB::ENGINE_OPTION_UIS_ALWAYS_ON_TOP, (std::strcmp(uisAlwaysOnTop, "true") == 0) ? 1 : 0, nullptr); @@ -465,9 +463,13 @@ static void carla_engine_init_common() if (const char* const binaryDir = std::getenv("ENGINE_OPTION_PATH_BINARIES")) gStandalone.engine->setOption(CB::ENGINE_OPTION_PATH_BINARIES, 0, binaryDir); + else + gStandalone.engine->setOption(CB::ENGINE_OPTION_PATH_BINARIES, 0, juceBinaryDir.getFullPathName().toRawUTF8()); if (const char* const resourceDir = std::getenv("ENGINE_OPTION_PATH_RESOURCES")) gStandalone.engine->setOption(CB::ENGINE_OPTION_PATH_RESOURCES, 0, resourceDir); + else + gStandalone.engine->setOption(CB::ENGINE_OPTION_PATH_RESOURCES, 0, juceBinaryDir.getChildFile("resources").getFullPathName().toRawUTF8()); if (const char* const preventBadBehaviour = std::getenv("ENGINE_OPTION_PREVENT_BAD_BEHAVIOUR")) gStandalone.engine->setOption(CB::ENGINE_OPTION_PREVENT_BAD_BEHAVIOUR, (std::strcmp(preventBadBehaviour, "true") == 0) ? 1 : 0, nullptr); @@ -568,8 +570,6 @@ bool carla_engine_init(const char* driverName, const char* clientName) return false; } - carla_engine_init_common(); - #ifdef BUILD_BRIDGE gStandalone.engine->setOption(CB::ENGINE_OPTION_PROCESS_MODE, CB::ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS, nullptr); gStandalone.engine->setOption(CB::ENGINE_OPTION_TRANSPORT_MODE, CB::ENGINE_TRANSPORT_MODE_JACK, nullptr); @@ -581,6 +581,8 @@ bool carla_engine_init(const char* driverName, const char* clientName) gStandalone.engine->setOption(CB::ENGINE_OPTION_TRANSPORT_MODE, static_cast(gStandalone.engineOptions.transportMode), nullptr); #endif + carla_engine_init_common(); + if (gStandalone.engine->init(clientName)) { #ifndef BUILD_BRIDGE diff --git a/source/backend/engine/CarlaEngineBridge.cpp b/source/backend/engine/CarlaEngineBridge.cpp index 38c708078..133159353 100644 --- a/source/backend/engine/CarlaEngineBridge.cpp +++ b/source/backend/engine/CarlaEngineBridge.cpp @@ -32,6 +32,7 @@ using juce::File; using juce::MemoryBlock; using juce::String; +using juce::Time; template bool jackbridge_shm_map2(char* shm, T*& value) noexcept @@ -374,7 +375,7 @@ public: fShmNonRtServerControl(), fIsOffline(false), fFirstIdle(true), - fLastPingCounter(-1), + fLastPingTime(-1), leakDetector_CarlaEngineBridge() { carla_stdout("CarlaEngineBridge::CarlaEngineBridge(\"%s\", \"%s\", \"%s\", \"%s\")", audioPoolBaseName, rtClientBaseName, nonRtClientBaseName, nonRtServerBaseName); @@ -492,6 +493,14 @@ public: if (shmRtClientDataSize != sizeof(BridgeRtClientData) || shmNonRtClientDataSize != sizeof(BridgeNonRtClientData) || shmNonRtServerDataSize != sizeof(BridgeNonRtServerData)) return false; + // tell backend we're live + { + const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex); + + fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerPong); + fShmNonRtServerControl.commitWrite(); + } + startThread(); return true; @@ -500,7 +509,7 @@ public: bool close() override { carla_debug("CarlaEnginePlugin::close()"); - fLastPingCounter = -1; + fLastPingTime = -1; CarlaEngine::close(); @@ -535,10 +544,13 @@ public: CarlaPlugin* const plugin(pData->plugins[0].plugin); CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,); + const bool wasFirstIdle(fFirstIdle); + if (fFirstIdle) { fFirstIdle = false; - fLastPingCounter = 0; + fLastPingTime = Time::currentTimeMillis(); + CARLA_SAFE_ASSERT(fLastPingTime > 0); char bufStr[STR_MAX+1]; uint32_t bufStrSize; @@ -753,6 +765,7 @@ public: fShmNonRtServerControl.waitIfDataIsReachingLimit(); carla_stdout("Carla Client Ready!"); + fLastPingTime = Time::currentTimeMillis(); } // send parameter outputs @@ -781,9 +794,9 @@ public: handleNonRtData(); } CARLA_SAFE_EXCEPTION("handleNonRtData"); - if (fLastPingCounter >= 0 && ++fLastPingCounter == 500) + if (fLastPingTime > 0 && Time::currentTimeMillis() > fLastPingTime + 5000 && ! wasFirstIdle) { - carla_stderr("Did not receive ping message from server for a long time, closing..."); + carla_stderr("Did not receive ping message from server for 5 secs, closing..."); callback(ENGINE_CALLBACK_QUIT, 0, 0, 0, 0.0f, nullptr); } } @@ -792,7 +805,7 @@ public: { CarlaEngine::callback(action, pluginId, value1, value2, value3, valueStr); - if (fLastPingCounter < 0) + if (fLastPingTime < 0) return; switch (action) @@ -872,8 +885,8 @@ public: } #endif - if (opcode != kPluginBridgeNonRtClientNull && fLastPingCounter > 0) - fLastPingCounter = 0; + if (opcode != kPluginBridgeNonRtClientNull && opcode != kPluginBridgeNonRtClientPingOnOff && fLastPingTime > 0) + fLastPingTime = Time::currentTimeMillis(); switch (opcode) { @@ -887,6 +900,12 @@ public: fShmNonRtServerControl.commitWrite(); } break; + case kPluginBridgeNonRtClientPingOnOff: { + const uint32_t onOff(fShmNonRtClientControl.readBool()); + + fLastPingTime = onOff ? Time::currentTimeMillis() : -1; + } break; + case kPluginBridgeNonRtClientActivate: if (plugin != nullptr && plugin->isEnabled()) plugin->setActive(true, false, false); @@ -1456,7 +1475,7 @@ private: bool fIsOffline; bool fFirstIdle; - int32_t fLastPingCounter; + int64_t fLastPingTime; CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineBridge) }; diff --git a/source/backend/plugin/CarlaPluginBridge.cpp b/source/backend/plugin/CarlaPluginBridge.cpp index fe1e27d9d..fe1541939 100644 --- a/source/backend/plugin/CarlaPluginBridge.cpp +++ b/source/backend/plugin/CarlaPluginBridge.cpp @@ -1179,8 +1179,13 @@ public: handleNonRtData(); } CARLA_SAFE_EXCEPTION("handleNonRtData"); } - else - carla_stderr2("TESTING: Bridge has closed!"); + else if (fInitiated) + { + fTimedOut = true; + fTimedError = true; + fInitiated = false; + pData->engine->callback(ENGINE_CALLBACK_PLUGIN_UNAVAILABLE, pData->id, 0, 0, 0.0f, "plugin bridge has been stopped or crashed"); + } CarlaPlugin::idle(); } diff --git a/source/utils/CarlaBridgeUtils.hpp b/source/utils/CarlaBridgeUtils.hpp index d632636d4..c86ecd97f 100644 --- a/source/utils/CarlaBridgeUtils.hpp +++ b/source/utils/CarlaBridgeUtils.hpp @@ -52,6 +52,7 @@ enum PluginBridgeRtClientOpcode { enum PluginBridgeNonRtClientOpcode { kPluginBridgeNonRtClientNull = 0, kPluginBridgeNonRtClientPing, + kPluginBridgeNonRtClientPingOnOff, // bool kPluginBridgeNonRtClientActivate, kPluginBridgeNonRtClientDeactivate, kPluginBridgeNonRtClientSetBufferSize, // uint @@ -197,6 +198,8 @@ const char* PluginBridgeNonRtClientOpcode2str(const PluginBridgeNonRtClientOpcod return "kPluginBridgeNonRtClientNull"; case kPluginBridgeNonRtClientPing: return "kPluginBridgeNonRtClientPing"; + case kPluginBridgeNonRtClientPingOnOff: + return "kPluginBridgeNonRtClientPingOnOff"; case kPluginBridgeNonRtClientActivate: return "kPluginBridgeNonRtClientActivate"; case kPluginBridgeNonRtClientDeactivate: