362 lines
9.8 KiB
C++
362 lines
9.8 KiB
C++
/*
|
|
* Carla Pipe utils
|
|
* Copyright (C) 2013-2023 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.
|
|
*/
|
|
|
|
#ifndef CARLA_PIPE_UTILS_HPP_INCLUDED
|
|
#define CARLA_PIPE_UTILS_HPP_INCLUDED
|
|
|
|
#include "CarlaJuceUtils.hpp"
|
|
#include "CarlaMutex.hpp"
|
|
|
|
#ifdef BUILDING_CARLA
|
|
# include "lv2/atom.h"
|
|
#else
|
|
# include "lv2/atom/atom.h"
|
|
#endif
|
|
|
|
// -----------------------------------------------------------------------
|
|
// CarlaPipeCommon class
|
|
|
|
class CarlaPipeCommon
|
|
{
|
|
protected:
|
|
/*!
|
|
* Constructor.
|
|
*/
|
|
CarlaPipeCommon() noexcept;
|
|
|
|
/*!
|
|
* Destructor.
|
|
*/
|
|
virtual ~CarlaPipeCommon() /*noexcept*/;
|
|
|
|
/*!
|
|
* A message has been received (in the context of idlePipe()).
|
|
* If extra data is required, use any of the readNextLineAs* functions.
|
|
* Returning true means the message has been handled and should not propagate to subclasses.
|
|
*/
|
|
virtual bool msgReceived(const char* msg) noexcept = 0;
|
|
|
|
/*!
|
|
* An error has occurred during the current requested operation.
|
|
* Reimplementing this method allows to catch these errors as strings.
|
|
* By default the error is simply printed to stderr.
|
|
*/
|
|
virtual void fail(const char* error) noexcept
|
|
{
|
|
carla_stderr2(error);
|
|
}
|
|
|
|
public:
|
|
/*!
|
|
* Check if the pipe is running.
|
|
*/
|
|
bool isPipeRunning() const noexcept;
|
|
|
|
/*!
|
|
* Check the pipe for new messages and send them to msgReceived().
|
|
*/
|
|
void idlePipe(bool onlyOnce = false) noexcept;
|
|
|
|
// -------------------------------------------------------------------
|
|
// write lock
|
|
|
|
/*!
|
|
* Lock the pipe write mutex.
|
|
*/
|
|
void lockPipe() const noexcept;
|
|
|
|
/*!
|
|
* Try locking the pipe write mutex.
|
|
* Returns true if successful.
|
|
*/
|
|
bool tryLockPipe() const noexcept;
|
|
|
|
/*!
|
|
* Unlock the pipe write mutex.
|
|
*/
|
|
void unlockPipe() const noexcept;
|
|
|
|
/*!
|
|
* Get the pipe write lock.
|
|
*/
|
|
CarlaMutex& getPipeLock() const noexcept;
|
|
|
|
// -------------------------------------------------------------------
|
|
// read lines, must only be called in the context of msgReceived()
|
|
|
|
/*!
|
|
* Read the next line as a boolean.
|
|
*/
|
|
bool readNextLineAsBool(bool& value) const noexcept;
|
|
|
|
/*!
|
|
* Read the next line as a byte.
|
|
*/
|
|
bool readNextLineAsByte(uint8_t& value) const noexcept;
|
|
|
|
/*!
|
|
* Read the next line as an integer.
|
|
*/
|
|
bool readNextLineAsInt(int32_t& value) const noexcept;
|
|
|
|
/*!
|
|
* Read the next line as an unsigned integer.
|
|
*/
|
|
bool readNextLineAsUInt(uint32_t& value) const noexcept;
|
|
|
|
/*!
|
|
* Read the next line as a long integer.
|
|
*/
|
|
bool readNextLineAsLong(int64_t& value) const noexcept;
|
|
|
|
/*!
|
|
* Read the next line as a long unsigned integer.
|
|
*/
|
|
bool readNextLineAsULong(uint64_t& value) const noexcept;
|
|
|
|
/*!
|
|
* Read the next line as a floating point number (single precision).
|
|
*/
|
|
bool readNextLineAsFloat(float& value) const noexcept;
|
|
|
|
/*!
|
|
* Read the next line as a floating point number (double precision).
|
|
*/
|
|
bool readNextLineAsDouble(double& value) const noexcept;
|
|
|
|
/*!
|
|
* Read the next line as a string.
|
|
* @note: @a value must be freed if valid and allocateString is true.
|
|
*/
|
|
bool readNextLineAsString(const char*& value, bool allocateString, uint32_t size = 0) const noexcept;
|
|
|
|
/*!
|
|
* Read the next line as a string, returning an allocated copy that needs to be freed.
|
|
*/
|
|
char* readNextLineAsString() const noexcept;
|
|
|
|
// -------------------------------------------------------------------
|
|
// write messages, must be locked before calling
|
|
|
|
/*!
|
|
* Write a valid message with unknown size.
|
|
* A valid message has only one '\n' character and it's at the end.
|
|
*/
|
|
bool writeMessage(const char* msg) const noexcept;
|
|
|
|
/*!
|
|
* Write a valid message with known size.
|
|
* A valid message has only one '\n' character and it's at the end.
|
|
*/
|
|
bool writeMessage(const char* msg, std::size_t size) const noexcept;
|
|
|
|
/*!
|
|
* Write and fix a message.
|
|
*/
|
|
bool writeAndFixMessage(const char* msg) const noexcept;
|
|
|
|
/*!
|
|
* Write an empty message, which means a single '\n'.
|
|
*/
|
|
bool writeEmptyMessage() const noexcept;
|
|
|
|
/*!
|
|
* Flush all messages currently in cache.
|
|
*/
|
|
bool flushMessages() const noexcept;
|
|
|
|
// -------------------------------------------------------------------
|
|
// write prepared messages, no lock or flush needed (done internally)
|
|
|
|
/*!
|
|
* Write an "error" message.
|
|
*/
|
|
bool writeErrorMessage(const char* error) const noexcept;
|
|
|
|
/*!
|
|
* Write a "control" message used for parameter/control changes.
|
|
*/
|
|
bool writeControlMessage(uint32_t index, float value, bool withWriteLock = true) const noexcept;
|
|
|
|
/*!
|
|
* Write a "configure" message used for state changes.
|
|
*/
|
|
bool writeConfigureMessage(const char* key, const char* value) const noexcept;
|
|
|
|
/*!
|
|
* Write a "program" message (using index).
|
|
*/
|
|
bool writeProgramMessage(uint32_t index) const noexcept;
|
|
|
|
/*!
|
|
* Write a "program" message (using channel, bank and program).
|
|
*/
|
|
bool writeProgramMessage(uint8_t channel, uint32_t bank, uint32_t program) const noexcept;
|
|
|
|
/*!
|
|
* Write a "midiprogram" message (using bank and program).
|
|
*/
|
|
bool writeMidiProgramMessage(uint32_t bank, uint32_t program) const noexcept;
|
|
|
|
/*!
|
|
* Write a "reloadprograms" message.
|
|
*/
|
|
bool writeReloadProgramsMessage(int32_t index) const noexcept;
|
|
|
|
/*!
|
|
* Write a MIDI "note" message.
|
|
*/
|
|
bool writeMidiNoteMessage(bool onOff, uint8_t channel, uint8_t note, uint8_t velocity) const noexcept;
|
|
|
|
/*!
|
|
* Write an lv2 "atom" message.
|
|
*/
|
|
bool writeLv2AtomMessage(uint32_t index, const LV2_Atom* atom) const noexcept;
|
|
|
|
/*!
|
|
* Write an lv2 "parameter" message.
|
|
*/
|
|
bool writeLv2ParameterMessage(const char* uri, float value, bool withWriteLock = true) const noexcept;
|
|
|
|
/*!
|
|
* Write an lv2 "urid" message.
|
|
*/
|
|
bool writeLv2UridMessage(uint32_t urid, const char* uri) const noexcept;
|
|
|
|
// -------------------------------------------------------------------
|
|
|
|
protected:
|
|
struct PrivateData;
|
|
PrivateData* const pData;
|
|
|
|
// -------------------------------------------------------------------
|
|
|
|
/*! @internal */
|
|
const char* _readline(bool allocReturn, uint16_t size, bool& readSucess) const noexcept;
|
|
|
|
/*! @internal */
|
|
const char* _readlineblock(bool allocReturn, uint16_t size = 0, uint32_t timeOutMilliseconds = 50) const noexcept;
|
|
|
|
/*! @internal */
|
|
bool _writeMsgBuffer(const char* msg, std::size_t size) const noexcept;
|
|
|
|
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPipeCommon)
|
|
};
|
|
|
|
// -----------------------------------------------------------------------
|
|
// CarlaPipeServer class
|
|
|
|
class CarlaPipeServer : public CarlaPipeCommon
|
|
{
|
|
public:
|
|
/*!
|
|
* Constructor.
|
|
*/
|
|
CarlaPipeServer() noexcept;
|
|
|
|
/*!
|
|
* Destructor.
|
|
*/
|
|
~CarlaPipeServer() /*noexcept*/ override;
|
|
|
|
/*!
|
|
* Get the process ID of this pipe's matching client.
|
|
* Will return 0 if client is not running.
|
|
* @note: Unsupported on Windows
|
|
*/
|
|
uintptr_t getPID() const noexcept;
|
|
|
|
/*!
|
|
* Start the pipe server using @a filename with 2 arguments.
|
|
* @see fail()
|
|
*/
|
|
bool startPipeServer(const char* const filename, const char* const arg1, const char* const arg2, const int size = -1) noexcept;
|
|
|
|
/*!
|
|
* Stop the pipe server.
|
|
* This will send a quit message to the client, wait for it to close for @a timeOutMilliseconds, and close the pipes.
|
|
*/
|
|
void stopPipeServer(const uint32_t timeOutMilliseconds) noexcept;
|
|
|
|
/*!
|
|
* Close the pipes without waiting for the child process to terminate.
|
|
*/
|
|
void closePipeServer() noexcept;
|
|
|
|
// -------------------------------------------------------------------
|
|
// write prepared messages, no lock or flush needed (done internally)
|
|
|
|
/*!
|
|
* Write a single "show" message.
|
|
*/
|
|
void writeShowMessage() const noexcept;
|
|
|
|
/*!
|
|
* Write a single "focus" message.
|
|
*/
|
|
void writeFocusMessage() const noexcept;
|
|
|
|
/*!
|
|
* Write a single "hide" message.
|
|
*/
|
|
void writeHideMessage() const noexcept;
|
|
|
|
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPipeServer)
|
|
};
|
|
|
|
// -----------------------------------------------------------------------
|
|
// CarlaPipeClient class
|
|
|
|
class CarlaPipeClient : public CarlaPipeCommon
|
|
{
|
|
public:
|
|
/*!
|
|
* Constructor.
|
|
*/
|
|
CarlaPipeClient() noexcept;
|
|
|
|
/*!
|
|
* Destructor.
|
|
*/
|
|
~CarlaPipeClient() /*noexcept*/ override;
|
|
|
|
/*!
|
|
* Initialize the pipes used by a server.
|
|
* @a argv must match the arguments set the by server.
|
|
*/
|
|
bool initPipeClient(const char* argv[]) noexcept;
|
|
|
|
/*!
|
|
* Close the pipes.
|
|
*/
|
|
void closePipeClient() noexcept;
|
|
|
|
// -------------------------------------------------------------------
|
|
// write prepared messages, no lock or flush needed (done internally)
|
|
|
|
/*!
|
|
* Write a single "exiting" message and wait for server to respond.
|
|
*/
|
|
void writeExitingMessageAndWait() noexcept;
|
|
|
|
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPipeClient)
|
|
};
|
|
|
|
// -----------------------------------------------------------------------
|
|
|
|
#endif // CARLA_PIPE_UTILS_HPP_INCLUDED
|