Keep track of volume changes in ALSA / Pulseaudio

How do you listen to the default changes in the volume of the main channel on the sound card? I would like to receive a notification via dbus or callback or something that has changed.

I tried looking for both the ALSA and PulseAudio APIs and they only allow you to set and get volume, but not listen to changes in the volume.

Any programming language is fine.

+4
source share
3 answers

This is possible using the ALSA API.

, snd_ctl_subscribe_events(), . snd_ctl_read() ; , poll(). SND_CTL_EVENT_ELEM SND_CTL_EVENT_MASK_VALUE, .

amixer monitor .

+7

: , 5% 100%. , .

pactl subscribe . , , - C-, .

run.sh:

pactl subscribe | grep --line-buffered "sink" | ./prog

, 3:

pactl subscribe | grep --line-buffered "sink #3" | ./prog

prog.c:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[]){
    while(1){
        while(getchar() != '\n');
        system("./volume_notify.sh");
    }
}

pactl , .

--

, amixer, CL. while , .

#include <stdio.h>
#include <alsa/asoundlib.h>

#define MAX_CARDS 256

int monitor_native(char const *name);
int open_ctl(const char *name, snd_ctl_t **ctlp);
void close_all(snd_ctl_t* ctls[], int ncards);

int main(int argc, char* argv[]){

    const char *ctl_name = "hw:0";

    while(monitor_native(ctl_name) == 1){
        //volume has been changed, do something
        system("~/.volume_notify.sh");
    }

    return 0;
}

int monitor_native(char const *name) {
    snd_ctl_t *ctls[MAX_CARDS];
    int ncards = 0;
    int i, err = 0;

    if (!name) {
        int card = -1;
        while (snd_card_next(&card) >= 0 && card >= 0) {
            char cardname[16];
            if (ncards >= MAX_CARDS) {
                fprintf(stderr, "alsactl: too many cards\n");
                close_all(ctls, ncards);
                return -E2BIG;
            }
            sprintf(cardname, "hw:%d", card);
            err = open_ctl(cardname, &ctls[ncards]);
            if (err < 0) {
                close_all(ctls, ncards);
                return err;
            }
            ncards++;
        }
    } else {
        err = open_ctl(name, &ctls[0]);
        if (err < 0) {
            close_all(ctls, ncards);
            return err;
        }
        ncards++;
    }

    for (;ncards > 0;) {
        pollfd* fds = new pollfd[ncards];

        for (i = 0; i < ncards; i++) {
            snd_ctl_poll_descriptors(ctls[i], &fds[i], 1);
        }

        err = poll(fds, ncards, -1);
        if (err <= 0) {
            err = 0;
            break;
        }

        for (i = 0; i < ncards; i++) {
            unsigned short revents;
            snd_ctl_poll_descriptors_revents(ctls[i], &fds[i], 1, &revents);
            if (revents & POLLIN) {
                snd_ctl_event_t *event;
                snd_ctl_event_alloca(&event);

                if (snd_ctl_read(ctls[i], event) < 0) {
                    continue;
                }
                if (snd_ctl_event_get_type(event) != SND_CTL_EVENT_ELEM) {
                    continue;
                }

                unsigned int mask = snd_ctl_event_elem_get_mask(event);
                if (mask & SND_CTL_EVENT_MASK_VALUE) {
                    close_all(ctls, ncards);
                    return 1;
                }
            }
        }
    }

    close_all(ctls, ncards);
    return 0;
}

int open_ctl(const char *name, snd_ctl_t **ctlp) {
    snd_ctl_t *ctl;
    int err;

    err = snd_ctl_open(&ctl, name, SND_CTL_READONLY);
    if (err < 0) {
        fprintf(stderr, "Cannot open ctl %s\n", name);
        return err;
    }
    err = snd_ctl_subscribe_events(ctl, 1);
    if (err < 0) {
        fprintf(stderr, "Cannot open subscribe events to ctl %s\n", name);
        snd_ctl_close(ctl);
        return err;
    }
    *ctlp = ctl;
    return 0;
}

void close_all(snd_ctl_t* ctls[], int ncards) {
    for (ncards -= 1; ncards >= 0; --ncards) {
        snd_ctl_close(ctls[ncards]);
    }
}
+3

Looks like @ sealj553's answer, but doesn't need a C program:

pactl subscribe | grep --line-buffered "sink" | xargs -n1 ./volume_notify.sh
+1
source

Source: https://habr.com/ru/post/1625421/


All Articles