2016-01-22 6 views
4

Как вы можете слушать изменения громкости основного канала на звуковой карте по умолчанию? Я хотел бы получить уведомление через dbus или обратный вызов или что-то, что изменилось.Наблюдать за изменениями громкости в ALSA/Pulseaudio

Я пробовал искать и API-интерфейс ALSA и PulseAudio, и они только позволяют вам установить и получить громкость, но не прослушать для изменения громкости.

Любой язык программирования в порядке.

ответ

4

Это возможно с помощью API ALSA.

Если у вас есть устройство управления, позвоните по номеру snd_ctl_subscribe_events(), чтобы включить события. Затем используйте snd_ctl_read() для чтения событий; дождаться их, использовать режим блокировки или poll(). Если событие имеет тип SND_CTL_EVENT_ELEM, и если его битовая маска для события содержит SND_CTL_EVENT_MASK_VALUE, значение этого элемента изменилось.

См., Например, the implementation of amixer monitor.

+0

Большое спасибо! –

+0

Если кому-то интересно, это превратилось в плагин node.js [здесь] (https://github.com/illegalprime/alsa-monitor-node). –

0

Редактировать: Во втором примере событие не генерируется для меня, когда объем составляет менее 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 monitor, ссылка на 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]); 
    } 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^