source: roaraudio/roard/hwmixer_oss.c @ 5381:430b1d26e12d

Last change on this file since 5381:430b1d26e12d was 5381:430b1d26e12d, checked in by phi, 12 years ago

updated copyright years

File size: 9.9 KB
Line 
1//hwmixer_oss.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2012
5 *
6 *  This file is part of roard a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  RoarAudio is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 */
25
26#include "roard.h"
27
28#ifndef ROAR_WITHOUT_DCOMP_MIXER
29
30#if defined(ROAR_HAVE_OSS_BSD) || defined(ROAR_HAVE_OSS)
31
32#define OSS_VOLUME_SCALE 100
33
34struct subdev {
35 int bit;
36 int channels;
37 long long int cmd_read, cmd_write;
38};
39
40static struct subdev_map {
41 const char * name;
42 struct subdev subdev;
43} g_subdevs[] = {
44 {"Volume",  {.bit = SOUND_MASK_VOLUME,  .cmd_read = SOUND_MIXER_READ_VOLUME,  .cmd_write = SOUND_MIXER_WRITE_VOLUME  }},
45 {"Bass",    {.bit = SOUND_MASK_BASS,    .cmd_read = SOUND_MIXER_READ_BASS,    .cmd_write = SOUND_MIXER_WRITE_BASS    }},
46 {"Treble",  {.bit = SOUND_MASK_TREBLE,  .cmd_read = SOUND_MIXER_READ_TREBLE,  .cmd_write = SOUND_MIXER_WRITE_TREBLE  }},
47 {"Synth",   {.bit = SOUND_MASK_SYNTH,   .cmd_read = SOUND_MIXER_READ_SYNTH,   .cmd_write = SOUND_MIXER_WRITE_SYNTH   }},
48 {"PCM",     {.bit = SOUND_MASK_PCM,     .cmd_read = SOUND_MIXER_READ_PCM,     .cmd_write = SOUND_MIXER_WRITE_PCM     }},
49 {"Speaker", {.bit = SOUND_MASK_SPEAKER, .cmd_read = SOUND_MIXER_READ_SPEAKER, .cmd_write = SOUND_MIXER_WRITE_SPEAKER }},
50 {"Line",    {.bit = SOUND_MASK_LINE,    .cmd_read = SOUND_MIXER_READ_LINE,    .cmd_write = SOUND_MIXER_WRITE_LINE    }},
51 {"Mic",     {.bit = SOUND_MASK_MIC,     .cmd_read = SOUND_MIXER_READ_MIC,     .cmd_write = SOUND_MIXER_WRITE_MIC     }},
52 {"CD",      {.bit = SOUND_MASK_CD,      .cmd_read = SOUND_MIXER_READ_CD,      .cmd_write = SOUND_MIXER_WRITE_CD      }},
53 {"Imix",    {.bit = SOUND_MASK_IMIX,    .cmd_read = SOUND_MIXER_READ_IMIX,    .cmd_write = SOUND_MIXER_WRITE_IMIX    }},
54 {"AltPCM",  {.bit = SOUND_MASK_ALTPCM,  .cmd_read = SOUND_MIXER_READ_ALTPCM,  .cmd_write = SOUND_MIXER_WRITE_ALTPCM  }},
55 {"Reclev",  {.bit = SOUND_MASK_RECLEV,  .cmd_read = SOUND_MIXER_READ_RECLEV,  .cmd_write = SOUND_MIXER_WRITE_RECLEV  }},
56 {"IGain",   {.bit = SOUND_MASK_IGAIN,   .cmd_read = SOUND_MIXER_READ_IGAIN,   .cmd_write = SOUND_MIXER_WRITE_IGAIN   }},
57 {"OGain",   {.bit = SOUND_MASK_OGAIN,   .cmd_read = SOUND_MIXER_READ_OGAIN,   .cmd_write = SOUND_MIXER_WRITE_OGAIN   }},
58 {"Line1",   {.bit = SOUND_MASK_LINE1,   .cmd_read = SOUND_MIXER_READ_LINE1,   .cmd_write = SOUND_MIXER_WRITE_LINE1   }},
59 {"Line2",   {.bit = SOUND_MASK_LINE2,   .cmd_read = SOUND_MIXER_READ_LINE2,   .cmd_write = SOUND_MIXER_WRITE_LINE2   }},
60 {"Line3",   {.bit = SOUND_MASK_LINE3,   .cmd_read = SOUND_MIXER_READ_LINE3,   .cmd_write = SOUND_MIXER_WRITE_LINE3   }},
61/*
62 {"Digital1", {.bit = SOUND_MASK_DIGITAL1, .cmd_read = SOUND_MIXER_READ_DIGITAL1, .cmd_write = SOUND_MIXER_WRITE_DIGITAL1}},
63 {"Digital2", {.bit = SOUND_MASK_DIGITAL2, .cmd_read = SOUND_MIXER_READ_DIGITAL2, .cmd_write = SOUND_MIXER_WRITE_DIGITAL2}},
64 {"Digital3", {.bit = SOUND_MASK_DIGITAL3, .cmd_read = SOUND_MIXER_READ_DIGITAL3, .cmd_write = SOUND_MIXER_WRITE_DIGITAL3}},
65 {"PhoneIn", {.bit = SOUND_MASK_PHONEIN, .cmd_read = SOUND_MIXER_READ_PHONEIN, .cmd_write = SOUND_MIXER_WRITE_PHONEIN }},
66 {"PhoneOut", {.bit = SOUND_MASK_PHONEOUT, .cmd_read = SOUND_MIXER_READ_PHONEOUT, .cmd_write = SOUND_MIXER_WRITE_PHONEOUT}},
67 {"Radio",   {.bit = SOUND_MASK_RADIO,   .cmd_read = SOUND_MIXER_READ_RADIO,   .cmd_write = SOUND_MIXER_WRITE_RADIO   }},
68 {"Video",   {.bit = SOUND_MASK_VIDEO,   .cmd_read = SOUND_MIXER_READ_VIDEO,   .cmd_write = SOUND_MIXER_WRITE_VIDEO   }},
69 {"Monitor", {.bit = SOUND_MASK_MONITOR, .cmd_read = SOUND_MIXER_READ_MONITOR, .cmd_write = SOUND_MIXER_WRITE_MONITOR }},
70*/
71 // Alias with better name:
72 {"Master",  {.bit = SOUND_MASK_VOLUME,  .cmd_read = SOUND_MIXER_READ_VOLUME,  .cmd_write = SOUND_MIXER_WRITE_VOLUME  }},
73 {"PCM2",    {.bit = SOUND_MASK_ALTPCM,  .cmd_read = SOUND_MIXER_READ_ALTPCM,  .cmd_write = SOUND_MIXER_WRITE_ALTPCM  }},
74 {NULL}
75};
76
77static int hwmixer_oss_open_stream(struct hwmixer_stream * stream, int devmask, int sdevmask, char * basename, struct roar_keyval * subname) {
78 struct subdev * subdev;
79 struct subdev * source_subdev = NULL;
80 struct roar_stream_server * ss;
81 const char * reqname = subname->value;
82 int i;
83 char name[80];
84
85 for (i = 0; g_subdevs[i].name != NULL; i++) {
86  if ( !strcasecmp(subname->key, g_subdevs[i].name) ) {
87   source_subdev = &(g_subdevs[i].subdev);
88   if ( reqname == NULL )
89    reqname = g_subdevs[i].name;
90   break;
91  }
92 }
93
94 if ( source_subdev == NULL )
95  return -1;
96
97 if ( !(devmask & source_subdev->bit) )
98  return -1;
99
100 subdev = roar_mm_malloc(sizeof(struct subdev));
101
102 if ( subdev == NULL )
103  return -1;
104
105 memcpy(subdev, source_subdev, sizeof(struct subdev));
106
107 subdev->channels = sdevmask & subdev->bit ? 2 : 1;
108
109 stream->ud     = subdev;
110
111 if ( basename == NULL ) {
112  streams_set_name(stream->stream, (char*)reqname);
113 } else {
114  snprintf(name, sizeof(name)-1, "%s/%s", basename, reqname);
115  name[sizeof(name)-1] = 0;
116  streams_set_name(stream->stream, name);
117 }
118
119 if (streams_get(stream->stream, &ss) != -1) {
120  ROAR_STREAM(ss)->info.channels = subdev->channels;
121 } else {
122  ROAR_WARN("hwmixer_dstr_open(*): can not get object for stream %i", stream->stream);
123 }
124
125 return 0;
126}
127
128int hwmixer_oss_open(struct hwmixer_stream * stream, char * drv, char * dev, int fh, char * basename, struct roar_keyval * subnames, size_t subnamelen) {
129 struct roar_vio_calls * vio = roar_mm_malloc(sizeof(struct roar_vio_calls));
130 struct roar_vio_defaults def;
131 struct roar_vio_sysio_ioctl ctl;
132 struct roar_keyval kv;
133 struct hwmixer_stream * cstream;
134 int devmask, sdevmask;
135 mixer_info info;
136 size_t i;
137
138 if ( vio == NULL ) {
139  return -1;
140 }
141
142 if ( fh == -1 ) {
143#ifdef ROAR_DEFAULT_OSS_MIX_DEV
144  if ( dev == NULL ) {
145   dev = ROAR_DEFAULT_OSS_MIX_DEV;
146  }
147#endif
148
149  if ( dev == NULL ) {
150   roar_mm_free(vio);
151   return -1;
152  }
153
154  if ( roar_vio_dstr_init_defaults(&def, ROAR_VIO_DEF_TYPE_FILE, O_RDWR, 0644) == -1 ) {
155   roar_mm_free(vio);
156   return -1;
157  }
158
159  if ( roar_vio_open_dstr(vio, dev, &def, 1) == -1 ) {
160   roar_mm_free(vio);
161   return -1;
162  }
163 } else {
164  if ( roar_vio_open_fh(vio, fh) == -1 ) {
165   roar_mm_free(vio);
166   return -1;
167  }
168 }
169
170 stream->baseud = vio;
171
172 ctl.cmd  = SOUND_MIXER_READ_DEVMASK;
173 ctl.argp = &devmask;
174
175 if ( roar_vio_ctl(vio, ROAR_VIO_CTL_SYSIO_IOCTL, &ctl) == -1 ) {
176  roar_vio_close(vio);
177  roar_mm_free(vio);
178  return -1;
179 }
180
181 ctl.cmd  = SOUND_MIXER_READ_STEREODEVS;
182 ctl.argp = &sdevmask;
183
184 if ( roar_vio_ctl(vio, ROAR_VIO_CTL_SYSIO_IOCTL, &ctl) == -1 ) {
185  sdevmask = 0;
186 }
187
188 if ( basename == NULL ) {
189  ctl.cmd  = SOUND_MIXER_INFO;
190  ctl.argp = &info;
191
192  if ( roar_vio_ctl(vio, ROAR_VIO_CTL_SYSIO_IOCTL, &ctl) == 0 ) {
193   basename = info.name;
194  }
195 }
196
197 if ( subnamelen == 0 ) {
198  kv.key   = "Master";
199  kv.value = NULL;
200
201  if ( hwmixer_oss_open_stream(stream, devmask, sdevmask, basename, &kv) == -1 ) {
202   roar_vio_close(vio);
203   roar_mm_free(vio);
204   return -1;
205  }
206 } else {
207  if ( hwmixer_oss_open_stream(stream, devmask, sdevmask, basename, subnames) == -1 ) {
208   roar_vio_close(vio);
209   roar_mm_free(vio);
210   return -1;
211  }
212
213  for (i = 1; i < subnamelen; i++) {
214   cstream = hwmixer_substream_new(stream);
215   if ( hwmixer_oss_open_stream(cstream, devmask, sdevmask, basename, &(subnames[i])) == -1 ) {
216    roar_vio_close(vio);
217    roar_mm_free(vio);
218    return -1;
219   }
220  }
221 }
222
223
224#ifdef TEST_HWMIXER_SUBSTREAMS
225 stream = hwmixer_substream_new(stream);
226 if ( stream == NULL ) {
227  ROAR_WARN("hwmixer_dstr_open(*): can not create substream");
228 } else {
229  if (streams_get(stream->stream, &ss) != -1) {
230   ROAR_STREAM(ss)->info.channels = 2;
231  } else {
232   ROAR_WARN("hwmixer_dstr_open(*): can not get object for stream %i", stream->stream);
233  }
234 }
235#endif
236
237 return 0;
238}
239
240int hwmixer_oss_close(struct hwmixer_stream * stream) {
241 // are we a substream? if yes we do not clean up anything.
242 // streams_delete() will do all our work.
243
244 roar_mm_free(stream->ud);
245
246 if ( stream->stream != stream->basestream )
247  return 0;
248
249 roar_vio_close(stream->baseud);
250 roar_mm_free(stream->baseud);
251 return 0;
252}
253
254int hwmixer_oss_set_vol(struct hwmixer_stream * stream, int channels, int mode, struct roar_mixer_settings * settings) {
255 struct roar_vio_calls * vio = stream->baseud;
256 struct roar_vio_sysio_ioctl ctl;
257 struct subdev         * subdev = stream->ud;
258 int i;
259 int l, r;
260
261 if ( channels == 0 )
262  return 0;
263
264 if ( channels == 1 ) {
265  l = r = settings->mixer[0];
266 } else {
267  l = settings->mixer[0];
268  r = settings->mixer[1];
269 }
270
271 if ( subdev->channels == 1 ) {
272  l = r = (l + r) / 2;
273 }
274
275 l = (l * OSS_VOLUME_SCALE) / settings->scale;
276 r = (r * OSS_VOLUME_SCALE) / settings->scale;
277
278 i = (l & 0xFF) | ((r & 0xFF) << 8);
279
280 ctl.cmd = subdev->cmd_write;
281 ctl.argp = &i;
282
283 return roar_vio_ctl(vio, ROAR_VIO_CTL_SYSIO_IOCTL, &ctl);
284}
285
286int hwmixer_oss_get_vol(struct hwmixer_stream * stream, int channels, int mode, struct roar_mixer_settings * settings) {
287 struct roar_vio_calls * vio = stream->baseud;
288 struct roar_vio_sysio_ioctl ctl;
289 struct subdev         * subdev = stream->ud;
290 int i;
291 int l, r;
292
293 ctl.cmd = subdev->cmd_read;
294 ctl.argp = &i;
295
296 if ( roar_vio_ctl(vio, ROAR_VIO_CTL_SYSIO_IOCTL, &ctl) == -1 )
297  return -1;
298
299 l =  i       & 0xFF;
300 r = (i >> 8) & 0xFF;
301
302 if ( subdev->channels == 1 )
303  r = l;
304
305 settings->scale    = OSS_VOLUME_SCALE;
306
307 if ( channels == 1 ) {
308  settings->mixer[0] = (l + r) / 2;
309 } else if ( channels == 2 ) {
310  settings->mixer[0] = l;
311  settings->mixer[1] = r;
312 } else {
313  return -1;
314 }
315
316 return 0;
317}
318
319#endif
320
321#endif
322
323//ll
Note: See TracBrowser for help on using the repository browser.