| @@ -28,71 +28,119 @@ CARLA_BACKEND_START_NAMESPACE | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| CarlaJackClient::CarlaJackClient() | |||
| : Thread("CarlaJackClient"), | |||
| fState(), | |||
| fIsValid(false), | |||
| fIsOffline(false), | |||
| fFirstIdle(true), | |||
| fLastPingTime(-1), | |||
| fAudioIns(0), | |||
| fAudioOuts(0) | |||
| class CarlaJackAppClient : public juce::Thread | |||
| { | |||
| carla_debug("CarlaJackClient::CarlaJackClient(\"%s\", \"%s\", \"%s\", \"%s\")", audioPoolBaseName, rtClientBaseName, nonRtClientBaseName, nonRtServerBaseName); | |||
| public: | |||
| JackServerState fServer; | |||
| LinkedList<JackClientState*> fClients; | |||
| CarlaJackAppClient() | |||
| : Thread("CarlaJackAppClient"), | |||
| fServer(), | |||
| fIsValid(false), | |||
| fIsOffline(false), | |||
| fLastPingTime(-1), | |||
| fAudioIns(0), | |||
| fAudioOuts(0) | |||
| { | |||
| carla_debug("CarlaJackAppClient::CarlaJackAppClient()"); | |||
| const char* const shmIds(std::getenv("CARLA_SHM_IDS")); | |||
| CARLA_SAFE_ASSERT_RETURN(shmIds != nullptr && std::strlen(shmIds) == 6*4,); | |||
| const char* const shmIds(std::getenv("CARLA_SHM_IDS")); | |||
| CARLA_SAFE_ASSERT_RETURN(shmIds != nullptr && std::strlen(shmIds) == 6*4,); | |||
| 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); | |||
| 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); | |||
| fBaseNameAudioPool[6] = '\0'; | |||
| fBaseNameRtClientControl[6] = '\0'; | |||
| fBaseNameNonRtClientControl[6] = '\0'; | |||
| fBaseNameNonRtServerControl[6] = '\0'; | |||
| fBaseNameAudioPool[6] = '\0'; | |||
| fBaseNameRtClientControl[6] = '\0'; | |||
| fBaseNameNonRtClientControl[6] = '\0'; | |||
| fBaseNameNonRtServerControl[6] = '\0'; | |||
| startThread(10); | |||
| } | |||
| startThread(10); | |||
| } | |||
| CarlaJackClient::~CarlaJackClient() noexcept | |||
| { | |||
| carla_debug("CarlaJackClient::~CarlaJackClient()"); | |||
| ~CarlaJackAppClient() noexcept override | |||
| { | |||
| carla_debug("CarlaJackAppClient::~CarlaJackAppClient()"); | |||
| carla_debug("CarlaEnginePlugin::close()"); | |||
| fLastPingTime = -1; | |||
| stopThread(5000); | |||
| clear(); | |||
| const CarlaMutexLocker cms(fRealtimeThreadMutex); | |||
| for (LinkedList<JackClientState*>::Itenerator it = fClients.begin2(); it.valid(); it.next()) | |||
| { | |||
| JackClientState* const jclient(it.getValue(nullptr)); | |||
| CARLA_SAFE_ASSERT_CONTINUE(jclient != nullptr); | |||
| delete jclient; | |||
| } | |||
| fClients.clear(); | |||
| } | |||
| carla_debug("CarlaEnginePlugin::close()"); | |||
| fLastPingTime = -1; | |||
| void clear() noexcept; | |||
| bool isValid() const noexcept; | |||
| stopThread(5000); | |||
| clear(); | |||
| void activate(); | |||
| void handleNonRtData(); | |||
| for (LinkedList<JackPortState*>::Itenerator it = fState.audioIns.begin2(); it.valid(); it.next()) | |||
| JackClientState* addClient(const char* const name) | |||
| { | |||
| if (JackPortState* const jport = it.getValue(nullptr)) | |||
| delete jport; | |||
| JackClientState* const jclient(new JackClientState(fServer, name)); | |||
| const CarlaMutexLocker cms(fRealtimeThreadMutex); | |||
| fClients.append(jclient); | |||
| return jclient; | |||
| } | |||
| for (LinkedList<JackPortState*>::Itenerator it = fState.audioOuts.begin2(); it.valid(); it.next()) | |||
| bool removeClient(JackClientState* const jclient) | |||
| { | |||
| if (JackPortState* const jport = it.getValue(nullptr)) | |||
| delete jport; | |||
| { | |||
| const CarlaMutexLocker cms(fRealtimeThreadMutex); | |||
| CARLA_SAFE_ASSERT_RETURN(fClients.removeOne(jclient), false); | |||
| } | |||
| delete jclient; | |||
| return true; | |||
| } | |||
| fState.audioIns.clear(); | |||
| fState.audioOuts.clear(); | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| bool CarlaJackClient::initIfNeeded(const char* const clientName) | |||
| { | |||
| carla_debug("CarlaJackClient::initIfNeeded(\"%s\")", clientName); | |||
| protected: | |||
| void run() override; | |||
| if (fState.name == nullptr) | |||
| fState.name = strdup(clientName); | |||
| private: | |||
| BridgeAudioPool fShmAudioPool; | |||
| BridgeRtClientControl fShmRtClientControl; | |||
| BridgeNonRtClientControl fShmNonRtClientControl; | |||
| BridgeNonRtServerControl fShmNonRtServerControl; | |||
| return fIsValid; | |||
| } | |||
| char fBaseNameAudioPool[6+1]; | |||
| char fBaseNameRtClientControl[6+1]; | |||
| char fBaseNameNonRtClientControl[6+1]; | |||
| char fBaseNameNonRtServerControl[6+1]; | |||
| bool fIsValid; | |||
| bool fIsOffline; | |||
| int64_t fLastPingTime; | |||
| uint32_t fAudioIns; | |||
| uint32_t fAudioOuts; | |||
| CarlaMutex fRealtimeThreadMutex; | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaJackAppClient) | |||
| }; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| void CarlaJackClient::clear() noexcept | |||
| void CarlaJackAppClient::clear() noexcept | |||
| { | |||
| fShmAudioPool.clear(); | |||
| fShmRtClientControl.clear(); | |||
| @@ -100,36 +148,19 @@ void CarlaJackClient::clear() noexcept | |||
| fShmNonRtServerControl.clear(); | |||
| } | |||
| bool CarlaJackClient::isValid() const noexcept | |||
| bool CarlaJackAppClient::isValid() const noexcept | |||
| { | |||
| return fIsValid; | |||
| } | |||
| void CarlaJackClient::activate() | |||
| void CarlaJackAppClient::activate() | |||
| { | |||
| const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex); | |||
| const bool wasFirstIdle(fFirstIdle); | |||
| if (wasFirstIdle) | |||
| { | |||
| fFirstIdle = false; | |||
| fLastPingTime = Time::currentTimeMillis(); | |||
| CARLA_SAFE_ASSERT(fLastPingTime > 0); | |||
| if (fState.audioIns.count() == 0 && fState.audioOuts.count() == 0) | |||
| { | |||
| carla_stderr("Create 2 ins, 2 outs prematurely for the client"); | |||
| fState.audioIns.append(new JackPortState(fState.name, "in_1", 0, JackPortIsOutput, false)); | |||
| fState.audioIns.append(new JackPortState(fState.name, "in_2", 1, JackPortIsOutput, false)); | |||
| fState.fakeIns = 2; | |||
| fState.audioOuts.append(new JackPortState(fState.name, "out_1", 0, JackPortIsInput, false)); | |||
| fState.audioOuts.append(new JackPortState(fState.name, "out_2", 1, JackPortIsInput, false)); | |||
| fState.fakeOuts = 2; | |||
| fState.prematurelyActivated = true; | |||
| } | |||
| char bufStr[STR_MAX+1]; | |||
| uint32_t bufStrSize; | |||
| @@ -151,7 +182,7 @@ void CarlaJackClient::activate() | |||
| fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerPluginInfo2); | |||
| carla_zeroChars(bufStr, STR_MAX); | |||
| std::strncpy(bufStr, fState.name, 64); | |||
| std::strncpy(bufStr, "Jack App", 64); | |||
| bufStrSize = carla_fixedValue(1U, 64U, static_cast<uint32_t>(std::strlen(bufStr))); | |||
| fShmNonRtServerControl.writeUInt(bufStrSize); | |||
| fShmNonRtServerControl.writeCustomData(bufStr, bufStrSize); | |||
| @@ -173,8 +204,8 @@ void CarlaJackClient::activate() | |||
| // kPluginBridgeNonRtServerAudioCount | |||
| { | |||
| const uint32_t aIns = fState.audioIns.count(); | |||
| const uint32_t aOuts = fState.audioOuts.count(); | |||
| const uint32_t aIns = 2; //fClient.audioIns.count(); | |||
| const uint32_t aOuts = 2; //fClient.audioOuts.count(); | |||
| // uint/ins, uint/outs | |||
| fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerAudioCount); | |||
| @@ -182,42 +213,47 @@ void CarlaJackClient::activate() | |||
| fShmNonRtServerControl.writeUInt(aOuts); | |||
| fShmNonRtServerControl.commitWrite(); | |||
| // kPluginBridgeNonRtServerPortName | |||
| for (uint32_t i=0; i<aIns; ++i) | |||
| { | |||
| const JackPortState* const jport(fState.audioIns.getAt(i, nullptr)); | |||
| CARLA_SAFE_ASSERT_CONTINUE(jport != nullptr); | |||
| //const JackPortState* const jport(fClient.audioIns.getAt(i, nullptr)); | |||
| //CARLA_SAFE_ASSERT_CONTINUE(jport != nullptr); | |||
| const char* const portName(jport->name); | |||
| CARLA_SAFE_ASSERT_CONTINUE(portName != nullptr && portName[0] != '\0'); | |||
| //const char* const portName(jport->name); | |||
| //CARLA_SAFE_ASSERT_CONTINUE(portName != nullptr && portName[0] != '\0'); | |||
| std::snprintf(bufStr, 64, "in_%i", i+1); | |||
| // byte/type, uint/index, uint/size, str[] (name) | |||
| fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerPortName); | |||
| fShmNonRtServerControl.writeByte(kPluginBridgePortAudioInput); | |||
| fShmNonRtServerControl.writeUInt(i); | |||
| bufStrSize = static_cast<uint32_t>(std::strlen(portName)); | |||
| bufStrSize = static_cast<uint32_t>(std::strlen(bufStr)); | |||
| fShmNonRtServerControl.writeUInt(bufStrSize); | |||
| fShmNonRtServerControl.writeCustomData(portName, bufStrSize); | |||
| fShmNonRtServerControl.writeCustomData(bufStr, bufStrSize); | |||
| } | |||
| // kPluginBridgeNonRtServerPortName | |||
| for (uint32_t i=0; i<aOuts; ++i) | |||
| { | |||
| const JackPortState* const jport(fState.audioOuts.getAt(i, nullptr)); | |||
| CARLA_SAFE_ASSERT_CONTINUE(jport != nullptr); | |||
| //const JackPortState* const jport(fClient.audioOuts.getAt(i, nullptr)); | |||
| //CARLA_SAFE_ASSERT_CONTINUE(jport != nullptr); | |||
| //const char* const portName(jport->name); | |||
| //CARLA_SAFE_ASSERT_CONTINUE(portName != nullptr && portName[0] != '\0'); | |||
| const char* const portName(jport->name); | |||
| CARLA_SAFE_ASSERT_CONTINUE(portName != nullptr && portName[0] != '\0'); | |||
| std::snprintf(bufStr, 64, "out_%i", i+1); | |||
| // byte/type, uint/index, uint/size, str[] (name) | |||
| fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerPortName); | |||
| fShmNonRtServerControl.writeByte(kPluginBridgePortAudioOutput); | |||
| fShmNonRtServerControl.writeUInt(i); | |||
| bufStrSize = static_cast<uint32_t>(std::strlen(portName)); | |||
| bufStrSize = static_cast<uint32_t>(std::strlen(bufStr)); | |||
| fShmNonRtServerControl.writeUInt(bufStrSize); | |||
| fShmNonRtServerControl.writeCustomData(portName, bufStrSize); | |||
| fShmNonRtServerControl.writeCustomData(bufStr, bufStrSize); | |||
| } | |||
| } | |||
| @@ -225,8 +261,8 @@ void CarlaJackClient::activate() | |||
| // kPluginBridgeNonRtServerMidiCount | |||
| { | |||
| const uint32_t mIns = fState.midiIns.count(); | |||
| const uint32_t mOuts = fState.midiOuts.count(); | |||
| const uint32_t mIns = 0; // fClient.midiIns.count(); | |||
| const uint32_t mOuts = 0; // fClient.midiOuts.count(); | |||
| // uint/ins, uint/outs | |||
| fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerMidiCount); | |||
| @@ -243,43 +279,15 @@ void CarlaJackClient::activate() | |||
| fShmNonRtServerControl.waitIfDataIsReachingLimit(); | |||
| // must be static | |||
| fAudioIns = fState.audioIns.count(); | |||
| fAudioOuts = fState.audioOuts.count(); | |||
| fAudioIns = 2; //fClient.audioIns.count(); | |||
| fAudioOuts = 2; //fClient.audioOuts.count(); | |||
| carla_stdout("Carla Jack Client Ready!"); | |||
| fLastPingTime = Time::currentTimeMillis(); | |||
| } | |||
| fState.activated = true; | |||
| } | |||
| void CarlaJackClient::deactivate() | |||
| { | |||
| const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex); | |||
| fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerUiClosed); | |||
| fShmNonRtServerControl.commitWrite(); | |||
| fState.activated = false; | |||
| fState.prematurelyActivated = false; | |||
| for (LinkedList<JackPortState*>::Itenerator it = fState.audioIns.begin2(); it.valid(); it.next()) | |||
| { | |||
| if (JackPortState* const jport = it.getValue(nullptr)) | |||
| delete jport; | |||
| } | |||
| for (LinkedList<JackPortState*>::Itenerator it = fState.audioOuts.begin2(); it.valid(); it.next()) | |||
| { | |||
| if (JackPortState* const jport = it.getValue(nullptr)) | |||
| delete jport; | |||
| } | |||
| fState.audioIns.clear(); | |||
| fState.audioOuts.clear(); | |||
| } | |||
| void CarlaJackClient::handleNonRtData() | |||
| void CarlaJackAppClient::handleNonRtData() | |||
| { | |||
| for (; fShmNonRtClientControl.isDataAvailableForReading();) | |||
| { | |||
| @@ -295,7 +303,7 @@ void CarlaJackClient::handleNonRtData() | |||
| continue; | |||
| ++shownNull; | |||
| } | |||
| carla_stdout("CarlaJackClient::handleNonRtData() - got opcode: %s", PluginBridgeNonRtClientOpcode2str(opcode)); | |||
| carla_stdout("CarlaJackAppClient::handleNonRtData() - got opcode: %s", PluginBridgeNonRtClientOpcode2str(opcode)); | |||
| } | |||
| // #endif | |||
| @@ -387,9 +395,9 @@ void CarlaJackClient::handleNonRtData() | |||
| } | |||
| } | |||
| void CarlaJackClient::run() | |||
| void CarlaJackAppClient::run() | |||
| { | |||
| carla_stderr("CarlaJackClient run START"); | |||
| carla_stderr("CarlaJackAppClient run START"); | |||
| if (! fShmAudioPool.attachClient(fBaseNameAudioPool)) | |||
| { | |||
| @@ -455,21 +463,21 @@ void CarlaJackClient::run() | |||
| if (shmRtClientDataSize != sizeof(BridgeRtClientData) || shmNonRtClientDataSize != sizeof(BridgeNonRtClientData) || shmNonRtServerDataSize != sizeof(BridgeNonRtServerData)) | |||
| { | |||
| carla_stderr2("CarlaJackClient: data size mismatch"); | |||
| carla_stderr2("CarlaJackAppClient: data size mismatch"); | |||
| return; | |||
| } | |||
| opcode = fShmNonRtClientControl.readOpcode(); | |||
| CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtClientSetBufferSize, opcode); | |||
| fState.bufferSize = fShmNonRtClientControl.readUInt(); | |||
| fServer.bufferSize = fShmNonRtClientControl.readUInt(); | |||
| opcode = fShmNonRtClientControl.readOpcode(); | |||
| CARLA_SAFE_ASSERT_INT(opcode == kPluginBridgeNonRtClientSetSampleRate, opcode); | |||
| fState.sampleRate = fShmNonRtClientControl.readDouble(); | |||
| fServer.sampleRate = fShmNonRtClientControl.readDouble(); | |||
| if (fState.bufferSize == 0 || carla_isZero(fState.sampleRate)) | |||
| if (fServer.bufferSize == 0 || carla_isZero(fServer.sampleRate)) | |||
| { | |||
| carla_stderr2("CarlaJackClient: invalid empty state"); | |||
| carla_stderr2("CarlaJackAppClient: invalid empty state"); | |||
| return; | |||
| } | |||
| @@ -483,6 +491,8 @@ void CarlaJackClient::run() | |||
| fIsValid = true; | |||
| activate(); | |||
| #ifdef __SSE2_MATH__ | |||
| // Set FTZ and DAZ flags | |||
| _mm_setcsr(_mm_getcsr() | 0x8040); | |||
| @@ -505,7 +515,7 @@ void CarlaJackClient::run() | |||
| //#ifdef DEBUG | |||
| if (opcode != kPluginBridgeRtClientProcess && opcode != kPluginBridgeRtClientMidiEvent) | |||
| { | |||
| carla_stdout("CarlaJackClientRtThread::run() - got opcode: %s", PluginBridgeRtClientOpcode2str(opcode)); | |||
| carla_stdout("CarlaJackAppClientRtThread::run() - got opcode: %s", PluginBridgeRtClientOpcode2str(opcode)); | |||
| } | |||
| //#endif | |||
| @@ -541,73 +551,102 @@ void CarlaJackClient::run() | |||
| if (cmtl.wasLocked()) | |||
| { | |||
| float* fdata = fShmAudioPool.data; | |||
| // tranport for all clients | |||
| const BridgeTimeInfo& bridgeTimeInfo(fShmRtClientControl.data->timeInfo); | |||
| if (fState.process == nullptr || ! fState.activated) | |||
| fServer.playing = bridgeTimeInfo.playing; | |||
| fServer.position.frame = bridgeTimeInfo.frame; | |||
| fServer.position.usecs = bridgeTimeInfo.usecs; | |||
| if (bridgeTimeInfo.valid & 0x1 /* kValidBBT */) | |||
| { | |||
| for (uint32_t i=0; i<fAudioIns; ++i) | |||
| fdata += fState.bufferSize*fAudioIns; | |||
| fServer.position.valid = JackPositionBBT; | |||
| if (fAudioOuts > 0) | |||
| carla_zeroFloats(fdata, fState.bufferSize*fAudioOuts); | |||
| fServer.position.bar = bridgeTimeInfo.bar; | |||
| fServer.position.beat = bridgeTimeInfo.beat; | |||
| fServer.position.tick = bridgeTimeInfo.tick; | |||
| if (! fState.activated) | |||
| { | |||
| fShmRtClientControl.data->procFlags = 1; | |||
| } | |||
| fServer.position.beats_per_bar = bridgeTimeInfo.beatsPerBar; | |||
| fServer.position.beat_type = bridgeTimeInfo.beatType; | |||
| fServer.position.ticks_per_beat = bridgeTimeInfo.ticksPerBeat; | |||
| fServer.position.beats_per_minute = bridgeTimeInfo.beatsPerMinute; | |||
| fServer.position.bar_start_tick = bridgeTimeInfo.barStartTick; | |||
| } | |||
| else | |||
| { | |||
| const BridgeTimeInfo& bridgeTimeInfo(fShmRtClientControl.data->timeInfo); | |||
| fServer.position.valid = static_cast<jack_position_bits_t>(0); | |||
| } | |||
| uint32_t i = 0; | |||
| for (LinkedList<JackPortState*>::Itenerator it = fState.audioIns.begin2(); it.valid(); it.next()) | |||
| { | |||
| CARLA_SAFE_ASSERT_BREAK(i++ < fAudioIns); | |||
| if (JackPortState* const jport = it.getValue(nullptr)) | |||
| jport->buffer = fdata; | |||
| fdata += fState.bufferSize; | |||
| } | |||
| float* fdata = fShmAudioPool.data; | |||
| i=0; | |||
| for (LinkedList<JackPortState*>::Itenerator it = fState.audioOuts.begin2(); it.valid(); it.next()) | |||
| { | |||
| CARLA_SAFE_ASSERT_BREAK(i++ < fAudioOuts); | |||
| if (JackPortState* const jport = it.getValue(nullptr)) | |||
| jport->buffer = fdata; | |||
| fdata += fState.bufferSize; | |||
| } | |||
| if (JackClientState* const jclient = fClients.getFirst(nullptr)) | |||
| //for (LinkedList<JackClientState*>::Itenerator it = fClients.begin2(); it.valid(); it.next()) | |||
| { | |||
| //JackClientState* const jclient(it.getValue(nullptr)); | |||
| //CARLA_SAFE_ASSERT_CONTINUE(jclient != nullptr); | |||
| fState.playing = bridgeTimeInfo.playing; | |||
| fState.position.frame = bridgeTimeInfo.frame; | |||
| fState.position.usecs = bridgeTimeInfo.usecs; | |||
| const CarlaMutexTryLocker cmtl2(jclient->mutex); | |||
| if (bridgeTimeInfo.valid & 0x1 /* kValidBBT */) | |||
| if (cmtl2.wasNotLocked() || jclient->processCb == nullptr || ! jclient->activated) | |||
| { | |||
| fState.position.valid = JackPositionBBT; | |||
| if (fAudioIns > 0) | |||
| fdata += fServer.bufferSize*fAudioIns; | |||
| fState.position.bar = bridgeTimeInfo.bar; | |||
| fState.position.beat = bridgeTimeInfo.beat; | |||
| fState.position.tick = bridgeTimeInfo.tick; | |||
| if (fAudioOuts > 0) | |||
| carla_zeroFloats(fdata, fServer.bufferSize*fAudioOuts); | |||
| fState.position.beats_per_bar = bridgeTimeInfo.beatsPerBar; | |||
| fState.position.beat_type = bridgeTimeInfo.beatType; | |||
| fState.position.ticks_per_beat = bridgeTimeInfo.ticksPerBeat; | |||
| fState.position.beats_per_minute = bridgeTimeInfo.beatsPerMinute; | |||
| fState.position.bar_start_tick = bridgeTimeInfo.barStartTick; | |||
| if (jclient->deactivated) | |||
| { | |||
| fShmRtClientControl.data->procFlags = 1; | |||
| } | |||
| } | |||
| else | |||
| { | |||
| fState.position.valid = static_cast<jack_position_bits_t>(0); | |||
| uint32_t i; | |||
| i = 0; | |||
| for (LinkedList<JackPortState*>::Itenerator it = jclient->audioIns.begin2(); it.valid(); it.next()) | |||
| { | |||
| CARLA_SAFE_ASSERT_BREAK(i++ < fAudioIns); | |||
| if (JackPortState* const jport = it.getValue(nullptr)) | |||
| jport->buffer = fdata; | |||
| fdata += fServer.bufferSize; | |||
| } | |||
| for (; i++ < fAudioIns;) | |||
| fdata += fServer.bufferSize; | |||
| i = 0; | |||
| for (LinkedList<JackPortState*>::Itenerator it = jclient->audioOuts.begin2(); it.valid(); it.next()) | |||
| { | |||
| CARLA_SAFE_ASSERT_BREAK(i++ < fAudioOuts); | |||
| if (JackPortState* const jport = it.getValue(nullptr)) | |||
| jport->buffer = fdata; | |||
| fdata += fServer.bufferSize; | |||
| } | |||
| for (; i++ < fAudioOuts;) | |||
| { | |||
| //carla_stderr("clearing buffer %i", i); | |||
| carla_zeroFloats(fdata, fServer.bufferSize); | |||
| fdata += fServer.bufferSize; | |||
| } | |||
| jclient->processCb(fServer.bufferSize, jclient->processCbPtr); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| if (fAudioIns > 0) | |||
| fdata += fServer.bufferSize*fAudioIns; | |||
| fState.process(fState.bufferSize, fState.processPtr); | |||
| if (fAudioOuts > 0) | |||
| carla_zeroFloats(fdata, fServer.bufferSize*fAudioOuts); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| carla_stderr2("CarlaJackClient: fRealtimeThreadMutex tryLock failed"); | |||
| carla_stderr2("CarlaJackAppClient: fRealtimeThreadMutex tryLock failed"); | |||
| } | |||
| carla_zeroBytes(fShmRtClientControl.data->midiOut, kBridgeRtClientDataMidiOutSize); | |||
| @@ -626,7 +665,7 @@ void CarlaJackClient::run() | |||
| if (quitReceived) | |||
| { | |||
| carla_stderr("CarlaJackClient run END - quit by carla"); | |||
| carla_stderr("CarlaJackAppClient run END - quit by carla"); | |||
| ::kill(::getpid(), SIGTERM); | |||
| } | |||
| @@ -638,29 +677,99 @@ void CarlaJackClient::run() | |||
| bool activated; | |||
| { | |||
| const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex); | |||
| activated = fState.activated; | |||
| const CarlaMutexLocker cms(fRealtimeThreadMutex); | |||
| if (activated) | |||
| if (JackClientState* const jclient = fClients.getLast(nullptr)) | |||
| { | |||
| carla_stderr("CarlaJackClient run END - quit error"); | |||
| fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerError); | |||
| fShmNonRtServerControl.writeUInt(messageSize); | |||
| fShmNonRtServerControl.writeCustomData(message, messageSize); | |||
| fShmNonRtServerControl.commitWrite(); | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| activated = jclient->activated; | |||
| } | |||
| else | |||
| { | |||
| carla_stderr("CarlaJackClient run END - quit itself"); | |||
| activated = true; | |||
| } | |||
| } | |||
| if (activated && fState.shutdown != nullptr) | |||
| fState.shutdown(fState.shutdownPtr); | |||
| if (activated) | |||
| { | |||
| carla_stderr("CarlaJackAppClient run END - quit error"); | |||
| const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex); | |||
| fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerError); | |||
| fShmNonRtServerControl.writeUInt(messageSize); | |||
| fShmNonRtServerControl.writeCustomData(message, messageSize); | |||
| fShmNonRtServerControl.commitWrite(); | |||
| } | |||
| else | |||
| { | |||
| carla_stderr("CarlaJackAppClient run END - quit itself"); | |||
| const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex); | |||
| fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerUiClosed); | |||
| fShmNonRtServerControl.commitWrite(); | |||
| } | |||
| /* | |||
| if (activated) | |||
| { | |||
| // TODO infoShutdown | |||
| if (fClient.shutdownCb != nullptr) | |||
| fClient.shutdownCb(fClient.shutdownCbPtr); | |||
| } | |||
| */ | |||
| } | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| static CarlaJackAppClient gClient; | |||
| CARLA_EXPORT | |||
| jack_client_t* jack_client_open(const char* client_name, jack_options_t options, jack_status_t* status, ...) | |||
| { | |||
| if (status != nullptr) | |||
| *status = JackNameNotUnique; | |||
| if (options & JackUseExactName) | |||
| return nullptr; | |||
| if (JackClientState* const client = gClient.addClient(client_name)) | |||
| return (jack_client_t*)client; | |||
| if (status != nullptr) | |||
| *status = JackServerError; | |||
| return nullptr; | |||
| } | |||
| CARLA_EXPORT | |||
| jack_client_t* jack_client_new(const char* client_name) | |||
| { | |||
| return jack_client_open(client_name, JackNullOption, nullptr); | |||
| } | |||
| CARLA_EXPORT | |||
| int jack_client_close(jack_client_t* client) | |||
| { | |||
| JackClientState* const jclient = (JackClientState*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 1); | |||
| gClient.removeClient(jclient); | |||
| return 0; | |||
| } | |||
| CARLA_EXPORT | |||
| pthread_t jack_client_thread_id(jack_client_t* client) | |||
| { | |||
| JackClientState* const jclient = (JackClientState*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 0); | |||
| CarlaJackAppClient* const jackAppPtr = jclient->server.jackAppPtr; | |||
| CARLA_SAFE_ASSERT_RETURN(jackAppPtr != nullptr, 0); | |||
| return (pthread_t)jackAppPtr->getThreadId(); | |||
| } | |||
| CARLA_BACKEND_END_NAMESPACE | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -676,7 +785,7 @@ CARLA_BACKEND_USE_NAMESPACE | |||
| CARLA_EXPORT | |||
| int jack_client_real_time_priority(jack_client_t*) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| carla_stdout("CarlaJackAppClient :: %s", __FUNCTION__); | |||
| return -1; | |||
| } | |||
| @@ -55,6 +55,10 @@ CARLA_BACKEND_START_NAMESPACE | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| class CarlaJackAppClient; | |||
| struct JackClientState; | |||
| struct JackServerState; | |||
| struct JackPortState { | |||
| char* name; | |||
| char* fullname; | |||
| @@ -94,104 +98,100 @@ struct JackPortState { | |||
| }; | |||
| struct JackClientState { | |||
| const JackServerState& server; | |||
| CarlaMutex mutex; | |||
| bool activated; | |||
| bool prematurelyActivated; | |||
| bool deactivated; // activated once, then deactivated | |||
| char* name; | |||
| uint32_t bufferSize; | |||
| double sampleRate; | |||
| bool playing; | |||
| jack_position_t position; | |||
| LinkedList<JackPortState*> audioIns; | |||
| LinkedList<JackPortState*> audioOuts; | |||
| uint32_t fakeIns, fakeOuts; | |||
| LinkedList<JackPortState> midiIns; | |||
| LinkedList<JackPortState> midiOuts; | |||
| JackProcessCallback process; | |||
| void* processPtr; | |||
| JackShutdownCallback shutdownCb; | |||
| void* shutdownCbPtr; | |||
| JackShutdownCallback shutdown; | |||
| void* shutdownPtr; | |||
| JackInfoShutdownCallback infoShutdownCb; | |||
| void* infoShutdownCbPtr; | |||
| JackClientState() | |||
| : activated(false), | |||
| prematurelyActivated(false), | |||
| name(nullptr), | |||
| bufferSize(0), | |||
| sampleRate(0.0), | |||
| playing(false), | |||
| JackProcessCallback processCb; | |||
| void* processCbPtr; | |||
| JackBufferSizeCallback bufferSizeCb; | |||
| void* bufferSizeCbPtr; | |||
| JackSampleRateCallback sampleRateCb; | |||
| void* sampleRateCbPtr; | |||
| JackSyncCallback syncCb; | |||
| void* syncCbPtr; | |||
| JackClientState(const JackServerState& s, const char* const n) | |||
| : server(s), | |||
| activated(false), | |||
| deactivated(false), | |||
| name(strdup(n)), | |||
| audioIns(), | |||
| audioOuts(), | |||
| fakeIns(0), | |||
| fakeOuts(0), | |||
| midiIns(), | |||
| midiOuts(), | |||
| process(nullptr), | |||
| processPtr(nullptr), | |||
| shutdown(nullptr), | |||
| shutdownPtr(nullptr) | |||
| { | |||
| carla_zeroStruct(position); | |||
| } | |||
| shutdownCb(nullptr), | |||
| shutdownCbPtr(nullptr), | |||
| infoShutdownCb(nullptr), | |||
| infoShutdownCbPtr(nullptr), | |||
| processCb(nullptr), | |||
| processCbPtr(nullptr), | |||
| bufferSizeCb(nullptr), | |||
| bufferSizeCbPtr(nullptr), | |||
| sampleRateCb(nullptr), | |||
| sampleRateCbPtr(nullptr), | |||
| syncCb(nullptr), | |||
| syncCbPtr(nullptr) {} | |||
| ~JackClientState() | |||
| { | |||
| free(name); | |||
| } | |||
| }; | |||
| // TODO JackServerState, with only bufsize, srate and tranport | |||
| // TODO add JackServerState ptr to JackClientState | |||
| // TODO each client gets its own JackClientState struct | |||
| class CarlaJackClient : public juce::Thread | |||
| { | |||
| public: | |||
| JackClientState fState; | |||
| CarlaJackClient(); | |||
| ~CarlaJackClient() noexcept override; | |||
| const CarlaMutexLocker cms(mutex); | |||
| bool initIfNeeded(const char* const clientName); | |||
| void clear() noexcept; | |||
| bool isValid() const noexcept; | |||
| for (LinkedList<JackPortState*>::Itenerator it = audioIns.begin2(); it.valid(); it.next()) | |||
| { | |||
| if (JackPortState* const jport = it.getValue(nullptr)) | |||
| delete jport; | |||
| } | |||
| void activate(); | |||
| void deactivate(); | |||
| void handleNonRtData(); | |||
| for (LinkedList<JackPortState*>::Itenerator it = audioOuts.begin2(); it.valid(); it.next()) | |||
| { | |||
| if (JackPortState* const jport = it.getValue(nullptr)) | |||
| delete jport; | |||
| } | |||
| // ------------------------------------------------------------------- | |||
| protected: | |||
| void run() override; | |||
| private: | |||
| BridgeAudioPool fShmAudioPool; | |||
| BridgeRtClientControl fShmRtClientControl; | |||
| BridgeNonRtClientControl fShmNonRtClientControl; | |||
| BridgeNonRtServerControl fShmNonRtServerControl; | |||
| free(name); | |||
| name = nullptr; | |||
| char fBaseNameAudioPool[6+1]; | |||
| char fBaseNameRtClientControl[6+1]; | |||
| char fBaseNameNonRtClientControl[6+1]; | |||
| char fBaseNameNonRtServerControl[6+1]; | |||
| audioIns.clear(); | |||
| audioOuts.clear(); | |||
| } | |||
| }; | |||
| bool fIsValid; | |||
| bool fIsOffline; | |||
| bool fFirstIdle; | |||
| int64_t fLastPingTime; | |||
| struct JackServerState { | |||
| CarlaJackAppClient* jackAppPtr; | |||
| uint32_t fAudioIns; | |||
| uint32_t fAudioOuts; | |||
| uint32_t bufferSize; | |||
| double sampleRate; | |||
| CarlaMutex fRealtimeThreadMutex; | |||
| bool playing; | |||
| jack_position_t position; | |||
| CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaJackClient) | |||
| JackServerState() | |||
| : jackAppPtr(nullptr), | |||
| bufferSize(0), | |||
| sampleRate(0.0), | |||
| playing(false) | |||
| { | |||
| carla_zeroStruct(position); | |||
| } | |||
| }; | |||
| CARLA_BACKEND_END_NAMESPACE | |||
| @@ -42,9 +42,7 @@ const char* jack_get_version_string(void) | |||
| CARLA_EXPORT | |||
| int jack_is_realtime(jack_client_t*) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| return 0; | |||
| return 1; | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -52,8 +50,6 @@ int jack_is_realtime(jack_client_t*) | |||
| CARLA_EXPORT | |||
| void jack_free(void* ptr) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| free(ptr); | |||
| } | |||
| @@ -31,133 +31,99 @@ int jack_set_thread_init_callback(jack_client_t*, JackThreadInitCallback, void*) | |||
| CARLA_EXPORT | |||
| void jack_on_shutdown(jack_client_t* client, JackShutdownCallback callback, void* arg) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| CarlaJackClient* const jclient = (CarlaJackClient*)client; | |||
| JackClientState* const jclient = (JackClientState*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr,); | |||
| JackClientState& jstate(jclient->fState); | |||
| CARLA_SAFE_ASSERT_RETURN(! jstate.activated,); | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| jstate.shutdown = callback; | |||
| jstate.shutdownPtr = arg; | |||
| jclient->shutdownCb = callback; | |||
| jclient->shutdownCbPtr = arg; | |||
| } | |||
| // void jack_on_info_shutdown (jack_client_t *client, | |||
| // JackInfoShutdownCallback shutdown_callback, void *arg) JACK_WEAK_EXPORT; | |||
| CARLA_EXPORT | |||
| int jack_set_process_callback(jack_client_t* client, JackProcessCallback callback, void* arg) | |||
| void jack_on_info_shutdown(jack_client_t* client, JackInfoShutdownCallback callback, void* arg) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| CarlaJackClient* const jclient = (CarlaJackClient*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 1); | |||
| JackClientState& jstate(jclient->fState); | |||
| CARLA_SAFE_ASSERT_RETURN(! jstate.activated, 1); | |||
| JackClientState* const jclient = (JackClientState*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr,); | |||
| jstate.process = callback; | |||
| jstate.processPtr = arg; | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| return 0; | |||
| jclient->infoShutdownCb = callback; | |||
| jclient->infoShutdownCbPtr = arg; | |||
| } | |||
| // int jack_set_freewheel_callback (jack_client_t *client, | |||
| // JackFreewheelCallback freewheel_callback, | |||
| // void *arg) JACK_OPTIONAL_WEAK_EXPORT; | |||
| CARLA_EXPORT | |||
| int jack_set_buffer_size_callback(jack_client_t* client, JackBufferSizeCallback /*callback*/, void* /*arg*/) | |||
| int jack_set_process_callback(jack_client_t* client, JackProcessCallback callback, void* arg) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| CarlaJackClient* const jclient = (CarlaJackClient*)client; | |||
| JackClientState* const jclient = (JackClientState*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 1); | |||
| const JackClientState& jstate(jclient->fState); | |||
| CARLA_SAFE_ASSERT_RETURN(! jstate.activated, 1); | |||
| // TODO | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| jclient->processCb = callback; | |||
| jclient->processCbPtr = arg; | |||
| return 0; | |||
| } | |||
| CARLA_EXPORT | |||
| int jack_set_sample_rate_callback(jack_client_t* client, JackSampleRateCallback /*callback*/, void* /*arg*/) | |||
| int jack_set_freewheel_callback(jack_client_t*, JackFreewheelCallback, void*) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| CarlaJackClient* const jclient = (CarlaJackClient*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 1); | |||
| const JackClientState& jstate(jclient->fState); | |||
| CARLA_SAFE_ASSERT_RETURN(! jstate.activated, 1); | |||
| // TODO | |||
| return 0; | |||
| } | |||
| CARLA_EXPORT | |||
| int jack_set_client_registration_callback(jack_client_t* client, JackClientRegistrationCallback, void*) | |||
| int jack_set_buffer_size_callback(jack_client_t* client, JackBufferSizeCallback callback, void* arg) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| CarlaJackClient* const jclient = (CarlaJackClient*)client; | |||
| JackClientState* const jclient = (JackClientState*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 1); | |||
| const JackClientState& jstate(jclient->fState); | |||
| CARLA_SAFE_ASSERT_RETURN(! jstate.activated, 1); | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| jclient->bufferSizeCb = callback; | |||
| jclient->bufferSizeCbPtr = arg; | |||
| return 0; | |||
| } | |||
| CARLA_EXPORT | |||
| int jack_set_port_registration_callback(jack_client_t* client, JackPortRegistrationCallback, void*) | |||
| int jack_set_sample_rate_callback(jack_client_t* client, JackSampleRateCallback callback, void* arg) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| CarlaJackClient* const jclient = (CarlaJackClient*)client; | |||
| JackClientState* const jclient = (JackClientState*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 1); | |||
| const JackClientState& jstate(jclient->fState); | |||
| CARLA_SAFE_ASSERT_RETURN(! jstate.activated, 1); | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| jclient->sampleRateCb = callback; | |||
| jclient->sampleRateCbPtr = arg; | |||
| return 0; | |||
| } | |||
| CARLA_EXPORT | |||
| int jack_set_port_connect_callback(jack_client_t* client, JackPortConnectCallback, void*) | |||
| int jack_set_client_registration_callback(jack_client_t*, JackClientRegistrationCallback, void*) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| CarlaJackClient* const jclient = (CarlaJackClient*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 1); | |||
| const JackClientState& jstate(jclient->fState); | |||
| CARLA_SAFE_ASSERT_RETURN(! jstate.activated, 1); | |||
| return 0; | |||
| } | |||
| // int jack_set_port_rename_callback (jack_client_t *client, | |||
| // JackPortRenameCallback | |||
| // rename_callback, void *arg) JACK_OPTIONAL_WEAK_EXPORT; | |||
| CARLA_EXPORT | |||
| int jack_set_graph_order_callback(jack_client_t* client, JackGraphOrderCallback, void*) | |||
| int jack_set_port_registration_callback(jack_client_t*, JackPortRegistrationCallback, void*) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| return 0; | |||
| } | |||
| CarlaJackClient* const jclient = (CarlaJackClient*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 1); | |||
| CARLA_EXPORT | |||
| int jack_set_port_connect_callback(jack_client_t*, JackPortConnectCallback, void*) | |||
| { | |||
| return 0; | |||
| } | |||
| const JackClientState& jstate(jclient->fState); | |||
| CARLA_SAFE_ASSERT_RETURN(! jstate.activated, 1); | |||
| CARLA_EXPORT | |||
| int jack_set_port_rename_callback(jack_client_t*, JackPortRenameCallback, void*) | |||
| { | |||
| return 0; | |||
| } | |||
| CARLA_EXPORT | |||
| int jack_set_graph_order_callback(jack_client_t*, JackGraphOrderCallback, void*) | |||
| { | |||
| return 0; | |||
| } | |||
| @@ -19,50 +19,6 @@ | |||
| CARLA_BACKEND_USE_NAMESPACE | |||
| static CarlaJackClient gClient; | |||
| static int gClientRefCount = 0; | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| CARLA_EXPORT | |||
| jack_client_t* jack_client_open(const char* client_name, jack_options_t /*options*/, jack_status_t* status, ...) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| if (! gClient.initIfNeeded(client_name)) | |||
| { | |||
| if (status != nullptr) | |||
| *status = JackServerError; | |||
| return nullptr; | |||
| } | |||
| ++gClientRefCount; | |||
| return (jack_client_t*)&gClient; | |||
| } | |||
| CARLA_EXPORT | |||
| jack_client_t* jack_client_new(const char* client_name) | |||
| { | |||
| return jack_client_open(client_name, JackNullOption, nullptr); | |||
| } | |||
| CARLA_EXPORT | |||
| int jack_client_close(jack_client_t* client) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| CarlaJackClient* const jclient = (CarlaJackClient*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 1); | |||
| JackClientState& jstate(jclient->fState); | |||
| if (jstate.activated) | |||
| jclient->deactivate(); | |||
| --gClientRefCount; | |||
| return 0; | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| CARLA_EXPORT | |||
| @@ -74,14 +30,10 @@ int jack_client_name_size(void) | |||
| CARLA_EXPORT | |||
| char* jack_get_client_name(jack_client_t* client) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| CarlaJackClient* const jclient = (CarlaJackClient*)client; | |||
| JackClientState* const jclient = (JackClientState*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, nullptr); | |||
| const JackClientState& jstate(jclient->fState); | |||
| return jstate.name; | |||
| return jclient->name; | |||
| } | |||
| CARLA_EXPORT | |||
| @@ -91,7 +43,7 @@ char* jack_get_uuid_for_client_name(jack_client_t*, const char*) | |||
| } | |||
| CARLA_EXPORT | |||
| char* jack_get_client_name_by_uuid (jack_client_t*, const char*) | |||
| char* jack_get_client_name_by_uuid(jack_client_t*, const char*) | |||
| { | |||
| return nullptr; | |||
| } | |||
| @@ -114,39 +66,26 @@ void jack_internal_client_close(const char*) | |||
| CARLA_EXPORT | |||
| int jack_activate(jack_client_t* client) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| CarlaJackClient* const jclient = (CarlaJackClient*)client; | |||
| JackClientState* const jclient = (JackClientState*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 1); | |||
| const JackClientState& jstate(jclient->fState); | |||
| CARLA_SAFE_ASSERT_RETURN(! jstate.activated, 1); | |||
| #if 0 | |||
| // needed for pulseaudio | |||
| static bool skipFirstActivate = true; | |||
| if (skipFirstActivate) { | |||
| skipFirstActivate = false; | |||
| return 0; | |||
| } | |||
| #endif | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| jclient->activate(); | |||
| jclient->activated = true; | |||
| jclient->deactivated = false; | |||
| return 0; | |||
| } | |||
| CARLA_EXPORT | |||
| int jack_deactivate(jack_client_t* /*client*/) | |||
| int jack_deactivate(jack_client_t* client) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| //CarlaJackClient* const jclient = (CarlaJackClient*)client; | |||
| //CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 1); | |||
| JackClientState* const jclient = (JackClientState*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 1); | |||
| //JackClientState& jstate(jclient->fState); | |||
| //CARLA_SAFE_ASSERT_RETURN(jstate.activated, 1); | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| //jclient->deactivate(); | |||
| jclient->activated = false; | |||
| jclient->deactivated = true; | |||
| return 0; | |||
| } | |||
| @@ -158,18 +97,4 @@ int jack_get_client_pid(const char*) | |||
| return 0; | |||
| } | |||
| CARLA_EXPORT | |||
| pthread_t jack_client_thread_id(jack_client_t* client) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| CarlaJackClient* const jclient = (CarlaJackClient*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 0); | |||
| const JackClientState& jstate(jclient->fState); | |||
| CARLA_SAFE_ASSERT_RETURN(jstate.activated, 0); | |||
| return (pthread_t)jclient->getThreadId(); | |||
| } | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| @@ -27,49 +27,32 @@ jack_port_t* jack_port_register(jack_client_t* client, const char* port_name, co | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s | %s %s %lu", __FUNCTION__, port_name, port_type, flags); | |||
| CarlaJackClient* const jclient = (CarlaJackClient*)client; | |||
| JackClientState* const jclient = (JackClientState*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, nullptr); | |||
| JackClientState& jstate(jclient->fState); | |||
| CARLA_SAFE_ASSERT_RETURN(port_name != nullptr && port_name[0] != '\0', nullptr); | |||
| CARLA_SAFE_ASSERT_RETURN(port_type != nullptr && port_type[0] != '\0', nullptr); | |||
| if (std::strcmp(port_type, JACK_DEFAULT_AUDIO_TYPE) == 0) | |||
| { | |||
| uint32_t index; | |||
| /**/ if (flags & JackPortIsInput) | |||
| if (flags & JackPortIsInput) | |||
| { | |||
| if (jstate.prematurelyActivated) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(jstate.fakeIns > 0, nullptr); | |||
| jstate.fakeIns -= 1; | |||
| index = jstate.audioIns.count() - jstate.fakeIns - 1; | |||
| } | |||
| else | |||
| { | |||
| index = jstate.audioIns.count(); | |||
| jstate.audioIns.append(new JackPortState(jstate.name, port_name, index, flags, false)); | |||
| } | |||
| return (jack_port_t*)jstate.audioIns.getAt(index, nullptr); | |||
| JackPortState* const port = new JackPortState(jclient->name, port_name, jclient->audioIns.count(), flags, false); | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| jclient->audioIns.append(port); | |||
| return (jack_port_t*)port; | |||
| } | |||
| else if (flags & JackPortIsOutput) | |||
| if (flags & JackPortIsOutput) | |||
| { | |||
| if (jstate.prematurelyActivated) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(jstate.fakeOuts > 0, nullptr); | |||
| jstate.fakeOuts -= 1; | |||
| index = jstate.audioOuts.count() - jstate.fakeOuts - 1; | |||
| } | |||
| else | |||
| { | |||
| index = jstate.audioOuts.count(); | |||
| jstate.audioOuts.append(new JackPortState(jstate.name, port_name, index, flags, false)); | |||
| } | |||
| return (jack_port_t*)jstate.audioOuts.getAt(index, nullptr); | |||
| JackPortState* const port = new JackPortState(jclient->name, port_name, jclient->audioOuts.count(), flags, false); | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| jclient->audioOuts.append(port); | |||
| return (jack_port_t*)port; | |||
| } | |||
| carla_stderr2("Invalid port flags '%x'", flags); | |||
| @@ -83,44 +66,29 @@ jack_port_t* jack_port_register(jack_client_t* client, const char* port_name, co | |||
| CARLA_EXPORT | |||
| int jack_port_unregister(jack_client_t* client, jack_port_t* port) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| CarlaJackClient* const jclient = (CarlaJackClient*)client; | |||
| JackClientState* const jclient = (JackClientState*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 1); | |||
| JackPortState* const jport = (JackPortState*)port; | |||
| CARLA_SAFE_ASSERT_RETURN(jport != nullptr, 1); | |||
| CARLA_SAFE_ASSERT_RETURN(! jport->isSystem, 1); | |||
| JackClientState& jstate(jclient->fState); | |||
| //CARLA_SAFE_ASSERT_RETURN(! jstate.activated, 1); | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| if (jport->flags & JackPortIsOutput) | |||
| if (jport->flags & JackPortIsInput) | |||
| { | |||
| if (jstate.prematurelyActivated) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(jstate.fakeIns < 2, 1); | |||
| jstate.fakeIns += 1; | |||
| } | |||
| else | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(jstate.audioIns.removeOne(jport), 1); | |||
| } | |||
| CARLA_SAFE_ASSERT_RETURN(jclient->audioOuts.removeOne(jport), 1); | |||
| return 0; | |||
| } | |||
| else | |||
| if (jport->flags & JackPortIsOutput) | |||
| { | |||
| if (jstate.prematurelyActivated) | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(jstate.fakeOuts < 2, 1); | |||
| jstate.fakeOuts += 1; | |||
| } | |||
| else | |||
| { | |||
| CARLA_SAFE_ASSERT_RETURN(jstate.audioOuts.removeOne(jport), 1); | |||
| } | |||
| CARLA_SAFE_ASSERT_RETURN(jclient->audioIns.removeOne(jport), 1); | |||
| return 0; | |||
| } | |||
| return 0; | |||
| carla_stderr2("Invalid port type on unregister"); | |||
| return 1; | |||
| } | |||
| CARLA_EXPORT | |||
| @@ -25,49 +25,34 @@ CARLA_BACKEND_USE_NAMESPACE | |||
| CARLA_EXPORT | |||
| int jack_set_freewheel(jack_client_t*, int) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| return 1; | |||
| } | |||
| CARLA_EXPORT | |||
| int jack_set_buffer_size(jack_client_t*, jack_nframes_t) | |||
| int jack_set_buffer_size(jack_client_t* client, jack_nframes_t bufferSize) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| JackClientState* const jclient = (JackClientState*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 0); | |||
| return 1; | |||
| return (jclient->server.bufferSize == bufferSize) ? 0 : 1; | |||
| } | |||
| CARLA_EXPORT | |||
| jack_nframes_t jack_get_sample_rate(jack_client_t* client) | |||
| { | |||
| carla_debug("CarlaJackClient :: %s", __FUNCTION__); | |||
| CarlaJackClient* const jclient = (CarlaJackClient*)client; | |||
| JackClientState* const jclient = (JackClientState*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 0); | |||
| const JackClientState& jstate(jclient->fState); | |||
| return jstate.sampleRate; | |||
| return jclient->server.sampleRate; | |||
| } | |||
| CARLA_EXPORT | |||
| jack_nframes_t jack_get_buffer_size(jack_client_t* client) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| CarlaJackClient* const jclient = (CarlaJackClient*)client; | |||
| JackClientState* const jclient = (JackClientState*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 0); | |||
| const JackClientState& jstate(jclient->fState); | |||
| return jstate.bufferSize; | |||
| } | |||
| CARLA_EXPORT | |||
| int jack_engine_takeover_timebase(jack_client_t*) | |||
| { | |||
| return ENOSYS; | |||
| return jclient->server.bufferSize; | |||
| } | |||
| CARLA_EXPORT | |||
| @@ -27,15 +27,10 @@ CARLA_BACKEND_USE_NAMESPACE | |||
| CARLA_EXPORT | |||
| jack_nframes_t jack_frame_time(const jack_client_t* client) | |||
| { | |||
| carla_debug("CarlaJackClient :: %s", __FUNCTION__); | |||
| CarlaJackClient* const jclient = (CarlaJackClient*)client; | |||
| JackClientState* const jclient = (JackClientState*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 0); | |||
| const JackClientState& jstate(jclient->fState); | |||
| CARLA_SAFE_ASSERT_RETURN(jstate.activated, 0); | |||
| return jstate.position.usecs; | |||
| return jclient->server.position.usecs; | |||
| } | |||
| // jack_nframes_t jack_last_frame_time (const jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT; | |||
| @@ -22,21 +22,24 @@ CARLA_BACKEND_USE_NAMESPACE | |||
| // -------------------------------------------------------------------------------------------------------------------- | |||
| CARLA_EXPORT | |||
| int jack_engine_takeover_timebase(jack_client_t*) | |||
| { | |||
| return ENOSYS; | |||
| } | |||
| // int jack_release_timebase (jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT; | |||
| CARLA_EXPORT | |||
| int jack_set_sync_callback(jack_client_t* client, JackSyncCallback /*callback*/, void* /*arg*/) | |||
| int jack_set_sync_callback(jack_client_t* client, JackSyncCallback callback, void* arg) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| CarlaJackClient* const jclient = (CarlaJackClient*)client; | |||
| JackClientState* const jclient = (JackClientState*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 1); | |||
| const JackClientState& jstate(jclient->fState); | |||
| CARLA_SAFE_ASSERT_RETURN(! jstate.activated, 1); | |||
| // TODO | |||
| const CarlaMutexLocker cms(jclient->mutex); | |||
| jclient->syncCb = callback; | |||
| jclient->syncCbPtr = arg; | |||
| return 0; | |||
| } | |||
| @@ -44,47 +47,45 @@ int jack_set_sync_callback(jack_client_t* client, JackSyncCallback /*callback*/, | |||
| // jack_time_t timeout) JACK_OPTIONAL_WEAK_EXPORT; | |||
| CARLA_EXPORT | |||
| int jack_set_timebase_callback(jack_client_t* client, int, JackTimebaseCallback, void*) | |||
| int jack_set_timebase_callback(jack_client_t*, int, JackTimebaseCallback, void*) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| CarlaJackClient* const jclient = (CarlaJackClient*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, 1); | |||
| const JackClientState& jstate(jclient->fState); | |||
| CARLA_SAFE_ASSERT_RETURN(! jstate.activated, 1); | |||
| // TODO | |||
| // FIXME? | |||
| return EBUSY; | |||
| } | |||
| CARLA_EXPORT | |||
| int jack_transport_locate(jack_client_t*, jack_nframes_t) | |||
| { | |||
| carla_stdout("CarlaJackClient :: %s", __FUNCTION__); | |||
| // FIXME? | |||
| return 1; | |||
| } | |||
| CARLA_EXPORT | |||
| jack_transport_state_t jack_transport_query(const jack_client_t* client, jack_position_t* pos) | |||
| { | |||
| carla_debug("CarlaJackClient :: %s", __FUNCTION__); | |||
| if (const JackClientState* const jclient = (JackClientState*)client) | |||
| { | |||
| const JackServerState& jserver(jclient->server); | |||
| CarlaJackClient* const jclient = (CarlaJackClient*)client; | |||
| CARLA_SAFE_ASSERT_RETURN(jclient != nullptr, JackTransportStopped); | |||
| if (pos != nullptr) | |||
| std::memcpy(pos, &jserver.position, sizeof(jack_position_t)); | |||
| const JackClientState& jstate(jclient->fState); | |||
| CARLA_SAFE_ASSERT_RETURN(jstate.activated, JackTransportStopped); | |||
| return jserver.playing ? JackTransportRolling : JackTransportStopped; | |||
| } | |||
| if (pos != nullptr) | |||
| std::memcpy(pos, &jstate.position, sizeof(jack_position_t)); | |||
| std::memset(pos, 0, sizeof(jack_position_t)); | |||
| return jstate.playing ? JackTransportRolling : JackTransportStopped; | |||
| return JackTransportStopped; | |||
| } | |||
| // jack_nframes_t jack_get_current_transport_frame (const jack_client_t *client) JACK_OPTIONAL_WEAK_EXPORT; | |||
| jack_nframes_t jack_get_current_transport_frame(const jack_client_t* client) | |||
| { | |||
| if (const JackClientState* const jclient = (JackClientState*)client) | |||
| return jclient->server.position.frame; | |||
| return 0; | |||
| } | |||
| CARLA_EXPORT | |||
| int jack_transport_reposition(jack_client_t*, const jack_position_t*) | |||