source: roaraudio/roard/driver_oss.c @ 1526:9f95e23b46e0

Last change on this file since 1526:9f95e23b46e0 was 1526:9f95e23b46e0, checked in by phi, 15 years ago

set need_config flag in open_device() and do not set explicitly values which are defaults anyway...

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