2015-06-08 05:00:23 -07:00
|
|
|
#include <Ecore.h>
|
|
|
|
#include <Eina.h>
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "emix.h"
|
|
|
|
|
|
|
|
#ifdef HAVE_PULSE
|
|
|
|
E_API Emix_Backend *emix_backend_pulse_get(void);
|
|
|
|
E_API const char *emix_backend_pulse_name;
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_ALSA
|
|
|
|
E_API Emix_Backend *emix_backend_alsa_get(void);
|
|
|
|
E_API const char *emix_backend_alsa_name;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int _log_domain;
|
|
|
|
|
|
|
|
#define CRIT(...) EINA_LOG_DOM_CRIT(_log_domain, __VA_ARGS__)
|
|
|
|
#define ERR(...) EINA_LOG_DOM_ERR(_log_domain, __VA_ARGS__)
|
|
|
|
#define WRN(...) EINA_LOG_DOM_WARN(_log_domain, __VA_ARGS__)
|
|
|
|
#define INF(...) EINA_LOG_DOM_INFO(_log_domain, __VA_ARGS__)
|
|
|
|
#define DBG(...) EINA_LOG_DOM_DBG(_log_domain, __VA_ARGS__)
|
|
|
|
|
|
|
|
struct Callback_Data
|
|
|
|
{
|
|
|
|
Emix_Event_Cb cb;
|
|
|
|
const void *data;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct Context
|
|
|
|
{
|
|
|
|
/* Valid backends *.so */
|
|
|
|
Eina_Array *backends;
|
|
|
|
Eina_List *backends_names;
|
|
|
|
Eina_List *callbacks;
|
|
|
|
|
|
|
|
Emix_Backend *loaded;
|
|
|
|
} Context;
|
|
|
|
|
|
|
|
typedef struct _Back
|
|
|
|
{
|
|
|
|
Emix_Backend *(*backend_get) (void);
|
|
|
|
const char *backend_name;
|
|
|
|
} Back;
|
|
|
|
|
|
|
|
static int _init_count = 0;
|
|
|
|
static Context *ctx = NULL;
|
|
|
|
|
|
|
|
static void
|
|
|
|
_events_cb(void *data EINA_UNUSED, enum Emix_Event event, void *event_info)
|
|
|
|
{
|
|
|
|
Eina_List *l;
|
|
|
|
struct Callback_Data *callback;
|
|
|
|
|
|
|
|
EINA_LIST_FOREACH(ctx->callbacks, l, callback)
|
|
|
|
callback->cb((void *)callback->data, event, event_info);
|
|
|
|
}
|
|
|
|
|
|
|
|
Eina_Bool
|
|
|
|
emix_init(void)
|
|
|
|
{
|
|
|
|
Back *back;
|
|
|
|
|
|
|
|
if (_init_count > 0)
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
if (!eina_init())
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Could not init eina\n");
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
_log_domain = eina_log_domain_register("emix", NULL);
|
|
|
|
if (_log_domain < 0)
|
|
|
|
{
|
|
|
|
EINA_LOG_CRIT("Could not create log domain 'emix'");
|
|
|
|
goto err_log;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ecore_init())
|
|
|
|
{
|
|
|
|
CRIT("Could not init ecore");
|
|
|
|
goto err_ecore;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx = calloc(1, sizeof(Context));
|
|
|
|
if (!ctx)
|
|
|
|
{
|
|
|
|
ERR("Could not create Epulse Context");
|
|
|
|
goto err_ecore;
|
|
|
|
}
|
|
|
|
ctx->backends = eina_array_new(2);
|
|
|
|
#ifdef HAVE_PULSE
|
|
|
|
back = calloc(1, sizeof(Back));
|
|
|
|
if (back)
|
|
|
|
{
|
|
|
|
back->backend_get = emix_backend_pulse_get;
|
|
|
|
back->backend_name = emix_backend_pulse_name;
|
|
|
|
eina_array_push(ctx->backends, back);
|
|
|
|
ctx->backends_names = eina_list_append(ctx->backends_names,
|
|
|
|
back->backend_name);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_ALSA
|
|
|
|
back = calloc(1, sizeof(Back));
|
|
|
|
if (back)
|
|
|
|
{
|
|
|
|
back->backend_get = emix_backend_alsa_get;
|
|
|
|
back->backend_name = emix_backend_alsa_name;
|
|
|
|
eina_array_push(ctx->backends, back);
|
|
|
|
ctx->backends_names = eina_list_append(ctx->backends_names,
|
|
|
|
back->backend_name);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (ctx->backends == NULL)
|
|
|
|
{
|
|
|
|
ERR("Could not find any valid backend");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
end:
|
|
|
|
_init_count++;
|
|
|
|
return EINA_TRUE;
|
|
|
|
err:
|
|
|
|
free(ctx);
|
|
|
|
ctx = NULL;
|
|
|
|
err_ecore:
|
|
|
|
eina_log_domain_unregister(_log_domain);
|
|
|
|
_log_domain = -1;
|
|
|
|
err_log:
|
|
|
|
eina_shutdown();
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
emix_shutdown()
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
Eina_Array_Iterator iterator;
|
|
|
|
Back *back;
|
|
|
|
|
|
|
|
if (_init_count == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
_init_count--;
|
|
|
|
if (_init_count > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (ctx->loaded && ctx->loaded->ebackend_shutdown)
|
|
|
|
ctx->loaded->ebackend_shutdown();
|
|
|
|
|
|
|
|
eina_list_free(ctx->backends_names);
|
|
|
|
EINA_ARRAY_ITER_NEXT(ctx->backends, i, back, iterator)
|
|
|
|
{
|
|
|
|
free(back);
|
|
|
|
}
|
|
|
|
eina_array_free(ctx->backends);
|
|
|
|
free(ctx);
|
|
|
|
ctx = NULL;
|
|
|
|
|
|
|
|
ecore_shutdown();
|
|
|
|
eina_shutdown();
|
|
|
|
}
|
|
|
|
|
|
|
|
const Eina_List*
|
|
|
|
emix_backends_available(void)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, NULL);
|
|
|
|
return ctx->backends_names;
|
|
|
|
}
|
|
|
|
|
2016-09-07 02:02:46 -07:00
|
|
|
int
|
|
|
|
emix_max_volume_get(void)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded &&
|
|
|
|
ctx->loaded->ebackend_max_volume_get),
|
|
|
|
0);
|
|
|
|
return ctx->loaded->ebackend_max_volume_get();
|
|
|
|
}
|
|
|
|
|
2015-06-08 05:00:23 -07:00
|
|
|
Eina_Bool
|
|
|
|
emix_backend_set(const char *backend)
|
|
|
|
{
|
|
|
|
Eina_List *l;
|
|
|
|
const char *name;
|
|
|
|
unsigned int i = 0;
|
|
|
|
Back *back;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && backend), EINA_FALSE);
|
|
|
|
if (ctx->loaded && ctx->loaded->ebackend_shutdown)
|
|
|
|
{
|
|
|
|
ctx->loaded->ebackend_shutdown();
|
|
|
|
ctx->loaded = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
EINA_LIST_FOREACH(ctx->backends_names, l, name)
|
|
|
|
{
|
|
|
|
if (!strncmp(name, backend, strlen(name)))
|
|
|
|
break;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == eina_list_count(ctx->backends_names))
|
|
|
|
{
|
|
|
|
CRIT("Requested backend not found (%s)", backend);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
back = eina_array_data_get(ctx->backends, i);
|
|
|
|
ctx->loaded = back->backend_get();
|
|
|
|
|
|
|
|
if (!ctx->loaded || !ctx->loaded->ebackend_init)
|
|
|
|
return EINA_FALSE;
|
|
|
|
|
|
|
|
return ctx->loaded->ebackend_init(_events_cb, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
const Eina_List*
|
|
|
|
emix_sinks_get(void)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded &&
|
|
|
|
ctx->loaded->ebackend_sinks_get),
|
|
|
|
NULL);
|
|
|
|
return ctx->loaded->ebackend_sinks_get();
|
|
|
|
}
|
|
|
|
|
|
|
|
Eina_Bool
|
|
|
|
emix_sink_default_support(void)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded &&
|
|
|
|
ctx->loaded->ebackend_sink_default_support),
|
|
|
|
EINA_FALSE);
|
|
|
|
return ctx->loaded->ebackend_sink_default_support();
|
|
|
|
}
|
|
|
|
|
|
|
|
const Emix_Sink*
|
|
|
|
emix_sink_default_get(void)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded &&
|
|
|
|
ctx->loaded->ebackend_sink_default_get),
|
|
|
|
NULL);
|
|
|
|
return ctx->loaded->ebackend_sink_default_get();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
emix_sink_default_set(Emix_Sink *sink)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
|
|
|
|
ctx->loaded->ebackend_sink_default_set &&
|
|
|
|
sink));
|
|
|
|
|
|
|
|
ctx->loaded->ebackend_sink_default_set(sink);
|
|
|
|
}
|
|
|
|
|
|
|
|
Eina_Bool
|
|
|
|
emix_sink_port_set(Emix_Sink *sink, Emix_Port *port)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded &&
|
|
|
|
ctx->loaded->ebackend_sink_port_set &&
|
|
|
|
sink && port), EINA_FALSE);
|
|
|
|
|
|
|
|
return ctx->loaded->ebackend_sink_port_set(sink, port);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
emix_sink_mute_set(Emix_Sink *sink, Eina_Bool mute)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
|
|
|
|
ctx->loaded->ebackend_sink_mute_set &&
|
|
|
|
sink));
|
|
|
|
|
|
|
|
ctx->loaded->ebackend_sink_mute_set(sink, mute);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
emix_sink_volume_set(Emix_Sink *sink, Emix_Volume volume)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
|
|
|
|
ctx->loaded->ebackend_sink_volume_set &&
|
|
|
|
sink));
|
|
|
|
|
|
|
|
ctx->loaded->ebackend_sink_volume_set(sink, volume);
|
|
|
|
}
|
|
|
|
|
|
|
|
Eina_Bool
|
|
|
|
emix_sink_change_support(void)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded &&
|
|
|
|
ctx->loaded->ebackend_sink_change_support),
|
|
|
|
EINA_FALSE);
|
|
|
|
return ctx->loaded->ebackend_sink_change_support();
|
|
|
|
}
|
|
|
|
|
|
|
|
const Eina_List*
|
|
|
|
emix_sink_inputs_get(void)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded &&
|
|
|
|
ctx->loaded->ebackend_sink_inputs_get),
|
|
|
|
NULL);
|
|
|
|
return ctx->loaded->ebackend_sink_inputs_get();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
emix_sink_input_mute_set(Emix_Sink_Input *input, Eina_Bool mute)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
|
|
|
|
ctx->loaded->ebackend_sink_input_mute_set &&
|
|
|
|
input));
|
|
|
|
|
|
|
|
ctx->loaded->ebackend_sink_input_mute_set(input, mute);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
emix_sink_input_volume_set(Emix_Sink_Input *input, Emix_Volume volume)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
|
|
|
|
ctx->loaded->ebackend_sink_input_volume_set &&
|
|
|
|
input));
|
|
|
|
|
|
|
|
ctx->loaded->ebackend_sink_input_volume_set(input, volume);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
emix_sink_input_sink_change(Emix_Sink_Input *input, Emix_Sink *sink)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
|
|
|
|
ctx->loaded->ebackend_sink_input_sink_change &&
|
|
|
|
input && sink));
|
|
|
|
|
|
|
|
ctx->loaded->ebackend_sink_input_sink_change(input, sink);
|
|
|
|
}
|
|
|
|
|
|
|
|
const Eina_List*
|
|
|
|
emix_sources_get(void)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded &&
|
|
|
|
ctx->loaded->ebackend_sources_get), NULL);
|
|
|
|
|
|
|
|
return ctx->loaded->ebackend_sources_get();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
emix_source_mute_set(Emix_Source *source, Eina_Bool mute)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
|
|
|
|
ctx->loaded->ebackend_source_mute_set &&
|
|
|
|
source));
|
|
|
|
|
|
|
|
ctx->loaded->ebackend_source_mute_set(source, mute);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
emix_source_volume_set(Emix_Source *source, Emix_Volume volume)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN((ctx && ctx->loaded &&
|
|
|
|
ctx->loaded->ebackend_source_volume_set &&
|
|
|
|
source));
|
|
|
|
|
|
|
|
ctx->loaded->ebackend_source_volume_set(source, volume);
|
|
|
|
}
|
|
|
|
|
|
|
|
Evas_Object *
|
|
|
|
emix_advanced_options_add(Evas_Object *parent)
|
|
|
|
{
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && ctx->loaded && parent &&
|
|
|
|
ctx->loaded->ebackend_advanced_options_add), NULL);
|
|
|
|
|
|
|
|
return ctx->loaded->ebackend_advanced_options_add(parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
Eina_Bool
|
|
|
|
emix_event_callback_add(Emix_Event_Cb cb, const void *data)
|
|
|
|
{
|
|
|
|
struct Callback_Data *callback;
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && cb), EINA_FALSE);
|
|
|
|
|
|
|
|
callback = calloc(1, sizeof(*callback));
|
|
|
|
callback->cb = cb;
|
|
|
|
callback->data = data;
|
|
|
|
|
|
|
|
ctx->callbacks = eina_list_append(ctx->callbacks, callback);
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
Eina_Bool
|
|
|
|
emix_event_callback_del(Emix_Event_Cb cb)
|
|
|
|
{
|
|
|
|
struct Callback_Data *callback;
|
|
|
|
Eina_List *l;
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL((ctx && cb), EINA_FALSE);
|
|
|
|
|
|
|
|
EINA_LIST_FOREACH(ctx->callbacks, l, callback)
|
|
|
|
{
|
|
|
|
if (callback->cb == cb)
|
|
|
|
{
|
|
|
|
ctx->callbacks = eina_list_remove_list(ctx->callbacks, l);
|
|
|
|
free(callback);
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|