source: roaraudio/roard/driver_oss.c @ 1518:5d7a197eceb6

Last change on this file since 1518:5d7a197eceb6 was 1518:5d7a197eceb6, checked in by phi, 15 years ago

reordered a lot code within oss driver, should be more flexible now

File size: 8.7 KB
Line 
1//driver_oss.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2008
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, 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 */
24
25#include "roard.h"
26#if defined(ROAR_HAVE_OSS_BSD) || defined(ROAR_HAVE_OSS)
27
28struct driver_oss {
29 char * device;
30 int fh;
31 int blocks;
32 int blocksize;
33 struct roar_audio_info info;
34};
35
36#define _get(vio,obj) (((struct driver_oss*)((vio)->inst))->obj)
37
38ssize_t driver_oss_write    (struct roar_vio_calls * vio, void *buf, size_t count);
39int     driver_oss_nonblock (struct roar_vio_calls * vio, int state);
40int     driver_oss_close_vio(struct roar_vio_calls * vio);
41
42int driver_oss_init_vio(struct roar_vio_calls * vio, struct driver_oss * inst) {
43 if ( vio == NULL )
44  return -1;
45
46 memset(vio, 0, sizeof(struct roar_vio_calls));
47
48 vio->write    = driver_oss_write;
49 vio->nonblock = driver_oss_nonblock;
50 vio->sync     = driver_oss_sync;
51 vio->ctl      = driver_oss_ctl;
52 vio->close    = driver_oss_close_vio;
53
54 vio->inst     = (void*) inst;
55
56 return 0;
57}
58
59int driver_oss_open_device(struct driver_oss * self) {
60 int    fh     = self->fh;
61 char * device = self->device;
62
63 if ( fh != -1 )
64  return 0;
65
66#ifdef ROAR_DEFAULT_OSS_DEV
67 if ( device == NULL )
68  device = ROAR_DEFAULT_OSS_DEV;
69#endif
70
71 if ( device == NULL ) {
72  ROAR_ERR("driver_oss_open_device(*): no default device found, you need to specify one manuelly");
73  return -1;
74 }
75
76 if ( (fh = open(device, O_WRONLY, 0644)) == -1 ) {
77  ROAR_ERR("driver_oss_open_device(*): Can not open OSS device: %s: %s", device, strerror(errno));
78  return -1;
79 }
80
81 self->fh = fh;
82
83 return 0;
84}
85
86int driver_oss_config_device(struct driver_oss * self) {
87 int                      fh   =   self->fh;
88 struct roar_audio_info * info = &(self->info);
89 int tmp, ctmp;
90 char * es;
91
92 if ( fh == -1 )
93  return -1;
94
95#ifdef SNDCTL_DSP_CHANNELS
96 tmp = info->channels;
97
98 if ( ioctl(fh, SNDCTL_DSP_CHANNELS, &tmp) == -1 ) {
99  ROAR_ERR("driver_oss_open(*): can not set number of channels");
100  return -1;
101 }
102
103 if ( tmp != info->channels ) {
104   ROAR_ERR("driver_oss_open(*): can not set requested numer of channels, OSS suggested %i channels, to use this restart with -oO channels=%i or set codec manuelly via -oO channels=num", tmp, tmp);
105  return -1;
106 }
107#else
108 switch (info->channels) {
109  case  1: tmp = 0; break;
110  case  2: tmp = 1; break;
111  default: return -1;
112 }
113
114 if ( ioctl(fh, SNDCTL_DSP_STEREO, &tmp) == -1 ) {
115  ROAR_ERR("driver_oss_open(*): can not set number of channels");
116  return -1;
117 }
118#endif
119
120 switch (info->codec) {
121  case ROAR_CODEC_PCM_S_LE:
122    switch (info->bits) {
123     case  8: tmp = AFMT_S8;     break;
124     case 16: tmp = AFMT_S16_LE; break;
125//     case 24: tmp = AFMT_S24_PACKED; break;
126#ifdef AFMT_S32_LE
127     case 32: tmp = AFMT_S32_LE; break;
128#endif
129     default: return -1;
130    }
131   break;
132  case ROAR_CODEC_PCM_S_BE:
133    switch (info->bits) {
134     case  8: tmp = AFMT_S8;     break;
135     case 16: tmp = AFMT_S16_BE; break;
136//     case 24: tmp = AFMT_S24_PACKED; break;
137#ifdef AFMT_S32_BE
138     case 32: tmp = AFMT_S32_BE; break;
139#endif
140     default: return -1;
141    }
142   break;
143  case ROAR_CODEC_PCM_U_LE:
144    switch (info->bits) {
145     case  8: tmp = AFMT_U8;     break;
146     case 16: tmp = AFMT_U16_LE; break;
147     default: return -1;
148    }
149   break;
150  case ROAR_CODEC_PCM_U_BE:
151    switch (info->bits) {
152     case  8: tmp = AFMT_U8;     break;
153     case 16: tmp = AFMT_U16_BE; break;
154     default: return -1;
155    }
156  case ROAR_CODEC_ALAW:
157    tmp = AFMT_A_LAW;
158   break;
159  case ROAR_CODEC_MULAW:
160    tmp = AFMT_MU_LAW;
161   break;
162#ifdef AFMT_VORBIS
163  case ROAR_CODEC_OGG_VORBIS:
164    tmp = AFMT_VORBIS;
165   break;
166#endif
167  default:
168    return -1;
169   break;
170 }
171
172 ctmp = tmp;
173#ifdef SNDCTL_DSP_SETFMT
174 if ( ioctl(fh, SNDCTL_DSP_SETFMT, &tmp) == -1 ) {
175#else
176 if ( ioctl(fh, SNDCTL_DSP_SAMPLESIZE, &tmp) == -1 ) {
177#endif
178  ROAR_ERR("driver_oss_open(*): can not set sample format");
179  return -1;
180 }
181
182 if ( tmp != ctmp ) {
183  es = NULL;
184  switch (tmp) {
185   case AFMT_S8    : es = "bits=8,codec=pcm";       break;
186   case AFMT_U8    : es = "bits=8,codec=pcm_u_le";  break;
187   case AFMT_S16_LE: es = "bits=16,codec=pcm_s_le"; break;
188   case AFMT_S16_BE: es = "bits=16,codec=pcm_s_be"; break;
189   case AFMT_U16_LE: es = "bits=16,codec=pcm_u_le"; break;
190   case AFMT_U16_BE: es = "bits=16,codec=pcm_u_be"; break;
191#ifdef AFMT_S32_LE
192   case AFMT_S32_LE: es = "bits=32,codec=pcm_s_le"; break;
193#endif
194#ifdef AFMT_S32_BE
195   case AFMT_S32_BE: es = "bits=32,codec=pcm_s_be"; break;
196#endif
197   case AFMT_A_LAW : es = "codec=alaw";             break;
198   case AFMT_MU_LAW: es = "codec=mulaw";            break;
199#ifdef AFMT_VORBIS
200   case AFMT_VORBIS: es = "codec=ogg_vorbis";       break;
201#endif
202  }
203
204  if ( es != NULL ) {
205   ROAR_ERR("driver_oss_open(*): can not set requested codec, OSS retruned another codec than requested, to use this restart with -oO %s or set codec manuelly via -oO codec=somecodec", es);
206  } else {
207   ROAR_ERR("driver_oss_open(*): can not set requested codec, set codec manuelly via -oO codec=somecodec");
208  }
209  return -1;
210 }
211
212 tmp = info->rate;
213
214 if ( ioctl(fh, SNDCTL_DSP_SPEED, &tmp) == -1 ) {
215  ROAR_ERR("driver_oss_open(*): can not set sample rate");
216  return -1;
217 }
218
219 if ( tmp < info->rate * 0.98 || tmp > info->rate * 1.02 ) {
220  ROAR_ERR("driver_oss_open(*): sample rate out of acceptable accuracy");
221  return -1;
222 }
223
224 return 0;
225}
226
227#define er() close(self->fh); if ( self->device ) free(self->device); free(self); return -1
228int driver_oss_open(struct roar_vio_calls * inst, char * device, struct roar_audio_info * info, int fh) {
229 struct driver_oss * self = NULL;
230 uint32_t tmp32;
231
232 if ( (self = malloc(sizeof(struct driver_oss))) == NULL ) {
233  ROAR_ERR("driver_oss_open(*): Can not malloc() instance data: %s", strerror(errno));
234  return -1;
235 }
236
237 memset(self, 0, sizeof(struct driver_oss));
238 memcpy(&(self->info), info, sizeof(struct roar_audio_info));
239
240 self->fh = fh;
241
242 if ( device != NULL )
243  self->device = strdup(device);
244
245 if ( driver_oss_init_vio(inst, self) == -1 ) {
246  ROAR_ERR("driver_oss_open(*): Can not init vio interface");
247  er();
248 }
249
250 if ( driver_oss_open_device(self) == -1 ) {
251  ROAR_ERR("driver_oss_open(*): Can not open audio device");
252  er();
253 }
254
255 if ( driver_oss_config_device(self) == -1 ) {
256  ROAR_ERR("driver_oss_open(*): Can not configure audio device");
257  er();
258 }
259
260 tmp32 = 4;
261 driver_oss_ctl(inst, ROAR_VIO_CTL_SET_DBLOCKS, &tmp32);
262
263 ROAR_DBG("driver_oss_open(*): OSS devices opened :)");
264
265 return 0;
266}
267#undef er
268
269int driver_oss_close(DRIVER_USERDATA_T   inst) {
270 return roar_vio_close((struct roar_vio_calls *)inst);
271}
272
273int     driver_oss_close_vio(struct roar_vio_calls * vio) {
274 close(_get(vio,fh));
275
276 if ( _get(vio,device) != NULL )
277  free(_get(vio,device));
278
279 free(vio->inst);
280 return 0;
281}
282
283int     driver_oss_nonblock(struct roar_vio_calls * vio, int state) {
284 if ( roar_socket_nonblock(_get(vio,fh), state) == -1 )
285  return -1;
286
287 if ( state == ROAR_SOCKET_NONBLOCK )
288  return 0;
289
290 roar_vio_sync(vio);
291
292 return 0;
293}
294
295int driver_oss_sync(struct roar_vio_calls * vio) {
296#ifdef SNDCTL_DSP_SYNC
297 return ioctl(_get(vio,fh), SNDCTL_DSP_SYNC, NULL);
298#else
299 return 0;
300#endif
301}
302
303int driver_oss_ctl(struct roar_vio_calls * vio, int cmd, void * data) {
304 int d;
305
306 if ( vio == NULL )
307  return -1;
308
309 switch (cmd) {
310  case ROAR_VIO_CTL_GET_DELAY:
311#ifdef SNDCTL_DSP_GETODELAY
312    if ( ioctl(_get(vio,fh), SNDCTL_DSP_GETODELAY, &d) == -1 )
313     return -1;
314
315    ROAR_DBG("driver_oss_ctl(*): delay=%i byte", d);
316
317    *(uint_least32_t *)data = d;
318#else
319    return -1;
320#endif
321   break;
322  case ROAR_VIO_CTL_SET_DBLOCKS:
323#ifdef SNDCTL_DSP_SETFRAGMENT
324    d = (*(uint_least32_t *)data) << 16 | 11; // (*data) fragements of 2048 Bytes.
325    if ( ioctl(_get(vio,fh), SNDCTL_DSP_SETFRAGMENT, &d) == -1 ) {
326     ROAR_WARN("driver_oss_ctl(*): Can not set fragment size, sorry :(");
327    }
328#else
329    return -1;
330#endif
331   break;
332  case ROAR_VIO_CTL_GET_DBLKSIZE:
333    *(uint_least32_t *)data = 2048;
334    return 0;
335   break;
336  default:
337   return -1;
338 }
339
340 return 0;
341}
342
343ssize_t driver_oss_write   (struct roar_vio_calls * vio, void *buf, size_t count) {
344 return write(_get(vio,fh), buf, count);
345}
346
347#endif
348//ll
Note: See TracBrowser for help on using the repository browser.