source: roaraudio/roard/driver_oss.c @ 1521:1ecaaea92527

Last change on this file since 1521:1ecaaea92527 was 1521:1ecaaea92527, checked in by phi, 15 years ago

do seting of framents on first write

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