aft: Honor AUDIO_FILE_REMOVE events.
[paraslash.git] / oss_mix.c
1 /* Copyright (C) 1998 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
2
3 /** \file oss_mix.c The OSS mixer plugin. */
4
5 #include <sys/soundcard.h>
6 #include <sys/ioctl.h>
7 #include <regex.h>
8
9 #include "para.h"
10 #include "error.h"
11 #include "mix.h"
12 #include "fd.h"
13 #include "string.h"
14
15 struct oss_mixer_channel {
16         const char *name;
17         int id;
18 };
19
20 static const struct oss_mixer_channel channels[] = {
21         {.name = "volume", .id = SOUND_MIXER_VOLUME},
22         {.name = "bass", .id = SOUND_MIXER_BASS},
23         {.name = "treble", .id = SOUND_MIXER_TREBLE},
24         {.name = "synth", .id = SOUND_MIXER_SYNTH},
25         {.name = "pcm", .id = SOUND_MIXER_PCM},
26         {.name = "speaker", .id = SOUND_MIXER_SPEAKER},
27         {.name = "line", .id = SOUND_MIXER_LINE},
28         {.name = "mic", .id = SOUND_MIXER_MIC},
29         {.name = "cd", .id = SOUND_MIXER_CD},
30         {.name = "imix", .id = SOUND_MIXER_IMIX},
31         {.name = "altpcm", .id = SOUND_MIXER_ALTPCM},
32         {.name = "reclev", .id = SOUND_MIXER_RECLEV},
33         {.name = "igain", .id = SOUND_MIXER_IGAIN},
34         {.name = "ogain", .id = SOUND_MIXER_OGAIN},
35 };
36
37 /** Iterate over all defined mixer channels. */
38 #define FOR_EACH_CHANNEL(i) for ((i) = 0; (i) < ARRAY_SIZE(channels); (i)++)
39
40 struct mixer_handle {
41         int fd;
42         int id;
43 };
44
45 static int oss_mix_open(const char *dev, struct mixer_handle **handle)
46 {
47         int ret;
48         struct mixer_handle *h;
49
50         *handle = NULL;
51         if (!dev)
52                 dev = "/dev/mixer";
53         PARA_INFO_LOG("opening %s\n", dev);
54         ret = para_open(dev, O_RDWR, 42);
55         if (ret < 0) {
56                 PARA_ERROR_LOG("could not open %s\n", dev);
57                 return ret;
58         }
59         h = para_malloc(sizeof(*h));
60         h->fd = ret;
61         *handle = h;
62         return 1;
63 }
64
65 static char *oss_mix_get_channels(__a_unused struct mixer_handle *handle)
66 {
67         int i;
68         char *list = NULL;
69
70         FOR_EACH_CHANNEL(i) {
71                 const char *name = channels[i].name;
72                 char *tmp = list;
73                 list = make_message("%s%s%s",
74                         list? list : "",
75                         list? ", " : "",
76                         name);
77                 free(tmp);
78         }
79         return list;
80 }
81
82 static int oss_mix_set_channel(struct mixer_handle *handle,
83                 const char *mixer_channel)
84 {
85         int i;
86
87         if (!mixer_channel) {
88                 handle->id = SOUND_MIXER_VOLUME; /* default */
89                 return 0;
90         }
91         FOR_EACH_CHANNEL(i) {
92                 if (strcasecmp(channels[i].name, mixer_channel))
93                         continue;
94                 handle->id = i;
95                 return 1;
96         }
97         return -E_BAD_CHANNEL;
98 }
99
100 static int oss_mix_get(struct mixer_handle *handle)
101 {
102         int val, fd = handle->fd, id = handle->id;
103
104         if (ioctl(fd, MIXER_READ(id), &val) < 0)
105                 return -ERRNO_TO_PARA_ERROR(errno);
106         /* take the mean value of left and right */
107         return (val % 256 + (val >> 8)) / 2;
108 }
109
110 static int oss_mix_set(struct mixer_handle *handle, int val)
111 {
112         int fd = handle->fd, id = handle->id, tmp = (val << 8) + val;
113
114         if (ioctl(fd, MIXER_WRITE(id), &tmp) < 0)
115                 return -ERRNO_TO_PARA_ERROR(errno);
116         return 1;
117 }
118
119 static void oss_mix_close(struct mixer_handle **handle)
120 {
121         struct mixer_handle *h;
122
123         if (!handle)
124                 return;
125         h = *handle;
126         if (h) {
127                 if (h->fd >= 0)
128                         close(h->fd);
129                 free(h);
130         }
131         *handle = NULL;
132 }
133
134 /** The mixer operations for the OSS mixer. */
135 const struct mixer oss_mixer = {
136         .name = "oss",
137         .open = oss_mix_open,
138         .get_channels = oss_mix_get_channels,
139         .set_channel = oss_mix_set_channel,
140         .close = oss_mix_close,
141         .get = oss_mix_get,
142         .set = oss_mix_set
143 };