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