aboutsummaryrefslogtreecommitdiff
path: root/lib/libmixer/mixer.3
blob: b541c94af779b640b3131d88c779be44e8b3abf5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
.\"-
.\" Copyright (c) 2021 Christos Margiolis <christos@FreeBSD.org>
.\"
.\" Permission is hereby granted, free of charge, to any person obtaining a copy
.\" of this software and associated documentation files (the "Software"), to deal
.\" in the Software without restriction, including without limitation the rights
.\" to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
.\" copies of the Software, and to permit persons to whom the Software is
.\" furnished to do so, subject to the following conditions:
.\"
.\" The above copyright notice and this permission notice shall be included in
.\" all copies or substantial portions of the Software.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
.\" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
.\" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
.\" AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
.\" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
.\" OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
.\" THE SOFTWARE.
.\"
.\" $FreeBSD$
.\"

.Dd September 22, 2021
.Dt mixer 3
.Os
.Sh NAME
.Nm mixer_open ,
.Nm mixer_close ,
.Nm mixer_get_dev ,
.Nm mixer_get_dev_byname ,
.Nm mixer_add_ctl ,
.Nm mixer_add_ctl_s ,
.Nm mixer_remove_ctl ,
.Nm mixer_get_ctl ,
.Nm mixer_get_ctl_byname ,
.Nm mixer_set_vol ,
.Nm mixer_set_mute ,
.Nm mixer_mod_recsrc ,
.Nm mixer_get_dunit ,
.Nm mixer_set_dunit ,
.Nm mixer_get_mode,
.Nm mixer_get_nmixers ,
.Nm MIX_ISDEV ,
.Nm MIX_ISMUTE ,
.Nm MIX_ISREC ,
.Nm MIX_ISRECSRC ,
.Nm MIX_VOLNORM ,
.Nm MIX_VOLDENORM
.Nd interface to OSS mixers
.Sh LIBRARY
Mixer library (libmixer, -lmixer)
.Sh SYNOPSIS
.In mixer.h
.Ft struct mixer *
.Fn mixer_open "const char *name"
.Ft int
.Fn mixer_close "struct mixer *m"
.Ft struct mix_dev *
.Fn mixer_get_dev "struct mixer *m" "int devno"
.Ft struct mix_dev *
.Fn mixer_get_dev_byname "struct mixer *m" "name"
.Ft int
.Fn mixer_add_ctl "struct mix_dev *parent" "int id" "const char *name" \
    "int (*mod)(struct mix_dev *d, void *p)" \
    "int (*print)(struct mix_dev *d, void *p)
.Ft int
.Fn mixer_add_ctl_s "mix_ctl_t *ctl"
.Ft int
.Fn mixer_remove_ctl "mix_ctl_t *ctl"
.Ft mix_ctl_t *
.Fn mixer_get_ctl "struct mix_dev *d" "int id"
.Ft mix_ctl_t *
.Fn mixer_get_ctl_byname "struct mix_dev *d" "const char *name"
.Ft int
.Fn mixer_set_vol "struct mixer *m" "mix_volume_t vol"
.Ft int
.Fn mixer_set_mute "struct mixer *m" "int opt"
.Ft int
.Fn mixer_mod_recsrc "struct mixer *m" "int opt"
.Ft int
.Fn mixer_get_dunit "void"
.Ft int
.Fn mixer_set_dunit "struct mixer *m" "int unit"
.Ft int
.Fn mixer_get_mode "int unit"
.Ft int
.Fn mixer_get_nmixers "void"
.Ft int
.Fn MIX_ISDEV "struct mixer *m" "int devno"
.Ft int
.Fn MIX_ISMUTE "struct mixer *m" "int devno"
.Ft int
.Fn MIX_ISREC "struct mixer *m" "int devno"
.Ft int
.Fn MIX_ISRECSRC "struct mixer *m" "int devno"
.Ft float
.Fn MIX_VOLNORM "int v"
.Ft int
.Fn MIX_VOLDENORM "float v"
.Sh DESCRIPTION
The
.Nm mixer
library allows userspace programs to access and manipulate OSS sound mixers in
a simple way.
.Ss Mixer
.Pp
A mixer is described by the following structure:
.Bd -literal
struct mixer {
	TAILQ_HEAD(, mix_dev) devs;		/* device list */
	struct mix_dev *dev;			/* selected device */
	oss_mixerinfo mi;			/* mixer info */
	oss_card_info ci;			/* audio card info */
	char name[NAME_MAX];			/* mixer name (e.g /dev/mixer0) */
	int fd;					/* file descriptor */
	int unit;				/* audio card unit */
	int ndev;				/* number of devices */
	int devmask;				/* supported devices */
#define MIX_MUTE		0x01
#define MIX_UNMUTE		0x02
#define MIX_TOGGLEMUTE		0x04
	int mutemask;				/* muted devices */
	int recmask;				/* recording devices */
#define MIX_ADDRECSRC		0x01
#define MIX_REMOVERECSRC	0x02
#define MIX_SETRECSRC		0x04
#define MIX_TOGGLERECSRC	0x08
	int recsrc;				/* recording sources */
#define MIX_MODE_MIXER		0x01
#define MIX_MODE_PLAY		0x02
#define MIX_MODE_REC		0x04
	int mode;				/* dev.pcm.X.mode sysctl */
	int f_default;				/* default mixer flag */
};
.Ed
.Pp
The fields are follows:
.Bl -tag -width "f_default"
.It Fa devs
A tail queue structure containing all supported mixer devices.
.It Fa dev
A pointer to the currently selected device. The device is one of the elements in
.Ar devs .
.It Fa mi
OSS information about the mixer. Look at the definition of the
.Ft oss_mixerinfo
structure in
.In sys/soundcard.h
to see its fields.
.It Fa ci
OSS audio card information. This structure is also defined in
.In sys/soundcard.h .
.It Fa name
Path to the mixer (e.g /dev/mixer0).
.It Fa fd
File descriptor returned when the mixer is opened in
.Fn mixer_open .
.It Fa unit
Audio card unit. Since each mixer device maps to a pcmX device,
.Ar unit
is always equal to the number of that pcmX device. For example, if the audio
device's number is 0 (i.e pcm0), then
.Ar unit
is 0 as well. This number is useful when checking if the mixer's audio
card is the default one.
.It Fa ndev
Number of devices in
.Ar devs .
.It Fa devmask
Bit mask containing all supported devices for the mixer. For example
if device 10 is supported, then the 10th bit in the mask will be set. By default,
.Fn mixer_open
stores only the supported devices in devs, so it's very unlikely this mask will
be needed.
.It Fa mutemask
Bit mask containing all muted devices. The logic is the same as with
.Ar devmask .
.It Fa recmask
Bit mask containing all recording devices. Again, same logic as with the
other masks.
.It Fa recsrc
Bit mask containing all recording sources. Yes, same logic again.
.It Fa mode
Bit mask containing the supported modes for this audio device. It holds the value
of the
.Ar dev.pcm.X.mode
sysctl.
.It Fa f_default
Flag which tells whether the mixer's audio card is the default one.
.El
.Ss Mixer device
.Pp
Each mixer device stored in a mixer is described as follows:
.Bd -literal
struct mix_dev {
	struct mixer *parent_mixer;		/* parent mixer */
	char name[NAME_MAX];			/* device name (e.g "vol") */
	int devno;				/* device number */
	struct mix_volume {
#define MIX_VOLMIN		0.0f
#define MIX_VOLMAX		1.0f
#define MIX_VOLNORM(v)		((v) / 100.0f)
#define MIX_VOLDENORM(v)	((int)((v) * 100.0f + 0.5f))
		float left;			/* left volume */
		float right;			/* right volume */
	} vol;
	int nctl;				/* number of controls */
	TAILQ_HEAD(, mix_ctl) ctls;		/* control list */
	TAILQ_ENTRY(mix_dev) devs;
};
.Ed
.Pp
The fields are follows:
.Bl -tag -width "parent_mixer"
.It Fa parent_mixer
Pointer to the mixer the device is attached to.
.It Fa name
Device name given by the OSS API. Devices can have one of the following names:
.Bd -ragged
vol, bass, treble, synth, pcm, speaker, line, mic, cd, mix,
pcm2, rec, igain, ogain, line1, line2, line3, dig1, dig2, dig3,
phin, phout, video, radio, and monitor.
.Ed
.It Fa devno
Device's index in the SOUND_MIXER_NRDEVICES macro defined in
.In sys/soundcard.h .
This number is used to check against the masks defined in the
.Ar mixer
structure.
.It Fa left, right
Left and right-ear volumes. Although the OSS API stores volumes in integers from
0-100, we normalize them to 32-bit floating point numbers. However, the volumes
can be denormalized using the
.Ar MIX_VOLDENORM
macro if needed.
.It Fa nctl
Number of user-defined mixer controls associated with the device.
.It Fa ctls
A tail queue containing user-defined mixer controls.
.El
.Ss User-defined mixer controls
.Pp
Each mixer device can have user-defined controls. The control structure
is defined as follows:
.Bd -literal
struct mix_ctl {
	struct mix_dev *parent_dev;		/* parent device */
	int id;					/* control id */
	char name[NAME_MAX];			/* control name */
	int (*mod)(struct mix_dev *, void *);	/* modify control values */
	int (*print)(struct mix_dev *, void *);	/* print control */
	TAILQ_ENTRY(mix_ctl) ctls;
};
.Ed
.Pp
The fields are follows:
.Bl -tag -width "parent_dev"
.It Fa parent_dev
Pointer to the device the control is attached to.
.It Fa id
Control ID assigned by the caller. Even though the library will
report it, care has to be taken to not give a control the same ID in case
the caller has to choose controls using their ID.
.It Fa name
Control name. As with
.Ar id ,
the caller has to make sure the same name is not used more than once.
.It Fa mod
Function pointer to a control modification function. As in
.Xr mixer 8 ,
each mixer control's values can be modified. For example, if we have a
volume control, the
.Ar mod
function will be responsible for handling volume changes.
.It Fa print
Function pointer to a control print function.
.El
.Ss Opening and closing the mixer
.Pp
The application must first call the
.Fn mixer_open
function to obtain a handle to the device, which is used as an argument
in most other functions and macros. The parameter
.Ar name
specifies the path to the mixer. OSS mixers are stored under
.Ar /dev/mixerN
where
.Ar N
is the number of the mixer device. Each device maps to an actual
.Ar pcm
audio card, so
.Ar /dev/mixer0
is the mixer for
.Ar pcm0 ,
and so on. If
.Ar name
is
.Ar NULL
or
.Ar /dev/mixer ,
.Fn mixer_open
opens the default mixer (hw.snd.defaul_unit).
.Pp
The
.Fn mixer_close
function frees resources and closes the mixer device. It's a good practice to
always call it when the application is done using the mixer.
.Ss Manipulating the mixer
.Pp
The
.Fn mixer_get_dev
and
.Fn mixer_get_dev_byname
functions select a mixer device, either by its number or by its name
respectively. The mixer structure keeps a list of all the devices, but only
one can be manipulated at a time. Each time a new device is to be manipulated,
one of the two functions has to be called.
.Pp
The
.Fn mixer_set_vol
function changes the volume of the selected mixer device. The
.Ar vol
parameter is a structure that stores the left and right volumes of a given
device. The allowed volume values are between MIX_VOLMIN (0.0) and
MIX_VOLMAX (1.0).
.Pp
The
.Fn mixer_set_mute
function modifies the mute of a selected device. The
.Ar opt
parameter has to be one of the following options:
.Bl -tag -width MIX_TOGGLEMUTE -offset indent
.It Dv MIX_MUTE
Mute the device.
.It Dv MIX_UNMUTE
Unmute the device.
.It Dv MIX_TOGGLEMUTE
Toggle the device's mute (e.g mute if unmuted and unmute if muted).
.El
.Pp
The
.Fn mixer_mod_recsrc
function modifies a recording device. The selected device has to be
a recording device, otherwise the function will fail. The
.Ar opt
parameter has to be one of the following options:
.Bl -tag -width MIX_REMOVERECSRC -offset indent
.It Dv MIX_ADDRECSRC
Add device to the recording sources.
.It Dv MIX_REMOVERECSRC
Remove device from the recording sources.
.It Dv MIX_SETRECSRC
Set device as the only recording source.
.It Dv MIX_TOGGLERECSRC
Toggle device from the recording sources.
.El
.Pp
The
.Fn mixer_get_dunit
and
.Fn mixer_set_dunit
functions get and set the default audio card in the system. Although this is
not really a mixer feature, it's useful to have instead of having to use
the
.Xr sysctl 3
controls.
.Pp
The
.Fn mixer_get_mode
function returns the playback/recording mode of the audio device the mixer
belongs to. The available values are the following:
.Bl -tag -width "MIX_STATUS_PLAY | MIX_STATUS_REC" -offset indent
.It Dv MIX_STATUS_NONE
Neither playback nor recording.
.It Dv MIX_STATUS_PLAY
Playback.
.It Dv MIX_STATUS_REC
Recording.
.It Dv MIX_STATUS_PLAY | MIX_STATUS_REC
Playback and recording.
.El
.Pp
The
.Fn mixer_get_nmixers
function returns the total number of mixer devices in the system.
.Pp
The
.Fn MIX_ISDEV
macro checks if a device is actually a valid device for a given mixer. It's very
unlikely that this macro will ever be needed since the library stores only
valid devices by default.
.Pp
The
.Fn MIX_ISMUTE
macro checks if a device is muted.
.Pp
The
.Fn MIX_ISREC
macro checks if a device is a recording device.
.Pp
The
.Fn MIX_ISRECSRC
macro checks if a device is a recording source.
.Pp
The
.Fn MIX_VOLNORM
macro normalizes a value to 32-bit floating point number. It's used
to normalize the volumes read from the OSS API.
.Pp
The
.Fn MIX_VOLDENORM
macro denormalizes the left and right volumes stores in the
.Ft mix_dev
structure.
.Ss Defining and using mixer controls
.Pp
The
.Fn mix_add_ctl
function creates a control and attaches it to the device specified in the
.Ar parent
argument.
.Pp
The
.Fn mix_add_ctl_s
function does the same thing as with
.Fn mix_add_ctl
but the caller passes a
.Ft mix_ctl_t *
structure instead of each field as a seperate argument.
.Pp
The
.Fn mixer_remove_ctl
functions removes a control from the device its attached to.
.Pp
The
.Fn mixer_get_ctl
function searches for a control in the device specified in the
.Ar d
argument and returns a pointer to it. The search is done using the control's ID.
.Pp
The
.Fn mixer_get_ctl_byname
function is the same as with
.Fn mixer_get_ctl
but the search is done using the control's name.
.Sh RETURN VALUES
.Pp
The
.Fn mixer_open
function returns the newly created handle on success and NULL on failure.
.Pp
The
.Fn mixer_close ,
.Fn mixer_set_vol ,
.Fn mixer_set_mute ,
.Fn mixer_mod_recsrc ,
.Fn mixer_get_dunut ,
.Fn mixer_set_dunit
and
.Fn mixer_get_nmixers
functions return 0 or positive values on success and -1 on failure.
.Pp
The
.Fn mixer_get_dev
and
.Fn mixer_get_dev_byname
functions return the selected device on success and NULL on failure.
.Pp
All functions set the value of
.Ar errno
on failure.
.Sh EXAMPLES
.Ss Change the volume of a device
.Bd -literal
struct mixer *m;
mix_volume_t vol;
char *mix_name, *dev_name;

mix_name = ...;
if ((m = mixer_open(mix_name)) == NULL)
	err(1, "mixer_open: %s", mix_name);

dev_name = ...;
if ((m->dev = mixer_get_dev_byname(m, dev_name)) < 0)
	err(1, "unknown device: %s", dev_name);

vol.left = ...;
vol.right = ....;
if (mixer_set_vol(m, vol) < 0)
	warn("cannot change volume");

(void)mixer_close(m);
.Ed
.Ss Mute all unmuted devices
.Bd -literal
struct mixer *m;
struct mix_dev *dp;

if ((m = mixer_open(NULL)) == NULL)	/* Open the default mixer. */
	err(1, "mixer_open");
TAILQ_FOREACH(dp, &m->devs, devs) {
	m->dev = dp;			/* Select device. */
	if (M_ISMUTE(m, dp->devno))
		continue;
	if (mixer_set_mute(m, MIX_MUTE) < 0)
		warn("cannot mute device: %s", dp->name);
}

(void)mixer_close(m);
.Ed
.Ss Print all recording sources' names and volumes
.Bd -literal
struct mixer *m;
struct mix_dev *dp;

char *mix_name, *dev_name;

mix_name = ...;
if ((m = mixer_open(mix_name)) == NULL)
	err(1, "mixer_open: %s", mix_name);

TAILQ_FOREACH(dp, &m->devs, devs) {
	if (M_ISRECSRC(m, dp->devno))
		printf("%s\\t%.2f:%.2f\\n",
		    dp->name, dp->vol.left, dp->vol.right);
}

(void)mixer_close(m);
.Ed
.Sh SEE ALSO
.Xr mixer 8 ,
.Xr sound 4 ,
.Xr sysctl 3 ,
.Xr queue 3
and
.Xr errno 2
.Sh AUTHORS
.An Christos Margiolis Aq Mt christos@FreeBSD.org