source: roaraudio/libroaross/libroaross.c @ 4007:fcdcc803bc06

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

get libroaross working again

File size: 52.0 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, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
36#include "roaraudio.h"
37#include "libroarlight/libroarlight.h"
38
39#if defined(ROAR_HAVE_OSS_BSD) || defined(ROAR_HAVE_OSS)
40#if defined(__OpenBSD__) || defined(__NetBSD__)
41#include <soundcard.h>
42#else
43#include <sys/soundcard.h>
44#endif
45#include <sys/ioctl.h>
46
47#ifdef ROAR_HAVE_H_SYS_TYPES
48#include <sys/types.h>
49#endif
50
51#ifdef ROAR_HAVE_H_FCNTL
52#include <fcntl.h>
53#endif
54
55#ifdef ROAR_HAVE_H_UNISTD
56#include <unistd.h>
57#endif
58
59#include <sys/stat.h>
60#include <dlfcn.h>
61#include <stdarg.h>
62
63#if defined(RTLD_NEXT)
64#define REAL_LIBC RTLD_NEXT
65#else
66#define REAL_LIBC ((void *) -1L)
67#endif
68
69#ifndef ENOTSUP
70#define ENOTSUP ENOSYS
71#endif
72
73#ifndef O_DIRECTORY
74#define O_DIRECTORY 0
75#endif
76
77#ifndef O_DIRECT
78#define O_DIRECT 0
79#endif
80
81#ifndef O_LARGEFILE
82#define O_LARGEFILE 0
83#endif
84
85#ifndef O_NOATIME
86#define O_NOATIME 0
87#endif
88
89#define _O_PARA_DIR (O_RDONLY|O_WRONLY|O_RDWR)
90#define _O_PARA_IGN (O_DIRECT|O_APPEND|O_LARGEFILE|O_NOATIME|O_NOCTTY|O_TRUNC)
91
92#if defined(ROAR_OS_NETBSD) && defined(ioctl)
93#define IOCTL_IS_ALIAS
94#endif
95
96#ifdef ROAR_OS_FREEBSD
97#define _VA_ARGS_MODE_T int
98#else
99#define _VA_ARGS_MODE_T mode_t
100#endif
101
102#ifdef ROAR_OS_FREEBSD
103#define _CREAT_ARG_PATHNAME path
104#else
105#define _CREAT_ARG_PATHNAME pathname
106#endif
107
108#ifdef ROAR_OS_NETBSD
109#define IOCTL() int _oss_ioctl __P((int fd, unsigned long com, void *argp))
110#define map_args int __fd = fd; unsigned long int __request = com
111#elif defined(ROAR_TARGET_CYGWIN)
112#define IOCTL() int ioctl (int __fd, int __cmd, ...)
113#define map_args unsigned long int __request = __cmd; void * argp
114#define va_argp
115#define ioctl_lastarg __cmd
116#else
117#define IOCTL() int ioctl (int __fd, unsigned long int __request, ...)
118#define map_args void * argp
119#define va_argp
120#define ioctl_lastarg __request
121#endif
122
123#define OSS_VOLUME_SCALE 100
124
125#define _MAX_POINTER  8
126
127// handle type:
128#define HT_NONE       0 /* Unused object */
129#define HT_STREAM     1 /* Stream with no specal handling needed */
130#define HT_MIXER      2 /* Mixer device */
131#define HT_WAVEFORM   3 /* Waveform device */
132#define HT_MIDI       4 /* MIDI device */
133#define HT_DMX        5 /* DMX512/DMX4Linux device */
134#define HT_VIO        6 /* General VIO object */
135#define HT_STATIC     7 /* Static file */
136
137struct session {
138 int refc;
139 struct roar_connection con;
140};
141
142static struct session _session = {.refc = 0};
143
144struct handle {
145 int refc; // refrence counter
146 struct session * session;
147 int type;
148 int sysio_flags;
149 struct roar_stream    stream;
150 struct roar_vio_calls stream_vio;
151 int                   stream_dir;
152 int                   stream_opened;
153 size_t                stream_buffersize;
154 size_t                readc, writec;
155 size_t                pos;
156 union {
157  struct {
158   char * data;
159   size_t len;
160  } sf;
161 } userdata;
162};
163
164static struct {
165 int     (*open)(const char *pathname, int flags, mode_t mode);
166 int     (*close)(int fd);
167 ssize_t (*write)(int fd, const void *buf, size_t count);
168 ssize_t (*read)(int fd, void *buf, size_t count);
169#ifndef IOCTL_IS_ALIAS
170 int     (*ioctl)(int d, int request, ...);
171#endif
172 off_t   (*lseek)(int fildes, off_t offset, int whence);
173 FILE   *(*fopen)(const char *path, const char *mode);
174 int     (*dup)(int oldfd);
175 int     (*dup2)(int oldfd, int newfd);
176 int     (*select)(int nfds, fd_set *readfds, fd_set *writefds,
177                   fd_set *exceptfds, struct timeval *timeout);
178 int     (*fcntl)(int fd, int cmd, ...);
179 int     (*access)(const char *pathname, int mode);
180 int     (*open64)(const char *__file, int __oflag, ...);
181 int     (*creat)(const char *_CREAT_ARG_PATHNAME, mode_t mode);
182 int     (*stat)(const char *path, struct stat *buf);
183 int     (*fstat)(int filedes, struct stat *buf);
184 int     (*lstat)(const char *path, struct stat *buf);
185} _os;
186
187static struct {
188 struct {
189  int volume;
190  int pcm;
191  int line;
192  int line1;
193  int line2;
194  int line3;
195  int digital1;
196  int digital2;
197  int digital3;
198 } sid;
199} _mix_settings = {
200                   .sid = {
201                           .volume   = -1,
202                           .pcm      = -1,
203                           .line     =  0,
204                           .line1    =  1,
205                           .line2    =  2,
206                           .line3    =  3,
207                           .digital1 =  1,
208                           .digital2 =  2,
209                           .digital3 =  3
210                          }
211                  };
212
213static struct pointer {
214 int fh;
215 struct handle * handle;
216} _ptr[_MAX_POINTER];
217
218
219static char _sf__dev_sndstat[] =
220 "Sound Driver:RoarAudio\n"
221 "Config options: 0\n"
222 "\n"
223 "Installed drivers:\n"
224 "Type 10: RoarAudio emulation\n"
225 "\n"
226 "Card config:\n"
227 "\n"
228 "Audio devices:\n"
229 "0: RoarAudio OSS emulation (DUPLEX)\n"
230 "\n"
231 "Midi devices:\n"
232 "0: RoarAudio OSS emulation MIDI\n"
233 "\n"
234 "Timers:\n"
235 "\n"
236 "Mixers:\n"
237 "0: RoarAudio OSS emulation Mixer\n"
238;
239
240static struct devices {
241  char * prefix;
242  int type;
243  size_t len;
244  void * userdata;
245  struct handle * (*open)(const char * file, int flags, mode_t mode, struct devices * ptr);
246} _device_list[] = {
247 {"/dev/dsp*",          HT_WAVEFORM,  0, NULL, NULL},
248 {"/dev/audio*",        HT_WAVEFORM,  0, NULL, NULL},
249 {"/dev/sound/dsp*",    HT_WAVEFORM,  0, NULL, NULL},
250 {"/dev/sound/audio*",  HT_WAVEFORM,  0, NULL, NULL},
251 {"/dev/mixer*",        HT_MIXER,     0, NULL, NULL},
252 {"/dev/sound/mixer*",  HT_MIXER,     0, NULL, NULL},
253 {"/dev/midi*",         HT_MIDI,      0, NULL, NULL},
254 {"/dev/rmidi*",        HT_MIDI,      0, NULL, NULL},
255 {"/dev/sound/midi*",   HT_MIDI,      0, NULL, NULL},
256 {"/dev/sound/rmidi*",  HT_MIDI,      0, NULL, NULL},
257 {"/dev/dmx*",          HT_DMX,       0, NULL, NULL},
258 {"/dev/misc/dmx*",     HT_DMX,       0, NULL, NULL},
259 {"/dev/dmxin*",        HT_DMX,       0, NULL, NULL},
260 {"/dev/misc/dmxin*",   HT_DMX,       0, NULL, NULL},
261 {"/dev/sndstat",       HT_STATIC,    sizeof(_sf__dev_sndstat)-1, _sf__dev_sndstat, NULL},
262#ifdef ROAR_DEFAULT_OSS_DEV
263 {ROAR_DEFAULT_OSS_DEV, HT_WAVEFORM,  0, NULL, NULL},
264#endif
265 {NULL, HT_NONE, 0, NULL, NULL},
266};
267
268
269static int _update_nonblock (struct handle * handle);
270
271static void _init_os (void) {
272 memset(&_os, 0, sizeof(_os));
273
274 // if call roar_dl_getsym() here all applications will segfaul.
275 // why?
276
277 _os.open   = dlsym(REAL_LIBC, "open");
278 _os.close  = dlsym(REAL_LIBC, "close");
279 _os.write  = dlsym(REAL_LIBC, "write");
280 _os.read   = dlsym(REAL_LIBC, "read");
281#ifndef IOCTL_IS_ALIAS
282 _os.ioctl  = dlsym(REAL_LIBC, "ioctl");
283#endif
284 _os.lseek  = dlsym(REAL_LIBC, "lseek");
285 _os.fopen  = dlsym(REAL_LIBC, "fopen");
286 _os.dup    = dlsym(REAL_LIBC, "dup");
287 _os.dup2   = dlsym(REAL_LIBC, "dup2");
288 _os.select = dlsym(REAL_LIBC, "select");
289 _os.fcntl  = dlsym(REAL_LIBC, "fcntl");
290 _os.access = dlsym(REAL_LIBC, "access");
291 _os.open64 = dlsym(REAL_LIBC, "open64");
292 _os.creat  = dlsym(REAL_LIBC, "creat");
293 _os.stat   = dlsym(REAL_LIBC, "stat");
294 _os.fstat  = dlsym(REAL_LIBC, "fstat");
295 _os.lstat  = dlsym(REAL_LIBC, "lstat");
296}
297
298static void _init_ptr (void) {
299 int i;
300
301 for (i = 0; i < _MAX_POINTER; i++) {
302  _ptr[i].fh = -1;
303 }
304}
305
306static void _init (void) {
307 static int inited = 0;
308
309 if ( !inited ) {
310  _init_os();
311  _init_ptr();
312  roar_vio_select(NULL, 0, NULL, NULL);
313  inited++;
314 }
315}
316
317static void _find_volume_sid (struct session * session) {
318 int i;
319 int num;
320 int id[ROAR_STREAMS_MAX];
321 struct roar_stream s;
322 char name[1024];
323
324 ROAR_DBG("_find_volume_sid(session=%p) = ?", session);
325
326 if ( (num = roar_list_streams(&(session->con), id, ROAR_STREAMS_MAX)) == -1 ) {
327  return;
328 }
329
330 for (i = 0; i < num; i++) {
331  if ( roar_get_stream(&(session->con), &s, id[i]) == -1 )
332   continue;
333
334  if ( s.dir != ROAR_DIR_MIXING )
335   continue;
336
337  if ( roar_stream_get_name(&(session->con), &s, name, 1024) == -1 )
338   continue;
339
340  if ( !strcasecmp(name, "Waveform Mixer") ) {
341   _mix_settings.sid.volume = id[i];
342   ROAR_DBG("_find_volume_sid(session=%p): found waveform mixer at sid %i", session, id[i]);
343   ROAR_DBG("_find_volume_sid(session=%p) = (void)", session);
344   return;
345  }
346 }
347}
348
349static int _open_dummy (void) {
350 int p[2];
351
352 if ( pipe(p) == -1 )
353  return -1;
354
355 close(p[1]);
356
357 return p[0];
358}
359
360static struct session * _open_session (char * server, char * name) {
361 struct session * ses = &_session;
362 int new_session = getenv("ROAR_OSS_NEW_SESSION") == NULL ? 0 : 1;
363
364 ROAR_DBG("_open_session(server='%s', name='%s') = ?", server, name);
365 ROAR_DBG("_open_session(server='%s', name='%s'): _session.refc=%i", server, name, _session.refc);
366
367 if ( new_session ) {
368  ses = roar_mm_malloc(sizeof(struct session));
369  if ( ses == NULL )
370   return NULL;
371
372  memset(ses, 0, sizeof(struct session));
373 }
374
375 if ( ses->refc == 0 ) {
376
377  if ( name == NULL )
378   name = getenv("ROAR_OSS_CLIENT_NAME");
379
380  if ( name == NULL )
381   name = "libroaross client";
382
383  if ( roar_simple_connect(&(ses->con), server, name) == -1 ) {
384   if ( new_session )
385    roar_mm_free(ses);
386
387   return NULL;
388  }
389
390  _find_volume_sid(ses);
391
392  if ( !new_session ) {
393   if ( getenv("ROAR_OSS_KEEP_SESSION") != NULL )
394    ses->refc++;
395  }
396 }
397
398 ses->refc++;
399
400 ROAR_DBG("_open_session(server='%s', name='%s') = %p", server, name, ses);
401 return ses;
402}
403
404static void _close_session(struct session * session) {
405 if ( session == NULL )
406  return;
407
408 session->refc--;
409
410 ROAR_DBG("_close_session(session=%p): session->refc=%i", session, session->refc);
411
412 if ( session->refc == 0 ) {
413  roar_disconnect(&(session->con));
414 }
415
416 if ( session != &_session )
417  roar_mm_free(session);
418}
419
420static struct handle * _open_handle(struct session * session) {
421 struct handle * handle;
422
423 ROAR_DBG("_open_handle(session=%p) = ?", session);
424
425 if ( (handle = roar_mm_malloc(sizeof(struct handle))) == NULL )
426  return NULL;
427
428 memset(handle, 0, sizeof(struct handle));
429
430 handle->refc = 1;
431 handle->session = session;
432
433 if ( session != NULL )
434  session->refc++; // TODO: better warp this
435
436 handle->type = HT_NONE;
437 handle->stream_dir = ROAR_DIR_PLAY;
438 roar_stream_new(&(handle->stream), ROAR_RATE_DEFAULT, ROAR_CHANNELS_DEFAULT, ROAR_BITS_DEFAULT, ROAR_CODEC_DEFAULT);
439
440 ROAR_DBG("_open_handle(session=%p) = %p", session, handle);
441 return handle;
442}
443
444static void _close_handle(struct handle * handle) {
445 int need_close = 0;
446
447 if (handle == NULL)
448  return;
449
450 handle->refc--;
451
452 ROAR_DBG("_close_handle(handle=%p): handle->refc=%i", handle, handle->refc);
453
454 if ( handle->refc == 0 ) {
455  switch (handle->type) {
456   case HT_VIO:
457     need_close = 1;
458    break;
459   case HT_STREAM:
460     if ( handle->stream_opened )
461      need_close = 1;
462    break;
463  }
464
465  if ( need_close )
466   roar_vio_close(&(handle->stream_vio));
467
468  if ( handle->session != NULL ) {
469   handle->session->refc--;
470
471   _close_session(handle->session);
472  }
473
474  roar_mm_free(handle);
475 }
476}
477
478static struct pointer * _get_pointer_by_fh (int fh) {
479 int i;
480
481 for (i = 0; i < _MAX_POINTER; i++) {
482  if ( _ptr[i].fh == fh )
483   return &(_ptr[i]);
484 }
485
486 return NULL;
487}
488
489static struct pointer * _open_pointer(struct handle * handle) {
490 struct pointer * ret = _get_pointer_by_fh(-1);
491
492 if ( ret == NULL )
493  return NULL;
494
495 if ( (ret->fh = _open_dummy()) == -1 )
496  return NULL;
497
498 ret->handle = handle;
499
500 return ret;
501}
502
503static struct pointer * _attach_pointer(struct handle * handle, int fh) {
504 struct pointer * ret = _get_pointer_by_fh(-1);
505
506 if ( ret == NULL )
507  return NULL;
508
509 if ( (ret->fh = fh) == -1 )
510  return NULL;
511
512 ret->handle = handle;
513
514 handle->refc++;
515
516 return ret;
517}
518
519static void _close_pointer(struct pointer * pointer) {
520 if ( pointer == NULL )
521  return;
522
523 _os.close(pointer->fh);
524
525 pointer->fh = -1;
526
527 _close_handle(pointer->handle);
528}
529
530// -------------------------------------
531// central function to find device:
532// -------------------------------------
533
534static struct devices * _get_device (const char * pathname) {
535 size_t len;
536 int i;
537
538 ROAR_DBG("_get_device(pathname='%s') = ?", pathname);
539
540 for (i = 0; _device_list[i].prefix != NULL; i++) {
541  len = strlen(_device_list[i].prefix);
542
543  if ( _device_list[i].prefix[len-1] == '*' ) {
544   len--;
545  } else {
546   len++;
547  }
548  if ( !strncmp(pathname, _device_list[i].prefix, len) ) {
549   return &(_device_list[i]);
550  }
551 }
552
553 ROAR_DBG("_get_device(pathname='%s') = NULL", pathname);
554 return NULL;
555}
556
557// -------------------------------------
558// central open function:
559// -------------------------------------
560
561static int _open_file (const char *pathname, int flags) {
562 struct session * session;
563 struct handle  * handle;
564 struct pointer * pointer;
565 struct devices * ptr = NULL;
566
567 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = ?", pathname, flags);
568
569/*
570 * Flags we ignore:
571 * O_DIRECT, O_APPEND, O_LARGEFILE, O_NOATIME, O_NOCTTY, O_TRUNC
572 */
573
574#ifdef O_ASYNC
575 if ( flags & O_ASYNC ) {
576  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1 // not supported O_ASYNC", pathname, flags);
577  errno = ENOSYS;
578  return -1;
579 }
580#endif
581
582 if ( (flags & O_DIRECTORY) || (flags & O_EXCL) ) {
583  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1 // invalid flags (O_DIRECTORY or O_EXCL)", pathname, flags);
584  errno = EINVAL;
585  return -1;
586 }
587
588 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = ?", pathname, flags);
589
590 if ( (ptr = _get_device(pathname)) == NULL )
591  return -2;
592
593 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = ?", pathname, flags);
594
595 if ( ptr->type == HT_STATIC || ptr->type == HT_VIO ) { // non-session handles
596  session = NULL;
597 } else {
598  if ( (session = _open_session(NULL, NULL)) == NULL ) {
599   ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
600   return -1;
601  }
602 }
603
604 if ( ptr->open != NULL ) {
605  // TODO: Add support to pass mode (perms) to open.
606  if ( (handle = ptr->open(pathname, flags, 0000, ptr)) == NULL ) {
607   _close_session(session);
608   ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
609   return -1;
610  }
611 } else {
612  if ( (handle = _open_handle(session)) == NULL ) {
613   _close_session(session);
614   ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
615   return -1;
616  }
617
618  handle->type        = ptr->type;
619  handle->sysio_flags = flags;
620  handle->stream_dir  = -1;
621 }
622
623 switch (flags & _O_PARA_DIR) {
624  case O_RDONLY:
625    switch (ptr->type) {
626     case HT_WAVEFORM:
627       handle->stream_dir = ROAR_DIR_MONITOR;
628      break;
629     case HT_MIDI:
630       handle->stream_dir = ROAR_DIR_MIDI_OUT;
631      break;
632     case HT_DMX:
633       handle->stream_dir = ROAR_DIR_LIGHT_OUT;
634      break;
635     case HT_MIXER:
636     case HT_STATIC:
637      break;
638     default:
639       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
640       return -1;
641    }
642   break;
643  case O_WRONLY:
644    switch (ptr->type) {
645     case HT_WAVEFORM:
646       handle->stream_dir = ROAR_DIR_PLAY;
647      break;
648     case HT_MIDI:
649       handle->stream_dir = ROAR_DIR_MIDI_IN;
650      break;
651     case HT_DMX:
652       handle->stream_dir = ROAR_DIR_LIGHT_IN;
653      break;
654     case HT_MIXER:
655     case HT_STATIC:
656      break;
657     default:
658       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
659       return -1;
660    }
661   break;
662  case O_RDWR:
663    switch (ptr->type) {
664     case HT_WAVEFORM:
665       handle->stream_dir = ROAR_DIR_BIDIR;
666      break;
667     case HT_MIXER:
668     case HT_STATIC:
669      break;
670     default:
671       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
672       return -1;
673    }
674   break;
675 }
676
677 switch (handle->type) {
678  case HT_WAVEFORM:
679    handle->type = HT_STREAM;
680   break;
681  case HT_MIDI:
682    handle->type = HT_STREAM;
683    handle->stream.info.rate     = 0;
684    handle->stream.info.bits     = ROAR_MIDI_BITS;
685    handle->stream.info.channels = ROAR_MIDI_CHANNELS_DEFAULT;
686    handle->stream.info.codec    = ROAR_CODEC_MIDI;
687   break;
688  case HT_DMX:
689    handle->stream.info.rate     = 0;
690    handle->stream.info.bits     = ROAR_LIGHT_BITS;
691    handle->stream.info.channels = 512;
692    handle->stream.info.codec    = ROAR_CODEC_ROARDMX;
693   break;
694  case HT_STATIC:
695    handle->userdata.sf.len      = ptr->len;
696    handle->userdata.sf.data     = ptr->userdata;
697   break;
698 }
699
700 if ( (pointer = _open_pointer(handle)) == NULL ) {
701  _close_handle(handle);
702  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
703  return -1;
704 }
705
706 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = %i", pathname, flags, pointer->fh);
707
708 return pointer->fh;
709}
710
711// -------------------------------------
712// VIO open function:
713// -------------------------------------
714
715int libroaross_open_vio(struct handle ** handleret, struct roar_vio_calls ** vio, int flags) {
716 struct handle  * handle;
717 struct pointer * pointer;
718
719 _init();
720
721 if ( vio == NULL )
722  return -1;
723
724 if ( (handle = _open_handle(NULL)) == NULL ) {
725  return -1;
726 }
727
728 handle->type        = HT_VIO;
729 handle->sysio_flags = flags;
730
731 if ( roar_vio_init_calls(&(handle->stream_vio)) == -1 ) {
732  _close_handle(handle);
733  return -1;
734 }
735
736 *vio = &(handle->stream_vio);
737
738 if ( handleret != NULL )
739  *handleret = handle;
740
741 if ( (pointer = _open_pointer(handle)) == NULL ) {
742  _close_handle(handle);
743  return -1;
744 }
745
746 return pointer->fh;
747}
748
749// -------------------------------------
750// open function for streams:
751// -------------------------------------
752
753static int _open_stream (struct handle * handle) {
754  // FIXME: this should be re-written much more cleanly:
755
756 if ( handle == NULL )
757  return -1;
758
759 if ( roar_vio_simple_new_stream_obj(&(handle->stream_vio),
760                                     &(handle->session->con), &(handle->stream),
761                                     handle->stream.info.rate,
762                                     handle->stream.info.channels,
763                                     handle->stream.info.bits,
764                                     handle->stream.info.codec,
765                                     handle->stream_dir
766                                    ) == -1 )
767  return -1;
768
769 handle->stream_opened++;
770
771 _mix_settings.sid.pcm = roar_stream_get_id(&(handle->stream));
772
773 _update_nonblock(handle);
774
775 return 0;
776}
777
778// -------------------------------------
779// function to update O_NONBLOCK:
780// -------------------------------------
781
782static int _update_nonblock (struct handle * handle) {
783 int opened = 0;
784 int state  = handle->sysio_flags & O_NONBLOCK ? ROAR_SOCKET_NONBLOCK : ROAR_SOCKET_BLOCK;
785
786 switch (handle->type) {
787  case HT_NONE:
788  case HT_STATIC:
789  case HT_MIXER:
790    // we can ignore setting of nonblock flag here.
791    return 0;
792   break;
793  case HT_VIO:
794    opened = 1;
795   break;
796  case HT_STREAM:
797  case HT_WAVEFORM:
798  case HT_MIDI:
799  case HT_DMX:
800    opened = handle->stream_opened;
801   break;
802 }
803
804 if ( opened ) {
805  return roar_vio_nonblock(&(handle->stream_vio), state);
806 }
807
808 return 0;
809}
810
811// -------------------------------------
812// function to parse format:
813// -------------------------------------
814
815static int _ioctl_stream_format (struct handle * handle, int format) {
816 struct roar_audio_info * info = &(handle->stream.info);
817
818 switch (format) {
819  case AFMT_S8:
820    info->bits  = 8;
821    info->codec = ROAR_CODEC_PCM_S_LE;
822   break;
823  case AFMT_U8:
824    info->bits  = 8;
825    info->codec = ROAR_CODEC_PCM_U_LE;
826   break;
827  case AFMT_S16_BE:
828    info->bits  = 16;
829    info->codec = ROAR_CODEC_PCM_S_BE;
830   break;
831  case AFMT_S16_LE:
832    info->bits  = 16;
833    info->codec = ROAR_CODEC_PCM_S_LE;
834   break;
835  case AFMT_U16_BE:
836    info->bits  = 16;
837    info->codec = ROAR_CODEC_PCM_U_BE;
838   break;
839  case AFMT_U16_LE:
840    info->bits  = 16;
841    info->codec = ROAR_CODEC_PCM_U_LE;
842   break;
843#ifdef AFMT_S32_BE
844  case AFMT_S32_BE:
845    info->bits  = 32;
846    info->codec = ROAR_CODEC_PCM_S_BE;
847   break;
848#endif
849#ifdef AFMT_S32_LE
850  case AFMT_S32_LE:
851    info->bits  = 32;
852    info->codec = ROAR_CODEC_PCM_S_LE;
853   break;
854#endif
855  case AFMT_A_LAW:
856    info->bits  = 8;
857    info->codec = ROAR_CODEC_ALAW;
858   break;
859  case AFMT_MU_LAW:
860    info->bits  = 8;
861    info->codec = ROAR_CODEC_MULAW;
862   break;
863#ifdef AFMT_VORBIS
864  case AFMT_VORBIS:
865    info->codec = ROAR_CODEC_OGG_VORBIS;
866   break;
867#endif
868  default:
869    ROAR_DBG("_ioctl_stream_format(*): unsupported format");
870    errno = ENOSYS;
871    return -1;
872   break;
873 }
874
875 return 0;
876}
877
878static inline int _ioctl_stream_format_list (void) {
879 int format = 0;
880
881 format |= AFMT_S8;
882 format |= AFMT_U8;
883
884 format |= AFMT_S16_BE;
885 format |= AFMT_S16_LE;
886
887 format |= AFMT_U16_BE;
888 format |= AFMT_U16_LE;
889
890#ifdef AFMT_S32_BE
891 format |= AFMT_S32_BE;
892#endif
893#ifdef AFMT_S32_LE
894 format |= AFMT_S32_LE;
895#endif
896
897 format |= AFMT_A_LAW;
898 format |= AFMT_MU_LAW;
899
900#ifdef AFMT_VORBIS
901 format |= AFMT_VORBIS;
902#endif
903
904 return format;
905}
906
907// -------------------------------------
908// mixer ioctls:
909// -------------------------------------
910
911static int _ioctl_mixer (struct handle * handle, long unsigned int req, void * vp) {
912 mixer_info * info;
913 int channels;
914 struct roar_mixer_settings mixer;
915 int o_w    =  0;
916 int o_sid  = -1;
917 int * ip   = vp;
918#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
919 char * name = NULL;
920#endif
921
922#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
923 switch (req) {
924#if 0
925  case SNDCTL_MIX_DESCRIPTION: name = "SNDCTL_MIX_DESCRIPTION"; break;
926  case SNDCTL_MIX_ENUMINFO:    name = "SNDCTL_MIX_ENUMINFO";    break;
927  case SNDCTL_MIX_EXTINFO:     name = "SNDCTL_MIX_EXTINFO";     break;
928  case SNDCTL_MIX_NREXT:       name = "SNDCTL_MIX_NREXT";       break;
929  case SNDCTL_MIX_NRMIX:       name = "SNDCTL_MIX_NRMIX";       break;
930  case SNDCTL_MIX_READ:        name = "SNDCTL_MIX_READ";        break;
931  case SNDCTL_MIX_WRITE:       name = "SNDCTL_MIX_WRITE";       break;
932#endif
933//  case SOUND_MIXER_INFO:             name = "SOUND_MIXER_INFO";             break;
934  case SOUND_OLD_MIXER_INFO:         name = "SOUND_OLD_MIXER_INFO";         break;
935  case SOUND_MIXER_ACCESS:           name = "SOUND_MIXER_ACCESS";           break;
936  case SOUND_MIXER_AGC:              name = "SOUND_MIXER_AGC";              break;
937  case SOUND_MIXER_3DSE:             name = "SOUND_MIXER_3DSE";             break;
938  case SOUND_MIXER_GETLEVELS:        name = "SOUND_MIXER_GETLEVELS";        break;
939  case SOUND_MIXER_SETLEVELS:        name = "SOUND_MIXER_SETLEVELS";        break;
940  case SOUND_MIXER_PRIVATE1:         name = "SOUND_MIXER_PRIVATE1";         break;
941  case SOUND_MIXER_PRIVATE2:         name = "SOUND_MIXER_PRIVATE2";         break;
942  case SOUND_MIXER_PRIVATE3:         name = "SOUND_MIXER_PRIVATE3";         break;
943  case SOUND_MIXER_PRIVATE4:         name = "SOUND_MIXER_PRIVATE4";         break;
944  case SOUND_MIXER_PRIVATE5:         name = "SOUND_MIXER_PRIVATE5";         break;
945  case OSS_GETVERSION:               name = "OSS_GETVERSION";               break;
946//  case SOUND_MIXER_READ_CAPS:        name = "SOUND_MIXER_READ_CAPS";        break;
947  case SOUND_MIXER_READ_MUTE:        name = "SOUND_MIXER_READ_MUTE";        break;
948/*
949  case :     name = "";     break;
950  case :     name = "";     break;
951*/
952 }
953 if ( name != NULL ) {
954  ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p): unspported mixer command %s", handle, req, ip, name);
955  ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p) = -1 // errno = ENOSYS", handle, req, ip);
956  errno = ENOSYS;
957  return -1;
958 }
959#endif
960
961 switch (req) {
962  case SOUND_MIXER_READ_VOLUME:    o_w = 0; o_sid = _mix_settings.sid.volume;   break;
963  case SOUND_MIXER_READ_LINE:      o_w = 0; o_sid = _mix_settings.sid.line;     break;
964  case SOUND_MIXER_READ_LINE1:     o_w = 0; o_sid = _mix_settings.sid.line1;    break;
965  case SOUND_MIXER_READ_LINE2:     o_w = 0; o_sid = _mix_settings.sid.line2;    break;
966  case SOUND_MIXER_READ_LINE3:     o_w = 0; o_sid = _mix_settings.sid.line3;    break;
967#if 0
968  case SOUND_MIXER_READ_DIGITAL1:  o_w = 0; o_sid = _mix_settings.sid.digital1; break;
969  case SOUND_MIXER_READ_DIGITAL2:  o_w = 0; o_sid = _mix_settings.sid.digital2; break;
970  case SOUND_MIXER_READ_DIGITAL3:  o_w = 0; o_sid = _mix_settings.sid.digital3; break;
971#endif
972  case SOUND_MIXER_WRITE_VOLUME:   o_w = 1; o_sid = _mix_settings.sid.volume;   break;
973  case SOUND_MIXER_WRITE_LINE:     o_w = 1; o_sid = _mix_settings.sid.line;     break;
974  case SOUND_MIXER_WRITE_LINE1:    o_w = 1; o_sid = _mix_settings.sid.line1;    break;
975  case SOUND_MIXER_WRITE_LINE2:    o_w = 1; o_sid = _mix_settings.sid.line2;    break;
976  case SOUND_MIXER_WRITE_LINE3:    o_w = 1; o_sid = _mix_settings.sid.line3;    break;
977#if 0
978  case SOUND_MIXER_WRITE_DIGITAL1: o_w = 1; o_sid = _mix_settings.sid.digital1; break;
979  case SOUND_MIXER_WRITE_DIGITAL2: o_w = 1; o_sid = _mix_settings.sid.digital2; break;
980  case SOUND_MIXER_WRITE_DIGITAL3: o_w = 1; o_sid = _mix_settings.sid.digital3; break;
981#endif
982  // we handle PCM seperatly as we want to be abled to abled to handle it on a stream (not mixer), too:
983  case SOUND_MIXER_READ_PCM:
984    o_w = 0;
985    if ( handle->type == HT_STREAM ) {
986     o_sid = roar_stream_get_id(&(handle->stream));
987    } else {
988     o_sid = _mix_settings.sid.pcm;
989    }
990   break;
991  case SOUND_MIXER_WRITE_PCM:
992    o_w = 1;
993    if ( handle->type == HT_STREAM ) {
994     o_sid = roar_stream_get_id(&(handle->stream));
995    } else {
996     o_sid = _mix_settings.sid.pcm;
997    }
998   break;
999 }
1000 if ( o_sid != -1 ) {
1001  // set/get volume
1002  if ( o_w ) {
1003   mixer.scale    = OSS_VOLUME_SCALE;
1004   mixer.mixer[0] = ( *ip       & 0xFF);
1005   mixer.mixer[1] = ((*ip >> 8) & 0xFF);
1006   if ( roar_set_vol(&(handle->session->con), o_sid, &mixer, 2) == -1 ) {
1007    errno = EIO;
1008    return -1;
1009   }
1010   return 0;
1011  } else {
1012   if ( roar_get_vol(&(handle->session->con), o_sid, &mixer, &channels) == -1 ) {
1013    errno = EIO;
1014    return -1;
1015   }
1016   *ip = ((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale) | (((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale)<<8);
1017   return 0;
1018  }
1019 }
1020
1021 switch (req) {
1022  case SOUND_MIXER_READ_STEREODEVS: /* FIXME: check the streams for channel config */
1023  case SOUND_MIXER_READ_DEVMASK:
1024    *ip = 0;
1025
1026    if ( _mix_settings.sid.volume != -1 )
1027     *ip |= SOUND_MASK_VOLUME;
1028    if ( _mix_settings.sid.pcm != -1 )
1029     *ip |= SOUND_MASK_PCM;
1030    if ( _mix_settings.sid.line != -1 )
1031     *ip |= SOUND_MASK_LINE;
1032    if ( _mix_settings.sid.line1 != -1 )
1033     *ip |= SOUND_MASK_LINE1;
1034    if ( _mix_settings.sid.line2 != -1 )
1035     *ip |= SOUND_MASK_LINE2;
1036    if ( _mix_settings.sid.line3 != -1 )
1037     *ip |= SOUND_MASK_LINE3;
1038    if ( _mix_settings.sid.digital1 != -1 )
1039#if 0
1040     *ip |= SOUND_MASK_DIGITAL1;
1041    if ( _mix_settings.sid.digital2 != -1 )
1042     *ip |= SOUND_MASK_DIGITAL2;
1043    if ( _mix_settings.sid.digital3 != -1 )
1044     *ip |= SOUND_MASK_DIGITAL3;
1045#endif
1046
1047    return 0;
1048   break;
1049  case SOUND_MIXER_READ_RECMASK:
1050  case SOUND_MIXER_READ_RECSRC:
1051    *ip = SOUND_MASK_VOLUME; // we can currently only read from mixer
1052    return 0;
1053   break;
1054  case SOUND_MIXER_WRITE_RECSRC:
1055    if ( *ip == SOUND_MASK_VOLUME ) {
1056     return  0;
1057    } else {
1058     errno = ENOTSUP;
1059     return -1;
1060    }
1061   break;
1062  case SOUND_MIXER_READ_CAPS:
1063    *ip = 0;
1064    return 0;
1065   break;
1066  case SOUND_MIXER_INFO:
1067    info = vp;
1068    memset(info, 0, sizeof(*info));
1069    strcpy(info->id, "RoarAudio");
1070    strcpy(info->name, "RoarAudio");
1071    return 0;
1072   break;
1073 }
1074
1075 ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p): unknown mixer CTL", handle, req, ip);
1076// _os.ioctl(-1, req, ip);
1077 ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p) = -1 // errno = ENOSYS", handle, req, ip);
1078 errno = ENOSYS;
1079 return -1;
1080}
1081
1082// -------------------------------------
1083// buffer size calculation:
1084// -------------------------------------
1085
1086static size_t _get_stream_buffersize (struct handle * handle) {
1087 if ( handle->stream_buffersize )
1088  return handle->stream_buffersize;
1089
1090 return handle->stream_buffersize = handle->stream.info.rate     *
1091                                    handle->stream.info.channels *
1092                                    handle->stream.info.bits     / 800;
1093}
1094
1095// -------------------------------------
1096// emulated functions follow:
1097// -------------------------------------
1098
1099int     open(const char *pathname, int flags, ...) {
1100 int     ret;
1101 mode_t  mode = 0;
1102 va_list args;
1103
1104 _init();
1105
1106 if ( pathname == NULL ) {
1107  errno = EFAULT;
1108  return -1;
1109 }
1110
1111 ROAR_DBG("open(pathname='%s', flags=%x, ...) = ?\n", pathname, flags);
1112 ret = _open_file(pathname, flags);
1113
1114 switch (ret) {
1115  case -2:       // continue as normal, use _op.open()
1116   break;
1117  case -1:       // pass error to caller
1118    return -1;
1119   break;
1120  default:       // return successfully opened pointer to caller
1121    return ret;
1122   break;
1123 }
1124
1125 if (flags & O_CREAT) {
1126  va_start(args, flags);
1127  mode = va_arg(args, _VA_ARGS_MODE_T);
1128  va_end(args);
1129 }
1130
1131 return _os.open(pathname, flags, mode);
1132}
1133
1134int    open64(const char *__file, int __oflag, ...) {
1135 int     ret;
1136 mode_t  mode = 0;
1137 va_list args;
1138
1139 _init();
1140
1141 if ( __file == NULL ) {
1142  errno = EFAULT;
1143  return -1;
1144 }
1145
1146 ROAR_DBG("open64(__file='%s', __oflags=%x, ...) = ?\n", __file, __oflag);
1147 ret = _open_file(__file, __oflag);
1148
1149 switch (ret) {
1150  case -2:       // continue as normal, use _op.open()
1151   break;
1152  case -1:       // pass error to caller
1153    return -1;
1154   break;
1155  default:       // return successfully opened pointer to caller
1156    return ret;
1157   break;
1158 }
1159
1160 if (__oflag & O_CREAT) {
1161  va_start(args, __oflag);
1162  mode = va_arg(args, _VA_ARGS_MODE_T);
1163  va_end(args);
1164 }
1165
1166 if ( _os.open64 != NULL ) {
1167  return _os.open64(__file, __oflag, mode);
1168 } else {
1169#ifdef O_LARGEFILE
1170  return _os.open(__file, __oflag | O_LARGEFILE, mode);
1171#else
1172  return _os.open(__file, __oflag, mode);
1173#endif
1174 }
1175}
1176
1177int     close(int fd) {
1178 struct pointer * pointer;
1179 _init();
1180
1181 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
1182  _close_pointer(pointer);
1183  return 0;
1184 }
1185
1186 return _os.close(fd);
1187}
1188
1189ssize_t write(int fd, const void *buf, size_t count) {
1190 struct roar_roardmx_message roardmxmsg;
1191 struct pointer * pointer;
1192 ssize_t ret;
1193 size_t i;
1194
1195 _init();
1196
1197 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
1198  ROAR_DBG("write(fd=%i, buf=%p, count=%lu) = ? // pointer write", fd, buf, (long unsigned int) count);
1199  switch (pointer->handle->type) {
1200   case HT_STREAM: // handle stream specific stuff
1201     if ( pointer->handle->stream_opened == 0 ) {
1202      if ( _open_stream(pointer->handle) == -1 ) {
1203       errno = EIO;
1204       return -1;
1205      }
1206     }
1207   case HT_VIO: // from here we only look at the VIO object of streams, or handle simple VIOs
1208     ret = roar_vio_write(&(pointer->handle->stream_vio), (char*)buf, count);
1209     if ( ret > 0 )
1210      pointer->handle->writec += ret;
1211     return ret;
1212    break;
1213   case HT_DMX: // DMX need specal handling as we need to convert the protocol
1214     if ( pointer->handle->stream_opened == 0 ) {
1215      if ( _open_stream(pointer->handle) == -1 ) {
1216       errno = EIO;
1217       return -1;
1218      }
1219     }
1220     if ( count > 0 ) {
1221      if ( roar_roardmx_message_new_sset(&roardmxmsg) == -1 ) {
1222       errno = EIO;
1223       return -1;
1224      }
1225      for (i = 0; i < count; i++) {
1226       if ( roar_roardmx_message_add_chanval(&roardmxmsg, pointer->handle->pos + i, ((unsigned char*)buf)[i]) == -1 ) {
1227#ifdef EMSGSIZE
1228        errno = EMSGSIZE;
1229#else
1230        errno = EIO;
1231#endif
1232        return -1;
1233       }
1234      }
1235      if ( roar_roardmx_message_send(&roardmxmsg, &(pointer->handle->stream_vio)) == -1 ) {
1236       errno = EIO;
1237       return -1;
1238      }
1239     }
1240     pointer->handle->pos += count;
1241     return count;
1242    break;
1243   default: // we don't know what to do with other types
1244     errno = EINVAL;
1245     return -1;
1246    break;
1247  }
1248 }
1249
1250 return _os.write(fd, buf, count);
1251}
1252
1253ssize_t read(int fd, void *buf, size_t count) {
1254 struct pointer * pointer;
1255 ssize_t ret;
1256
1257 _init();
1258
1259 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
1260  ROAR_DBG("read(fd=%i, buf=%p, count=%lu) = ? // pointer read", fd, buf, (long unsigned int)count);
1261
1262  switch (pointer->handle->type) {
1263   case HT_STREAM:
1264     if ( pointer->handle->stream_opened == 0 ) {
1265      if ( _open_stream(pointer->handle) == -1 ) {
1266       errno = EIO;
1267       return -1;
1268      }
1269     }
1270   case HT_VIO:
1271     ret = roar_vio_read(&(pointer->handle->stream_vio), buf, count);
1272     if ( ret > 0 )
1273      pointer->handle->readc += ret;
1274     return ret;
1275    break;
1276   case HT_STATIC:
1277     ROAR_DBG("read(fd=%i, buf=%p, count=%lu) = ? // type=HT_STATIC", fd, buf, (long unsigned int)count);
1278     ret = pointer->handle->pos + count; // calc the end of the read
1279
1280     if ( ret > (ssize_t)pointer->handle->userdata.sf.len ) {
1281      count = pointer->handle->userdata.sf.len - pointer->handle->pos;
1282     }
1283
1284     memcpy(buf, pointer->handle->userdata.sf.data + pointer->handle->pos, count);
1285     pointer->handle->pos += count;
1286     return count;
1287    break;
1288   default:
1289     errno = EINVAL;
1290     return -1;
1291    break;
1292  }
1293 }
1294
1295 return _os.read(fd, buf, count);
1296}
1297
1298off_t lseek(int fildes, off_t offset, int whence) {
1299 struct pointer * pointer;
1300 ssize_t tmp;
1301
1302 _init();
1303
1304 if ( (pointer = _get_pointer_by_fh(fildes)) != NULL ) {
1305  switch (pointer->handle->type) {
1306   case HT_DMX:
1307     switch (whence) {
1308      case SEEK_SET:
1309        pointer->handle->pos  = offset;
1310       break;
1311      case SEEK_CUR:
1312        pointer->handle->pos += offset;
1313       break;
1314      case SEEK_END:
1315      default:
1316        errno = EINVAL;
1317        return -1;
1318       break;
1319     }
1320     return pointer->handle->pos;
1321    break;
1322   case HT_VIO:
1323     return roar_vio_lseek(&(pointer->handle->stream_vio), offset, whence);
1324    break;
1325   case HT_STATIC:
1326     switch (whence) {
1327      case SEEK_SET:
1328        if ( offset < 0 || offset > (ssize_t)pointer->handle->userdata.sf.len ) {
1329         errno = EINVAL;
1330         return -1;
1331        }
1332        pointer->handle->pos  = offset;
1333       break;
1334      case SEEK_CUR:
1335        tmp = pointer->handle->pos + offset;
1336        if ( tmp < 0 || tmp > (ssize_t)pointer->handle->userdata.sf.len ) {
1337         errno = EINVAL;
1338         return -1;
1339        }
1340        pointer->handle->pos = tmp;
1341       break;
1342      case SEEK_END:
1343        tmp = pointer->handle->userdata.sf.len + offset;
1344        if ( tmp < 0 || tmp > (ssize_t)pointer->handle->userdata.sf.len ) {
1345         errno = EINVAL;
1346         return -1;
1347        }
1348        pointer->handle->pos = tmp;
1349       break;
1350      default:
1351        errno = EINVAL;
1352        return -1;
1353       break;
1354     }
1355    break;
1356   default:
1357     errno = EINVAL;
1358     return -1;
1359    break;
1360  }
1361 }
1362
1363 return _os.lseek(fildes, offset, whence);
1364}
1365
1366IOCTL() {
1367 map_args;
1368 struct pointer * pointer;
1369 struct handle  * handle;
1370 int * ip = NULL;
1371 size_t tmp;
1372 audio_buf_info * bi;
1373 count_info     * ci;
1374#ifdef __FIXME__
1375 char * nosys_reqname = NULL;
1376#endif
1377#ifdef va_argp
1378 va_list args;
1379#endif
1380
1381 _init();
1382
1383// ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = ?", __fd, (long unsigned int) __request);
1384
1385#ifdef va_argp
1386 va_start (args, ioctl_lastarg);
1387 argp = va_arg (args, void *);
1388 va_end (args);
1389#endif
1390
1391// ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): argp=%p", __fd, (long unsigned int) __request, argp);
1392
1393 if ( (pointer = _get_pointer_by_fh(__fd)) != NULL ) {
1394  ip = argp;
1395//  ROAR_DBG("ioctl(__fd=%i, __request=0x%lx): ip=%p", __fd, (long unsigned int) __request, ip);
1396#ifdef __FIXME__
1397  switch ((handle = pointer->handle)->type) {
1398   case SOUND_PCM_READ_RATE: nosys_reqname     = "SOUND_PCM_READ_RATE";     break;
1399   case SOUND_PCM_READ_CHANNELS: nosys_reqname = "SOUND_PCM_READ_CHANNELS"; break;
1400   case SOUND_PCM_READ_BITS: nosys_reqname     = "SOUND_PCM_READ_BITS";     break;
1401   case SOUND_PCM_READ_FILTER: nosys_reqname   = "SOUND_PCM_READ_FILTER";   break;
1402   case SNDCTL_COPR_RESET: nosys_reqname       = "SNDCTL_COPR_RESET";       break;
1403   case SNDCTL_COPR_LOAD: nosys_reqname        = "SNDCTL_COPR_LOAD";        break;
1404   case SNDCTL_COPR_HALT: nosys_reqname        = "SNDCTL_COPR_HALT";        break;
1405   case SNDCTL_COPR_RDATA: nosys_reqname       = "SNDCTL_COPR_RDATA";       break;
1406   case SNDCTL_COPR_RCODE: nosys_reqname       = "SNDCTL_COPR_RCODE";       break;
1407   case SNDCTL_COPR_WDATA: nosys_reqname       = "SNDCTL_COPR_WDATA";       break;
1408   case SNDCTL_COPR_WCODE: nosys_reqname       = "SNDCTL_COPR_WCODE";       break;
1409   case SNDCTL_COPR_RUN: nosys_reqname         = "SNDCTL_COPR_RUN";         break;
1410   case SNDCTL_COPR_SENDMSG: nosys_reqname     = "SNDCTL_COPR_SENDMSG";     break;
1411   case SNDCTL_COPR_RCVMSG: nosys_reqname      = "SNDCTL_COPR_RCVMSG";      break;
1412   case SNDCTL_DSP_GETCAPS: nosys_reqname      = "SNDCTL_DSP_GETCAPS";      break;
1413   default: nosys_reqname = "<<<UNKNOWN>>>"; break;
1414/*
1415   case : nosys_reqname = ""; break;
1416   case : nosys_reqname = ""; break;
1417   case : nosys_reqname = ""; break;
1418*/
1419  }
1420#endif
1421  switch ((handle = pointer->handle)->type) {
1422   case HT_STREAM:
1423     switch (__request) {
1424      case SNDCTL_DSP_RESET:
1425      case SNDCTL_DSP_POST:
1426      case SNDCTL_DSP_SYNC: // ignore for the moment.
1427      case SNDCTL_DSP_SETFRAGMENT: // any fragments should be ok for us...
1428      case SNDCTL_DSP_SETTRIGGER: // we should implement this using PAUSE flag.
1429        return 0;
1430       break;
1431      case SNDCTL_DSP_SPEED:
1432        handle->stream.info.rate = *ip;
1433        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): rate=%i", __fd, (long unsigned int) __request, *ip);
1434        return 0;
1435       break;
1436      case SNDCTL_DSP_CHANNELS:
1437        handle->stream.info.channels = *ip;
1438        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): channels=%i", __fd, (long unsigned int) __request, *ip);
1439        return 0;
1440       break;
1441      case SNDCTL_DSP_STEREO:
1442        handle->stream.info.channels = *ip ? 2 : 1;
1443        return 0;
1444       break;
1445      case SNDCTL_DSP_GETBLKSIZE:
1446        *ip = _get_stream_buffersize(handle);
1447        return 0;
1448       break;
1449      case SNDCTL_DSP_SETFMT:
1450        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): fmt=0x%x", __fd, (long unsigned int) __request, *ip);
1451        return _ioctl_stream_format(handle, *ip);
1452       break;
1453      case SNDCTL_DSP_GETFMTS:
1454//        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): ip=%p", __fd, (long unsigned int) __request, ip);
1455        *ip = _ioctl_stream_format_list();
1456        return 0;
1457       break;
1458      case SNDCTL_DSP_GETOSPACE:
1459      case SNDCTL_DSP_GETISPACE:
1460        bi = argp;
1461        memset(bi, 0, sizeof(*bi));
1462        bi->bytes      = _get_stream_buffersize(handle);
1463        bi->fragments  = 1;
1464        bi->fragsize   = bi->bytes;
1465        bi->fragstotal = 1;
1466        return 0;
1467       break;
1468      case SNDCTL_DSP_GETOPTR:
1469        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): writec=%lu", __fd, (long unsigned int) __request, (long unsigned int) handle->writec);
1470        ci = argp;
1471        memset(ci, 0, sizeof(*ci));
1472        ci->bytes  = handle->writec;
1473        ci->blocks = ci->bytes / (tmp = _get_stream_buffersize(handle));
1474        ci->ptr    = ci->bytes % tmp;
1475        return 0;
1476       break;
1477      case SNDCTL_DSP_GETIPTR:
1478        ci = argp;
1479        memset(ci, 0, sizeof(*ci));
1480        ci->bytes  = handle->readc;
1481        ci->blocks = ci->bytes / (tmp = _get_stream_buffersize(handle));
1482        ci->ptr    = ci->bytes % tmp;
1483        return 0;
1484       break;
1485#ifdef SNDCTL_DSP_GETPLAYVOL
1486      case SNDCTL_DSP_GETPLAYVOL:
1487        return _ioctl_mixer(handle, SOUND_MIXER_READ_PCM, argp);
1488       break;
1489#endif
1490#ifdef SNDCTL_DSP_SETPLAYVOL
1491      case SNDCTL_DSP_SETPLAYVOL:
1492        return _ioctl_mixer(handle, SOUND_MIXER_WRITE_PCM, argp);
1493       break;
1494#endif
1495#ifdef SNDCTL_DSP_NONBLOCK
1496      case SNDCTL_DSP_NONBLOCK:
1497        return fcntl(__fd, F_SETFL, handle->sysio_flags|O_NONBLOCK);
1498       break;
1499#endif
1500      default:
1501#ifdef __FIXME__
1502        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX (%s)) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request, nosys_reqname);
1503#else
1504        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
1505#endif
1506        errno = ENOSYS;
1507        return -1;
1508     }
1509    break;
1510   case HT_MIXER:
1511     return _ioctl_mixer(handle, __request, argp);
1512    break;
1513   default:
1514     ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): unknown handle type: no ioctl()s supported", __fd, (long unsigned int) __request);
1515     ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
1516     errno = EINVAL;
1517     return -1;
1518    break;
1519  }
1520 }
1521
1522#ifdef IOCTL_IS_ALIAS
1523 errno = ENOSYS;
1524 return -1;
1525#else
1526 return _os.ioctl(__fd, __request, argp);
1527#endif
1528}
1529
1530int dup(int oldfd) {
1531 struct pointer * pointer;
1532 int ret;
1533
1534 _init();
1535
1536 ret = _os.dup(oldfd);
1537
1538 if (ret == -1)
1539  return -1;
1540
1541 if ( (pointer = _get_pointer_by_fh(oldfd)) != NULL ) {
1542  if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1543   _os.close(ret);
1544   return -1;
1545  }
1546 }
1547
1548 return ret;
1549}
1550
1551int dup2(int oldfd, int newfd) {
1552 struct pointer * pointer;
1553 int ret;
1554
1555 _init();
1556
1557 ret = _os.dup2(oldfd, newfd);
1558
1559 if (ret == -1)
1560  return -1;
1561
1562 if ( (pointer = _get_pointer_by_fh(oldfd)) != NULL ) {
1563  if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1564   _os.close(ret);
1565   return -1;
1566  }
1567 }
1568
1569 return ret;
1570}
1571
1572int select(int nfds, fd_set *readfds, fd_set *writefds,
1573           fd_set *exceptfds, struct timeval *timeout) {
1574 struct roar_vio_selecttv rtv;
1575 struct roar_vio_select * sv  = NULL;
1576 struct pointer * pointer;
1577 struct handle  * handle;
1578 ssize_t ret;
1579 size_t num = 0;
1580 size_t idx;
1581 int i;
1582 int i_r, i_w, i_e;
1583 int max_index = -1;
1584 static volatile int is_critical = 0;
1585
1586 _init();
1587
1588 if ( is_critical )
1589  return _os.select(nfds, readfds, writefds, exceptfds, timeout);
1590
1591 ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = ?", nfds, readfds, writefds, exceptfds, timeout);
1592
1593 if ( nfds == 0 ) {
1594  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = 0", nfds, readfds, writefds, exceptfds, timeout);
1595  return 0;
1596 }
1597
1598 if ( readfds == NULL && writefds == NULL && exceptfds == NULL ) {
1599  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = 0", nfds, readfds, writefds, exceptfds, timeout);
1600  return 0;
1601 }
1602
1603 if ( timeout != NULL ) {
1604  rtv.sec = timeout->tv_sec;
1605  rtv.nsec = timeout->tv_usec*1000;
1606 }
1607
1608 // count number of handles:
1609 for (i = 0; i < nfds; i++) {
1610  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p): i=%i, EXISTS", nfds, readfds, writefds, exceptfds, timeout, i);
1611  if ( (readfds   != NULL && FD_ISSET(i, readfds  )) ||
1612       (writefds  != NULL && FD_ISSET(i, writefds )) ||
1613       (exceptfds != NULL && FD_ISSET(i, exceptfds))
1614     ) {
1615   ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p): i=%i, EXISTS", nfds, readfds, writefds, exceptfds, timeout, i);
1616   num++;
1617   max_index = i;
1618  }
1619 }
1620
1621 if ( num == 0 ) {
1622  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = 0", nfds, readfds, writefds, exceptfds, timeout);
1623  return 0;
1624 }
1625
1626 nfds = max_index + 1;
1627
1628 // create sv;
1629 sv = roar_mm_malloc(sizeof(struct roar_vio_select)*num);
1630 if ( sv == NULL ) {
1631  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = -1", nfds, readfds, writefds, exceptfds, timeout);
1632  return -1;
1633 }
1634
1635 memset(sv, 0, sizeof(struct roar_vio_select)*num);
1636
1637 for (i = 0, idx = 0; i < nfds; i++) {
1638  if ( idx >= num ) {
1639   roar_mm_free(sv);
1640   errno = EFAULT;
1641   ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = -1 // i=%i, idx=%i, num=%i", nfds, readfds, writefds, exceptfds, timeout, i, (int)idx, (int)num);
1642   return -1;
1643  }
1644  i_r = readfds   != NULL && FD_ISSET(i, readfds);
1645  i_w = writefds  != NULL && FD_ISSET(i, writefds);
1646  i_e = exceptfds != NULL && FD_ISSET(i, exceptfds);
1647
1648  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p): i=%i, i_r=%i, i_w=%i, i_e=%i", nfds, readfds, writefds, exceptfds, timeout, i, i_r, i_w, i_e);
1649
1650  if ( i_r || i_w || i_e ) {
1651   // TODO: use VIO for pointers...
1652   if ( (pointer = _get_pointer_by_fh(i)) != NULL ) {
1653    handle = pointer->handle;
1654    sv[idx].vio     = NULL;
1655    sv[idx].fh      = -1;
1656    switch (handle->type) {
1657     case HT_DMX:
1658     case HT_STREAM:
1659       if ( ! handle->stream_opened ) {
1660        // implement this as statichly return OK
1661        errno = ENOSYS;
1662        return -1;
1663       }
1664     case HT_VIO:
1665       sv[idx].vio = &(handle->stream_vio);
1666      break;
1667     default: /* non supported type */
1668       errno = EINVAL;
1669       return -1;
1670      break;
1671    }
1672   } else {
1673    sv[idx].vio     = NULL;
1674    sv[idx].fh      = i;
1675   }
1676
1677   sv[idx].ud.si   = i;
1678   sv[idx].eventsq = (i_r ? ROAR_VIO_SELECT_READ   : 0) |
1679                     (i_w ? ROAR_VIO_SELECT_WRITE  : 0) |
1680                     (i_e ? ROAR_VIO_SELECT_EXCEPT : 0);
1681   idx++;
1682  }
1683 }
1684
1685 is_critical++;
1686 ret = roar_vio_select(sv, num, timeout == NULL ? NULL : &rtv, NULL);
1687 is_critical--;
1688
1689 if ( ret < 1 ) {
1690  roar_mm_free(sv);
1691  ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = %i", nfds, readfds, writefds, exceptfds, timeout, (int)ret);
1692  return ret;
1693 }
1694
1695 // update readfds, writefds, exceptfds:
1696 if ( readfds != NULL )
1697  FD_ZERO(readfds);
1698
1699 if ( writefds != NULL )
1700  FD_ZERO(writefds);
1701
1702 if ( exceptfds != NULL )
1703  FD_ZERO(exceptfds);
1704
1705 for (idx = 0; idx < num; idx++) {
1706  if ( sv[idx].eventsa == 0 )
1707   continue;
1708
1709  if ( sv[idx].eventsa & ROAR_VIO_SELECT_READ )
1710   if ( readfds != NULL )
1711    FD_SET(sv[idx].ud.si, readfds);
1712
1713  if ( sv[idx].eventsa & ROAR_VIO_SELECT_WRITE )
1714   if ( writefds != NULL )
1715    FD_SET(sv[idx].ud.si, writefds);
1716
1717  if ( sv[idx].eventsa & ROAR_VIO_SELECT_EXCEPT )
1718   if ( exceptfds != NULL )
1719    FD_SET(sv[idx].ud.si, exceptfds);
1720 }
1721
1722 roar_mm_free(sv);
1723
1724 ROAR_DBG("select(nfds=%i, readfds=%p, writefds=%p, exceptfds=%p, timeout=%p) = %i", nfds, readfds, writefds, exceptfds, timeout, (int)ret);
1725 return ret;
1726}
1727
1728int fcntl(int fd, int cmd, ...) {
1729 enum { NONE, UNKNOWN, LONG, POINTER } type = NONE;
1730 struct pointer * pointer;
1731 va_list ap;
1732 long argl = -1;
1733 void * vp = NULL;
1734 int ret   = -1;
1735 int diff;
1736
1737 _init();
1738
1739 ROAR_DBG("fcntl(fd=%i, cmd=%i, ...) = ?", fd, cmd);
1740
1741 switch (cmd) {
1742  case F_DUPFD:
1743  case F_SETFD:
1744  case F_SETFL:
1745  case F_SETOWN:
1746#ifdef F_SETSIG
1747  case F_SETSIG:
1748#endif
1749#ifdef F_SETLEASE
1750  case F_SETLEASE:
1751#endif
1752#ifdef F_NOTIFY
1753  case F_NOTIFY:
1754#endif
1755    type = LONG;
1756   break;
1757  case F_GETFD:
1758  case F_GETFL:
1759  case F_GETOWN:
1760#ifdef F_GETSIG
1761  case F_GETSIG:
1762#endif
1763#ifdef F_GETLEASE
1764  case F_GETLEASE:
1765#endif
1766    type = NONE;
1767   break;
1768  case F_GETLK:
1769  case F_SETLK:
1770  case F_SETLKW:
1771    type = POINTER;
1772   break;
1773/*
1774  case F_EXLCK:
1775  case F_GETLK64:
1776  case F_SETLK64:
1777  case F_SETLKW64:
1778  case F_SHLCK:
1779  case F_LINUX_SPECIFIC_BASE:
1780  case F_INPROGRESS:
1781*/
1782  default:
1783    type = UNKNOWN;
1784 }
1785
1786 if ( type == UNKNOWN ) {
1787  errno = EINVAL;
1788  return -1;
1789 }
1790
1791 if ( type != NONE ) {
1792  va_start(ap, cmd);
1793  switch (type) {
1794   case LONG:
1795     argl = va_arg(ap, long);
1796    break;
1797   case POINTER:
1798     vp = va_arg(ap, void*);
1799    break;
1800   default: /* make compiler happy */
1801    break;
1802  }
1803  va_end(ap);
1804 }
1805
1806 if ( (pointer = _get_pointer_by_fh(fd)) == NULL ) {
1807  switch (type) {
1808   case NONE:
1809     ROAR_DBG("fcntl(fd=%i, cmd=%i): fd is true sysio, pass call to kernel", fd, cmd);
1810     return _os.fcntl(fd, cmd);
1811    break;
1812   case LONG:
1813     ROAR_DBG("fcntl(fd=%i, cmd=%i, arg=%li): fd is true sysio, pass call to kernel", fd, cmd, argl);
1814     return _os.fcntl(fd, cmd, argl);
1815    break;
1816   case POINTER:
1817     ROAR_DBG("fcntl(fd=%i, cmd=%i, lock=%p): fd is true sysio, pass call to kernel", fd, cmd, vp);
1818     return _os.fcntl(fd, cmd, vp);
1819    break;
1820   default: /* make compiler happy */
1821    break;
1822  }
1823 }
1824
1825 ROAR_DBG("fcntl(fd=%i, cmd=%i, ...): fd is true pointer, handle internaly", fd, cmd);
1826
1827 switch (cmd) {
1828  case F_DUPFD:
1829    ret = _os.fcntl(fd, F_DUPFD, argl);
1830
1831    if ( ret != -1 ) {
1832     if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1833      _os.close(ret);
1834      ret = -1;
1835     }
1836    }
1837   break;
1838  case F_SETFD:
1839    if ( argl == 0 ) {
1840     ret = 0;
1841    } else {
1842     errno = ENOSYS;
1843     ret = -1;
1844    }
1845   break;
1846  case F_GETFD:
1847    ret = 0;
1848   break;
1849  case F_GETFL:
1850    ret = pointer->handle->sysio_flags;
1851   break;
1852  case F_SETFL:
1853    diff  = (int)argl ^ pointer->handle->sysio_flags;
1854    diff &= (int)~(int)_O_PARA_DIR;
1855    diff &= (int)~(int)_O_PARA_IGN;
1856
1857    if ( diff & O_NONBLOCK ) {
1858     diff -= O_NONBLOCK;
1859     pointer->handle->sysio_flags ^= O_NONBLOCK;
1860     if ( _update_nonblock(pointer->handle) == -1 ) {
1861      pointer->handle->sysio_flags ^= O_NONBLOCK;
1862      return -1;
1863     }
1864    }
1865
1866    if ( diff == 0 ) { // only flags changed we ignore anyway.
1867     pointer->handle->sysio_flags  = (int)argl;
1868     ret = 0;
1869    } else {
1870     errno = EINVAL;
1871     ret = -1;
1872    }
1873   break;
1874/* TODO: add support for those types:
1875  case F_SETFD:
1876  case F_SETOWN:
1877  case F_SETSIG:
1878  case F_SETLEASE:
1879  case F_NOTIFY:
1880  case F_GETOWN:
1881  case F_GETSIG:
1882  case F_GETLEASE:
1883  case F_GETLK:
1884  case F_SETLK:
1885  case F_SETLKW:
1886*/
1887  default:
1888    errno = ENOSYS;
1889    ret = -1;
1890   break;
1891 }
1892
1893 return ret;
1894}
1895
1896int access(const char *pathname, int mode) {
1897 struct devices * ptr = NULL;
1898
1899 _init();
1900
1901 if ( (ptr = _get_device(pathname)) != NULL ) {
1902  // the only flag we do not support is +x, which means
1903  // we need to reject all requets with X_OK.
1904  if ( mode & X_OK ) {
1905   errno = EACCES;
1906   return -1;
1907  }
1908
1909  // in addition HT_STATIC files do not support write (+w)
1910  // so we need to reject W_OK.
1911  if ( ptr->type == HT_STATIC && (mode & W_OK) ) {
1912   errno = EACCES;
1913   return -1;
1914  }
1915
1916  // Else the access is granted:
1917  return 0;
1918 }
1919
1920 return _os.access(pathname, mode);
1921}
1922
1923int creat(const char *_CREAT_ARG_PATHNAME, mode_t mode) {
1924 _init();
1925
1926 if ( _get_device(_CREAT_ARG_PATHNAME) != NULL ) {
1927  errno = EEXIST;
1928  return -1;
1929 }
1930
1931 return _os.creat(_CREAT_ARG_PATHNAME, mode);
1932}
1933
1934// -------------------------------------
1935// emulated *stat*() functions follow:
1936// -------------------------------------
1937
1938int stat(const char *path, struct stat *buf) {
1939 struct devices * ptr;
1940
1941 _init();
1942
1943 if ( (ptr = _get_device(path)) != NULL ) {
1944  errno = ENOSYS;
1945  return -1;
1946 }
1947
1948 return _os.stat(path, buf);
1949}
1950
1951int fstat(int filedes, struct stat *buf) {
1952 struct pointer * pointer;
1953
1954 _init();
1955
1956 if ( (pointer = _get_pointer_by_fh(filedes)) == NULL ) {
1957  return _os.fstat(filedes, buf);
1958 }
1959
1960 errno = ENOSYS;
1961 return -1;
1962}
1963
1964int lstat(const char *path, struct stat *buf) {
1965 _init();
1966
1967 if ( _get_device(path) != NULL ) {
1968  return stat(path, buf);
1969 }
1970
1971 return _os.lstat(path, buf);
1972}
1973
1974// -------------------------------------
1975// emulated stdio functions follow:
1976// -------------------------------------
1977
1978//roar_vio_to_stdio
1979
1980static int _vio_close    (struct roar_vio_calls * vio) {
1981 int ret = 0;
1982
1983 if ( roar_vio_get_fh(vio) != -1 )
1984  ret = close(roar_vio_get_fh(vio));
1985
1986 roar_mm_free(vio);
1987
1988 return ret;
1989}
1990
1991FILE *fopen(const char *path, const char *mode) {
1992 struct roar_vio_calls * vio;
1993 FILE  * fr;
1994 int     ret;
1995 int     r = 0, w = 0;
1996 int     flags = 0;
1997 int     i;
1998 register char c;
1999
2000 _init();
2001
2002 if ( path == NULL || mode == NULL ) {
2003  errno = EFAULT;
2004  return NULL;
2005 }
2006
2007 ROAR_DBG("open(path='%s', mode='%s') = ?\n", path, mode);
2008
2009 for (i = 0; (c = mode[i]) != 0; i++) {
2010  switch (c) {
2011   case 'r': r = 1; break;
2012   case 'w': w = 1; break;
2013   case 'a': w = 1; break;
2014   case '+':
2015     r = 1;
2016     w = 1;
2017    break;
2018  }
2019 }
2020
2021 if ( r && w ) {
2022  flags = O_RDWR;
2023 } else if ( r ) {
2024  flags = O_RDONLY;
2025 } else if ( w ) {
2026  flags = O_WRONLY;
2027 } else {
2028  errno = EINVAL;
2029  return NULL;
2030 }
2031
2032 ret = _open_file(path, flags);
2033
2034 switch (ret) {
2035  case -2:       // continue as normal, use _op.open()
2036   break;
2037  case -1:       // pass error to caller
2038    return NULL;
2039   break;
2040  default:       // return successfully opened pointer to caller
2041    if ( (vio = roar_mm_malloc(sizeof(struct roar_vio_calls))) == NULL ) {
2042     return NULL; // errno should be set correctly by roar_mm_malloc().
2043    }
2044
2045    roar_vio_init_calls(vio);  // TODO: add error handling.
2046    roar_vio_set_fh(vio, ret); // TODO: add error handling.
2047    vio->close = _vio_close;
2048    if ( (fr = roar_vio_to_stdio(vio, flags)) == NULL ) {
2049     _vio_close(vio);
2050     errno = EIO;
2051     return NULL;
2052    } else {
2053     return fr;
2054    }
2055   break;
2056 }
2057
2058 return _os.fopen(path, mode);
2059}
2060
2061// -------------------------------------
2062// RoarAudio plugin functions follow:
2063// -------------------------------------
2064
2065ROAR_DL_PLUGIN_START(libroaross) {
2066 (void)para;
2067 _init();
2068} ROAR_DL_PLUGIN_END
2069
2070#endif
2071
2072//ll
Note: See TracBrowser for help on using the repository browser.