source: roaraudio/roard/driver_oss.c @ 1527:8ae116c7e48b

Last change on this file since 1527:8ae116c7e48b was 1527:8ae116c7e48b, checked in by phi, 15 years ago

added support to add server stream, removed unessesery return 0

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