1 #include <Ecore.h>
2 #include <Eina.h>
3
4 #include "config.h"
5 #include "emix.h"
6
7 #ifdef HAVE_PULSE
8 E_API Emix_Backend *emix_backend_pulse_get(void);
9 E_API extern const char *emix_backend_pulse_name;
10 #endif
11 #ifdef HAVE_ALSA
12 E_API Emix_Backend *emix_backend_alsa_get(void);
13 E_API extern const char *emix_backend_alsa_name;
14 #endif
15
16 static int _log_domain;
17
18 #define CRIT(...) EINA_LOG_DOM_CRIT(_log_domain, __VA_ARGS__)
19 #define ERR(...) EINA_LOG_DOM_ERR(_log_domain, __VA_ARGS__)
20 #define WRN(...) EINA_LOG_DOM_WARN(_log_domain, __VA_ARGS__)
21 #define INF(...) EINA_LOG_DOM_INFO(_log_domain, __VA_ARGS__)
22 #define DBG(...) EINA_LOG_DOM_DBG(_log_domain, __VA_ARGS__)
23
24 struct Callback_Data
25 {
26 Emix_Event_Cb cb;
27 const void *data;
28 };
29
30 typedef struct Context
31 {
32 /* Valid backends *.so */
33 Eina_Array *backends;
34 Eina_List *backends_names;
35 Eina_List *callbacks;
36 Eina_List *configs;
37
38 Emix_Backend *loaded;
39 } Context;
40
41 typedef struct _Back
42 {
43 Emix_Backend *(*backend_get) (void);
44 const char *backend_name;
45 } Back;
46
47 static int _init_count = 0;
48 static Context *ctx = NULL;
49
50 static void
_events_cb(void * data EINA_UNUSED,enum Emix_Event event,void * event_info)51 _events_cb(void *data EINA_UNUSED, enum Emix_Event event, void *event_info)
52 {
53 Eina_List *l;
54 struct Callback_Data *callback;
55
56 EINA_LIST_FOREACH(ctx->callbacks, l, callback)
57 callback->cb((void *)callback->data, event, event_info);
58 }
59
60 Eina_Bool
emix_init(void)61 emix_init(void)
62 {
63 Back *back;
64
65 if (_init_count > 0)
66 goto end;
67
68 if (!eina_init())
69 {
70 fprintf(stderr, "Could not init eina\n");
71 return EINA_FALSE;
72 }
73
74 _log_domain = eina_log_domain_register("emix", NULL);
75 if (_log_domain < 0)
76 {
77 EINA_LOG_CRIT("Could not create log domain 'emix'");
78 goto err_log;
79 }
80
81 if (!ecore_init())
82 {
83 CRIT("Could not init ecore");
84 goto err_ecore;
85 }
86
87 ctx = calloc(1, sizeof(Context));
88 if (!ctx)
89 {
90 ERR("Could not create Epulse Context");
91 goto err_ecore;
92 }
93 ctx->backends = eina_array_new(2);
94 #ifdef HAVE_PULSE
95 back = calloc(1, sizeof(Back));
96 if (back)
97 {
98 back->backend_get = emix_backend_pulse_get;
99 back->backend_name = emix_backend_pulse_name;
100 eina_array_push(ctx->backends, back);
101 ctx->backends_names = eina_list_append(ctx->backends_names,
102 back->backend_name);
103 }
104 #endif
105 #ifdef HAVE_ALSA
106 back = calloc(1, sizeof(Back));
107 if (back)
108 {
109 back->backend_get = emix_backend_alsa_get;
110 back->backend_name = emix_backend_alsa_name;
111 eina_array_push(ctx->backends, back);
112 ctx->backends_names = eina_list_append(ctx->backends_names,
113 back->backend_name);
114 }
115 #endif
116
117 if (ctx->backends == NULL)
118 {
119 ERR("Could not find any valid backend");
120 goto err;
121 }
122
123 end:
124 _init_count++;
125 return EINA_TRUE;
126 err:
127 free(ctx);
128 ctx = NULL;
129 err_ecore:
130 eina_log_domain_unregister(_log_domain);
131 _log_domain = -1;
132 err_log:
133 eina_shutdown();
134 return EINA_FALSE;
135 }
136
137 void
emix_shutdown()138 emix_shutdown()
139 {
140 unsigned int i;
141 Eina_Array_Iterator iterator;
142 Back *back;
143
144 if (_init_count == 0)
145 return;
146
147 _init_count--;
148 if (_init_count > 0)
149 return;
150
151 if (ctx->loaded && ctx->loaded->ebackend_shutdown)
152 ctx->loaded->ebackend_shutdown();
153
154 eina_list_free(ctx->backends_names);
155 EINA_ARRAY_ITER_NEXT(ctx->backends, i, back, iterator)
156 {
157 free(back);
158 }
159 eina_array_free(ctx->backends);
160 free(ctx);
161 ctx = NULL;
162
163 ecore_shutdown();
164 eina_shutdown();
165 }
166
167 const Eina_List*
emix_backends_available(void)168 emix_backends_available(void)
169 {
170 EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL);
171 return ctx->backends_names;
172 }
173
174 const Eina_List *
emix_configs_available(void)175 emix_configs_available(void)
176 {
177 EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL);
178 return ctx->configs;
179 }
180
181 int
emix_max_volume_get(void)182 emix_max_volume_get(void)
183 {
184 EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded &&
185 ctx->loaded->ebackend_max_volume_get),
186 0);
187 return ctx->loaded->ebackend_max_volume_get();
188 }
189
190 Eina_Bool
emix_backend_set(const char * backend)191 emix_backend_set(const char *backend)
192 {
193 Eina_List *l;
194 const char *name;
195 unsigned int i = 0;
196 Back *back;
197
198 EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && backend), EINA_FALSE);
199 if (ctx->loaded && ctx->loaded->ebackend_shutdown)
200 {
201 ctx->loaded->ebackend_shutdown();
202 ctx->loaded = NULL;
203 }
204
205 EINA_LIST_FOREACH(ctx->backends_names, l, name)
206 {
207 if (!strncmp(name, backend, strlen(name)))
208 break;
209 i++;
210 }
211
212 if (i == eina_list_count(ctx->backends_names))
213 {
214 CRIT("Requested backend not found (%s)", backend);
215 return EINA_FALSE;
216 }
217
218 back = eina_array_data_get(ctx->backends, i);
219 ctx->loaded = back->backend_get();
220
221 if (!ctx->loaded || !ctx->loaded->ebackend_init)
222 return EINA_FALSE;
223
224 return ctx->loaded->ebackend_init(_events_cb, NULL);
225 }
226
227 const Eina_List*
emix_sinks_get(void)228 emix_sinks_get(void)
229 {
230 EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded &&
231 ctx->loaded->ebackend_sinks_get),
232 NULL);
233 return ctx->loaded->ebackend_sinks_get();
234 }
235
236 Eina_Bool
emix_sink_default_support(void)237 emix_sink_default_support(void)
238 {
239 EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded &&
240 ctx->loaded->ebackend_sink_default_support),
241 EINA_FALSE);
242 return ctx->loaded->ebackend_sink_default_support();
243 }
244
245 const Emix_Sink*
emix_sink_default_get(void)246 emix_sink_default_get(void)
247 {
248 EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded &&
249 ctx->loaded->ebackend_sink_default_get),
250 NULL);
251 return ctx->loaded->ebackend_sink_default_get();
252 }
253
254 void
emix_sink_default_set(Emix_Sink * sink)255 emix_sink_default_set(Emix_Sink *sink)
256 {
257 EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
258 ctx->loaded->ebackend_sink_default_set &&
259 sink));
260
261 ctx->loaded->ebackend_sink_default_set(sink);
262 }
263
264 Eina_Bool
emix_sink_port_set(Emix_Sink * sink,Emix_Port * port)265 emix_sink_port_set(Emix_Sink *sink, Emix_Port *port)
266 {
267 EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded &&
268 ctx->loaded->ebackend_sink_port_set &&
269 sink && port), EINA_FALSE);
270
271 return ctx->loaded->ebackend_sink_port_set(sink, port);
272 }
273
274 void
emix_sink_mute_set(Emix_Sink * sink,Eina_Bool mute)275 emix_sink_mute_set(Emix_Sink *sink, Eina_Bool mute)
276 {
277 EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
278 ctx->loaded->ebackend_sink_mute_set &&
279 sink));
280
281 ctx->loaded->ebackend_sink_mute_set(sink, mute);
282 }
283
284 void
emix_sink_volume_set(Emix_Sink * sink,Emix_Volume * volume)285 emix_sink_volume_set(Emix_Sink *sink, Emix_Volume *volume)
286 {
287 EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
288 ctx->loaded->ebackend_sink_volume_set &&
289 sink));
290
291 ctx->loaded->ebackend_sink_volume_set(sink, volume);
292 }
293
294 Eina_Bool
emix_sink_change_support(void)295 emix_sink_change_support(void)
296 {
297 EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded &&
298 ctx->loaded->ebackend_sink_change_support),
299 EINA_FALSE);
300 return ctx->loaded->ebackend_sink_change_support();
301 }
302
303 const Eina_List*
emix_sink_inputs_get(void)304 emix_sink_inputs_get(void)
305 {
306 EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded &&
307 ctx->loaded->ebackend_sink_inputs_get),
308 NULL);
309 return ctx->loaded->ebackend_sink_inputs_get();
310 }
311
312 void
emix_sink_input_mute_set(Emix_Sink_Input * input,Eina_Bool mute)313 emix_sink_input_mute_set(Emix_Sink_Input *input, Eina_Bool mute)
314 {
315 EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
316 ctx->loaded->ebackend_sink_input_mute_set &&
317 input));
318
319 ctx->loaded->ebackend_sink_input_mute_set(input, mute);
320 }
321
322 void
emix_sink_input_volume_set(Emix_Sink_Input * input,Emix_Volume * volume)323 emix_sink_input_volume_set(Emix_Sink_Input *input, Emix_Volume *volume)
324 {
325 EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
326 ctx->loaded->ebackend_sink_input_volume_set &&
327 input));
328
329 ctx->loaded->ebackend_sink_input_volume_set(input, volume);
330 }
331
332 void
emix_sink_input_sink_change(Emix_Sink_Input * input,Emix_Sink * sink)333 emix_sink_input_sink_change(Emix_Sink_Input *input, Emix_Sink *sink)
334 {
335 EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
336 ctx->loaded->ebackend_sink_input_sink_change &&
337 input && sink));
338
339 ctx->loaded->ebackend_sink_input_sink_change(input, sink);
340 }
341
342 const Eina_List*
emix_sources_get(void)343 emix_sources_get(void)
344 {
345 EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded &&
346 ctx->loaded->ebackend_sources_get), NULL);
347
348 return ctx->loaded->ebackend_sources_get();
349 }
350
351 void
emix_source_mute_set(Emix_Source * source,Eina_Bool mute)352 emix_source_mute_set(Emix_Source *source, Eina_Bool mute)
353 {
354 EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
355 ctx->loaded->ebackend_source_mute_set &&
356 source));
357
358 ctx->loaded->ebackend_source_mute_set(source, mute);
359 }
360
361 void
emix_source_volume_set(Emix_Source * source,Emix_Volume * volume)362 emix_source_volume_set(Emix_Source *source, Emix_Volume *volume)
363 {
364 EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
365 ctx->loaded->ebackend_source_volume_set &&
366 source));
367
368 ctx->loaded->ebackend_source_volume_set(source, volume);
369 }
370
371 Evas_Object *
emix_advanced_options_add(Evas_Object * parent)372 emix_advanced_options_add(Evas_Object *parent)
373 {
374 EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded && parent &&
375 ctx->loaded->ebackend_advanced_options_add), NULL);
376
377 return ctx->loaded->ebackend_advanced_options_add(parent);
378 }
379
380 Eina_Bool
emix_event_callback_add(Emix_Event_Cb cb,const void * data)381 emix_event_callback_add(Emix_Event_Cb cb, const void *data)
382 {
383 struct Callback_Data *callback;
384 EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && cb), EINA_FALSE);
385
386 callback = calloc(1, sizeof(*callback));
387 callback->cb = cb;
388 callback->data = data;
389
390 ctx->callbacks = eina_list_append(ctx->callbacks, callback);
391 return EINA_TRUE;
392 }
393
394 Eina_Bool
emix_event_callback_del(Emix_Event_Cb cb)395 emix_event_callback_del(Emix_Event_Cb cb)
396 {
397 struct Callback_Data *callback;
398 Eina_List *l;
399 EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && cb), EINA_FALSE);
400
401 EINA_LIST_FOREACH(ctx->callbacks, l, callback)
402 {
403 if (callback->cb == cb)
404 {
405 ctx->callbacks = eina_list_remove_list(ctx->callbacks, l);
406 free(callback);
407 return EINA_TRUE;
408 }
409 }
410
411 return EINA_FALSE;
412 }
413
414 const Eina_List*
emix_cards_get(void)415 emix_cards_get(void)
416 {
417 EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded &&
418 ctx->loaded->ebackend_cards_get), NULL);
419
420 return ctx->loaded->ebackend_cards_get();
421 }
422
423 Eina_Bool
emix_card_profile_set(Emix_Card * card,Emix_Profile * profile)424 emix_card_profile_set(Emix_Card *card, Emix_Profile *profile)
425 {
426 EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded &&
427 ctx->loaded->ebackend_card_profile_set &&
428 card && profile), EINA_FALSE);
429
430 return ctx->loaded->ebackend_card_profile_set(card, profile);
431 }
432
433
434