Add mixer module.

This is the mixer modules as in:

      git://staff.get-e.org/users/barbieri/e_module-mixer.git

it's being used with ALSA backend for some time without problems and
it's ready for inclusion. We still lack OSS4 engine.


SVN revision: 35282
This commit is contained in:
Gustavo Sverzut Barbieri 2008-08-01 03:08:16 +00:00
parent d6badc27c2
commit c28047e3a1
25 changed files with 3693 additions and 1 deletions

View File

@ -262,6 +262,35 @@ AC_SUBST(edje_cc)
AC_DEFINE(E_INTERNAL, 1, "This define can be used to wrap internal E stuff, as config.h isn't exported")
dnl Check for Alsa
AC_ARG_ENABLE(alsa, AS_HELP_STRING([--enable-alsa],
[enable support for alsa(default=autodetect)]),
[ enable_alsa=$enableval ], [ enable_alsa=default ])
AM_CONDITIONAL(HAVE_ALSA, false)
if test "x$enable_alsa" = "xdefault" || test "x$enable_alsa" = "xyes"; then
PKG_CHECK_MODULES(ALSA, [alsa >= 1.0.8],
[ SOUND_CFLAGS="$ALSA_CFLAGS -DHAVE_ALSA $SOUND_CFLAGS"
SOUND_LDFLAGS="$ALSA_LIBS $SOUND_LDFLAGS"
AM_CONDITIONAL(HAVE_ALSA, true)
have_alsa=yes ],
[ if test "x$enable_alsa" = "xyes"; then
AC_MSG_ERROR([alsa library >= 1.0.8 not found])
fi
])
else
have_alsa=no
fi
if test "$have_alsa" = "yes"; then
AC_DEFINE(HAVE_ALSA, 1, [Define if the ALSA output plugin should be built])
else
have_alsa=no
fi
AC_SUBST(SOUND_CFLAGS)
AC_SUBST(SOUND_LDFLAGS)
AC_OUTPUT([
Makefile
enlightenment.spec
@ -375,6 +404,8 @@ src/modules/conf_interaction/Makefile
src/modules/conf_interaction/module.desktop
src/modules/gadman/Makefile
src/modules/gadman/module.desktop
src/modules/mixer/Makefile
src/modules/mixer/module.desktop
src/preload/Makefile
data/Makefile
data/fonts/Makefile

View File

@ -62,7 +62,8 @@ default_deskpreview.edc \
default_fontpreview.edc \
default_wizard.edc \
default_toolbar.edc \
default_slidesel.edc
default_slidesel.edc \
default_mixer.edc
default.edj: Makefile $(EXTRA_DIST)
$(EDJE_CC) $(EDJE_FLAGS) \

View File

@ -86,4 +86,5 @@ collections {
#include "default_wizard.edc"
#include "default_toolbar.edc"
#include "default_slidesel.edc"
#include "default_mixer.edc"
}

View File

@ -0,0 +1,246 @@
images {
image: "e17_mixer_base.png" COMP;
image: "e17_mixer_mute.png" COMP;
image: "e17_mixer_left_low.png" COMP;
image: "e17_mixer_left_medium.png" COMP;
image: "e17_mixer_left_high.png" COMP;
image: "e17_mixer_right_low.png" COMP;
image: "e17_mixer_right_medium.png" COMP;
image: "e17_mixer_right_high.png" COMP;
}
group {
name: "e/modules/mixer/main";
max: 128 128;
min: 1 1;
script {
public message(Msg_Type:type, id, ...) {
if ((type == MSG_INT_SET) && (id == 0)) {
new mute, left, right;
mute = getarg(2);
left = getarg(3);
right = getarg(4);
if (mute)
run_program(PROGRAM:"mute");
else
run_program(PROGRAM:"unmute");
if (left <= 0)
run_program(PROGRAM:"left_none");
else if (left < 33)
run_program(PROGRAM:"left_low");
else if (left < 66)
run_program(PROGRAM:"left_medium");
else if (left >= 66)
run_program(PROGRAM:"left_high");
if (right <= 0)
run_program(PROGRAM:"right_none");
else if (right < 33)
run_program(PROGRAM:"right_low");
else if (right < 66)
run_program(PROGRAM:"right_medium");
else if (right >= 66)
run_program(PROGRAM:"right_high");
}
}
}
parts {
part {
name: "base";
mouse_events: 0;
type: RECT;
description {
state: "default" 0.0;
color: 255 255 255 0;
aspect: 1 1;
aspect_preference: BOTH;
}
}
part {
name: "speaker";
mouse_events: 0;
type: IMAGE;
description {
state: "default" 0.0;
aspect: 1 1;
aspect_preference: BOTH;
rel1.to: "base";
rel2.to: "base";
image.normal: "e17_mixer_base.png";
}
}
part {
name: "left";
mouse_events: 0;
type: IMAGE;
description {
state: "default" 0.0;
visible: 0;
aspect: 1 1;
aspect_preference: BOTH;
rel1.to: "base";
rel2.to: "base";
image.normal: "e17_mixer_left_low.png";
}
description {
state: "low" 0.0;
inherit: "default" 0.0;
visible: 1;
}
description {
state: "medium" 0.0;
inherit: "default" 0.0;
visible: 1;
image.normal: "e17_mixer_left_medium.png";
}
description {
state: "high" 0.0;
inherit: "default" 0.0;
visible: 1;
image.normal: "e17_mixer_left_high.png";
}
}
part {
name: "right";
mouse_events: 0;
type: IMAGE;
description {
state: "default" 0.0;
visible: 0;
aspect: 1 1;
aspect_preference: BOTH;
rel1.to: "base";
rel2.to: "base";
image.normal: "e17_mixer_right_low.png";
}
description {
state: "low" 0.0;
inherit: "default" 0.0;
visible: 1;
}
description {
state: "medium" 0.0;
inherit: "default" 0.0;
visible: 1;
image.normal: "e17_mixer_right_medium.png";
}
description {
state: "high" 0.0;
inherit: "default" 0.0;
visible: 1;
image.normal: "e17_mixer_right_high.png";
}
}
part {
name: "mute";
mouse_events: 0;
type: IMAGE;
description {
state: "default" 0.0;
aspect: 1 1;
aspect_preference: BOTH;
visible: 0;
rel1.to: "base";
rel2.to: "base";
image.normal: "e17_mixer_mute.png";
}
description {
state: "active" 0.0;
inherit: "default" 0.0;
visible: 1;
}
}
part {
name: "over";
type: RECT;
description {
state: "default" 0.0;
rel1.to: "base";
rel2.to: "base";
color: 255 255 255 0;
}
}
}
programs {
program {
name: "mute";
action: STATE_SET "active" 0.0;
transition: LINEAR 0.1;
target: "mute";
}
program {
name: "unmute";
action: STATE_SET "default" 0.0;
transition: LINEAR 0.1;
target: "mute";
}
program {
name: "left_none";
action: STATE_SET "default" 0.0;
transition: LINEAR 0.1;
target: "left";
}
program {
name: "left_low";
action: STATE_SET "low" 0.0;
transition: LINEAR 0.1;
target: "left";
}
program {
name: "left_medium";
action: STATE_SET "medium" 0.0;
transition: LINEAR 0.1;
target: "left";
}
program {
name: "left_high";
action: STATE_SET "high" 0.0;
transition: LINEAR 0.1;
target: "left";
}
program {
name: "right_none";
action: STATE_SET "default" 0.0;
transition: LINEAR 0.1;
target: "right";
}
program {
name: "right_low";
action: STATE_SET "low" 0.0;
transition: LINEAR 0.1;
target: "right";
}
program {
name: "right_medium";
action: STATE_SET "medium" 0.0;
transition: LINEAR 0.1;
target: "right";
}
program {
name: "right_high";
action: STATE_SET "high" 0.0;
transition: LINEAR 0.1;
target: "right";
}
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -51,6 +51,7 @@ conf_paths \
conf_mime \
conf_interaction \
gadman \
mixer \
conf_window_remembers
if HAVE_TEMPERATURE

View File

@ -0,0 +1,39 @@
MAINTAINERCLEANFILES = Makefile.in
MODULE = mixer
# data files for the module
filesdir = $(libdir)/enlightenment/modules/$(MODULE)
files_DATA = e-module-$(MODULE).edj module.desktop
EXTRA_DIST = $(files_DATA)
# the module .so file
INCLUDES = -I. \
-I$(top_srcdir) \
-I$(top_srcdir)/src/modules/$(MODULE) \
-I$(top_srcdir)/src/bin \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/modules \
@e_cflags@ @SOUND_CFLAGS@
pkgdir = $(libdir)/enlightenment/modules/$(MODULE)/$(MODULE_ARCH)
pkg_LTLIBRARIES = module.la
module_la_SOURCES = e_mod_main.h \
e_mod_main.c \
e_mod_system.h \
conf_gadget.c \
conf_module.c \
app_mixer.c
if HAVE_ALSA
module_la_SOURCES += sys_alsa.c
else
module_la_SOURCES += sys_dummy.c
endif
module_la_LIBADD = @SOUND_LDFLAGS@ @e_libs@ @dlopen_libs@
module_la_LDFLAGS = -module -avoid-version
module_la_DEPENDENCIES = $(top_builddir)/config.h
uninstall:
rm -rf $(DESTDIR)$(libdir)/enlightenment/modules/$(MODULE)

View File

@ -0,0 +1,614 @@
#include "e_mod_main.h"
extern const char _Name[];
typedef struct E_Mixer_App_Dialog_Data
{
E_Mixer_System *sys;
char *card;
char *channel_name;
int lock_sliders;
Evas_List *cards;
Evas_List *channels_infos;
struct channel_info *channel_info;
E_Mixer_Channel_State state;
struct e_mixer_app_ui
{
Evas_Object *hlayout;
struct e_mixer_app_ui_cards
{
Evas_Object *frame;
Evas_Object *list;
} cards;
struct e_mixer_app_ui_channels
{
Evas_Object *frame;
Evas_Object *list;
} channels;
struct e_mixer_app_ui_channel_editor
{
Evas_Object *frame;
Evas_Object *label_card;
Evas_Object *card;
Evas_Object *label_channel;
Evas_Object *channel;
Evas_Object *label_type;
Evas_Object *type;
Evas_Object *label_left;
Evas_Object *left;
Evas_Object *label_right;
Evas_Object *right;
Evas_Object *mute;
Evas_Object *lock_sliders;
} channel_editor;
} ui;
struct
{
void *data;
void (*func)(E_Dialog *dialog, void *data);
} del;
} E_Mixer_App_Dialog_Data;
struct channel_info
{
int has_capture;
char *name;
E_Mixer_Channel *id;
E_Mixer_App_Dialog_Data *app;
};
static void
_cb_changed_left(void *data, Evas_Object *obj)
{
E_Mixer_App_Dialog_Data *app = data;
E_Mixer_Channel_State *state;
state = &app->state;
if (app->lock_sliders && (state->left != state->right))
{
state->right = state->left;
e_widget_slider_value_int_set(app->ui.channel_editor.right,
state->right);
}
e_mixer_system_set_volume(app->sys, app->channel_info->id,
state->left, state->right);
}
static void
_cb_changed_right(void *data, Evas_Object *obj)
{
E_Mixer_App_Dialog_Data *app = data;
E_Mixer_Channel_State *state;
state = &app->state;
if (app->lock_sliders && (state->right != state->left))
{
state->left = state->right;
e_widget_slider_value_int_set(app->ui.channel_editor.left,
state->left);
}
e_mixer_system_set_volume(app->sys, app->channel_info->id,
state->left, state->right);
}
static void
_cb_changed_mute(void *data, Evas_Object *obj)
{
E_Mixer_App_Dialog_Data *app = data;
e_mixer_system_set_mute(app->sys, app->channel_info->id, app->state.mute);
}
static void
_cb_changed_lock_sliders(void *data, Evas_Object *obj)
{
E_Mixer_App_Dialog_Data *app = data;
E_Mixer_Channel_State *state;
if (!app->lock_sliders)
return;
state = &app->state;
if (state->left == state->right)
return;
state->left = state->right = (state->left + state->right) / 2;
e_widget_slider_value_int_set(app->ui.channel_editor.left, state->left);
e_widget_slider_value_int_set(app->ui.channel_editor.right, state->right);
e_mixer_system_set_volume(app->sys, app->channel_info->id,
state->left, state->right);
}
static void
_update_channel_editor_state(E_Mixer_App_Dialog_Data *app, const E_Mixer_Channel_State state)
{
struct e_mixer_app_ui_channel_editor *ui;
ui = &app->ui.channel_editor;
e_widget_slider_value_int_set(ui->left, state.left);
e_widget_slider_value_int_set(ui->right, state.right);
if (e_mixer_system_can_mute(app->sys, app->channel_info->id))
{
e_widget_disabled_set(ui->mute, 0);
e_widget_check_checked_set(ui->mute, state.mute);
}
else
{
e_widget_disabled_set(ui->mute, 1);
e_widget_check_checked_set(ui->mute, 0);
}
}
static void
_populate_channel_editor(E_Mixer_App_Dialog_Data *app)
{
struct e_mixer_app_ui_channel_editor *ui;
E_Mixer_Channel_State state;
char *card_name;
ui = &app->ui.channel_editor;
card_name = e_mixer_system_get_card_name(app->card);
e_widget_entry_text_set(ui->card, card_name);
if (card_name)
free(card_name);
e_widget_entry_text_set(ui->channel, app->channel_name);
if (e_mixer_system_has_capture(app->sys, app->channel_info->id))
e_widget_entry_text_set(ui->type, D_("Capture"));
else
e_widget_entry_text_set(ui->type, D_("Playback"));
e_mixer_system_get_state(app->sys, app->channel_info->id, &state);
_update_channel_editor_state(app, state);
app->lock_sliders = (state.left == state.right);
e_widget_check_checked_set(ui->lock_sliders, app->lock_sliders);
}
static void
_cb_channel_selected(void *data)
{
struct channel_info *info = data;
E_Mixer_App_Dialog_Data *app;
app = info->app;
app->channel_info = info;
_populate_channel_editor(app);
}
static int
_channel_info_cmp(void *data_a, void *data_b)
{
struct channel_info *a = data_a, *b = data_b;
if (a->has_capture < b->has_capture)
return -1;
else if (a->has_capture > b->has_capture)
return 1;
return strcmp(a->name, b->name);
}
static Evas_List *
_channels_info_new(E_Mixer_System *sys)
{
Evas_List *channels, *channels_infos, *l;
channels = e_mixer_system_get_channels(sys);
channels_infos = NULL;
for (l = channels; l != NULL; l = l->next)
{
struct channel_info *info;
info = malloc(sizeof(*info));
info->id = l->data;
info->name = e_mixer_system_get_channel_name(sys, info->id);
info->has_capture = e_mixer_system_has_capture(sys, info->id);
channels_infos = evas_list_append(channels_infos, info);
}
e_mixer_system_free_channels(channels);
return evas_list_sort(channels_infos, -1, _channel_info_cmp);
}
static void
_channels_info_free(Evas_List *list)
{
Evas_List *l;
for (l = list; l != NULL; l = l->next)
{
struct channel_info *info = l->data;
free(info->name);
free(info);
}
evas_list_free(list);
}
static int
_cb_system_update(void *data, E_Mixer_System *sys)
{
E_Mixer_App_Dialog_Data *app;
E_Mixer_Channel_State state;
app = data;
if ((!app->sys) || (!app->channel_info))
return 1;
e_mixer_system_get_state(app->sys, app->channel_info->id, &state);
_update_channel_editor_state(app, state);
return 1;
}
static void
_populate_channels(E_Mixer_App_Dialog_Data *app)
{
Evas_List *l;
Evas_Object *ilist;
int header_input;
int i;
ilist = app->ui.channels.list;
edje_freeze();
e_widget_ilist_freeze(ilist);
e_widget_ilist_clear(ilist);
if (app->sys)
e_mixer_system_del(app->sys);
app->sys = e_mixer_system_new(app->card);
e_mixer_system_callback_set(app->sys, _cb_system_update, app);
if (app->channel_name)
free(app->channel_name);
app->channel_name = e_mixer_system_get_default_channel_name(app->sys);
if (app->channels_infos)
_channels_info_free(app->channels_infos);
app->channels_infos = _channels_info_new(app->sys);
if (app->channels_infos)
{
struct channel_info *info = app->channels_infos->data;
if (info->has_capture)
{
e_widget_ilist_header_append(ilist, NULL, D_("Input"));
header_input = 1;
i = 1;
}
else
{
e_widget_ilist_header_append(ilist, NULL, D_("Output"));
header_input = 0;
i = 1;
}
}
for (l = app->channels_infos; l != NULL; l = l->next, i++)
{
struct channel_info *info = l->data;
if ((!header_input) && info->has_capture)
{
e_widget_ilist_header_append(ilist, NULL, D_("Input"));
header_input = 1;
i++;
}
info->app = app;
e_widget_ilist_append(ilist, NULL, info->name, _cb_channel_selected,
info, info->name);
if (app->channel_name && info->name &&
(strcmp(app->channel_name, info->name) == 0))
{
e_widget_ilist_selected_set(ilist, i);
app->channel_info = info;
}
}
e_widget_ilist_go(ilist);
e_widget_ilist_thaw(ilist);
edje_thaw();
}
static void
select_card(E_Mixer_App_Dialog_Data *app)
{
_populate_channels(app);
e_widget_ilist_selected_set(app->ui.channels.list, 1);
}
static void
_cb_card_selected(void *data)
{
select_card(data);
}
static void
_create_cards(E_Dialog *dialog, Evas *evas, E_Mixer_App_Dialog_Data *app)
{
struct e_mixer_app_ui_cards *ui;
Evas_List *l;
app->card = e_mixer_system_get_default_card();
app->cards = e_mixer_system_get_cards();
if (evas_list_count(app->cards) < 2)
return;
ui = &app->ui.cards;
ui->list = e_widget_tlist_add(evas, &app->card);
e_widget_tlist_go(ui->list);
for (l = app->cards; l != NULL; l = l->next)
{
char *card, *card_name;
card = l->data;
card_name = e_mixer_system_get_card_name(card);
e_widget_tlist_append(ui->list, card_name, _cb_card_selected,
app, card);
free(card_name);
}
ui->frame = e_widget_framelist_add(evas, D_("Cards"), 0);
e_widget_framelist_object_append(ui->frame, ui->list);
e_widget_list_object_append(app->ui.hlayout, ui->frame, 1, 0, 0.0);
}
static void
_create_channels(E_Dialog *dialog, Evas *evas, E_Mixer_App_Dialog_Data *app)
{
struct e_mixer_app_ui_channels *ui;
ui = &app->ui.channels;
ui->list = e_widget_ilist_add(evas, 24, 24, &app->channel_name);
e_widget_min_size_set(ui->list, 180, 100);
e_widget_ilist_go(ui->list);
ui->frame = e_widget_framelist_add(evas, D_("Channels"), 0);
e_widget_framelist_object_append(ui->frame, ui->list);
e_widget_list_object_append(app->ui.hlayout, ui->frame, 1, 1, 0.0);
}
static void
_create_channel_editor(E_Dialog *dialog, Evas *evas, E_Mixer_App_Dialog_Data *app)
{
struct e_mixer_app_ui_channel_editor *ui;
ui = &app->ui.channel_editor;
ui->label_card = e_widget_label_add(evas, D_("Card:"));
ui->card = e_widget_entry_add(evas, NULL, NULL, NULL, NULL);
e_widget_entry_readonly_set(ui->card, 1);
ui->label_channel = e_widget_label_add(evas, D_("Channel:"));
ui->channel = e_widget_entry_add(evas, NULL, NULL, NULL, NULL);
e_widget_entry_readonly_set(ui->channel, 1);
ui->label_type = e_widget_label_add(evas, D_("Type:"));
ui->type = e_widget_entry_add(evas, NULL, NULL, NULL, NULL);
e_widget_entry_readonly_set(ui->type, 1);
ui->label_left = e_widget_label_add(evas, D_("Left:"));
ui->left = e_widget_slider_add(evas, 1, 0, "%3.0f", 0.0, 100.0, 10.0, 100.0,
NULL, &app->state.left, 150);
e_widget_on_change_hook_set(ui->left, _cb_changed_left, app);
ui->label_right = e_widget_label_add(evas, D_("Right:"));
ui->right = e_widget_slider_add(evas, 1, 0, "%3.0f", 0.0, 100.0, 10.0, 100.0,
NULL, &app->state.right, 150);
e_widget_on_change_hook_set(ui->right, _cb_changed_right, app);
ui->mute = e_widget_check_add(evas, D_("Mute"), &app->state.mute);
e_widget_on_change_hook_set(ui->mute, _cb_changed_mute, app);
ui->lock_sliders = e_widget_check_add(evas, D_("Lock Sliders"),
&app->lock_sliders);
e_widget_on_change_hook_set(ui->lock_sliders, _cb_changed_lock_sliders, app);
ui->frame = e_widget_framelist_add(evas, D_("Edit"), 0);
e_widget_framelist_object_append(ui->frame, ui->label_card);
e_widget_framelist_object_append(ui->frame, ui->card);
e_widget_framelist_object_append(ui->frame, ui->label_channel);
e_widget_framelist_object_append(ui->frame, ui->channel);
e_widget_framelist_object_append(ui->frame, ui->label_type);
e_widget_framelist_object_append(ui->frame, ui->type);
e_widget_framelist_object_append(ui->frame, ui->label_left);
e_widget_framelist_object_append(ui->frame, ui->left);
e_widget_framelist_object_append(ui->frame, ui->label_right);
e_widget_framelist_object_append(ui->frame, ui->right);
e_widget_framelist_object_append(ui->frame, ui->mute);
e_widget_framelist_object_append(ui->frame, ui->lock_sliders);
e_widget_list_object_append(app->ui.hlayout, ui->frame, 1, 1, 0.5);
}
static void
_create_ui(E_Dialog *dialog, E_Mixer_App_Dialog_Data *app)
{
struct e_mixer_app_ui *ui;
Evas *evas;
int mw, mh;
evas = e_win_evas_get(dialog->win);
ui = &app->ui;
ui->hlayout = e_widget_list_add(evas, 0, 1);
_create_cards(dialog, evas, app);
_create_channels(dialog, evas, app);
_create_channel_editor(dialog, evas, app);
if (ui->cards.list)
e_widget_tlist_selected_set(ui->cards.list, 0);
else
select_card(app);
e_widget_ilist_selected_set(ui->channels.list, 1);
e_widget_min_size_get(ui->hlayout, &mw, &mh);
if (mw < 300)
mw = 300;
if (mh < 200)
mh = 200;
e_dialog_content_set(dialog, ui->hlayout, mw, mh);
}
static void
_mixer_app_dialog_del(E_Dialog *dialog, E_Mixer_App_Dialog_Data *app)
{
if (app->del.func)
app->del.func(dialog, app->del.data);
if (app->card)
free(app->card);
if (app->channel_name)
free(app->channel_name);
if (app->cards)
e_mixer_system_free_cards(app->cards);
if (app->channels_infos)
_channels_info_free(app->channels_infos);
e_mixer_system_del(app->sys);
e_util_defer_object_del(E_OBJECT(dialog));
dialog->data = NULL;
E_FREE(app);
}
static void
_cb_win_del(E_Win *win)
{
E_Dialog *dialog;
E_Mixer_App_Dialog_Data *app;
dialog = win->data;
app = dialog->data;
_mixer_app_dialog_del(dialog, app);
}
static void
_cb_dialog_dismiss(void *data, E_Dialog *dialog)
{
_mixer_app_dialog_del(dialog, data);
}
E_Dialog *
e_mixer_app_dialog_new(E_Container *con, void (*func)(E_Dialog *dialog, void *data), void *data)
{
E_Mixer_App_Dialog_Data *app;
E_Dialog *dialog;
dialog = e_dialog_new(con, _Name, "e_mixer_app_dialog");
if (!dialog)
return NULL;
app = E_NEW(E_Mixer_App_Dialog_Data, 1);
if (!app)
{
e_object_del(E_OBJECT(dialog));
return NULL;
}
dialog->data = app;
app->del.data = data;
app->del.func = func;
e_dialog_title_set(dialog, D_(_Name));
e_dialog_resizable_set(dialog, 1);
e_win_delete_callback_set(dialog->win, _cb_win_del);
_create_ui(dialog, app);
e_dialog_button_add(dialog, D_("Close"), NULL, _cb_dialog_dismiss, app);
e_dialog_button_focus_num(dialog, 1);
e_win_centered_set(dialog->win, 1);
e_dialog_show(dialog);
return dialog;
}
static inline int
_find_card_by_name(E_Mixer_App_Dialog_Data *app, const char *card_name)
{
Evas_List *l;
int i;
for (i = 0, l = app->cards; l != NULL; i++, l = l->next)
if (strcmp(card_name, l->data) == 0)
return i;
return -1;
}
static inline int
_find_channel_by_name(E_Mixer_App_Dialog_Data *app, const char *channel_name)
{
Evas_List *l;
int i, header_input;
if (app->channels_infos)
{
struct channel_info *info = app->channels_infos->data;
header_input = !!info->has_capture;
i = 1;
}
for (l = app->channels_infos; l != NULL; l = l->next, i++)
{
struct channel_info *info = l->data;
if ((!header_input) && info->has_capture)
{
header_input = 1;
i++;
}
if (strcmp(channel_name, info->name) == 0)
return i;
}
return -1;
}
int
e_mixer_app_dialog_select(E_Dialog *dialog, const char *card_name, const char *channel_name)
{
E_Mixer_App_Dialog_Data *app;
int n;
if (!dialog)
return 0;
app = dialog->data;
if (!app)
return 0;
n = _find_card_by_name(app, card_name);
if (n < 0)
return 0;
if (app->ui.cards.list)
e_widget_tlist_selected_set(app->ui.cards.list, n);
n = _find_channel_by_name(app, channel_name);
if (n < 0)
return 0;
e_widget_ilist_selected_set(app->ui.channels.list, n);
return 1;
}

View File

@ -0,0 +1,389 @@
#include "e_mod_main.h"
extern const char _Name[];
struct _E_Config_Dialog_Data
{
int lock_sliders;
int show_locked;
int card_num;
int channel;
const char *card;
const char *channel_name;
Evas_List *cards;
Evas_List *cards_names;
Evas_List *channels_names;
struct mixer_config_ui
{
Evas_Object *table;
struct mixer_config_ui_general
{
Evas_Object *frame;
Evas_Object *lock_sliders;
Evas_Object *show_locked;
} general;
struct mixer_config_ui_cards
{
Evas_Object *frame;
E_Radio_Group *radio;
} cards;
struct mixer_config_ui_channels
{
Evas_Object *frame;
Evas_Object *scroll;
Evas_Object *list;
E_Radio_Group *radio;
Evas_List *radios;
} channels;
} ui;
E_Mixer_Gadget_Config *conf;
};
static void
_mixer_fill_cards_info(E_Config_Dialog_Data *cfdata)
{
Evas_List *l;
int i;
cfdata->card_num = -1;
cfdata->cards = e_mixer_system_get_cards();
cfdata->cards_names = NULL;
for (l = cfdata->cards, i = 0; l != NULL; l = l->next, i++)
{
char *card, *name;
card = l->data;
name = e_mixer_system_get_card_name(card);
if ((cfdata->card_num < 0) && card && cfdata->card &&
(strcmp(card, cfdata->card) == 0))
cfdata->card_num = i;
cfdata->cards_names = evas_list_append(cfdata->cards_names, name);
}
if (cfdata->card_num < 0)
cfdata->card_num = 0;
}
static void
_mixer_fill_channels_info(E_Config_Dialog_Data *cfdata)
{
E_Mixer_System *sys;
Evas_List *l;
int i;
sys = e_mixer_system_new(cfdata->card);
if (!sys)
return;
cfdata->channel = 0;
cfdata->channel_name = evas_stringshare_add(cfdata->conf->channel_name);
cfdata->channels_names = e_mixer_system_get_channels_names(sys);
for (l = cfdata->channels_names, i = 0; l != NULL; l = l->next, i++)
{
char *channel;
channel = l->data;
if (channel && cfdata->channel_name &&
(strcmp(channel, cfdata->channel_name) == 0))
{
cfdata->channel = i;
break;
}
}
e_mixer_system_del(sys);
}
static void *
_create_data(E_Config_Dialog *dialog)
{
E_Config_Dialog_Data *cfdata;
E_Mixer_Gadget_Config *conf;
cfdata = E_NEW(E_Config_Dialog_Data, 1);
if (!cfdata)
return NULL;
conf = dialog->data;
cfdata->conf = conf;
cfdata->lock_sliders = conf->lock_sliders;
cfdata->show_locked = conf->show_locked;
cfdata->card = evas_stringshare_add(conf->card);
_mixer_fill_cards_info(cfdata);
_mixer_fill_channels_info(cfdata);
return cfdata;
}
static void
_free_data(E_Config_Dialog *dialog, E_Config_Dialog_Data *cfdata)
{
E_Mixer_Gadget_Config *conf;
Evas_List *l;
conf = dialog->data;
if (conf)
conf->dialog = NULL;
if (!cfdata)
return;
for (l = cfdata->cards_names; l != NULL; l = l->next)
if (l->data)
free(l->data);
evas_list_free(cfdata->cards_names);
if (cfdata->channels_names)
e_mixer_system_free_channels_names(cfdata->channels_names);
if (cfdata->cards)
e_mixer_system_free_cards(cfdata->cards);
if (cfdata->card)
evas_stringshare_del(cfdata->card);
if (cfdata->channel_name)
evas_stringshare_del(cfdata->channel_name);
evas_list_free(cfdata->ui.channels.radios);
E_FREE(cfdata);
}
static int
_basic_apply(E_Config_Dialog *dialog, E_Config_Dialog_Data *cfdata)
{
E_Mixer_Gadget_Config *conf;
const char *card, *channel;
conf = dialog->data;
conf->lock_sliders = cfdata->lock_sliders;
conf->show_locked = cfdata->show_locked;
card = evas_list_nth(cfdata->cards, cfdata->card_num);
if (card)
{
if (conf->card && (strcmp(card, conf->card) != 0))
evas_stringshare_del(conf->card);
conf->card = evas_stringshare_add(card);
}
channel = evas_list_nth(cfdata->channels_names, cfdata->channel);
if (channel)
{
if (conf->channel_name && (strcmp(channel, conf->channel_name) != 0))
evas_stringshare_del(conf->channel_name);
conf->channel_name = evas_stringshare_add(channel);
}
e_mixer_update(conf->instance);
return 1;
}
static void
_lock_change(void *data, Evas_Object *obj, void *event)
{
E_Config_Dialog_Data *cfdata;
cfdata = data;
e_widget_disabled_set(cfdata->ui.general.show_locked, !cfdata->lock_sliders);
}
static void
_basic_create_general(Evas *evas, E_Config_Dialog_Data *cfdata)
{
struct mixer_config_ui_general *ui;
ui = &cfdata->ui.general;
ui->frame = e_widget_framelist_add(evas, D_("General Settings"), 0);
ui->lock_sliders = e_widget_check_add(
evas, D_("Lock Sliders"), &cfdata->lock_sliders);
evas_object_smart_callback_add(
ui->lock_sliders, "changed", _lock_change, cfdata);
e_widget_framelist_object_append(ui->frame, ui->lock_sliders);
ui->show_locked = e_widget_check_add(
evas, D_("Show both sliders when locked"), &cfdata->show_locked);
e_widget_disabled_set(ui->show_locked, !cfdata->lock_sliders);
e_widget_framelist_object_append(ui->frame, ui->show_locked);
}
static void
_clear_channels(E_Config_Dialog_Data *cfdata)
{
Evas_List *l;
for (l = cfdata->ui.channels.radios; l != NULL; l = l->next)
evas_object_del(l->data);
cfdata->ui.channels.radios = evas_list_free(cfdata->ui.channels.radios);
}
static void
_fill_channels(Evas *evas, E_Config_Dialog_Data *cfdata)
{
struct mixer_config_ui_channels *ui;
Evas_Object *selected;
Evas_Coord mw, mh;
Evas_List *l;
int i;
ui = &cfdata->ui.channels;
ui->radio = e_widget_radio_group_new(&cfdata->channel);
for (i = 0, l = cfdata->channels_names; l != NULL; l = l->next, i++)
{
Evas_Object *ow;
const char *name;
name = l->data;
if (!name)
continue;
ow = e_widget_radio_add(evas, name, i, ui->radio);
ui->radios = evas_list_append(ui->radios, ow);
e_widget_list_object_append(ui->list, ow, 1, 1, 0.0);
}
e_widget_min_size_get(ui->list, &mw, &mh);
evas_object_resize(ui->list, mw, mh);
selected = evas_list_nth(ui->radios, cfdata->channel);
if (selected)
{
Evas_Coord x, y, w, h, lx, ly;
evas_object_geometry_get(selected, &x, &y, &w, &h);
evas_object_geometry_get(ui->list, &lx, &ly, NULL, NULL);
x -= lx;
y -= ly - 10;
h += 20;
e_widget_scrollframe_child_region_show(ui->scroll, x, y, w, h);
}
}
static void
_channel_scroll_set_min_size(struct mixer_config_ui_channels *ui)
{
Evas_Coord w, h;
int len;
len = evas_list_count(ui->radios);
if (len < 1)
return;
e_widget_min_size_get(ui->list, &w, &h);
h = 4 * h / len;
e_widget_min_size_set(ui->scroll, w, h);
}
static void
_basic_create_channels(Evas *evas, E_Config_Dialog_Data *cfdata)
{
struct mixer_config_ui_channels *ui;
ui = &cfdata->ui.channels;
ui->list = e_widget_list_add(evas, 1, 0);
ui->scroll = e_widget_scrollframe_simple_add(evas, ui->list);
ui->frame = e_widget_framelist_add(evas, D_("Channels"), 0);
_fill_channels(evas, cfdata);
_channel_scroll_set_min_size(ui);
e_widget_framelist_object_append(ui->frame, ui->scroll);
}
static void
_card_change(void *data, Evas_Object *obj, void *event)
{
E_Config_Dialog_Data *cfdata;
Evas *evas;
char *card;
cfdata = data;
if (cfdata->card)
evas_stringshare_del(cfdata->card);
e_mixer_system_free_channels_names(cfdata->channels_names);
if (cfdata->channel_name)
evas_stringshare_del(cfdata->channel_name);
card = evas_list_nth(cfdata->cards, cfdata->card_num);
cfdata->card = evas_stringshare_add(card);
_mixer_fill_channels_info(cfdata);
evas = evas_object_evas_get(obj);
_clear_channels(cfdata);
_fill_channels(evas, cfdata);
}
static void
_basic_create_cards(Evas *evas, E_Config_Dialog_Data *cfdata)
{
struct mixer_config_ui_cards *ui;
Evas_List *l;
int i;
ui = &cfdata->ui.cards;
ui->frame = e_widget_framelist_add(evas, D_("Sound Cards"), 0);
ui->radio = e_widget_radio_group_new(&cfdata->card_num);
for (i = 0, l = cfdata->cards_names; l != NULL; l = l->next, i++)
{
Evas_Object *ow;
const char *card;
card = l->data;
if (!card)
continue;
ow = e_widget_radio_add(evas, card, i, ui->radio);
e_widget_framelist_object_append(ui->frame, ow);
evas_object_smart_callback_add(ow, "changed", _card_change, cfdata);
}
}
static Evas_Object *
_basic_create(E_Config_Dialog *cfd, Evas *evas, E_Config_Dialog_Data *cfdata)
{
if (!cfdata)
return NULL;
cfdata->ui.table = e_widget_table_add(evas, 0);
_basic_create_general(evas, cfdata);
_basic_create_cards(evas, cfdata);
_basic_create_channels(evas, cfdata);
e_widget_table_object_append(cfdata->ui.table, cfdata->ui.general.frame,
0, 0, 1, 1, 1, 1, 1, 0);
e_widget_table_object_append(cfdata->ui.table, cfdata->ui.cards.frame,
0, 1, 1, 1, 1, 1, 1, 0);
e_widget_table_object_append(cfdata->ui.table, cfdata->ui.channels.frame,
0, 2, 1, 1, 1, 1, 1, 1);
return cfdata->ui.table;
}
E_Config_Dialog *
e_mixer_config_dialog_new(E_Container *con, E_Mixer_Gadget_Config *conf)
{
E_Config_Dialog *dialog;
E_Config_Dialog_View *view;
if (e_config_dialog_find(_Name, "e_mixer_config_dialog_new"))
return NULL;
view = E_NEW(E_Config_Dialog_View, 1);
if (!view)
return NULL;
view->create_cfdata = _create_data;
view->free_cfdata = _free_data;
view->basic.create_widgets = _basic_create;
view->basic.apply_cfdata = _basic_apply;
dialog = e_config_dialog_new(con, D_("Mixer Configuration"),
_Name, "e_mixer_config_dialog_new",
e_mixer_theme_path(), 0, view, conf);
e_dialog_resizable_set(dialog->dia, 1);
return dialog;
}

View File

@ -0,0 +1,192 @@
#include "e_mod_main.h"
extern const char _Name[];
struct _E_Config_Dialog_Data
{
int default_instance;
struct mixer_config_ui
{
Evas_Object *list;
struct mixer_config_ui_general
{
Evas_Object *frame;
E_Radio_Group *radio;
} general;
} ui;
};
static int
_find_default_instance_index(E_Mixer_Module_Context *ctxt)
{
Evas_List *l;
int i;
for (i = 0, l = ctxt->instances; l != NULL; l = l->next, i++)
if (l->data == ctxt->default_instance)
return i;
return 0;
}
static void *
_create_data(E_Config_Dialog *dialog)
{
E_Config_Dialog_Data *cfdata;
E_Mixer_Module_Context *ctxt;
cfdata = E_NEW(E_Config_Dialog_Data, 1);
if (!cfdata)
return NULL;
ctxt = dialog->data;
cfdata->default_instance = _find_default_instance_index(ctxt);
return cfdata;
}
static void
_free_data(E_Config_Dialog *dialog, E_Config_Dialog_Data *cfdata)
{
E_Mixer_Module_Context *ctxt;
ctxt = dialog->data;
if (ctxt)
ctxt->conf_dialog = NULL;
E_FREE(cfdata);
}
static int
_basic_apply(E_Config_Dialog *dialog, E_Config_Dialog_Data *cfdata)
{
E_Mixer_Module_Context *ctxt;
ctxt = dialog->data;
ctxt->default_instance = evas_list_nth(ctxt->instances,
cfdata->default_instance);
if (ctxt->default_instance)
{
E_Mixer_Module_Config *conf;
const char *id;
conf = ctxt->conf;
if (conf->default_gc_id)
evas_stringshare_del(conf->default_gc_id);
id = ctxt->default_instance->gcc->cf->id;
conf->default_gc_id = evas_stringshare_add(id);
}
return 1;
}
static void
_basic_create_general(E_Config_Dialog *dialog, Evas *evas, E_Config_Dialog_Data *cfdata)
{
struct mixer_config_ui_general *ui;
E_Mixer_Module_Context *ctxt;
Evas_Object *label;
Evas_List *l;
int i;
ui = &cfdata->ui.general;
ctxt = dialog->data;
ui->frame = e_widget_framelist_add(evas, D_("General Settings"), 0);
label = e_widget_label_add(evas, D_("Mixer to use for global actions:"));
e_widget_framelist_object_append(ui->frame, label);
ui->radio = e_widget_radio_group_new(&cfdata->default_instance);
for (i = 0, l = ctxt->instances; l != NULL; l = l->next, i++)
{
E_Mixer_Instance *inst;
E_Mixer_Gadget_Config *conf;
Evas_Object *o;
char name[128];
char *card_name;
inst = l->data;
conf = inst->conf;
card_name = e_mixer_system_get_card_name(conf->card);
snprintf(name, sizeof(name), "%s: %s", card_name, conf->channel_name);
free(card_name);
o = e_widget_radio_add(evas, name, i, ui->radio);
e_widget_framelist_object_append(ui->frame, o);
}
e_widget_list_object_append(cfdata->ui.list, ui->frame, 1, 1, 0.5);
}
static void
cb_mixer_app_del(E_Dialog *dialog, void *data)
{
E_Mixer_Module_Context *ctxt = data;
ctxt->mixer_dialog = NULL;
}
static void
cb_mixer_call(void *data, void *data2)
{
E_Mixer_Module_Context *ctxt = data;
E_Container *con;
if (ctxt->mixer_dialog)
{
e_dialog_show(ctxt->mixer_dialog);
return;
}
con = e_container_current_get(e_manager_current_get());
ctxt->mixer_dialog = e_mixer_app_dialog_new(con, cb_mixer_app_del, ctxt);
}
static void
_basic_create_mixer_call(E_Config_Dialog *dialog, Evas *evas, E_Config_Dialog_Data *cfdata)
{
Evas_Object *button;
button = e_widget_button_add(evas, D_("Launch mixer..."), NULL,
cb_mixer_call, dialog->data, NULL);
e_widget_list_object_append(cfdata->ui.list, button, 0, 0, 0.0);
}
static Evas_Object *
_basic_create(E_Config_Dialog *dialog, Evas *evas, E_Config_Dialog_Data *cfdata)
{
if (!cfdata)
return NULL;
cfdata->ui.list = e_widget_list_add(evas, 0, 0);
_basic_create_general(dialog, evas, cfdata);
_basic_create_mixer_call(dialog, evas, cfdata);
return cfdata->ui.list;
}
E_Config_Dialog *
e_mixer_config_module_dialog_new(E_Container *con, E_Mixer_Module_Context *ctxt)
{
E_Config_Dialog *dialog;
E_Config_Dialog_View *view;
if (e_config_dialog_find(_Name, "e_mixer_config_module_dialog_new"))
return NULL;
view = E_NEW(E_Config_Dialog_View, 1);
if (!view)
return NULL;
view->create_cfdata = _create_data;
view->free_cfdata = _free_data;
view->basic.create_widgets = _basic_create;
view->basic.apply_cfdata = _basic_apply;
dialog = e_config_dialog_new(con, D_("Mixer Module Configuration"),
_Name, "e_mixer_config_module_dialog_new",
e_mixer_theme_path(), 0, view, ctxt);
return dialog;
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,89 @@
#define D_(str) dgettext(PACKAGE, str)
#ifndef E_MOD_MAIN_H
#define E_MOD_MAIN_H
#include "config.h"
#include "e_mod_system.h"
#include <e.h>
#define MOD_CONF_VERSION 3
typedef struct E_Mixer_Gadget_Config
{
int lock_sliders;
int show_locked;
const char *card;
const char *channel_name;
const char *id;
E_Config_Dialog *dialog;
struct E_Mixer_Instance *instance;
} E_Mixer_Gadget_Config;
typedef struct E_Mixer_Module_Config
{
int version;
const char *default_gc_id;
Evas_Hash *gadgets;
} E_Mixer_Module_Config;
typedef struct E_Mixer_Instance
{
E_Gadcon_Client *gcc;
E_Gadcon_Popup *popup;
E_Menu *menu;
struct
{
Evas_Object *gadget;
Evas_Object *label;
Evas_Object *left;
Evas_Object *right;
Evas_Object *mute;
Evas_Object *table;
Evas_Object *button;
struct
{
Ecore_X_Window win;
Ecore_Event_Handler *mouse_up;
Ecore_Event_Handler *key_down;
} input;
} ui;
E_Mixer_System *sys;
E_Mixer_Channel *channel;
E_Mixer_Channel_State mixer_state;
E_Mixer_Gadget_Config *conf;
} E_Mixer_Instance;
typedef struct E_Mixer_Module_Context
{
E_Config_DD *module_conf_edd;
E_Config_DD *gadget_conf_edd;
E_Mixer_Module_Config *conf;
E_Config_Dialog *conf_dialog;
E_Mixer_Instance *default_instance;
Evas_List *instances;
E_Dialog *mixer_dialog;
struct st_mixer_actions
{
E_Action *incr;
E_Action *decr;
E_Action *mute;
} actions;
} E_Mixer_Module_Context;
EAPI extern E_Module_Api e_modapi;
EAPI void *e_modapi_init(E_Module *m);
EAPI int e_modapi_shutdown(E_Module *m);
EAPI int e_modapi_save(E_Module *m);
E_Config_Dialog *e_mixer_config_module_dialog_new(E_Container *con, E_Mixer_Module_Context *ctxt);
E_Config_Dialog *e_mixer_config_dialog_new(E_Container *con, E_Mixer_Gadget_Config *conf);
E_Dialog *e_mixer_app_dialog_new(E_Container *con, void (*func)(E_Dialog *dialog, void *data), void *data);
int e_mixer_app_dialog_select(E_Dialog *dialog, const char *card_name, const char *channel_name);
int e_mixer_update(E_Mixer_Instance *inst);
const char *e_mixer_theme_path(void);
#endif

View File

@ -0,0 +1,48 @@
#ifndef E_MOD_SYSTEM_H
#define E_MOD_SYSTEM_H
#include <Evas.h>
typedef void E_Mixer_System;
typedef void E_Mixer_Channel;
struct E_Mixer_Channel_State
{
int mute;
int left;
int right;
};
typedef struct E_Mixer_Channel_State E_Mixer_Channel_State;
Evas_List *e_mixer_system_get_cards(void);
void e_mixer_system_free_cards(Evas_List *cards);
char *e_mixer_system_get_default_card(void);
char *e_mixer_system_get_card_name(const char *card);
E_Mixer_System *e_mixer_system_new(const char *card);
void e_mixer_system_del(E_Mixer_System *self);
int e_mixer_system_callback_set(E_Mixer_System *self, int (*func)(void *data, E_Mixer_System *self), void *data);
Evas_List *e_mixer_system_get_channels(E_Mixer_System *self);
void e_mixer_system_free_channels(Evas_List *channels);
Evas_List *e_mixer_system_get_channels_names(E_Mixer_System *self);
void e_mixer_system_free_channels_names(Evas_List *channels_names);
char *e_mixer_system_get_default_channel_name(E_Mixer_System *self);
E_Mixer_Channel *e_mixer_system_get_channel_by_name(E_Mixer_System *self, const char *name);
char *e_mixer_system_get_channel_name(E_Mixer_System *self, E_Mixer_Channel *channel);
void e_mixer_system_channel_del(E_Mixer_Channel *channel);
int e_mixer_system_get_state(E_Mixer_System *self, E_Mixer_Channel *channel, E_Mixer_Channel_State *state);
int e_mixer_system_set_state(E_Mixer_System *self, E_Mixer_Channel *channel, const E_Mixer_Channel_State *state);
int e_mixer_system_get_volume(E_Mixer_System *self, E_Mixer_Channel *channel, int *left, int *right);
int e_mixer_system_set_volume(E_Mixer_System *self, E_Mixer_Channel *channel, int left, int right);
int e_mixer_system_get_mute(E_Mixer_System *self, E_Mixer_Channel *channel, int *mute);
int e_mixer_system_set_mute(E_Mixer_System *self, E_Mixer_Channel *channel, int mute);
int e_mixer_system_can_mute(E_Mixer_System *self, E_Mixer_Channel *channel);
int e_mixer_system_has_capture(E_Mixer_System *self, E_Mixer_Channel *channel);
#endif /* E_MOD_SYSTEM_H */

View File

@ -0,0 +1,5 @@
[Desktop Entry]
Type=Link
Name=Mixer
Icon=e-module-mixer
Comment=<hilight>Mixer Gadget</hilight><br><br>A module to provide a mixer for changing volume.

View File

@ -0,0 +1,618 @@
#include <alsa/asoundlib.h>
#include <stdlib.h>
#include <math.h>
#include <poll.h>
#include <alloca.h>
#include <Ecore.h>
#include "e_mod_system.h"
struct e_mixer_callback_desc
{
int (*func)(void *data, E_Mixer_System *self);
void *data;
E_Mixer_System *self;
Ecore_Idler *idler;
Evas_List *handlers;
};
static int _mixer_callback_add(E_Mixer_System *self, int (*func)(void *data, E_Mixer_System *self), void *data);
static int _mixer_callback_del(E_Mixer_System *self, struct e_mixer_callback_desc *desc);
static int
_cb_dispatch(void *data)
{
struct e_mixer_callback_desc *desc;
int r;
desc = data;
snd_mixer_handle_events(desc->self);
r = desc->func(desc->data, desc->self);
desc->idler = NULL;
if (!r)
_mixer_callback_del(desc->self, desc); /* desc is invalid then. */
return 0;
}
static int
_cb_fd_handler(void *data, Ecore_Fd_Handler *fd_handler)
{
struct e_mixer_callback_desc *desc;
desc = data;
if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR))
{
desc->handlers = evas_list_remove(desc->handlers, fd_handler);
if (!desc->handlers)
{
E_Mixer_System *s;
int (*f)(void *, E_Mixer_System *);
void *d;
s = desc->self;
f = desc->func;
d = desc->data;
_mixer_callback_del(s, desc);
_mixer_callback_add(s, f, d);
}
return 0;
}
if (!desc->idler)
desc->idler = ecore_idler_add(_cb_dispatch, desc);
return 1;
}
static int
_mixer_callback_add(E_Mixer_System *self, int (*func)(void *data, E_Mixer_System *self), void *data)
{
struct e_mixer_callback_desc *desc;
struct pollfd *pfds;
int len;
len = snd_mixer_poll_descriptors_count(self);
if (len <= 0)
return 0;
desc = malloc(sizeof(struct e_mixer_callback_desc));
if (!desc)
return 0;
desc->func = func;
desc->data = data;
desc->self = self;
desc->idler = NULL;
desc->handlers = NULL;
pfds = alloca(len * sizeof(struct pollfd));
len = snd_mixer_poll_descriptors(self, pfds, len);
if (len <= 0)
{
free(desc);
return 0;
}
while (len > 0)
{
Ecore_Fd_Handler *fd_handler;
len--;
fd_handler = ecore_main_fd_handler_add(
pfds[len].fd, ECORE_FD_READ, _cb_fd_handler, desc, NULL, NULL);
desc->handlers = evas_list_prepend(desc->handlers, fd_handler);
}
snd_mixer_set_callback_private(self, desc);
return 1;
}
static int
_mixer_callback_del(E_Mixer_System *self, struct e_mixer_callback_desc *desc)
{
Evas_List *l;
snd_mixer_set_callback_private(self, NULL);
for (l = desc->handlers; l != NULL; l = l->next)
ecore_main_fd_handler_del(l->data);
evas_list_free(desc->handlers);
free(desc);
return 1;
}
static int
_mixer_callback_replace(E_Mixer_System *self, struct e_mixer_callback_desc *desc, int (*func)(void *data, E_Mixer_System *self), void *data)
{
desc->func = func;
desc->data = data;
return 1;
}
E_Mixer_System *
e_mixer_system_new(const char *name)
{
snd_mixer_t *handle;
int err;
if (!name)
return NULL;
err = snd_mixer_open(&handle, 0);
if (err < 0)
goto error_open;
err = snd_mixer_attach(handle, name);
if (err < 0)
goto error_load;
err = snd_mixer_selem_register(handle, NULL, NULL);
if (err < 0)
goto error_load;
err = snd_mixer_load(handle);
if (err < 0)
goto error_load;
return handle;
error_load:
snd_mixer_close(handle);
error_open:
fprintf(stderr, "MIXER: Cannot get hardware info: %s\n", snd_strerror(err));
return NULL;
}
void
e_mixer_system_del(E_Mixer_System *self)
{
struct e_mixer_callback_desc *desc;
if (self <= 0)
return;
desc = snd_mixer_get_callback_private(self);
if (desc)
_mixer_callback_del(self, desc);
snd_mixer_close(self);
}
int
e_mixer_system_callback_set(E_Mixer_System *self, int (*func)(void *data, E_Mixer_System *self), void *data)
{
struct e_mixer_callback_desc *desc;
if (!self)
return 0;
desc = snd_mixer_get_callback_private(self);
if (!desc)
{
if (func)
return _mixer_callback_add(self, func, data);
return 1;
}
else
{
if (func)
return _mixer_callback_replace(self, desc, func, data);
else
return _mixer_callback_del(self, desc);
}
}
Evas_List *
e_mixer_system_get_cards(void)
{
int err, card_num;
Evas_List *cards;
cards = NULL;
card_num = -1;
while (((err = snd_card_next(&card_num)) == 0) && (card_num >= 0))
{
snd_ctl_t *control;
char buf[256];
snprintf(buf, sizeof(buf), "hw:%d", card_num);
if (snd_ctl_open(&control, buf, 0) < 0)
break;
snd_ctl_close(control);
cards = evas_list_append(cards, strdup(buf));
}
if (err < 0)
fprintf(stderr, "MIXER: Cannot get available card number: %s\n",
snd_strerror(err));
return cards;
}
void
e_mixer_system_free_cards(Evas_List *cards)
{
Evas_List *e;
for (e = cards; e != NULL; e = e->next)
free(e->data);
evas_list_free(cards);
}
char *
e_mixer_system_get_default_card(void)
{
static const char buf[] = "hw:0";
snd_ctl_t *control;
if (snd_ctl_open(&control, buf, 0) < 0)
return NULL;
snd_ctl_close(control);
return strdup(buf);
}
char *
e_mixer_system_get_card_name(const char *card)
{
snd_ctl_card_info_t *hw_info;
const char *name;
snd_ctl_t *control;
int err;
if (!card)
return NULL;
snd_ctl_card_info_alloca(&hw_info);
err = snd_ctl_open(&control, card, 0);
if (err < 0)
return NULL;
err = snd_ctl_card_info(control, hw_info);
if (err < 0)
{
fprintf(stderr, "MIXER: Cannot get hardware info: %s: %s\n", card,
snd_strerror(err));
snd_ctl_close(control);
return NULL;
}
snd_ctl_close(control);
name = snd_ctl_card_info_get_name(hw_info);
if (!name)
{
fprintf(stderr, "MIXER: Cannot get hardware name: %s\n", card);
return NULL;
}
return strdup(name);
}
Evas_List *
e_mixer_system_get_channels(E_Mixer_System *self)
{
Evas_List *channels;
snd_mixer_elem_t *elem;
if (!self)
return NULL;
channels = NULL;
elem = snd_mixer_first_elem(self);
for (; elem != NULL; elem = snd_mixer_elem_next(elem))
{
if ((!snd_mixer_selem_is_active(elem)) ||
(!snd_mixer_selem_has_playback_volume(elem)))
continue;
channels = evas_list_append(channels, elem);
}
return channels;
}
void
e_mixer_system_free_channels(Evas_List *channels)
{
evas_list_free(channels);
}
Evas_List *
e_mixer_system_get_channels_names(E_Mixer_System *self)
{
Evas_List *channels;
snd_mixer_elem_t *elem;
snd_mixer_selem_id_t *sid;
if (!self)
return NULL;
channels = NULL;
snd_mixer_selem_id_alloca(&sid);
elem = snd_mixer_first_elem(self);
for (; elem != NULL; elem = snd_mixer_elem_next(elem))
{
const char *name;
if ((!snd_mixer_selem_is_active(elem)) ||
(!snd_mixer_selem_has_playback_volume(elem)))
continue;
snd_mixer_selem_get_id(elem, sid);
name = snd_mixer_selem_id_get_name(sid);
if (name)
channels = evas_list_append(channels, strdup(name));
}
return channels;
}
void
e_mixer_system_free_channels_names(Evas_List *channels_names)
{
Evas_List *e;
for (e = channels_names; e != NULL; e = e->next)
free(e->data);
evas_list_free(channels_names);
}
char *
e_mixer_system_get_default_channel_name(E_Mixer_System *self)
{
snd_mixer_elem_t *elem;
snd_mixer_selem_id_t *sid;
if (!self)
return NULL;
snd_mixer_selem_id_alloca(&sid);
elem = snd_mixer_first_elem(self);
for (; elem != NULL; elem = snd_mixer_elem_next(elem))
{
const char *name;
if ((!snd_mixer_selem_is_active(elem)) ||
(!snd_mixer_selem_has_playback_volume(elem)))
continue;
snd_mixer_selem_get_id(elem, sid);
name = snd_mixer_selem_id_get_name(sid);
if (name)
return strdup(name);
}
return NULL;
}
E_Mixer_Channel *
e_mixer_system_get_channel_by_name(E_Mixer_System *self, const char *name)
{
snd_mixer_elem_t *elem;
snd_mixer_selem_id_t *sid;
if ((!self) || (!name))
return NULL;
snd_mixer_selem_id_alloca(&sid);
elem = snd_mixer_first_elem(self);
for (; elem != NULL; elem = snd_mixer_elem_next(elem))
{
const char *n;
if ((!snd_mixer_selem_is_active(elem)) ||
(!snd_mixer_selem_has_playback_volume(elem)))
continue;
snd_mixer_selem_get_id(elem, sid);
n = snd_mixer_selem_id_get_name(sid);
if (n && (strcmp(n, name) == 0))
return elem;
}
return NULL;
}
void
e_mixer_system_channel_del(E_Mixer_Channel *channel)
{
}
char *
e_mixer_system_get_channel_name(E_Mixer_System *self, E_Mixer_Channel *channel)
{
snd_mixer_selem_id_t *sid;
const char *n;
char *name;
if ((!self) || (!channel))
return NULL;
snd_mixer_selem_id_alloca(&sid);
snd_mixer_selem_get_id(channel, sid);
n = snd_mixer_selem_id_get_name(sid);
if (n)
name = strdup(n);
else
name = NULL;
return name;
}
int
e_mixer_system_get_volume(E_Mixer_System *self, E_Mixer_Channel *channel, int *left, int *right)
{
long lvol, rvol, range, min, max;
if ((!self) || (!channel) || (!left) || (!right))
return 0;
snd_mixer_handle_events(self);
snd_mixer_selem_get_playback_volume_range(channel, &min, &max);
range = max - min;
if (range < 1)
return 0;
if (snd_mixer_selem_has_playback_channel(channel, 0))
snd_mixer_selem_get_playback_volume(channel, 0, &lvol);
else
lvol = min;
if (snd_mixer_selem_has_playback_channel(channel, 1))
snd_mixer_selem_get_playback_volume(channel, 1, &rvol);
else
rvol = min;
if (snd_mixer_selem_is_playback_mono(channel) ||
snd_mixer_selem_has_playback_volume_joined(channel))
rvol = lvol;
*left = rint((double)(lvol - min) * 100 / (double)range);
*right = rint((double)(rvol - min) * 100 / (double)range);
return 1;
}
int
e_mixer_system_set_volume(E_Mixer_System *self, E_Mixer_Channel *channel, int left, int right)
{
long range, min, max, div;
int mode;
if ((!self) || (!channel))
return 0;
snd_mixer_handle_events(self);
snd_mixer_selem_get_playback_volume_range(channel, &min, &max);
div = 100 + min;
if (div == 0)
{
div = 1; /* no zero-division */
min++;
}
range = max - min;
if (range < 1)
return 0;
mode = 0;
if (left >= 0)
{
left = (((range * left) + (range / 2)) / div) - min;
mode |= 1;
}
if (right >= 0)
{
right = (((range * right) + (range / 2)) / div) - min;
mode |= 2;
}
if (mode & 1)
snd_mixer_selem_set_playback_volume(channel, 0, left);
if ((!snd_mixer_selem_is_playback_mono(channel)) &&
(!snd_mixer_selem_has_playback_volume_joined(channel)) &&
(mode & 2))
{
if (snd_mixer_selem_has_playback_channel(channel, 1))
snd_mixer_selem_set_playback_volume(channel, 1, right);
}
return 1;
}
int
e_mixer_system_can_mute(E_Mixer_System *self, E_Mixer_Channel *channel)
{
if ((!self) || (!channel))
return 0;
snd_mixer_handle_events(self);
return (snd_mixer_selem_has_playback_switch(channel) ||
snd_mixer_selem_has_playback_switch_joined(channel));
}
int
e_mixer_system_get_mute(E_Mixer_System *self, E_Mixer_Channel *channel, int *mute)
{
if ((!self) || (!channel) || (!mute))
return 0;
snd_mixer_handle_events(self);
if (snd_mixer_selem_has_playback_switch(channel) ||
snd_mixer_selem_has_playback_switch_joined(channel))
{
int m;
/* XXX: not checking for return, always returns 0 even if it worked.
* alsamixer also don't check it. Bug?
*/
snd_mixer_selem_get_playback_switch(channel, 0, &m);
*mute = !m;
}
else
*mute = 0;
return 1;
}
int
e_mixer_system_set_mute(E_Mixer_System *self, E_Mixer_Channel *channel, int mute)
{
if ((!self) || (!channel))
return 0;
snd_mixer_handle_events(self);
if (snd_mixer_selem_has_playback_switch(channel) ||
snd_mixer_selem_has_playback_switch_joined(channel))
return snd_mixer_selem_set_playback_switch_all(channel, !mute);
else
return 0;
}
int
e_mixer_system_get_state(E_Mixer_System *self, E_Mixer_Channel *channel, E_Mixer_Channel_State *state)
{
int r;
if (!state)
return 0;
r = e_mixer_system_get_mute(self, channel, &state->mute);
r &= e_mixer_system_get_volume(self, channel, &state->left, &state->right);
return r;
}
int
e_mixer_system_set_state(E_Mixer_System *self, E_Mixer_Channel *channel, const E_Mixer_Channel_State *state)
{
int r;
if (!state)
return 0;
r = e_mixer_system_set_mute(self, channel, state->mute);
r &= e_mixer_system_set_volume(self, channel, state->left, state->right);
return r;
}
int
e_mixer_system_has_capture(E_Mixer_System *self, E_Mixer_Channel *channel)
{
if ((!self) || (!channel))
return 0;
return snd_mixer_selem_has_capture_switch(channel);
}

View File

@ -0,0 +1,166 @@
#include "e_mod_system.h"
#include <stdlib.h>
#include <string.h>
static const char _name[] = "dummy";
E_Mixer_System *
e_mixer_system_new(const char *name)
{
if (strcmp(name, _name) == 0)
return (E_Mixer_System *)-1;
else
return NULL;
}
void
e_mixer_system_del(E_Mixer_System *self)
{
}
int
e_mixer_system_callback_set(E_Mixer_System *self, int (*func)(void *data, E_Mixer_System *self), void *data)
{
return 0;
}
Evas_List *
e_mixer_system_get_cards(void)
{
return evas_list_append(NULL, _name);
}
void
e_mixer_system_free_cards(Evas_List *cards)
{
evas_list_free(cards);
}
char *
e_mixer_system_get_default_card(void)
{
return strdup(_name);
}
char *
e_mixer_system_get_card_name(const char *card)
{
if (strcmp(card, _name) == 0)
return strdup(_name);
else
return NULL;
}
Evas_List *
e_mixer_system_get_channels(E_Mixer_System *self)
{
return evas_list_append(NULL, (void *)-2);
}
void
e_mixer_system_free_channels(Evas_List *channels)
{
evas_list_free(channels);
}
Evas_List *
e_mixer_system_get_channels_names(E_Mixer_System *self)
{
return evas_list_append(NULL, _name);
}
void
e_mixer_system_free_channels_names(Evas_List *channels_names)
{
evas_list_free(channels_names);
}
char *
e_mixer_system_get_default_channel_name(E_Mixer_System *self)
{
return strdup(_name);
}
E_Mixer_Channel *
e_mixer_system_get_channel_by_name(E_Mixer_System *self, const char *name)
{
if (strcmp(name, _name) == 0)
return (E_Mixer_Channel *)-2;
else
return NULL;
}
void
e_mixer_system_channel_del(E_Mixer_Channel *channel)
{
}
char *
e_mixer_system_get_channel_name(E_Mixer_System *self, E_Mixer_Channel *channel)
{
if (channel == (E_Mixer_Channel *)-2)
return strdup(_name);
else
return NULL;
}
int
e_mixer_system_get_volume(E_Mixer_System *self, E_Mixer_Channel *channel, int *left, int *right)
{
if (left)
*left = 0;
if (right)
*right = 0;
return 1;
}
int
e_mixer_system_set_volume(E_Mixer_System *self, E_Mixer_Channel *channel, int left, int right)
{
return 0;
}
int
e_mixer_system_can_mute(E_Mixer_System *self, E_Mixer_Channel *channel)
{
return 1;
}
int
e_mixer_system_get_mute(E_Mixer_System *self, E_Mixer_Channel *channel, int *mute)
{
if (mute)
*mute = 1;
return 1;
}
int
e_mixer_system_set_mute(E_Mixer_System *self, E_Mixer_Channel *channel, int mute)
{
return 0;
}
int
e_mixer_system_get_state(E_Mixer_System *self, E_Mixer_Channel *channel, E_Mixer_Channel_State *state)
{
const E_Mixer_Channel_State def = {1, 0, 0};
if (state)
*state = def;
return 1;
}
int
e_mixer_system_set_state(E_Mixer_System *self, E_Mixer_Channel *channel, const E_Mixer_Channel_State *state)
{
return 0;
}
int
e_mixer_system_has_capture(E_Mixer_System *self, E_Mixer_Channel *channel)
{
return 0;
}