X-Git-Url: https://vcs.maemo.org/git/?a=blobdiff_plain;f=src%2Fmixer.c;h=109ce9b5b9fb48de19cc91b7f7a2b00784a2a9b6;hb=6526b47b2c63c9f46b63d3a5e72cbe71b04d60ac;hp=d5950dec3fbb82d000255ad6da5ffcc6c6d2801c;hpb=0ab1d8b96ad5925c497855c4e09fcde1dc24ef74;p=monky diff --git a/src/mixer.c b/src/mixer.c index d5950de..109ce9b 100644 --- a/src/mixer.c +++ b/src/mixer.c @@ -1,20 +1,46 @@ -/* +/* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*- + * vim: ts=4 sw=4 noet ai cindent syntax=c + * * Conky, a system monitor, based on torsmo * - * This program is licensed under BSD license, read COPYING + * Any original torsmo code is licensed under the BSD license + * + * All code written since the fork of torsmo is licensed under the GPL + * + * Please see COPYING for details + * + * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen + * Copyright (c) 2005-2010 Brenden Matthews, Philip Kovacs, et. al. + * (see AUTHORS) + * All rights reserved. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . * - * $Id$ */ +#include "conky.h" +#include "logging.h" +#include "specials.h" +#include "text_object.h" #include - #include #include -#include -#include +#include -#include "conky.h" +#ifdef MIXER_IS_ALSA +#include +#else #ifdef HAVE_LINUX_SOUNDCARD_H #include #else @@ -22,27 +48,183 @@ #include #else #include -#endif /* __OpenBSD__ */ -#endif /* HAVE_LINUX_SOUNDCARD_H */ +#endif /* __OpenBSD__ */ +#endif /* HAVE_LINUX_SOUNDCARD_H */ +#endif /* MIXER_IS_ALSA */ #define MIXER_DEV "/dev/mixer" +#ifdef MIXER_IS_ALSA +#define MAX_MIXERS 8 +struct mixer_control { + char name[64]; + snd_mixer_t *mixer; + snd_mixer_selem_id_t *sid; + snd_mixer_elem_t *elem; + long vol_min, vol_max; +}; + +static struct mixer_control mixer_data[MAX_MIXERS]; +int num_mixers = 0; +static char soundcard[64] = "default"; +#else static int mixer_fd; static const char *devs[] = SOUND_DEVICE_NAMES; +#endif + +#ifdef MIXER_IS_ALSA +static int parse_simple_id(const char *str, snd_mixer_selem_id_t *sid) +{ + int c, size; + char buf[128]; + char *ptr = buf; + + while (*str == ' ' || *str == '\t') + str++; + if (!(*str)) + return -EINVAL; + size = 1; /* for '\0' */ + if (*str != '"' && *str != '\'') { + while (*str && *str != ',') { + if (size < (int)sizeof(buf)) { + *ptr++ = *str; + size++; + } + str++; + } + } else { + c = *str++; + while (*str && *str != c) { + if (size < (int)sizeof(buf)) { + *ptr++ = *str; + size++; + } + str++; + } + if (*str == c) + str++; + } + if (*str == '\0') { + snd_mixer_selem_id_set_index(sid, 0); + *ptr = 0; + goto _set; + } + if (*str != ',') + return -EINVAL; + *ptr = 0; /* terminate the string */ + str++; + if (!isdigit(*str)) + return -EINVAL; + snd_mixer_selem_id_set_index(sid, atoi(str)); + _set: + snd_mixer_selem_id_set_name(sid, buf); + return 0; +} + +int mixer_init (const char *name) +{ + /* from amixer.c, replaced -EINVAL with -1 */ + int i, err; + if (!name) + name = "Master"; + + for (i = 0; i < num_mixers; i++) { + if (!strcasecmp (mixer_data[i].name, name)) { + return i; + } + } + if (i == MAX_MIXERS) { + fprintf (stderr, "max mixers (%d) reached\n", MAX_MIXERS); + return -1; + }; + + num_mixers++; +#define data mixer_data[i] + + strncpy (mixer_data[i].name, name, 63); + mixer_data[i].name[63] = '\0'; + snd_mixer_selem_id_alloca (&data.sid); + data.mixer = NULL; + if (parse_simple_id (name, data.sid) < 0) { + fprintf (stderr, "Wrong mixer identifier: %s\n", name); + return -1; + } + if ((err = snd_mixer_open (&data.mixer, 0)) < 0) { + fprintf (stderr, "snd_mixer_open: %s\n", snd_strerror (err)); + return -1; + } + if ((err = snd_mixer_attach (data.mixer, soundcard)) < 0) { + fprintf (stderr, "snd_mixer_attach: %s\n", snd_strerror (err)); + return -1; + } + if ((err = snd_mixer_selem_register (data.mixer, NULL, NULL)) < 0) { + fprintf (stderr, "snd_mixer_selem_register: %s\n", + snd_strerror (err)); + return -1; + } + if ((err = snd_mixer_load (data.mixer)) < 0) { + fprintf (stderr, "snd_mixer_load: %s\n", snd_strerror (err)); + return -1; + } + if (!(data.elem = snd_mixer_find_selem (data.mixer, data.sid))) { + fprintf (stderr, "snd_mixer_find_selem (\"%s\", %i)\n", + snd_mixer_selem_id_get_name (data.sid), + snd_mixer_selem_id_get_index (data.sid)); + return -1; + } + snd_mixer_selem_get_playback_volume_range(data.elem, &data.vol_min, &data.vol_max); + return i; +} +static int mixer_get_avg (int i) +{ + long val; + snd_mixer_handle_events (data.mixer); + snd_mixer_selem_get_playback_volume (data.elem, 0, &val); + return (int) val; +} +static int mixer_get_left (int i) +{ + /* stub */ + return mixer_get_avg (i); +} +static int mixer_get_right (int i) +{ + /* stub */ + return mixer_get_avg (i); +} +int mixer_to_255(int i, int x) +{ + return (x-data.vol_min)*255/(data.vol_max-data.vol_min); +} +int mixer_is_mute(int i) +{ + snd_mixer_handle_events (data.mixer); + if (snd_mixer_selem_has_playback_switch (data.elem)) { + int val, err; + if ((err = snd_mixer_selem_get_playback_switch(data.elem, 0, &val)) < 0) + fprintf (stderr, "playback_switch: %s\n", snd_strerror (err)); + return !val; + } else { + return !mixer_get_avg(i); + } +} +#undef data + +#else /* MIXER_IS_ALSA */ int mixer_init(const char *name) { unsigned int i; - if (name == 0 || name[0] == '\0') + if (name == 0 || name[0] == '\0') { name = "vol"; + } /* open mixer */ if (mixer_fd <= 0) { mixer_fd = open(MIXER_DEV, O_RDONLY); if (mixer_fd == -1) { - ERR("can't open %s: %s", MIXER_DEV, - strerror(errno)); + NORM_ERR("can't open %s: %s", MIXER_DEV, strerror(errno)); return -1; } } @@ -62,8 +244,9 @@ static int mixer_get(int i) int val = -1; if (ioctl(mixer_fd, MIXER_READ(i), &val) == -1) { - if (!rep) - ERR("mixer ioctl: %s", strerror(errno)); + if (!rep) { + NORM_ERR("mixer ioctl: %s", strerror(errno)); + } rep = 1; return 0; } @@ -72,18 +255,119 @@ static int mixer_get(int i) return val; } -int mixer_get_avg(int i) +static int mixer_get_avg(int i) { int v = mixer_get(i); + return ((v >> 8) + (v & 0xFF)) / 2; } -int mixer_get_left(int i) +static int mixer_get_left(int i) { return mixer_get(i) >> 8; } -int mixer_get_right(int i) +static int mixer_get_right(int i) { return mixer_get(i) & 0xFF; } +int mixer_is_mute(int i) +{ + return !mixer_get(i); +} + +#define mixer_to_255(i, x) x +#endif /* MIXER_IS_ALSA */ + +void parse_mixer_arg(struct text_object *obj, const char *arg) +{ + obj->data.l = mixer_init(arg); +} + +/* chan specifies the channel to print: + * -1 := left channel + * 0 := channel average + * 1 := right channel + */ +static void print_mixer_chan(struct text_object *obj, int chan, char *p, int p_max_size) +{ + int val; + + if (chan < 0) + val = mixer_get_left(obj->data.l); + else if (chan == 0) + val = mixer_get_avg(obj->data.l); + else + val = mixer_get_right(obj->data.l); + + percent_print(p, p_max_size, val); +} + +void print_mixer(struct text_object *obj, char *p, int p_max_size) +{ + print_mixer_chan(obj, 0, p, p_max_size); +} + +void print_mixerl(struct text_object *obj, char *p, int p_max_size) +{ + print_mixer_chan(obj, -1, p, p_max_size); +} + +void print_mixerr(struct text_object *obj, char *p, int p_max_size) +{ + print_mixer_chan(obj, 1, p, p_max_size); +} + +int check_mixer_muted(struct text_object *obj) +{ + if (!mixer_is_mute(obj->data.l)) + return 0; + return 1; +} + +void scan_mixer_bar(struct text_object *obj, const char *arg) +{ + char buf1[64]; + int n; + + if (arg && sscanf(arg, "%63s %n", buf1, &n) >= 1) { + obj->data.i = mixer_init(buf1); + scan_bar(obj, arg + n); + } else { + obj->data.i = mixer_init(NULL); + scan_bar(obj, arg); + } +} + +/* see print_mixer() above for a description of 'chan' */ +static void print_mixer_bar_chan(struct text_object *obj, int chan, char *p, int p_max_size) +{ + int val; + + if (!p_max_size) + return; + + if (chan < 0) + val = mixer_get_left(obj->data.i); + else if (chan == 0) + val = mixer_get_avg(obj->data.i); + else + val = mixer_get_right(obj->data.i); + + new_bar(obj, p, p_max_size, mixer_to_255(obj->data.i, val)); +} + +void print_mixer_bar(struct text_object *obj, char *p, int p_max_size) +{ + print_mixer_bar_chan(obj, 0, p, p_max_size); +} + +void print_mixerl_bar(struct text_object *obj, char *p, int p_max_size) +{ + print_mixer_bar_chan(obj, -1, p, p_max_size); +} + +void print_mixerr_bar(struct text_object *obj, char *p, int p_max_size) +{ + print_mixer_bar_chan(obj, 1, p, p_max_size); +}