source: roaraudio/roard/hwmixer_oss.c @ 4390:7df0ee32543e

Last change on this file since 4390:7df0ee32543e was 4390:7df0ee32543e, checked in by phi, 14 years ago

ckeck for OSS, do not assume it's presense

File size: 6.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 {"PCM",    {.bit = SOUND_MASK_PCM,    .cmd_read = SOUND_MIXER_READ_PCM,    .cmd_write = SOUND_MIXER_WRITE_PCM}},
44 {NULL}
45};
46
47static int hwmixer_oss_open_stream(struct hwmixer_stream * stream, int devmask, int sdevmask, char * basename, struct roar_keyval * subname) {
48 struct subdev * subdev;
49 struct subdev * source_subdev = NULL;
50 struct roar_stream_server * ss;
51 const char * reqname = subname->value;
52 int i;
53 char name[80];
54
55 for (i = 0; g_subdevs[i].name != NULL; i++) {
56  if ( !strcasecmp(subname->key, g_subdevs[i].name) ) {
57   source_subdev = &(g_subdevs[i].subdev);
58   if ( reqname == NULL )
59    reqname = g_subdevs[i].name;
60   break;
61  }
62 }
63
64 if ( source_subdev == NULL )
65  return -1;
66
67 if ( !(devmask & source_subdev->bit) )
68  return -1;
69
70 subdev = roar_mm_malloc(sizeof(struct subdev));
71
72 if ( subdev == NULL )
73  return -1;
74
75 memcpy(subdev, source_subdev, sizeof(struct subdev));
76
77 subdev->channels = sdevmask & subdev->bit ? 2 : 1;
78
79 stream->ud     = subdev;
80
81 if ( basename == NULL ) {
82  streams_set_name(stream->stream, reqname);
83 } else {
84  snprintf(name, sizeof(name)-1, "%s/%s", basename, reqname);
85  name[sizeof(name)-1] = 0;
86  streams_set_name(stream->stream, name);
87 }
88
89 if (streams_get(stream->stream, &ss) != -1) {
90  ROAR_STREAM(ss)->info.channels = subdev->channels;
91 } else {
92  ROAR_WARN("hwmixer_dstr_open(*): can not get object for stream %i", stream->stream);
93 }
94
95 return 0;
96}
97
98int hwmixer_oss_open(struct hwmixer_stream * stream, char * drv, char * dev, int fh, char * basename, struct roar_keyval * subnames, size_t subnamelen) {
99 struct roar_vio_calls * vio = roar_mm_malloc(sizeof(struct roar_vio_calls));
100 struct roar_vio_defaults def;
101 struct roar_vio_sysio_ioctl ctl;
102 struct roar_keyval kv;
103 struct hwmixer_stream * cstream;
104 int devmask, sdevmask;
105 size_t i;
106
107 if ( vio == NULL ) {
108  return -1;
109 }
110
111 if ( fh == -1 ) {
112#ifdef ROAR_DEFAULT_OSS_MIX_DEV
113  if ( dev == NULL ) {
114   dev = ROAR_DEFAULT_OSS_MIX_DEV;
115  }
116#endif
117
118  if ( dev == NULL ) {
119   roar_mm_free(vio);
120   return -1;
121  }
122
123  if ( roar_vio_dstr_init_defaults(&def, ROAR_VIO_DEF_TYPE_FILE, O_RDWR, 0644) == -1 ) {
124   roar_mm_free(vio);
125   return -1;
126  }
127
128  if ( roar_vio_open_dstr(vio, dev, &def, 1) == -1 ) {
129   roar_mm_free(vio);
130   return -1;
131  }
132 } else {
133  if ( roar_vio_open_fh(vio, fh) == -1 ) {
134   roar_mm_free(vio);
135   return -1;
136  }
137 }
138
139 stream->baseud = vio;
140
141 ctl.cmd  = SOUND_MIXER_READ_DEVMASK;
142 ctl.argp = &devmask;
143
144 if ( roar_vio_ctl(vio, ROAR_VIO_CTL_SYSIO_IOCTL, &ctl) == -1 ) {
145  roar_vio_close(vio);
146  roar_mm_free(vio);
147  return -1;
148 }
149
150 ctl.cmd  = SOUND_MIXER_READ_STEREODEVS;
151 ctl.argp = &sdevmask;
152
153 if ( roar_vio_ctl(vio, ROAR_VIO_CTL_SYSIO_IOCTL, &ctl) == -1 ) {
154  sdevmask = 0;
155 }
156
157 if ( subnamelen == 0 ) {
158  kv.key   = "Volume";
159  kv.value = NULL;
160
161  if ( hwmixer_oss_open_stream(stream, devmask, sdevmask, basename, &kv) == -1 ) {
162   roar_vio_close(vio);
163   roar_mm_free(vio);
164   return -1;
165  }
166 } else {
167  if ( hwmixer_oss_open_stream(stream, devmask, sdevmask, basename, subnames) == -1 ) {
168   roar_vio_close(vio);
169   roar_mm_free(vio);
170   return -1;
171  }
172
173  for (i = 1; i < subnamelen; i++) {
174   cstream = hwmixer_substream_new(stream);
175   if ( hwmixer_oss_open_stream(cstream, devmask, sdevmask, basename, &(subnames[i])) == -1 ) {
176    roar_vio_close(vio);
177    roar_mm_free(vio);
178    return -1;
179   }
180  }
181 }
182
183
184#ifdef TEST_HWMIXER_SUBSTREAMS
185 stream = hwmixer_substream_new(stream);
186 if ( stream == NULL ) {
187  ROAR_WARN("hwmixer_dstr_open(*): can not create substream");
188 } else {
189  if (streams_get(stream->stream, &ss) != -1) {
190   ROAR_STREAM(ss)->info.channels = 2;
191  } else {
192   ROAR_WARN("hwmixer_dstr_open(*): can not get object for stream %i", stream->stream);
193  }
194 }
195#endif
196
197 return 0;
198}
199
200int hwmixer_oss_close(struct hwmixer_stream * stream) {
201 // are we a substream? if yes we do not clean up anything.
202 // streams_delete() will do all our work.
203
204 roar_mm_free(stream->ud);
205
206 if ( stream->stream != stream->basestream )
207  return 0;
208
209 roar_vio_close(stream->baseud);
210 roar_mm_free(stream->baseud);
211 return 0;
212}
213
214int hwmixer_oss_set_vol(struct hwmixer_stream * stream, int channels, int mode, struct roar_mixer_settings * settings) {
215 struct roar_vio_calls * vio = stream->baseud;
216 struct roar_vio_sysio_ioctl ctl;
217 struct subdev         * subdev = stream->ud;
218 int i;
219 int l, r;
220
221 if ( channels == 0 )
222  return 0;
223
224 if ( channels == 1 ) {
225  l = r = settings->mixer[0];
226 } else {
227  l = settings->mixer[0];
228  r = settings->mixer[1];
229 }
230
231 if ( subdev->channels == 1 ) {
232  l = r = (l + r) / 2;
233 }
234
235 l = (l * OSS_VOLUME_SCALE) / settings->scale;
236 r = (r * OSS_VOLUME_SCALE) / settings->scale;
237
238 i = (l & 0xFF) | ((r & 0xFF) << 8);
239
240 ctl.cmd = subdev->cmd_write;
241 ctl.argp = &i;
242
243 return roar_vio_ctl(vio, ROAR_VIO_CTL_SYSIO_IOCTL, &ctl);
244}
245
246int hwmixer_oss_get_vol(struct hwmixer_stream * stream, int channels, int mode, struct roar_mixer_settings * settings) {
247 struct roar_vio_calls * vio = stream->baseud;
248 struct roar_vio_sysio_ioctl ctl;
249 struct subdev         * subdev = stream->ud;
250 int i;
251 int l, r;
252
253 ctl.cmd = subdev->cmd_read;
254 ctl.argp = &i;
255
256 if ( roar_vio_ctl(vio, ROAR_VIO_CTL_SYSIO_IOCTL, &ctl) == -1 )
257  return -1;
258
259 l =  i       & 0xFF;
260 r = (i >> 8) & 0xFF;
261
262 if ( subdev->channels == 1 )
263  r = l;
264
265 settings->scale    = OSS_VOLUME_SCALE;
266
267 if ( channels == 1 ) {
268  settings->mixer[0] = (l + r) / 2;
269 } else if ( channels == 2 ) {
270  settings->mixer[0] = l;
271  settings->mixer[1] = r;
272 } else {
273  return -1;
274 }
275
276 return 0;
277}
278
279#endif
280
281//ll
Note: See TracBrowser for help on using the repository browser.