Compare commits

..

4 commits

Author SHA1 Message Date
6026bef0a0 Minor fixes
All checks were successful
Create releases with ArchLinux pkg / check-and-build-and-release (push) Successful in 1s
2024-07-21 13:05:39 +09:00
2c9f3b0452 Tweak "--wait" time max
All checks were successful
Create releases with ArchLinux pkg / check-and-build-and-release (push) Successful in 12s
2024-07-21 12:51:43 +09:00
ea6f59fbc5 Fix client arg parse
All checks were successful
Create releases with ArchLinux pkg / check-and-build-and-release (push) Successful in 12s
2024-07-21 12:45:08 +09:00
257ba1db6c Impl "--wait"
All checks were successful
Create releases with ArchLinux pkg / check-and-build-and-release (push) Successful in 15s
"--wait" causes the server to wait for the action to complete before
sending a response to the client.
2024-07-21 12:37:21 +09:00
6 changed files with 140 additions and 44 deletions

View file

@ -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}")

View file

@ -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)

View file

@ -11,7 +11,7 @@
// local includes
#include "common_constants.h"
void print_usage(char *name) {
void print_usage(const char *name) {
printf("Usage:\n");
printf(" %s\n", name);
printf(" [--start-recording \n");
@ -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) {
@ -36,37 +37,56 @@ void cleanup_data_socket(int *data_socket) {
int main(int argc, char **argv) {
UnixSocketEventType type = UNIX_SOCKET_EVENT_NOP;
if (argc == 2) {
if (strncmp(argv[1], "--start-recording", 17) == 0) {
type = UNIX_SOCKET_EVENT_START_RECORDING;
} else if (strncmp(argv[1], "--stop-recording", 16) == 0) {
type = UNIX_SOCKET_EVENT_STOP_RECORDING;
} else if (strncmp(argv[1], "--start-streaming", 17) == 0) {
type = UNIX_SOCKET_EVENT_START_STREAMING;
} else if (strncmp(argv[1], "--toggle-recording", 18) == 0) {
type = UNIX_SOCKET_EVENT_TOGGLE_RECORDING;
} else if (strncmp(argv[1], "--stop-streaming", 16) == 0) {
type = UNIX_SOCKET_EVENT_STOP_STREAMING;
} else if (strncmp(argv[1], "--toggle-streaming", 18) == 0) {
type = UNIX_SOCKET_EVENT_TOGGLE_STREAMING;
} else if (strncmp(argv[1], "--start-replay-buffer", 21) == 0) {
type = UNIX_SOCKET_EVENT_START_REPLAY_BUFFER;
} else if (strncmp(argv[1], "--stop-replay-buffer", 20) == 0) {
type = UNIX_SOCKET_EVENT_STOP_REPLAY_BUFFER;
} else if (strncmp(argv[1], "--toggle-replay-buffer", 22) == 0) {
type = UNIX_SOCKET_EVENT_TOGGLE_REPLAY_BUFFER;
} else if (strncmp(argv[1], "--save-replay-buffer", 20) == 0) {
type = UNIX_SOCKET_EVENT_SAVE_REPLAY_BUFFER;
} else if (strncmp(argv[1], "--get-status", 12) == 0) {
type = UNIX_SOCKET_EVENT_GET_STATUS;
const char *program_name = argv[0];
++argv;
--argc;
if (argc == 0) {
print_usage(program_name);
return 1;
}
while (argc != 0) {
if (strncmp(argv[0], "--start-recording", 17) == 0) {
type = UNIX_SOCKET_EVENT_START_RECORDING |
(UNIX_SOCKET_EVENT_WAIT & type);
} else if (strncmp(argv[0], "--stop-recording", 16) == 0) {
type = UNIX_SOCKET_EVENT_STOP_RECORDING |
(UNIX_SOCKET_EVENT_WAIT & type);
} else if (strncmp(argv[0], "--start-streaming", 17) == 0) {
type = UNIX_SOCKET_EVENT_START_STREAMING |
(UNIX_SOCKET_EVENT_WAIT & type);
} else if (strncmp(argv[0], "--toggle-recording", 18) == 0) {
type = UNIX_SOCKET_EVENT_TOGGLE_RECORDING |
(UNIX_SOCKET_EVENT_WAIT & type);
} else if (strncmp(argv[0], "--stop-streaming", 16) == 0) {
type = UNIX_SOCKET_EVENT_STOP_STREAMING |
(UNIX_SOCKET_EVENT_WAIT & type);
} else if (strncmp(argv[0], "--toggle-streaming", 18) == 0) {
type = UNIX_SOCKET_EVENT_TOGGLE_STREAMING |
(UNIX_SOCKET_EVENT_WAIT & type);
} else if (strncmp(argv[0], "--start-replay-buffer", 21) == 0) {
type = UNIX_SOCKET_EVENT_START_REPLAY_BUFFER |
(UNIX_SOCKET_EVENT_WAIT & type);
} else if (strncmp(argv[0], "--stop-replay-buffer", 20) == 0) {
type = UNIX_SOCKET_EVENT_STOP_REPLAY_BUFFER |
(UNIX_SOCKET_EVENT_WAIT & type);
} else if (strncmp(argv[0], "--toggle-replay-buffer", 22) == 0) {
type = UNIX_SOCKET_EVENT_TOGGLE_REPLAY_BUFFER |
(UNIX_SOCKET_EVENT_WAIT & type);
} else if (strncmp(argv[0], "--save-replay-buffer", 20) == 0) {
type = UNIX_SOCKET_EVENT_SAVE_REPLAY_BUFFER |
(UNIX_SOCKET_EVENT_WAIT & type);
} else if (strncmp(argv[0], "--get-status", 12) == 0) {
type = UNIX_SOCKET_EVENT_GET_STATUS |
(UNIX_SOCKET_EVENT_WAIT & type);
} else if (strncmp(argv[0], "--wait", 6) == 0) {
type |= UNIX_SOCKET_EVENT_WAIT;
} else {
puts("ERROR: Invalid arg!");
print_usage(argv[0]);
print_usage(program_name);
return 2;
}
} else {
print_usage(argv[0]);
return 1;
++argv;
--argc;
}
char socket_filename[108];
@ -76,7 +96,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));
@ -123,7 +143,7 @@ int main(int argc, char **argv) {
// Error. TODO handle this.
return 7;
} else {
switch(type) {
switch(type & UNIX_SOCKET_EVENT_MASK) {
case UNIX_SOCKET_EVENT_START_RECORDING:
puts("Sent event \"start recording\"!");
break;

View file

@ -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

View file

@ -16,6 +16,22 @@
// obs-studio includes
#include <obs-frontend-api.h>
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 > 5000) {
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;
}
}
}

View file

@ -4,11 +4,15 @@
// standard library includes
#include <stdint.h>
#include <threads.h>
#include <stdatomic.h>
// unix includes
#include <sys/socket.h>
#include <sys/un.h>
// third party includes
#include <obs-frontend-api.h>
// 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