1 #include <alsa/asoundlib.h>
3 #include "e_mod_system.h"
6 struct e_mixer_callback_desc
8 int (*func)(void *data, E_Mixer_System *self);
16 static int _mixer_callback_add(E_Mixer_System *self, int (*func)(void *data, E_Mixer_System *self), void *data);
17 static int _mixer_callback_del(E_Mixer_System *self, struct e_mixer_callback_desc *desc);
21 _cb_dispatch(void *data)
23 struct e_mixer_callback_desc *desc;
27 snd_mixer_handle_events(desc->self);
28 r = desc->func(desc->data, desc->self);
32 _mixer_callback_del(desc->self, desc); /* desc is invalid then. */
34 return ECORE_CALLBACK_CANCEL;
38 _cb_fd_handler(void *data, Ecore_Fd_Handler *fd_handler)
40 struct e_mixer_callback_desc *desc;
44 if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR))
46 desc->handlers = eina_list_remove(desc->handlers, fd_handler);
50 int (*f)(void *, E_Mixer_System *);
56 _mixer_callback_del(s, desc);
57 _mixer_callback_add(s, f, d);
59 return ECORE_CALLBACK_CANCEL;
63 desc->idler = ecore_idler_add(_cb_dispatch, desc);
64 return ECORE_CALLBACK_RENEW;
68 _mixer_callback_add(E_Mixer_System *self, int (*func)(void *data, E_Mixer_System *self), void *data)
70 struct e_mixer_callback_desc *desc;
74 len = snd_mixer_poll_descriptors_count(self);
78 desc = malloc(sizeof(struct e_mixer_callback_desc));
86 desc->handlers = NULL;
88 pfds = alloca(len * sizeof(struct pollfd));
89 len = snd_mixer_poll_descriptors(self, pfds, len);
98 Ecore_Fd_Handler *fd_handler;
101 fd_handler = ecore_main_fd_handler_add(
102 pfds[len].fd, ECORE_FD_READ, _cb_fd_handler, desc, NULL, NULL);
103 desc->handlers = eina_list_prepend(desc->handlers, fd_handler);
106 snd_mixer_set_callback_private(self, desc);
112 _mixer_callback_del(E_Mixer_System *self, struct e_mixer_callback_desc *desc)
114 Ecore_Fd_Handler *handler;
116 EINA_LIST_FREE(desc->handlers, handler)
117 ecore_main_fd_handler_del(handler);
119 snd_mixer_set_callback_private(self, NULL);
127 _mixer_callback_replace(E_Mixer_System *self __UNUSED__, struct e_mixer_callback_desc *desc, int (*func)(void *data, E_Mixer_System *self), void *data)
136 e_mixer_system_new(const char *name)
144 err = snd_mixer_open(&handle, 0);
148 err = snd_mixer_attach(handle, name);
152 err = snd_mixer_selem_register(handle, NULL, NULL);
156 err = snd_mixer_load(handle);
163 snd_mixer_close(handle);
165 fprintf(stderr, "MIXER: Cannot get hardware info: %s\n", snd_strerror(err));
170 e_mixer_system_del(E_Mixer_System *self)
172 struct e_mixer_callback_desc *desc;
177 desc = snd_mixer_get_callback_private(self);
179 _mixer_callback_del(self, desc);
181 snd_mixer_close(self);
185 e_mixer_system_callback_set(E_Mixer_System *self, int (*func)(void *data, E_Mixer_System *self), void *data)
187 struct e_mixer_callback_desc *desc;
192 desc = snd_mixer_get_callback_private(self);
196 return _mixer_callback_add(self, func, data);
202 return _mixer_callback_replace(self, desc, func, data);
204 return _mixer_callback_del(self, desc);
209 e_mixer_system_get_cards(void)
216 while (((err = snd_card_next(&card_num)) == 0) && (card_num >= 0))
221 snprintf(buf, sizeof(buf), "hw:%d", card_num);
223 if (snd_ctl_open(&control, buf, 0) < 0)
225 snd_ctl_close(control);
226 cards = eina_list_append(cards, eina_stringshare_add(buf));
230 fprintf(stderr, "MIXER: Cannot get available card number: %s\n",
237 e_mixer_system_free_cards(Eina_List *cards)
241 EINA_LIST_FREE(cards, card)
242 eina_stringshare_del(card);
246 e_mixer_system_get_default_card(void)
248 static const char buf[] = "hw:0";
251 if (snd_ctl_open(&control, buf, 0) < 0)
253 snd_ctl_close(control);
254 return eina_stringshare_add(buf);
258 e_mixer_system_get_card_name(const char *card)
260 snd_ctl_card_info_t *hw_info;
268 snd_ctl_card_info_alloca(&hw_info);
270 err = snd_ctl_open(&control, card, 0);
274 err = snd_ctl_card_info(control, hw_info);
277 fprintf(stderr, "MIXER: Cannot get hardware info: %s: %s\n", card,
279 snd_ctl_close(control);
283 snd_ctl_close(control);
284 name = snd_ctl_card_info_get_name(hw_info);
287 fprintf(stderr, "MIXER: Cannot get hardware name: %s\n", card);
291 return eina_stringshare_add(name);
295 e_mixer_system_get_channels(E_Mixer_System *self)
298 snd_mixer_elem_t *elem;
305 elem = snd_mixer_first_elem(self);
306 for (; elem; elem = snd_mixer_elem_next(elem))
308 if ((!snd_mixer_selem_is_active(elem)) ||
309 (!snd_mixer_selem_has_playback_volume(elem)))
312 channels = eina_list_append(channels, elem);
319 e_mixer_system_free_channels(Eina_List *channels)
321 eina_list_free(channels);
325 e_mixer_system_get_channels_names(E_Mixer_System *self)
328 snd_mixer_elem_t *elem;
329 snd_mixer_selem_id_t *sid;
335 snd_mixer_selem_id_alloca(&sid);
337 elem = snd_mixer_first_elem(self);
338 for (; elem; elem = snd_mixer_elem_next(elem))
341 if ((!snd_mixer_selem_is_active(elem)) ||
342 (!snd_mixer_selem_has_playback_volume(elem)))
345 snd_mixer_selem_get_id(elem, sid);
346 name = snd_mixer_selem_id_get_name(sid);
348 channels = eina_list_append(channels, eina_stringshare_add(name));
355 e_mixer_system_free_channels_names(Eina_List *channels_names)
359 EINA_LIST_FREE(channels_names, channel)
360 eina_stringshare_del(channel);
364 e_mixer_system_get_default_channel_name(E_Mixer_System *self)
366 snd_mixer_elem_t *elem;
367 snd_mixer_selem_id_t *sid;
372 snd_mixer_selem_id_alloca(&sid);
374 elem = snd_mixer_first_elem(self);
375 for (; elem; elem = snd_mixer_elem_next(elem))
378 if ((!snd_mixer_selem_is_active(elem)) ||
379 (!snd_mixer_selem_has_playback_volume(elem)))
382 snd_mixer_selem_get_id(elem, sid);
383 name = snd_mixer_selem_id_get_name(sid);
385 return eina_stringshare_add(name);
392 e_mixer_system_get_channel_by_name(E_Mixer_System *self, const char *name)
394 snd_mixer_elem_t *elem;
395 snd_mixer_selem_id_t *sid;
397 if ((!self) || (!name))
400 snd_mixer_selem_id_alloca(&sid);
402 elem = snd_mixer_first_elem(self);
403 for (; elem; elem = snd_mixer_elem_next(elem))
406 if ((!snd_mixer_selem_is_active(elem)) ||
407 (!snd_mixer_selem_has_playback_volume(elem)))
410 snd_mixer_selem_get_id(elem, sid);
411 n = snd_mixer_selem_id_get_name(sid);
412 if (n && (strcmp(n, name) == 0))
420 e_mixer_system_channel_del(E_Mixer_Channel *channel __UNUSED__)
425 e_mixer_system_get_channel_name(E_Mixer_System *self, E_Mixer_Channel *channel)
427 snd_mixer_selem_id_t *sid;
430 if ((!self) || (!channel))
433 snd_mixer_selem_id_alloca(&sid);
434 snd_mixer_selem_get_id(channel, sid);
435 name = eina_stringshare_add(snd_mixer_selem_id_get_name(sid));
441 e_mixer_system_get_volume(E_Mixer_System *self, E_Mixer_Channel *channel, int *left, int *right)
443 long lvol, rvol, range, min, max;
445 if ((!self) || (!channel) || (!left) || (!right))
448 snd_mixer_handle_events(self);
449 snd_mixer_selem_get_playback_volume_range(channel, &min, &max);
454 if (snd_mixer_selem_has_playback_channel(channel, 0))
455 snd_mixer_selem_get_playback_volume(channel, 0, &lvol);
459 if (snd_mixer_selem_has_playback_channel(channel, 1))
460 snd_mixer_selem_get_playback_volume(channel, 1, &rvol);
464 if (snd_mixer_selem_is_playback_mono(channel) ||
465 snd_mixer_selem_has_playback_volume_joined(channel))
468 *left = rint((double)(lvol - min) * 100 / (double)range);
469 *right = rint((double)(rvol - min) * 100 / (double)range);
475 e_mixer_system_set_volume(E_Mixer_System *self, E_Mixer_Channel *channel, int left, int right)
477 long range, min, max, div;
480 if ((!self) || (!channel))
483 snd_mixer_handle_events(self);
484 snd_mixer_selem_get_playback_volume_range(channel, &min, &max);
488 div = 1; /* no zero-division */
499 left = (((range * left) + (range / 2)) / div) - min;
505 right = (((range * right) + (range / 2)) / div) - min;
510 snd_mixer_selem_set_playback_volume(channel, 0, left);
512 if ((!snd_mixer_selem_is_playback_mono(channel)) &&
513 (!snd_mixer_selem_has_playback_volume_joined(channel)) &&
516 if (snd_mixer_selem_has_playback_channel(channel, 1))
517 snd_mixer_selem_set_playback_volume(channel, 1, right);
524 e_mixer_system_can_mute(E_Mixer_System *self, E_Mixer_Channel *channel)
526 if ((!self) || (!channel))
529 snd_mixer_handle_events(self);
530 return (snd_mixer_selem_has_playback_switch(channel) ||
531 snd_mixer_selem_has_playback_switch_joined(channel));
535 e_mixer_system_get_mute(E_Mixer_System *self, E_Mixer_Channel *channel, int *mute)
537 if ((!self) || (!channel) || (!mute))
540 snd_mixer_handle_events(self);
541 if (snd_mixer_selem_has_playback_switch(channel) ||
542 snd_mixer_selem_has_playback_switch_joined(channel))
546 /* XXX: not checking for return, always returns 0 even if it worked.
547 * alsamixer also don't check it. Bug?
549 snd_mixer_selem_get_playback_switch(channel, 0, &m);
559 e_mixer_system_set_mute(E_Mixer_System *self, E_Mixer_Channel *channel, int mute)
561 if ((!self) || (!channel))
564 snd_mixer_handle_events(self);
565 if (snd_mixer_selem_has_playback_switch(channel) ||
566 snd_mixer_selem_has_playback_switch_joined(channel))
567 return snd_mixer_selem_set_playback_switch_all(channel, !mute);
573 e_mixer_system_get_state(E_Mixer_System *self, E_Mixer_Channel *channel, E_Mixer_Channel_State *state)
580 r = e_mixer_system_get_mute(self, channel, &state->mute);
581 r &= e_mixer_system_get_volume(self, channel, &state->left, &state->right);
586 e_mixer_system_set_state(E_Mixer_System *self, E_Mixer_Channel *channel, const E_Mixer_Channel_State *state)
593 r = e_mixer_system_set_mute(self, channel, state->mute);
594 r &= e_mixer_system_set_volume(self, channel, state->left, state->right);
599 e_mixer_system_has_capture(E_Mixer_System *self, E_Mixer_Channel *channel)
601 if ((!self) || (!channel))
604 return snd_mixer_selem_has_capture_switch(channel);