2 * Copyright 2004-2005 Timo Hirvonen
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
25 #define ALSA_PCM_NEW_HW_PARAMS_API
26 #define ALSA_PCM_NEW_SW_PARAMS_API
28 #include <alsa/asoundlib.h>
30 static snd_mixer_t
*alsa_mixer_handle
;
31 static snd_mixer_elem_t
*mixer_elem
= NULL
;
32 static long mixer_vol_min
, mixer_vol_max
;
35 static char *alsa_mixer_device
= NULL
;
36 static char *alsa_mixer_element
= NULL
;
38 static int alsa_mixer_init(void)
40 if (alsa_mixer_device
== NULL
)
41 alsa_mixer_device
= xstrdup("default");
42 if (alsa_mixer_element
== NULL
)
43 alsa_mixer_element
= xstrdup("PCM");
44 /* FIXME: check device */
48 static int alsa_mixer_exit(void)
50 free(alsa_mixer_device
);
51 alsa_mixer_device
= NULL
;
52 free(alsa_mixer_element
);
53 alsa_mixer_element
= NULL
;
57 static int alsa_mixer_open(int *volume_max
)
59 snd_mixer_selem_id_t
*sid
;
60 snd_mixer_elem_t
*elem
;
64 snd_mixer_selem_id_alloca(&sid
);
66 rc
= snd_mixer_open(&alsa_mixer_handle
, 0);
69 rc
= snd_mixer_attach(alsa_mixer_handle
, alsa_mixer_device
);
72 rc
= snd_mixer_selem_register(alsa_mixer_handle
, NULL
, NULL
);
75 rc
= snd_mixer_load(alsa_mixer_handle
);
78 count
= snd_mixer_get_count(alsa_mixer_handle
);
80 d_print("error: mixer does not have elements\n");
83 elem
= snd_mixer_first_elem(alsa_mixer_handle
);
86 int has_vol
, has_switch
;
88 snd_mixer_selem_get_id(elem
, sid
);
89 name
= snd_mixer_selem_id_get_name(sid
);
90 d_print("name = %s\n", name
);
91 d_print("has playback volume = %d\n", snd_mixer_selem_has_playback_volume(elem
));
92 d_print("has playback switch = %d\n", snd_mixer_selem_has_playback_switch(elem
));
93 if (strcasecmp(name
, alsa_mixer_element
)) {
94 elem
= snd_mixer_elem_next(elem
);
97 has_vol
= snd_mixer_selem_has_playback_volume(elem
);
99 d_print("mixer element `%s' does not have playback volume\n", name
);
102 snd_mixer_selem_get_playback_volume_range(elem
,
103 &mixer_vol_min
, &mixer_vol_max
);
104 has_switch
= snd_mixer_selem_has_playback_switch(elem
);
105 /* FIXME: get number of channels */
107 *volume_max
= mixer_vol_max
- mixer_vol_min
;
110 d_print("error: mixer element `%s' not found\n", alsa_mixer_element
);
113 d_print("error: %s\n", snd_strerror(rc
));
117 static int alsa_mixer_close(void)
119 snd_mixer_close(alsa_mixer_handle
);
123 static int alsa_mixer_get_fds(int *fds
)
125 struct pollfd pfd
[NR_MIXER_FDS
];
128 count
= snd_mixer_poll_descriptors(alsa_mixer_handle
, pfd
, NR_MIXER_FDS
);
129 for (i
= 0; i
< count
; i
++)
134 static int alsa_mixer_set_volume(int l
, int r
)
136 if (mixer_elem
== NULL
) {
141 if (l
> mixer_vol_max
)
142 d_print("error: left volume too high (%d > %ld)\n",
144 if (r
> mixer_vol_max
)
145 d_print("error: right volume too high (%d > %ld)\n",
147 snd_mixer_selem_set_playback_volume(mixer_elem
, SND_MIXER_SCHN_FRONT_LEFT
, l
);
148 snd_mixer_selem_set_playback_volume(mixer_elem
, SND_MIXER_SCHN_FRONT_RIGHT
, r
);
152 static int alsa_mixer_get_volume(int *l
, int *r
)
156 if (mixer_elem
== NULL
)
158 snd_mixer_handle_events(alsa_mixer_handle
);
159 snd_mixer_selem_get_playback_volume(mixer_elem
, SND_MIXER_SCHN_FRONT_LEFT
, &lv
);
160 snd_mixer_selem_get_playback_volume(mixer_elem
, SND_MIXER_SCHN_FRONT_RIGHT
, &rv
);
161 *l
= lv
- mixer_vol_min
;
162 *r
= rv
- mixer_vol_min
;
166 static int alsa_mixer_set_option(int key
, const char *val
)
170 free(alsa_mixer_element
);
171 alsa_mixer_element
= xstrdup(val
);
174 free(alsa_mixer_device
);
175 alsa_mixer_device
= xstrdup(val
);
178 return -OP_ERROR_NOT_OPTION
;
183 static int alsa_mixer_get_option(int key
, char **val
)
187 if (alsa_mixer_element
)
188 *val
= xstrdup(alsa_mixer_element
);
191 if (alsa_mixer_device
)
192 *val
= xstrdup(alsa_mixer_device
);
195 return -OP_ERROR_NOT_OPTION
;
200 const struct mixer_plugin_ops op_mixer_ops
= {
201 .init
= alsa_mixer_init
,
202 .exit
= alsa_mixer_exit
,
203 .open
= alsa_mixer_open
,
204 .close
= alsa_mixer_close
,
205 .get_fds
= alsa_mixer_get_fds
,
206 .set_volume
= alsa_mixer_set_volume
,
207 .get_volume
= alsa_mixer_get_volume
,
208 .set_option
= alsa_mixer_set_option
,
209 .get_option
= alsa_mixer_get_option
212 const char * const op_mixer_options
[] = {