1 /*
2 * Copyright (C) 2014 Michal Ratajsky <michal.ratajsky@gmail.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the licence, or (at your option) any later version.
8 *
9 * This library 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 GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "config.h"
19
20 #include <glib.h>
21 #include <glib-object.h>
22 #include <gmodule.h>
23
24 #include "matemixer.h"
25 #include "matemixer-private.h"
26 #include "matemixer-backend-module.h"
27
28 /**
29 * SECTION:matemixer
30 * @short_description: Library initialization and support functions
31 * @include: libmatemixer/matemixer.h
32 * @see_also: #MateMixerContext
33 *
34 * The libmatemixer library must be initialized before it is used by an
35 * application. The initialization function loads dynamic modules which provide
36 * access to sound systems (also called backends) and it only succeeds if there
37 * is at least one usable module present on the target system.
38 *
39 * To connect to a sound system and access the mixer functionality after the
40 * library is initialized, create a #MateMixerContext using the
41 * mate_mixer_context_new() function.
42 */
43
44 static void load_modules (void);
45 static gint compare_modules (gconstpointer a,
46 gconstpointer b);
47
48 static GList *modules = NULL;
49 static gboolean initialized = FALSE;
50
51 /**
52 * mate_mixer_init:
53 *
54 * Initializes the library. You must call this function before using any other
55 * function from the library.
56 *
57 * Returns: %TRUE on success or %FALSE if the library installation does not
58 * provide support for any sound system backends.
59 */
60 gboolean
mate_mixer_init(void)61 mate_mixer_init (void)
62 {
63 if (initialized == TRUE)
64 return TRUE;
65
66 load_modules ();
67
68 if (modules != NULL) {
69 GList *list = modules;
70
71 while (list != NULL) {
72 GTypeModule *module = G_TYPE_MODULE (list->data);
73 GList *next = list->next;
74
75 /* Load the plugin and remove it from the list if it fails */
76 if (g_type_module_use (module) == FALSE) {
77 g_object_unref (module);
78 modules = g_list_delete_link (modules, list);
79 }
80 list = next;
81 }
82
83 if (modules != NULL) {
84 /* Sort the usable modules by priority */
85 modules = g_list_sort (modules, compare_modules);
86 initialized = TRUE;
87 } else
88 g_critical ("No usable backend modules have been found");
89 } else
90 g_critical ("No backend modules have been found");
91
92 return initialized;
93 }
94
95 /**
96 * mate_mixer_is_initialized:
97 *
98 * Returns %TRUE if the library has been initialized.
99 *
100 * Returns: %TRUE or %FALSE.
101 */
102 gboolean
mate_mixer_is_initialized(void)103 mate_mixer_is_initialized (void)
104 {
105 return initialized;
106 }
107
108 /**
109 * _mate_mixer_list_modules:
110 *
111 * Gets a list of loaded backend modules.
112 *
113 * Returns: a #GList.
114 */
115 const GList *
_mate_mixer_list_modules(void)116 _mate_mixer_list_modules (void)
117 {
118 return (const GList *) modules;
119 }
120
121 /**
122 * _mate_mixer_create_channel_mask:
123 * @positions: an array of channel positions
124 * @n: number of channel positions in the array
125 *
126 * Creates a channel mask using the given list of channel positions.
127 *
128 * Returns: a channel mask.
129 */
130 guint32
_mate_mixer_create_channel_mask(MateMixerChannelPosition * positions,guint n)131 _mate_mixer_create_channel_mask (MateMixerChannelPosition *positions, guint n)
132 {
133 guint32 mask = 0;
134 guint i = 0;
135
136 for (i = 0; i < n; i++) {
137 if (positions[i] > MATE_MIXER_CHANNEL_UNKNOWN &&
138 positions[i] < MATE_MIXER_CHANNEL_MAX)
139 mask |= 1 << positions[i];
140 }
141 return mask;
142 }
143
144 static void
load_modules(void)145 load_modules (void)
146 {
147 static gboolean loaded = FALSE;
148
149 if (loaded == TRUE)
150 return;
151
152 if (G_LIKELY (g_module_supported () == TRUE)) {
153 GDir *dir;
154 GError *error = NULL;
155
156 /* Read the directory which contains module libraries and create a list
157 * of those that are likely to be usable backend modules */
158 dir = g_dir_open (LIBMATEMIXER_BACKEND_DIR, 0, &error);
159 if (dir != NULL) {
160 const gchar *name;
161
162 while ((name = g_dir_read_name (dir)) != NULL) {
163 gchar *file;
164
165 if (g_str_has_suffix (name, "." G_MODULE_SUFFIX) == FALSE)
166 continue;
167
168 file = g_build_filename (LIBMATEMIXER_BACKEND_DIR, name, NULL);
169 modules = g_list_prepend (modules,
170 mate_mixer_backend_module_new (file));
171 g_free (file);
172 }
173
174 g_dir_close (dir);
175 } else {
176 g_critical ("%s", error->message);
177 g_error_free (error);
178 }
179 } else {
180 g_critical ("Unable to load backend modules: Not supported");
181 }
182
183 loaded = TRUE;
184 }
185
186 /* Backend modules sorting function, higher priority number means higher priority
187 * of the backend module */
188 static gint
compare_modules(gconstpointer a,gconstpointer b)189 compare_modules (gconstpointer a, gconstpointer b)
190 {
191 const MateMixerBackendInfo *info1, *info2;
192
193 info1 = mate_mixer_backend_module_get_info (MATE_MIXER_BACKEND_MODULE (a));
194 info2 = mate_mixer_backend_module_get_info (MATE_MIXER_BACKEND_MODULE (b));
195
196 return info2->priority - info1->priority;
197 }
198