source: roaraudio/roard/driver_oss.c @ 3838:533d385df0da

Last change on this file since 3838:533d385df0da was 3838:533d385df0da, checked in by phi, 14 years ago

made OSS driver fh save

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