enlightenment/src/modules/mixer/lib/emix.c

412 lines
10 KiB
C

#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;
}
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();
}
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));
sink->set_volume.channel_count = volume.channel_count;
sink->set_volume.volumes = calloc(volume.channel_count, sizeof(int));
for (unsigned int i = 0; i < volume.channel_count; i++)
{
sink->set_volume.volumes[i] = volume.volumes[i];
}
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;
}