source: roaraudio/roard/hwmixer_oss.c @ 4708:c9d40761088a

Last change on this file since 4708:c9d40761088a was 4708:c9d40761088a, checked in by phi, 13 years ago

updated copyright statements

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