source: roaraudio/libroaross/libroaross.c @ 3664:fdbfa4ac9e3b

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

added a lot things in direction of HT_VIO, fixed some bugs with mixer code

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