diff --git a/CMakeLists.txt b/CMakeLists.txt index 24ffb02..23c69e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,6 @@ # --- Detect if the plugin is build out of tree or not --- if(CMAKE_PROJECT_NAME STREQUAL "obs-studio") set(BUILD_OUT_OF_TREE OFF) - if(OBS_CMAKE_VERSION VERSION_GREATER_EQUAL 3.0.0) - legacy_check() - endif() else() set(BUILD_OUT_OF_TREE ON) cmake_minimum_required(VERSION 3.18) @@ -60,7 +57,8 @@ if(OS_WINDOWS) nvidia-move-filter.c) target_link_libraries(${PROJECT_NAME} strmiids - w32-pthreads) + w32-pthreads + ws2_32) elseif(OS_MACOS) set(MACOS_BUNDLEID "com.exeldro.${PROJECT_NAME}") set(MACOSX_PLUGIN_GUI_IDENTIFIER "${MACOS_BUNDLEID}") diff --git a/move-action-filter.c b/move-action-filter.c index b33b969..0f05536 100644 --- a/move-action-filter.c +++ b/move-action-filter.c @@ -1,6 +1,19 @@ #include "move-transition.h" #include "obs-frontend-api.h" +#ifdef _WIN32 +#include +#include +#include +#else +#include +#include +#include +#include +#define SOCKET int +#define closesocket(s) close(s) +#endif + #define MOVE_ACTION_NONE 0 #define MOVE_ACTION_FRONTEND 1 #define MOVE_ACTION_SOURCE_HOTKEY 2 @@ -10,6 +23,7 @@ #define MOVE_ACTION_SOURCE_MUTE 6 #define MOVE_ACTION_SOURCE_AUDIO_TRACK 7 #define MOVE_ACTION_SETTING 8 +#define MOVE_ACTION_UDP_PACKET 9 #define MOVE_ACTION_ENABLE 0 #define MOVE_ACTION_DISABLE 1 @@ -38,6 +52,9 @@ struct move_action_action { char *value_string; long long value_int; double value_float; + char *udp_host; + int udp_port; + char *udp_packet; }; struct move_action_info { @@ -171,6 +188,51 @@ void move_action_update(void *data, obs_data_t *settings) move_action->end_action.hotkey_name = NULL; changed = true; } + + if (start_action == MOVE_ACTION_UDP_PACKET) { + const char *udp_host = obs_data_get_string(settings, "udp_host"); + if (!move_action->start_action.udp_host || strcmp(udp_host, move_action->start_action.udp_host) != 0) { + bfree(move_action->start_action.udp_host); + move_action->start_action.udp_host = bstrdup(udp_host); + changed = true; + } + move_action->start_action.udp_port = (int)obs_data_get_int(settings, "udp_port"); + const char *udp_packet = obs_data_get_string(settings, "udp_packet"); + if (!move_action->start_action.udp_packet || strcmp(udp_packet, move_action->start_action.udp_packet) != 0) { + bfree(move_action->start_action.udp_packet); + move_action->start_action.udp_packet = bstrdup(udp_packet); + changed = true; + } + } else if (move_action->start_action.udp_host || move_action->start_action.udp_packet) { + bfree(move_action->start_action.udp_host); + move_action->start_action.udp_host = NULL; + bfree(move_action->start_action.udp_packet); + move_action->start_action.udp_packet = NULL; + changed = true; + } + + if (end_action == MOVE_ACTION_UDP_PACKET) { + const char *udp_host = obs_data_get_string(settings, "end_udp_host"); + if (!move_action->end_action.udp_host || strcmp(udp_host, move_action->end_action.udp_host) != 0) { + bfree(move_action->end_action.udp_host); + move_action->end_action.udp_host = bstrdup(udp_host); + changed = true; + } + move_action->end_action.udp_port = (int)obs_data_get_int(settings, "end_udp_port"); + const char *udp_packet = obs_data_get_string(settings, "end_udp_packet"); + if (!move_action->end_action.udp_packet || strcmp(udp_packet, move_action->end_action.udp_packet) != 0) { + bfree(move_action->end_action.udp_packet); + move_action->end_action.udp_packet = bstrdup(udp_packet); + changed = true; + } + } else if (move_action->end_action.udp_host || move_action->end_action.udp_packet) { + bfree(move_action->end_action.udp_host); + move_action->end_action.udp_host = NULL; + bfree(move_action->end_action.udp_packet); + move_action->end_action.udp_packet = NULL; + changed = true; + } + if (changed) { move_action->start_action.hotkey_id = OBS_INVALID_HOTKEY_ID; if (move_action->start_action.hotkey_name && strlen(move_action->start_action.hotkey_name)) { @@ -406,6 +468,8 @@ static void move_action_actual_destroy(void *data) bfree(move_action->start_action.filter_name); bfree(move_action->start_action.setting_name); bfree(move_action->start_action.value_string); + bfree(move_action->start_action.udp_host); + bfree(move_action->start_action.udp_packet); bfree(move_action->end_action.source_name); bfree(move_action->end_action.hotkey_name); bfree(move_action->end_action.scene_name); @@ -413,6 +477,8 @@ static void move_action_actual_destroy(void *data) bfree(move_action->end_action.filter_name); bfree(move_action->end_action.setting_name); bfree(move_action->end_action.value_string); + bfree(move_action->end_action.udp_host); + bfree(move_action->end_action.udp_packet); bfree(move_action); } @@ -596,7 +662,7 @@ static bool move_action_setting_changed(void *data, obs_properties_t *props, obs obs_property_float_step(p)); } else if (setting_type == OBS_PROPERTY_INT) { obs_property_int_set_limits(value_int, obs_property_int_min(p), obs_property_int_max(p), - obs_property_int_step(p)); + obs_property_int_step(p)); } } obs_properties_destroy(ps); @@ -764,6 +830,14 @@ static bool move_action_action_changed(obs_properties_t *props, obs_property_t * (action == MOVE_ACTION_SETTING && obs_data_get_int(settings, "setting_type") == OBS_PROPERTY_BOOL)); + move_action_setting_changed(NULL, props, property, settings); + + obs_property_t *udp_host = obs_properties_get(props, "udp_host"); + obs_property_set_visible(udp_host, action == MOVE_ACTION_UDP_PACKET); + obs_property_t *udp_port = obs_properties_get(props, "udp_port"); + obs_property_set_visible(udp_port, action == MOVE_ACTION_UDP_PACKET); + obs_property_t *udp_packet = obs_properties_get(props, "udp_packet"); + obs_property_set_visible(udp_packet, action == MOVE_ACTION_UDP_PACKET); return true; } @@ -818,6 +892,14 @@ static bool move_action_end_action_changed(obs_properties_t *props, obs_property (action == MOVE_ACTION_SETTING && obs_data_get_int(settings, "end_setting_type") == OBS_PROPERTY_BOOL)); + move_action_end_setting_changed(NULL, props, property, settings); + + obs_property_t *udp_host = obs_properties_get(props, "end_udp_host"); + obs_property_set_visible(udp_host, action == MOVE_ACTION_UDP_PACKET); + obs_property_t *udp_port = obs_properties_get(props, "end_udp_port"); + obs_property_set_visible(udp_port, action == MOVE_ACTION_UDP_PACKET); + obs_property_t *udp_packet = obs_properties_get(props, "end_udp_packet"); + obs_property_set_visible(udp_packet, action == MOVE_ACTION_UDP_PACKET); return true; } @@ -889,6 +971,7 @@ static obs_properties_t *move_action_properties(void *data) obs_property_list_add_int(p, obs_module_text("FilterEnable"), MOVE_ACTION_FILTER_ENABLE); obs_property_list_add_int(p, obs_module_text("FrontendHotkey"), MOVE_ACTION_FRONTEND_HOTKEY); obs_property_list_add_int(p, obs_module_text("Setting"), MOVE_ACTION_SETTING); + obs_property_list_add_int(p, obs_module_text("UdpPacket"), MOVE_ACTION_UDP_PACKET); obs_property_set_modified_callback(p, move_action_action_changed); p = obs_properties_add_list(start_action, "scene", obs_module_text("Scene"), OBS_COMBO_TYPE_EDITABLE, @@ -916,7 +999,11 @@ static obs_properties_t *move_action_properties(void *data) obs_properties_add_float(start_action, "value_double", obs_module_text("Value"), 0.0, 0.0, 1.0); obs_properties_add_int(start_action, "value_int", obs_module_text("Value"), 0, 0, 1); obs_properties_add_color_alpha(start_action, "value_color", obs_module_text("Value")); - obs_properties_add_text(start_action, "value_string", obs_module_text("Value"), OBS_TEXT_MULTILINE); //OBS_TEXT_DEFAULT); + obs_properties_add_text(start_action, "value_string", obs_module_text("Value"), OBS_TEXT_MULTILINE); + + obs_properties_add_text(start_action, "udp_host", obs_module_text("UdpHost"), OBS_TEXT_DEFAULT); + obs_properties_add_int(start_action, "udp_port", obs_module_text("UdpPort"), 1, 65535, 1); + obs_properties_add_text(start_action, "udp_packet", obs_module_text("UdpPacket"), OBS_TEXT_DEFAULT); p = obs_properties_add_list(start_action, "audio_track", obs_module_text("AudioTrack"), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); @@ -993,6 +1080,7 @@ static obs_properties_t *move_action_properties(void *data) obs_property_list_add_int(p, obs_module_text("FilterEnable"), MOVE_ACTION_FILTER_ENABLE); obs_property_list_add_int(p, obs_module_text("FrontendHotkey"), MOVE_ACTION_FRONTEND_HOTKEY); obs_property_list_add_int(p, obs_module_text("Setting"), MOVE_ACTION_SETTING); + obs_property_list_add_int(p, obs_module_text("UdpPacket"), MOVE_ACTION_UDP_PACKET); obs_property_set_modified_callback(p, move_action_end_action_changed); p = obs_properties_add_list(end_action, "end_scene", obs_module_text("Scene"), OBS_COMBO_TYPE_EDITABLE, @@ -1020,7 +1108,11 @@ static obs_properties_t *move_action_properties(void *data) obs_properties_add_float(end_action, "end_value_double", obs_module_text("Value"), 0.0, 0.0, 1.0); obs_properties_add_int(end_action, "end_value_int", obs_module_text("Value"), 0, 0, 1); obs_properties_add_color_alpha(end_action, "end_value_color", obs_module_text("Value")); - obs_properties_add_text(end_action, "end_value_string", obs_module_text("Value"), OBS_TEXT_MULTILINE); //OBS_TEXT_DEFAULT); + obs_properties_add_text(end_action, "end_value_string", obs_module_text("Value"), OBS_TEXT_MULTILINE); + + obs_properties_add_text(end_action, "end_udp_host", obs_module_text("UdpHost"), OBS_TEXT_DEFAULT); + obs_properties_add_int(end_action, "end_udp_port", obs_module_text("UdpPort"), 1, 65535, 1); + obs_properties_add_text(end_action, "end_udp_packet", obs_module_text("UdpPacket"), OBS_TEXT_DEFAULT); p = obs_properties_add_list(end_action, "end_audio_track", obs_module_text("AudioTrack"), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); @@ -1076,6 +1168,12 @@ static obs_properties_t *move_action_properties(void *data) obs_property_list_add_int(p, obs_module_text("StartTrigger.MoveMatch"), START_TRIGGER_MOVE_MATCH); obs_property_list_add_int(p, obs_module_text("StartTrigger.MoveIn"), START_TRIGGER_MOVE_IN); obs_property_list_add_int(p, obs_module_text("StartTrigger.MoveOut"), START_TRIGGER_MOVE_OUT); + obs_property_list_add_int(p, obs_module_text("StartTrigger.Udp"), START_TRIGGER_UDP); + + obs_property_set_modified_callback2(p, move_filter_start_trigger_changed, data); + + obs_properties_add_int(ppts, S_START_TRIGGER_UDP_PORT, obs_module_text("UdpPort"), 1, 65535, 1); + obs_properties_add_text(ppts, S_START_TRIGGER_UDP_PACKET, obs_module_text("UdpPacket"), OBS_TEXT_DEFAULT); p = obs_properties_add_list(ppts, S_STOP_TRIGGER, obs_module_text("StopTrigger"), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); @@ -1089,6 +1187,11 @@ static obs_properties_t *move_action_properties(void *data) obs_property_list_add_int(p, obs_module_text("StartTrigger.MoveMatch"), START_TRIGGER_MOVE_MATCH); obs_property_list_add_int(p, obs_module_text("StartTrigger.MoveIn"), START_TRIGGER_MOVE_IN); obs_property_list_add_int(p, obs_module_text("StartTrigger.MoveOut"), START_TRIGGER_MOVE_OUT); + obs_property_list_add_int(p, obs_module_text("StartTrigger.Udp"), START_TRIGGER_UDP); + obs_property_set_modified_callback2(p, move_filter_stop_trigger_changed, data); + + obs_properties_add_int(ppts, S_STOP_TRIGGER_UDP_PORT, obs_module_text("UdpPort"), 1, 65535, 1); + obs_properties_add_text(ppts, S_STOP_TRIGGER_UDP_PACKET, obs_module_text("UdpPacket"), OBS_TEXT_DEFAULT); obs_source_t *parent = obs_filter_get_parent(move_action->move_filter.source); @@ -1321,6 +1424,23 @@ void move_action_execute(void *data) } obs_source_release(source); } + } else if (move_action->action == MOVE_ACTION_UDP_PACKET) { + SOCKET sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sockfd >= 0) { + struct hostent *host = gethostbyname( + move_action->udp_host && strlen(move_action->udp_host) ? move_action->udp_host : "127.0.0.1"); + if (host) { + struct sockaddr_in server; + memset(&server, 0, sizeof(server)); + server.sin_family = AF_INET; + server.sin_addr = *((struct in_addr *)host->h_addr); + server.sin_port = htons(move_action->udp_port ? move_action->udp_port : 3000); + char *packet = move_action->udp_packet && strlen(move_action->udp_packet) ? move_action->udp_packet + : "move-action"; + sendto(sockfd, packet, (int)strlen(packet), 0, (const struct sockaddr *)&server, sizeof(server)); + closesocket(sockfd); + } + } } } diff --git a/move-directshow-filter.cpp b/move-directshow-filter.cpp index 70f5730..e5e3fb5 100644 --- a/move-directshow-filter.cpp +++ b/move-directshow-filter.cpp @@ -6,7 +6,7 @@ extern "C" { #include #include #include -#include "util/threading.h" +#include #define PROP_MAX 100 diff --git a/move-filter.c b/move-filter.c index 87ad62b..68352e4 100644 --- a/move-filter.c +++ b/move-filter.c @@ -1,6 +1,31 @@ #include "move-transition.h" #include "obs-frontend-api.h" #include +#include +#include + +#ifdef _WIN32 +#include +#include +#include +#else +#include +#include +#include +#include +#define SOCKET int +#define closesocket(s) close(s) +#endif + +struct udp_server { + int port; + pthread_t thread; + DARRAY(struct move_filter *) start_triggers; + DARRAY(struct move_filter *) stop_triggers; +}; + +DARRAY(struct udp_server) udp_servers; +pthread_mutex_t udp_servers_mutex; bool is_move_filter(const char *filter_id) { @@ -20,8 +45,49 @@ void move_filter_init(struct move_filter *move_filter, obs_source_t *source, voi move_filter->move_start = move_start; } +void stop_udp_thread(struct udp_server *udp_server) +{ + SOCKET sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sockfd >= 0) { + struct sockaddr_in server; + struct hostent *host = gethostbyname("127.0.0.1"); + + memset(&server, 0, sizeof(server)); + server.sin_family = AF_INET; + server.sin_addr = *((struct in_addr *)host->h_addr); + server.sin_port = htons(udp_server->port); + char *exit_message = "exit"; + sendto(sockfd, (const char *)exit_message, (int)strlen(exit_message), 0, (const struct sockaddr *)&server, + sizeof(server)); + closesocket(sockfd); + } +} + void move_filter_destroy(struct move_filter *move_filter) { + pthread_mutex_lock(&udp_servers_mutex); + for (size_t i = 0; i < udp_servers.num; i++) { + for (size_t j = 0; j < udp_servers.array[j].start_triggers.num; j++) { + if (udp_servers.array[i].start_triggers.array[j] != move_filter) + continue; + da_erase(udp_servers.array[i].start_triggers, j); + if (!udp_servers.array[i].start_triggers.num && !udp_servers.array[j].stop_triggers.num) { + stop_udp_thread(&udp_servers.array[i]); + } + break; + } + for (size_t j = 0; j < udp_servers.array[j].stop_triggers.num; j++) { + if (udp_servers.array[i].stop_triggers.array[j] != move_filter) + continue; + da_erase(udp_servers.array[i].stop_triggers, j); + if (!udp_servers.array[i].start_triggers.num && !udp_servers.array[j].stop_triggers.num) { + stop_udp_thread(&udp_servers.array[i]); + } + break; + } + } + pthread_mutex_unlock(&udp_servers_mutex); + bfree(move_filter->filter_name); bfree(move_filter->simultaneous_move_name); bfree(move_filter->next_move_name); @@ -137,6 +203,89 @@ void move_filter_hold_hotkey(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey, move_filter->holding = false; } +static void *udp_server_thread(void *data) +{ + os_set_thread_name("move_udp_server_thread"); + + struct udp_server *udp_server = data; + + SOCKET sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (sockfd < 0) + return NULL; + + struct sockaddr_in si_me; + memset((char *)&si_me, 0, sizeof(si_me)); + + si_me.sin_family = AF_INET; + si_me.sin_port = htons(udp_server->port); + si_me.sin_addr.s_addr = htonl(INADDR_ANY); + + if (bind(sockfd, (struct sockaddr *)&si_me, sizeof(si_me)) == -1) + return NULL; + + struct sockaddr_in si_other; + int recv_len; + int port = udp_server->port; + pthread_t self = pthread_self(); + +#define BUFLEN 512 + char buf[BUFLEN]; + int slen = sizeof(si_other); + while (true) { + recv_len = recvfrom(sockfd, buf, BUFLEN, 0, (struct sockaddr *)&si_other, &slen); + pthread_mutex_lock(&udp_servers_mutex); + if (recv_len == -1) + break; + + udp_server = NULL; + for (size_t i = 0; i < udp_servers.num; i++) { + if (udp_servers.array[i].port == port) { + udp_server = &udp_servers.array[i]; + break; + } else if (pthread_equal(udp_servers.array[i].thread, self)) { + udp_server = &udp_servers.array[i]; + break; + } + } + if (!udp_server) + break; + + if (!udp_server->start_triggers.num && !udp_server->stop_triggers.num) + break; + + if (recv_len < BUFLEN) { + buf[recv_len] = 0; + for (size_t i = 0; i < udp_server->start_triggers.num; i++) { + struct move_filter *move_filter = udp_server->start_triggers.array[i]; + obs_data_t *settings = obs_source_get_settings(move_filter->source); + const char *packet = obs_data_get_string(settings, "start_trigger_udp_packet"); + if (!strlen(packet) || strcmp(packet, buf) == 0) { + move_filter_start(move_filter); + } + obs_data_release(settings); + } + for (size_t i = 0; i < udp_server->stop_triggers.num; i++) { + struct move_filter *move_filter = udp_server->stop_triggers.array[i]; + obs_data_t *settings = obs_source_get_settings(move_filter->source); + const char *packet = obs_data_get_string(settings, "stop_trigger_udp_packet"); + if (!strlen(packet) || strcmp(packet, buf) == 0) { + move_filter_stop(move_filter); + } + obs_data_release(settings); + } + } + pthread_mutex_unlock(&udp_servers_mutex); + } + da_free(udp_server->start_triggers); + da_free(udp_server->stop_triggers); + da_erase_item(udp_servers, udp_server); + if (!udp_servers.num) + da_free(udp_servers); + pthread_mutex_unlock(&udp_servers_mutex); + closesocket(sockfd); + return NULL; +} + void move_filter_update(struct move_filter *move_filter, obs_data_t *settings) { const char *filter_name = obs_source_get_name(move_filter->source); @@ -181,8 +330,115 @@ void move_filter_update(struct move_filter *move_filter, obs_data_t *settings) move_filter->easing = obs_data_get_int(settings, S_EASING_MATCH); move_filter->easing_function = obs_data_get_int(settings, S_EASING_FUNCTION_MATCH); + pthread_mutex_lock(&udp_servers_mutex); move_filter->start_trigger = (uint32_t)obs_data_get_int(settings, S_START_TRIGGER); + if (move_filter->start_trigger == START_TRIGGER_UDP) { + int port = (int)obs_data_get_int(settings, S_START_TRIGGER_UDP_PORT); + if (!port) + port = 3000; + struct udp_server *udp_server = NULL; + for (size_t i = 0; i < udp_servers.num; i++) { + if (udp_servers.array[i].port == port) { + udp_server = &udp_servers.array[i]; + } else { + for (size_t j = 0; j < udp_servers.array[i].start_triggers.num; j++) { + if (udp_servers.array[i].start_triggers.array[j] == move_filter) { + da_erase(udp_servers.array[i].start_triggers, j); + if (!udp_servers.array[i].start_triggers.num && + !udp_servers.array[i].stop_triggers.num) { + stop_udp_thread(&udp_servers.array[i]); + } + break; + } + } + } + } + if (!udp_server) { + udp_server = da_push_back_new(udp_servers); + udp_server->port = port; + da_init(udp_server->start_triggers); + da_init(udp_server->stop_triggers); + da_push_back(udp_server->start_triggers, &move_filter); + pthread_create(&udp_server->thread, NULL, udp_server_thread, udp_server); + } + bool found = false; + for (size_t i = 0; i < udp_server->start_triggers.num; i++) { + if (udp_server->start_triggers.array[i] == move_filter) { + found = true; + break; + } + } + if (!found) + da_push_back(udp_server->start_triggers, &move_filter); + + } else { + // stop existing udp server + for (size_t i = 0; i < udp_servers.num; i++) { + for (size_t j = 0; j < udp_servers.array[j].start_triggers.num; j++) { + if (udp_servers.array[i].start_triggers.array[j] != move_filter) + continue; + da_erase(udp_servers.array[i].start_triggers, j); + if (!udp_servers.array[i].start_triggers.num && !udp_servers.array[j].stop_triggers.num) { + stop_udp_thread(&udp_servers.array[i]); + } + break; + } + } + } move_filter->stop_trigger = (uint32_t)obs_data_get_int(settings, S_STOP_TRIGGER); + if (move_filter->stop_trigger == START_TRIGGER_UDP) { + int port = (int)obs_data_get_int(settings, S_STOP_TRIGGER_UDP_PORT); + if (!port) + port = 3000; + struct udp_server *udp_server = NULL; + for (size_t i = 0; i < udp_servers.num; i++) { + if (udp_servers.array[i].port == port) { + udp_server = &udp_servers.array[i]; + } else { + for (size_t j = 0; j < udp_servers.array[i].stop_triggers.num; j++) { + if (udp_servers.array[i].stop_triggers.array[j] == move_filter) { + da_erase(udp_servers.array[i].stop_triggers, j); + if (!udp_servers.array[i].start_triggers.num && + !udp_servers.array[i].stop_triggers.num) { + stop_udp_thread(&udp_servers.array[i]); + } + break; + } + } + } + } + if (!udp_server) { + udp_server = da_push_back_new(udp_servers); + udp_server->port = port; + da_init(udp_server->start_triggers); + da_init(udp_server->stop_triggers); + da_push_back(udp_server->stop_triggers, &move_filter); + pthread_create(&udp_server->thread, NULL, udp_server_thread, udp_server); + } + bool found = false; + for (size_t i = 0; i < udp_server->stop_triggers.num; i++) { + if (udp_server->stop_triggers.array[i] == move_filter) { + found = true; + break; + } + } + if (!found) + da_push_back(udp_server->stop_triggers, &move_filter); + } else { + // stop existing udp server + for (size_t i = 0; i < udp_servers.num; i++) { + for (size_t j = 0; j < udp_servers.array[j].stop_triggers.num; j++) { + if (udp_servers.array[i].stop_triggers.array[j] != move_filter) + continue; + da_erase(udp_servers.array[i].stop_triggers, j); + if (!udp_servers.array[i].start_triggers.num && !udp_servers.array[j].stop_triggers.num) { + stop_udp_thread(&udp_servers.array[i]); + } + break; + } + } + } + pthread_mutex_unlock(&udp_servers_mutex); const char *simultaneous_move_name = obs_data_get_string(settings, S_SIMULTANEOUS_MOVE); if (!move_filter->simultaneous_move_name || strcmp(move_filter->simultaneous_move_name, simultaneous_move_name) != 0) { @@ -390,6 +646,30 @@ void prop_list_add_move_filter(obs_source_t *parent, obs_source_t *child, void * obs_property_list_add_string(p, name, name); } +bool move_filter_start_trigger_changed(void *priv, obs_properties_t *props, obs_property_t *property, obs_data_t *settings) +{ + obs_property_t *port = obs_properties_get(props, S_START_TRIGGER_UDP_PORT); + obs_property_t *packet = obs_properties_get(props, S_START_TRIGGER_UDP_PACKET); + bool udp = obs_data_get_int(settings, S_START_TRIGGER) == START_TRIGGER_UDP; + if (obs_property_visible(port) == udp && obs_property_visible(packet) == udp) + return false; + obs_property_set_visible(port, udp); + obs_property_set_visible(packet, udp); + return true; +} + +bool move_filter_stop_trigger_changed(void *priv, obs_properties_t *props, obs_property_t *property, obs_data_t *settings) +{ + obs_property_t *port = obs_properties_get(props, S_STOP_TRIGGER_UDP_PORT); + obs_property_t *packet = obs_properties_get(props, S_STOP_TRIGGER_UDP_PACKET); + bool udp = obs_data_get_int(settings, S_STOP_TRIGGER) == START_TRIGGER_UDP; + if (obs_property_visible(port) == udp && obs_property_visible(packet) == udp) + return false; + obs_property_set_visible(port, udp); + obs_property_set_visible(packet, udp); + return true; +} + void move_filter_properties(struct move_filter *move_filter, obs_properties_t *ppts) { obs_property_t *p = obs_properties_add_int(ppts, S_START_DELAY, obs_module_text("StartDelay"), 0, 10000000, 100); @@ -427,6 +707,12 @@ void move_filter_properties(struct move_filter *move_filter, obs_properties_t *p obs_property_list_add_int(p, obs_module_text("StartTrigger.MoveMatch"), START_TRIGGER_MOVE_MATCH); obs_property_list_add_int(p, obs_module_text("StartTrigger.MoveIn"), START_TRIGGER_MOVE_IN); obs_property_list_add_int(p, obs_module_text("StartTrigger.MoveOut"), START_TRIGGER_MOVE_OUT); + obs_property_list_add_int(p, obs_module_text("StartTrigger.Udp"), START_TRIGGER_UDP); + + obs_property_set_modified_callback2(p, move_filter_start_trigger_changed, move_filter); + + obs_properties_add_int(ppts, S_START_TRIGGER_UDP_PORT, obs_module_text("UdpPort"), 1, 65535, 1); + obs_properties_add_text(ppts, S_START_TRIGGER_UDP_PACKET, obs_module_text("UdpPacket"), OBS_TEXT_DEFAULT); p = obs_properties_add_list(ppts, S_STOP_TRIGGER, obs_module_text("StopTrigger"), OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_INT); @@ -440,6 +726,12 @@ void move_filter_properties(struct move_filter *move_filter, obs_properties_t *p obs_property_list_add_int(p, obs_module_text("StartTrigger.MoveMatch"), START_TRIGGER_MOVE_MATCH); obs_property_list_add_int(p, obs_module_text("StartTrigger.MoveIn"), START_TRIGGER_MOVE_IN); obs_property_list_add_int(p, obs_module_text("StartTrigger.MoveOut"), START_TRIGGER_MOVE_OUT); + obs_property_list_add_int(p, obs_module_text("StartTrigger.Udp"), START_TRIGGER_UDP); + + obs_property_set_modified_callback2(p, move_filter_stop_trigger_changed, move_filter); + + obs_properties_add_int(ppts, S_STOP_TRIGGER_UDP_PORT, obs_module_text("UdpPort"), 1, 65535, 1); + obs_properties_add_text(ppts, S_STOP_TRIGGER_UDP_PACKET, obs_module_text("UdpPacket"), OBS_TEXT_DEFAULT); obs_source_t *parent = obs_filter_get_parent(move_filter->source); @@ -467,6 +759,8 @@ void move_filter_defaults(obs_data_t *settings) { obs_data_set_default_bool(settings, S_ENABLED_MATCH_MOVING, true); obs_data_set_default_int(settings, S_DURATION, 300); + obs_data_set_default_int(settings, S_START_TRIGGER_UDP_PORT, 3000); + obs_data_set_default_int(settings, S_STOP_TRIGGER_UDP_PORT, 3000); } void move_filter_activate(void *data) diff --git a/move-transition.c b/move-transition.c index 7cd7f76..3a58ce1 100644 --- a/move-transition.c +++ b/move-transition.c @@ -4,6 +4,7 @@ #include "graphics/math-defs.h" #include "graphics/matrix4.h" #include "easing.h" +#include struct move_info { obs_source_t *source; @@ -3225,9 +3226,14 @@ extern void unload_nvar(void); void SetMoveDirectShowFilter(struct obs_source_info *obs_source_info); #endif +extern DARRAY(struct udp_server) udp_servers; +extern pthread_mutex_t udp_servers_mutex; + bool obs_module_load(void) { blog(LOG_INFO, "[Move Transition] loaded version %s", PROJECT_VERSION); + da_init(udp_servers); + pthread_mutex_init(&udp_servers_mutex, NULL); obs_register_source(&move_transition); obs_register_source(&move_transition_override_filter); obs_register_source(&move_source_filter); @@ -3246,3 +3252,7 @@ bool obs_module_load(void) #endif return true; } + +void obs_module_unload() { + pthread_mutex_destroy(&udp_servers_mutex); +} diff --git a/move-transition.h b/move-transition.h index 8025219..5467a0b 100644 --- a/move-transition.h +++ b/move-transition.h @@ -73,7 +73,11 @@ #define S_CACHE_TRANSITIONS "cache_transitions" #define S_NESTED_SCENES "nested_scenes" #define S_START_TRIGGER "start_trigger" +#define S_START_TRIGGER_UDP_PORT "start_trigger_udp_port" +#define S_START_TRIGGER_UDP_PACKET "start_trigger_udp_packet" #define S_STOP_TRIGGER "stop_trigger" +#define S_STOP_TRIGGER_UDP_PORT "stop_trigger_udp_port" +#define S_STOP_TRIGGER_UDP_PACKET "stop_trigger_udp_packet" #define S_START_DELAY "start_delay" #define S_END_DELAY "end_delay" #define S_ACTIONS "actions" @@ -171,6 +175,7 @@ #define START_TRIGGER_MOVE_MATCH 14 #define START_TRIGGER_MOVE_IN 15 #define START_TRIGGER_MOVE_OUT 16 +#define START_TRIGGER_UDP 17 #define MOVE_VALUE_UNKNOWN 0 #define MOVE_VALUE_INT 1 @@ -276,6 +281,8 @@ void move_filter_stop(struct move_filter *move_filter); void move_filter_ended(struct move_filter *move_filter); bool move_filter_tick(struct move_filter *move_filter, float seconds, float *t); void move_filter_properties(struct move_filter *move_filter, obs_properties_t *ppts); +bool move_filter_start_trigger_changed(void *priv, obs_properties_t *props, obs_property_t *property, obs_data_t *settings); +bool move_filter_stop_trigger_changed(void *priv, obs_properties_t *props, obs_property_t *property, obs_data_t *settings); void move_filter_defaults(obs_data_t *settings); void move_filter_activate(void *data); void move_filter_deactivate(void *data);