1 /******************************************************************************
2     Copyright (C) 2017 by Hugh Bailey <jim@obsproject.com>
3 
4     This program is free software: you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation, either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 ******************************************************************************/
17 
18 #include "obs-scripting-lua.h"
19 #include "cstrcache.h"
20 
21 #include <obs-module.h>
22 
23 /* ========================================================================= */
24 
get_table_string_(lua_State * script,int idx,const char * name,const char * func)25 static inline const char *get_table_string_(lua_State *script, int idx,
26 					    const char *name, const char *func)
27 {
28 	const char *str = "";
29 
30 	lua_pushstring(script, name);
31 	lua_gettable(script, idx - 1);
32 	if (!lua_isstring(script, -1))
33 		warn("%s: no item '%s' of type %s", func, name, "string");
34 	else
35 		str = cstrcache_get(lua_tostring(script, -1));
36 	lua_pop(script, 1);
37 
38 	return str;
39 }
40 
get_table_int_(lua_State * script,int idx,const char * name,const char * func)41 static inline int get_table_int_(lua_State *script, int idx, const char *name,
42 				 const char *func)
43 {
44 	int val = 0;
45 
46 	lua_pushstring(script, name);
47 	lua_gettable(script, idx - 1);
48 	val = (int)lua_tointeger(script, -1);
49 	lua_pop(script, 1);
50 
51 	UNUSED_PARAMETER(func);
52 
53 	return val;
54 }
55 
get_callback_from_table_(lua_State * script,int idx,const char * name,int * p_reg_idx,const char * func)56 static inline void get_callback_from_table_(lua_State *script, int idx,
57 					    const char *name, int *p_reg_idx,
58 					    const char *func)
59 {
60 	*p_reg_idx = LUA_REFNIL;
61 
62 	lua_pushstring(script, name);
63 	lua_gettable(script, idx - 1);
64 	if (!lua_isfunction(script, -1)) {
65 		if (!lua_isnil(script, -1)) {
66 			warn("%s: item '%s' is not a function", func, name);
67 		}
68 		lua_pop(script, 1);
69 	} else {
70 		*p_reg_idx = luaL_ref(script, LUA_REGISTRYINDEX);
71 	}
72 }
73 
74 #define get_table_string(script, idx, name) \
75 	get_table_string_(script, idx, name, __FUNCTION__)
76 #define get_table_int(script, idx, name) \
77 	get_table_int_(script, idx, name, __FUNCTION__)
78 #define get_callback_from_table(script, idx, name, p_reg_idx) \
79 	get_callback_from_table_(script, idx, name, p_reg_idx, __FUNCTION__)
80 
ls_get_libobs_obj_(lua_State * script,const char * type,int lua_idx,void * libobs_out,const char * id,const char * func,int line)81 bool ls_get_libobs_obj_(lua_State *script, const char *type, int lua_idx,
82 			void *libobs_out, const char *id, const char *func,
83 			int line)
84 {
85 	swig_type_info *info = SWIG_TypeQuery(script, type);
86 	if (info == NULL) {
87 		warn("%s:%d: SWIG could not find type: %s%s%s", func, line,
88 		     id ? id : "", id ? "::" : "", type);
89 		return false;
90 	}
91 
92 	int ret = SWIG_ConvertPtr(script, lua_idx, libobs_out, info, 0);
93 	if (!SWIG_IsOK(ret)) {
94 		warn("%s:%d: SWIG failed to convert lua object to obs "
95 		     "object: %s%s%s",
96 		     func, line, id ? id : "", id ? "::" : "", type);
97 		return false;
98 	}
99 
100 	return true;
101 }
102 
103 #define ls_get_libobs_obj(type, lua_index, obs_obj)                            \
104 	ls_get_libobs_obj_(ls->script, #type " *", lua_index, obs_obj, ls->id, \
105 			   __FUNCTION__, __LINE__)
106 
ls_push_libobs_obj_(lua_State * script,const char * type,void * libobs_in,bool ownership,const char * id,const char * func,int line)107 bool ls_push_libobs_obj_(lua_State *script, const char *type, void *libobs_in,
108 			 bool ownership, const char *id, const char *func,
109 			 int line)
110 {
111 	swig_type_info *info = SWIG_TypeQuery(script, type);
112 	if (info == NULL) {
113 		warn("%s:%d: SWIG could not find type: %s%s%s", func, line,
114 		     id ? id : "", id ? "::" : "", type);
115 		return false;
116 	}
117 
118 	SWIG_NewPointerObj(script, libobs_in, info, (int)ownership);
119 	return true;
120 }
121 
122 #define ls_push_libobs_obj(type, obs_obj, ownership)                    \
123 	ls_push_libobs_obj_(ls->script, #type " *", obs_obj, ownership, \
124 			    ls->id, __FUNCTION__, __LINE__)
125 
126 /* ========================================================================= */
127 
128 struct obs_lua_data;
129 
130 struct obs_lua_source {
131 	struct obs_lua_script *data;
132 
133 	lua_State *script;
134 	const char *id;
135 	const char *display_name;
136 	int func_create;
137 	int func_destroy;
138 	int func_get_width;
139 	int func_get_height;
140 	int func_get_defaults;
141 	int func_get_properties;
142 	int func_update;
143 	int func_activate;
144 	int func_deactivate;
145 	int func_show;
146 	int func_hide;
147 	int func_video_tick;
148 	int func_video_render;
149 	int func_save;
150 	int func_load;
151 
152 	pthread_mutex_t definition_mutex;
153 	struct obs_lua_data *first_source;
154 
155 	struct obs_lua_source *next;
156 	struct obs_lua_source **p_prev_next;
157 };
158 
159 extern pthread_mutex_t lua_source_def_mutex;
160 struct obs_lua_source *first_source_def = NULL;
161 
162 struct obs_lua_data {
163 	obs_source_t *source;
164 	struct obs_lua_source *ls;
165 	int lua_data_ref;
166 
167 	struct obs_lua_data *next;
168 	struct obs_lua_data **p_prev_next;
169 };
170 
171 #define call_func(name, args, rets)                                \
172 	call_func_(ls->script, ls->func_##name, args, rets, #name, \
173 		   ls->display_name)
174 #define have_func(name) (ls->func_##name != LUA_REFNIL)
175 #define ls_push_data() \
176 	lua_rawgeti(ls->script, LUA_REGISTRYINDEX, ld->lua_data_ref)
177 #define ls_pop(count) lua_pop(ls->script, count)
178 #define lock_script()                                              \
179 	struct obs_lua_script *__data = ls->data;                  \
180 	struct obs_lua_script *__prev_script = current_lua_script; \
181 	current_lua_script = __data;                               \
182 	pthread_mutex_lock(&__data->mutex);
183 #define unlock_script()                       \
184 	pthread_mutex_unlock(&__data->mutex); \
185 	current_lua_script = __prev_script;
186 
obs_lua_source_get_name(void * type_data)187 static const char *obs_lua_source_get_name(void *type_data)
188 {
189 	struct obs_lua_source *ls = type_data;
190 	return ls->display_name;
191 }
192 
obs_lua_source_create(obs_data_t * settings,obs_source_t * source)193 static void *obs_lua_source_create(obs_data_t *settings, obs_source_t *source)
194 {
195 	struct obs_lua_source *ls = obs_source_get_type_data(source);
196 	struct obs_lua_data *data = NULL;
197 
198 	pthread_mutex_lock(&ls->definition_mutex);
199 	if (!ls->script)
200 		goto fail;
201 	if (!have_func(create))
202 		goto fail;
203 
204 	lock_script();
205 
206 	ls_push_libobs_obj(obs_data_t, settings, false);
207 	ls_push_libobs_obj(obs_source_t, source, false);
208 	call_func(create, 2, 1);
209 
210 	int lua_data_ref = luaL_ref(ls->script, LUA_REGISTRYINDEX);
211 	if (lua_data_ref != LUA_REFNIL) {
212 		data = bmalloc(sizeof(*data));
213 		data->source = source;
214 		data->ls = ls;
215 		data->lua_data_ref = lua_data_ref;
216 	}
217 
218 	unlock_script();
219 
220 	if (data) {
221 		struct obs_lua_data *next = ls->first_source;
222 		data->next = next;
223 		data->p_prev_next = &ls->first_source;
224 		if (next)
225 			next->p_prev_next = &data->next;
226 		ls->first_source = data;
227 	}
228 
229 fail:
230 	pthread_mutex_unlock(&ls->definition_mutex);
231 	return data;
232 }
233 
call_destroy(struct obs_lua_data * ld)234 static void call_destroy(struct obs_lua_data *ld)
235 {
236 	struct obs_lua_source *ls = ld->ls;
237 
238 	ls_push_data();
239 	call_func(destroy, 1, 0);
240 	luaL_unref(ls->script, LUA_REGISTRYINDEX, ld->lua_data_ref);
241 	ld->lua_data_ref = LUA_REFNIL;
242 }
243 
obs_lua_source_destroy(void * data)244 static void obs_lua_source_destroy(void *data)
245 {
246 	struct obs_lua_data *ld = data;
247 	struct obs_lua_source *ls = ld->ls;
248 	struct obs_lua_data *next;
249 
250 	pthread_mutex_lock(&ls->definition_mutex);
251 	if (!ls->script)
252 		goto fail;
253 	if (!have_func(destroy))
254 		goto fail;
255 
256 	lock_script();
257 	call_destroy(ld);
258 	unlock_script();
259 
260 fail:
261 	next = ld->next;
262 	*ld->p_prev_next = next;
263 	if (next)
264 		next->p_prev_next = ld->p_prev_next;
265 
266 	bfree(data);
267 	pthread_mutex_unlock(&ls->definition_mutex);
268 }
269 
obs_lua_source_get_width(void * data)270 static uint32_t obs_lua_source_get_width(void *data)
271 {
272 	struct obs_lua_data *ld = data;
273 	struct obs_lua_source *ls = ld->ls;
274 	uint32_t width = 0;
275 
276 	pthread_mutex_lock(&ls->definition_mutex);
277 	if (!ls->script)
278 		goto fail;
279 	if (!have_func(get_width))
280 		goto fail;
281 
282 	lock_script();
283 
284 	ls_push_data();
285 	if (call_func(get_width, 1, 1)) {
286 		width = (uint32_t)lua_tointeger(ls->script, -1);
287 		ls_pop(1);
288 	}
289 
290 	unlock_script();
291 
292 fail:
293 	pthread_mutex_unlock(&ls->definition_mutex);
294 	return width;
295 }
296 
obs_lua_source_get_height(void * data)297 static uint32_t obs_lua_source_get_height(void *data)
298 {
299 	struct obs_lua_data *ld = data;
300 	struct obs_lua_source *ls = ld->ls;
301 	uint32_t height = 0;
302 
303 	pthread_mutex_lock(&ls->definition_mutex);
304 	if (!ls->script)
305 		goto fail;
306 	if (!have_func(get_height))
307 		goto fail;
308 
309 	lock_script();
310 
311 	ls_push_data();
312 	if (call_func(get_height, 1, 1)) {
313 		height = (uint32_t)lua_tointeger(ls->script, -1);
314 		ls_pop(1);
315 	}
316 
317 	unlock_script();
318 
319 fail:
320 	pthread_mutex_unlock(&ls->definition_mutex);
321 	return height;
322 }
323 
obs_lua_source_get_defaults(void * type_data,obs_data_t * settings)324 static void obs_lua_source_get_defaults(void *type_data, obs_data_t *settings)
325 {
326 	struct obs_lua_source *ls = type_data;
327 
328 	pthread_mutex_lock(&ls->definition_mutex);
329 	if (!ls->script)
330 		goto fail;
331 	if (!have_func(get_defaults))
332 		goto fail;
333 
334 	lock_script();
335 
336 	ls_push_libobs_obj(obs_data_t, settings, false);
337 	call_func(get_defaults, 1, 0);
338 
339 	unlock_script();
340 
341 fail:
342 	pthread_mutex_unlock(&ls->definition_mutex);
343 }
344 
obs_lua_source_get_properties(void * data)345 static obs_properties_t *obs_lua_source_get_properties(void *data)
346 {
347 	struct obs_lua_data *ld = data;
348 	struct obs_lua_source *ls = ld->ls;
349 	obs_properties_t *props = NULL;
350 
351 	pthread_mutex_lock(&ls->definition_mutex);
352 	if (!ls->script)
353 		goto fail;
354 	if (!have_func(get_properties))
355 		goto fail;
356 
357 	lock_script();
358 
359 	ls_push_data();
360 	if (call_func(get_properties, 1, 1)) {
361 		ls_get_libobs_obj(obs_properties_t, -1, &props);
362 		ls_pop(1);
363 	}
364 
365 	unlock_script();
366 
367 fail:
368 	pthread_mutex_unlock(&ls->definition_mutex);
369 	return props;
370 }
371 
obs_lua_source_update(void * data,obs_data_t * settings)372 static void obs_lua_source_update(void *data, obs_data_t *settings)
373 {
374 	struct obs_lua_data *ld = data;
375 	struct obs_lua_source *ls = ld->ls;
376 
377 	pthread_mutex_lock(&ls->definition_mutex);
378 	if (!ls->script)
379 		goto fail;
380 	if (!have_func(update))
381 		goto fail;
382 
383 	lock_script();
384 
385 	ls_push_data();
386 	ls_push_libobs_obj(obs_data_t, settings, false);
387 	call_func(update, 2, 0);
388 
389 	unlock_script();
390 
391 fail:
392 	pthread_mutex_unlock(&ls->definition_mutex);
393 }
394 
395 #define DEFINE_VOID_DATA_CALLBACK(name)               \
396 	static void obs_lua_source_##name(void *data) \
397 	{                                             \
398 		struct obs_lua_data *ld = data;       \
399 		struct obs_lua_source *ls = ld->ls;   \
400 		if (!have_func(name))                 \
401 			return;                       \
402 		lock_script();                        \
403 		ls_push_data();                       \
404 		call_func(name, 1, 0);                \
405 		unlock_script();                      \
406 	}
407 DEFINE_VOID_DATA_CALLBACK(activate)
DEFINE_VOID_DATA_CALLBACK(deactivate)408 DEFINE_VOID_DATA_CALLBACK(deactivate)
409 DEFINE_VOID_DATA_CALLBACK(show)
410 DEFINE_VOID_DATA_CALLBACK(hide)
411 #undef DEFINE_VOID_DATA_CALLBACK
412 
413 static void obs_lua_source_video_tick(void *data, float seconds)
414 {
415 	struct obs_lua_data *ld = data;
416 	struct obs_lua_source *ls = ld->ls;
417 
418 	pthread_mutex_lock(&ls->definition_mutex);
419 	if (!ls->script)
420 		goto fail;
421 	if (!have_func(video_tick))
422 		goto fail;
423 
424 	lock_script();
425 
426 	ls_push_data();
427 	lua_pushnumber(ls->script, (double)seconds);
428 	call_func(video_tick, 2, 0);
429 
430 	unlock_script();
431 
432 fail:
433 	pthread_mutex_unlock(&ls->definition_mutex);
434 }
435 
obs_lua_source_video_render(void * data,gs_effect_t * effect)436 static void obs_lua_source_video_render(void *data, gs_effect_t *effect)
437 {
438 	struct obs_lua_data *ld = data;
439 	struct obs_lua_source *ls = ld->ls;
440 
441 	pthread_mutex_lock(&ls->definition_mutex);
442 	if (!ls->script)
443 		goto fail;
444 	if (!have_func(video_render))
445 		goto fail;
446 
447 	lock_script();
448 
449 	ls_push_data();
450 	ls_push_libobs_obj(gs_effect_t, effect, false);
451 	call_func(video_render, 2, 0);
452 
453 	unlock_script();
454 
455 fail:
456 	pthread_mutex_unlock(&ls->definition_mutex);
457 }
458 
obs_lua_source_save(void * data,obs_data_t * settings)459 static void obs_lua_source_save(void *data, obs_data_t *settings)
460 {
461 	struct obs_lua_data *ld = data;
462 	struct obs_lua_source *ls = ld->ls;
463 
464 	pthread_mutex_lock(&ls->definition_mutex);
465 	if (!ls->script)
466 		goto fail;
467 	if (!have_func(save))
468 		goto fail;
469 
470 	lock_script();
471 
472 	ls_push_data();
473 	ls_push_libobs_obj(obs_data_t, settings, false);
474 	call_func(save, 2, 0);
475 
476 	unlock_script();
477 
478 fail:
479 	pthread_mutex_unlock(&ls->definition_mutex);
480 }
481 
obs_lua_source_load(void * data,obs_data_t * settings)482 static void obs_lua_source_load(void *data, obs_data_t *settings)
483 {
484 	struct obs_lua_data *ld = data;
485 	struct obs_lua_source *ls = ld->ls;
486 
487 	pthread_mutex_lock(&ls->definition_mutex);
488 	if (!ls->script)
489 		goto fail;
490 	if (!have_func(load))
491 		goto fail;
492 
493 	lock_script();
494 
495 	ls_push_data();
496 	ls_push_libobs_obj(obs_data_t, settings, false);
497 	call_func(load, 2, 0);
498 
499 	unlock_script();
500 
501 fail:
502 	pthread_mutex_unlock(&ls->definition_mutex);
503 }
504 
source_type_unload(struct obs_lua_source * ls)505 static void source_type_unload(struct obs_lua_source *ls)
506 {
507 #define unref(name)                                      \
508 	luaL_unref(ls->script, LUA_REGISTRYINDEX, name); \
509 	name = LUA_REFNIL
510 
511 	unref(ls->func_create);
512 	unref(ls->func_destroy);
513 	unref(ls->func_get_width);
514 	unref(ls->func_get_height);
515 	unref(ls->func_get_defaults);
516 	unref(ls->func_get_properties);
517 	unref(ls->func_update);
518 	unref(ls->func_activate);
519 	unref(ls->func_deactivate);
520 	unref(ls->func_show);
521 	unref(ls->func_hide);
522 	unref(ls->func_video_tick);
523 	unref(ls->func_video_render);
524 	unref(ls->func_save);
525 	unref(ls->func_load);
526 #undef unref
527 }
528 
obs_lua_source_free_type_data(void * type_data)529 static void obs_lua_source_free_type_data(void *type_data)
530 {
531 	struct obs_lua_source *ls = type_data;
532 
533 	pthread_mutex_lock(&ls->definition_mutex);
534 
535 	if (ls->script) {
536 		lock_script();
537 		source_type_unload(ls);
538 		unlock_script();
539 		ls->script = NULL;
540 	}
541 
542 	pthread_mutex_unlock(&ls->definition_mutex);
543 	pthread_mutex_destroy(&ls->definition_mutex);
544 	bfree(ls);
545 }
546 
547 EXPORT void obs_enable_source_type(const char *name, bool enable);
548 
find_existing(const char * id)549 static inline struct obs_lua_source *find_existing(const char *id)
550 {
551 	struct obs_lua_source *existing = NULL;
552 
553 	pthread_mutex_lock(&lua_source_def_mutex);
554 	struct obs_lua_source *ls = first_source_def;
555 	while (ls) {
556 		/* can compare pointers here due to string table */
557 		if (ls->id == id) {
558 			existing = ls;
559 			break;
560 		}
561 
562 		ls = ls->next;
563 	}
564 	pthread_mutex_unlock(&lua_source_def_mutex);
565 
566 	return existing;
567 }
568 
obs_lua_register_source(lua_State * script)569 static int obs_lua_register_source(lua_State *script)
570 {
571 	struct obs_lua_source ls = {0};
572 	struct obs_lua_source *existing = NULL;
573 	struct obs_lua_source *v = NULL;
574 	struct obs_source_info info = {0};
575 	const char *id;
576 
577 	if (!verify_args1(script, is_table))
578 		goto fail;
579 
580 	id = get_table_string(script, -1, "id");
581 	if (!id || !*id)
582 		goto fail;
583 
584 	/* redefinition */
585 	existing = find_existing(id);
586 	if (existing) {
587 		if (existing->script) {
588 			existing = NULL;
589 			goto fail;
590 		}
591 
592 		pthread_mutex_lock(&existing->definition_mutex);
593 	}
594 
595 	v = existing ? existing : &ls;
596 
597 	v->script = script;
598 	v->id = id;
599 
600 	info.id = v->id;
601 	info.type = (enum obs_source_type)get_table_int(script, -1, "type");
602 
603 	info.output_flags = get_table_int(script, -1, "output_flags");
604 
605 	lua_pushstring(script, "get_name");
606 	lua_gettable(script, -2);
607 	if (lua_pcall(script, 0, 1, 0) == 0) {
608 		v->display_name = cstrcache_get(lua_tostring(script, -1));
609 		lua_pop(script, 1);
610 	}
611 
612 	if (!v->display_name || !*v->display_name || !*info.id ||
613 	    !info.output_flags)
614 		goto fail;
615 
616 #define get_callback(val)                                                  \
617 	do {                                                               \
618 		get_callback_from_table(script, -1, #val, &v->func_##val); \
619 		info.val = obs_lua_source_##val;                           \
620 	} while (false)
621 
622 	get_callback(create);
623 	get_callback(destroy);
624 	get_callback(get_width);
625 	get_callback(get_height);
626 	get_callback(get_properties);
627 	get_callback(update);
628 	get_callback(activate);
629 	get_callback(deactivate);
630 	get_callback(show);
631 	get_callback(hide);
632 	get_callback(video_tick);
633 	get_callback(video_render);
634 	get_callback(save);
635 	get_callback(load);
636 #undef get_callback
637 
638 	get_callback_from_table(script, -1, "get_defaults",
639 				&v->func_get_defaults);
640 
641 	if (!existing) {
642 		ls.data = current_lua_script;
643 
644 		pthread_mutex_init_recursive(&ls.definition_mutex);
645 
646 		info.type_data = bmemdup(&ls, sizeof(ls));
647 		info.free_type_data = obs_lua_source_free_type_data;
648 		info.get_name = obs_lua_source_get_name;
649 		info.get_defaults2 = obs_lua_source_get_defaults;
650 		obs_register_source(&info);
651 
652 		pthread_mutex_lock(&lua_source_def_mutex);
653 		v = info.type_data;
654 
655 		struct obs_lua_source *next = first_source_def;
656 		v->next = next;
657 		if (next)
658 			next->p_prev_next = &v->next;
659 		v->p_prev_next = &first_source_def;
660 		first_source_def = v;
661 
662 		pthread_mutex_unlock(&lua_source_def_mutex);
663 	} else {
664 		existing->script = script;
665 		existing->data = current_lua_script;
666 		obs_enable_source_type(id, true);
667 
668 		struct obs_lua_data *ld = v->first_source;
669 		while (ld) {
670 			struct obs_lua_source *ls = v;
671 
672 			if (have_func(create)) {
673 				obs_source_t *source = ld->source;
674 				obs_data_t *settings =
675 					obs_source_get_settings(source);
676 
677 				ls_push_libobs_obj(obs_data_t, settings, false);
678 				ls_push_libobs_obj(obs_source_t, source, false);
679 				call_func(create, 2, 1);
680 
681 				ld->lua_data_ref =
682 					luaL_ref(ls->script, LUA_REGISTRYINDEX);
683 				obs_data_release(settings);
684 			}
685 
686 			ld = ld->next;
687 		}
688 	}
689 
690 fail:
691 	if (existing) {
692 		pthread_mutex_unlock(&existing->definition_mutex);
693 	}
694 	return 0;
695 }
696 
697 /* ========================================================================= */
698 
add_lua_source_functions(lua_State * script)699 void add_lua_source_functions(lua_State *script)
700 {
701 	lua_getglobal(script, "obslua");
702 
703 	lua_pushstring(script, "obs_register_source");
704 	lua_pushcfunction(script, obs_lua_register_source);
705 	lua_rawset(script, -3);
706 
707 	lua_pop(script, 1);
708 }
709 
undef_source_type(struct obs_lua_script * data,struct obs_lua_source * ls)710 static inline void undef_source_type(struct obs_lua_script *data,
711 				     struct obs_lua_source *ls)
712 {
713 	pthread_mutex_lock(&ls->definition_mutex);
714 	pthread_mutex_lock(&data->mutex);
715 
716 	obs_enable_source_type(ls->id, false);
717 
718 	struct obs_lua_data *ld = ls->first_source;
719 	while (ld) {
720 		call_destroy(ld);
721 		ld = ld->next;
722 	}
723 
724 	source_type_unload(ls);
725 	ls->script = NULL;
726 
727 	pthread_mutex_unlock(&data->mutex);
728 	pthread_mutex_unlock(&ls->definition_mutex);
729 }
730 
undef_lua_script_sources(struct obs_lua_script * data)731 void undef_lua_script_sources(struct obs_lua_script *data)
732 {
733 	pthread_mutex_lock(&lua_source_def_mutex);
734 
735 	struct obs_lua_source *def = first_source_def;
736 	while (def) {
737 		if (def->script == data->script)
738 			undef_source_type(data, def);
739 		def = def->next;
740 	}
741 
742 	pthread_mutex_unlock(&lua_source_def_mutex);
743 }
744