|
@@ -1000,6 +1000,8 @@ static bool obs_init_data(void)
|
|
if (!obs_view_init(&data->main_view))
|
|
if (!obs_view_init(&data->main_view))
|
|
goto fail;
|
|
goto fail;
|
|
|
|
|
|
|
|
+ data->sources = NULL;
|
|
|
|
+ data->public_sources = NULL;
|
|
data->private_data = obs_data_create();
|
|
data->private_data = obs_data_create();
|
|
data->valid = true;
|
|
data->valid = true;
|
|
|
|
|
|
@@ -1019,6 +1021,20 @@ void obs_main_view_free(struct obs_view *view)
|
|
pthread_mutex_destroy(&view->channels_mutex);
|
|
pthread_mutex_destroy(&view->channels_mutex);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#define FREE_OBS_HASH_TABLE(handle, table, type) \
|
|
|
|
+ do { \
|
|
|
|
+ struct obs_context_data *ctx, *tmp; \
|
|
|
|
+ int unfreed = 0; \
|
|
|
|
+ HASH_ITER (handle, *(struct obs_context_data **)table, ctx, \
|
|
|
|
+ tmp) { \
|
|
|
|
+ obs_##type##_destroy((obs_##type##_t *)ctx); \
|
|
|
|
+ unfreed++; \
|
|
|
|
+ } \
|
|
|
|
+ if (unfreed) \
|
|
|
|
+ blog(LOG_INFO, "\t%d " #type "(s) were remaining", \
|
|
|
|
+ unfreed); \
|
|
|
|
+ } while (false)
|
|
|
|
+
|
|
#define FREE_OBS_LINKED_LIST(type) \
|
|
#define FREE_OBS_LINKED_LIST(type) \
|
|
do { \
|
|
do { \
|
|
int unfreed = 0; \
|
|
int unfreed = 0; \
|
|
@@ -1042,12 +1058,14 @@ static void obs_free_data(void)
|
|
|
|
|
|
blog(LOG_INFO, "Freeing OBS context data");
|
|
blog(LOG_INFO, "Freeing OBS context data");
|
|
|
|
|
|
- FREE_OBS_LINKED_LIST(source);
|
|
|
|
FREE_OBS_LINKED_LIST(output);
|
|
FREE_OBS_LINKED_LIST(output);
|
|
FREE_OBS_LINKED_LIST(encoder);
|
|
FREE_OBS_LINKED_LIST(encoder);
|
|
FREE_OBS_LINKED_LIST(display);
|
|
FREE_OBS_LINKED_LIST(display);
|
|
FREE_OBS_LINKED_LIST(service);
|
|
FREE_OBS_LINKED_LIST(service);
|
|
|
|
|
|
|
|
+ FREE_OBS_HASH_TABLE(hh, &data->public_sources, source);
|
|
|
|
+ FREE_OBS_HASH_TABLE(hh_uuid, &data->sources, source);
|
|
|
|
+
|
|
os_task_queue_wait(obs->destruction_task_thread);
|
|
os_task_queue_wait(obs->destruction_task_thread);
|
|
|
|
|
|
pthread_mutex_destroy(&data->sources_mutex);
|
|
pthread_mutex_destroy(&data->sources_mutex);
|
|
@@ -1869,17 +1887,16 @@ void obs_enum_sources(bool (*enum_proc)(void *, obs_source_t *), void *param)
|
|
obs_source_t *source;
|
|
obs_source_t *source;
|
|
|
|
|
|
pthread_mutex_lock(&obs->data.sources_mutex);
|
|
pthread_mutex_lock(&obs->data.sources_mutex);
|
|
- source = obs->data.first_source;
|
|
|
|
|
|
+ source = obs->data.public_sources;
|
|
|
|
|
|
while (source) {
|
|
while (source) {
|
|
obs_source_t *s = obs_source_get_ref(source);
|
|
obs_source_t *s = obs_source_get_ref(source);
|
|
if (s) {
|
|
if (s) {
|
|
- if (strcmp(s->info.id, group_info.id) == 0 &&
|
|
|
|
|
|
+ if (s->info.type == OBS_SOURCE_TYPE_INPUT &&
|
|
!enum_proc(param, s)) {
|
|
!enum_proc(param, s)) {
|
|
obs_source_release(s);
|
|
obs_source_release(s);
|
|
break;
|
|
break;
|
|
- } else if (s->info.type == OBS_SOURCE_TYPE_INPUT &&
|
|
|
|
- !s->context.private &&
|
|
|
|
|
|
+ } else if (strcmp(s->info.id, group_info.id) == 0 &&
|
|
!enum_proc(param, s)) {
|
|
!enum_proc(param, s)) {
|
|
obs_source_release(s);
|
|
obs_source_release(s);
|
|
break;
|
|
break;
|
|
@@ -1887,7 +1904,7 @@ void obs_enum_sources(bool (*enum_proc)(void *, obs_source_t *), void *param)
|
|
obs_source_release(s);
|
|
obs_source_release(s);
|
|
}
|
|
}
|
|
|
|
|
|
- source = (obs_source_t *)source->context.next;
|
|
|
|
|
|
+ source = (obs_source_t *)source->context.hh.next;
|
|
}
|
|
}
|
|
|
|
|
|
pthread_mutex_unlock(&obs->data.sources_mutex);
|
|
pthread_mutex_unlock(&obs->data.sources_mutex);
|
|
@@ -1898,20 +1915,20 @@ void obs_enum_scenes(bool (*enum_proc)(void *, obs_source_t *), void *param)
|
|
obs_source_t *source;
|
|
obs_source_t *source;
|
|
|
|
|
|
pthread_mutex_lock(&obs->data.sources_mutex);
|
|
pthread_mutex_lock(&obs->data.sources_mutex);
|
|
- source = obs->data.first_source;
|
|
|
|
|
|
|
|
|
|
+ source = obs->data.public_sources;
|
|
while (source) {
|
|
while (source) {
|
|
obs_source_t *s = obs_source_get_ref(source);
|
|
obs_source_t *s = obs_source_get_ref(source);
|
|
if (s) {
|
|
if (s) {
|
|
if (source->info.type == OBS_SOURCE_TYPE_SCENE &&
|
|
if (source->info.type == OBS_SOURCE_TYPE_SCENE &&
|
|
- !source->context.private && !enum_proc(param, s)) {
|
|
|
|
|
|
+ !enum_proc(param, s)) {
|
|
obs_source_release(s);
|
|
obs_source_release(s);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
obs_source_release(s);
|
|
obs_source_release(s);
|
|
}
|
|
}
|
|
|
|
|
|
- source = (obs_source_t *)source->context.next;
|
|
|
|
|
|
+ source = (obs_source_t *)source->context.hh.next;
|
|
}
|
|
}
|
|
|
|
|
|
pthread_mutex_unlock(&obs->data.sources_mutex);
|
|
pthread_mutex_unlock(&obs->data.sources_mutex);
|
|
@@ -1940,11 +1957,31 @@ static inline void obs_enum(void *pstart, pthread_mutex_t *mutex, void *proc,
|
|
pthread_mutex_unlock(mutex);
|
|
pthread_mutex_unlock(mutex);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static inline void obs_enum_uuid(void *pstart, pthread_mutex_t *mutex,
|
|
|
|
+ void *proc, void *param)
|
|
|
|
+{
|
|
|
|
+ struct obs_context_data **start = pstart, *context, *tmp;
|
|
|
|
+ bool (*enum_proc)(void *, void *) = proc;
|
|
|
|
+
|
|
|
|
+ assert(start);
|
|
|
|
+ assert(mutex);
|
|
|
|
+ assert(enum_proc);
|
|
|
|
+
|
|
|
|
+ pthread_mutex_lock(mutex);
|
|
|
|
+
|
|
|
|
+ HASH_ITER (hh_uuid, *start, context, tmp) {
|
|
|
|
+ if (!enum_proc(param, context))
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pthread_mutex_unlock(mutex);
|
|
|
|
+}
|
|
|
|
+
|
|
void obs_enum_all_sources(bool (*enum_proc)(void *, obs_source_t *),
|
|
void obs_enum_all_sources(bool (*enum_proc)(void *, obs_source_t *),
|
|
void *param)
|
|
void *param)
|
|
{
|
|
{
|
|
- obs_enum(&obs->data.first_source, &obs->data.sources_mutex, enum_proc,
|
|
|
|
- param);
|
|
|
|
|
|
+ obs_enum_uuid(&obs->data.sources, &obs->data.sources_mutex, enum_proc,
|
|
|
|
+ param);
|
|
}
|
|
}
|
|
|
|
|
|
void obs_enum_outputs(bool (*enum_proc)(void *, obs_output_t *), void *param)
|
|
void obs_enum_outputs(bool (*enum_proc)(void *, obs_output_t *), void *param)
|
|
@@ -1974,15 +2011,41 @@ static inline void *get_context_by_name(void *vfirst, const char *name,
|
|
|
|
|
|
pthread_mutex_lock(mutex);
|
|
pthread_mutex_lock(mutex);
|
|
|
|
|
|
- context = *first;
|
|
|
|
- while (context) {
|
|
|
|
- if (!context->private && strcmp(context->name, name) == 0) {
|
|
|
|
- context = addref(context);
|
|
|
|
- break;
|
|
|
|
|
|
+ /* If context list head has a hash table, look the name up in there */
|
|
|
|
+ if (*first && (*first)->hh.tbl) {
|
|
|
|
+ HASH_FIND_STR(*first, name, context);
|
|
|
|
+ } else {
|
|
|
|
+ context = *first;
|
|
|
|
+ while (context) {
|
|
|
|
+ if (!context->private &&
|
|
|
|
+ strcmp(context->name, name) == 0) {
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ context = context->next;
|
|
}
|
|
}
|
|
- context = context->next;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (context)
|
|
|
|
+ addref(context);
|
|
|
|
+
|
|
|
|
+ pthread_mutex_unlock(mutex);
|
|
|
|
+ return context;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void *get_context_by_uuid(void *ptable, const char *uuid,
|
|
|
|
+ pthread_mutex_t *mutex,
|
|
|
|
+ void *(*addref)(void *))
|
|
|
|
+{
|
|
|
|
+ struct obs_context_data **ht = ptable;
|
|
|
|
+ struct obs_context_data *context;
|
|
|
|
+
|
|
|
|
+ pthread_mutex_lock(mutex);
|
|
|
|
+
|
|
|
|
+ HASH_FIND_UUID(*ht, uuid, context);
|
|
|
|
+ if (context)
|
|
|
|
+ addref(context);
|
|
|
|
+
|
|
pthread_mutex_unlock(mutex);
|
|
pthread_mutex_unlock(mutex);
|
|
return context;
|
|
return context;
|
|
}
|
|
}
|
|
@@ -2014,38 +2077,27 @@ static inline void *obs_id_(void *data)
|
|
|
|
|
|
obs_source_t *obs_get_source_by_name(const char *name)
|
|
obs_source_t *obs_get_source_by_name(const char *name)
|
|
{
|
|
{
|
|
- return get_context_by_name(&obs->data.first_source, name,
|
|
|
|
|
|
+ return get_context_by_name(&obs->data.public_sources, name,
|
|
&obs->data.sources_mutex,
|
|
&obs->data.sources_mutex,
|
|
obs_source_addref_safe_);
|
|
obs_source_addref_safe_);
|
|
}
|
|
}
|
|
|
|
|
|
obs_source_t *obs_get_source_by_uuid(const char *uuid)
|
|
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;
|
|
|
|
|
|
+ return get_context_by_uuid(&obs->data.sources, uuid,
|
|
|
|
+ &obs->data.sources_mutex,
|
|
|
|
+ obs_source_addref_safe_);
|
|
}
|
|
}
|
|
|
|
|
|
obs_source_t *obs_get_transition_by_name(const char *name)
|
|
obs_source_t *obs_get_transition_by_name(const char *name)
|
|
{
|
|
{
|
|
- struct obs_source **first = &obs->data.first_source;
|
|
|
|
|
|
+ struct obs_source **first = &obs->data.sources;
|
|
struct obs_source *source;
|
|
struct obs_source *source;
|
|
|
|
|
|
pthread_mutex_lock(&obs->data.sources_mutex);
|
|
pthread_mutex_lock(&obs->data.sources_mutex);
|
|
|
|
|
|
|
|
+ /* Transitions are private but can be found via this method, so we
|
|
|
|
+ * can't look them up by name in the public_sources hash table. */
|
|
source = *first;
|
|
source = *first;
|
|
while (source) {
|
|
while (source) {
|
|
if (source->info.type == OBS_SOURCE_TYPE_TRANSITION &&
|
|
if (source->info.type == OBS_SOURCE_TYPE_TRANSITION &&
|
|
@@ -2053,13 +2105,18 @@ obs_source_t *obs_get_transition_by_name(const char *name)
|
|
source = obs_source_addref_safe_(source);
|
|
source = obs_source_addref_safe_(source);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
- source = (void *)source->context.next;
|
|
|
|
|
|
+ source = (void *)source->context.hh_uuid.next;
|
|
}
|
|
}
|
|
|
|
|
|
pthread_mutex_unlock(&obs->data.sources_mutex);
|
|
pthread_mutex_unlock(&obs->data.sources_mutex);
|
|
return source;
|
|
return source;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+obs_source_t *obs_get_transition_by_uuid(const char *uuid)
|
|
|
|
+{
|
|
|
|
+ return obs_get_source_by_uuid(uuid);
|
|
|
|
+}
|
|
|
|
+
|
|
obs_output_t *obs_get_output_by_name(const char *name)
|
|
obs_output_t *obs_get_output_by_name(const char *name)
|
|
{
|
|
{
|
|
return get_context_by_name(&obs->data.first_output, name,
|
|
return get_context_by_name(&obs->data.first_output, name,
|
|
@@ -2503,19 +2560,19 @@ obs_data_array_t *obs_save_sources_filtered(obs_save_source_filter_cb cb,
|
|
|
|
|
|
pthread_mutex_lock(&data->sources_mutex);
|
|
pthread_mutex_lock(&data->sources_mutex);
|
|
|
|
|
|
- source = data->first_source;
|
|
|
|
|
|
+ source = data->public_sources;
|
|
|
|
|
|
while (source) {
|
|
while (source) {
|
|
if ((source->info.type != OBS_SOURCE_TYPE_FILTER) != 0 &&
|
|
if ((source->info.type != OBS_SOURCE_TYPE_FILTER) != 0 &&
|
|
- !source->context.private && !source->removed &&
|
|
|
|
- !source->temp_removed && cb(data_, source)) {
|
|
|
|
|
|
+ !source->removed && !source->temp_removed &&
|
|
|
|
+ cb(data_, source)) {
|
|
obs_data_t *source_data = obs_save_source(source);
|
|
obs_data_t *source_data = obs_save_source(source);
|
|
|
|
|
|
obs_data_array_push_back(array, source_data);
|
|
obs_data_array_push_back(array, source_data);
|
|
obs_data_release(source_data);
|
|
obs_data_release(source_data);
|
|
}
|
|
}
|
|
|
|
|
|
- source = (obs_source_t *)source->context.next;
|
|
|
|
|
|
+ source = (obs_source_t *)source->context.hh.next;
|
|
}
|
|
}
|
|
|
|
|
|
pthread_mutex_unlock(&data->sources_mutex);
|
|
pthread_mutex_unlock(&data->sources_mutex);
|
|
@@ -2539,14 +2596,25 @@ void obs_reset_source_uuids()
|
|
{
|
|
{
|
|
pthread_mutex_lock(&obs->data.sources_mutex);
|
|
pthread_mutex_lock(&obs->data.sources_mutex);
|
|
|
|
|
|
- struct obs_source *source = obs->data.first_source;
|
|
|
|
- while (source) {
|
|
|
|
- bfree((void *)source->context.uuid);
|
|
|
|
- source->context.uuid = os_generate_uuid();
|
|
|
|
|
|
+ /* Move all sources to a new hash table */
|
|
|
|
+ struct obs_context_data *ht =
|
|
|
|
+ (struct obs_context_data *)obs->data.sources;
|
|
|
|
+ struct obs_context_data *new_ht = NULL;
|
|
|
|
+
|
|
|
|
+ struct obs_context_data *ctx, *tmp;
|
|
|
|
+ HASH_ITER (hh_uuid, ht, ctx, tmp) {
|
|
|
|
+ HASH_DELETE(hh_uuid, ht, ctx);
|
|
|
|
|
|
- source = (struct obs_source *)source->context.next;
|
|
|
|
|
|
+ bfree((void *)ctx->uuid);
|
|
|
|
+ ctx->uuid = os_generate_uuid();
|
|
|
|
+
|
|
|
|
+ HASH_ADD_UUID(new_ht, uuid, ctx);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* The old table will be automatically freed once the last element has
|
|
|
|
+ * been removed, so we can simply overwrite the pointer. */
|
|
|
|
+ obs->data.sources = (struct obs_source *)new_ht;
|
|
|
|
+
|
|
pthread_mutex_unlock(&obs->data.sources_mutex);
|
|
pthread_mutex_unlock(&obs->data.sources_mutex);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2662,6 +2730,91 @@ void obs_context_data_insert(struct obs_context_data *context,
|
|
pthread_mutex_unlock(mutex);
|
|
pthread_mutex_unlock(mutex);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static inline char *obs_context_deduplicate_name(void *phash, const char *name)
|
|
|
|
+{
|
|
|
|
+ struct obs_context_data *head = phash;
|
|
|
|
+ struct obs_context_data *item = NULL;
|
|
|
|
+
|
|
|
|
+ HASH_FIND_STR(head, name, item);
|
|
|
|
+ if (!item)
|
|
|
|
+ return NULL;
|
|
|
|
+
|
|
|
|
+ struct dstr new_name = {0};
|
|
|
|
+ int suffix = 2;
|
|
|
|
+
|
|
|
|
+ while (item) {
|
|
|
|
+ dstr_printf(&new_name, "%s %d", name, suffix++);
|
|
|
|
+ HASH_FIND_STR(head, new_name.array, item);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return new_name.array;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void obs_context_data_insert_name(struct obs_context_data *context,
|
|
|
|
+ pthread_mutex_t *mutex, void *pfirst)
|
|
|
|
+{
|
|
|
|
+ struct obs_context_data **first = pfirst;
|
|
|
|
+ char *new_name;
|
|
|
|
+
|
|
|
|
+ assert(context);
|
|
|
|
+ assert(mutex);
|
|
|
|
+ assert(first);
|
|
|
|
+
|
|
|
|
+ context->mutex = mutex;
|
|
|
|
+
|
|
|
|
+ pthread_mutex_lock(mutex);
|
|
|
|
+
|
|
|
|
+ /* Ensure name is not a duplicate. */
|
|
|
|
+ new_name = obs_context_deduplicate_name(*first, context->name);
|
|
|
|
+ if (new_name) {
|
|
|
|
+ blog(LOG_WARNING,
|
|
|
|
+ "Attempted to insert context with duplicate name \"%s\"!"
|
|
|
|
+ " Name has been changed to \"%s\"",
|
|
|
|
+ context->name, new_name);
|
|
|
|
+ /* Since this happens before the context creation finishes,
|
|
|
|
+ * do not bother to add it to the rename cache. */
|
|
|
|
+ bfree(context->name);
|
|
|
|
+ context->name = new_name;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ HASH_ADD_STR(*first, name, context);
|
|
|
|
+
|
|
|
|
+ pthread_mutex_unlock(mutex);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void obs_context_data_insert_uuid(struct obs_context_data *context,
|
|
|
|
+ pthread_mutex_t *mutex, void *pfirst_uuid)
|
|
|
|
+{
|
|
|
|
+ struct obs_context_data **first_uuid = pfirst_uuid;
|
|
|
|
+ struct obs_context_data *item = NULL;
|
|
|
|
+
|
|
|
|
+ assert(context);
|
|
|
|
+ assert(mutex);
|
|
|
|
+ assert(first_uuid);
|
|
|
|
+
|
|
|
|
+ context->mutex = mutex;
|
|
|
|
+
|
|
|
|
+ pthread_mutex_lock(mutex);
|
|
|
|
+
|
|
|
|
+ /* Ensure UUID is not a duplicate.
|
|
|
|
+ * This should only ever happen if a scene collection file has been
|
|
|
|
+ * manually edited and an entry has been duplicated without removing
|
|
|
|
+ * or regenerating the UUID. */
|
|
|
|
+ HASH_FIND_UUID(*first_uuid, context->uuid, item);
|
|
|
|
+ if (item) {
|
|
|
|
+ blog(LOG_WARNING,
|
|
|
|
+ "Attempted to insert context with duplicate UUID \"%s\"!",
|
|
|
|
+ context->uuid);
|
|
|
|
+ /* It is practically impossible for the new UUID to be a
|
|
|
|
+ * duplicate, so don't bother checking again. */
|
|
|
|
+ bfree((void *)context->uuid);
|
|
|
|
+ context->uuid = os_generate_uuid();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ HASH_ADD_UUID(*first_uuid, uuid, context);
|
|
|
|
+ pthread_mutex_unlock(mutex);
|
|
|
|
+}
|
|
|
|
+
|
|
void obs_context_data_remove(struct obs_context_data *context)
|
|
void obs_context_data_remove(struct obs_context_data *context)
|
|
{
|
|
{
|
|
if (context && context->prev_next) {
|
|
if (context && context->prev_next) {
|
|
@@ -2674,6 +2827,35 @@ void obs_context_data_remove(struct obs_context_data *context)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void obs_context_data_remove_name(struct obs_context_data *context, void *phead)
|
|
|
|
+{
|
|
|
|
+ struct obs_context_data **head = phead;
|
|
|
|
+
|
|
|
|
+ assert(head);
|
|
|
|
+
|
|
|
|
+ if (!context)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ pthread_mutex_lock(context->mutex);
|
|
|
|
+ HASH_DELETE(hh, *head, context);
|
|
|
|
+ pthread_mutex_unlock(context->mutex);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void obs_context_data_remove_uuid(struct obs_context_data *context,
|
|
|
|
+ void *puuid_head)
|
|
|
|
+{
|
|
|
|
+ struct obs_context_data **uuid_head = puuid_head;
|
|
|
|
+
|
|
|
|
+ assert(uuid_head);
|
|
|
|
+
|
|
|
|
+ if (!context || !context->uuid || !uuid_head)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ pthread_mutex_lock(context->mutex);
|
|
|
|
+ HASH_DELETE(hh_uuid, *uuid_head, context);
|
|
|
|
+ pthread_mutex_unlock(context->mutex);
|
|
|
|
+}
|
|
|
|
+
|
|
void obs_context_wait(struct obs_context_data *context)
|
|
void obs_context_wait(struct obs_context_data *context)
|
|
{
|
|
{
|
|
pthread_mutex_lock(context->mutex);
|
|
pthread_mutex_lock(context->mutex);
|
|
@@ -2692,6 +2874,37 @@ void obs_context_data_setname(struct obs_context_data *context,
|
|
pthread_mutex_unlock(&context->rename_cache_mutex);
|
|
pthread_mutex_unlock(&context->rename_cache_mutex);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+void obs_context_data_setname_ht(struct obs_context_data *context,
|
|
|
|
+ const char *name, void *phead)
|
|
|
|
+{
|
|
|
|
+ struct obs_context_data **head = phead;
|
|
|
|
+ char *new_name;
|
|
|
|
+
|
|
|
|
+ pthread_mutex_lock(context->mutex);
|
|
|
|
+ pthread_mutex_lock(&context->rename_cache_mutex);
|
|
|
|
+
|
|
|
|
+ HASH_DEL(*head, context);
|
|
|
|
+ if (context->name)
|
|
|
|
+ da_push_back(context->rename_cache, &context->name);
|
|
|
|
+
|
|
|
|
+ /* Ensure new name is not a duplicate. */
|
|
|
|
+ new_name = obs_context_deduplicate_name(*head, name);
|
|
|
|
+ if (new_name) {
|
|
|
|
+ blog(LOG_WARNING,
|
|
|
|
+ "Attempted to rename context to duplicate name \"%s\"!"
|
|
|
|
+ " New name has been changed to \"%s\"",
|
|
|
|
+ context->name, new_name);
|
|
|
|
+ context->name = new_name;
|
|
|
|
+ } else {
|
|
|
|
+ context->name = dup_name(name, context->private);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ HASH_ADD_STR(*head, name, context);
|
|
|
|
+
|
|
|
|
+ pthread_mutex_unlock(&context->rename_cache_mutex);
|
|
|
|
+ pthread_mutex_unlock(context->mutex);
|
|
|
|
+}
|
|
|
|
+
|
|
profiler_name_store_t *obs_get_profiler_name_store(void)
|
|
profiler_name_store_t *obs_get_profiler_name_store(void)
|
|
{
|
|
{
|
|
return obs->name_store;
|
|
return obs->name_store;
|