| 
							- /*
 -  * Carla Bridge utils
 -  * Copyright (C) 2013-2020 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 "CarlaBridgeUtils.hpp"
 - #include "CarlaShmUtils.hpp"
 - 
 - // must be last
 - #include "jackbridge/JackBridge.hpp"
 - 
 - #if defined(CARLA_OS_WIN) && !defined(BUILDING_CARLA_FOR_WINE)
 - # define PLUGIN_BRIDGE_NAMEPREFIX_AUDIO_POOL    "Local\\carla-bridge_shm_ap_"
 - # define PLUGIN_BRIDGE_NAMEPREFIX_RT_CLIENT     "Local\\carla-bridge_shm_rtC_"
 - # define PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_CLIENT "Local\\carla-bridge_shm_nonrtC_"
 - # define PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_SERVER "Local\\carla-bridge_shm_nonrtS_"
 - #else
 - # define PLUGIN_BRIDGE_NAMEPREFIX_AUDIO_POOL    "/crlbrdg_shm_ap_"
 - # define PLUGIN_BRIDGE_NAMEPREFIX_RT_CLIENT     "/crlbrdg_shm_rtC_"
 - # define PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_CLIENT "/crlbrdg_shm_nonrtC_"
 - # define PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_SERVER "/crlbrdg_shm_nonrtS_"
 - #endif
 - 
 - // -------------------------------------------------------------------------------------------------------------------
 - 
 - template<typename T>
 - bool jackbridge_shm_map2(void* shm, T*& value) noexcept
 - {
 -     value = (T*)jackbridge_shm_map(shm, sizeof(T));
 -     return (value != nullptr);
 - }
 - 
 - // -------------------------------------------------------------------------------------------------------------------
 - 
 - BridgeAudioPool::BridgeAudioPool() noexcept
 -     : data(nullptr),
 -       dataSize(0),
 -       filename(),
 -       isServer(false)
 - {
 -     carla_zeroChars(shm, 64);
 -     jackbridge_shm_init(shm);
 - }
 - 
 - BridgeAudioPool::~BridgeAudioPool() noexcept
 - {
 -     // should be cleared by now
 -     CARLA_SAFE_ASSERT(data == nullptr);
 - 
 -     clear();
 - }
 - 
 - bool BridgeAudioPool::initializeServer() noexcept
 - {
 -     char tmpFileBase[64];
 -     std::sprintf(tmpFileBase, PLUGIN_BRIDGE_NAMEPREFIX_AUDIO_POOL "XXXXXX");
 - 
 -     const carla_shm_t shm2 = carla_shm_create_temp(tmpFileBase);
 -     CARLA_SAFE_ASSERT_RETURN(carla_is_shm_valid(shm2), false);
 - 
 -     void* const shmptr = shm;
 -     carla_shm_t& shm1  = *(carla_shm_t*)shmptr;
 -     carla_copyStruct(shm1, shm2);
 - 
 -     filename = tmpFileBase;
 -     isServer = true;
 -     return true;
 - }
 - 
 - bool BridgeAudioPool::attachClient(const char* const basename) noexcept
 - {
 -     CARLA_SAFE_ASSERT_RETURN(basename != nullptr && basename[0] != '\0', false);
 - 
 -     // must be invalid right now
 -     CARLA_SAFE_ASSERT_RETURN(! jackbridge_shm_is_valid(shm), false);
 - 
 -     filename  = PLUGIN_BRIDGE_NAMEPREFIX_AUDIO_POOL;
 -     filename += basename;
 - 
 -     jackbridge_shm_attach(shm, filename);
 - 
 -     return jackbridge_shm_is_valid(shm);
 - }
 - 
 - void BridgeAudioPool::clear() noexcept
 - {
 -     filename.clear();
 - 
 -     if (! jackbridge_shm_is_valid(shm))
 -     {
 -         CARLA_SAFE_ASSERT(data == nullptr);
 -         return;
 -     }
 - 
 -     if (data != nullptr)
 -     {
 -         if (isServer)
 -             jackbridge_shm_unmap(shm, data);
 -         data = nullptr;
 -     }
 - 
 -     dataSize = 0;
 -     jackbridge_shm_close(shm);
 -     jackbridge_shm_init(shm);
 - }
 - 
 - void BridgeAudioPool::resize(const uint32_t bufferSize, const uint32_t audioPortCount, const uint32_t cvPortCount) noexcept
 - {
 -     CARLA_SAFE_ASSERT_RETURN(jackbridge_shm_is_valid(shm),);
 -     CARLA_SAFE_ASSERT_RETURN(isServer,);
 - 
 -     if (data != nullptr)
 -         jackbridge_shm_unmap(shm, data);
 - 
 -     dataSize = (audioPortCount+cvPortCount)*bufferSize*sizeof(float);
 - 
 -     if (dataSize == 0)
 -         dataSize = sizeof(float);
 - 
 -     data = (float*)jackbridge_shm_map(shm, dataSize);
 -     CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
 - 
 -     std::memset(data, 0, dataSize);
 - }
 - 
 - const char* BridgeAudioPool::getFilenameSuffix() const noexcept
 - {
 -     CARLA_SAFE_ASSERT_RETURN(filename.isNotEmpty(), nullptr);
 - 
 -     const std::size_t prefixLength(std::strlen(PLUGIN_BRIDGE_NAMEPREFIX_AUDIO_POOL));
 -     CARLA_SAFE_ASSERT_RETURN(filename.length() > prefixLength, nullptr);
 - 
 -     return filename.buffer() + prefixLength;
 - }
 - 
 - // -------------------------------------------------------------------------------------------------------------------
 - 
 - BridgeRtClientControl::BridgeRtClientControl() noexcept
 -     : data(nullptr),
 -       filename(),
 -       needsSemDestroy(false),
 -       isServer(false)
 - {
 -     carla_zeroChars(shm, 64);
 -     jackbridge_shm_init(shm);
 - }
 - 
 - BridgeRtClientControl::~BridgeRtClientControl() noexcept
 - {
 -     // should be cleared by now
 -     CARLA_SAFE_ASSERT(data == nullptr);
 - 
 -     clear();
 - }
 - 
 - bool BridgeRtClientControl::initializeServer() noexcept
 - {
 -     char tmpFileBase[64];
 -     std::sprintf(tmpFileBase, PLUGIN_BRIDGE_NAMEPREFIX_RT_CLIENT "XXXXXX");
 - 
 -     const carla_shm_t shm2 = carla_shm_create_temp(tmpFileBase);
 -     CARLA_SAFE_ASSERT_RETURN(carla_is_shm_valid(shm2), false);
 - 
 -     void* const shmptr = shm;
 -     carla_shm_t& shm1  = *(carla_shm_t*)shmptr;
 -     carla_copyStruct(shm1, shm2);
 - 
 -     filename = tmpFileBase;
 -     isServer = true;
 - 
 -     if (! mapData())
 -     {
 -         jackbridge_shm_close(shm);
 -         jackbridge_shm_init(shm);
 -         return false;
 -     }
 - 
 -     CARLA_SAFE_ASSERT(data != nullptr);
 - 
 -     if (! jackbridge_sem_init(&data->sem.server))
 -     {
 -         unmapData();
 -         jackbridge_shm_close(shm);
 -         jackbridge_shm_init(shm);
 -         return false;
 -     }
 - 
 -     if (! jackbridge_sem_init(&data->sem.client))
 -     {
 -         jackbridge_sem_destroy(&data->sem.server);
 -         unmapData();
 -         jackbridge_shm_close(shm);
 -         jackbridge_shm_init(shm);
 -         return false;
 -     }
 - 
 -     needsSemDestroy = true;
 -     return true;
 - }
 - 
 - bool BridgeRtClientControl::attachClient(const char* const basename) noexcept
 - {
 -     CARLA_SAFE_ASSERT_RETURN(basename != nullptr && basename[0] != '\0', false);
 - 
 -     // must be invalid right now
 -     CARLA_SAFE_ASSERT_RETURN(! jackbridge_shm_is_valid(shm), false);
 - 
 -     filename  = PLUGIN_BRIDGE_NAMEPREFIX_RT_CLIENT;
 -     filename += basename;
 - 
 -     jackbridge_shm_attach(shm, filename);
 - 
 -     return jackbridge_shm_is_valid(shm);
 - }
 - 
 - void BridgeRtClientControl::clear() noexcept
 - {
 -     filename.clear();
 - 
 -     if (needsSemDestroy)
 -     {
 -         jackbridge_sem_destroy(&data->sem.client);
 -         jackbridge_sem_destroy(&data->sem.server);
 -         needsSemDestroy = false;
 -     }
 - 
 -     if (data != nullptr)
 -         unmapData();
 - 
 -     if (! jackbridge_shm_is_valid(shm))
 -         return;
 - 
 -     jackbridge_shm_close(shm);
 -     jackbridge_shm_init(shm);
 - }
 - 
 - bool BridgeRtClientControl::mapData() noexcept
 - {
 -     CARLA_SAFE_ASSERT(data == nullptr);
 - 
 -     if (! jackbridge_shm_map2<BridgeRtClientData>(shm, data))
 -         return false;
 - 
 -     if (isServer)
 -     {
 -         std::memset(data, 0, sizeof(BridgeRtClientData));
 -         setRingBuffer(&data->ringBuffer, true);
 -     }
 -     else
 -     {
 -         CARLA_SAFE_ASSERT(data->midiOut[0] == 0);
 -         setRingBuffer(&data->ringBuffer, false);
 - 
 -         CARLA_SAFE_ASSERT_RETURN(jackbridge_sem_connect(&data->sem.server), false);
 -         CARLA_SAFE_ASSERT_RETURN(jackbridge_sem_connect(&data->sem.client), false);
 -     }
 - 
 -     return true;
 - }
 - 
 - void BridgeRtClientControl::unmapData() noexcept
 - {
 -     if (isServer)
 -     {
 -         CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
 -         jackbridge_shm_unmap(shm, data);
 -     }
 - 
 -     data = nullptr;
 -     setRingBuffer(nullptr, false);
 - }
 - 
 - bool BridgeRtClientControl::waitForClient(const uint msecs) noexcept
 - {
 -     CARLA_SAFE_ASSERT_RETURN(msecs > 0, false);
 -     CARLA_SAFE_ASSERT_RETURN(data != nullptr, false);
 -     CARLA_SAFE_ASSERT_RETURN(isServer, false);
 - 
 -     jackbridge_sem_post(&data->sem.server, true);
 - 
 -     return jackbridge_sem_timedwait(&data->sem.client, msecs, true);
 - }
 - 
 - bool BridgeRtClientControl::writeOpcode(const PluginBridgeRtClientOpcode opcode) noexcept
 - {
 -     return writeUInt(static_cast<uint32_t>(opcode));
 - }
 - 
 - PluginBridgeRtClientOpcode BridgeRtClientControl::readOpcode() noexcept
 - {
 -     CARLA_SAFE_ASSERT_RETURN(! isServer, kPluginBridgeRtClientNull);
 - 
 -     return static_cast<PluginBridgeRtClientOpcode>(readUInt());
 - }
 - 
 - BridgeRtClientControl::WaitHelper::WaitHelper(BridgeRtClientControl& c) noexcept
 -     : data(c.data),
 -       ok(jackbridge_sem_timedwait(&data->sem.server, 5000, false)) {}
 - 
 - BridgeRtClientControl::WaitHelper::~WaitHelper() noexcept
 - {
 -     if (ok)
 -         jackbridge_sem_post(&data->sem.client, false);
 - }
 - 
 - // -------------------------------------------------------------------------------------------------------------------
 - 
 - BridgeNonRtClientControl::BridgeNonRtClientControl() noexcept
 -     : data(nullptr),
 -       filename(),
 -       mutex(),
 -       isServer(false)
 - {
 -     carla_zeroChars(shm, 64);
 -     jackbridge_shm_init(shm);
 - }
 - 
 - BridgeNonRtClientControl::~BridgeNonRtClientControl() noexcept
 - {
 -     // should be cleared by now
 -     CARLA_SAFE_ASSERT(data == nullptr);
 - 
 -     clear();
 - }
 - 
 - bool BridgeNonRtClientControl::initializeServer() noexcept
 - {
 -     char tmpFileBase[64];
 -     std::sprintf(tmpFileBase, PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_CLIENT "XXXXXX");
 - 
 -     const carla_shm_t shm2 = carla_shm_create_temp(tmpFileBase);
 -     CARLA_SAFE_ASSERT_RETURN(carla_is_shm_valid(shm2), false);
 - 
 -     void* const shmptr = shm;
 -     carla_shm_t& shm1  = *(carla_shm_t*)shmptr;
 -     carla_copyStruct(shm1, shm2);
 - 
 -     filename = tmpFileBase;
 -     isServer = true;
 - 
 -     if (! mapData())
 -     {
 -         jackbridge_shm_close(shm);
 -         jackbridge_shm_init(shm);
 -         return false;
 -     }
 - 
 -     CARLA_SAFE_ASSERT(data != nullptr);
 -     return true;
 - }
 - 
 - bool BridgeNonRtClientControl::attachClient(const char* const basename) noexcept
 - {
 -     CARLA_SAFE_ASSERT_RETURN(basename != nullptr && basename[0] != '\0', false);
 - 
 -     // must be invalid right now
 -     CARLA_SAFE_ASSERT_RETURN(! jackbridge_shm_is_valid(shm), false);
 - 
 -     filename  = PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_CLIENT;
 -     filename += basename;
 - 
 -     jackbridge_shm_attach(shm, filename);
 - 
 -     return jackbridge_shm_is_valid(shm);
 - }
 - 
 - void BridgeNonRtClientControl::clear() noexcept
 - {
 -     filename.clear();
 - 
 -     if (data != nullptr)
 -         unmapData();
 - 
 -     if (! jackbridge_shm_is_valid(shm))
 -     {
 -         if (! isServer) {
 -             CARLA_SAFE_ASSERT(data == nullptr);
 -         }
 -         return;
 -     }
 - 
 -     jackbridge_shm_close(shm);
 -     jackbridge_shm_init(shm);
 - }
 - 
 - bool BridgeNonRtClientControl::mapData() noexcept
 - {
 -     CARLA_SAFE_ASSERT(data == nullptr);
 - 
 -     if (jackbridge_shm_map2<BridgeNonRtClientData>(shm, data))
 -     {
 -         setRingBuffer(&data->ringBuffer, isServer);
 -         return true;
 -     }
 - 
 -     return false;
 - }
 - 
 - void BridgeNonRtClientControl::unmapData() noexcept
 - {
 -     if (isServer)
 -     {
 -         CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
 -         jackbridge_shm_unmap(shm, data);
 -     }
 - 
 -     data = nullptr;
 -     setRingBuffer(nullptr, false);
 - }
 - 
 - void BridgeNonRtClientControl::waitIfDataIsReachingLimit() noexcept
 - {
 -     CARLA_SAFE_ASSERT_RETURN(isServer,);
 - 
 -     if (getAvailableDataSize() < BigStackBuffer::size/4)
 -         return;
 - 
 -     for (int i=50; --i >= 0;)
 -     {
 -         if (getAvailableDataSize() >= BigStackBuffer::size*3/4)
 -         {
 -             writeOpcode(kPluginBridgeNonRtClientPing);
 -             commitWrite();
 -             return;
 -         }
 -         carla_msleep(20);
 -     }
 - 
 -     carla_stderr("Server waitIfDataIsReachingLimit() reached and failed");
 - }
 - 
 - bool BridgeNonRtClientControl::writeOpcode(const PluginBridgeNonRtClientOpcode opcode) noexcept
 - {
 -     CARLA_SAFE_ASSERT_RETURN(isServer, false);
 - 
 -     return writeUInt(static_cast<uint32_t>(opcode));
 - }
 - 
 - PluginBridgeNonRtClientOpcode BridgeNonRtClientControl::readOpcode() noexcept
 - {
 -     CARLA_SAFE_ASSERT_RETURN(! isServer, kPluginBridgeNonRtClientNull);
 - 
 -     return static_cast<PluginBridgeNonRtClientOpcode>(readUInt());
 - }
 - 
 - // -------------------------------------------------------------------------------------------------------------------
 - 
 - BridgeNonRtServerControl::BridgeNonRtServerControl() noexcept
 -     : data(nullptr),
 -       filename(),
 -       mutex(),
 -       isServer(false)
 - {
 -     carla_zeroChars(shm, 64);
 -     jackbridge_shm_init(shm);
 - }
 - 
 - BridgeNonRtServerControl::~BridgeNonRtServerControl() noexcept
 - {
 -     // should be cleared by now
 -     CARLA_SAFE_ASSERT(data == nullptr);
 - 
 -     clear();
 - }
 - 
 - bool BridgeNonRtServerControl::initializeServer() noexcept
 - {
 -     char tmpFileBase[64];
 -     std::sprintf(tmpFileBase, PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_SERVER "XXXXXX");
 - 
 -     const carla_shm_t shm2 = carla_shm_create_temp(tmpFileBase);
 -     CARLA_SAFE_ASSERT_RETURN(carla_is_shm_valid(shm2), false);
 - 
 -     void* const shmptr = shm;
 -     carla_shm_t& shm1  = *(carla_shm_t*)shmptr;
 -     carla_copyStruct(shm1, shm2);
 - 
 -     filename = tmpFileBase;
 -     isServer = true;
 - 
 -     if (! mapData())
 -     {
 -         jackbridge_shm_close(shm);
 -         jackbridge_shm_init(shm);
 -         return false;
 -     }
 - 
 -     CARLA_SAFE_ASSERT(data != nullptr);
 -     return true;
 - }
 - 
 - bool BridgeNonRtServerControl::attachClient(const char* const basename) noexcept
 - {
 -     CARLA_SAFE_ASSERT_RETURN(basename != nullptr && basename[0] != '\0', false);
 - 
 -     // must be invalid right now
 -     CARLA_SAFE_ASSERT_RETURN(! jackbridge_shm_is_valid(shm), false);
 - 
 -     filename  = PLUGIN_BRIDGE_NAMEPREFIX_NON_RT_SERVER;
 -     filename += basename;
 - 
 -     jackbridge_shm_attach(shm, filename);
 - 
 -     return jackbridge_shm_is_valid(shm);
 - }
 - 
 - void BridgeNonRtServerControl::clear() noexcept
 - {
 -     filename.clear();
 - 
 -     if (data != nullptr)
 -         unmapData();
 - 
 -     if (! jackbridge_shm_is_valid(shm))
 -     {
 -         CARLA_SAFE_ASSERT(data == nullptr);
 -         return;
 -     }
 - 
 -     jackbridge_shm_close(shm);
 -     jackbridge_shm_init(shm);
 - }
 - 
 - bool BridgeNonRtServerControl::mapData() noexcept
 - {
 -     CARLA_SAFE_ASSERT(data == nullptr);
 - 
 -     if (jackbridge_shm_map2<BridgeNonRtServerData>(shm, data))
 -     {
 -         setRingBuffer(&data->ringBuffer, isServer);
 -         return true;
 -     }
 - 
 -     return false;
 - }
 - 
 - void BridgeNonRtServerControl::unmapData() noexcept
 - {
 -     if (isServer)
 -     {
 -         CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
 -         jackbridge_shm_unmap(shm, data);
 -     }
 - 
 -     data = nullptr;
 -     setRingBuffer(nullptr, false);
 - }
 - 
 - PluginBridgeNonRtServerOpcode BridgeNonRtServerControl::readOpcode() noexcept
 - {
 -     CARLA_SAFE_ASSERT_RETURN(isServer, kPluginBridgeNonRtServerNull);
 - 
 -     return static_cast<PluginBridgeNonRtServerOpcode>(readUInt());
 - }
 - 
 - void BridgeNonRtServerControl::waitIfDataIsReachingLimit() noexcept
 - {
 -     CARLA_SAFE_ASSERT_RETURN(! isServer,);
 - 
 -     if (getAvailableDataSize() < HugeStackBuffer::size/4)
 -         return;
 - 
 -     for (int i=50; --i >= 0;)
 -     {
 -         if (getAvailableDataSize() >= HugeStackBuffer::size*3/4)
 -         {
 -             writeOpcode(kPluginBridgeNonRtServerPong);
 -             commitWrite();
 -             return;
 -         }
 -         carla_msleep(20);
 -     }
 - 
 -     carla_stderr("Client waitIfDataIsReachingLimit() reached and failed");
 - }
 - 
 - bool BridgeNonRtServerControl::writeOpcode(const PluginBridgeNonRtServerOpcode opcode) noexcept
 - {
 -     CARLA_SAFE_ASSERT_RETURN(! isServer, false);
 - 
 -     return writeUInt(static_cast<uint32_t>(opcode));
 - }
 - 
 - // -------------------------------------------------------------------------------------------------------------------
 
 
  |