source: roaraudio/libroaross/libroaross.c @ 3657:e6be7ef3fece

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

added support for dup() and dup2()

File size: 32.5 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
62#if defined(RTLD_NEXT)
63#define REAL_LIBC RTLD_NEXT
64#else
65#define REAL_LIBC ((void *) -1L)
66#endif
67
68#ifndef ENOTSUP
69#define ENOTSUP ENOSYS
70#endif
71
72#if defined(ROAR_OS_NETBSD) && defined(ioctl)
73#define IOCTL_IS_ALIAS
74#endif
75
76#ifdef ROAR_OS_FREEBSD
77#define mode_t int
78#endif
79
80#ifdef ROAR_OS_NETBSD
81#define IOCTL() int _oss_ioctl __P((int fd, unsigned long com, void *argp))
82#define map_args int __fd = fd; unsigned long int __request = com
83#elif defined(ROAR_TARGET_CYGWIN)
84#define IOCTL() int ioctl (int __fd, int __cmd, ...)
85#define map_args unsigned long int __request = __cmd; void * argp
86#define va_argp
87#define ioctl_lastarg __cmd
88#else
89#define IOCTL() int ioctl (int __fd, unsigned long int __request, ...)
90#define map_args void * argp
91#define va_argp
92#define ioctl_lastarg __request
93#endif
94
95#define OSS_VOLUME_SCALE 100
96
97#define _MAX_POINTER  8
98
99// handle type:
100#define HT_NONE       0
101#define HT_STREAM     1
102#define HT_MIXER      2
103#define HT_WAVEFORM   3
104#define HT_MIDI       4
105#define HT_DMX        5
106
107struct session {
108 int refc;
109 struct roar_connection con;
110};
111
112static struct session _session = {.refc = 0};
113
114struct handle {
115 int refc; // refrence counter
116 struct session * session;
117 int type;
118 struct roar_stream    stream;
119 struct roar_vio_calls stream_vio;
120 int                   stream_dir;
121 int                   stream_opened;
122 size_t                stream_buffersize;
123 size_t                readc, writec;
124 size_t                pos;
125};
126
127static struct {
128 int     (*open)(const char *pathname, int flags, mode_t mode);
129 int     (*close)(int fd);
130 ssize_t (*write)(int fd, const void *buf, size_t count);
131 ssize_t (*read)(int fd, void *buf, size_t count);
132#ifndef IOCTL_IS_ALIAS
133 int     (*ioctl)(int d, int request, ...);
134#endif
135 off_t   (*lseek)(int fildes, off_t offset, int whence);
136 FILE   *(*fopen)(const char *path, const char *mode);
137 int     (*dup)(int oldfd);
138 int     (*dup2)(int oldfd, int newfd);
139} _os;
140
141static struct {
142 struct {
143  int volume;
144  int pcm;
145  int line;
146  int line1;
147  int line2;
148  int line3;
149  int digital1;
150  int digital2;
151  int digital3;
152 } sid;
153} _mix_settings = {
154                   .sid = {
155                           .volume   = -1,
156                           .pcm      = -1,
157                           .line     =  0,
158                           .line1    =  1,
159                           .line2    =  2,
160                           .line3    =  3,
161                           .digital1 =  1,
162                           .digital2 =  2,
163                           .digital3 =  3
164                          }
165                  };
166
167static struct pointer {
168 int fh;
169 struct handle * handle;
170} _ptr[_MAX_POINTER];
171
172static void _init_os (void) {
173 memset(&_os, 0, sizeof(_os));
174
175 _os.open  = dlsym(REAL_LIBC, "open");
176 _os.close = dlsym(REAL_LIBC, "close");
177 _os.write = dlsym(REAL_LIBC, "write");
178 _os.read  = dlsym(REAL_LIBC, "read");
179#ifndef IOCTL_IS_ALIAS
180 _os.ioctl = dlsym(REAL_LIBC, "ioctl");
181#endif
182 _os.lseek = dlsym(REAL_LIBC, "lseek");
183 _os.fopen = dlsym(REAL_LIBC, "fopen");
184 _os.dup   = dlsym(REAL_LIBC, "dup");
185 _os.dup2  = dlsym(REAL_LIBC, "dup2");
186}
187
188static void _init_ptr (void) {
189 int i;
190
191 for (i = 0; i < _MAX_POINTER; i++) {
192  _ptr[i].fh = -1;
193 }
194}
195
196static void _init (void) {
197 static int inited = 0;
198
199 if ( !inited ) {
200  _init_os();
201  _init_ptr();
202  inited++;
203 }
204}
205
206static void _find_volume_sid (struct session * session) {
207 int i;
208 int num;
209 int id[ROAR_STREAMS_MAX];
210 struct roar_stream s;
211 char name[1024];
212
213 ROAR_DBG("_find_volume_sid(session=%p) = ?", session);
214
215 if ( (num = roar_list_streams(&(session->con), id, ROAR_STREAMS_MAX)) == -1 ) {
216  return;
217 }
218
219 for (i = 0; i < num; i++) {
220  if ( roar_get_stream(&(session->con), &s, id[i]) == -1 )
221   continue;
222
223  if ( s.dir != ROAR_DIR_MIXING )
224   continue;
225
226  if ( roar_stream_get_name(&(session->con), &s, name, 1024) == -1 )
227   continue;
228
229  if ( !strcasecmp(name, "Waveform Mixer") ) {
230   _mix_settings.sid.volume = id[i];
231   ROAR_DBG("_find_volume_sid(session=%p): found waveform mixer at sid %i", session, id[i]);
232   ROAR_DBG("_find_volume_sid(session=%p) = (void)", session);
233   return;
234  }
235 }
236}
237
238static int _open_dummy (void) {
239 int p[2];
240
241 if ( pipe(p) == -1 )
242  return -1;
243
244 close(p[1]);
245
246 return p[0];
247}
248
249static struct session * _open_session (char * server, char * name) {
250 struct session * ses = &_session;
251 int new_session = getenv("ROAR_OSS_NEW_SESSION") == NULL ? 0 : 1;
252
253 ROAR_DBG("_open_session(server='%s', name='%s') = ?", server, name);
254 ROAR_DBG("_open_session(server='%s', name='%s'): _session.refc=%i", server, name, _session.refc);
255
256 if ( new_session ) {
257  ses = malloc(sizeof(struct session));
258  if ( ses == NULL )
259   return NULL;
260
261  memset(ses, 0, sizeof(struct session));
262 }
263
264 if ( ses->refc == 0 ) {
265
266  if ( name == NULL )
267   name = getenv("ROAR_OSS_CLIENT_NAME");
268
269  if ( name == NULL )
270   name = "libroaross client";
271
272  if ( roar_simple_connect(&(ses->con), server, name) == -1 ) {
273   if ( new_session )
274    free(ses);
275
276   return NULL;
277  }
278
279  _find_volume_sid(ses);
280
281  if ( !new_session ) {
282   if ( getenv("ROAR_OSS_KEEP_SESSION") != NULL )
283    ses->refc++;
284  }
285 }
286
287 ses->refc++;
288
289 ROAR_DBG("_open_session(server='%s', name='%s') = %p", server, name, ses);
290 return ses;
291}
292
293static void _close_session(struct session * session) {
294 if ( session == NULL )
295  return;
296
297 session->refc--;
298
299 ROAR_DBG("_close_session(session=%p): session->refc=%i", session, session->refc);
300
301 if ( session->refc == 0 ) {
302  roar_disconnect(&(session->con));
303 }
304
305 if ( session != &_session )
306  free(session);
307}
308
309static struct handle * _open_handle(struct session * session) {
310 struct handle * handle;
311
312 ROAR_DBG("_open_handle(session=%p) = ?", session);
313
314 if ( (handle = roar_mm_malloc(sizeof(struct handle))) == NULL )
315  return NULL;
316
317 memset(handle, 0, sizeof(struct handle));
318
319 handle->refc = 1;
320 handle->session = session;
321 session->refc++; // TODO: better warp this
322 handle->type = HT_NONE;
323 handle->stream_dir = ROAR_DIR_PLAY;
324 roar_stream_new(&(handle->stream), ROAR_RATE_DEFAULT, ROAR_CHANNELS_DEFAULT, ROAR_BITS_DEFAULT, ROAR_CODEC_DEFAULT);
325
326 ROAR_DBG("_open_handle(session=%p) = %p", session, handle);
327 return handle;
328}
329
330static void _close_handle(struct handle * handle) {
331 if (handle == NULL)
332  return;
333
334 handle->refc--;
335
336 ROAR_DBG("_close_handle(handle=%p): handle->refc=%i", handle, handle->refc);
337
338 if ( handle->refc == 0 ) {
339  if ( handle->stream_opened )
340   roar_vio_close(&(handle->stream_vio));
341
342  handle->session->refc--;
343
344  _close_session(handle->session);
345
346  roar_mm_free(handle);
347 }
348}
349
350static struct pointer * _get_pointer_by_fh (int fh) {
351 int i;
352
353 for (i = 0; i < _MAX_POINTER; i++) {
354  if ( _ptr[i].fh == fh )
355   return &(_ptr[i]);
356 }
357
358 return NULL;
359}
360
361static struct pointer * _open_pointer(struct handle * handle) {
362 struct pointer * ret = _get_pointer_by_fh(-1);
363
364 if ( ret == NULL )
365  return NULL;
366
367 if ( (ret->fh = _open_dummy()) == -1 )
368  return NULL;
369
370 ret->handle = handle;
371
372 return ret;
373}
374
375static struct pointer * _attach_pointer(struct handle * handle, int fh) {
376 struct pointer * ret = _get_pointer_by_fh(-1);
377
378 if ( ret == NULL )
379  return NULL;
380
381 if ( (ret->fh = fh) == -1 )
382  return NULL;
383
384 ret->handle = handle;
385
386 handle->refc++;
387
388 return ret;
389}
390
391static void _close_pointer(struct pointer * pointer) {
392 if ( pointer == NULL )
393  return;
394
395 _os.close(pointer->fh);
396
397 pointer->fh = -1;
398
399 _close_handle(pointer->handle);
400}
401
402// -------------------------------------
403// central open function:
404// -------------------------------------
405
406static int _open_file (const char *pathname, int flags) {
407 struct session * session;
408 struct handle  * handle;
409 struct pointer * pointer;
410 struct {
411  char * prefix;
412  int type;
413 } * ptr = NULL, p[] = {
414  {"/dev/dsp",           HT_WAVEFORM},
415  {"/dev/audio",         HT_WAVEFORM},
416  {"/dev/sound/dsp",     HT_WAVEFORM},
417  {"/dev/sound/audio",   HT_WAVEFORM},
418  {"/dev/mixer",         HT_MIXER},
419  {"/dev/sound/mixer",   HT_MIXER},
420  {"/dev/midi",          HT_MIDI},
421  {"/dev/rmidi",         HT_MIDI},
422  {"/dev/sound/midi",    HT_MIDI},
423  {"/dev/sound/rmidi",   HT_MIDI},
424  {"/dev/dmx",           HT_DMX},
425  {"/dev/misc/dmx",      HT_DMX},
426  {"/dev/dmxin",         HT_DMX},
427  {"/dev/misc/dmxin",    HT_DMX},
428#ifdef ROAR_DEFAULT_OSS_DEV
429  {ROAR_DEFAULT_OSS_DEV, HT_WAVEFORM},
430#endif
431  {NULL, HT_NONE},
432 };
433 int i;
434
435 for (i = 0; p[i].prefix != NULL; i++) {
436  if ( !strcmp(pathname, p[i].prefix) ) {
437   ptr = &(p[i]);
438  }
439 }
440
441 if ( ptr == NULL )
442  return -2;
443
444 if ( (session = _open_session(NULL, NULL)) == NULL ) {
445  return -1;
446 }
447
448 if ( (handle = _open_handle(session)) == NULL ) {
449  _close_session(session);
450  return -1;
451 }
452
453 handle->type       = ptr->type;
454 handle->stream_dir = -1;
455
456 switch (flags & (O_RDONLY|O_WRONLY|O_RDWR)) {
457  case O_RDONLY:
458    switch (ptr->type) {
459     case HT_WAVEFORM:
460       handle->stream_dir = ROAR_DIR_MONITOR;
461      break;
462     case HT_MIDI:
463       handle->stream_dir = ROAR_DIR_MIDI_OUT;
464      break;
465     case HT_DMX:
466       handle->stream_dir = ROAR_DIR_LIGHT_OUT;
467      break;
468     default:
469       return -1;
470    }
471   break;
472  case O_WRONLY:
473    switch (ptr->type) {
474     case HT_WAVEFORM:
475       handle->stream_dir = ROAR_DIR_PLAY;
476      break;
477     case HT_MIDI:
478       handle->stream_dir = ROAR_DIR_MIDI_IN;
479      break;
480     case HT_DMX:
481       handle->stream_dir = ROAR_DIR_LIGHT_IN;
482      break;
483     default:
484       return -1;
485    }
486   break;
487  case O_RDWR:
488    switch (ptr->type) {
489     case HT_WAVEFORM:
490       handle->stream_dir = ROAR_DIR_BIDIR;
491      break;
492     default:
493       return -1;
494    }
495   break;
496 }
497
498 switch (handle->type) {
499  case HT_WAVEFORM:
500    handle->type = HT_STREAM;
501   break;
502  case HT_MIDI:
503    handle->type = HT_STREAM;
504    handle->stream.info.rate     = 0;
505    handle->stream.info.bits     = ROAR_MIDI_BITS;
506    handle->stream.info.channels = ROAR_MIDI_CHANNELS_DEFAULT;
507    handle->stream.info.codec    = ROAR_CODEC_MIDI;
508   break;
509  case HT_DMX:
510    handle->stream.info.rate     = 0;
511    handle->stream.info.bits     = ROAR_LIGHT_BITS;
512    handle->stream.info.channels = 512;
513    handle->stream.info.codec    = ROAR_CODEC_ROARDMX;
514   break;
515 }
516
517 if ( (pointer = _open_pointer(handle)) == NULL ) {
518  _close_handle(handle);
519  return -1;
520 }
521
522 return pointer->fh;
523}
524
525// -------------------------------------
526// open function for streams:
527// -------------------------------------
528
529static int _open_stream (struct handle * handle) {
530  // FIXME: this should be re-written much more cleanly:
531
532 if ( handle == NULL )
533  return -1;
534
535 if ( roar_vio_simple_new_stream_obj(&(handle->stream_vio),
536                                     &(handle->session->con), &(handle->stream),
537                                     handle->stream.info.rate,
538                                     handle->stream.info.channels,
539                                     handle->stream.info.bits,
540                                     handle->stream.info.codec,
541                                     handle->stream_dir
542                                    ) == -1 )
543  return -1;
544
545 handle->stream_opened++;
546
547 _mix_settings.sid.pcm = roar_stream_get_id(&(handle->stream));
548
549 return 0;
550}
551
552// -------------------------------------
553// function to parse format:
554// -------------------------------------
555
556static int _ioctl_stream_format (struct handle * handle, int format) {
557 struct roar_audio_info * info = &(handle->stream.info);
558
559 switch (format) {
560  case AFMT_S8:
561    info->bits  = 8;
562    info->codec = ROAR_CODEC_PCM_S_LE;
563   break;
564  case AFMT_U8:
565    info->bits  = 8;
566    info->codec = ROAR_CODEC_PCM_U_LE;
567   break;
568  case AFMT_S16_BE:
569    info->bits  = 16;
570    info->codec = ROAR_CODEC_PCM_S_BE;
571   break;
572  case AFMT_S16_LE:
573    info->bits  = 16;
574    info->codec = ROAR_CODEC_PCM_S_LE;
575   break;
576  case AFMT_U16_BE:
577    info->bits  = 16;
578    info->codec = ROAR_CODEC_PCM_U_BE;
579   break;
580  case AFMT_U16_LE:
581    info->bits  = 16;
582    info->codec = ROAR_CODEC_PCM_U_LE;
583   break;
584#ifdef AFMT_S32_BE
585  case AFMT_S32_BE:
586    info->bits  = 32;
587    info->codec = ROAR_CODEC_PCM_S_BE;
588   break;
589#endif
590#ifdef AFMT_S32_LE
591  case AFMT_S32_LE:
592    info->bits  = 32;
593    info->codec = ROAR_CODEC_PCM_S_LE;
594   break;
595#endif
596  case AFMT_A_LAW:
597    info->bits  = 8;
598    info->codec = ROAR_CODEC_ALAW;
599   break;
600  case AFMT_MU_LAW:
601    info->bits  = 8;
602    info->codec = ROAR_CODEC_MULAW;
603   break;
604#ifdef AFMT_VORBIS
605  case AFMT_VORBIS:
606    info->codec = ROAR_CODEC_OGG_VORBIS;
607   break;
608#endif
609  default:
610    ROAR_DBG("_ioctl_stream_format(*): unsupported format");
611    errno = ENOSYS;
612    return -1;
613   break;
614 }
615
616 return 0;
617}
618
619static inline int _ioctl_stream_format_list (void) {
620 int format = 0;
621
622 format |= AFMT_S8;
623 format |= AFMT_U8;
624
625 format |= AFMT_S16_BE;
626 format |= AFMT_S16_LE;
627
628 format |= AFMT_U16_BE;
629 format |= AFMT_U16_LE;
630
631#ifdef AFMT_S32_BE
632 format |= AFMT_S32_BE;
633#endif
634#ifdef AFMT_S32_LE
635 format |= AFMT_S32_LE;
636#endif
637
638 format |= AFMT_A_LAW;
639 format |= AFMT_MU_LAW;
640
641#ifdef AFMT_VORBIS
642 format |= AFMT_VORBIS;
643#endif
644
645 return format;
646}
647
648// -------------------------------------
649// mixer ioctls:
650// -------------------------------------
651
652static int _ioctl_mixer (struct handle * handle, long unsigned int req, void * vp) {
653 mixer_info * info;
654 int channels;
655 struct roar_mixer_settings mixer;
656 int o_w    =  0;
657 int o_sid  = -1;
658 int * ip   = vp;
659#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
660 char * name = NULL;
661#endif
662
663#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
664 switch (req) {
665#if 0
666  case SNDCTL_MIX_DESCRIPTION: name = "SNDCTL_MIX_DESCRIPTION"; break;
667  case SNDCTL_MIX_ENUMINFO:    name = "SNDCTL_MIX_ENUMINFO";    break;
668  case SNDCTL_MIX_EXTINFO:     name = "SNDCTL_MIX_EXTINFO";     break;
669  case SNDCTL_MIX_NREXT:       name = "SNDCTL_MIX_NREXT";       break;
670  case SNDCTL_MIX_NRMIX:       name = "SNDCTL_MIX_NRMIX";       break;
671  case SNDCTL_MIX_READ:        name = "SNDCTL_MIX_READ";        break;
672  case SNDCTL_MIX_WRITE:       name = "SNDCTL_MIX_WRITE";       break;
673#endif
674//  case SOUND_MIXER_INFO:             name = "SOUND_MIXER_INFO";             break;
675  case SOUND_OLD_MIXER_INFO:         name = "SOUND_OLD_MIXER_INFO";         break;
676  case SOUND_MIXER_ACCESS:           name = "SOUND_MIXER_ACCESS";           break;
677  case SOUND_MIXER_AGC:              name = "SOUND_MIXER_AGC";              break;
678  case SOUND_MIXER_3DSE:             name = "SOUND_MIXER_3DSE";             break;
679  case SOUND_MIXER_GETLEVELS:        name = "SOUND_MIXER_GETLEVELS";        break;
680  case SOUND_MIXER_SETLEVELS:        name = "SOUND_MIXER_SETLEVELS";        break;
681  case SOUND_MIXER_PRIVATE1:         name = "SOUND_MIXER_PRIVATE1";         break;
682  case SOUND_MIXER_PRIVATE2:         name = "SOUND_MIXER_PRIVATE2";         break;
683  case SOUND_MIXER_PRIVATE3:         name = "SOUND_MIXER_PRIVATE3";         break;
684  case SOUND_MIXER_PRIVATE4:         name = "SOUND_MIXER_PRIVATE4";         break;
685  case SOUND_MIXER_PRIVATE5:         name = "SOUND_MIXER_PRIVATE5";         break;
686  case OSS_GETVERSION:               name = "OSS_GETVERSION";               break;
687//  case SOUND_MIXER_READ_CAPS:        name = "SOUND_MIXER_READ_CAPS";        break;
688  case SOUND_MIXER_READ_MUTE:        name = "SOUND_MIXER_READ_MUTE";        break;
689/*
690  case :     name = "";     break;
691  case :     name = "";     break;
692*/
693 }
694 if ( name != NULL ) {
695  ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p): unspported mixer command %s", handle, req, ip, name);
696  ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p) = -1 // errno = ENOSYS", handle, req, ip);
697  errno = ENOSYS;
698  return -1;
699 }
700#endif
701
702 switch (req) {
703  case SOUND_MIXER_READ_VOLUME:    o_w = 0; o_sid = _mix_settings.sid.volume;   break;
704  case SOUND_MIXER_READ_LINE:      o_w = 0; o_sid = _mix_settings.sid.line;     break;
705  case SOUND_MIXER_READ_LINE1:     o_w = 0; o_sid = _mix_settings.sid.line1;    break;
706  case SOUND_MIXER_READ_LINE2:     o_w = 0; o_sid = _mix_settings.sid.line2;    break;
707  case SOUND_MIXER_READ_LINE3:     o_w = 0; o_sid = _mix_settings.sid.line3;    break;
708#if 0
709  case SOUND_MIXER_READ_DIGITAL1:  o_w = 0; o_sid = _mix_settings.sid.digital1; break;
710  case SOUND_MIXER_READ_DIGITAL2:  o_w = 0; o_sid = _mix_settings.sid.digital2; break;
711  case SOUND_MIXER_READ_DIGITAL3:  o_w = 0; o_sid = _mix_settings.sid.digital3; break;
712#endif
713  case SOUND_MIXER_WRITE_VOLUME:   o_w = 1; o_sid = _mix_settings.sid.volume;   break;
714  case SOUND_MIXER_WRITE_LINE:     o_w = 1; o_sid = _mix_settings.sid.line;     break;
715  case SOUND_MIXER_WRITE_LINE1:    o_w = 1; o_sid = _mix_settings.sid.line1;    break;
716  case SOUND_MIXER_WRITE_LINE2:    o_w = 1; o_sid = _mix_settings.sid.line2;    break;
717  case SOUND_MIXER_WRITE_LINE3:    o_w = 1; o_sid = _mix_settings.sid.line3;    break;
718#if 0
719  case SOUND_MIXER_WRITE_DIGITAL1: o_w = 1; o_sid = _mix_settings.sid.digital1; break;
720  case SOUND_MIXER_WRITE_DIGITAL2: o_w = 1; o_sid = _mix_settings.sid.digital2; break;
721  case SOUND_MIXER_WRITE_DIGITAL3: o_w = 1; o_sid = _mix_settings.sid.digital3; break;
722#endif
723  // we handle PCM seperatly as we want to be abled to abled to handle it on a stream (not mixer), too:
724  case SOUND_MIXER_READ_PCM:
725    o_w = 0;
726    if ( handle->type == HT_STREAM ) {
727     o_sid = roar_stream_get_id(&(handle->stream));
728    } else {
729     o_sid = _mix_settings.sid.pcm;
730    }
731   break;
732  case SOUND_MIXER_WRITE_PCM:
733    o_w = 1;
734    if ( handle->type == HT_STREAM ) {
735     o_sid = roar_stream_get_id(&(handle->stream));
736    } else {
737     o_sid = _mix_settings.sid.pcm;
738    }
739   break;
740 }
741 if ( o_sid != -1 ) {
742  // set/get volume
743  if ( o_w ) {
744   mixer.scale    = OSS_VOLUME_SCALE;
745   mixer.mixer[0] = ( *ip       & 0xFF);
746   mixer.mixer[1] = ((*ip >> 8) & 0xFF);
747   if ( roar_set_vol(&(handle->session->con), o_sid, &mixer, 2) == -1 ) {
748    errno = EIO;
749    return -1;
750   }
751   return 0;
752  } else {
753   if ( roar_get_vol(&(handle->session->con), o_sid, &mixer, &channels) == -1 ) {
754    errno = EIO;
755    return -1;
756   }
757   *ip = ((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale) | (((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale)<<8);
758   return 0;
759  }
760 }
761
762 switch (req) {
763  case SOUND_MIXER_READ_STEREODEVS: /* FIXME: check the streams for channel config */
764  case SOUND_MIXER_READ_DEVMASK:
765    *ip = 0;
766
767    if ( _mix_settings.sid.volume != -1 )
768     *ip |= SOUND_MASK_VOLUME;
769    if ( _mix_settings.sid.pcm != -1 )
770     *ip |= SOUND_MASK_PCM;
771    if ( _mix_settings.sid.line != -1 )
772     *ip |= SOUND_MASK_LINE;
773    if ( _mix_settings.sid.line1 != -1 )
774     *ip |= SOUND_MASK_LINE1;
775    if ( _mix_settings.sid.line2 != -1 )
776     *ip |= SOUND_MASK_LINE2;
777    if ( _mix_settings.sid.line3 != -1 )
778     *ip |= SOUND_MASK_LINE3;
779    if ( _mix_settings.sid.digital1 != -1 )
780#if 0
781     *ip |= SOUND_MASK_DIGITAL1;
782    if ( _mix_settings.sid.digital2 != -1 )
783     *ip |= SOUND_MASK_DIGITAL2;
784    if ( _mix_settings.sid.digital3 != -1 )
785     *ip |= SOUND_MASK_DIGITAL3;
786#endif
787
788    return 0;
789   break;
790  case SOUND_MIXER_READ_RECMASK:
791  case SOUND_MIXER_READ_RECSRC:
792    *ip = SOUND_MASK_VOLUME; // we can currently only read from mixer
793    return 0;
794   break;
795  case SOUND_MIXER_WRITE_RECSRC:
796    if ( *ip == SOUND_MASK_VOLUME ) {
797     return  0;
798    } else {
799     errno = ENOTSUP;
800     return -1;
801    }
802   break;
803  case SOUND_MIXER_READ_CAPS:
804    *ip = 0;
805    return 0;
806   break;
807  case SOUND_MIXER_INFO:
808    info = vp;
809    memset(info, 0, sizeof(*info));
810    strcpy(info->id, "RoarAudio");
811    strcpy(info->name, "RoarAudio");
812    return 0;
813   break;
814 }
815
816 ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p): unknown mixer CTL", handle, req, ip);
817// _os.ioctl(-1, req, ip);
818 ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p) = -1 // errno = ENOSYS", handle, req, ip);
819 errno = ENOSYS;
820 return -1;
821}
822
823// -------------------------------------
824// buffer size calculation:
825// -------------------------------------
826
827static size_t _get_stream_buffersize (struct handle * handle) {
828 if ( handle->stream_buffersize )
829  return handle->stream_buffersize;
830
831 return handle->stream_buffersize = handle->stream.info.rate     *
832                                    handle->stream.info.channels *
833                                    handle->stream.info.bits     / 800;
834}
835
836// -------------------------------------
837// emulated functions follow:
838// -------------------------------------
839
840int     open(const char *pathname, int flags, ...) {
841 int     ret;
842 mode_t  mode = 0;
843 va_list args;
844
845 _init();
846
847 if ( pathname == NULL ) {
848  errno = EFAULT;
849  return -1;
850 }
851
852 ROAR_DBG("open(pathname='%s', flags=%x, ...) = ?\n", pathname, flags);
853 ret = _open_file(pathname, flags);
854
855 switch (ret) {
856  case -2:       // continue as normal, use _op.open()
857   break;
858  case -1:       // pass error to caller
859    return -1;
860   break;
861  default:       // return successfully opened pointer to caller
862    return ret;
863   break;
864 }
865
866 if (flags & O_CREAT) {
867  va_start(args, flags);
868  mode = va_arg(args, mode_t);
869  va_end(args);
870 }
871
872 return _os.open(pathname, flags, mode);
873}
874
875int     close(int fd) {
876 struct pointer * pointer;
877 _init();
878
879 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
880  _close_pointer(pointer);
881  return 0;
882 }
883
884 return _os.close(fd);
885}
886
887ssize_t write(int fd, const void *buf, size_t count) {
888 struct roar_roardmx_message roardmxmsg;
889 struct pointer * pointer;
890 ssize_t ret;
891 size_t i;
892
893 _init();
894
895 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
896  ROAR_DBG("write(fd=%i, buf=%p, count=%lu) = ? // pointer write", fd, buf, (long unsigned int) count);
897  switch (pointer->handle->type) {
898   case HT_STREAM:
899     if ( pointer->handle->stream_opened == 0 ) {
900      if ( _open_stream(pointer->handle) == -1 ) {
901       errno = EIO;
902       return -1;
903      }
904     }
905     ret = roar_vio_write(&(pointer->handle->stream_vio), (char*)buf, count);
906     if ( ret > 0 )
907      pointer->handle->writec += ret;
908     return ret;
909    break;
910   case HT_DMX:
911     if ( pointer->handle->stream_opened == 0 ) {
912      if ( _open_stream(pointer->handle) == -1 ) {
913       errno = EIO;
914       return -1;
915      }
916     }
917     if ( count > 0 ) {
918      if ( roar_roardmx_message_new_sset(&roardmxmsg) == -1 ) {
919       errno = EIO;
920       return -1;
921      }
922      for (i = 0; i < count; i++) {
923       if ( roar_roardmx_message_add_chanval(&roardmxmsg, pointer->handle->pos + i, ((unsigned char*)buf)[i]) == -1 ) {
924#ifdef EMSGSIZE
925        errno = EMSGSIZE;
926#else
927        errno = EIO;
928#endif
929        return -1;
930       }
931      }
932      if ( roar_roardmx_message_send(&roardmxmsg, &(pointer->handle->stream_vio)) == -1 ) {
933       errno = EIO;
934       return -1;
935      }
936     }
937     pointer->handle->pos += count;
938     return count;
939    break;
940   default:
941     errno = EINVAL;
942     return -1;
943    break;
944  }
945 }
946
947 return _os.write(fd, buf, count);
948}
949
950ssize_t read(int fd, void *buf, size_t count) {
951 struct pointer * pointer;
952 ssize_t ret;
953
954 _init();
955
956 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
957  if ( pointer->handle->type == HT_STREAM ) {
958   if ( pointer->handle->stream_opened == 0 ) {
959    if ( _open_stream(pointer->handle) == -1 ) {
960     errno = EIO;
961     return -1;
962    }
963   }
964   ret = roar_vio_read(&(pointer->handle->stream_vio), buf, count);
965   if ( ret > 0 )
966    pointer->handle->readc += ret;
967   return ret;
968  } else {
969   errno = EINVAL;
970   return -1;
971  }
972 }
973
974 return _os.read(fd, buf, count);
975}
976
977off_t lseek(int fildes, off_t offset, int whence) {
978 struct pointer * pointer;
979
980 _init();
981
982 if ( (pointer = _get_pointer_by_fh(fildes)) != NULL ) {
983  if ( pointer->handle->type == HT_DMX ) {
984   switch (whence) {
985    case SEEK_SET:
986      pointer->handle->pos  = offset;
987     break;
988    case SEEK_CUR:
989      pointer->handle->pos += offset;
990     break;
991    case SEEK_END:
992    default:
993      errno = EINVAL;
994      return -1;
995     break;
996   }
997   return pointer->handle->pos;
998  } else {
999   errno = EINVAL;
1000   return -1;
1001  }
1002 }
1003
1004 return _os.lseek(fildes, offset, whence);
1005}
1006
1007IOCTL() {
1008 map_args;
1009 struct pointer * pointer;
1010 struct handle  * handle;
1011 int * ip = NULL;
1012 size_t tmp;
1013 audio_buf_info * bi;
1014 count_info     * ci;
1015#ifdef __FIXME__
1016 char * nosys_reqname = NULL;
1017#endif
1018#ifdef va_argp
1019 va_list args;
1020#endif
1021
1022 _init();
1023
1024// ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = ?", __fd, (long unsigned int) __request);
1025
1026#ifdef va_argp
1027 va_start (args, ioctl_lastarg);
1028 argp = va_arg (args, void *);
1029 va_end (args);
1030#endif
1031
1032// ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): argp=%p", __fd, (long unsigned int) __request, argp);
1033
1034 if ( (pointer = _get_pointer_by_fh(__fd)) != NULL ) {
1035  ip = argp;
1036//  ROAR_DBG("ioctl(__fd=%i, __request=0x%lx): ip=%p", __fd, (long unsigned int) __request, ip);
1037#ifdef __FIXME__
1038  switch ((handle = pointer->handle)->type) {
1039   case SOUND_PCM_READ_RATE: nosys_reqname = "SOUND_PCM_READ_RATE"; break;
1040   case SOUND_PCM_READ_CHANNELS: nosys_reqname = "SOUND_PCM_READ_CHANNELS"; break;
1041   case SOUND_PCM_READ_BITS: nosys_reqname = "SOUND_PCM_READ_BITS"; break;
1042   case SOUND_PCM_READ_FILTER: nosys_reqname = "SOUND_PCM_READ_FILTER"; break;
1043   case SNDCTL_COPR_RESET: nosys_reqname = "SNDCTL_COPR_RESET"; break;
1044   case SNDCTL_COPR_LOAD: nosys_reqname = "SNDCTL_COPR_LOAD"; break;
1045   case SNDCTL_COPR_HALT: nosys_reqname = "SNDCTL_COPR_HALT"; break;
1046   case SNDCTL_COPR_RDATA: nosys_reqname = "SNDCTL_COPR_RDATA"; break;
1047   case SNDCTL_COPR_RCODE: nosys_reqname = "SNDCTL_COPR_RCODE"; break;
1048   case SNDCTL_COPR_WDATA: nosys_reqname = "SNDCTL_COPR_WDATA"; break;
1049   case SNDCTL_COPR_WCODE: nosys_reqname = "SNDCTL_COPR_WCODE"; break;
1050   case SNDCTL_COPR_RUN: nosys_reqname = "SNDCTL_COPR_RUN"; break;
1051   case SNDCTL_COPR_SENDMSG: nosys_reqname = "SNDCTL_COPR_SENDMSG"; break;
1052   case SNDCTL_COPR_RCVMSG: nosys_reqname = "SNDCTL_COPR_RCVMSG"; break;
1053   case SNDCTL_DSP_GETCAPS: nosys_reqname = "SNDCTL_DSP_GETCAPS"; break;
1054   default: nosys_reqname = "<<<UNKNOWN>>>"; break;
1055/*
1056   case : nosys_reqname = ""; break;
1057   case : nosys_reqname = ""; break;
1058   case : nosys_reqname = ""; break;
1059*/
1060  }
1061#endif
1062  switch ((handle = pointer->handle)->type) {
1063   case HT_STREAM:
1064     switch (__request) {
1065      case SNDCTL_DSP_RESET:
1066      case SNDCTL_DSP_POST:
1067      case SNDCTL_DSP_SYNC: // ignore for the moment.
1068      case SNDCTL_DSP_SETFRAGMENT: // any fragments should be ok for us...
1069      case SNDCTL_DSP_SETTRIGGER: // we should implement this using PAUSE flag.
1070        return 0;
1071       break;
1072      case SNDCTL_DSP_SPEED:
1073        handle->stream.info.rate = *ip;
1074        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): rate=%i", __fd, (long unsigned int) __request, *ip);
1075        return 0;
1076       break;
1077      case SNDCTL_DSP_CHANNELS:
1078        handle->stream.info.channels = *ip;
1079        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): channels=%i", __fd, (long unsigned int) __request, *ip);
1080        return 0;
1081       break;
1082      case SNDCTL_DSP_STEREO:
1083        handle->stream.info.channels = *ip ? 2 : 1;
1084        return 0;
1085       break;
1086      case SNDCTL_DSP_GETBLKSIZE:
1087        *ip = _get_stream_buffersize(handle);
1088        return 0;
1089       break;
1090      case SNDCTL_DSP_SETFMT:
1091        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): fmt=0x%x", __fd, (long unsigned int) __request, *ip);
1092        return _ioctl_stream_format(handle, *ip);
1093       break;
1094      case SNDCTL_DSP_GETFMTS:
1095//        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): ip=%p", __fd, (long unsigned int) __request, ip);
1096        *ip = _ioctl_stream_format_list();
1097        return 0;
1098       break;
1099      case SNDCTL_DSP_GETOSPACE:
1100      case SNDCTL_DSP_GETISPACE:
1101        bi = argp;
1102        memset(bi, 0, sizeof(*bi));
1103        bi->bytes      = _get_stream_buffersize(handle);
1104        bi->fragments  = 1;
1105        bi->fragsize   = bi->bytes;
1106        bi->fragstotal = 1;
1107        return 0;
1108       break;
1109      case SNDCTL_DSP_GETOPTR:
1110        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): writec=%lu", __fd, (long unsigned int) __request, (long unsigned int) handle->writec);
1111        ci = argp;
1112        memset(ci, 0, sizeof(*ci));
1113        ci->bytes  = handle->writec;
1114        ci->blocks = ci->bytes / (tmp = _get_stream_buffersize(handle));
1115        ci->ptr    = ci->bytes % tmp;
1116        return 0;
1117       break;
1118      case SNDCTL_DSP_GETIPTR:
1119        ci = argp;
1120        memset(ci, 0, sizeof(*ci));
1121        ci->bytes  = handle->readc;
1122        ci->blocks = ci->bytes / (tmp = _get_stream_buffersize(handle));
1123        ci->ptr    = ci->bytes % tmp;
1124        return 0;
1125       break;
1126#ifdef SNDCTL_DSP_GETPLAYVOL
1127      case SNDCTL_DSP_GETPLAYVOL:
1128        return _ioctl_mixer(handle, SOUND_MIXER_READ_PCM, argp);
1129       break;
1130#endif
1131#ifdef SNDCTL_DSP_SETPLAYVOL
1132      case SNDCTL_DSP_SETPLAYVOL:
1133        return _ioctl_mixer(handle, SOUND_MIXER_WRITE_PCM, argp);
1134       break;
1135#endif
1136      default:
1137#ifdef __FIXME__
1138        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX (%s)) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request, nosys_reqname);
1139#else
1140        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
1141#endif
1142        errno = ENOSYS;
1143        return -1;
1144     }
1145    break;
1146   case HT_MIXER:
1147     return _ioctl_mixer(handle, __request, argp);
1148    break;
1149   default:
1150     ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): unknown handle type: no ioctl()s supported", __fd, (long unsigned int) __request);
1151     ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
1152     errno = EINVAL;
1153     return -1;
1154    break;
1155  }
1156 }
1157
1158#ifdef IOCTL_IS_ALIAS
1159 errno = ENOSYS;
1160 return -1;
1161#else
1162 return _os.ioctl(__fd, __request, argp);
1163#endif
1164}
1165
1166int dup(int oldfd) {
1167 struct pointer * pointer;
1168 int ret;
1169
1170 _init();
1171
1172 ret = _os.dup(oldfd);
1173
1174 if (ret == -1)
1175  return -1;
1176
1177 if ( (pointer = _get_pointer_by_fh(oldfd)) != NULL ) {
1178  if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1179   _os.close(ret);
1180   return -1;
1181  }
1182 }
1183
1184 return ret;
1185}
1186
1187int dup2(int oldfd, int newfd) {
1188 struct pointer * pointer;
1189 int ret;
1190
1191 _init();
1192
1193 ret = _os.dup2(oldfd, newfd);
1194
1195 if (ret == -1)
1196  return -1;
1197
1198 if ( (pointer = _get_pointer_by_fh(oldfd)) != NULL ) {
1199  if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1200   _os.close(ret);
1201   return -1;
1202  }
1203 }
1204
1205 return ret;
1206}
1207
1208// -------------------------------------
1209// emulated stdio functions follow:
1210// -------------------------------------
1211
1212//roar_vio_to_stdio
1213
1214FILE *fopen(const char *path, const char *mode) {
1215 struct pointer * pointer;
1216 FILE  * fr;
1217 int     ret;
1218 int     r = 0, w = 0;
1219 int     flags = 0;
1220 int     i;
1221 register char c;
1222
1223 _init();
1224
1225 if ( path == NULL || mode == NULL ) {
1226  errno = EFAULT;
1227  return NULL;
1228 }
1229
1230 ROAR_DBG("open(path='%s', mode='%s') = ?\n", path, mode);
1231
1232 for (i = 0; (c = mode[i]) != 0; i++) {
1233  switch (c) {
1234   case 'r': r = 1; break;
1235   case 'w': w = 1; break;
1236   case 'a': w = 1; break;
1237   case '+':
1238     r = 1;
1239     w = 1;
1240    break;
1241  }
1242 }
1243
1244 if ( r && w ) {
1245  flags = O_RDWR;
1246 } else if ( r ) {
1247  flags = O_RDONLY;
1248 } else if ( w ) {
1249  flags = O_WRONLY;
1250 } else {
1251  errno = EINVAL;
1252  return NULL;
1253 }
1254
1255 ret = _open_file(path, flags);
1256
1257 switch (ret) {
1258  case -2:       // continue as normal, use _op.open()
1259   break;
1260  case -1:       // pass error to caller
1261    return NULL;
1262   break;
1263  default:       // return successfully opened pointer to caller
1264    if ( (pointer = _get_pointer_by_fh(ret)) != NULL ) {
1265     if ( (fr = roar_vio_to_stdio(&(pointer->handle->stream_vio), flags)) == NULL ) {
1266      errno = EIO;
1267      return NULL;
1268     } else {
1269      return fr;
1270     }
1271    } else {
1272     errno = EIO;
1273     return NULL;
1274    }
1275   break;
1276 }
1277
1278 return _os.fopen(path, mode);
1279}
1280
1281#endif
1282
1283//ll
Note: See TracBrowser for help on using the repository browser.