source: roaraudio/roard/hwmixer_oss.c @ 4389:346c516e9ce1

Last change on this file since 4389:346c516e9ce1 was 4389:346c516e9ce1, checked in by phi, 14 years ago

get substreams based on subnames working

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