2008-07-31 20:08:16 -07:00
|
|
|
#include <alsa/asoundlib.h>
|
|
|
|
#include <poll.h>
|
|
|
|
#include "e_mod_system.h"
|
2010-03-10 13:54:23 -08:00
|
|
|
#include "e.h"
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
struct e_mixer_callback_desc
|
|
|
|
{
|
2011-07-15 12:26:57 -07:00
|
|
|
int (*func)(void *data,
|
|
|
|
E_Mixer_System *self);
|
|
|
|
void *data;
|
2008-07-31 20:08:16 -07:00
|
|
|
E_Mixer_System *self;
|
2011-07-15 12:26:57 -07:00
|
|
|
Ecore_Idler *idler;
|
|
|
|
Eina_List *handlers;
|
2008-07-31 20:08:16 -07:00
|
|
|
};
|
|
|
|
|
2011-07-15 12:26:57 -07:00
|
|
|
static int _mixer_callback_add(E_Mixer_System *self,
|
|
|
|
int (*func)(void *data, E_Mixer_System *self),
|
|
|
|
void *data);
|
2012-08-24 06:57:22 -07:00
|
|
|
static int _mixer_callback_del(E_Mixer_System *self,
|
2011-07-15 12:26:57 -07:00
|
|
|
struct e_mixer_callback_desc *desc);
|
2008-07-31 20:08:16 -07:00
|
|
|
|
2010-06-24 09:19:12 -07:00
|
|
|
static Eina_Bool
|
2008-07-31 20:08:16 -07:00
|
|
|
_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)
|
2011-07-15 12:26:57 -07:00
|
|
|
_mixer_callback_del(desc->self, desc); /* desc is invalid then. */
|
2008-07-31 20:08:16 -07:00
|
|
|
|
2010-06-24 09:19:12 -07:00
|
|
|
return ECORE_CALLBACK_CANCEL;
|
2008-07-31 20:08:16 -07:00
|
|
|
}
|
|
|
|
|
2010-06-24 09:19:12 -07:00
|
|
|
static Eina_Bool
|
2012-08-24 06:57:22 -07:00
|
|
|
_cb_fd_handler(void *data,
|
2011-07-15 12:26:57 -07:00
|
|
|
Ecore_Fd_Handler *fd_handler)
|
2008-07-31 20:08:16 -07:00
|
|
|
{
|
|
|
|
struct e_mixer_callback_desc *desc;
|
|
|
|
|
|
|
|
desc = data;
|
|
|
|
|
|
|
|
if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR))
|
2010-03-10 13:54:23 -08:00
|
|
|
{
|
2011-07-15 12:26:57 -07:00
|
|
|
desc->handlers = eina_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 ECORE_CALLBACK_CANCEL;
|
2010-03-10 13:54:23 -08:00
|
|
|
}
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
if (!desc->idler)
|
2010-03-10 13:54:23 -08:00
|
|
|
desc->idler = ecore_idler_add(_cb_dispatch, desc);
|
2010-06-24 09:19:12 -07:00
|
|
|
return ECORE_CALLBACK_RENEW;
|
2008-07-31 20:08:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2011-07-15 12:26:57 -07:00
|
|
|
_mixer_callback_add(E_Mixer_System *self,
|
|
|
|
int (*func)(void *data, E_Mixer_System *self),
|
|
|
|
void *data)
|
2008-07-31 20:08:16 -07:00
|
|
|
{
|
|
|
|
struct e_mixer_callback_desc *desc;
|
|
|
|
struct pollfd *pfds;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
len = snd_mixer_poll_descriptors_count(self);
|
|
|
|
if (len <= 0)
|
2010-03-10 13:54:23 -08:00
|
|
|
return 0;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
desc = malloc(sizeof(struct e_mixer_callback_desc));
|
|
|
|
if (!desc)
|
2010-03-10 13:54:23 -08:00
|
|
|
return 0;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
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)
|
2010-03-10 13:54:23 -08:00
|
|
|
{
|
2011-07-15 12:26:57 -07:00
|
|
|
free(desc);
|
|
|
|
return 0;
|
2010-03-10 13:54:23 -08:00
|
|
|
}
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
while (len > 0)
|
2010-03-10 13:54:23 -08:00
|
|
|
{
|
2011-07-15 12:26:57 -07:00
|
|
|
Ecore_Fd_Handler *fd_handler;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
2011-07-15 12:26:57 -07:00
|
|
|
len--;
|
|
|
|
fd_handler = ecore_main_fd_handler_add(
|
|
|
|
pfds[len].fd, ECORE_FD_READ, _cb_fd_handler, desc, NULL, NULL);
|
|
|
|
desc->handlers = eina_list_prepend(desc->handlers, fd_handler);
|
2010-03-10 13:54:23 -08:00
|
|
|
}
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
snd_mixer_set_callback_private(self, desc);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2012-08-24 06:57:22 -07:00
|
|
|
_mixer_callback_del(E_Mixer_System *self,
|
2011-07-15 12:26:57 -07:00
|
|
|
struct e_mixer_callback_desc *desc)
|
2008-07-31 20:08:16 -07:00
|
|
|
{
|
2009-03-11 08:13:42 -07:00
|
|
|
Ecore_Fd_Handler *handler;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
2009-03-11 08:13:42 -07:00
|
|
|
EINA_LIST_FREE(desc->handlers, handler)
|
2010-03-10 13:54:23 -08:00
|
|
|
ecore_main_fd_handler_del(handler);
|
2008-07-31 20:08:16 -07:00
|
|
|
|
2010-07-29 19:55:06 -07:00
|
|
|
snd_mixer_set_callback_private(self, NULL);
|
|
|
|
|
2008-07-31 20:08:16 -07:00
|
|
|
free(desc);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2011-07-15 12:26:57 -07:00
|
|
|
_mixer_callback_replace(E_Mixer_System *self __UNUSED__,
|
|
|
|
struct e_mixer_callback_desc *desc,
|
|
|
|
int (*func)(void *data, E_Mixer_System *self),
|
|
|
|
void *data)
|
2008-07-31 20:08:16 -07:00
|
|
|
{
|
|
|
|
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)
|
2010-03-10 13:54:23 -08:00
|
|
|
return NULL;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
err = snd_mixer_open(&handle, 0);
|
|
|
|
if (err < 0)
|
2010-03-10 13:54:23 -08:00
|
|
|
goto error_open;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
err = snd_mixer_attach(handle, name);
|
|
|
|
if (err < 0)
|
2010-03-10 13:54:23 -08:00
|
|
|
goto error_load;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
err = snd_mixer_selem_register(handle, NULL, NULL);
|
|
|
|
if (err < 0)
|
2010-03-10 13:54:23 -08:00
|
|
|
goto error_load;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
err = snd_mixer_load(handle);
|
|
|
|
if (err < 0)
|
2010-03-10 13:54:23 -08:00
|
|
|
goto error_load;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
return handle;
|
|
|
|
|
2011-07-15 12:26:57 -07:00
|
|
|
error_load:
|
2008-07-31 20:08:16 -07:00
|
|
|
snd_mixer_close(handle);
|
2011-07-15 12:26:57 -07:00
|
|
|
error_open:
|
2008-07-31 20:08:16 -07:00
|
|
|
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;
|
|
|
|
|
2010-03-10 13:54:23 -08:00
|
|
|
if (!self)
|
|
|
|
return;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
desc = snd_mixer_get_callback_private(self);
|
|
|
|
if (desc)
|
2010-03-10 13:54:23 -08:00
|
|
|
_mixer_callback_del(self, desc);
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
snd_mixer_close(self);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2011-07-15 12:26:57 -07:00
|
|
|
e_mixer_system_callback_set(E_Mixer_System *self,
|
|
|
|
int (*func)(void *data, E_Mixer_System *self),
|
|
|
|
void *data)
|
2008-07-31 20:08:16 -07:00
|
|
|
{
|
|
|
|
struct e_mixer_callback_desc *desc;
|
|
|
|
|
|
|
|
if (!self)
|
2010-03-10 13:54:23 -08:00
|
|
|
return 0;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
desc = snd_mixer_get_callback_private(self);
|
|
|
|
if (!desc)
|
2010-03-10 13:54:23 -08:00
|
|
|
{
|
2011-07-15 12:26:57 -07:00
|
|
|
if (func)
|
|
|
|
return _mixer_callback_add(self, func, data);
|
|
|
|
return 1;
|
2010-03-10 13:54:23 -08:00
|
|
|
}
|
2008-07-31 20:08:16 -07:00
|
|
|
else
|
2010-03-10 13:54:23 -08:00
|
|
|
{
|
2011-07-15 12:26:57 -07:00
|
|
|
if (func)
|
|
|
|
return _mixer_callback_replace(self, desc, func, data);
|
|
|
|
else
|
|
|
|
return _mixer_callback_del(self, desc);
|
2010-03-10 13:54:23 -08:00
|
|
|
}
|
2008-07-31 20:08:16 -07:00
|
|
|
}
|
|
|
|
|
2008-10-22 04:49:33 -07:00
|
|
|
Eina_List *
|
2008-07-31 20:08:16 -07:00
|
|
|
e_mixer_system_get_cards(void)
|
|
|
|
{
|
|
|
|
int err, card_num;
|
2008-10-22 04:49:33 -07:00
|
|
|
Eina_List *cards;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
cards = NULL;
|
|
|
|
card_num = -1;
|
|
|
|
while (((err = snd_card_next(&card_num)) == 0) && (card_num >= 0))
|
2010-03-10 13:54:23 -08:00
|
|
|
{
|
2011-07-15 12:26:57 -07:00
|
|
|
snd_ctl_t *control;
|
|
|
|
char buf[256];
|
2008-07-31 20:08:16 -07:00
|
|
|
|
2011-07-15 12:26:57 -07:00
|
|
|
snprintf(buf, sizeof(buf), "hw:%d", card_num);
|
2008-07-31 20:08:16 -07:00
|
|
|
|
2011-07-15 12:26:57 -07:00
|
|
|
if (snd_ctl_open(&control, buf, 0) < 0)
|
|
|
|
break;
|
|
|
|
snd_ctl_close(control);
|
|
|
|
cards = eina_list_append(cards, eina_stringshare_add(buf));
|
2010-03-10 13:54:23 -08:00
|
|
|
}
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
if (err < 0)
|
2010-03-10 13:54:23 -08:00
|
|
|
fprintf(stderr, "MIXER: Cannot get available card number: %s\n",
|
2011-07-15 12:26:57 -07:00
|
|
|
snd_strerror(err));
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
return cards;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-10-22 04:49:33 -07:00
|
|
|
e_mixer_system_free_cards(Eina_List *cards)
|
2008-07-31 20:08:16 -07:00
|
|
|
{
|
2009-03-11 08:13:42 -07:00
|
|
|
const char *card;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
2009-03-11 08:13:42 -07:00
|
|
|
EINA_LIST_FREE(cards, card)
|
2010-03-10 13:54:23 -08:00
|
|
|
eina_stringshare_del(card);
|
2008-07-31 20:08:16 -07:00
|
|
|
}
|
|
|
|
|
2009-03-11 08:13:42 -07:00
|
|
|
const char *
|
2008-07-31 20:08:16 -07:00
|
|
|
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)
|
2010-03-10 13:54:23 -08:00
|
|
|
return NULL;
|
2008-07-31 20:08:16 -07:00
|
|
|
snd_ctl_close(control);
|
2009-03-11 08:13:42 -07:00
|
|
|
return eina_stringshare_add(buf);
|
2008-07-31 20:08:16 -07:00
|
|
|
}
|
|
|
|
|
2009-03-11 08:13:42 -07:00
|
|
|
const char *
|
2008-07-31 20:08:16 -07:00
|
|
|
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)
|
2010-03-10 13:54:23 -08:00
|
|
|
return NULL;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
snd_ctl_card_info_alloca(&hw_info);
|
|
|
|
|
|
|
|
err = snd_ctl_open(&control, card, 0);
|
|
|
|
if (err < 0)
|
2010-03-10 13:54:23 -08:00
|
|
|
return NULL;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
err = snd_ctl_card_info(control, hw_info);
|
|
|
|
if (err < 0)
|
2010-03-10 13:54:23 -08:00
|
|
|
{
|
2011-07-15 12:26:57 -07:00
|
|
|
fprintf(stderr, "MIXER: Cannot get hardware info: %s: %s\n", card,
|
|
|
|
snd_strerror(err));
|
|
|
|
snd_ctl_close(control);
|
|
|
|
return NULL;
|
2010-03-10 13:54:23 -08:00
|
|
|
}
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
snd_ctl_close(control);
|
|
|
|
name = snd_ctl_card_info_get_name(hw_info);
|
|
|
|
if (!name)
|
2010-03-10 13:54:23 -08:00
|
|
|
{
|
2011-07-15 12:26:57 -07:00
|
|
|
fprintf(stderr, "MIXER: Cannot get hardware name: %s\n", card);
|
|
|
|
return NULL;
|
2010-03-10 13:54:23 -08:00
|
|
|
}
|
2008-07-31 20:08:16 -07:00
|
|
|
|
2009-03-11 08:13:42 -07:00
|
|
|
return eina_stringshare_add(name);
|
2008-07-31 20:08:16 -07:00
|
|
|
}
|
|
|
|
|
2008-10-22 04:49:33 -07:00
|
|
|
Eina_List *
|
2008-07-31 20:08:16 -07:00
|
|
|
e_mixer_system_get_channels(E_Mixer_System *self)
|
|
|
|
{
|
2008-10-22 04:49:33 -07:00
|
|
|
Eina_List *channels;
|
2008-07-31 20:08:16 -07:00
|
|
|
snd_mixer_elem_t *elem;
|
|
|
|
|
|
|
|
if (!self)
|
2010-03-10 13:54:23 -08:00
|
|
|
return NULL;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
channels = NULL;
|
|
|
|
|
|
|
|
elem = snd_mixer_first_elem(self);
|
2010-08-21 06:52:25 -07:00
|
|
|
for (; elem; elem = snd_mixer_elem_next(elem))
|
2010-03-10 13:54:23 -08:00
|
|
|
{
|
2011-07-15 12:26:57 -07:00
|
|
|
if ((!snd_mixer_selem_is_active(elem)) ||
|
2009-04-17 13:13:17 -07:00
|
|
|
(!snd_mixer_selem_has_playback_volume(elem)))
|
2011-07-15 12:26:57 -07:00
|
|
|
continue;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
2011-07-15 12:26:57 -07:00
|
|
|
channels = eina_list_append(channels, elem);
|
2010-03-10 13:54:23 -08:00
|
|
|
}
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
return channels;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-10-22 04:49:33 -07:00
|
|
|
e_mixer_system_free_channels(Eina_List *channels)
|
2008-07-31 20:08:16 -07:00
|
|
|
{
|
2008-10-22 04:49:33 -07:00
|
|
|
eina_list_free(channels);
|
2008-07-31 20:08:16 -07:00
|
|
|
}
|
|
|
|
|
2008-10-22 04:49:33 -07:00
|
|
|
Eina_List *
|
2008-07-31 20:08:16 -07:00
|
|
|
e_mixer_system_get_channels_names(E_Mixer_System *self)
|
|
|
|
{
|
2008-10-22 04:49:33 -07:00
|
|
|
Eina_List *channels;
|
2008-07-31 20:08:16 -07:00
|
|
|
snd_mixer_elem_t *elem;
|
|
|
|
snd_mixer_selem_id_t *sid;
|
|
|
|
|
|
|
|
if (!self)
|
2010-03-10 13:54:23 -08:00
|
|
|
return NULL;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
channels = NULL;
|
|
|
|
snd_mixer_selem_id_alloca(&sid);
|
|
|
|
|
|
|
|
elem = snd_mixer_first_elem(self);
|
2010-08-21 06:52:25 -07:00
|
|
|
for (; elem; elem = snd_mixer_elem_next(elem))
|
2010-03-10 13:54:23 -08:00
|
|
|
{
|
2011-07-15 12:26:57 -07:00
|
|
|
const char *name;
|
|
|
|
if ((!snd_mixer_selem_is_active(elem)) ||
|
2009-04-17 13:13:17 -07:00
|
|
|
(!snd_mixer_selem_has_playback_volume(elem)))
|
2011-07-15 12:26:57 -07:00
|
|
|
continue;
|
2009-04-17 13:13:17 -07:00
|
|
|
|
2011-07-15 12:26:57 -07:00
|
|
|
snd_mixer_selem_get_id(elem, sid);
|
|
|
|
name = snd_mixer_selem_id_get_name(sid);
|
|
|
|
if (name)
|
|
|
|
channels = eina_list_append(channels, eina_stringshare_add(name));
|
2010-03-10 13:54:23 -08:00
|
|
|
}
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
return channels;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-10-22 04:49:33 -07:00
|
|
|
e_mixer_system_free_channels_names(Eina_List *channels_names)
|
2008-07-31 20:08:16 -07:00
|
|
|
{
|
2009-03-11 08:13:42 -07:00
|
|
|
const char *channel;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
2009-03-11 08:13:42 -07:00
|
|
|
EINA_LIST_FREE(channels_names, channel)
|
2010-03-10 13:54:23 -08:00
|
|
|
eina_stringshare_del(channel);
|
2008-07-31 20:08:16 -07:00
|
|
|
}
|
|
|
|
|
2009-03-11 08:13:42 -07:00
|
|
|
const char *
|
2008-07-31 20:08:16 -07:00
|
|
|
e_mixer_system_get_default_channel_name(E_Mixer_System *self)
|
|
|
|
{
|
|
|
|
snd_mixer_elem_t *elem;
|
|
|
|
snd_mixer_selem_id_t *sid;
|
|
|
|
|
|
|
|
if (!self)
|
2010-03-10 13:54:23 -08:00
|
|
|
return NULL;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
snd_mixer_selem_id_alloca(&sid);
|
|
|
|
|
|
|
|
elem = snd_mixer_first_elem(self);
|
2010-08-21 06:52:25 -07:00
|
|
|
for (; elem; elem = snd_mixer_elem_next(elem))
|
2010-03-10 13:54:23 -08:00
|
|
|
{
|
2011-07-15 12:26:57 -07:00
|
|
|
const char *name;
|
|
|
|
if ((!snd_mixer_selem_is_active(elem)) ||
|
2009-04-17 13:13:17 -07:00
|
|
|
(!snd_mixer_selem_has_playback_volume(elem)))
|
2011-07-15 12:26:57 -07:00
|
|
|
continue;
|
2009-04-17 13:13:17 -07:00
|
|
|
|
2011-07-15 12:26:57 -07:00
|
|
|
snd_mixer_selem_get_id(elem, sid);
|
|
|
|
name = snd_mixer_selem_id_get_name(sid);
|
|
|
|
if (name)
|
|
|
|
return eina_stringshare_add(name);
|
2010-03-10 13:54:23 -08:00
|
|
|
}
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
E_Mixer_Channel *
|
2011-07-15 12:26:57 -07:00
|
|
|
e_mixer_system_get_channel_by_name(E_Mixer_System *self,
|
2012-08-24 06:57:22 -07:00
|
|
|
const char *name)
|
2008-07-31 20:08:16 -07:00
|
|
|
{
|
|
|
|
snd_mixer_elem_t *elem;
|
|
|
|
snd_mixer_selem_id_t *sid;
|
|
|
|
|
|
|
|
if ((!self) || (!name))
|
2010-03-10 13:54:23 -08:00
|
|
|
return NULL;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
snd_mixer_selem_id_alloca(&sid);
|
|
|
|
|
|
|
|
elem = snd_mixer_first_elem(self);
|
2010-08-21 06:52:25 -07:00
|
|
|
for (; elem; elem = snd_mixer_elem_next(elem))
|
2010-03-10 13:54:23 -08:00
|
|
|
{
|
2011-07-15 12:26:57 -07:00
|
|
|
const char *n;
|
|
|
|
if ((!snd_mixer_selem_is_active(elem)) ||
|
2009-04-17 13:13:17 -07:00
|
|
|
(!snd_mixer_selem_has_playback_volume(elem)))
|
2011-07-15 12:26:57 -07:00
|
|
|
continue;
|
2009-04-17 13:13:17 -07:00
|
|
|
|
2011-07-15 12:26:57 -07:00
|
|
|
snd_mixer_selem_get_id(elem, sid);
|
|
|
|
n = snd_mixer_selem_id_get_name(sid);
|
|
|
|
if (n && (strcmp(n, name) == 0))
|
|
|
|
return elem;
|
2010-03-10 13:54:23 -08:00
|
|
|
}
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-03-10 13:54:23 -08:00
|
|
|
e_mixer_system_channel_del(E_Mixer_Channel *channel __UNUSED__)
|
2008-07-31 20:08:16 -07:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2009-03-11 08:13:42 -07:00
|
|
|
const char *
|
2012-08-24 06:57:22 -07:00
|
|
|
e_mixer_system_get_channel_name(E_Mixer_System *self,
|
2011-07-15 12:26:57 -07:00
|
|
|
E_Mixer_Channel *channel)
|
2008-07-31 20:08:16 -07:00
|
|
|
{
|
|
|
|
snd_mixer_selem_id_t *sid;
|
2009-03-11 08:13:42 -07:00
|
|
|
const char *name;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
if ((!self) || (!channel))
|
2010-03-10 13:54:23 -08:00
|
|
|
return NULL;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
snd_mixer_selem_id_alloca(&sid);
|
|
|
|
snd_mixer_selem_get_id(channel, sid);
|
2009-03-11 08:13:42 -07:00
|
|
|
name = eina_stringshare_add(snd_mixer_selem_id_get_name(sid));
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-08-24 06:57:22 -07:00
|
|
|
e_mixer_system_get_volume(E_Mixer_System *self,
|
2011-07-15 12:26:57 -07:00
|
|
|
E_Mixer_Channel *channel,
|
2012-08-24 06:57:22 -07:00
|
|
|
int *left,
|
|
|
|
int *right)
|
2008-07-31 20:08:16 -07:00
|
|
|
{
|
|
|
|
long lvol, rvol, range, min, max;
|
|
|
|
|
|
|
|
if ((!self) || (!channel) || (!left) || (!right))
|
2010-03-10 13:54:23 -08:00
|
|
|
return 0;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
snd_mixer_handle_events(self);
|
|
|
|
snd_mixer_selem_get_playback_volume_range(channel, &min, &max);
|
|
|
|
range = max - min;
|
|
|
|
if (range < 1)
|
2010-03-10 13:54:23 -08:00
|
|
|
return 0;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
if (snd_mixer_selem_has_playback_channel(channel, 0))
|
2010-03-10 13:54:23 -08:00
|
|
|
snd_mixer_selem_get_playback_volume(channel, 0, &lvol);
|
2008-07-31 20:08:16 -07:00
|
|
|
else
|
2010-03-10 13:54:23 -08:00
|
|
|
lvol = min;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
if (snd_mixer_selem_has_playback_channel(channel, 1))
|
2010-03-10 13:54:23 -08:00
|
|
|
snd_mixer_selem_get_playback_volume(channel, 1, &rvol);
|
2008-07-31 20:08:16 -07:00
|
|
|
else
|
2010-03-10 13:54:23 -08:00
|
|
|
rvol = min;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
if (snd_mixer_selem_is_playback_mono(channel) ||
|
2010-03-10 13:54:23 -08:00
|
|
|
snd_mixer_selem_has_playback_volume_joined(channel))
|
|
|
|
rvol = lvol;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
*left = rint((double)(lvol - min) * 100 / (double)range);
|
|
|
|
*right = rint((double)(rvol - min) * 100 / (double)range);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-08-24 06:57:22 -07:00
|
|
|
e_mixer_system_set_volume(E_Mixer_System *self,
|
2011-07-15 12:26:57 -07:00
|
|
|
E_Mixer_Channel *channel,
|
2012-08-24 06:57:22 -07:00
|
|
|
int left,
|
|
|
|
int right)
|
2008-07-31 20:08:16 -07:00
|
|
|
{
|
2012-05-04 02:38:52 -07:00
|
|
|
long range, min, max, divide;
|
2008-07-31 20:08:16 -07:00
|
|
|
int mode;
|
|
|
|
|
|
|
|
if ((!self) || (!channel))
|
2010-03-10 13:54:23 -08:00
|
|
|
return 0;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
snd_mixer_handle_events(self);
|
|
|
|
snd_mixer_selem_get_playback_volume_range(channel, &min, &max);
|
2012-05-04 02:38:52 -07:00
|
|
|
divide = 100 + min;
|
|
|
|
if (divide == 0)
|
2010-03-10 13:54:23 -08:00
|
|
|
{
|
2012-05-04 02:38:52 -07:00
|
|
|
divide = 1; /* no zero-division */
|
2011-07-15 12:26:57 -07:00
|
|
|
min++;
|
2010-03-10 13:54:23 -08:00
|
|
|
}
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
range = max - min;
|
|
|
|
if (range < 1)
|
2010-03-10 13:54:23 -08:00
|
|
|
return 0;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
mode = 0;
|
|
|
|
if (left >= 0)
|
2010-03-10 13:54:23 -08:00
|
|
|
{
|
2012-05-04 02:38:52 -07:00
|
|
|
left = (((range * left) + (range / 2)) / divide) - min;
|
2011-07-15 12:26:57 -07:00
|
|
|
mode |= 1;
|
2010-03-10 13:54:23 -08:00
|
|
|
}
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
if (right >= 0)
|
2010-03-10 13:54:23 -08:00
|
|
|
{
|
2012-05-04 02:38:52 -07:00
|
|
|
right = (((range * right) + (range / 2)) / divide) - min;
|
2011-07-15 12:26:57 -07:00
|
|
|
mode |= 2;
|
2010-03-10 13:54:23 -08:00
|
|
|
}
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
if (mode & 1)
|
2010-03-10 13:54:23 -08:00
|
|
|
snd_mixer_selem_set_playback_volume(channel, 0, left);
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
if ((!snd_mixer_selem_is_playback_mono(channel)) &&
|
2010-03-10 13:54:23 -08:00
|
|
|
(!snd_mixer_selem_has_playback_volume_joined(channel)) &&
|
|
|
|
(mode & 2))
|
|
|
|
{
|
2011-07-15 12:26:57 -07:00
|
|
|
if (snd_mixer_selem_has_playback_channel(channel, 1))
|
|
|
|
snd_mixer_selem_set_playback_volume(channel, 1, right);
|
2010-03-10 13:54:23 -08:00
|
|
|
}
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-08-24 06:57:22 -07:00
|
|
|
e_mixer_system_can_mute(E_Mixer_System *self,
|
2011-07-15 12:26:57 -07:00
|
|
|
E_Mixer_Channel *channel)
|
2008-07-31 20:08:16 -07:00
|
|
|
{
|
|
|
|
if ((!self) || (!channel))
|
2010-03-10 13:54:23 -08:00
|
|
|
return 0;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
snd_mixer_handle_events(self);
|
2011-07-15 12:26:57 -07:00
|
|
|
return snd_mixer_selem_has_playback_switch(channel) ||
|
|
|
|
snd_mixer_selem_has_playback_switch_joined(channel);
|
2008-07-31 20:08:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-08-24 06:57:22 -07:00
|
|
|
e_mixer_system_get_mute(E_Mixer_System *self,
|
2011-07-15 12:26:57 -07:00
|
|
|
E_Mixer_Channel *channel,
|
2012-08-24 06:57:22 -07:00
|
|
|
int *mute)
|
2008-07-31 20:08:16 -07:00
|
|
|
{
|
|
|
|
if ((!self) || (!channel) || (!mute))
|
2010-03-10 13:54:23 -08:00
|
|
|
return 0;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
snd_mixer_handle_events(self);
|
|
|
|
if (snd_mixer_selem_has_playback_switch(channel) ||
|
2010-03-10 13:54:23 -08:00
|
|
|
snd_mixer_selem_has_playback_switch_joined(channel))
|
|
|
|
{
|
2011-07-15 12:26:57 -07:00
|
|
|
int m;
|
2010-03-10 13:54:23 -08:00
|
|
|
|
2011-07-15 12:26:57 -07:00
|
|
|
/* 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;
|
2010-03-10 13:54:23 -08:00
|
|
|
}
|
2008-07-31 20:08:16 -07:00
|
|
|
else
|
2010-03-10 13:54:23 -08:00
|
|
|
*mute = 0;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-08-24 06:57:22 -07:00
|
|
|
e_mixer_system_set_mute(E_Mixer_System *self,
|
2011-07-15 12:26:57 -07:00
|
|
|
E_Mixer_Channel *channel,
|
2012-08-24 06:57:22 -07:00
|
|
|
int mute)
|
2008-07-31 20:08:16 -07:00
|
|
|
{
|
|
|
|
if ((!self) || (!channel))
|
2010-03-10 13:54:23 -08:00
|
|
|
return 0;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
snd_mixer_handle_events(self);
|
|
|
|
if (snd_mixer_selem_has_playback_switch(channel) ||
|
2010-03-10 13:54:23 -08:00
|
|
|
snd_mixer_selem_has_playback_switch_joined(channel))
|
|
|
|
return snd_mixer_selem_set_playback_switch_all(channel, !mute);
|
2008-07-31 20:08:16 -07:00
|
|
|
else
|
2010-03-10 13:54:23 -08:00
|
|
|
return 0;
|
2008-07-31 20:08:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2012-08-24 06:57:22 -07:00
|
|
|
e_mixer_system_get_state(E_Mixer_System *self,
|
|
|
|
E_Mixer_Channel *channel,
|
2011-07-15 12:26:57 -07:00
|
|
|
E_Mixer_Channel_State *state)
|
2008-07-31 20:08:16 -07:00
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (!state)
|
2010-03-10 13:54:23 -08:00
|
|
|
return 0;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
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
|
2012-08-24 06:57:22 -07:00
|
|
|
e_mixer_system_set_state(E_Mixer_System *self,
|
|
|
|
E_Mixer_Channel *channel,
|
2011-07-15 12:26:57 -07:00
|
|
|
const E_Mixer_Channel_State *state)
|
2008-07-31 20:08:16 -07:00
|
|
|
{
|
|
|
|
int r;
|
|
|
|
|
|
|
|
if (!state)
|
2010-03-10 13:54:23 -08:00
|
|
|
return 0;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
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
|
2012-08-24 06:57:22 -07:00
|
|
|
e_mixer_system_has_capture(E_Mixer_System *self,
|
2011-07-15 12:26:57 -07:00
|
|
|
E_Mixer_Channel *channel)
|
2008-07-31 20:08:16 -07:00
|
|
|
{
|
|
|
|
if ((!self) || (!channel))
|
2010-03-10 13:54:23 -08:00
|
|
|
return 0;
|
2008-07-31 20:08:16 -07:00
|
|
|
|
|
|
|
return snd_mixer_selem_has_capture_switch(channel);
|
|
|
|
}
|
2011-07-15 12:26:57 -07:00
|
|
|
|