| @@ -156,17 +156,10 @@ class CarlaJackClient : public Thread | |||||
| public: | public: | ||||
| JackClientState fState; | JackClientState fState; | ||||
| CarlaJackClient(const char* const audioPoolBaseName, const char* const rtClientBaseName, const char* const nonRtClientBaseName, const char* const nonRtServerBaseName) | |||||
| CarlaJackClient() | |||||
| : Thread("CarlaJackClient"), | : Thread("CarlaJackClient"), | ||||
| fState(), | fState(), | ||||
| fShmAudioPool(), | |||||
| fShmRtClientControl(), | |||||
| fShmNonRtClientControl(), | |||||
| fShmNonRtServerControl(), | |||||
| fBaseNameAudioPool(audioPoolBaseName), | |||||
| fBaseNameRtClientControl(rtClientBaseName), | |||||
| fBaseNameNonRtClientControl(nonRtClientBaseName), | |||||
| fBaseNameNonRtServerControl(nonRtServerBaseName), | |||||
| fIsValid(false), | |||||
| fIsOffline(false), | fIsOffline(false), | ||||
| fFirstIdle(true), | fFirstIdle(true), | ||||
| fLastPingTime(-1), | fLastPingTime(-1), | ||||
| @@ -174,118 +167,27 @@ public: | |||||
| fAudioOuts(0) | fAudioOuts(0) | ||||
| { | { | ||||
| carla_debug("CarlaJackClient::CarlaJackClient(\"%s\", \"%s\", \"%s\", \"%s\")", audioPoolBaseName, rtClientBaseName, nonRtClientBaseName, nonRtServerBaseName); | carla_debug("CarlaJackClient::CarlaJackClient(\"%s\", \"%s\", \"%s\", \"%s\")", audioPoolBaseName, rtClientBaseName, nonRtClientBaseName, nonRtServerBaseName); | ||||
| } | |||||
| ~CarlaJackClient() noexcept override | |||||
| { | |||||
| carla_debug("CarlaJackClient::~CarlaJackClient()"); | |||||
| clear(); | |||||
| } | |||||
| bool init(const char* const clientName) | |||||
| { | |||||
| carla_debug("CarlaJackClient::init(\"%s\")", clientName); | |||||
| if (! fShmAudioPool.attachClient(fBaseNameAudioPool)) | |||||
| { | |||||
| carla_stderr("Failed to attach to audio pool shared memory"); | |||||
| return false; | |||||
| } | |||||
| const char* const shmIds(std::getenv("CARLA_SHM_IDS")); | |||||
| CARLA_SAFE_ASSERT_RETURN(shmIds != nullptr && std::strlen(shmIds) == 6*4,); | |||||
| if (! fShmRtClientControl.attachClient(fBaseNameRtClientControl)) | |||||
| { | |||||
| clear(); | |||||
| carla_stderr("Failed to attach to rt client control shared memory"); | |||||
| return false; | |||||
| } | |||||
| std::memcpy(fBaseNameAudioPool, shmIds+6*0, 6); | |||||
| std::memcpy(fBaseNameRtClientControl, shmIds+6*1, 6); | |||||
| std::memcpy(fBaseNameNonRtClientControl, shmIds+6*2, 6); | |||||
| std::memcpy(fBaseNameNonRtServerControl, shmIds+6*3, 6); | |||||
| if (! fShmRtClientControl.mapData()) | |||||
| { | |||||
| clear(); | |||||
| carla_stderr("Failed to map rt client control shared memory"); | |||||
| return false; | |||||
| } | |||||
| if (! fShmNonRtClientControl.attachClient(fBaseNameNonRtClientControl)) | |||||
| { | |||||
| clear(); | |||||
| carla_stderr("Failed to attach to non-rt client control shared memory"); | |||||
| return false; | |||||
| } | |||||
| if (! fShmNonRtClientControl.mapData()) | |||||
| { | |||||
| clear(); | |||||
| carla_stderr("Failed to map non-rt control client shared memory"); | |||||
| return false; | |||||
| } | |||||
| if (! fShmNonRtServerControl.attachClient(fBaseNameNonRtServerControl)) | |||||
| { | |||||
| clear(); | |||||
| carla_stderr("Failed to attach to non-rt server control shared memory"); | |||||
| return false; | |||||
| } | |||||
| if (! fShmNonRtServerControl.mapData()) | |||||
| { | |||||
| clear(); | |||||
| carla_stderr("Failed to map non-rt control server shared memory"); | |||||
| return false; | |||||
| } | |||||
| PluginBridgeNonRtClientOpcode opcode; | |||||
| opcode = fShmNonRtClientControl.readOpcode(); | |||||
| CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtClientNull, opcode); | |||||
| const uint32_t shmRtClientDataSize = fShmNonRtClientControl.readUInt(); | |||||
| CARLA_SAFE_ASSERT_INT2(shmRtClientDataSize == sizeof(BridgeRtClientData), shmRtClientDataSize, sizeof(BridgeRtClientData)); | |||||
| const uint32_t shmNonRtClientDataSize = fShmNonRtClientControl.readUInt(); | |||||
| CARLA_SAFE_ASSERT_INT2(shmNonRtClientDataSize == sizeof(BridgeNonRtClientData), shmNonRtClientDataSize, sizeof(BridgeNonRtClientData)); | |||||
| const uint32_t shmNonRtServerDataSize = fShmNonRtClientControl.readUInt(); | |||||
| CARLA_SAFE_ASSERT_INT2(shmNonRtServerDataSize == sizeof(BridgeNonRtServerData), shmNonRtServerDataSize, sizeof(BridgeNonRtServerData)); | |||||
| if (shmRtClientDataSize != sizeof(BridgeRtClientData) || shmNonRtClientDataSize != sizeof(BridgeNonRtClientData) || shmNonRtServerDataSize != sizeof(BridgeNonRtServerData)) | |||||
| { | |||||
| carla_stderr2("CarlaJackClient: data size mismatch"); | |||||
| return false; | |||||
| } | |||||
| opcode = fShmNonRtClientControl.readOpcode(); | |||||
| CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtClientSetBufferSize, opcode); | |||||
| fState.bufferSize = fShmNonRtClientControl.readUInt(); | |||||
| opcode = fShmNonRtClientControl.readOpcode(); | |||||
| CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtClientSetSampleRate, opcode); | |||||
| fState.sampleRate = fShmNonRtClientControl.readDouble(); | |||||
| if (fState.bufferSize == 0 || carla_isZero(fState.sampleRate)) | |||||
| { | |||||
| carla_stderr2("CarlaJackClient: invalid empty state"); | |||||
| return false; | |||||
| } | |||||
| fState.name = strdup(clientName); | |||||
| // tell backend we're live | |||||
| { | |||||
| const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex); | |||||
| fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerPong); | |||||
| fShmNonRtServerControl.commitWrite(); | |||||
| } | |||||
| fBaseNameAudioPool[6] = '\0'; | |||||
| fBaseNameRtClientControl[6] = '\0'; | |||||
| fBaseNameNonRtClientControl[6] = '\0'; | |||||
| fBaseNameNonRtServerControl[6] = '\0'; | |||||
| startThread(10); | startThread(10); | ||||
| return true; | |||||
| } | } | ||||
| bool close() | |||||
| ~CarlaJackClient() noexcept override | |||||
| { | { | ||||
| carla_debug("CarlaJackClient::~CarlaJackClient()"); | |||||
| carla_debug("CarlaEnginePlugin::close()"); | carla_debug("CarlaEnginePlugin::close()"); | ||||
| fLastPingTime = -1; | fLastPingTime = -1; | ||||
| @@ -306,8 +208,16 @@ public: | |||||
| fState.audioIns.clear(); | fState.audioIns.clear(); | ||||
| fState.audioOuts.clear(); | fState.audioOuts.clear(); | ||||
| } | |||||
| bool initIfNeeded(const char* const clientName) | |||||
| { | |||||
| carla_debug("CarlaJackClient::initIfNeeded(\"%s\")", clientName); | |||||
| if (fState.name == nullptr) | |||||
| fState.name = strdup(clientName); | |||||
| return true; | |||||
| return fIsValid; | |||||
| } | } | ||||
| void clear() noexcept | void clear() noexcept | ||||
| @@ -318,6 +228,11 @@ public: | |||||
| fShmNonRtServerControl.clear(); | fShmNonRtServerControl.clear(); | ||||
| } | } | ||||
| bool isValid() const noexcept | |||||
| { | |||||
| return fIsValid; | |||||
| } | |||||
| void activate() | void activate() | ||||
| { | { | ||||
| const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex); | const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex); | ||||
| @@ -607,6 +522,98 @@ protected: | |||||
| { | { | ||||
| carla_stderr("CarlaJackClient run START"); | carla_stderr("CarlaJackClient run START"); | ||||
| if (! fShmAudioPool.attachClient(fBaseNameAudioPool)) | |||||
| { | |||||
| carla_stderr("Failed to attach to audio pool shared memory"); | |||||
| return; | |||||
| } | |||||
| if (! fShmRtClientControl.attachClient(fBaseNameRtClientControl)) | |||||
| { | |||||
| clear(); | |||||
| carla_stderr("Failed to attach to rt client control shared memory"); | |||||
| return; | |||||
| } | |||||
| if (! fShmRtClientControl.mapData()) | |||||
| { | |||||
| clear(); | |||||
| carla_stderr("Failed to map rt client control shared memory"); | |||||
| return; | |||||
| } | |||||
| if (! fShmNonRtClientControl.attachClient(fBaseNameNonRtClientControl)) | |||||
| { | |||||
| clear(); | |||||
| carla_stderr("Failed to attach to non-rt client control shared memory"); | |||||
| return; | |||||
| } | |||||
| if (! fShmNonRtClientControl.mapData()) | |||||
| { | |||||
| clear(); | |||||
| carla_stderr("Failed to map non-rt control client shared memory"); | |||||
| return; | |||||
| } | |||||
| if (! fShmNonRtServerControl.attachClient(fBaseNameNonRtServerControl)) | |||||
| { | |||||
| clear(); | |||||
| carla_stderr("Failed to attach to non-rt server control shared memory"); | |||||
| return; | |||||
| } | |||||
| if (! fShmNonRtServerControl.mapData()) | |||||
| { | |||||
| clear(); | |||||
| carla_stderr("Failed to map non-rt control server shared memory"); | |||||
| return; | |||||
| } | |||||
| PluginBridgeNonRtClientOpcode opcode; | |||||
| opcode = fShmNonRtClientControl.readOpcode(); | |||||
| CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtClientNull, opcode); | |||||
| const uint32_t shmRtClientDataSize = fShmNonRtClientControl.readUInt(); | |||||
| CARLA_SAFE_ASSERT_INT2(shmRtClientDataSize == sizeof(BridgeRtClientData), shmRtClientDataSize, sizeof(BridgeRtClientData)); | |||||
| const uint32_t shmNonRtClientDataSize = fShmNonRtClientControl.readUInt(); | |||||
| CARLA_SAFE_ASSERT_INT2(shmNonRtClientDataSize == sizeof(BridgeNonRtClientData), shmNonRtClientDataSize, sizeof(BridgeNonRtClientData)); | |||||
| const uint32_t shmNonRtServerDataSize = fShmNonRtClientControl.readUInt(); | |||||
| CARLA_SAFE_ASSERT_INT2(shmNonRtServerDataSize == sizeof(BridgeNonRtServerData), shmNonRtServerDataSize, sizeof(BridgeNonRtServerData)); | |||||
| if (shmRtClientDataSize != sizeof(BridgeRtClientData) || shmNonRtClientDataSize != sizeof(BridgeNonRtClientData) || shmNonRtServerDataSize != sizeof(BridgeNonRtServerData)) | |||||
| { | |||||
| carla_stderr2("CarlaJackClient: data size mismatch"); | |||||
| return; | |||||
| } | |||||
| opcode = fShmNonRtClientControl.readOpcode(); | |||||
| CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtClientSetBufferSize, opcode); | |||||
| fState.bufferSize = fShmNonRtClientControl.readUInt(); | |||||
| opcode = fShmNonRtClientControl.readOpcode(); | |||||
| CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtClientSetSampleRate, opcode); | |||||
| fState.sampleRate = fShmNonRtClientControl.readDouble(); | |||||
| if (fState.bufferSize == 0 || carla_isZero(fState.sampleRate)) | |||||
| { | |||||
| carla_stderr2("CarlaJackClient: invalid empty state"); | |||||
| return; | |||||
| } | |||||
| // tell backend we're live | |||||
| { | |||||
| const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex); | |||||
| fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerPong); | |||||
| fShmNonRtServerControl.commitWrite(); | |||||
| } | |||||
| fIsValid = true; | |||||
| #ifdef __SSE2_MATH__ | #ifdef __SSE2_MATH__ | ||||
| // Set FTZ and DAZ flags | // Set FTZ and DAZ flags | ||||
| _mm_setcsr(_mm_getcsr() | 0x8040); | _mm_setcsr(_mm_getcsr() | 0x8040); | ||||
| @@ -791,11 +798,12 @@ private: | |||||
| BridgeNonRtClientControl fShmNonRtClientControl; | BridgeNonRtClientControl fShmNonRtClientControl; | ||||
| BridgeNonRtServerControl fShmNonRtServerControl; | BridgeNonRtServerControl fShmNonRtServerControl; | ||||
| CarlaString fBaseNameAudioPool; | |||||
| CarlaString fBaseNameRtClientControl; | |||||
| CarlaString fBaseNameNonRtClientControl; | |||||
| CarlaString fBaseNameNonRtServerControl; | |||||
| char fBaseNameAudioPool[6+1]; | |||||
| char fBaseNameRtClientControl[6+1]; | |||||
| char fBaseNameNonRtClientControl[6+1]; | |||||
| char fBaseNameNonRtServerControl[6+1]; | |||||
| bool fIsValid; | |||||
| bool fIsOffline; | bool fIsOffline; | ||||
| bool fFirstIdle; | bool fFirstIdle; | ||||
| int64_t fLastPingTime; | int64_t fLastPingTime; | ||||
| @@ -814,57 +822,23 @@ CARLA_BACKEND_END_NAMESPACE | |||||
| CARLA_BACKEND_USE_NAMESPACE | CARLA_BACKEND_USE_NAMESPACE | ||||
| static CarlaJackClient* gClient = nullptr; | |||||
| static int gClientRefCount = 0; | |||||
| static CarlaJackClient gClient; | |||||
| static int gClientRefCount = 0; | |||||
| CARLA_EXPORT | CARLA_EXPORT | ||||
| jack_client_t* jack_client_open(const char* client_name, jack_options_t /*options*/, jack_status_t* status, ...) | jack_client_t* jack_client_open(const char* client_name, jack_options_t /*options*/, jack_status_t* status, ...) | ||||
| { | { | ||||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | ||||
| if (gClient != nullptr) | |||||
| { | |||||
| ++gClientRefCount; | |||||
| return (jack_client_t*)gClient; | |||||
| } | |||||
| const char* const shmIds(std::getenv("CARLA_SHM_IDS")); | |||||
| if (shmIds == nullptr || std::strlen(shmIds) != 6*4) | |||||
| { | |||||
| if (status != nullptr) | |||||
| *status = JackFailure; | |||||
| return nullptr; | |||||
| } | |||||
| char audioPoolBaseName[6+1]; | |||||
| char rtClientBaseName[6+1]; | |||||
| char nonRtClientBaseName[6+1]; | |||||
| char nonRtServerBaseName[6+1]; | |||||
| std::memcpy(audioPoolBaseName, shmIds+6*0, 6); | |||||
| std::memcpy(rtClientBaseName, shmIds+6*1, 6); | |||||
| std::memcpy(nonRtClientBaseName, shmIds+6*2, 6); | |||||
| std::memcpy(nonRtServerBaseName, shmIds+6*3, 6); | |||||
| audioPoolBaseName[6] = '\0'; | |||||
| rtClientBaseName[6] = '\0'; | |||||
| nonRtClientBaseName[6] = '\0'; | |||||
| nonRtServerBaseName[6] = '\0'; | |||||
| CarlaJackClient* const client = new CarlaJackClient(audioPoolBaseName, rtClientBaseName, | |||||
| nonRtClientBaseName, nonRtServerBaseName); | |||||
| if (! client->init(client_name)) | |||||
| if (! gClient.initIfNeeded(client_name)) | |||||
| { | { | ||||
| if (status != nullptr) | if (status != nullptr) | ||||
| *status = JackServerError; | *status = JackServerError; | ||||
| return nullptr; | return nullptr; | ||||
| } | } | ||||
| gClient = client; | |||||
| ++gClientRefCount; | ++gClientRefCount; | ||||
| return (jack_client_t*)client; | |||||
| return (jack_client_t*)&gClient; | |||||
| } | } | ||||
| CARLA_EXPORT | CARLA_EXPORT | ||||
| @@ -886,21 +860,7 @@ int jack_client_close(jack_client_t* client) | |||||
| if (jstate.activated) | if (jstate.activated) | ||||
| jclient->deactivate(); | jclient->deactivate(); | ||||
| if (--gClientRefCount == 0) | |||||
| { | |||||
| #if 0 | |||||
| static bool ignoreFirstClientClose = true; | |||||
| if (ignoreFirstClientClose) | |||||
| { | |||||
| ignoreFirstClientClose = false; | |||||
| return 0; | |||||
| } | |||||
| #endif | |||||
| jclient->close(); | |||||
| delete jclient; | |||||
| gClient = nullptr; | |||||
| } | |||||
| --gClientRefCount; | |||||
| return 0; | return 0; | ||||
| } | } | ||||