Last active
June 25, 2022 11:16
-
-
Save takaswie/8378fe3bc04652d83428694cd7573bc0 to your computer and use it in GitHub Desktop.
Assertion test at mixer class implementation for removal event
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <alsa/asoundlib.h> | |
#include <sys/epoll.h> | |
#include <stdbool.h> | |
static bool unsafe; | |
// (alsa-lib:src/mixer/mixer.c) | |
// snd_mixer_handle_events() | |
// (alsa-lib:src/control/hcontrol.c) | |
// ->snd_hctl_handle_events() | |
// ->snd_hctl_handle_event() | |
// ->snd_hctl_elem_remove() | |
// ->snd_hctl_elem_throw_event(REMOVE) | |
// ->snd_hctl_elem_add() | |
// ->snd_hctl_elem_throw_event(ADD) | |
// ->snd_hctl_elem_throw_event(VALUE | INFO) | |
// ->snd_hctl_elem_t.callback() | |
// (alsa-lib:src/mixer/mixer.c) | |
// = hctl_elem_event_handler() (src/mixer/mixer.c) | |
// assert(bag_emptry(bag)) | |
static int mixer_class_event(snd_mixer_class_t *class, unsigned int mask, snd_hctl_elem_t *helem, | |
snd_mixer_elem_t *melem) | |
{ | |
printf("Event:\n"); | |
if (mask == SND_CTL_EVENT_MASK_REMOVE) { | |
printf(" remove\n"); | |
if (!unsafe) | |
snd_mixer_elem_detach(melem, helem); | |
} else { | |
switch (mask) { | |
case SND_CTL_EVENT_MASK_ADD: | |
{ | |
snd_mixer_elem_t *melem; | |
int err; | |
printf(" add\n"); | |
printf(" %s, %d\n", snd_hctl_elem_get_name(helem), snd_hctl_elem_get_index(helem)); | |
err = snd_mixer_elem_new(&melem, SND_MIXER_ELEM_SIMPLE + 1, 0, helem, NULL); | |
if (err < 0) { | |
printf("snd_mixer_elem_new(): %s\n", strerror(-err)); | |
return 0; | |
} | |
err = snd_mixer_elem_attach(melem, helem); | |
if (err < 0) { | |
printf("snd_mixer_elem_attach(): %s\n", strerror(-err)); | |
return 0; | |
} | |
err = snd_mixer_elem_add(melem, class); | |
if (err < 0) { | |
printf("snd_mixer_elem_add(): %s\n", strerror(-err)); | |
return 0; | |
} | |
break; | |
} | |
case SND_CTL_EVENT_MASK_VALUE: | |
printf(" value\n"); | |
break; | |
case SND_CTL_EVENT_MASK_INFO: | |
printf(" info\n"); | |
break; | |
case SND_CTL_EVENT_MASK_TLV: | |
printf(" tlv\n"); | |
break; | |
default: | |
break; | |
} | |
} | |
return 0; | |
} | |
static int mixer_class_compare(const snd_mixer_elem_t *c1, const snd_mixer_elem_t *c2) | |
{ | |
// Momentary logic. | |
return c1 == c2 ? 0 : (c1 > c2 ? 1 : -1); | |
} | |
static int register_mixer_class(snd_mixer_t *handle) | |
{ | |
snd_mixer_class_t *class; | |
int err; | |
if (snd_mixer_class_malloc(&class)) { | |
printf("snd_mixer_class_malloc(): %s\n", strerror(ENOMEM)); | |
return -ENOMEM; | |
} | |
snd_mixer_class_set_event(class, mixer_class_event); | |
snd_mixer_class_set_compare(class, mixer_class_compare); | |
err = snd_mixer_class_register(class, handle); | |
if (err < 0) { | |
printf("snd_mixer_class_register(): %s\n", strerror(-err)); | |
// TODO: free. | |
return err; | |
} | |
return 0; | |
} | |
static void dispatch_event(snd_mixer_t *handle, int epfd) | |
{ | |
struct epoll_event events[10]; | |
while (1) { | |
int result; | |
result = epoll_wait(epfd, events, 10, 100); | |
if (result < 0) { | |
printf("epoll_wait(): %s\n", strerror(errno)); | |
break; | |
} else if (result > 0) { | |
int err; | |
printf("events: %d\n", result); | |
err = snd_mixer_handle_events(handle); | |
if (err < 0) | |
printf("snd_mixer_handle_events(): %s\n", strerror(-err)); | |
} | |
} | |
} | |
static void run_dispatcher(snd_mixer_t *handle) | |
{ | |
int epfd; | |
unsigned int count; | |
struct pollfd *pfds; | |
int i; | |
int err; | |
epfd = epoll_create(1); | |
if (epfd < 0) { | |
printf("epoll_create(): %s\n", strerror(errno)); | |
return; | |
} | |
count = snd_mixer_poll_descriptors_count(handle); | |
pfds = calloc(count, sizeof(*pfds)); | |
if (pfds == NULL) { | |
printf("calloc(): %s\n", strerror(ENOMEM)); | |
goto err_epfd; | |
} | |
err = snd_mixer_poll_descriptors(handle, pfds, count); | |
if (err < 0) { | |
printf("snd_mixer_poll_descriptors(): %s\n", strerror(-err)); | |
goto err_pfds; | |
} | |
for (i = 0; i < count; ++i) { | |
struct epoll_event ev = { | |
.data.fd = pfds[i].fd, | |
.events = pfds[i].events, | |
}; | |
if (epoll_ctl(epfd, EPOLL_CTL_ADD, pfds[i].fd, &ev) < 0) { | |
printf("epoll_ctl(EPOLL_CTL_ADD): %s\n", strerror(errno)); | |
goto err_pfds; | |
} | |
} | |
dispatch_event(handle, epfd); | |
for (i = 0; i < count; ++i) { | |
if (epoll_ctl(epfd, EPOLL_CTL_DEL, pfds[i].fd, NULL) < 0) | |
printf("epoll_ctl(EPOLL_CTL_DEL): %s\n", strerror(errno)); | |
} | |
err_pfds: | |
free(pfds); | |
err_epfd: | |
close(epfd); | |
} | |
int main(int argc, const char **argv) | |
{ | |
snd_mixer_t *handle; | |
int err; | |
unsafe = argc > 1; | |
err = snd_mixer_open(&handle, 0); | |
if (err < 0) { | |
printf("snd_mixer_open(): %s\n", strerror(-err)); | |
return EXIT_FAILURE; | |
} | |
err = snd_mixer_attach(handle, "hw:0"); | |
if (err < 0) { | |
printf("snd_mixer_attach(): %s\n", strerror(-err)); | |
goto err_handle; | |
} | |
err = register_mixer_class(handle); | |
if (err < 0) | |
goto err_attach; | |
err = snd_mixer_selem_register(handle, NULL, NULL); | |
if (err < 0) { | |
printf("snd_mixer_selem_register(): %s\n", strerror(-err)); | |
goto err_attach; | |
} | |
err = snd_mixer_load(handle); | |
if (err < 0) { | |
printf("snd_mixer_load(): %s\n", strerror(-err)); | |
goto err_attach; | |
} | |
run_dispatcher(handle); | |
snd_mixer_free(handle); | |
err_attach: | |
snd_mixer_detach(handle, "hw:0"); | |
err_handle: | |
snd_mixer_close(handle); | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment