diff options
| author | Watcom <watcom.hecht@gmail.com> | 2016-09-14 04:26:45 -0300 | 
|---|---|---|
| committer | Michael Stapelberg <stapelberg@users.noreply.github.com> | 2016-09-14 09:26:45 +0200 | 
| commit | 8d2ef5f99b2ebc08a0a9d1f26492094692b1fc6b (patch) | |
| tree | f264785b909bf2b1b9dc9c53f03dcd8126786920 | |
| parent | 48e10658b46e07b89ee7074af1a56bdc61656f05 (diff) | |
pulse device may be specified by name (#126) (#162)
| -rw-r--r-- | include/i3status.h | 2 | ||||
| -rw-r--r-- | man/i3status.man | 21 | ||||
| -rw-r--r-- | src/print_volume.c | 12 | ||||
| -rw-r--r-- | src/pulse.c | 71 | 
4 files changed, 75 insertions, 31 deletions
| diff --git a/include/i3status.h b/include/i3status.h index 3911e04..dd0ba02 100644 --- a/include/i3status.h +++ b/include/i3status.h @@ -217,7 +217,7 @@ void print_eth_info(yajl_gen json_gen, char *buffer, const char *interface, cons  void print_load(yajl_gen json_gen, char *buffer, const char *format, const float max_threshold);  void print_volume(yajl_gen json_gen, char *buffer, const char *fmt, const char *fmt_muted, const char *device, const char *mixer, int mixer_idx);  bool process_runs(const char *path); -int volume_pulseaudio(uint32_t sink_idx); +int volume_pulseaudio(uint32_t sink_idx, const char *sink_name);  bool pulse_initialize(void);  /* socket file descriptor for general purposes */ diff --git a/man/i3status.man b/man/i3status.man index cdde2aa..cb1c248 100644 --- a/man/i3status.man +++ b/man/i3status.man @@ -487,10 +487,16 @@ or   device = "pulse:N" -where N is the index of the PulseAudio sink. If no sink is specified the -default is used. If the device string is missing or is set to "default", -PulseAudio will be tried if detected and will fallback to ALSA (Linux) -or OSS (FreeBSD/OpenBSD). +where N is the index or name of the PulseAudio sink. You can obtain the name of +the sink with the following command: + + $ pacmd list-sinks | grep name: +            name: <alsa_output.pci-0000_00_14.2.analog-stereo> + +The name is what's inside the angle brackets, not including them. If no sink is +specified the default sink is used. If the device string is missing or is set +to "default", PulseAudio will be tried if detected and will fallback to ALSA +(Linux) or OSS (FreeBSD/OpenBSD).  *Example order*: +volume master+ @@ -516,6 +522,13 @@ volume master {  	device = "pulse:1"  }  ------------------------------------------------------------- +------------------------------------------------------------- +volume master { +	format = "♪: %volume" +	format_muted = "♪: muted (%volume)" +	device = "pulse:alsa_output.pci-0000_00_14.2.analog-stereo" +} +-------------------------------------------------------------  == Universal module options diff --git a/src/print_volume.c b/src/print_volume.c index 58cba2a..51e84f3 100644 --- a/src/print_volume.c +++ b/src/print_volume.c @@ -4,6 +4,7 @@  #include <stdlib.h>  #include <stdio.h>  #include <err.h> +#include <ctype.h>  #include <yajl/yajl_gen.h>  #include <yajl/yajl_version.h> @@ -67,9 +68,12 @@ void print_volume(yajl_gen json_gen, char *buffer, const char *fmt, const char *       * index of the PulseAudio sink then force PulseAudio, optionally       * overriding the default sink */      if (!strncasecmp(device, "pulse", strlen("pulse"))) { -        uint32_t sink_idx = device[5] == ':' ? (uint32_t)atoi(device + 6) -                                             : DEFAULT_SINK_INDEX; -        int cvolume = pulse_initialize() ? volume_pulseaudio(sink_idx) : 0; +        uint32_t sink_idx = device[strlen("pulse")] == ':' ? (uint32_t)atoi(device + strlen("pulse:")) : DEFAULT_SINK_INDEX; +        const char *sink_name = device[strlen("pulse")] == ':' && +                                        !isdigit(device[strlen("pulse:")]) +                                    ? device + strlen("pulse:") +                                    : NULL; +        int cvolume = pulse_initialize() ? volume_pulseaudio(sink_idx, sink_name) : 0;          int ivolume = DECOMPOSE_VOLUME(cvolume);          bool muted = DECOMPOSE_MUTED(cvolume);          if (muted) { @@ -85,7 +89,7 @@ void print_volume(yajl_gen json_gen, char *buffer, const char *fmt, const char *          goto out;      } else if (!strcasecmp(device, "default") && pulse_initialize()) {          /* no device specified or "default" set */ -        int cvolume = volume_pulseaudio(DEFAULT_SINK_INDEX); +        int cvolume = volume_pulseaudio(DEFAULT_SINK_INDEX, NULL);          int ivolume = DECOMPOSE_VOLUME(cvolume);          bool muted = DECOMPOSE_MUTED(cvolume);          if (ivolume >= 0) { diff --git a/src/pulse.c b/src/pulse.c index 3398014..50999f7 100644 --- a/src/pulse.c +++ b/src/pulse.c @@ -11,6 +11,7 @@  #define APP_ID "org.i3wm"  typedef struct indexed_volume_s { +    char *name;      uint32_t idx;      int volume;      TAILQ_ENTRY(indexed_volume_s) entries; @@ -45,22 +46,35 @@ static bool pulseaudio_free_operation(pa_context *c, pa_operation *o) {   * save the volume for the specified sink index   * returning true if the value was changed   */ -static bool save_volume(uint32_t sink_idx, int new_volume) { +static bool save_volume(uint32_t sink_idx, int new_volume, const char *name) {      pthread_mutex_lock(&pulse_mutex);      indexed_volume_t *entry;      TAILQ_FOREACH(entry, &cached_volume, entries) { -        if (entry->idx == sink_idx) { -            const bool changed = (new_volume != entry->volume); -            entry->volume = new_volume; -            pthread_mutex_unlock(&pulse_mutex); -            return changed; +        if (name) { +            if (!entry->name || strcmp(entry->name, name)) { +                continue; +            } +        } else { +            if (entry->idx != sink_idx) { +                continue; +            }          } +        const bool changed = (new_volume != entry->volume); +        entry->volume = new_volume; +        pthread_mutex_unlock(&pulse_mutex); +        return changed;      }      /* index not found, store it */      entry = malloc(sizeof(*entry));      TAILQ_INSERT_HEAD(&cached_volume, entry, entries);      entry->idx = sink_idx;      entry->volume = new_volume; +    if (name) { +        entry->name = malloc(strlen(name) + 1); +        strcpy(entry->name, name); +    } else { +        entry->name = NULL; +    }      pthread_mutex_unlock(&pulse_mutex);      return true;  } @@ -88,20 +102,26 @@ static void store_volume_from_sink_cb(pa_context *c,       * DEFAULT_SINK_INDEX as the index, and another with its proper value       * (using bitwise OR to avoid early-out logic) */      if ((info->index == default_sink_idx && -         save_volume(DEFAULT_SINK_INDEX, composed_volume)) | -        save_volume(info->index, composed_volume)) { +         save_volume(DEFAULT_SINK_INDEX, composed_volume, NULL)) | +        save_volume(info->index, composed_volume, info->name)) {          /* if the volume or mute flag changed, wake the main thread */          pthread_kill(main_thread, SIGUSR1);      }  } -static void get_sink_info(pa_context *c, uint32_t idx) { -    pa_operation *o = -        idx == DEFAULT_SINK_INDEX ? pa_context_get_sink_info_by_name( -                                        c, "@DEFAULT_SINK@", store_volume_from_sink_cb, NULL) -                                  : pa_context_get_sink_info_by_index( -                                        c, idx, store_volume_from_sink_cb, NULL); -    pulseaudio_free_operation(c, o); +static void get_sink_info(pa_context *c, uint32_t idx, const char *name) { +    pa_operation *o; + +    if (name || idx == DEFAULT_SINK_INDEX) { +        o = pa_context_get_sink_info_by_name( +            c, name ? name : "@DEFAULT_SINK@", store_volume_from_sink_cb, NULL); +    } else { +        o = pa_context_get_sink_info_by_index( +            c, idx, store_volume_from_sink_cb, NULL); +    } +    if (o) { +        pulseaudio_free_operation(c, o); +    }  }  static void store_default_sink_cb(pa_context *c, @@ -138,7 +158,7 @@ static void subscribe_cb(pa_context *c, pa_subscription_event_type_t t,              update_default_sink(c);              break;          case PA_SUBSCRIPTION_EVENT_SINK: -            get_sink_info(c, idx); +            get_sink_info(c, idx, NULL);              break;          default:              break; @@ -183,25 +203,32 @@ static void context_state_callback(pa_context *c, void *userdata) {   * returns the current volume in percent, which, as per PulseAudio,   * may be > 100%   */ -int volume_pulseaudio(uint32_t sink_idx) { +int volume_pulseaudio(uint32_t sink_idx, const char *sink_name) {      if (!context_ready || default_sink_idx == DEFAULT_SINK_INDEX)          return -1;      pthread_mutex_lock(&pulse_mutex);      const indexed_volume_t *entry;      TAILQ_FOREACH(entry, &cached_volume, entries) { -        if (entry->idx == sink_idx) { -            int vol = entry->volume; -            pthread_mutex_unlock(&pulse_mutex); -            return vol; +        if (sink_name) { +            if (!entry->name || strcmp(entry->name, sink_name)) { +                continue; +            } +        } else { +            if (entry->idx != sink_idx) { +                continue; +            }          } +        int vol = entry->volume; +        pthread_mutex_unlock(&pulse_mutex); +        return vol;      }      pthread_mutex_unlock(&pulse_mutex);      /* first time requires a prime callback call because we only get       * updates when the volume actually changes, but we need it to       * be correct even if it never changes */      pa_threaded_mainloop_lock(main_loop); -    get_sink_info(context, sink_idx); +    get_sink_info(context, sink_idx, sink_name);      pa_threaded_mainloop_unlock(main_loop);      /* show 0 while we don't have this information */      return 0; | 
