From d21c37ee64543a9671e9644b05c008e7e59c2c1b Mon Sep 17 00:00:00 2001 From: falkTX Date: Sun, 19 Aug 2018 15:57:33 +0200 Subject: [PATCH] Restart plugin bridges when re-activated, using last saved state --- source/backend/plugin/CarlaPluginBridge.cpp | 230 +++++++++++++------- 1 file changed, 156 insertions(+), 74 deletions(-) diff --git a/source/backend/plugin/CarlaPluginBridge.cpp b/source/backend/plugin/CarlaPluginBridge.cpp index e5b985e6e..aa5c08995 100644 --- a/source/backend/plugin/CarlaPluginBridge.cpp +++ b/source/backend/plugin/CarlaPluginBridge.cpp @@ -912,8 +912,7 @@ public: 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"); + handleProcessStopped(); } CarlaPlugin::idle(); @@ -1086,7 +1085,10 @@ public: void activate() noexcept override { - CARLA_SAFE_ASSERT_RETURN(! fTimedError,); + if (! fBridgeThread.isThreadRunning()) + { + CARLA_SAFE_ASSERT_RETURN(restartBridgeThread(),); + } { const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex); @@ -1832,8 +1834,17 @@ public: fInfo.aIns = fShmNonRtServerControl.readUInt(); fInfo.aOuts = fShmNonRtServerControl.readUInt(); - CARLA_SAFE_ASSERT(fInfo.aInNames == nullptr); - CARLA_SAFE_ASSERT(fInfo.aOutNames == nullptr); + if (fInfo.aInNames != nullptr) + { + delete[] fInfo.aInNames; + fInfo.aInNames = nullptr; + } + + if (fInfo.aOutNames != nullptr) + { + delete[] fInfo.aOutNames; + fInfo.aOutNames = nullptr; + } if (fInfo.aIns > 0) { @@ -2326,26 +2337,6 @@ public: return false; } - // --------------------------------------------------------------- - // initial values - - fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientVersion); - fShmNonRtClientControl.writeUInt(CARLA_PLUGIN_BRIDGE_API_VERSION); - - fShmNonRtClientControl.writeUInt(static_cast(sizeof(BridgeRtClientData))); - fShmNonRtClientControl.writeUInt(static_cast(sizeof(BridgeNonRtClientData))); - fShmNonRtClientControl.writeUInt(static_cast(sizeof(BridgeNonRtServerData))); - - fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientInitialSetup); - fShmNonRtClientControl.writeUInt(pData->engine->getBufferSize()); - fShmNonRtClientControl.writeDouble(pData->engine->getSampleRate()); - - fShmNonRtClientControl.commitWrite(); - - // testing dummy message - fShmRtClientControl.writeOpcode(kPluginBridgeRtClientNull); - fShmRtClientControl.commitWrite(); - #ifndef CARLA_OS_WIN // --------------------------------------------------------------- // set wine prefix @@ -2388,58 +2379,10 @@ public: fWinePrefix.toRawUTF8(), #endif bridgeBinary, label, shmIdsStr); - fBridgeThread.startThread(); - } - - // --------------------------------------------------------------- - // wait for bridge to start - - fInitiated = false; - fLastPongTime = Time::currentTimeMillis(); - CARLA_SAFE_ASSERT(fLastPongTime > 0); - - static bool sFirstInit = true; - - int64_t timeoutEnd = 5000; - - if (sFirstInit) - timeoutEnd *= 2; -#ifndef CARLA_OS_WIN - if (fBinaryType == BINARY_WIN32 || fBinaryType == BINARY_WIN64) - timeoutEnd *= 2; -#endif - sFirstInit = false; - - const bool needsEngineIdle = pData->engine->getType() != kEngineTypePlugin; - - for (; Time::currentTimeMillis() < fLastPongTime + timeoutEnd && fBridgeThread.isThreadRunning();) - { - pData->engine->callback(ENGINE_CALLBACK_IDLE, 0, 0, 0, 0.0f, nullptr); - - if (needsEngineIdle) - pData->engine->idle(); - - idle(); - - if (fInitiated) - break; - if (pData->engine->isAboutToClose()) - break; - - carla_msleep(20); } - fLastPongTime = -1; - - if (fInitError || ! fInitiated) - { - fBridgeThread.stopThread(6000); - - if (! fInitError) - pData->engine->setLastError("Timeout while waiting for a response from plugin-bridge\n(or the plugin crashed on initialization?)"); - + if (! restartBridgeThread()) return false; - } // --------------------------------------------------------------- // register client @@ -2586,6 +2529,24 @@ private: BridgeParamInfo* fParams; + void handleProcessStopped() noexcept + { + const bool wasActive = pData->active; + pData->active = false; + + if (wasActive) + { +#if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) + if (pData->engine->isOscControlRegistered()) + pData->engine->oscSend_control_set_parameter_value(pData->id, PARAMETER_ACTIVE, 0.0f); + pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, PARAMETER_ACTIVE, 0, 0.0f, nullptr); +#endif + } + + if (pData->hints & PLUGIN_HAS_CUSTOM_UI) + pData->engine->callback(ENGINE_CALLBACK_UI_STATE_CHANGED, pData->id, 0, 0, 0.0f, nullptr); + } + void resizeAudioPool(const uint32_t bufferSize) { fShmAudioPool.resize(bufferSize, fInfo.aIns+fInfo.aOuts, fInfo.cvIns+fInfo.cvOuts); @@ -2609,6 +2570,127 @@ private: carla_stderr2("waitForClient(%s) timed out", action); } + bool restartBridgeThread() + { + fInitiated = false; + fInitError = false; + fTimedError = false; + + // reset memory + fShmRtClientControl.data->procFlags = 0; + carla_zeroStruct(fShmRtClientControl.data->timeInfo); + carla_zeroBytes(fShmRtClientControl.data->midiOut, kBridgeRtClientDataMidiOutSize); + + fShmRtClientControl.clearData(); + fShmNonRtClientControl.clearData(); + fShmNonRtServerControl.clearData(); + + fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientVersion); + fShmNonRtClientControl.writeUInt(CARLA_PLUGIN_BRIDGE_API_VERSION); + + fShmNonRtClientControl.writeUInt(static_cast(sizeof(BridgeRtClientData))); + fShmNonRtClientControl.writeUInt(static_cast(sizeof(BridgeNonRtClientData))); + fShmNonRtClientControl.writeUInt(static_cast(sizeof(BridgeNonRtServerData))); + + fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientInitialSetup); + fShmNonRtClientControl.writeUInt(pData->engine->getBufferSize()); + fShmNonRtClientControl.writeDouble(pData->engine->getSampleRate()); + + fShmNonRtClientControl.commitWrite(); + + if (fShmAudioPool.dataSize != 0) + { + fShmRtClientControl.writeOpcode(kPluginBridgeRtClientSetAudioPool); + fShmRtClientControl.writeULong(static_cast(fShmAudioPool.dataSize)); + fShmRtClientControl.commitWrite(); + } + else + { + // testing dummy message + fShmRtClientControl.writeOpcode(kPluginBridgeRtClientNull); + fShmRtClientControl.commitWrite(); + } + + fBridgeThread.startThread(); + + fLastPongTime = Time::currentTimeMillis(); + CARLA_SAFE_ASSERT(fLastPongTime > 0); + + static bool sFirstInit = true; + + int64_t timeoutEnd = 5000; + + if (sFirstInit) + timeoutEnd *= 2; +#ifndef CARLA_OS_WIN + if (fBinaryType == BINARY_WIN32 || fBinaryType == BINARY_WIN64) + timeoutEnd *= 2; +#endif + sFirstInit = false; + + const bool needsEngineIdle = pData->engine->getType() != kEngineTypePlugin; + + for (; Time::currentTimeMillis() < fLastPongTime + timeoutEnd && fBridgeThread.isThreadRunning();) + { + pData->engine->callback(ENGINE_CALLBACK_IDLE, 0, 0, 0, 0.0f, nullptr); + + if (needsEngineIdle) + pData->engine->idle(); + + idle(); + + if (fInitiated) + break; + if (pData->engine->isAboutToClose()) + break; + + carla_msleep(20); + } + + fLastPongTime = -1; + + if (fInitError || ! fInitiated) + { + fBridgeThread.stopThread(6000); + + if (! fInitError) + pData->engine->setLastError("Timeout while waiting for a response from plugin-bridge\n" + "(or the plugin crashed on initialization?)"); + + return false; + } + + if (const size_t dataSize = fInfo.chunk.size()) + { +#ifdef CARLA_PROPER_CPP11_SUPPORT + void* data = fInfo.chunk.data(); +#else + void* data = &fInfo.chunk.front(); +#endif + CarlaString dataBase64(CarlaString::asBase64(data, dataSize)); + CARLA_SAFE_ASSERT_RETURN(dataBase64.length() > 0, true); + + String filePath(File::getSpecialLocation(File::tempDirectory).getFullPathName()); + + filePath += CARLA_OS_SEP_STR ".CarlaChunk_"; + filePath += fShmAudioPool.getFilenameSuffix(); + + if (File(filePath).replaceWithText(dataBase64.buffer())) + { + const uint32_t ulength(static_cast(filePath.length())); + + const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex); + + fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientSetChunkDataFile); + fShmNonRtClientControl.writeUInt(ulength); + fShmNonRtClientControl.writeCustomData(filePath.toRawUTF8(), ulength); + fShmNonRtClientControl.commitWrite(); + } + } + + return true; + } + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginBridge) };