diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5566193 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/.cache/ +/build*/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..f84fa4c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.25) +project(obs-studio-plugin-unix-socket-control) + +add_compile_options( + -Wall -Wextra -Wpedantic + $<$:-O0> +) + +if(NOT DEFINED CMAKE_BUILD_TYPE OR NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Debug") + message("Set build type to Debug by default") +endif() + +set(unix-socket-control_SOURCES + src/plugin.c + src/socket.c +) + +add_library(unix-socket-control MODULE + ${unix-socket-control_SOURCES}) + +find_package(libobs REQUIRED) +target_link_libraries(unix-socket-control PRIVATE OBS::libobs) diff --git a/compile_commands.json b/compile_commands.json new file mode 120000 index 0000000..71ca32f --- /dev/null +++ b/compile_commands.json @@ -0,0 +1 @@ +buildDebug/compile_commands.json \ No newline at end of file diff --git a/src/plugin.c b/src/plugin.c new file mode 100644 index 0000000..68adc95 --- /dev/null +++ b/src/plugin.c @@ -0,0 +1,24 @@ +// plugin includes +#include +#include + +// local includes +#include "socket.h" + +static UnixSocketHandler global_unix_socket_handler={ + .flags = 0xFFFFFFFFFFFFFFFF +}; + +OBS_DECLARE_MODULE() + +OBS_MODULE_USE_DEFAULT_LOCALE("unix-socket-control", "en-US") + +bool obs_module_load(void) { + global_unix_socket_handler = init_unix_socket_handler(); + + return is_unix_socket_handler_valid(global_unix_socket_handler) ? true : false; +} + +void obs_module_unload(void) { + cleanup_unix_socket_handler(&global_unix_socket_handler); +} diff --git a/src/socket.c b/src/socket.c new file mode 100644 index 0000000..7bfc3cf --- /dev/null +++ b/src/socket.c @@ -0,0 +1,67 @@ +#include "socket.h" + +// standard library includes +#include + +// unix includes +#include +#include +#include + +#define UNIX_SOCKET_HANDLER_SOCKET_NAME "/tmp/obs-studio-plugin-unix-socket-handler-socket" + +UnixSocketHandler init_unix_socket_handler(void) { + UnixSocketHandler handler; + + memset(&handler, 0, sizeof(UnixSocketHandler)); + + umask(S_IRWXO); + + // Set up linked list of events. + handler.events_head.next = &handler.events_tail; + handler.events_tail.prev = &handler.events_head; + + handler.events_head.type = UNIX_SOCKET_EVENT_HEAD; + handler.events_tail.type = UNIX_SOCKET_EVENT_TAIL; + + // Set up unix socket. + handler.socket_descriptor = socket(AF_UNIX, SOCK_SEQPACKET, 0); + if (handler.socket_descriptor == -1) { + handler.flags = 0xFFFFFFFFFFFFFFFF; + return handler; + } + + handler.name.sun_family = AF_UNIX; + strncpy(handler.name.sun_path, + UNIX_SOCKET_HANDLER_SOCKET_NAME, + sizeof(handler.name.sun_path) - 1); + + int ret = bind(handler.socket_descriptor, + (const struct sockaddr*) &handler.name, + sizeof(handler.name)); + if (ret == -1) { + close(handler.socket_descriptor); + handler.socket_descriptor = -1; + handler.flags = 0xFFFFFFFFFFFFFFFF; + return handler; + } + + return handler; +} + +void cleanup_unix_socket_handler(UnixSocketHandler *handler) { + if (handler->flags == 0xFFFFFFFFFFFFFFFF) { + return; + } + + if (handler->socket_descriptor >= 0) { + close(handler->socket_descriptor); + handler->socket_descriptor = -1; + unlink(UNIX_SOCKET_HANDLER_SOCKET_NAME); + } + handler->flags = 0xFFFFFFFFFFFFFFFF; +} + +int is_unix_socket_handler_valid(UnixSocketHandler handler) { + return handler.flags == 0xFFFFFFFFFFFFFFFF ? 0 : 1; +} diff --git a/src/socket.h b/src/socket.h new file mode 100644 index 0000000..78d1560 --- /dev/null +++ b/src/socket.h @@ -0,0 +1,42 @@ +#ifndef OBS_STUDIO_PLUGIN_UNIX_SOCKET_CONTROL_SOCKET_H_ +#define OBS_STUDIO_PLUGIN_UNIX_SOCKET_CONTROL_SOCKET_H_ + +// standard library includes +#include + +// unix includes +#include +#include + +typedef enum UnixSocketEventType { + UNIX_SOCKET_EVENT_NOP, + UNIX_SOCKET_EVENT_HEAD, + UNIX_SOCKET_EVENT_TAIL, + UNIX_SOCKET_EVENT_START_RECORDING, + UNIX_SOCKET_EVENT_STOP_RECORDING, + UNIX_SOCKET_EVENT_START_STREAMING, + UNIX_SOCKET_EVENT_STOP_STREAMING +} UnixSocketEventType; + +typedef struct UnixSocketEvent { + struct UnixSocketEvent *next; + struct UnixSocketEvent *prev; + UnixSocketEventType type; +} UnixSocketEvent; + +typedef struct UnixSocketHandler { + /* + * All ones - invalid/cleaned-up instance + */ + uint64_t flags; + UnixSocketEvent events_head; + UnixSocketEvent events_tail; + struct sockaddr_un name; + int socket_descriptor; +} UnixSocketHandler; + +UnixSocketHandler init_unix_socket_handler(void); +void cleanup_unix_socket_handler(UnixSocketHandler *handler); +int is_unix_socket_handler_valid(UnixSocketHandler handler); + +#endif