diff --git a/CMakeLists.txt b/CMakeLists.txt index 575cbad..1bd6ef2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.25) set(obs_usc_VERSION_MAJOR 1) -set(obs_usc_VERSION_MINOR 3) +set(obs_usc_VERSION_MINOR 4) set(obs_usc_VERSION_PATCH 0) set(obs_usc_VERSION_STR "${obs_usc_VERSION_MAJOR}.${obs_usc_VERSION_MINOR}.${obs_usc_VERSION_PATCH}") diff --git a/archLinuxPackaging/PKGBUILD b/archLinuxPackaging/PKGBUILD index 6bfe99f..2eb7ede 100644 --- a/archLinuxPackaging/PKGBUILD +++ b/archLinuxPackaging/PKGBUILD @@ -1,5 +1,5 @@ pkgname=obs-studio-plugin-unix-socket-control -pkgver=1.3.0 +pkgver=1.4.0 pkgrel=1 pkgdesc="An obs studio plugin to command obs to start/stop recording/streaming via unix socket" arch=(x86_64) diff --git a/src/client.c b/src/client.c index d0623dc..974293c 100644 --- a/src/client.c +++ b/src/client.c @@ -25,6 +25,7 @@ void print_usage(char *name) { printf(" | --toggle-replay-buffer\n"); printf(" | --save-replay-buffer\n"); printf(" | --get-status]\n"); + printf(" --wait\n"); } void cleanup_data_socket(int *data_socket) { @@ -38,27 +39,40 @@ int main(int argc, char **argv) { if (argc == 2) { if (strncmp(argv[1], "--start-recording", 17) == 0) { - type = UNIX_SOCKET_EVENT_START_RECORDING; + type = UNIX_SOCKET_EVENT_START_RECORDING | + (UNIX_SOCKET_EVENT_WAIT & type); } else if (strncmp(argv[1], "--stop-recording", 16) == 0) { - type = UNIX_SOCKET_EVENT_STOP_RECORDING; + type = UNIX_SOCKET_EVENT_STOP_RECORDING | + (UNIX_SOCKET_EVENT_WAIT & type); } else if (strncmp(argv[1], "--start-streaming", 17) == 0) { - type = UNIX_SOCKET_EVENT_START_STREAMING; + type = UNIX_SOCKET_EVENT_START_STREAMING | + (UNIX_SOCKET_EVENT_WAIT & type); } else if (strncmp(argv[1], "--toggle-recording", 18) == 0) { - type = UNIX_SOCKET_EVENT_TOGGLE_RECORDING; + type = UNIX_SOCKET_EVENT_TOGGLE_RECORDING | + (UNIX_SOCKET_EVENT_WAIT & type); } else if (strncmp(argv[1], "--stop-streaming", 16) == 0) { - type = UNIX_SOCKET_EVENT_STOP_STREAMING; + type = UNIX_SOCKET_EVENT_STOP_STREAMING | + (UNIX_SOCKET_EVENT_WAIT & type); } else if (strncmp(argv[1], "--toggle-streaming", 18) == 0) { - type = UNIX_SOCKET_EVENT_TOGGLE_STREAMING; + type = UNIX_SOCKET_EVENT_TOGGLE_STREAMING | + (UNIX_SOCKET_EVENT_WAIT & type); } else if (strncmp(argv[1], "--start-replay-buffer", 21) == 0) { - type = UNIX_SOCKET_EVENT_START_REPLAY_BUFFER; + type = UNIX_SOCKET_EVENT_START_REPLAY_BUFFER | + (UNIX_SOCKET_EVENT_WAIT & type); } else if (strncmp(argv[1], "--stop-replay-buffer", 20) == 0) { - type = UNIX_SOCKET_EVENT_STOP_REPLAY_BUFFER; + type = UNIX_SOCKET_EVENT_STOP_REPLAY_BUFFER | + (UNIX_SOCKET_EVENT_WAIT & type); } else if (strncmp(argv[1], "--toggle-replay-buffer", 22) == 0) { - type = UNIX_SOCKET_EVENT_TOGGLE_REPLAY_BUFFER; + type = UNIX_SOCKET_EVENT_TOGGLE_REPLAY_BUFFER | + (UNIX_SOCKET_EVENT_WAIT & type); } else if (strncmp(argv[1], "--save-replay-buffer", 20) == 0) { - type = UNIX_SOCKET_EVENT_SAVE_REPLAY_BUFFER; + type = UNIX_SOCKET_EVENT_SAVE_REPLAY_BUFFER | + (UNIX_SOCKET_EVENT_WAIT & type); } else if (strncmp(argv[1], "--get-status", 12) == 0) { - type = UNIX_SOCKET_EVENT_GET_STATUS; + type = UNIX_SOCKET_EVENT_GET_STATUS | + (UNIX_SOCKET_EVENT_WAIT & type); + } else if (strncmp(argv[1], "--wait", 6) == 0) { + type |= UNIX_SOCKET_EVENT_WAIT; } else { puts("ERROR: Invalid arg!"); print_usage(argv[0]); @@ -76,7 +90,7 @@ int main(int argc, char **argv) { struct sockaddr_un addr; int ret; __attribute__((cleanup(cleanup_data_socket))) int data_socket = -1; - char send_buf = (char)type; + unsigned char send_buf = (unsigned char)type; char buffer[8]; memset(buffer, 0, sizeof(buffer)); diff --git a/src/common_constants.h b/src/common_constants.h index f2c3e44..fa5b7bc 100644 --- a/src/common_constants.h +++ b/src/common_constants.h @@ -15,7 +15,9 @@ typedef enum UnixSocketEventType { UNIX_SOCKET_EVENT_SAVE_REPLAY_BUFFER, UNIX_SOCKET_EVENT_TOGGLE_RECORDING, UNIX_SOCKET_EVENT_TOGGLE_STREAMING, - UNIX_SOCKET_EVENT_TOGGLE_REPLAY_BUFFER + UNIX_SOCKET_EVENT_TOGGLE_REPLAY_BUFFER, + UNIX_SOCKET_EVENT_WAIT = 0x80, + UNIX_SOCKET_EVENT_MASK = 0x7F } UnixSocketEventType; #endif diff --git a/src/socket.c b/src/socket.c index 70f00ba..be5d23b 100644 --- a/src/socket.c +++ b/src/socket.c @@ -16,6 +16,22 @@ // obs-studio includes #include +void internal_wait_on_obs_frontend_event(UnixSocketHandler *handler, UnixSocketEventType event) { + if (is_unix_socket_handler_valid(handler) && (event & UNIX_SOCKET_EVENT_WAIT) != 0) { + struct timespec duration; + duration.tv_sec = 0; + duration.tv_nsec = 1000000; + unsigned int ticks = 0; + while(atomic_load(&handler->callback_var) != (event & UNIX_SOCKET_EVENT_MASK)) { + if (++ticks > 1400) { + break; + } else { + thrd_sleep(&duration, 0); + } + } + } +} + int unix_socket_handler_thread_function(void *ud) { UnixSocketHandler *handler = (UnixSocketHandler*)ud; @@ -57,6 +73,8 @@ int unix_socket_handler_thread_function(void *ud) { } mtx_unlock(handler->mutex); + atomic_store(&handler->callback_var, 0); + ret = read(data_socket, buffer, sizeof(buffer)); if (ret == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { @@ -72,37 +90,45 @@ int unix_socket_handler_thread_function(void *ud) { break; } - if (buffer[0] == UNIX_SOCKET_EVENT_START_RECORDING) { + if ((buffer[0] & UNIX_SOCKET_EVENT_MASK) == UNIX_SOCKET_EVENT_START_RECORDING) { obs_frontend_recording_start(); + internal_wait_on_obs_frontend_event(handler, buffer[0]); ret_buffer[0] = UNIX_SOCKET_EVENT_NOP; - } else if (buffer[0] == UNIX_SOCKET_EVENT_STOP_RECORDING) { + } else if ((buffer[0] & UNIX_SOCKET_EVENT_MASK) == UNIX_SOCKET_EVENT_STOP_RECORDING) { obs_frontend_recording_stop(); + internal_wait_on_obs_frontend_event(handler, buffer[0]); ret_buffer[0] = UNIX_SOCKET_EVENT_NOP; - } else if (buffer[0] == UNIX_SOCKET_EVENT_TOGGLE_RECORDING) { + } else if ((buffer[0] & UNIX_SOCKET_EVENT_MASK) == UNIX_SOCKET_EVENT_TOGGLE_RECORDING) { ret_buffer[0] = UNIX_SOCKET_EVENT_TOGGLE_RECORDING; if (obs_frontend_recording_active()) { obs_frontend_recording_stop(); + internal_wait_on_obs_frontend_event(handler, UNIX_SOCKET_EVENT_STOP_RECORDING | (buffer[0] & UNIX_SOCKET_EVENT_WAIT)); ret_buffer[1] = UNIX_SOCKET_EVENT_STOP_RECORDING; } else { obs_frontend_recording_start(); + internal_wait_on_obs_frontend_event(handler, UNIX_SOCKET_EVENT_START_RECORDING | (buffer[0] & UNIX_SOCKET_EVENT_WAIT)); ret_buffer[1] = UNIX_SOCKET_EVENT_START_RECORDING; } - } else if (buffer[0] == UNIX_SOCKET_EVENT_START_STREAMING) { + } else if ((buffer[0] & UNIX_SOCKET_EVENT_MASK) == UNIX_SOCKET_EVENT_START_STREAMING) { obs_frontend_streaming_start(); + internal_wait_on_obs_frontend_event(handler, buffer[0]); ret_buffer[0] = UNIX_SOCKET_EVENT_NOP; - } else if (buffer[0] == UNIX_SOCKET_EVENT_STOP_STREAMING) { + } else if ((buffer[0] & UNIX_SOCKET_EVENT_MASK) == UNIX_SOCKET_EVENT_STOP_STREAMING) { obs_frontend_streaming_stop(); + internal_wait_on_obs_frontend_event(handler, buffer[0]); ret_buffer[0] = UNIX_SOCKET_EVENT_NOP; - } else if (buffer[0] == UNIX_SOCKET_EVENT_TOGGLE_STREAMING) { + } else if ((buffer[0] & UNIX_SOCKET_EVENT_MASK) == UNIX_SOCKET_EVENT_TOGGLE_STREAMING) { ret_buffer[0] = UNIX_SOCKET_EVENT_TOGGLE_STREAMING; if (obs_frontend_streaming_active()) { obs_frontend_streaming_stop(); + internal_wait_on_obs_frontend_event(handler, UNIX_SOCKET_EVENT_STOP_STREAMING | (buffer[0] & UNIX_SOCKET_EVENT_WAIT)); ret_buffer[1] = UNIX_SOCKET_EVENT_STOP_STREAMING; } else { obs_frontend_streaming_start(); + internal_wait_on_obs_frontend_event(handler, UNIX_SOCKET_EVENT_START_STREAMING | (buffer[0] & UNIX_SOCKET_EVENT_WAIT)); ret_buffer[1] = UNIX_SOCKET_EVENT_START_STREAMING; } - } else if (buffer[0] == UNIX_SOCKET_EVENT_GET_STATUS) { + } else if ((buffer[0] & UNIX_SOCKET_EVENT_MASK) == UNIX_SOCKET_EVENT_GET_STATUS) { ret_buffer[0] = UNIX_SOCKET_EVENT_GET_STATUS; if (obs_frontend_recording_active()) { ret_buffer[1] |= 1; @@ -113,24 +139,29 @@ int unix_socket_handler_thread_function(void *ud) { if (obs_frontend_replay_buffer_active()) { ret_buffer[1] |= 4; } - } else if (buffer[0] == UNIX_SOCKET_EVENT_START_REPLAY_BUFFER) { + } else if ((buffer[0] & UNIX_SOCKET_EVENT_MASK) == UNIX_SOCKET_EVENT_START_REPLAY_BUFFER) { obs_frontend_replay_buffer_start(); + internal_wait_on_obs_frontend_event(handler, buffer[0]); ret_buffer[0] = UNIX_SOCKET_EVENT_NOP; - } else if (buffer[0] == UNIX_SOCKET_EVENT_STOP_REPLAY_BUFFER) { + } else if ((buffer[0] & UNIX_SOCKET_EVENT_MASK) == UNIX_SOCKET_EVENT_STOP_REPLAY_BUFFER) { obs_frontend_replay_buffer_stop(); + internal_wait_on_obs_frontend_event(handler, buffer[0]); ret_buffer[0] = UNIX_SOCKET_EVENT_NOP; - } else if (buffer[0] == UNIX_SOCKET_EVENT_TOGGLE_REPLAY_BUFFER) { + } else if ((buffer[0] & UNIX_SOCKET_EVENT_MASK) == UNIX_SOCKET_EVENT_TOGGLE_REPLAY_BUFFER) { ret_buffer[0] = UNIX_SOCKET_EVENT_TOGGLE_REPLAY_BUFFER; if (obs_frontend_replay_buffer_active()) { obs_frontend_replay_buffer_stop(); + internal_wait_on_obs_frontend_event(handler, UNIX_SOCKET_EVENT_STOP_REPLAY_BUFFER | (buffer[0] & UNIX_SOCKET_EVENT_WAIT)); ret_buffer[1] = UNIX_SOCKET_EVENT_STOP_REPLAY_BUFFER; } else { obs_frontend_replay_buffer_start(); + internal_wait_on_obs_frontend_event(handler, UNIX_SOCKET_EVENT_START_REPLAY_BUFFER | (buffer[0] & UNIX_SOCKET_EVENT_WAIT)); ret_buffer[1] = UNIX_SOCKET_EVENT_START_REPLAY_BUFFER; } - } else if (buffer[0] == UNIX_SOCKET_EVENT_SAVE_REPLAY_BUFFER) { + } else if ((buffer[0] & UNIX_SOCKET_EVENT_MASK) == UNIX_SOCKET_EVENT_SAVE_REPLAY_BUFFER) { if (obs_frontend_replay_buffer_active()) { obs_frontend_replay_buffer_save(); + internal_wait_on_obs_frontend_event(handler, buffer[0]); ret_buffer[0] = UNIX_SOCKET_EVENT_NOP; } else { ret = -1; @@ -164,6 +195,11 @@ void init_unix_socket_handler(UnixSocketHandler *handler) { umask(S_IRWXO); + // Set up atomic value. + atomic_init(&handler->callback_var, 0); + + obs_frontend_add_event_callback(unix_socket_handler_frontend_event_callback, handler); + // Set up unix socket. handler->socket_descriptor = socket(AF_UNIX, SOCK_SEQPACKET, 0); if (handler->socket_descriptor == -1) { @@ -266,3 +302,35 @@ void cleanup_unix_socket_handler(UnixSocketHandler *handler) { int is_unix_socket_handler_valid(const UnixSocketHandler *handler) { return handler->flags == 0xFFFFFFFFFFFFFFFF ? 0 : 1; } + +void unix_socket_handler_frontend_event_callback(enum obs_frontend_event event, + void *ud) { + UnixSocketHandler *handler = ud; + if (is_unix_socket_handler_valid(handler)) { + switch (event) { + case OBS_FRONTEND_EVENT_RECORDING_STARTED: + atomic_store(&handler->callback_var, UNIX_SOCKET_EVENT_START_RECORDING); + break; + case OBS_FRONTEND_EVENT_RECORDING_STOPPED: + atomic_store(&handler->callback_var, UNIX_SOCKET_EVENT_STOP_RECORDING); + break; + case OBS_FRONTEND_EVENT_STREAMING_STARTED: + atomic_store(&handler->callback_var, UNIX_SOCKET_EVENT_START_STREAMING); + break; + case OBS_FRONTEND_EVENT_STREAMING_STOPPED: + atomic_store(&handler->callback_var, UNIX_SOCKET_EVENT_STOP_STREAMING); + break; + case OBS_FRONTEND_EVENT_REPLAY_BUFFER_STARTED: + atomic_store(&handler->callback_var, UNIX_SOCKET_EVENT_START_REPLAY_BUFFER); + break; + case OBS_FRONTEND_EVENT_REPLAY_BUFFER_STOPPED: + atomic_store(&handler->callback_var, UNIX_SOCKET_EVENT_STOP_REPLAY_BUFFER); + break; + case OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED: + atomic_store(&handler->callback_var, UNIX_SOCKET_EVENT_SAVE_REPLAY_BUFFER); + break; + default: + break; + } + } +} diff --git a/src/socket.h b/src/socket.h index 72d4fb2..324fe55 100644 --- a/src/socket.h +++ b/src/socket.h @@ -4,11 +4,15 @@ // standard library includes #include #include +#include // unix includes #include #include +// third party includes +#include + // local includes #include "common_constants.h" @@ -20,6 +24,7 @@ typedef struct UnixSocketHandler { struct sockaddr_un name; thrd_t *thread; mtx_t *mutex; + atomic_uint callback_var; /* * ???? 0001 - thread should stop */ @@ -32,5 +37,6 @@ typedef struct UnixSocketHandler { void init_unix_socket_handler(UnixSocketHandler *handler); void cleanup_unix_socket_handler(UnixSocketHandler *handler); int is_unix_socket_handler_valid(const UnixSocketHandler *handler); +void unix_socket_handler_frontend_event_callback(enum obs_frontend_event event, void *ud); #endif