clap

CLAP Audio Plugin API
Log | Files | Refs | README | LICENSE

commit 96be27ae41b9f43899effb7b20b10fb995013c49
parent 37862e5a766cf657da28aa18b5a9fe23c312ce9a
Author: Alexandre BIQUE <bique.alexandre@gmail.com>
Date:   Tue, 17 Aug 2021 16:11:27 +0200

Fix cute troubles

Diffstat:
Mexamples/gui/CMakeLists.txt | 5++---
Mexamples/gui/application.cc | 49++++++++++++++++++++++++++++++++++---------------
Mexamples/gui/application.hh | 15++++++++-------
Mexamples/host/application.cc | 6+++---
Mexamples/io/remote-channel.cc | 17++++++++++++++---
Mexamples/io/remote-channel.hh | 6++++--
Mexamples/plugins/dc-offset/dc-offset.cc | 18++++++++++--------
Mexamples/plugins/dc-offset/skin/main.qml | 4++--
Mexamples/plugins/gain/gain.cc | 18++++++++++--------
Mexamples/plugins/remote-gui.cc | 37++++++++++++++++++++++++++++++++-----
Mexamples/plugins/remote-gui.hh | 3+++
11 files changed, 122 insertions(+), 56 deletions(-)

diff --git a/examples/gui/CMakeLists.txt b/examples/gui/CMakeLists.txt @@ -2,6 +2,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) find_package(Qt6 COMPONENTS Quick REQUIRED) +find_package(Qt6 COMPONENTS Widgets REQUIRED) add_executable(clap-gui main.cc @@ -14,9 +15,7 @@ add_executable(clap-gui plugin-proxy.hh plugin-proxy.cc ) -target_compile_options(clap-gui PRIVATE -fsanitize=address) -target_link_options(clap-gui PRIVATE -fsanitize=address) -target_link_libraries(clap-gui clap-io Qt6::Quick) +target_link_libraries(clap-gui clap-io Qt6::Widgets Qt6::Quick) set_target_properties(clap-gui PROPERTIES CXX_STANDARD 17) install(TARGETS clap-gui DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") \ No newline at end of file diff --git a/examples/gui/application.cc b/examples/gui/application.cc @@ -1,15 +1,15 @@ #include <QCommandLineParser> #include <QQmlContext> #include <QQmlEngine> -#include <QQuickView> #include <QQuickItem> +#include <QQuickView> #include <QWindow> #include "../io/messages.hh" #include "application.hh" -Application::Application(int argc, char **argv) - : QGuiApplication(argc, argv), quickView_(new QQuickView()) { +Application::Application(int& argc, char **argv) + : QApplication(argc, argv), quickView_(new QQuickView()) { bool waitForDebbugger = false; while (waitForDebbugger) @@ -34,20 +34,28 @@ Application::Application(int argc, char **argv) auto socket = parser.value(socketOpt).toULongLong(); - socketReadNotifier_ = new QSocketNotifier(socket, QSocketNotifier::Read, this); - connect( - socketReadNotifier_, - &QSocketNotifier::activated, - [this](QSocketDescriptor socket, QSocketNotifier::Type type) { remoteChannel_->onRead(); }); + socketReadNotifier_.reset(new QSocketNotifier(socket, QSocketNotifier::Read, this)); + connect(socketReadNotifier_.get(), + &QSocketNotifier::activated, + [this](QSocketDescriptor socket, QSocketNotifier::Type type) { + remoteChannel_->onRead(); + if (!remoteChannel_->isOpen()) + quit(); + }); - socketWriteNotifier_ = new QSocketNotifier(socket, QSocketNotifier::Write, this); - connect( - socketWriteNotifier_, - &QSocketNotifier::activated, - [this](QSocketDescriptor socket, QSocketNotifier::Type type) { remoteChannel_->onWrite(); }); + socketWriteNotifier_.reset(new QSocketNotifier(socket, QSocketNotifier::Write, this)); + connect(socketWriteNotifier_.get(), + &QSocketNotifier::activated, + [this](QSocketDescriptor socket, QSocketNotifier::Type type) { + remoteChannel_->onWrite(); + if (!remoteChannel_->isOpen()) + { + quit(); + } + }); - socketErrorNotifier_ = new QSocketNotifier(socket, QSocketNotifier::Exception, this); - connect(socketErrorNotifier_, + socketErrorNotifier_.reset(new QSocketNotifier(socket, QSocketNotifier::Exception, this)); + connect(socketErrorNotifier_.get(), &QSocketNotifier::activated, [this](QSocketDescriptor socket, QSocketNotifier::Type type) { remoteChannel_->onError(); @@ -70,8 +78,19 @@ void Application::modifyFd(clap_fd_flags flags) { socketErrorNotifier_->setEnabled(flags & CLAP_FD_ERROR); } +void Application::removeFd() { + socketReadNotifier_.reset(); + socketWriteNotifier_.reset(); + socketErrorNotifier_.reset(); +} + void Application::onMessage(const clap::RemoteChannel::Message &msg) { switch (msg.type) { + case clap::messages::kDestroyRequest: + clap::messages::DestroyResponse rp; + remoteChannel_->sendResponseAsync(rp, msg.cookie); + break; + case clap::messages::kDefineParameterRequest: { clap::messages::DefineParameterRequest rq; msg.get(rq); diff --git a/examples/gui/application.hh b/examples/gui/application.hh @@ -1,6 +1,6 @@ #pragma once -#include <QGuiApplication> +#include <QApplication> #include <QSocketNotifier> #include <QWindow> @@ -9,24 +9,25 @@ class QQuickView; -class Application : public QGuiApplication, public clap::RemoteChannel::EventControl { +class Application : public QApplication, public clap::RemoteChannel::EventControl { Q_OBJECT; public: - Application(int argc, char **argv); + Application(int& argc, char **argv); clap::RemoteChannel& remoteChannel() const { return *remoteChannel_; } void modifyFd(clap_fd_flags flags) override; + void removeFd() override; - static Application& instance() { return *dynamic_cast<Application *>(QCoreApplication::instance()); } + static Application& instance() { return *dynamic_cast<Application *>(QApplication::instance()); } private: void onMessage(const clap::RemoteChannel::Message& msg); QQuickView *quickView_ = nullptr; - QSocketNotifier *socketReadNotifier_ = nullptr; - QSocketNotifier *socketWriteNotifier_ = nullptr; - QSocketNotifier *socketErrorNotifier_ = nullptr; + std::unique_ptr<QSocketNotifier> socketReadNotifier_; + std::unique_ptr<QSocketNotifier> socketWriteNotifier_; + std::unique_ptr<QSocketNotifier> socketErrorNotifier_; std::unique_ptr<QWindow> hostWindow_ = nullptr; diff --git a/examples/host/application.cc b/examples/host/application.cc @@ -55,12 +55,12 @@ Application::Application(int argc, char **argv) Application::~Application() { saveSettings(); - delete mainWindow_; - mainWindow_ = nullptr; - delete engine_; engine_ = nullptr; + delete mainWindow_; + mainWindow_ = nullptr; + delete settings_; settings_ = nullptr; } diff --git a/examples/io/remote-channel.cc b/examples/io/remote-channel.cc @@ -95,6 +95,9 @@ namespace clap { if (socket_ == -1) return; + modifyFd(0); + evControl_.removeFd(); + ::close(socket_); socket_ = -1; } @@ -166,6 +169,9 @@ namespace clap { } void RemoteChannel::runOnce() { + if (!isOpen()) + return; + #ifdef __unix__ pollfd pfd; pfd.fd = socket_; @@ -173,14 +179,19 @@ namespace clap { pfd.revents = 0; int ret = ::poll(&pfd, 1, -1); - if (ret < 1) - // TODO error handling + if (ret < 1) { + if (errno == EAGAIN || errno == EINTR) + return; + close(); return; + } if (pfd.revents & POLLOUT) onWrite(); - if (pfd.revents & POLLIN) + if (isOpen() && pfd.revents & POLLIN) onRead(); + if (isOpen() && pfd.revents & POLLERR) + close(); #endif } } // namespace clap diff --git a/examples/io/remote-channel.hh b/examples/io/remote-channel.hh @@ -16,6 +16,7 @@ namespace clap { class EventControl { public: virtual void modifyFd(clap_fd_flags flags) = 0; + virtual void removeFd() = 0; }; struct Message final { @@ -53,7 +54,7 @@ namespace clap { void set(const T &msg) noexcept { type = T::type; data = &msg; - size = sizeof (T); + size = sizeof(T); } }; @@ -103,6 +104,7 @@ namespace clap { void runOnce(); clap_fd fd() const { return socket_; } + bool isOpen() const noexcept { return socket_ != -1; } private: using ReadBuffer = Buffer<uint8_t, 128 * 1024>; @@ -122,7 +124,7 @@ namespace clap { uint32_t nextCookie_ = 0; MessageHandler handler_; - std::unordered_map<uint32_t /* cookie */, const MessageHandler&> syncHandlers_; + std::unordered_map<uint32_t /* cookie */, const MessageHandler &> syncHandlers_; EventControl &evControl_; clap_fd socket_; clap_fd_flags ioFlags_ = 0; diff --git a/examples/plugins/dc-offset/dc-offset.cc b/examples/plugins/dc-offset/dc-offset.cc @@ -27,15 +27,17 @@ namespace clap { kParamIdOffset = 0, }; - DcOffset::DcOffset(const std::string& pluginPath, const clap_host *host) : CorePlugin(PathProvider::create(pluginPath, "dc-offset"), descriptor(), host) { + DcOffset::DcOffset(const std::string &pluginPath, const clap_host *host) + : CorePlugin(PathProvider::create(pluginPath, "dc-offset"), descriptor(), host) { parameters_.addParameter(clap_param_info{ - .id = kParamIdOffset, - .flags = 0, - .name = "offset", - .module = "/", - .min_value = -1, - .max_value = 1, - .default_value = 0, + kParamIdOffset, + 0, + nullptr, + "offset", + "/", + -1, + 1, + 0, }); } diff --git a/examples/plugins/dc-offset/skin/main.qml b/examples/plugins/dc-offset/skin/main.qml @@ -6,8 +6,8 @@ Rectangle { height: 200 color: "#224477" - Dial { + /*Dial { property QtObject param: plugin.getParam(0) inputMode: Dial.Vertical - } + }*/ } \ No newline at end of file diff --git a/examples/plugins/gain/gain.cc b/examples/plugins/gain/gain.cc @@ -26,15 +26,17 @@ namespace clap { kParamIdGain = 0, }; - Gain::Gain(const std::string& pluginPath, const clap_host *host) : CorePlugin(PathProvider::create(pluginPath, "gain"), descriptor(), host) { + Gain::Gain(const std::string &pluginPath, const clap_host *host) + : CorePlugin(PathProvider::create(pluginPath, "gain"), descriptor(), host) { parameters_.addParameter(clap_param_info{ - .id = kParamIdGain, - .flags = 0, - .name = "gain", - .module = "/", - .min_value = -1, - .max_value = 1, - .default_value = 0, + kParamIdGain, + 0, + nullptr, + "gain", + "/", + -1, + 1, + 0, }); } diff --git a/examples/plugins/remote-gui.cc b/examples/plugins/remote-gui.cc @@ -6,8 +6,8 @@ #include <cassert> #include "../io/messages.hh" -#include "path-provider.hh" #include "core-plugin.hh" +#include "path-provider.hh" #include "remote-gui.hh" namespace clap { @@ -22,7 +22,7 @@ namespace clap { assert(child_ == -1); assert(!channel_); - auto& pathProvider = plugin_.pathProvider(); + auto &pathProvider = plugin_.pathProvider(); #ifdef __unix__ /* create a socket pair */ @@ -49,7 +49,13 @@ namespace clap { ::snprintf(socketStr, sizeof(socketStr), "%d", sockets[1]); auto path = pathProvider.getGuiExecutable(); auto skin = pathProvider.getSkinDirectory(); - ::execl(path.c_str(), path.c_str(), "--socket", socketStr, "--skin", skin.c_str(), (const char *)nullptr); + ::execl(path.c_str(), + path.c_str(), + "--socket", + socketStr, + "--skin", + skin.c_str(), + (const char *)nullptr); printf("Failed to start child process: %m\n"); std::terminate(); } else { @@ -71,6 +77,10 @@ namespace clap { plugin_.hostEventLoop_->modify_fd(plugin_.host_, channel_->fd(), flags); } + void RemoteGui::removeFd() { + plugin_.hostEventLoop_->unregister_fd(plugin_.host_, channel_->fd()); + } + clap_fd RemoteGui::fd() const { return channel_ ? channel_->fd() : -1; } void RemoteGui::onFd(clap_fd_flags flags) { @@ -128,8 +138,25 @@ namespace clap { messages::DestroyResponse response; channel_->sendRequestSync(request, response); - plugin_.hostEventLoop_->unregister_fd(plugin_.host_, channel_->fd()); + channel_->close(); channel_.reset(); + + waitChild(); + } + + void RemoteGui::waitChild() { +#ifdef __unix__ + if (child_ == -1) + return; + int stat = 0; + int ret; + + do { + ret = ::waitpid(child_, &stat, 0); + } while (ret == -1 && errno == EINTR); + + child_ = -1; +#endif } bool RemoteGui::attachCocoa(void *nsView) noexcept { @@ -149,7 +176,7 @@ namespace clap { messages::AttachResponse response; request.window = window; - std::snprintf(request.display, sizeof(request.display), "%s", display_name ? : ""); + std::snprintf(request.display, sizeof(request.display), "%s", display_name ?: ""); return channel_->sendRequestSync(request, response); } diff --git a/examples/plugins/remote-gui.hh b/examples/plugins/remote-gui.hh @@ -33,11 +33,14 @@ namespace clap { // RemoteChannel::EventControl void modifyFd(clap_fd_flags flags) override; + void removeFd() override; + clap_fd fd() const; void onFd(clap_fd_flags flags); private: void onMessage(const RemoteChannel::Message& msg); + void waitChild(); std::unique_ptr<RemoteChannel> channel_;