| @@ -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<int>(gStandalone.engineOptions.transportMode), nullptr); | |||
| #endif | |||
| carla_engine_init_common(); | |||
| if (gStandalone.engine->init(clientName)) | |||
| { | |||
| #ifndef BUILD_BRIDGE | |||
| @@ -32,6 +32,7 @@ | |||
| using juce::File; | |||
| using juce::MemoryBlock; | |||
| using juce::String; | |||
| using juce::Time; | |||
| template<typename T> | |||
| 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) | |||
| }; | |||
| @@ -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(); | |||
| } | |||
| @@ -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: | |||