source: roaraudio/roard/driver_oss.c @ 5278:b3e0dd3f3141

Last change on this file since 5278:b3e0dd3f3141 was 5278:b3e0dd3f3141, checked in by phi, 12 years ago

last parts of merging _nonblock into _ctl and fixed sizeof(cmd) of _ctls

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