WIP: Impl. "server" plugin and "client" executable
Untested.
This commit is contained in:
parent
c850536731
commit
99fab95766
6 changed files with 278 additions and 45 deletions
|
@ -21,3 +21,5 @@ add_library(unix-socket-control MODULE
|
||||||
|
|
||||||
find_package(libobs REQUIRED)
|
find_package(libobs REQUIRED)
|
||||||
target_link_libraries(unix-socket-control PRIVATE OBS::libobs)
|
target_link_libraries(unix-socket-control PRIVATE OBS::libobs)
|
||||||
|
|
||||||
|
add_executable(unix-socket-control-client src/client.c)
|
||||||
|
|
119
src/client.c
Normal file
119
src/client.c
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
// standard library includes
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// unix includes
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
// local includes
|
||||||
|
#include "common_constants.h"
|
||||||
|
|
||||||
|
void print_usage(char *name) {
|
||||||
|
printf("Usage:\n");
|
||||||
|
printf(" %s\n", name);
|
||||||
|
printf(" [--start-recording \n");
|
||||||
|
printf(" | --stop-recording\n");
|
||||||
|
printf(" | --start-streaming\n");
|
||||||
|
printf(" | --stop-streaming\n");
|
||||||
|
printf(" | --get-status]\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup_data_socket(int *data_socket) {
|
||||||
|
if (*data_socket >= 0) {
|
||||||
|
close(*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], "--stop-streaming", 16) == 0) {
|
||||||
|
type = UNIX_SOCKET_EVENT_STOP_STREAMING;
|
||||||
|
} else if (strncmp(argv[1], "--get-status", 12) == 0) {
|
||||||
|
type = UNIX_SOCKET_EVENT_GET_STATUS;
|
||||||
|
} else {
|
||||||
|
puts("ERROR: Invalid arg!");
|
||||||
|
print_usage(argv[0]);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print_usage(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_un addr;
|
||||||
|
int ret;
|
||||||
|
__attribute__((cleanup(cleanup_data_socket))) int data_socket = -1;
|
||||||
|
char send_buf = (char)type;
|
||||||
|
char buffer[8];
|
||||||
|
|
||||||
|
memset(buffer, 0, sizeof(buffer));
|
||||||
|
|
||||||
|
data_socket = socket(AF_UNIX, SOCK_SEQPACKET, 0);
|
||||||
|
if (data_socket == -1) {
|
||||||
|
// Error. TODO handle this.
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&addr, 0, sizeof(addr));
|
||||||
|
|
||||||
|
addr.sun_family = AF_UNIX;
|
||||||
|
strncpy(addr.sun_path,
|
||||||
|
UNIX_SOCKET_HANDLER_SOCKET_NAME,
|
||||||
|
sizeof(addr.sun_path) - 1);
|
||||||
|
|
||||||
|
ret = connect(data_socket, (const struct sockaddr*) &addr, sizeof(addr));
|
||||||
|
if (ret == -1) {
|
||||||
|
// Error. TODO handle this.
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = write(data_socket, &send_buf, 1);
|
||||||
|
if (ret == -1) {
|
||||||
|
// Error. TODO handle this.
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = read(data_socket, buffer, sizeof(buffer));
|
||||||
|
if (ret == -1 || ret < 8) {
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == UNIX_SOCKET_EVENT_GET_STATUS && buffer[0] == UNIX_SOCKET_EVENT_GET_STATUS) {
|
||||||
|
printf("Is recording: %s\nIs streaming: %s\n",
|
||||||
|
(buffer[1] & 1) != 0 ? "true" : "false",
|
||||||
|
(buffer[1] & 2) != 0 ? "true" : "false");
|
||||||
|
} else if (buffer[0] != UNIX_SOCKET_EVENT_NOP) {
|
||||||
|
// Error. TODO handle this.
|
||||||
|
return 7;
|
||||||
|
} else {
|
||||||
|
switch(type) {
|
||||||
|
case UNIX_SOCKET_EVENT_START_RECORDING:
|
||||||
|
puts("Sent event \"start recording\"!");
|
||||||
|
break;
|
||||||
|
case UNIX_SOCKET_EVENT_STOP_RECORDING:
|
||||||
|
puts("Sent event \"stop recording\"!");
|
||||||
|
break;
|
||||||
|
case UNIX_SOCKET_EVENT_START_STREAMING:
|
||||||
|
puts("Sent event \"start streaming\"!");
|
||||||
|
break;
|
||||||
|
case UNIX_SOCKET_EVENT_STOP_STREAMING:
|
||||||
|
puts("Sent event \"stop streaming\"!");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Error. TODO handle this
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
15
src/common_constants.h
Normal file
15
src/common_constants.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef OBS_STUDIO_PLUGIN_UNIX_SOCKET_CONTROL_COMMON_CONSTANTS_H_
|
||||||
|
#define OBS_STUDIO_PLUGIN_UNIX_SOCKET_CONTROL_COMMON_CONSTANTS_H_
|
||||||
|
|
||||||
|
#define UNIX_SOCKET_HANDLER_SOCKET_NAME "/tmp/obs-studio-plugin-unix-socket-handler-socket"
|
||||||
|
|
||||||
|
typedef enum UnixSocketEventType {
|
||||||
|
UNIX_SOCKET_EVENT_NOP = 0,
|
||||||
|
UNIX_SOCKET_EVENT_START_RECORDING,
|
||||||
|
UNIX_SOCKET_EVENT_STOP_RECORDING,
|
||||||
|
UNIX_SOCKET_EVENT_START_STREAMING,
|
||||||
|
UNIX_SOCKET_EVENT_STOP_STREAMING,
|
||||||
|
UNIX_SOCKET_EVENT_GET_STATUS
|
||||||
|
} UnixSocketEventType;
|
||||||
|
|
||||||
|
#endif
|
|
@ -14,7 +14,7 @@ OBS_DECLARE_MODULE()
|
||||||
OBS_MODULE_USE_DEFAULT_LOCALE("unix-socket-control", "en-US")
|
OBS_MODULE_USE_DEFAULT_LOCALE("unix-socket-control", "en-US")
|
||||||
|
|
||||||
bool obs_module_load(void) {
|
bool obs_module_load(void) {
|
||||||
global_unix_socket_handler = init_unix_socket_handler();
|
init_unix_socket_handler(&global_unix_socket_handler);
|
||||||
|
|
||||||
return is_unix_socket_handler_valid(global_unix_socket_handler) ? true : false;
|
return is_unix_socket_handler_valid(global_unix_socket_handler) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
156
src/socket.c
156
src/socket.c
|
@ -6,47 +6,137 @@
|
||||||
// unix includes
|
// unix includes
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <threads.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define UNIX_SOCKET_HANDLER_SOCKET_NAME "/tmp/obs-studio-plugin-unix-socket-handler-socket"
|
// obs-studio includes
|
||||||
|
#include <obs-frontend-api.h>
|
||||||
|
|
||||||
UnixSocketHandler init_unix_socket_handler(void) {
|
int unix_socket_handler_thread_function(void *ud) {
|
||||||
UnixSocketHandler handler;
|
UnixSocketHandler *handler = (UnixSocketHandler*)ud;
|
||||||
|
|
||||||
memset(&handler, 0, sizeof(UnixSocketHandler));
|
int ret;
|
||||||
|
int data_socket;
|
||||||
|
char buffer[8];
|
||||||
|
char ret_buffer[8];
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
mtx_lock(handler->mutex);
|
||||||
|
if ((handler->ccflags & 1) != 0) {
|
||||||
|
mtx_unlock(handler->mutex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mtx_unlock(handler->mutex);
|
||||||
|
|
||||||
|
data_socket = accept(handler->socket_descriptor, 0, 0);
|
||||||
|
if (data_socket == -1) {
|
||||||
|
// Error. TODO handle this.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(ret_buffer, 0, sizeof(ret_buffer));
|
||||||
|
|
||||||
|
ret = read(data_socket, buffer, sizeof(buffer));
|
||||||
|
if (ret == -1) {
|
||||||
|
// Error. TODO handle this.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer[0] == UNIX_SOCKET_EVENT_START_RECORDING) {
|
||||||
|
obs_frontend_recording_start();
|
||||||
|
ret_buffer[0] = UNIX_SOCKET_EVENT_NOP;
|
||||||
|
} else if (buffer[0] == UNIX_SOCKET_EVENT_STOP_RECORDING) {
|
||||||
|
obs_frontend_recording_stop();
|
||||||
|
ret_buffer[0] = UNIX_SOCKET_EVENT_NOP;
|
||||||
|
} else if (buffer[0] == UNIX_SOCKET_EVENT_START_STREAMING) {
|
||||||
|
obs_frontend_streaming_start();
|
||||||
|
ret_buffer[0] = UNIX_SOCKET_EVENT_NOP;
|
||||||
|
} else if (buffer[0] == UNIX_SOCKET_EVENT_STOP_STREAMING) {
|
||||||
|
obs_frontend_streaming_stop();
|
||||||
|
ret_buffer[0] = UNIX_SOCKET_EVENT_NOP;
|
||||||
|
} else if (buffer[0] == UNIX_SOCKET_EVENT_GET_STATUS) {
|
||||||
|
ret_buffer[0] = UNIX_SOCKET_EVENT_GET_STATUS;
|
||||||
|
if (obs_frontend_recording_active()) {
|
||||||
|
ret_buffer[1] |= 1;
|
||||||
|
}
|
||||||
|
if (obs_frontend_streaming_active()) {
|
||||||
|
ret_buffer[1] |= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = write(data_socket, ret_buffer, sizeof(ret_buffer));
|
||||||
|
if (ret == -1) {
|
||||||
|
// Error. TODO handle this.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(data_socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_unix_socket_handler(UnixSocketHandler *handler) {
|
||||||
|
memset(handler, 0, sizeof(UnixSocketHandler));
|
||||||
|
|
||||||
umask(S_IRWXO);
|
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.
|
// Set up unix socket.
|
||||||
handler.socket_descriptor = socket(AF_UNIX, SOCK_SEQPACKET, 0);
|
handler->socket_descriptor = socket(AF_UNIX, SOCK_SEQPACKET, 0);
|
||||||
if (handler.socket_descriptor == -1) {
|
if (handler->socket_descriptor == -1) {
|
||||||
handler.flags = 0xFFFFFFFFFFFFFFFF;
|
handler->flags = 0xFFFFFFFFFFFFFFFF;
|
||||||
return handler;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
handler.name.sun_family = AF_UNIX;
|
handler->name.sun_family = AF_UNIX;
|
||||||
strncpy(handler.name.sun_path,
|
strncpy(handler->name.sun_path,
|
||||||
UNIX_SOCKET_HANDLER_SOCKET_NAME,
|
UNIX_SOCKET_HANDLER_SOCKET_NAME,
|
||||||
sizeof(handler.name.sun_path) - 1);
|
sizeof(handler->name.sun_path) - 1);
|
||||||
|
|
||||||
int ret = bind(handler.socket_descriptor,
|
int ret = bind(handler->socket_descriptor,
|
||||||
(const struct sockaddr*) &handler.name,
|
(const struct sockaddr*) &handler->name,
|
||||||
sizeof(handler.name));
|
sizeof(handler->name));
|
||||||
if (ret == -1) {
|
if (ret == -1) {
|
||||||
close(handler.socket_descriptor);
|
close(handler->socket_descriptor);
|
||||||
handler.socket_descriptor = -1;
|
handler->socket_descriptor = -1;
|
||||||
handler.flags = 0xFFFFFFFFFFFFFFFF;
|
handler->flags = 0xFFFFFFFFFFFFFFFF;
|
||||||
return handler;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return handler;
|
ret = listen(handler->socket_descriptor, 20);
|
||||||
|
if (ret == -1) {
|
||||||
|
close(handler->socket_descriptor);
|
||||||
|
handler->socket_descriptor = -1;
|
||||||
|
unlink(UNIX_SOCKET_HANDLER_SOCKET_NAME);
|
||||||
|
handler->flags = 0xFFFFFFFFFFFFFFFF;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up concurrency.
|
||||||
|
handler->mutex = malloc(sizeof(mtx_t));
|
||||||
|
ret = mtx_init(handler->mutex, mtx_plain);
|
||||||
|
if (ret != thrd_success) {
|
||||||
|
close(handler->socket_descriptor);
|
||||||
|
handler->socket_descriptor = -1;
|
||||||
|
unlink(UNIX_SOCKET_HANDLER_SOCKET_NAME);
|
||||||
|
handler->flags = 0xFFFFFFFFFFFFFFFF;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
handler->thread = malloc(sizeof(thrd_t));
|
||||||
|
ret = thrd_create(handler->thread,
|
||||||
|
unix_socket_handler_thread_function,
|
||||||
|
handler);
|
||||||
|
if (ret != thrd_success) {
|
||||||
|
close(handler->socket_descriptor);
|
||||||
|
handler->socket_descriptor = -1;
|
||||||
|
unlink(UNIX_SOCKET_HANDLER_SOCKET_NAME);
|
||||||
|
mtx_destroy(handler->mutex);
|
||||||
|
handler->flags = 0xFFFFFFFFFFFFFFFF;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_unix_socket_handler(UnixSocketHandler *handler) {
|
void cleanup_unix_socket_handler(UnixSocketHandler *handler) {
|
||||||
|
@ -59,6 +149,20 @@ void cleanup_unix_socket_handler(UnixSocketHandler *handler) {
|
||||||
handler->socket_descriptor = -1;
|
handler->socket_descriptor = -1;
|
||||||
unlink(UNIX_SOCKET_HANDLER_SOCKET_NAME);
|
unlink(UNIX_SOCKET_HANDLER_SOCKET_NAME);
|
||||||
}
|
}
|
||||||
|
if (handler->mutex) {
|
||||||
|
mtx_lock(handler->mutex);
|
||||||
|
handler->ccflags |= 1;
|
||||||
|
mtx_unlock(handler->mutex);
|
||||||
|
thrd_join(*handler->thread, 0);
|
||||||
|
|
||||||
|
free(handler->thread);
|
||||||
|
handler->thread = 0;
|
||||||
|
|
||||||
|
mtx_destroy(handler->mutex);
|
||||||
|
free(handler->mutex);
|
||||||
|
handler->mutex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
handler->flags = 0xFFFFFFFFFFFFFFFF;
|
handler->flags = 0xFFFFFFFFFFFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
29
src/socket.h
29
src/socket.h
|
@ -3,39 +3,32 @@
|
||||||
|
|
||||||
// standard library includes
|
// standard library includes
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <threads.h>
|
||||||
|
|
||||||
// unix includes
|
// unix includes
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
|
||||||
typedef enum UnixSocketEventType {
|
// local includes
|
||||||
UNIX_SOCKET_EVENT_NOP,
|
#include "common_constants.h"
|
||||||
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 {
|
typedef struct UnixSocketHandler {
|
||||||
/*
|
/*
|
||||||
* All ones - invalid/cleaned-up instance
|
* All ones - invalid/cleaned-up instance
|
||||||
*/
|
*/
|
||||||
uint64_t flags;
|
uint64_t flags;
|
||||||
UnixSocketEvent events_head;
|
|
||||||
UnixSocketEvent events_tail;
|
|
||||||
struct sockaddr_un name;
|
struct sockaddr_un name;
|
||||||
|
thrd_t *thread;
|
||||||
|
mtx_t *mutex;
|
||||||
|
/*
|
||||||
|
* ???? 0001 - thread should stop
|
||||||
|
*/
|
||||||
|
volatile uint64_t ccflags;
|
||||||
|
|
||||||
int socket_descriptor;
|
int socket_descriptor;
|
||||||
} UnixSocketHandler;
|
} UnixSocketHandler;
|
||||||
|
|
||||||
UnixSocketHandler init_unix_socket_handler(void);
|
void init_unix_socket_handler(UnixSocketHandler *handler);
|
||||||
void cleanup_unix_socket_handler(UnixSocketHandler *handler);
|
void cleanup_unix_socket_handler(UnixSocketHandler *handler);
|
||||||
int is_unix_socket_handler_valid(UnixSocketHandler handler);
|
int is_unix_socket_handler_valid(UnixSocketHandler handler);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue