source: roaraudio/libroaross/libroaross.c @ 3148:b179bc36c36a

Last change on this file since 3148:b179bc36c36a was 3148:b179bc36c36a, checked in by phi, 14 years ago

got it basicly working!

File size: 11.8 KB
Line 
1//libroaross.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010
5 *
6 *  This file is part of libroar 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 *  libroar 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 *  NOTE for everyone want's to change something and send patches:
24 *  read README and HACKING! There a addition information on
25 *  the license of this document you need to read before you send
26 *  any patches.
27 *
28 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
29 *  or libpulse*:
30 *  The libs libroaresd, libroararts and libroarpulse link this lib
31 *  and are therefore GPL. Because of this it may be illigal to use
32 *  them with any software that uses libesd, libartsc or libpulse*.
33 */
34
35#include "roaraudio.h"
36
37#if defined(ROAR_HAVE_OSS_BSD) || defined(ROAR_HAVE_OSS)
38#if defined(__OpenBSD__) || defined(__NetBSD__)
39#include <soundcard.h>
40#else
41#include <sys/soundcard.h>
42#endif
43#include <sys/ioctl.h>
44
45#ifdef ROAR_HAVE_H_SYS_TYPES
46#include <sys/types.h>
47#endif
48
49#ifdef ROAR_HAVE_H_FCNTL
50#include <fcntl.h>
51#endif
52
53#ifdef ROAR_HAVE_H_UNISTD
54#include <unistd.h>
55#endif
56
57#include <sys/stat.h>
58#include <dlfcn.h>
59
60#if defined(RTLD_NEXT)
61#define REAL_LIBC RTLD_NEXT
62#else
63#define REAL_LIBC ((void *) -1L)
64#endif
65
66#define _MAX_POINTER  8
67
68// handle type:
69#define HT_NONE       0
70#define HT_STREAM     1
71#define HT_MIXER      2
72
73struct session {
74 int refc;
75 struct roar_connection con;
76};
77
78static struct session _session = {.refc = 0};
79
80struct handle {
81 int refc; // refrence counter
82 struct session * session;
83 int type;
84 struct roar_stream    stream;
85 struct roar_vio_calls stream_vio;
86 int                   stream_dir;
87 int                   stream_opened;
88};
89
90static struct {
91 int     (*open)(const char *pathname, int flags, mode_t mode);
92 int     (*close)(int fd);
93 ssize_t (*write)(int fd, const void *buf, size_t count);
94 ssize_t (*read)(int fd, void *buf, size_t count);
95 int     (*ioctl)(int d, int request, ...);
96} _os;
97
98static struct pointer {
99 int fh;
100 struct handle * handle;
101} _ptr[_MAX_POINTER];
102
103static void _init_os (void) {
104 memset(&_os, 0, sizeof(_os));
105
106 _os.open  = dlsym(REAL_LIBC, "open");
107 _os.close = dlsym(REAL_LIBC, "close");
108 _os.write = dlsym(REAL_LIBC, "write");
109 _os.read  = dlsym(REAL_LIBC, "read");
110 _os.ioctl = dlsym(REAL_LIBC, "ioctl");
111}
112
113static void _init_ptr (void) {
114 int i;
115
116 for (i = 0; i < _MAX_POINTER; i++) {
117  _ptr[i].fh = -1;
118 }
119}
120
121static void _init (void) {
122 static int inited = 0;
123
124 if ( !inited ) {
125  _init_os();
126  _init_ptr();
127  inited++;
128 }
129}
130
131static int _open_dummy (void) {
132 int p[2];
133
134 if ( pipe(p) == -1 )
135  return -1;
136
137 close(p[1]);
138
139 return p[0];
140}
141
142static struct session * _open_session (char * server, char * name) {
143 if ( _session.refc == 0 ) {
144
145  if ( name == NULL )
146   name = "libroaross client";
147
148  if ( roar_simple_connect(&(_session.con), server, name) == -1 )
149   return NULL;
150 }
151
152 _session.refc++;
153 return &_session;
154}
155
156static void _close_session(struct session * session) {
157 if ( session == NULL )
158  return;
159
160 session->refc--;
161
162 ROAR_DBG("_close_session(session=%p): session->refc=%i", session, session->refc);
163
164 if ( session->refc == 0 ) {
165  roar_disconnect(&(session->con));
166 }
167}
168
169static struct handle * _open_handle(struct session * session) {
170 struct handle * handle;
171
172 if ( (handle = roar_mm_malloc(sizeof(struct handle))) == NULL )
173  return NULL;
174
175 memset(handle, 0, sizeof(struct handle));
176
177 handle->refc = 1;
178 handle->session = session;
179 session->refc++; // TODO: better warp this
180 handle->type = HT_NONE;
181 handle->stream_dir = ROAR_DIR_PLAY;
182 roar_stream_new(&(handle->stream), ROAR_RATE_DEFAULT, ROAR_CHANNELS_DEFAULT, ROAR_BITS_DEFAULT, ROAR_CODEC_DEFAULT);
183
184 return handle;
185}
186
187static void _close_handle(struct handle * handle) {
188 if (handle == NULL)
189  return;
190
191 handle->refc--;
192
193 ROAR_DBG("_close_handle(handle=%p): handle->refc=%i", handle, handle->refc);
194
195 if ( handle->refc == 0 ) {
196  if ( handle->stream_opened )
197   roar_vio_close(&(handle->stream_vio));
198
199  handle->session->refc--;
200
201  _close_session(handle->session);
202
203  roar_mm_free(handle);
204 }
205}
206
207static struct pointer * _get_pointer_by_fh (int fh) {
208 int i;
209
210 for (i = 0; i < _MAX_POINTER; i++) {
211  if ( _ptr[i].fh == fh )
212   return &(_ptr[i]);
213 }
214
215 return NULL;
216}
217
218static struct pointer * _open_pointer(struct handle * handle) {
219 struct pointer * ret = _get_pointer_by_fh(-1);
220
221 if ( ret == NULL )
222  return NULL;
223
224 if ( (ret->fh = _open_dummy()) == -1 )
225  return NULL;
226
227 ret->handle = handle;
228
229 return ret;
230}
231
232static void _close_pointer(struct pointer * pointer) {
233 if ( pointer == NULL )
234  return;
235
236 _os.close(pointer->fh);
237
238 pointer->fh = -1;
239
240 _close_handle(pointer->handle);
241}
242
243// -------------------------------------
244// central open function:
245// -------------------------------------
246
247static int _open_file (const char *pathname, int flags) {
248 struct session * session;
249 struct handle  * handle;
250 struct pointer * pointer;
251 struct {
252  char * prefix;
253  int type;
254 } * ptr = NULL, p[] = {
255  {"/dev/dsp", HT_STREAM},
256  {NULL, HT_NONE},
257 };
258 int i;
259
260 for (i = 0; p[i].prefix != NULL; i++) {
261  if ( !strcmp(pathname, p[i].prefix) ) {
262   ptr = &(p[i]);
263  }
264 }
265
266 if ( ptr == NULL )
267  return -2;
268
269 if ( (session = _open_session(NULL, NULL)) == NULL ) {
270  return -1;
271 }
272
273 if ( (handle = _open_handle(session)) == NULL ) {
274  _close_session(session);
275  return -1;
276 }
277
278 handle->type = ptr->type;
279
280 switch (flags & (O_RDONLY|O_WRONLY|O_RDWR)) {
281  case O_RDONLY:
282    handle->stream_dir = ROAR_DIR_MONITOR;
283   break;
284  case O_WRONLY:
285    handle->stream_dir = ROAR_DIR_PLAY;
286   break;
287  case O_RDWR:
288    handle->stream_dir = ROAR_DIR_BIDIR;
289   break;
290 }
291
292 if ( (pointer = _open_pointer(handle)) == NULL ) {
293  _close_handle(handle);
294  return -1;
295 }
296
297 return pointer->fh;
298}
299
300// -------------------------------------
301// open function for streams:
302// -------------------------------------
303
304static int _open_stream (struct handle * handle) {
305  // FIXME: this should be re-written much more cleanly:
306
307 if ( handle == NULL )
308  return -1;
309
310 if ( roar_vio_simple_new_stream_obj(&(handle->stream_vio),
311                                     &(handle->session->con), &(handle->stream),
312                                     handle->stream.info.rate,
313                                     handle->stream.info.channels,
314                                     handle->stream.info.bits,
315                                     handle->stream.info.codec,
316                                     handle->stream_dir
317                                    ) == -1 )
318  return -1;
319
320 handle->stream_opened++;
321
322 return 0;
323}
324
325// -------------------------------------
326// function to parse format:
327// -------------------------------------
328
329static int _ioctl_stream_format (struct handle * handle, int format) {
330 struct roar_audio_info * info = &(handle->stream.info);
331
332 switch (format) {
333  case AFMT_S8:
334    info->bits  = 8;
335    info->codec = ROAR_CODEC_PCM_S_LE;
336   break;
337  case AFMT_U8:
338    info->bits  = 8;
339    info->codec = ROAR_CODEC_PCM_U_LE;
340   break;
341  case AFMT_S16_BE:
342    info->bits  = 16;
343    info->codec = ROAR_CODEC_PCM_S_BE;
344   break;
345  case AFMT_S16_LE:
346    info->bits  = 16;
347    info->codec = ROAR_CODEC_PCM_S_LE;
348   break;
349  case AFMT_U16_BE:
350    info->bits  = 16;
351    info->codec = ROAR_CODEC_PCM_U_BE;
352   break;
353  case AFMT_U16_LE:
354    info->bits  = 16;
355    info->codec = ROAR_CODEC_PCM_U_LE;
356   break;
357#ifdef AFMT_S32_BE
358  case AFMT_S32_BE:
359    info->bits  = 32;
360    info->codec = ROAR_CODEC_PCM_S_BE;
361   break;
362#endif
363#ifdef AFMT_S32_LE
364  case AFMT_S32_LE:
365    info->bits  = 32;
366    info->codec = ROAR_CODEC_PCM_S_LE;
367   break;
368#endif
369  case AFMT_A_LAW:
370    info->bits  = 8;
371    info->codec = ROAR_CODEC_ALAW;
372   break;
373  case AFMT_MU_LAW:
374    info->bits  = 8;
375    info->codec = ROAR_CODEC_MULAW;
376   break;
377#ifdef AFMT_VORBIS
378  case AFMT_VORBIS:
379    info->codec = ROAR_CODEC_OGG_VORBIS;
380   break;
381#endif
382  default:
383    errno = ENOSYS;
384    return -1;
385   break;
386 }
387
388 return 0;
389}
390
391// -------------------------------------
392// emulated functions follow:
393// -------------------------------------
394
395int     open(const char *pathname, int flags, ...) {
396 int     ret;
397 mode_t  mode = 0;
398 va_list args;
399
400 _init();
401
402 ret = _open_file(pathname, flags);
403
404 switch (ret) {
405  case -2:       // continue as normal, use _op.open()
406   break;
407  case -1:       // pass error to caller
408    return -1;
409   break;
410  default:       // return successfully opened pointer to caller
411    return ret;
412   break;
413 }
414
415 if (flags & O_CREAT) {
416  va_start(args, flags);
417  mode = va_arg(args, mode_t);
418  va_end(args);
419 }
420
421 return _os.open(pathname, flags, mode);
422}
423
424int     close(int fd) {
425 struct pointer * pointer;
426 _init();
427
428 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
429  _close_pointer(pointer);
430  return 0;
431 }
432
433 return _os.close(fd);
434}
435
436ssize_t write(int fd, const void *buf, size_t count) {
437 struct pointer * pointer;
438
439 _init();
440
441 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
442  if ( pointer->handle->type == HT_STREAM ) {
443   if ( pointer->handle->stream_opened == 0 ) {
444    if ( _open_stream(pointer->handle) == -1 ) {
445     errno = EIO;
446     return -1;
447    }
448   }
449   return roar_vio_write(&(pointer->handle->stream_vio), (char*)buf, count);
450  } else {
451   errno = EINVAL;
452   return -1;
453  }
454 }
455
456 return _os.write(fd, buf, count);
457}
458
459ssize_t read(int fd, void *buf, size_t count) {
460 struct pointer * pointer;
461
462 _init();
463
464 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
465  if ( pointer->handle->type == HT_STREAM ) {
466   if ( pointer->handle->stream_opened == 0 ) {
467    if ( _open_stream(pointer->handle) == -1 ) {
468     errno = EIO;
469     return -1;
470    }
471   }
472   return roar_vio_read(&(pointer->handle->stream_vio), buf, count);
473  } else {
474   errno = EINVAL;
475   return -1;
476  }
477 }
478
479 return _os.read(fd, buf, count);
480}
481
482extern int ioctl (int __fd, unsigned long int __request, ...) {
483 struct pointer * pointer;
484 struct handle  * handle;
485 va_list args;
486 void *argp;
487 int * ip = NULL;
488
489 _init();
490
491 ROAR_DBG("ioctl(__fd=%i, __request=%lu) = ?", __fd, (long unsigned int) __request);
492
493 va_start (args, __request);
494 argp = va_arg (args, void *);
495 va_end (args);
496
497 ROAR_DBG("ioctl(__fd=%i, __request=%lu): argp=%p", __fd, (long unsigned int) __request, argp);
498
499 if ( (pointer = _get_pointer_by_fh(__fd)) != NULL ) {
500  ip = argp;
501  ROAR_DBG("ioctl(__fd=%i, __request=%lu): ip=%p", __fd, (long unsigned int) __request, ip);
502  switch ((handle = pointer->handle)->type) {
503   case HT_STREAM:
504     switch (__request) {
505      case SNDCTL_DSP_RESET:
506      case SNDCTL_DSP_POST:
507       break;
508      case SNDCTL_DSP_SPEED:
509        handle->stream.info.rate = *ip;
510        return 0;
511       break;
512      case SNDCTL_DSP_CHANNELS:
513        handle->stream.info.channels = *ip;
514        return 0;
515       break;
516      case SNDCTL_DSP_SETFMT:
517        return _ioctl_stream_format(handle, *ip);
518       break;
519      case SNDCTL_DSP_GETFMTS:
520        ROAR_DBG("ioctl(__fd=%i, __request=%lu): ip=%p", __fd, (long unsigned int) __request, ip);
521        *ip = AFMT_S8|AFMT_S16_LE;
522        return 0;
523       break;
524      default:
525        ROAR_DBG("ioctl(__fd=%i, __request=%lu) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
526        errno = ENOSYS;
527        return -1;
528     }
529    break;
530   case HT_MIXER:
531     errno = ENOSYS;
532     return -1;
533    break;
534   default:
535     errno = EINVAL;
536     return -1;
537    break;
538  }
539 }
540
541 return _os.ioctl(__fd, __request, argp);
542}
543
544#endif
545
546//ll
Note: See TracBrowser for help on using the repository browser.