source: roaraudio/roard/driver_oss.c @ 1542:db6dd41ef52a

Last change on this file since 1542:db6dd41ef52a was 1541:7b51b5ded747, checked in by phi, 15 years ago

codecs needing a cf can not be autoconfigured yet

File size: 13.7 KB
RevLine 
[916]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
[1518]28struct driver_oss {
29 char * device;
30 int fh;
31 int blocks;
32 int blocksize;
33 struct roar_audio_info info;
[1521]34 int need_reopen;
35 int need_config;
[1527]36 struct roar_stream_server * stream;
[1530]37 int ssid;
[1518]38};
39
40#define _get(vio,obj) (((struct driver_oss*)((vio)->inst))->obj)
41
42ssize_t driver_oss_write    (struct roar_vio_calls * vio, void *buf, size_t count);
43int     driver_oss_nonblock (struct roar_vio_calls * vio, int state);
44int     driver_oss_close_vio(struct roar_vio_calls * vio);
[1539]45int     driver_oss_reopen_device(struct driver_oss * self);
[1518]46
47int driver_oss_init_vio(struct roar_vio_calls * vio, struct driver_oss * inst) {
48 if ( vio == NULL )
49  return -1;
[919]50
[1518]51 memset(vio, 0, sizeof(struct roar_vio_calls));
52
53 vio->write    = driver_oss_write;
54 vio->nonblock = driver_oss_nonblock;
55 vio->sync     = driver_oss_sync;
56 vio->ctl      = driver_oss_ctl;
57 vio->close    = driver_oss_close_vio;
58
59 vio->inst     = (void*) inst;
60
61 return 0;
62}
63
64int driver_oss_open_device(struct driver_oss * self) {
65 int    fh     = self->fh;
66 char * device = self->device;
67
68 if ( fh != -1 )
69  return 0;
[919]70
[924]71#ifdef ROAR_DEFAULT_OSS_DEV
[919]72 if ( device == NULL )
73  device = ROAR_DEFAULT_OSS_DEV;
[924]74#endif
75
76 if ( device == NULL ) {
[1518]77  ROAR_ERR("driver_oss_open_device(*): no default device found, you need to specify one manuelly");
78  return -1;
79 }
80
81 if ( (fh = open(device, O_WRONLY, 0644)) == -1 ) {
82  ROAR_ERR("driver_oss_open_device(*): Can not open OSS device: %s: %s", device, strerror(errno));
[924]83  return -1;
84 }
[919]85
[1526]86 self->fh          = fh;
87 self->need_config = 1;
[1518]88
89 return 0;
90}
[919]91
[1518]92int driver_oss_config_device(struct driver_oss * self) {
93 int                      fh   =   self->fh;
94 struct roar_audio_info * info = &(self->info);
95 int tmp, ctmp;
96 char * es;
[1532]97 int autoconfig         = 0;
98 int need_update_server = 0;
[919]99
[1518]100 if ( fh == -1 )
101  return -1;
[945]102
[1532]103 if ( self->ssid != -1 ) {
104  autoconfig = streams_get_flag(self->ssid, ROAR_FLAG_AUTOCONF);
105 }
106
[1533]107 ROAR_DBG("driver_oss_config_device(self=%p): ssid=%i, autoconfig=%i", self, self->ssid, autoconfig);
[1532]108
[945]109#ifdef SNDCTL_DSP_CHANNELS
110 tmp = info->channels;
111
112 if ( ioctl(fh, SNDCTL_DSP_CHANNELS, &tmp) == -1 ) {
[1533]113  ROAR_ERR("driver_oss_config_device(*): can not set number of channels");
[1518]114  return -1;
[945]115 }
116
117 if ( tmp != info->channels ) {
[1532]118  if ( autoconfig ) {
119   need_update_server = 1;
120   self->info.channels = tmp;
121  } else {
[1533]122   ROAR_ERR("driver_oss_config_device(*): 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);
[1532]123   return -1;
124  }
[945]125 }
126#else
[919]127 switch (info->channels) {
128  case  1: tmp = 0; break;
129  case  2: tmp = 1; break;
[1518]130  default: return -1;
[919]131 }
132
133 if ( ioctl(fh, SNDCTL_DSP_STEREO, &tmp) == -1 ) {
[1533]134  ROAR_ERR("driver_oss_config_device(*): can not set number of channels");
[1518]135  return -1;
[919]136 }
[945]137#endif
[919]138
[942]139 switch (info->codec) {
140  case ROAR_CODEC_PCM_S_LE:
141    switch (info->bits) {
142     case  8: tmp = AFMT_S8;     break;
143     case 16: tmp = AFMT_S16_LE; break;
144//     case 24: tmp = AFMT_S24_PACKED; break;
145#ifdef AFMT_S32_LE
146     case 32: tmp = AFMT_S32_LE; break;
147#endif
[1518]148     default: return -1;
[942]149    }
150   break;
151  case ROAR_CODEC_PCM_S_BE:
152    switch (info->bits) {
153     case  8: tmp = AFMT_S8;     break;
154     case 16: tmp = AFMT_S16_BE; break;
155//     case 24: tmp = AFMT_S24_PACKED; break;
156#ifdef AFMT_S32_BE
157     case 32: tmp = AFMT_S32_BE; break;
158#endif
[1518]159     default: return -1;
[942]160    }
161   break;
162  case ROAR_CODEC_PCM_U_LE:
163    switch (info->bits) {
164     case  8: tmp = AFMT_U8;     break;
165     case 16: tmp = AFMT_U16_LE; break;
[1518]166     default: return -1;
[919]167    }
168   break;
[942]169  case ROAR_CODEC_PCM_U_BE:
170    switch (info->bits) {
171     case  8: tmp = AFMT_U8;     break;
172     case 16: tmp = AFMT_U16_BE; break;
[1518]173     default: return -1;
[942]174    }
175  case ROAR_CODEC_ALAW:
176    tmp = AFMT_A_LAW;
177   break;
178  case ROAR_CODEC_MULAW:
179    tmp = AFMT_MU_LAW;
180   break;
181#ifdef AFMT_VORBIS
182  case ROAR_CODEC_OGG_VORBIS:
183    tmp = AFMT_VORBIS;
184   break;
185#endif
186  default:
[1518]187    return -1;
[942]188   break;
189 }
190
191 ctmp = tmp;
[946]192#ifdef SNDCTL_DSP_SETFMT
193 if ( ioctl(fh, SNDCTL_DSP_SETFMT, &tmp) == -1 ) {
194#else
[942]195 if ( ioctl(fh, SNDCTL_DSP_SAMPLESIZE, &tmp) == -1 ) {
[946]196#endif
[1533]197  ROAR_ERR("driver_oss_config_device(*): can not set sample format");
[1518]198  return -1;
[919]199 }
200
[942]201 if ( tmp != ctmp ) {
[1532]202  if ( autoconfig ) {
203   need_update_server = 1;
204   switch (tmp) {
205    case AFMT_S8    : self->info.bits =  8; self->info.codec = ROAR_CODEC_PCM;      break;
206    case AFMT_U8    : self->info.bits =  8; self->info.codec = ROAR_CODEC_PCM_U_LE; break;
207    case AFMT_S16_LE: self->info.bits = 16; self->info.codec = ROAR_CODEC_PCM_S_LE; break;
208    case AFMT_S16_BE: self->info.bits = 16; self->info.codec = ROAR_CODEC_PCM_S_BE; break;
209    case AFMT_U16_LE: self->info.bits = 16; self->info.codec = ROAR_CODEC_PCM_U_LE; break;
210    case AFMT_U16_BE: self->info.bits = 16; self->info.codec = ROAR_CODEC_PCM_U_BE; break;
[942]211#ifdef AFMT_S32_LE
[1532]212    case AFMT_S32_LE: self->info.bits = 32; self->info.codec = ROAR_CODEC_PCM_S_LE; break;
[942]213#endif
214#ifdef AFMT_S32_BE
[1532]215    case AFMT_S32_BE: self->info.bits = 32; self->info.codec = ROAR_CODEC_PCM_S_BE; break;
216#endif
[1541]217/*
[1532]218    case AFMT_A_LAW : self->info.bits =  8; self->info.codec = ROAR_CODEC_ALAW;     break;
219    case AFMT_MU_LAW: self->info.bits =  8; self->info.codec = ROAR_CODEC_MULAW;    break;
220#ifdef AFMT_VORBIS
221    case AFMT_VORBIS: self->info.codec = ROAR_CODEC_OGG_VORBIS;                     break;
[942]222#endif
[1541]223*/
224    case AFMT_A_LAW:
225    case AFMT_MU_LAW:
226#ifdef AFMT_VORBIS
227    case AFMT_VORBIS:
228#endif
229      ROAR_WARN("driver_oss_config_device(*): Auto config failed: OSS Codec %i needs a codecfilter!", tmp);
230      ROAR_ERR("driver_oss_config_device(*): can not set requested codec, set codec manuelly via -oO codec=somecodec");
231      return -1;
232     break;
[1532]233    default:
234      ROAR_WARN("driver_oss_config_device(*): Auto config failed: unknown OSS Codec %i", tmp);
235      ROAR_ERR("driver_oss_config_device(*): can not set requested codec, set codec manuelly via -oO codec=somecodec");
[1541]236      return -1;
[1532]237     break;
238   }
239  } else {
240   es = NULL;
241   switch (tmp) {
242    case AFMT_S8    : es = "bits=8,codec=pcm";       break;
243    case AFMT_U8    : es = "bits=8,codec=pcm_u_le";  break;
244    case AFMT_S16_LE: es = "bits=16,codec=pcm_s_le"; break;
245    case AFMT_S16_BE: es = "bits=16,codec=pcm_s_be"; break;
246    case AFMT_U16_LE: es = "bits=16,codec=pcm_u_le"; break;
247    case AFMT_U16_BE: es = "bits=16,codec=pcm_u_be"; break;
248#ifdef AFMT_S32_LE
249    case AFMT_S32_LE: es = "bits=32,codec=pcm_s_le"; break;
250#endif
251#ifdef AFMT_S32_BE
252    case AFMT_S32_BE: es = "bits=32,codec=pcm_s_be"; break;
253#endif
254    case AFMT_A_LAW : es = "codec=alaw";             break;
255    case AFMT_MU_LAW: es = "codec=mulaw";            break;
[942]256#ifdef AFMT_VORBIS
[1532]257    case AFMT_VORBIS: es = "codec=ogg_vorbis";       break;
[942]258#endif
[1532]259   }
260
261   if ( es != NULL ) {
[1533]262    ROAR_ERR("driver_oss_config_device(*): 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);
[1532]263   } else {
[1533]264    ROAR_ERR("driver_oss_config_device(*): can not set requested codec, set codec manuelly via -oO codec=somecodec");
[1532]265   }
266   return -1;
[942]267  }
[919]268 }
269
270 tmp = info->rate;
271
272 if ( ioctl(fh, SNDCTL_DSP_SPEED, &tmp) == -1 ) {
[1533]273  ROAR_ERR("driver_oss_config_device(*): can not set sample rate");
[1518]274  return -1;
[919]275 }
276
[1530]277 if ( tmp != info->rate ) {
[1532]278  if ( autoconfig ) {
279   need_update_server = 1;
280   self->info.rate = tmp;
281  } else {
282   ROAR_WARN("driver_oss_config_device(*): Device does not support requested sample rate: req=%iHz, sug=%iHz",
283                     info->rate, tmp);
[1530]284
[1532]285   if ( tmp < info->rate * 0.98 || tmp > info->rate * 1.02 ) {
[1533]286    ROAR_ERR("driver_oss_config_device(*): sample rate out of acceptable accuracy");
[1532]287    return -1;
288   }
[1530]289  }
[1518]290 }
291
[1521]292 // latency things:
293#ifdef SNDCTL_DSP_SETFRAGMENT
294
295 // defaults
296 if ( self->blocksize < 1 )
297  self->blocksize = 2048;
298 if ( self->blocks < 1 )
299  self->blocks    =    4;
300
[1523]301 switch (self->blocksize) {
302  case 1<< 4: tmp =  4; break;
303  case 1<< 5: tmp =  5; break;
304  case 1<< 6: tmp =  6; break;
305  case 1<< 7: tmp =  7; break;
306  case 1<< 8: tmp =  8; break;
307  case 1<< 9: tmp =  9; break;
308  case 1<<10: tmp = 10; break;
309  case 1<<11: tmp = 11; break;
310  case 1<<12: tmp = 12; break;
311  case 1<<13: tmp = 13; break;
312  case 1<<14: tmp = 14; break;
313  case 1<<15: tmp = 15; break;
314  case 1<<16: tmp = 16; break;
315  default: tmp = 11;
316    ROAR_WARN("driver_oss_config_device(*): blocksize of %i byte is not a valid value. trying 2KB", self->blocksize);
317   break;
318 }
319
[1524]320 ROAR_DBG("driver_oss_config_device(*): blocksize=%i(N=%i), blocks=%i", self->blocksize, tmp, self->blocks);
[1521]321
322 tmp |= self->blocks << 16;
323 if ( ioctl(fh, SNDCTL_DSP_SETFRAGMENT, &tmp) == -1 ) {
324  ROAR_WARN("driver_oss_ctl(*): Can not set fragment size, sorry :(");
325 }
326#endif
327
[1532]328 if ( need_update_server ) {
329  if ( self->stream == NULL ) {
330   streams_get(self->ssid, &(self->stream));
331  }
332
333  if ( self->stream == NULL ) {
334   ROAR_ERR("driver_oss_config_device(*): Auto config failed: can not set new values for stream: no stream object known");
335   return -1;
336  }
337
338  memcpy(&(ROAR_STREAM(self->stream)->info), info, sizeof(struct roar_audio_info));
339 }
340
[1521]341 self->need_config = 0;
342
[1518]343 return 0;
344}
345
346#define er() close(self->fh); if ( self->device ) free(self->device); free(self); return -1
347int driver_oss_open(struct roar_vio_calls * inst, char * device, struct roar_audio_info * info, int fh) {
348 struct driver_oss * self = NULL;
349
350 if ( (self = malloc(sizeof(struct driver_oss))) == NULL ) {
351  ROAR_ERR("driver_oss_open(*): Can not malloc() instance data: %s", strerror(errno));
352  return -1;
353 }
354
355 memset(self, 0, sizeof(struct driver_oss));
356 memcpy(&(self->info), info, sizeof(struct roar_audio_info));
357
[1530]358 self->ssid = -1;
359 self->fh   = fh;
[1518]360
361 if ( device != NULL )
362  self->device = strdup(device);
363
364 if ( driver_oss_init_vio(inst, self) == -1 ) {
365  ROAR_ERR("driver_oss_open(*): Can not init vio interface");
[919]366  er();
367 }
368
[1518]369 if ( driver_oss_open_device(self) == -1 ) {
370  ROAR_ERR("driver_oss_open(*): Can not open audio device");
371  er();
372 }
373
[935]374 ROAR_DBG("driver_oss_open(*): OSS devices opened :)");
[934]375
[919]376 return 0;
[917]377}
[1518]378#undef er
[917]379
[1539]380int     driver_oss_reopen_device(struct driver_oss * self) {
381#ifdef SNDCTL_DSP_SYNC
382 ioctl(self->fh, SNDCTL_DSP_SYNC, NULL);
383#endif
384
385 close(self->fh);
386
387 if ( driver_oss_open_device(self) == -1 )
388  return -1;
389
390 self->need_config = 1;
391
392 return 0;
393}
394
[917]395int driver_oss_close(DRIVER_USERDATA_T   inst) {
[1242]396 return roar_vio_close((struct roar_vio_calls *)inst);
[917]397}
398
[1518]399int     driver_oss_close_vio(struct roar_vio_calls * vio) {
400 close(_get(vio,fh));
401
402 if ( _get(vio,device) != NULL )
403  free(_get(vio,device));
404
405 free(vio->inst);
406 return 0;
407}
408
409int     driver_oss_nonblock(struct roar_vio_calls * vio, int state) {
410 if ( roar_socket_nonblock(_get(vio,fh), state) == -1 )
411  return -1;
412
413 if ( state == ROAR_SOCKET_NONBLOCK )
414  return 0;
415
416 roar_vio_sync(vio);
417
418 return 0;
419}
420
[1138]421int driver_oss_sync(struct roar_vio_calls * vio) {
422#ifdef SNDCTL_DSP_SYNC
[1518]423 return ioctl(_get(vio,fh), SNDCTL_DSP_SYNC, NULL);
[1138]424#else
425 return 0;
426#endif
427}
[916]428
[1151]429int driver_oss_ctl(struct roar_vio_calls * vio, int cmd, void * data) {
[1521]430 struct driver_oss * self = vio->inst;
[1538]431#ifdef SNDCTL_DSP_GETODELAY
[1151]432 int d;
[1538]433#endif
[1151]434
[1524]435 ROAR_DBG("driver_oss_ctl(vio=%p, cmd=0x%.8x, data=%p) = ?", vio, cmd, data);
[1521]436
[1151]437 if ( vio == NULL )
438  return -1;
439
[1222]440 switch (cmd) {
441  case ROAR_VIO_CTL_GET_DELAY:
442#ifdef SNDCTL_DSP_GETODELAY
[1518]443    if ( ioctl(_get(vio,fh), SNDCTL_DSP_GETODELAY, &d) == -1 )
[1222]444     return -1;
445
446    ROAR_DBG("driver_oss_ctl(*): delay=%i byte", d);
[1151]447
[1222]448    *(uint_least32_t *)data = d;
449#else
450    return -1;
451#endif
452   break;
453  case ROAR_VIO_CTL_SET_DBLOCKS:
454#ifdef SNDCTL_DSP_SETFRAGMENT
[1521]455    if ( !self->need_config ) {
456     ROAR_WARN("driver_oss_ctl(*): possible late ROAR_VIO_CTL_SET_DBLOCKS, setting anyway.");
[1222]457    }
[1521]458
459    self->blocks    = *(uint_least32_t *)data;
460#else
461    return -1;
462#endif
463   break;
464  case ROAR_VIO_CTL_SET_DBLKSIZE:
465#ifdef SNDCTL_DSP_SETFRAGMENT
466    if ( !self->need_config ) {
467     ROAR_WARN("driver_oss_ctl(*): possible late ROAR_VIO_CTL_SET_DBLKSIZE, setting anyway.");
468    }
469
470    self->blocksize = *(uint_least32_t *)data;
[1222]471#else
472    return -1;
473#endif
474   break;
475  case ROAR_VIO_CTL_GET_DBLKSIZE:
[1521]476    if ( !self->blocksize )
477     return -1;
478
479    *(uint_least32_t *)data = self->blocksize;
[1527]480   break;
[1532]481  case ROAR_VIO_CTL_SET_SSTREAMID:
[1530]482    self->ssid = *(int *)data;
483   break;
[1527]484  case ROAR_VIO_CTL_SET_SSTREAM:
485    self->stream = data;
[1222]486   break;
[1539]487  case ROAR_VIO_CTL_GET_AUINFO:
488    memcpy(data, &(self->info), sizeof(struct roar_audio_info));
489   break;
490  case ROAR_VIO_CTL_SET_AUINFO:
491    memcpy(&(self->info), data, sizeof(struct roar_audio_info));
492    return driver_oss_reopen_device(self);
493   break;
[1222]494  default:
495   return -1;
496 }
[1151]497
498 return 0;
499}
500
[1518]501ssize_t driver_oss_write   (struct roar_vio_calls * vio, void *buf, size_t count) {
[1540]502 if ( _get(vio,fh) == -1 )
503  return -1;
504
[1521]505 if ( _get(vio,need_config) ) {
506  if ( driver_oss_config_device(vio->inst) == -1 ) {
507   return -1;
508  }
509 }
510
[1518]511 return write(_get(vio,fh), buf, count);
512}
513
[916]514#endif
515//ll
Note: See TracBrowser for help on using the repository browser.