1 #include <alsa/asoundlib.h>
3 #include "e_mod_system.h"
6 struct e_mixer_callback_desc
8 int (*func)(void *data,
16 static int _mixer_callback_add(E_Mixer_System *self,
17 int (*func)(void *data, E_Mixer_System *self),
19 static int _mixer_callback_del(E_Mixer_System *self,
20 struct e_mixer_callback_desc *desc);
23 _cb_dispatch(void *data)
25 struct e_mixer_callback_desc *desc;
29 snd_mixer_handle_events(desc->self);
30 r = desc->func(desc->data, desc->self);
34 _mixer_callback_del(desc->self, desc); /* desc is invalid then. */
36 return ECORE_CALLBACK_CANCEL;
40 _cb_fd_handler(void *data,
41 Ecore_Fd_Handler *fd_handler)
43 struct e_mixer_callback_desc *desc;
47 if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR))
49 desc->handlers = eina_list_remove(desc->handlers, fd_handler);
60 _mixer_callback_del(s, desc);
61 _mixer_callback_add(s, f, d);
63 return ECORE_CALLBACK_CANCEL;
67 desc->idler = ecore_idler_add(_cb_dispatch, desc);
68 return ECORE_CALLBACK_RENEW;
72 _mixer_callback_add(E_Mixer_System *self,
73 int (*func)(void *data, E_Mixer_System *self),
76 struct e_mixer_callback_desc *desc;
80 len = snd_mixer_poll_descriptors_count(self);
84 desc = malloc(sizeof(struct e_mixer_callback_desc));
92 desc->handlers = NULL;
94 pfds = alloca(len * sizeof(struct pollfd));
95 len = snd_mixer_poll_descriptors(self, pfds, len);
104 Ecore_Fd_Handler *fd_handler;
107 fd_handler = ecore_main_fd_handler_add(
108 pfds[len].fd, ECORE_FD_READ, _cb_fd_handler, desc, NULL, NULL);
109 desc->handlers = eina_list_prepend(desc->handlers, fd_handler);
112 snd_mixer_set_callback_private(self, desc);
118 _mixer_callback_del(E_Mixer_System *self,
119 struct e_mixer_callback_desc *desc)
121 Ecore_Fd_Handler *handler;
123 EINA_LIST_FREE(desc->handlers, handler)
124 ecore_main_fd_handler_del(handler);
126 snd_mixer_set_callback_private(self, NULL);
134 _mixer_callback_replace(E_Mixer_System *self __UNUSED__,
135 struct e_mixer_callback_desc *desc,
136 int (*func)(void *data, E_Mixer_System *self),
146 e_mixer_system_new(const char *name)
154 err = snd_mixer_open(&handle, 0);
158 err = snd_mixer_attach(handle, name);
162 err = snd_mixer_selem_register(handle, NULL, NULL);
166 err = snd_mixer_load(handle);
173 snd_mixer_close(handle);
175 fprintf(stderr, "MIXER: Cannot get hardware info: %s\n", snd_strerror(err));
180 e_mixer_system_del(E_Mixer_System *self)
182 struct e_mixer_callback_desc *desc;
187 desc = snd_mixer_get_callback_private(self);
189 _mixer_callback_del(self, desc);
191 snd_mixer_close(self);
195 e_mixer_system_callback_set(E_Mixer_System *self,
196 int (*func)(void *data, E_Mixer_System *self),
199 struct e_mixer_callback_desc *desc;
204 desc = snd_mixer_get_callback_private(self);
208 return _mixer_callback_add(self, func, data);
214 return _mixer_callback_replace(self, desc, func, data);
216 return _mixer_callback_del(self, desc);
221 e_mixer_system_get_cards(void)
228 while (((err = snd_card_next(&card_num)) == 0) && (card_num >= 0))
233 snprintf(buf, sizeof(buf), "hw:%d", card_num);
235 if (snd_ctl_open(&control, buf, 0) < 0)
237 snd_ctl_close(control);
238 cards = eina_list_append(cards, eina_stringshare_add(buf));
242 fprintf(stderr, "MIXER: Cannot get available card number: %s\n",
249 e_mixer_system_free_cards(Eina_List *cards)
253 EINA_LIST_FREE(cards, card)
254 eina_stringshare_del(card);
258 e_mixer_system_get_default_card(void)
260 static const char buf[] = "hw:0";
263 if (snd_ctl_open(&control, buf, 0) < 0)
265 snd_ctl_close(control);
266 return eina_stringshare_add(buf);
270 e_mixer_system_get_card_name(const char *card)
272 snd_ctl_card_info_t *hw_info;
280 snd_ctl_card_info_alloca(&hw_info);
282 err = snd_ctl_open(&control, card, 0);
286 err = snd_ctl_card_info(control, hw_info);
289 fprintf(stderr, "MIXER: Cannot get hardware info: %s: %s\n", card,
291 snd_ctl_close(control);
295 snd_ctl_close(control);
296 name = snd_ctl_card_info_get_name(hw_info);
299 fprintf(stderr, "MIXER: Cannot get hardware name: %s\n", card);
303 return eina_stringshare_add(name);
307 e_mixer_system_get_channels(E_Mixer_System *self)
310 snd_mixer_elem_t *elem;
317 elem = snd_mixer_first_elem(self);
318 for (; elem; elem = snd_mixer_elem_next(elem))
320 if ((!snd_mixer_selem_is_active(elem)) ||
321 (!snd_mixer_selem_has_playback_volume(elem)))
324 channels = eina_list_append(channels, elem);
331 e_mixer_system_free_channels(Eina_List *channels)
333 eina_list_free(channels);
337 e_mixer_system_get_channels_names(E_Mixer_System *self)
340 snd_mixer_elem_t *elem;
341 snd_mixer_selem_id_t *sid;
347 snd_mixer_selem_id_alloca(&sid);
349 elem = snd_mixer_first_elem(self);
350 for (; elem; elem = snd_mixer_elem_next(elem))
353 if ((!snd_mixer_selem_is_active(elem)) ||
354 (!snd_mixer_selem_has_playback_volume(elem)))
357 snd_mixer_selem_get_id(elem, sid);
358 name = snd_mixer_selem_id_get_name(sid);
360 channels = eina_list_append(channels, eina_stringshare_add(name));
367 e_mixer_system_free_channels_names(Eina_List *channels_names)
371 EINA_LIST_FREE(channels_names, channel)
372 eina_stringshare_del(channel);
376 e_mixer_system_get_default_channel_name(E_Mixer_System *self)
378 snd_mixer_elem_t *elem;
379 snd_mixer_selem_id_t *sid;
384 snd_mixer_selem_id_alloca(&sid);
386 elem = snd_mixer_first_elem(self);
387 for (; elem; elem = snd_mixer_elem_next(elem))
390 if ((!snd_mixer_selem_is_active(elem)) ||
391 (!snd_mixer_selem_has_playback_volume(elem)))
394 snd_mixer_selem_get_id(elem, sid);
395 name = snd_mixer_selem_id_get_name(sid);
397 return eina_stringshare_add(name);
404 e_mixer_system_get_channel_by_name(E_Mixer_System *self,
407 snd_mixer_elem_t *elem;
408 snd_mixer_selem_id_t *sid;
410 if ((!self) || (!name))
413 snd_mixer_selem_id_alloca(&sid);
415 elem = snd_mixer_first_elem(self);
416 for (; elem; elem = snd_mixer_elem_next(elem))
419 if ((!snd_mixer_selem_is_active(elem)) ||
420 (!snd_mixer_selem_has_playback_volume(elem)))
423 snd_mixer_selem_get_id(elem, sid);
424 n = snd_mixer_selem_id_get_name(sid);
425 if (n && (strcmp(n, name) == 0))
433 e_mixer_system_channel_del(E_Mixer_Channel *channel __UNUSED__)
438 e_mixer_system_get_channel_name(E_Mixer_System *self,
439 E_Mixer_Channel *channel)
441 snd_mixer_selem_id_t *sid;
444 if ((!self) || (!channel))
447 snd_mixer_selem_id_alloca(&sid);
448 snd_mixer_selem_get_id(channel, sid);
449 name = eina_stringshare_add(snd_mixer_selem_id_get_name(sid));
455 e_mixer_system_get_volume(E_Mixer_System *self,
456 E_Mixer_Channel *channel,
460 long lvol, rvol, range, min, max;
462 if ((!self) || (!channel) || (!left) || (!right))
465 snd_mixer_handle_events(self);
466 snd_mixer_selem_get_playback_volume_range(channel, &min, &max);
471 if (snd_mixer_selem_has_playback_channel(channel, 0))
472 snd_mixer_selem_get_playback_volume(channel, 0, &lvol);
476 if (snd_mixer_selem_has_playback_channel(channel, 1))
477 snd_mixer_selem_get_playback_volume(channel, 1, &rvol);
481 if (snd_mixer_selem_is_playback_mono(channel) ||
482 snd_mixer_selem_has_playback_volume_joined(channel))
485 *left = rint((double)(lvol - min) * 100 / (double)range);
486 *right = rint((double)(rvol - min) * 100 / (double)range);
492 e_mixer_system_set_volume(E_Mixer_System *self,
493 E_Mixer_Channel *channel,
497 long range, min, max, div;
500 if ((!self) || (!channel))
503 snd_mixer_handle_events(self);
504 snd_mixer_selem_get_playback_volume_range(channel, &min, &max);
508 div = 1; /* no zero-division */
519 left = (((range * left) + (range / 2)) / div) - min;
525 right = (((range * right) + (range / 2)) / div) - min;
530 snd_mixer_selem_set_playback_volume(channel, 0, left);
532 if ((!snd_mixer_selem_is_playback_mono(channel)) &&
533 (!snd_mixer_selem_has_playback_volume_joined(channel)) &&
536 if (snd_mixer_selem_has_playback_channel(channel, 1))
537 snd_mixer_selem_set_playback_volume(channel, 1, right);
544 e_mixer_system_can_mute(E_Mixer_System *self,
545 E_Mixer_Channel *channel)
547 if ((!self) || (!channel))
550 snd_mixer_handle_events(self);
551 return snd_mixer_selem_has_playback_switch(channel) ||
552 snd_mixer_selem_has_playback_switch_joined(channel);
556 e_mixer_system_get_mute(E_Mixer_System *self,
557 E_Mixer_Channel *channel,
560 if ((!self) || (!channel) || (!mute))
563 snd_mixer_handle_events(self);
564 if (snd_mixer_selem_has_playback_switch(channel) ||
565 snd_mixer_selem_has_playback_switch_joined(channel))
569 /* XXX: not checking for return, always returns 0 even if it worked.
570 * alsamixer also don't check it. Bug?
572 snd_mixer_selem_get_playback_switch(channel, 0, &m);
582 e_mixer_system_set_mute(E_Mixer_System *self,
583 E_Mixer_Channel *channel,
586 if ((!self) || (!channel))
589 snd_mixer_handle_events(self);
590 if (snd_mixer_selem_has_playback_switch(channel) ||
591 snd_mixer_selem_has_playback_switch_joined(channel))
592 return snd_mixer_selem_set_playback_switch_all(channel, !mute);
598 e_mixer_system_get_state(E_Mixer_System *self,
599 E_Mixer_Channel *channel,
600 E_Mixer_Channel_State *state)
607 r = e_mixer_system_get_mute(self, channel, &state->mute);
608 r &= e_mixer_system_get_volume(self, channel, &state->left, &state->right);
613 e_mixer_system_set_state(E_Mixer_System *self,
614 E_Mixer_Channel *channel,
615 const E_Mixer_Channel_State *state)
622 r = e_mixer_system_set_mute(self, channel, state->mute);
623 r &= e_mixer_system_set_volume(self, channel, state->left, state->right);
628 e_mixer_system_has_capture(E_Mixer_System *self,
629 E_Mixer_Channel *channel)
631 if ((!self) || (!channel))
634 return snd_mixer_selem_has_capture_switch(channel);