diff --git a/docs/sphinx/reference-core.rst b/docs/sphinx/reference-core.rst index 002a6d3b7..b6d0720e1 100644 --- a/docs/sphinx/reference-core.rst +++ b/docs/sphinx/reference-core.rst @@ -333,6 +333,15 @@ Libobs Objects --------------------- +.. function:: obs_source_t *obs_get_source_by_uuid(const char *uuid) + + Gets a source by its UUID. + + Increments the source reference counter, use + :c:func:`obs_source_release()` to release it when complete. + +--------------------- + .. function:: obs_source_t *obs_get_transition_by_name(const char *name) Gets a transition by its name. diff --git a/docs/sphinx/reference-sources.rst b/docs/sphinx/reference-sources.rst index 38996da1c..ec59a2e97 100644 --- a/docs/sphinx/reference-sources.rst +++ b/docs/sphinx/reference-sources.rst @@ -941,6 +941,12 @@ General Source Functions --------------------- +.. function:: const char *obs_source_get_uuid(const obs_source_t *source) + + :return: The UUID of the source + +--------------------- + .. function:: void obs_source_set_name(obs_source_t *source, const char *name) Sets the name of a source. If the source is not private and the name diff --git a/libobs/obs-encoder.c b/libobs/obs-encoder.c index 8d8c8620c..677b92f7d 100644 --- a/libobs/obs-encoder.c +++ b/libobs/obs-encoder.c @@ -52,7 +52,7 @@ static bool init_encoder(struct obs_encoder *encoder, const char *name, pthread_mutex_init_value(&encoder->pause.mutex); if (!obs_context_data_init(&encoder->context, OBS_OBJ_TYPE_ENCODER, - settings, name, hotkey_data, false)) + settings, name, NULL, hotkey_data, false)) return false; if (pthread_mutex_init_recursive(&encoder->init_mutex) != 0) return false; diff --git a/libobs/obs-internal.h b/libobs/obs-internal.h index b7df1f235..7a3bd7999 100644 --- a/libobs/obs-internal.h +++ b/libobs/obs-internal.h @@ -520,6 +520,7 @@ typedef void (*obs_destroy_cb)(void *obj); struct obs_context_data { char *name; + const char *uuid; void *data; obs_data_t *settings; signal_handler_t *signals; @@ -545,8 +546,8 @@ struct obs_context_data { extern bool obs_context_data_init(struct obs_context_data *context, enum obs_obj_type type, obs_data_t *settings, - const char *name, obs_data_t *hotkey_data, - bool private); + const char *name, const char *uuid, + obs_data_t *hotkey_data, bool private); extern void obs_context_init_control(struct obs_context_data *context, void *object, obs_destroy_cb destroy); extern void obs_context_data_free(struct obs_context_data *context); @@ -834,7 +835,8 @@ extern struct obs_source_info *get_source_info2(const char *unversioned_id, uint32_t ver); extern bool obs_source_init_context(struct obs_source *source, obs_data_t *settings, const char *name, - obs_data_t *hotkey_data, bool private); + const char *uuid, obs_data_t *hotkey_data, + bool private); extern bool obs_transition_init(obs_source_t *transition); extern void obs_transition_free(obs_source_t *transition); @@ -851,8 +853,9 @@ extern void audio_monitor_destroy(struct audio_monitor *monitor); extern obs_source_t * obs_source_create_set_last_ver(const char *id, const char *name, - obs_data_t *settings, obs_data_t *hotkey_data, - uint32_t last_obs_ver, bool is_private); + const char *uuid, obs_data_t *settings, + obs_data_t *hotkey_data, uint32_t last_obs_ver, + bool is_private); extern void obs_source_destroy(struct obs_source *source); enum view_type { diff --git a/libobs/obs-output.c b/libobs/obs-output.c index ad71c7ced..9e847f3bc 100644 --- a/libobs/obs-output.c +++ b/libobs/obs-output.c @@ -94,7 +94,7 @@ static bool init_output_handlers(struct obs_output *output, const char *name, obs_data_t *settings, obs_data_t *hotkey_data) { if (!obs_context_data_init(&output->context, OBS_OBJ_TYPE_OUTPUT, - settings, name, hotkey_data, false)) + settings, name, NULL, hotkey_data, false)) return false; signal_handler_add_array(output->context.signals, output_signals); diff --git a/libobs/obs-service.c b/libobs/obs-service.c index 53269c6ca..a2cd0140c 100644 --- a/libobs/obs-service.c +++ b/libobs/obs-service.c @@ -52,7 +52,8 @@ static obs_service_t *obs_service_create_internal(const char *id, service = bzalloc(sizeof(struct obs_service)); if (!obs_context_data_init(&service->context, OBS_OBJ_TYPE_SERVICE, - settings, name, hotkey_data, private)) { + settings, name, NULL, hotkey_data, + private)) { bfree(service); return NULL; } diff --git a/libobs/obs-source.c b/libobs/obs-source.c index 037c2668f..f92d54f49 100644 --- a/libobs/obs-source.c +++ b/libobs/obs-source.c @@ -118,11 +118,11 @@ static const char *source_signals[] = { }; bool obs_source_init_context(struct obs_source *source, obs_data_t *settings, - const char *name, obs_data_t *hotkey_data, - bool private) + const char *name, const char *uuid, + obs_data_t *hotkey_data, bool private) { if (!obs_context_data_init(&source->context, OBS_OBJ_TYPE_SOURCE, - settings, name, hotkey_data, private)) + settings, name, uuid, hotkey_data, private)) return false; return signal_handler_add_array(source->context.signals, @@ -340,7 +340,7 @@ static void obs_source_init_audio_hotkeys(struct obs_source *source) } static obs_source_t * -obs_source_create_internal(const char *id, const char *name, +obs_source_create_internal(const char *id, const char *name, const char *uuid, obs_data_t *settings, obs_data_t *hotkey_data, bool private, uint32_t last_obs_ver) { @@ -370,7 +370,7 @@ obs_source_create_internal(const char *id, const char *name, source->push_to_talk_key = OBS_INVALID_HOTKEY_ID; source->last_obs_ver = last_obs_ver; - if (!obs_source_init_context(source, settings, name, hotkey_data, + if (!obs_source_init_context(source, settings, name, uuid, hotkey_data, private)) goto fail; @@ -420,24 +420,25 @@ fail: obs_source_t *obs_source_create(const char *id, const char *name, obs_data_t *settings, obs_data_t *hotkey_data) { - return obs_source_create_internal(id, name, settings, hotkey_data, + return obs_source_create_internal(id, name, NULL, settings, hotkey_data, false, LIBOBS_API_VER); } obs_source_t *obs_source_create_private(const char *id, const char *name, obs_data_t *settings) { - return obs_source_create_internal(id, name, settings, NULL, true, + return obs_source_create_internal(id, name, NULL, settings, NULL, true, LIBOBS_API_VER); } obs_source_t *obs_source_create_set_last_ver(const char *id, const char *name, + const char *uuid, obs_data_t *settings, obs_data_t *hotkey_data, uint32_t last_obs_ver, bool is_private) { - return obs_source_create_internal(id, name, settings, hotkey_data, + return obs_source_create_internal(id, name, uuid, settings, hotkey_data, is_private, last_obs_ver); } @@ -4242,6 +4243,13 @@ const char *obs_source_get_name(const obs_source_t *source) : NULL; } +const char *obs_source_get_uuid(const obs_source_t *source) +{ + return obs_source_valid(source, "obs_source_get_uuid") + ? source->context.uuid + : NULL; +} + void obs_source_set_name(obs_source_t *source, const char *name) { if (!obs_source_valid(source, "obs_source_set_name")) diff --git a/libobs/obs.c b/libobs/obs.c index bf045f68f..8ae0b4051 100644 --- a/libobs/obs.c +++ b/libobs/obs.c @@ -2019,6 +2019,26 @@ obs_source_t *obs_get_source_by_name(const char *name) obs_source_addref_safe_); } +obs_source_t *obs_get_source_by_uuid(const char *uuid) +{ + struct obs_source **first = &obs->data.first_source; + struct obs_source *source; + + pthread_mutex_lock(&obs->data.sources_mutex); + + source = *first; + while (source) { + if (strcmp(source->context.uuid, uuid) == 0) { + source = obs_source_get_ref(source); + break; + } + source = (struct obs_source *)source->context.next; + } + + pthread_mutex_unlock(&obs->data.sources_mutex); + return source; +} + obs_source_t *obs_get_transition_by_name(const char *name) { struct obs_source **first = &obs->data.first_source; @@ -2203,6 +2223,7 @@ static obs_source_t *obs_load_source_type(obs_data_t *source_data, obs_data_array_t *filters = obs_data_get_array(source_data, "filters"); obs_source_t *source; const char *name = obs_data_get_string(source_data, "name"); + const char *uuid = obs_data_get_string(source_data, "uuid"); const char *id = obs_data_get_string(source_data, "id"); const char *v_id = obs_data_get_string(source_data, "versioned_id"); obs_data_t *settings = obs_data_get_obj(source_data, "settings"); @@ -2223,8 +2244,9 @@ static obs_source_t *obs_load_source_type(obs_data_t *source_data, if (!*v_id) v_id = id; - source = obs_source_create_set_last_ver(v_id, name, settings, hotkeys, - prev_ver, is_private); + source = obs_source_create_set_last_ver(v_id, name, uuid, settings, + hotkeys, prev_ver, is_private); + if (source->owns_info_id) { bfree((void *)source->info.unversioned_id); source->info.unversioned_id = bstrdup(id); @@ -2398,6 +2420,7 @@ obs_data_t *obs_save_source(obs_source_t *source) int64_t sync = obs_source_get_sync_offset(source); uint32_t flags = obs_source_get_flags(source); const char *name = obs_source_get_name(source); + const char *uuid = obs_source_get_uuid(source); const char *id = source->info.unversioned_id; const char *v_id = source->info.id; bool enabled = obs_source_enabled(source); @@ -2422,6 +2445,7 @@ obs_data_t *obs_save_source(obs_source_t *source) obs_data_set_int(source_data, "prev_ver", LIBOBS_API_VER); obs_data_set_string(source_data, "name", name); + obs_data_set_string(source_data, "uuid", uuid); obs_data_set_string(source_data, "id", id); obs_data_set_string(source_data, "versioned_id", v_id); obs_data_set_obj(source_data, "settings", settings); @@ -2528,12 +2552,11 @@ static inline char *dup_name(const char *name, bool private) } } -static inline bool obs_context_data_init_wrap(struct obs_context_data *context, - enum obs_obj_type type, - obs_data_t *settings, - const char *name, - obs_data_t *hotkey_data, - bool private) +static inline bool +obs_context_data_init_wrap(struct obs_context_data *context, + enum obs_obj_type type, obs_data_t *settings, + const char *name, const char *uuid, + obs_data_t *hotkey_data, bool private) { assert(context); memset(context, 0, sizeof(*context)); @@ -2552,6 +2575,12 @@ static inline bool obs_context_data_init_wrap(struct obs_context_data *context, if (!context->procs) return false; + if (uuid && strlen(uuid) == UUID_STR_LENGTH) + context->uuid = bstrdup(uuid); + /* Only automatically generate UUIDs for sources */ + else if (type == OBS_OBJ_TYPE_SOURCE) + context->uuid = os_generate_uuid(); + context->name = dup_name(name, private); context->settings = obs_data_newref(settings); context->hotkey_data = obs_data_newref(hotkey_data); @@ -2560,10 +2589,10 @@ static inline bool obs_context_data_init_wrap(struct obs_context_data *context, bool obs_context_data_init(struct obs_context_data *context, enum obs_obj_type type, obs_data_t *settings, - const char *name, obs_data_t *hotkey_data, - bool private) + const char *name, const char *uuid, + obs_data_t *hotkey_data, bool private) { - if (obs_context_data_init_wrap(context, type, settings, name, + if (obs_context_data_init_wrap(context, type, settings, name, uuid, hotkey_data, private)) { return true; } else { @@ -2581,6 +2610,7 @@ void obs_context_data_free(struct obs_context_data *context) obs_context_data_remove(context); pthread_mutex_destroy(&context->rename_cache_mutex); bfree(context->name); + bfree((void *)context->uuid); for (size_t i = 0; i < context->rename_cache.num; i++) bfree(context->rename_cache.array[i]); diff --git a/libobs/obs.h b/libobs/obs.h index 1e56cc384..7cba70a69 100644 --- a/libobs/obs.h +++ b/libobs/obs.h @@ -697,6 +697,14 @@ EXPORT void obs_enum_services(bool (*enum_proc)(void *, obs_service_t *), */ EXPORT obs_source_t *obs_get_source_by_name(const char *name); +/** + * Gets a source by its UUID. + * + * Increments the source reference counter, use obs_source_release to + * release it when complete. + */ +EXPORT obs_source_t *obs_get_source_by_uuid(const char *uuid); + /** Get a transition source by its name. */ EXPORT obs_source_t *obs_get_transition_by_name(const char *name); @@ -1115,6 +1123,9 @@ EXPORT const char *obs_source_get_name(const obs_source_t *source); /** Sets the name of a source */ EXPORT void obs_source_set_name(obs_source_t *source, const char *name); +/** Gets the UUID of a source */ +EXPORT const char *obs_source_get_uuid(const obs_source_t *source); + /** Gets the source type */ EXPORT enum obs_source_type obs_source_get_type(const obs_source_t *source);