source: roaraudio/roard/driver_oss.c @ 6056:8d4468a24909

Last change on this file since 6056:8d4468a24909 was 6052:d48765b2475e, checked in by phi, 9 years ago

updated copyright headers

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