2
* Purpose: A sample program for developing a simple mixer applet.
3
* Copyright (C) 4Front Technologies, 2007. Released under GPLv2/CDDL.
5
* This program is not usefull by itself. It just demonstrates techniques that
6
* can be used when developing very simple mixer applets that control just
7
* the key volumes in the system.
9
* The full OSS 4.0 mixer API is rather complex and designed for allmighty
10
* master mixer applications. However there is a subset of the API that can be
11
* used rather easily. This subset is limited to control of the main output volume,
12
* audio/wave/pcm playback volume and/or recording input level. It cannot be
13
* used for anything else.
15
* This program demonstrates three main techniques to be used by mixer applets:
17
* 1) How to find the default mixer device that controls the primary
18
* sound card/device in the system. This device is connected to the
19
* primary (desktop) speakers and the default system sounds/beep are
20
* directed to it. Normally this device is the audio chip installed on
21
* the motherboard of the computer.
23
* 2) How to find out the main, pcm and recording volume controls for
26
* 3) How to read the current volume and how to change it.
34
#include <soundcard.h>
42
static int mixer_dev = -1; /* Use the default mixer */
45
find_default_mixer (int mixer_fd)
55
* The default mixer device in the system can be found by checking the
56
* priority parameter of all mixer devices in the system. The device with the
57
* highest priority value is the winner. If there are multiple devices with the
58
* same priority then the first one should be selected.
60
* Note that there should be some method for selecting the mixer device number.
61
* In many cases the user actually wants to use some other mixer than the
65
for (i = 0; i < sysinfo.nummixers; i++)
69
if (ioctl (mixer_fd, SNDCTL_MIXERINFO, &mi) == -1)
71
perror ("SNDCTL_MIXERINFO");
75
if (mi.priority < -1) /* Not suitable default mixer */
78
if (mi.priority > best_pri)
81
best_pri = mi.priority;
85
printf("Mixer device %d seems to be the most probable motherboard device\n",
92
show_controls (int mixer_fd, char *heading, int mixer_dev, int ctls[], int count)
98
printf("\n***** %s *****\n", heading);
100
for (i=0;i<count;i++)
104
* Obtain the mixer extension definition. It might be a good idea to cache
105
* this info in global variables so that doesn't need to be reloaded
108
* Reloading this info every time may cause serious troubles because in that
109
* way the application cannot be noticed after the mixer interface has changed.
115
if (ioctl (mixer_fd, SNDCTL_MIX_EXTINFO, &ext) == -1)
117
perror ("SNDCTL_MIX_EXTINFO");
122
* Have to initialize the dev, ctl and timestamp fields before reading the
128
val.timestamp = ext.timestamp;
130
if (ioctl (mixer_fd, SNDCTL_MIX_READ, &val) == -1)
135
* Getting errno=EIDRM tells that the mixer struicture has been changed. This
136
* may happen for example if new firmware gets loaded to the device. In such
137
* case the application should start from the beginning and to load all
138
* the information again.
141
fprintf (stderr, "Mixer structure changed. Please try again\n");
145
perror ("SNDCTL_MIX_READ");
149
printf ("\t%3d: %s\t ", ctl, ext.extname);
153
case MIXT_MONOSLIDER:
154
printf ("monoslider %d ", val.value & 0xff);
157
case MIXT_STEREOSLIDER:
158
printf ("stereoslider %d:%d ", val.value & 0xff,
159
(val.value >> 8) & 0xff);
163
printf ("slider %d ", val.value);
166
case MIXT_MONOSLIDER16:
167
printf ("monoslider %d ", val.value & 0xffff);
170
case MIXT_STEREOSLIDER16:
171
printf ("stereoslider %d:%d ", val.value & 0xffff,
172
(val.value >> 16) & 0xffff);
176
* Sometimes there may be just a MUTE control instead of a slider. However
177
* it's also possible that there is both mute and a slider.
180
printf ("ONOFF %d ", val.value);
184
printf ("mute %d ", val.value);
188
* Enumerated controls may be used for example for recording source
192
printf ("Selection %d ", val.value);
197
printf ("Unknown control type (%d), value=0x%08x ", ext.type,
207
main (int argc, char *argv[])
213
* Bins for the mixer controls.
215
#define ADD_TO_BIN(bin, ctl) \
216
if (n_##bin >= MAX_CTL) \
218
fprintf(stderr, #bin " table is full\n"); exit(-1); \
220
bin##_ctls[n_##bin++] = ctl
222
int mainvol_ctls[MAX_CTL];
223
int pcmvol_ctls[MAX_CTL];
224
int recvol_ctls[MAX_CTL];
225
int monvol_ctls[MAX_CTL];
226
int n_mainvol=0, n_pcmvol=0, n_recvol=0, n_monvol=0;
229
if ((devmixer=getenv("OSS_MIXERDEV"))==NULL)
230
devmixer = "/dev/mixer";
233
* Get the mixer device number from command line.
236
mixer_dev = atoi (argv[1]);
239
* Open /dev/mixer. This device file can be used regardless of the actual
240
* mixer device number.
243
if ((mixer_fd = open (devmixer, O_RDWR, 0)) == -1)
250
* Get OSS system info to a global buffer.
253
if (ioctl (mixer_fd, SNDCTL_SYSINFO, &sysinfo) == -1)
255
perror ("SNDCTL_SYSINFO");
260
* Check the mixer device number.
264
mixer_dev = find_default_mixer (mixer_fd);
266
if (mixer_dev < 0 || mixer_dev >= sysinfo.nummixers)
268
fprintf (stderr, "Nonexistent mixer device %d\n", mixer_dev);
272
printf ("Using OSS mixer device %d\n", mixer_dev);
275
* The second step is to find the main volume, audio/pcm playback volume and
276
* recording level controls.
278
* It's important to understand that many mixer devices don't have such
279
* controls. This is perfectly normal and the mixer applet must be able to
280
* handle this. Aborting or displaying loud error message should be avoided.
282
* It's also possible that some mixers have multiple main volume, pcm or
283
* record level controls. In such case the application can support all of
284
* of them or select just the first one. Having multiple controls means that
285
* the device hase multiple sets of speakers or audio devices and each of
286
* them has separate volume controls.
290
if (ioctl (mixer_fd, SNDCTL_MIX_NREXT, &n) == -1)
292
perror ("SNDCTL_MIX_NREXT");
296
for (i = 0; i < n; i++)
303
if (ioctl (mixer_fd, SNDCTL_MIX_EXTINFO, &ext) == -1)
305
perror ("SNDCTL_MIX_EXTINFO");
310
* The MIXF_MAINVOL, MIXF_PCMVOL, MIXF_MONVOL and MIXF_RECVOL flags are used to mark
311
* potential main volume, pcm and recording level controls. This makes it
312
* possible to implement support for these common types of controls without
313
* having to implement fully featured mixer program.
315
* Mixer applets using this simplified interface should ignore all mixer
316
* controls that don't have any of these three flags. However
318
* Note that while mixer controls should have at most one of thse flags defined
319
* it may happen that some devices violate this rule. It's up to
320
* application what it does with such controls. Preferably it gets added
321
* to all of the bins.
325
flags & (MIXF_MAINVOL | MIXF_PCMVOL | MIXF_RECVOL | MIXF_MONVOL))
327
printf ("Mixer control %d is ", i);
329
if (ext.flags & MIXF_MAINVOL)
333
ADD_TO_BIN(mainvol, i);
336
if (ext.flags & MIXF_PCMVOL)
340
ADD_TO_BIN(pcmvol, i);
343
if (ext.flags & MIXF_RECVOL)
347
ADD_TO_BIN(recvol, i);
350
if (ext.flags & MIXF_MONVOL)
354
ADD_TO_BIN(monvol, i);
357
* It is possible that many/most/all mixer controls don't have any of the above
358
* flags set. This means that such controls are for expert use only. It is
359
* recommended that mixer applets have an [Advanced options] button that is
360
* enabled if such controls are found. This button can launch ossxmix (or
361
* some configurable program).
364
printf ("%s\n", ext.extname);
369
* Now we have selected the mixer controls. Next show their values.
370
* Since setting the value is pretty much identical to reading them we don't
371
* demonstrate it in this program.
376
show_controls (mixer_fd, "Main volume controls", mixer_dev, mainvol_ctls, n_mainvol);
378
printf ("No main volume control available\n");
381
show_controls (mixer_fd, "Pcm volume controls", mixer_dev, pcmvol_ctls, n_pcmvol);
383
printf ("No pcm volume control available\n");
386
show_controls (mixer_fd, "Rec volume controls", mixer_dev, recvol_ctls, n_recvol);
388
printf ("No rec volume control available\n");
391
show_controls (mixer_fd, "Monitor volume controls", mixer_dev, monvol_ctls, n_monvol);
393
printf ("No monitor volume control available\n");
397
if (n_mainvol + n_pcmvol + n_recvol + n_monvol == 0)
399
printf("\nNo 'simple' mixer controls available for this device\n");
400
printf("It may be a good idea to start 'ossxmix -d %d' which can access advanced options.\n", mixer_dev);