source: roaraudio/roard/hwmixer_oss.c @ 4391:f86f7695815f

Last change on this file since 4391:f86f7695815f was 4391:f86f7695815f, checked in by phi, 14 years ago

added more controls

File size: 9.7 KB
Line 
1//hwmixer_oss.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010
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 size_t i;
134
135 if ( vio == NULL ) {
136  return -1;
137 }
138
139 if ( fh == -1 ) {
140#ifdef ROAR_DEFAULT_OSS_MIX_DEV
141  if ( dev == NULL ) {
142   dev = ROAR_DEFAULT_OSS_MIX_DEV;
143  }
144#endif
145
146  if ( dev == NULL ) {
147   roar_mm_free(vio);
148   return -1;
149  }
150
151  if ( roar_vio_dstr_init_defaults(&def, ROAR_VIO_DEF_TYPE_FILE, O_RDWR, 0644) == -1 ) {
152   roar_mm_free(vio);
153   return -1;
154  }
155
156  if ( roar_vio_open_dstr(vio, dev, &def, 1) == -1 ) {
157   roar_mm_free(vio);
158   return -1;
159  }
160 } else {
161  if ( roar_vio_open_fh(vio, fh) == -1 ) {
162   roar_mm_free(vio);
163   return -1;
164  }
165 }
166
167 stream->baseud = vio;
168
169 ctl.cmd  = SOUND_MIXER_READ_DEVMASK;
170 ctl.argp = &devmask;
171
172 if ( roar_vio_ctl(vio, ROAR_VIO_CTL_SYSIO_IOCTL, &ctl) == -1 ) {
173  roar_vio_close(vio);
174  roar_mm_free(vio);
175  return -1;
176 }
177
178 ctl.cmd  = SOUND_MIXER_READ_STEREODEVS;
179 ctl.argp = &sdevmask;
180
181 if ( roar_vio_ctl(vio, ROAR_VIO_CTL_SYSIO_IOCTL, &ctl) == -1 ) {
182  sdevmask = 0;
183 }
184
185 if ( subnamelen == 0 ) {
186  kv.key   = "Master";
187  kv.value = NULL;
188
189  if ( hwmixer_oss_open_stream(stream, devmask, sdevmask, basename, &kv) == -1 ) {
190   roar_vio_close(vio);
191   roar_mm_free(vio);
192   return -1;
193  }
194 } else {
195  if ( hwmixer_oss_open_stream(stream, devmask, sdevmask, basename, subnames) == -1 ) {
196   roar_vio_close(vio);
197   roar_mm_free(vio);
198   return -1;
199  }
200
201  for (i = 1; i < subnamelen; i++) {
202   cstream = hwmixer_substream_new(stream);
203   if ( hwmixer_oss_open_stream(cstream, devmask, sdevmask, basename, &(subnames[i])) == -1 ) {
204    roar_vio_close(vio);
205    roar_mm_free(vio);
206    return -1;
207   }
208  }
209 }
210
211
212#ifdef TEST_HWMIXER_SUBSTREAMS
213 stream = hwmixer_substream_new(stream);
214 if ( stream == NULL ) {
215  ROAR_WARN("hwmixer_dstr_open(*): can not create substream");
216 } else {
217  if (streams_get(stream->stream, &ss) != -1) {
218   ROAR_STREAM(ss)->info.channels = 2;
219  } else {
220   ROAR_WARN("hwmixer_dstr_open(*): can not get object for stream %i", stream->stream);
221  }
222 }
223#endif
224
225 return 0;
226}
227
228int hwmixer_oss_close(struct hwmixer_stream * stream) {
229 // are we a substream? if yes we do not clean up anything.
230 // streams_delete() will do all our work.
231
232 roar_mm_free(stream->ud);
233
234 if ( stream->stream != stream->basestream )
235  return 0;
236
237 roar_vio_close(stream->baseud);
238 roar_mm_free(stream->baseud);
239 return 0;
240}
241
242int hwmixer_oss_set_vol(struct hwmixer_stream * stream, int channels, int mode, struct roar_mixer_settings * settings) {
243 struct roar_vio_calls * vio = stream->baseud;
244 struct roar_vio_sysio_ioctl ctl;
245 struct subdev         * subdev = stream->ud;
246 int i;
247 int l, r;
248
249 if ( channels == 0 )
250  return 0;
251
252 if ( channels == 1 ) {
253  l = r = settings->mixer[0];
254 } else {
255  l = settings->mixer[0];
256  r = settings->mixer[1];
257 }
258
259 if ( subdev->channels == 1 ) {
260  l = r = (l + r) / 2;
261 }
262
263 l = (l * OSS_VOLUME_SCALE) / settings->scale;
264 r = (r * OSS_VOLUME_SCALE) / settings->scale;
265
266 i = (l & 0xFF) | ((r & 0xFF) << 8);
267
268 ctl.cmd = subdev->cmd_write;
269 ctl.argp = &i;
270
271 return roar_vio_ctl(vio, ROAR_VIO_CTL_SYSIO_IOCTL, &ctl);
272}
273
274int hwmixer_oss_get_vol(struct hwmixer_stream * stream, int channels, int mode, struct roar_mixer_settings * settings) {
275 struct roar_vio_calls * vio = stream->baseud;
276 struct roar_vio_sysio_ioctl ctl;
277 struct subdev         * subdev = stream->ud;
278 int i;
279 int l, r;
280
281 ctl.cmd = subdev->cmd_read;
282 ctl.argp = &i;
283
284 if ( roar_vio_ctl(vio, ROAR_VIO_CTL_SYSIO_IOCTL, &ctl) == -1 )
285  return -1;
286
287 l =  i       & 0xFF;
288 r = (i >> 8) & 0xFF;
289
290 if ( subdev->channels == 1 )
291  r = l;
292
293 settings->scale    = OSS_VOLUME_SCALE;
294
295 if ( channels == 1 ) {
296  settings->mixer[0] = (l + r) / 2;
297 } else if ( channels == 2 ) {
298  settings->mixer[0] = l;
299  settings->mixer[1] = r;
300 } else {
301  return -1;
302 }
303
304 return 0;
305}
306
307#endif
308
309//ll
Note: See TracBrowser for help on using the repository browser.