1 /* GSequencer - Advanced GTK Sequencer
2  * Copyright (C) 2005-2020 Joël Krähemann
3  *
4  * This file is part of GSequencer.
5  *
6  * GSequencer is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GSequencer is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GSequencer.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <ags/plugin/ags_dssi_manager.h>
21 
22 #include <ags/plugin/ags_base_plugin.h>
23 
24 #if defined(AGS_W32API)
25 #include <windows.h>
26 #else
27 #include <dlfcn.h>
28 #endif
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/types.h>
34 #include <unistd.h>
35 
36 #include <string.h>
37 #include <strings.h>
38 
39 #include <dssi.h>
40 
41 #include <ags/config.h>
42 
43 void ags_dssi_manager_class_init(AgsDssiManagerClass *dssi_manager);
44 void ags_dssi_manager_init (AgsDssiManager *dssi_manager);
45 void ags_dssi_manager_dispose(GObject *gobject);
46 void ags_dssi_manager_finalize(GObject *gobject);
47 
48 /**
49  * SECTION:ags_dssi_manager
50  * @short_description: Singleton pattern to organize DSSI
51  * @title: AgsDssiManager
52  * @section_id:
53  * @include: ags/plugin/ags_dssi_manager.h
54  *
55  * The #AgsDssiManager loads/unloads DSSI plugins.
56  */
57 
58 static gpointer ags_dssi_manager_parent_class = NULL;
59 
60 AgsDssiManager *ags_dssi_manager = NULL;
61 gchar **ags_dssi_default_path = NULL;
62 
63 GType
ags_dssi_manager_get_type(void)64 ags_dssi_manager_get_type (void)
65 {
66   static volatile gsize g_define_type_id__volatile = 0;
67 
68   if(g_once_init_enter (&g_define_type_id__volatile)){
69     GType ags_type_dssi_manager = 0;
70 
71     static const GTypeInfo ags_dssi_manager_info = {
72       sizeof (AgsDssiManagerClass),
73       NULL, /* base_init */
74       NULL, /* base_finalize */
75       (GClassInitFunc) ags_dssi_manager_class_init,
76       NULL, /* class_finalize */
77       NULL, /* class_data */
78       sizeof (AgsDssiManager),
79       0,    /* n_preallocs */
80       (GInstanceInitFunc) ags_dssi_manager_init,
81     };
82 
83     ags_type_dssi_manager = g_type_register_static(G_TYPE_OBJECT,
84 						   "AgsDssiManager",
85 						   &ags_dssi_manager_info,
86 						   0);
87 
88     g_once_init_leave(&g_define_type_id__volatile, ags_type_dssi_manager);
89   }
90 
91   return g_define_type_id__volatile;
92 }
93 
94 void
ags_dssi_manager_class_init(AgsDssiManagerClass * dssi_manager)95 ags_dssi_manager_class_init(AgsDssiManagerClass *dssi_manager)
96 {
97   GObjectClass *gobject;
98 
99   ags_dssi_manager_parent_class = g_type_class_peek_parent(dssi_manager);
100 
101   /* GObjectClass */
102   gobject = (GObjectClass *) dssi_manager;
103 
104   gobject->dispose = ags_dssi_manager_dispose;
105   gobject->finalize = ags_dssi_manager_finalize;
106 }
107 
108 void
ags_dssi_manager_init(AgsDssiManager * dssi_manager)109 ags_dssi_manager_init(AgsDssiManager *dssi_manager)
110 {
111   /* dssi manager mutex */
112   g_rec_mutex_init(&(dssi_manager->obj_mutex));
113 
114   /* dssi plugin and path */
115   dssi_manager->dssi_plugin = NULL;
116 
117   if(ags_dssi_default_path == NULL){
118     gchar *dssi_env;
119 
120     if((dssi_env = getenv("DSSI_PATH")) != NULL){
121       gchar *iter, *next;
122       guint i;
123 
124       ags_dssi_default_path = (gchar **) malloc(sizeof(gchar *));
125 
126       iter = dssi_env;
127       i = 0;
128 
129       while((next = strchr(iter, G_SEARCHPATH_SEPARATOR)) != NULL){
130 	ags_dssi_default_path = (gchar **) realloc(ags_dssi_default_path,
131 						   (i + 2) * sizeof(gchar *));
132 	ags_dssi_default_path[i] = g_strndup(iter,
133 					     next - iter);
134 
135 	iter = next + 1;
136 	i++;
137       }
138 
139       if(*iter != '\0'){
140 	ags_dssi_default_path = (gchar **) realloc(ags_dssi_default_path,
141 						   (i + 2) * sizeof(gchar *));
142 	ags_dssi_default_path[i] = g_strdup(iter);
143 
144 	i++;
145       }
146 
147       ags_dssi_default_path[i] = NULL;
148     }else{
149 #if defined(AGS_W32API)
150       AgsApplicationContext *application_context;
151 
152       gchar *app_dir;
153       gchar *path;
154 
155       guint i;
156 
157       i = 0;
158 
159       application_context = ags_application_context_get_instance();
160 
161       app_dir = NULL;
162 
163       if(strlen(application_context->argv[0]) > strlen("\\gsequencer.exe")){
164 	app_dir = g_strndup(application_context->argv[0],
165 			    strlen(application_context->argv[0]) - strlen("\\gsequencer.exe"));
166       }
167 
168       ags_dssi_default_path = (gchar **) malloc(2 * sizeof(gchar *));
169 
170       path = g_strdup_printf("%s\\dssi",
171 			     g_get_current_dir());
172 
173       if(g_file_test(path,
174 		     G_FILE_TEST_IS_DIR)){
175 	ags_dssi_default_path[i++] = path;
176       }else{
177 	g_free(path);
178 
179 	if(g_path_is_absolute(app_dir)){
180 	  ags_dssi_default_path[i++] = g_strdup_printf("%s\\dssi",
181 						       app_dir);
182 	}else{
183 	  ags_dssi_default_path[i++] = g_strdup_printf("%s\\%s\\dssi",
184 						       g_get_current_dir(),
185 						       app_dir);
186 	}
187       }
188 
189       ags_dssi_default_path[i++] = NULL;
190 
191       g_free(app_dir);
192 #else
193       gchar *home_dir;
194       guint i;
195 
196 #ifdef AGS_MAC_BUNDLE
197       if((home_dir = getenv("HOME")) != NULL){
198 	ags_dssi_default_path = (gchar **) malloc(7 * sizeof(gchar *));
199       }else{
200 	ags_dssi_default_path = (gchar **) malloc(6 * sizeof(gchar *));
201       }
202 #else
203       if((home_dir = getenv("HOME")) != NULL){
204 	ags_dssi_default_path = (gchar **) malloc(6 * sizeof(gchar *));
205       }else{
206 	ags_dssi_default_path = (gchar **) malloc(5 * sizeof(gchar *));
207       }
208 #endif
209 
210       i = 0;
211 
212 #ifdef AGS_MAC_BUNDLE
213       ags_dssi_default_path[i++] = g_strdup_printf("%s/dssi",
214 						   getenv("GSEQUENCER_PLUGIN_DIR"));
215 #endif
216 
217       ags_dssi_default_path[i++] = g_strdup("/usr/lib64/dssi");
218       ags_dssi_default_path[i++] = g_strdup("/usr/local/lib64/dssi");
219       ags_dssi_default_path[i++] = g_strdup("/usr/lib/dssi");
220       ags_dssi_default_path[i++] = g_strdup("/usr/local/lib/dssi");
221 
222       if(home_dir != NULL){
223 	ags_dssi_default_path[i++] = g_strdup_printf("%s/.dssi",
224 						     home_dir);
225       }
226 
227       ags_dssi_default_path[i++] = NULL;
228 #endif
229     }
230   }
231 }
232 
233 void
ags_dssi_manager_dispose(GObject * gobject)234 ags_dssi_manager_dispose(GObject *gobject)
235 {
236   AgsDssiManager *dssi_manager;
237 
238   dssi_manager = AGS_DSSI_MANAGER(gobject);
239 
240   if(dssi_manager->dssi_plugin != NULL){
241     g_list_free_full(dssi_manager->dssi_plugin,
242 		     (GDestroyNotify) g_object_unref);
243 
244     dssi_manager->dssi_plugin = NULL;
245   }
246 
247   /* call parent */
248   G_OBJECT_CLASS(ags_dssi_manager_parent_class)->dispose(gobject);
249 }
250 
251 void
ags_dssi_manager_finalize(GObject * gobject)252 ags_dssi_manager_finalize(GObject *gobject)
253 {
254   AgsDssiManager *dssi_manager;
255 
256   GList *dssi_plugin;
257 
258   dssi_manager = AGS_DSSI_MANAGER(gobject);
259 
260   dssi_plugin = dssi_manager->dssi_plugin;
261 
262   g_list_free_full(dssi_plugin,
263 		   (GDestroyNotify) g_object_unref);
264 
265   if(dssi_manager == ags_dssi_manager){
266     ags_dssi_manager = NULL;
267   }
268 
269   /* call parent */
270   G_OBJECT_CLASS(ags_dssi_manager_parent_class)->finalize(gobject);
271 }
272 
273 /**
274  * ags_dssi_manager_get_default_path:
275  *
276  * Get dssi manager default plugin path.
277  *
278  * Returns: (element-type utf8) (array zero-terminated=1) (transfer none): the plugin default search path as a string vector
279  *
280  * Since: 3.0.0
281  */
282 gchar**
ags_dssi_manager_get_default_path()283 ags_dssi_manager_get_default_path()
284 {
285   return(ags_dssi_default_path);
286 }
287 
288 /**
289  * ags_dssi_manager_set_default_path:
290  * @default_path: (element-type utf8) (array zero-terminated=1) (transfer full): the string vector array to use as default path
291  *
292  * Set dssi manager default plugin path.
293  *
294  * Since: 3.0.0
295  */
296 void
ags_dssi_manager_set_default_path(gchar ** default_path)297 ags_dssi_manager_set_default_path(gchar** default_path)
298 {
299   ags_dssi_default_path = default_path;
300 }
301 
302 /**
303  * ags_dssi_manager_get_filenames:
304  * @dssi_manager: the #AgsDssiManager
305  *
306  * Retrieve all filenames
307  *
308  * Returns: (element-type utf8) (array zero-terminated=1) (transfer full): a %NULL-terminated array of filenames
309  *
310  * Since: 3.0.0
311  */
312 gchar**
ags_dssi_manager_get_filenames(AgsDssiManager * dssi_manager)313 ags_dssi_manager_get_filenames(AgsDssiManager *dssi_manager)
314 {
315   GList *start_dssi_plugin, *dssi_plugin;
316 
317   gchar **filenames;
318 
319   guint i;
320   gboolean contains_filename;
321 
322   GRecMutex *dssi_manager_mutex;
323   GRecMutex *base_plugin_mutex;
324 
325   if(!AGS_DSSI_MANAGER(dssi_manager)){
326     return(NULL);
327   }
328 
329   /* get dssi manager mutex */
330   dssi_manager_mutex = AGS_DSSI_MANAGER_GET_OBJ_MUTEX(dssi_manager);
331 
332   /* collect */
333   g_rec_mutex_lock(dssi_manager_mutex);
334 
335   dssi_plugin =
336     start_dssi_plugin = g_list_copy(dssi_manager->dssi_plugin);
337 
338   g_rec_mutex_unlock(dssi_manager_mutex);
339 
340   filenames = NULL;
341 
342   for(i = 0; dssi_plugin != NULL;){
343     gchar *filename;
344 
345     /* get base plugin mutex */
346     base_plugin_mutex = AGS_BASE_PLUGIN_GET_OBJ_MUTEX(dssi_plugin->data);
347 
348     /* duplicate filename */
349     g_rec_mutex_lock(base_plugin_mutex);
350 
351     filename = g_strdup(AGS_BASE_PLUGIN(dssi_plugin->data)->filename);
352 
353     g_rec_mutex_unlock(base_plugin_mutex);
354 
355     if(filenames == NULL){
356       filenames = (gchar **) malloc(2 * sizeof(gchar *));
357 
358       /* set filename */
359       filenames[i] = filename;
360 
361       /* terminate */
362       filenames[i + 1] = NULL;
363 
364       i++;
365     }else{
366 #ifdef HAVE_GLIB_2_44
367       contains_filename = g_strv_contains(filenames,
368 					  filename);
369 #else
370       contains_filename = ags_strv_contains(filenames,
371 					    filename);
372 #endif
373 
374       if(!contains_filename){
375 	filenames = (gchar **) realloc(filenames,
376 				       (i + 2) * sizeof(gchar *));
377 	filenames[i] = filename;
378 	filenames[i + 1] = NULL;
379 
380 	i++;
381       }else{
382 	g_free(filename);
383       }
384 
385     }
386 
387     dssi_plugin = dssi_plugin->next;
388   }
389 
390   g_list_free(start_dssi_plugin);
391 
392   return(filenames);
393 }
394 
395 /**
396  * ags_dssi_manager_find_dssi_plugin:
397  * @dssi_manager: the #AgsDssiManager
398  * @filename: the filename of the plugin
399  * @effect: the effect's name
400  *
401  * Lookup filename in loaded plugins.
402  *
403  * Returns: (transfer none): the matching #AgsDssiPlugin
404  *
405  * Since: 3.0.0
406  */
407 AgsDssiPlugin*
ags_dssi_manager_find_dssi_plugin(AgsDssiManager * dssi_manager,gchar * filename,gchar * effect)408 ags_dssi_manager_find_dssi_plugin(AgsDssiManager *dssi_manager,
409 				  gchar *filename, gchar *effect)
410 {
411   AgsDssiPlugin *dssi_plugin;
412 
413   GList *start_list, *list;
414 
415   gboolean success;
416 
417   GRecMutex *dssi_manager_mutex;
418   GRecMutex *base_plugin_mutex;
419 
420   if(!AGS_DSSI_MANAGER(dssi_manager)){
421     return(NULL);
422   }
423 
424   /* get dssi manager mutex */
425   dssi_manager_mutex = AGS_DSSI_MANAGER_GET_OBJ_MUTEX(dssi_manager);
426 
427   /* collect */
428   g_rec_mutex_lock(dssi_manager_mutex);
429 
430   list =
431     start_list = g_list_copy(dssi_manager->dssi_plugin);
432 
433   g_rec_mutex_unlock(dssi_manager_mutex);
434 
435   success = FALSE;
436 
437   while(list != NULL){
438     dssi_plugin = AGS_DSSI_PLUGIN(list->data);
439 
440     /* get base plugin mutex */
441     base_plugin_mutex = AGS_BASE_PLUGIN_GET_OBJ_MUTEX(dssi_plugin);
442 
443     /* check filename and effect */
444     g_rec_mutex_lock(base_plugin_mutex);
445 
446     success = (!g_strcmp0(AGS_BASE_PLUGIN(dssi_plugin)->filename,
447 			  filename) &&
448 	       !g_strcmp0(AGS_BASE_PLUGIN(dssi_plugin)->effect,
449 			  effect)) ? TRUE: FALSE;
450 
451     g_rec_mutex_unlock(base_plugin_mutex);
452 
453     if(success){
454       break;
455     }
456 
457     list = list->next;
458   }
459 
460   g_list_free(start_list);
461 
462   if(!success){
463     dssi_plugin = NULL;
464   }
465 
466   return(dssi_plugin);
467 }
468 
469 /**
470  * ags_dssi_manager_find_dssi_plugin_with_fallback:
471  * @dssi_manager: the #AgsDssiManager
472  * @filename: the filename of the plugin
473  * @effect: the effect's name
474  *
475  * Lookup filename in loaded plugins.
476  *
477  * Returns: (transfer none): the matching #AgsDssiPlugin
478  *
479  * Since: 3.5.10
480  */
481 AgsDssiPlugin*
ags_dssi_manager_find_dssi_plugin_with_fallback(AgsDssiManager * dssi_manager,gchar * filename,gchar * effect)482 ags_dssi_manager_find_dssi_plugin_with_fallback(AgsDssiManager *dssi_manager,
483 						gchar *filename, gchar *effect)
484 {
485   AgsDssiPlugin *dssi_plugin;
486 
487   GList *start_list, *list;
488 
489   gchar *filename_suffix;
490 
491   gboolean success;
492 
493   GRecMutex *dssi_manager_mutex;
494   GRecMutex *base_plugin_mutex;
495 
496   if(!AGS_DSSI_MANAGER(dssi_manager) ||
497      filename == NULL ||
498      effect == NULL){
499     return(NULL);
500   }
501 
502   /* get dssi manager mutex */
503   dssi_manager_mutex = AGS_DSSI_MANAGER_GET_OBJ_MUTEX(dssi_manager);
504 
505   dssi_plugin = ags_dssi_manager_find_dssi_plugin(dssi_manager,
506 						  filename, effect);
507 
508   if(dssi_plugin == NULL){
509     filename_suffix = strrchr(filename, "/");
510 
511     /* collect */
512     g_rec_mutex_lock(dssi_manager_mutex);
513 
514     list =
515       start_list = g_list_copy(dssi_manager->dssi_plugin);
516 
517     g_rec_mutex_unlock(dssi_manager_mutex);
518 
519     success = FALSE;
520 
521     while(list != NULL){
522       dssi_plugin = AGS_DSSI_PLUGIN(list->data);
523 
524       /* get base plugin mutex */
525       base_plugin_mutex = AGS_BASE_PLUGIN_GET_OBJ_MUTEX(dssi_plugin);
526 
527       /* check filename and effect */
528       g_rec_mutex_lock(base_plugin_mutex);
529 
530       success = (g_str_has_suffix(AGS_BASE_PLUGIN(dssi_plugin)->filename,
531 				  filename_suffix) &&
532 		 !g_strcmp0(AGS_BASE_PLUGIN(dssi_plugin)->effect,
533 			    effect)) ? TRUE: FALSE;
534 
535       g_rec_mutex_unlock(base_plugin_mutex);
536 
537       if(success){
538 	break;
539       }
540 
541       list = list->next;
542     }
543 
544     g_list_free(start_list);
545 
546     if(!success){
547       dssi_plugin = NULL;
548     }
549   }
550 
551   return(dssi_plugin);
552 }
553 
554 /**
555  * ags_dssi_manager_load_blacklist:
556  * @dssi_manager: the #AgsDssiManager
557  * @blacklist_filename: the filename as string
558  *
559  * Load blacklisted plugin filenames.
560  *
561  * Since: 3.0.0
562  */
563 void
ags_dssi_manager_load_blacklist(AgsDssiManager * dssi_manager,gchar * blacklist_filename)564 ags_dssi_manager_load_blacklist(AgsDssiManager *dssi_manager,
565 				gchar *blacklist_filename)
566 {
567   GRecMutex *dssi_manager_mutex;
568 
569   if(!AGS_DSSI_MANAGER(dssi_manager) ||
570      blacklist_filename == NULL){
571     return;
572   }
573 
574   /* get dssi manager mutex */
575   dssi_manager_mutex = AGS_DSSI_MANAGER_GET_OBJ_MUTEX(dssi_manager);
576 
577   /* fill in */
578   g_rec_mutex_lock(dssi_manager_mutex);
579 
580   if(g_file_test(blacklist_filename,
581 		 (G_FILE_TEST_EXISTS |
582 		  G_FILE_TEST_IS_REGULAR))){
583     FILE *file;
584 
585     gchar *str;
586 
587     file = fopen(blacklist_filename,
588 		 "r");
589 
590 #ifndef AGS_W32API
591     while(getline(&str, NULL, file) != -1){
592       dssi_manager->dssi_plugin_blacklist = g_list_prepend(dssi_manager->dssi_plugin_blacklist,
593 							   str);
594     }
595 #endif
596   }
597 
598   g_rec_mutex_unlock(dssi_manager_mutex);
599 }
600 
601 /**
602  * ags_dssi_manager_load_file:
603  * @dssi_manager: the #AgsDssiManager
604  * @dssi_path: the dssi path
605  * @filename: the filename of the plugin
606  *
607  * Load @filename specified plugin.
608  *
609  * Since: 3.0.0
610  */
611 void
ags_dssi_manager_load_file(AgsDssiManager * dssi_manager,gchar * dssi_path,gchar * filename)612 ags_dssi_manager_load_file(AgsDssiManager *dssi_manager,
613 			   gchar *dssi_path,
614 			   gchar *filename)
615 {
616   AgsDssiPlugin *dssi_plugin;
617 
618   gchar *path;
619   gchar *effect;
620 
621   void *plugin_so;
622   DSSI_Descriptor_Function dssi_descriptor;
623   DSSI_Descriptor *plugin_descriptor;
624   unsigned long i;
625   gboolean success;
626 
627   GRecMutex *dssi_manager_mutex;
628 
629   if(!AGS_IS_DSSI_MANAGER(dssi_manager) ||
630      dssi_path == NULL ||
631      filename == NULL){
632     return;
633   }
634 
635   /* get dssi manager mutex */
636   dssi_manager_mutex = AGS_DSSI_MANAGER_GET_OBJ_MUTEX(dssi_manager);
637 
638   /* load */
639   g_rec_mutex_lock(dssi_manager_mutex);
640 
641   path = g_strdup_printf("%s%c%s",
642 			 dssi_path,
643 			 G_DIR_SEPARATOR,
644 			 filename);
645 
646   g_message("ags_dssi_manager.c loading - %s", path);
647 
648 #ifdef AGS_W32API
649   plugin_so = LoadLibrary(path);
650 #else
651   plugin_so = dlopen(path,
652 		     RTLD_NOW);
653 #endif
654 
655   if(plugin_so == NULL){
656     g_warning("ags_dssi_manager.c - failed to load static object file");
657 
658 #ifndef AGS_W32API
659     dlerror();
660 #endif
661 
662     g_rec_mutex_unlock(dssi_manager_mutex);
663 
664     return;
665   }
666 
667   success = FALSE;
668 
669 #ifdef AGS_W32API
670   dssi_descriptor = (DSSI_Descriptor_Function) GetProcAddress(plugin_so,
671 							      "dssi_descriptor");
672 
673   success = (!dssi_descriptor) ? FALSE: TRUE;
674 #else
675   dssi_descriptor = (DSSI_Descriptor_Function) dlsym(plugin_so,
676 						     "dssi_descriptor");
677 
678   success = (dlerror() == NULL) ? TRUE: FALSE;
679 #endif
680 
681   if(success && dssi_descriptor){
682     for(i = 0; (plugin_descriptor = dssi_descriptor(i)) != NULL; i++){
683       if(ags_base_plugin_find_effect(dssi_manager->dssi_plugin,
684 				     path,
685 				     plugin_descriptor->LADSPA_Plugin->Name) == NULL){
686 	dssi_plugin = ags_dssi_plugin_new(path,
687 					  plugin_descriptor->LADSPA_Plugin->Name,
688 					  i);
689 	ags_base_plugin_load_plugin((AgsBasePlugin *) dssi_plugin);
690 	dssi_manager->dssi_plugin = g_list_prepend(dssi_manager->dssi_plugin,
691 						   dssi_plugin);
692       }
693     }
694   }
695 
696   g_rec_mutex_unlock(dssi_manager_mutex);
697 
698   g_free(path);
699 }
700 
701 /**
702  * ags_dssi_manager_load_default_directory:
703  * @dssi_manager: the #AgsDssiManager
704  *
705  * Loads all available plugins.
706  *
707  * Since: 3.0.0
708  */
709 void
ags_dssi_manager_load_default_directory(AgsDssiManager * dssi_manager)710 ags_dssi_manager_load_default_directory(AgsDssiManager *dssi_manager)
711 {
712   AgsDssiPlugin *dssi_plugin;
713 
714   GDir *dir;
715 
716   gchar **dssi_path;
717   gchar *filename;
718 
719   GError *error;
720 
721   if(!AGS_DSSI_MANAGER(dssi_manager)){
722     return;
723   }
724 
725   dssi_path = ags_dssi_default_path;
726 
727   while(*dssi_path != NULL){
728     if(!g_file_test(*dssi_path,
729 		    G_FILE_TEST_EXISTS)){
730       dssi_path++;
731 
732       continue;
733     }
734 
735     error = NULL;
736     dir = g_dir_open(*dssi_path,
737 		     0,
738 		     &error);
739 
740     if(error != NULL){
741       g_warning("%s", error->message);
742 
743       dssi_path++;
744 
745       g_error_free(error);
746 
747       continue;
748     }
749 
750     while((filename = g_dir_read_name(dir)) != NULL){
751       if(g_str_has_suffix(filename,
752 			  AGS_LIBRARY_SUFFIX) &&
753 	 !g_list_find_custom(dssi_manager->dssi_plugin_blacklist,
754 			     filename,
755 			     strcmp)){
756 	ags_dssi_manager_load_file(dssi_manager,
757 				   *dssi_path,
758 				   filename);
759       }
760     }
761 
762     dssi_path++;
763   }
764 }
765 
766 /**
767  * ags_dssi_manager_get_dssi_plugin:
768  * @dssi_manager: the #AgsDssiManager
769  *
770  * Get dssi plugin.
771  *
772  * Returns: (transfer full): the #GList-struct containing #AgsDssiPlugin
773  *
774  * Since: 3.5.15
775  */
776 GList*
ags_dssi_manager_get_dssi_plugin(AgsDssiManager * dssi_manager)777 ags_dssi_manager_get_dssi_plugin(AgsDssiManager *dssi_manager)
778 {
779   GList *dssi_plugin;
780 
781   GRecMutex *dssi_manager_mutex;
782 
783   if(!AGS_IS_DSSI_MANAGER(dssi_manager)){
784     return(NULL);
785   }
786 
787   /* get dssi manager mutex */
788   dssi_manager_mutex = AGS_DSSI_MANAGER_GET_OBJ_MUTEX(dssi_manager);
789 
790   g_rec_mutex_lock(dssi_manager_mutex);
791 
792   dssi_plugin = g_list_copy_deep(dssi_manager->dssi_plugin,
793 				 (GCopyFunc) g_object_ref,
794 				 NULL);
795 
796   g_rec_mutex_unlock(dssi_manager_mutex);
797 
798   return(dssi_plugin);
799 }
800 
801 /**
802  * ags_dssi_manager_get_instance:
803  *
804  * Get instance.
805  *
806  * Returns: (transfer none): the #AgsDssiManager
807  *
808  * Since: 3.0.0
809  */
810 AgsDssiManager*
ags_dssi_manager_get_instance()811 ags_dssi_manager_get_instance()
812 {
813   static GMutex mutex;
814 
815   g_mutex_lock(&(mutex));
816 
817   if(ags_dssi_manager == NULL){
818     ags_dssi_manager = ags_dssi_manager_new();
819   }
820 
821   g_mutex_unlock(&(mutex));
822 
823   return(ags_dssi_manager);
824 }
825 
826 /**
827  * ags_dssi_manager_new:
828  *
829  * Create a new instance of #AgsDssiManager
830  *
831  * Returns: the new #AgsDssiManager
832  *
833  * Since: 3.0.0
834  */
835 AgsDssiManager*
ags_dssi_manager_new()836 ags_dssi_manager_new()
837 {
838   AgsDssiManager *dssi_manager;
839 
840   dssi_manager = (AgsDssiManager *) g_object_new(AGS_TYPE_DSSI_MANAGER,
841 						 NULL);
842 
843   return(dssi_manager);
844 }
845