mirror of
https://codeberg.org/dnkl/yambar.git
synced 2025-04-23 20:35:42 +02:00
module/alsa: monitors volume and muted state of selected card/mixer
This commit is contained in:
parent
cba97a0e65
commit
0d8704737e
4 changed files with 181 additions and 0 deletions
|
@ -22,6 +22,7 @@ pkg_check_modules(XCB_XKB REQUIRED xcb-xkb) # Module/xkb
|
||||||
pkg_check_modules(JSON REQUIRED json-c) # Module/i3
|
pkg_check_modules(JSON REQUIRED json-c) # Module/i3
|
||||||
pkg_check_modules(UDEV REQUIRED libudev) # Module/battery
|
pkg_check_modules(UDEV REQUIRED libudev) # Module/battery
|
||||||
pkg_check_modules(MPD REQUIRED libmpdclient) # Module/mpd
|
pkg_check_modules(MPD REQUIRED libmpdclient) # Module/mpd
|
||||||
|
pkg_check_modules(ALSA REQUIRED alsa) # Module/alsa
|
||||||
|
|
||||||
add_executable(f00bar
|
add_executable(f00bar
|
||||||
bar.c bar.h
|
bar.c bar.h
|
||||||
|
@ -48,6 +49,7 @@ add_executable(f00bar
|
||||||
particles/ramp.c particles/ramp.h
|
particles/ramp.c particles/ramp.h
|
||||||
particles/string.c particles/string.h
|
particles/string.c particles/string.h
|
||||||
|
|
||||||
|
modules/alsa.c modules/alsa.h
|
||||||
modules/backlight.c modules/backlight.h
|
modules/backlight.c modules/backlight.h
|
||||||
modules/battery.c modules/battery.h
|
modules/battery.c modules/battery.h
|
||||||
modules/clock.c modules/clock.h
|
modules/clock.c modules/clock.h
|
||||||
|
@ -70,6 +72,7 @@ target_compile_options(f00bar PRIVATE
|
||||||
${JSON_CFLAGS_OTHER}
|
${JSON_CFLAGS_OTHER}
|
||||||
${UDEV_CFLAGS_OTHER}
|
${UDEV_CFLAGS_OTHER}
|
||||||
${MPD_CFLAGS_OTHER}
|
${MPD_CFLAGS_OTHER}
|
||||||
|
${ALSA_CFLAGS_OTHER}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(f00bar PRIVATE
|
target_include_directories(f00bar PRIVATE
|
||||||
|
@ -80,6 +83,7 @@ target_include_directories(f00bar PRIVATE
|
||||||
${JSON_INCLUDE_DIRS}
|
${JSON_INCLUDE_DIRS}
|
||||||
${UDEV_INCLUDE_DIRS}
|
${UDEV_INCLUDE_DIRS}
|
||||||
${MPD_INCLUDE_DIRS}
|
${MPD_INCLUDE_DIRS}
|
||||||
|
${ALSA_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(f00bar
|
target_link_libraries(f00bar
|
||||||
|
@ -91,4 +95,5 @@ target_link_libraries(f00bar
|
||||||
${JSON_LIBRARIES}
|
${JSON_LIBRARIES}
|
||||||
${UDEV_LIBRARIES}
|
${UDEV_LIBRARIES}
|
||||||
${MPD_LIBRARIES}
|
${MPD_LIBRARIES}
|
||||||
|
${ALSA_LIBRARIES}
|
||||||
)
|
)
|
||||||
|
|
21
config.c
21
config.c
|
@ -21,6 +21,7 @@
|
||||||
#include "particles/string.h"
|
#include "particles/string.h"
|
||||||
|
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
|
#include "modules/alsa.h"
|
||||||
#include "modules/backlight.h"
|
#include "modules/backlight.h"
|
||||||
#include "modules/battery.h"
|
#include "modules/battery.h"
|
||||||
#include "modules/clock.h"
|
#include "modules/clock.h"
|
||||||
|
@ -568,6 +569,24 @@ module_removables_from_config(const struct yml_node *node,
|
||||||
particle_from_config(content, parent_font), left, right);
|
particle_from_config(content, parent_font), left, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct module *
|
||||||
|
module_alsa_from_config(const struct yml_node *node,
|
||||||
|
const struct font *parent_font)
|
||||||
|
{
|
||||||
|
const struct yml_node *card = yml_get_value(node, "card");
|
||||||
|
const struct yml_node *mixer = yml_get_value(node, "mixer");
|
||||||
|
const struct yml_node *content = yml_get_value(node, "content");
|
||||||
|
|
||||||
|
assert(yml_is_scalar(card));
|
||||||
|
assert(yml_is_scalar(mixer));
|
||||||
|
assert(content != NULL);
|
||||||
|
|
||||||
|
return module_alsa(
|
||||||
|
yml_value_as_string(card),
|
||||||
|
yml_value_as_string(mixer),
|
||||||
|
particle_from_config(content, parent_font));
|
||||||
|
}
|
||||||
|
|
||||||
struct bar *
|
struct bar *
|
||||||
conf_to_bar(const struct yml_node *bar)
|
conf_to_bar(const struct yml_node *bar)
|
||||||
{
|
{
|
||||||
|
@ -682,6 +701,8 @@ conf_to_bar(const struct yml_node *bar)
|
||||||
mods[idx] = module_network_from_config(it.node, font);
|
mods[idx] = module_network_from_config(it.node, font);
|
||||||
else if (strcmp(mod_name, "removables") == 0)
|
else if (strcmp(mod_name, "removables") == 0)
|
||||||
mods[idx] = module_removables_from_config(it.node, font);
|
mods[idx] = module_removables_from_config(it.node, font);
|
||||||
|
else if (strcmp(mod_name, "alsa") == 0)
|
||||||
|
mods[idx] = module_alsa_from_config(it.node, font);
|
||||||
else
|
else
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
|
148
modules/alsa.c
Normal file
148
modules/alsa.c
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
#include "alsa.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <alsa/asoundlib.h>
|
||||||
|
|
||||||
|
#define LOG_MODULE "alsa"
|
||||||
|
#define LOG_ENABLE_DBG 1
|
||||||
|
#include "../log.h"
|
||||||
|
#include "../bar.h"
|
||||||
|
|
||||||
|
struct private {
|
||||||
|
char *card;
|
||||||
|
char *mixer;
|
||||||
|
struct particle *label;
|
||||||
|
|
||||||
|
long vol_min;
|
||||||
|
long vol_max;
|
||||||
|
long vol_cur;
|
||||||
|
bool muted;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
destroy(struct module *mod)
|
||||||
|
{
|
||||||
|
struct private *m = mod->private;
|
||||||
|
m->label->destroy(m->label);
|
||||||
|
free(m->card);
|
||||||
|
free(m->mixer);
|
||||||
|
free(m);
|
||||||
|
module_default_destroy(mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct exposable *
|
||||||
|
content(struct module *mod)
|
||||||
|
{
|
||||||
|
struct private *m = mod->private;
|
||||||
|
|
||||||
|
mtx_lock(&mod->lock);
|
||||||
|
struct tag_set tags = {
|
||||||
|
.tags = (struct tag *[]){
|
||||||
|
tag_new_int_range(mod, "volume", m->vol_cur, m->vol_min, m->vol_max),
|
||||||
|
tag_new_bool(mod, "muted", m->muted),
|
||||||
|
},
|
||||||
|
.count = 2,
|
||||||
|
};
|
||||||
|
mtx_unlock(&mod->lock);
|
||||||
|
|
||||||
|
struct exposable *exposable = m->label->instantiate(m->label, &tags);
|
||||||
|
|
||||||
|
tag_set_destroy(&tags);
|
||||||
|
return exposable;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_state(struct module *mod, snd_mixer_elem_t *elem)
|
||||||
|
{
|
||||||
|
struct private *m = mod->private;
|
||||||
|
|
||||||
|
long cur, min, max;
|
||||||
|
snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_MONO, &cur);
|
||||||
|
snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
|
||||||
|
|
||||||
|
int unmuted;
|
||||||
|
snd_mixer_selem_get_playback_switch(elem, SND_MIXER_SCHN_MONO, &unmuted);
|
||||||
|
|
||||||
|
LOG_DBG("muted=%d, cur=%ld, min=%ld, max=%ld", !unmuted, cur, min, max);
|
||||||
|
|
||||||
|
mtx_lock(&mod->lock);
|
||||||
|
m->vol_min = min;
|
||||||
|
m->vol_max = max;
|
||||||
|
m->vol_cur = cur;
|
||||||
|
m->muted = !unmuted;
|
||||||
|
mtx_unlock(&mod->lock);
|
||||||
|
|
||||||
|
mod->bar->refresh(mod->bar);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
run(struct module_run_context *ctx)
|
||||||
|
{
|
||||||
|
struct module *mod = ctx->module;
|
||||||
|
struct private *m = mod->private;
|
||||||
|
|
||||||
|
module_signal_ready(ctx);
|
||||||
|
|
||||||
|
snd_mixer_t *handle;
|
||||||
|
snd_mixer_open(&handle, 0);
|
||||||
|
snd_mixer_attach(handle, m->card);
|
||||||
|
snd_mixer_selem_register(handle, NULL, NULL);
|
||||||
|
snd_mixer_load(handle);
|
||||||
|
|
||||||
|
snd_mixer_selem_id_t *sid;
|
||||||
|
snd_mixer_selem_id_alloca(&sid);
|
||||||
|
snd_mixer_selem_id_set_index(sid, 0);
|
||||||
|
snd_mixer_selem_id_set_name(sid, m->mixer);
|
||||||
|
snd_mixer_elem_t* elem = snd_mixer_find_selem(handle, sid);
|
||||||
|
|
||||||
|
/* Initial state */
|
||||||
|
update_state(mod, elem);
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
int fd_count = snd_mixer_poll_descriptors_count(handle);
|
||||||
|
assert(fd_count >= 1);
|
||||||
|
|
||||||
|
struct pollfd fds[1 + fd_count];
|
||||||
|
|
||||||
|
fds[0] = (struct pollfd){.fd = ctx->abort_fd, .events = POLLIN};
|
||||||
|
snd_mixer_poll_descriptors(handle, &fds[1], fd_count);
|
||||||
|
|
||||||
|
poll(fds, fd_count + 1, -1);
|
||||||
|
|
||||||
|
if (fds[0].revents & POLLIN)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (fds[1].revents & POLLHUP) {
|
||||||
|
/* Don't know if this can happen */
|
||||||
|
LOG_ERR("disconnected from alsa");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
snd_mixer_handle_events(handle);
|
||||||
|
update_state(mod, elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
snd_mixer_close(handle);
|
||||||
|
snd_config_update_free_global();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct module *
|
||||||
|
module_alsa(const char *card, const char *mixer, struct particle *label)
|
||||||
|
{
|
||||||
|
struct private *priv = malloc(sizeof(*priv));
|
||||||
|
priv->label = label;
|
||||||
|
priv->card = strdup(card);
|
||||||
|
priv->mixer = strdup(mixer);
|
||||||
|
priv->vol_cur = priv->vol_min = priv->vol_max = 0;
|
||||||
|
priv->muted = true;
|
||||||
|
|
||||||
|
struct module *mod = module_common_new();
|
||||||
|
mod->private = priv;
|
||||||
|
mod->run = &run;
|
||||||
|
mod->destroy = &destroy;
|
||||||
|
mod->content = &content;
|
||||||
|
return mod;
|
||||||
|
}
|
7
modules/alsa.h
Normal file
7
modules/alsa.h
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../module.h"
|
||||||
|
#include "../particle.h"
|
||||||
|
|
||||||
|
struct module *module_alsa(
|
||||||
|
const char *card, const char *mixer, struct particle *label);
|
Loading…
Add table
Reference in a new issue