source: roaraudio/libroaross/libroaross.c @ 3665:c5a64a24bef4

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

added a lot debug lions, fixed bug with mixer

File size: 34.1 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 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = ?", pathname, flags);
454
455 for (i = 0; _device_list[i].prefix != NULL; i++) {
456  if ( !strcmp(pathname, _device_list[i].prefix) ) {
457   ptr = &(_device_list[i]);
458  }
459 }
460
461 if ( ptr == NULL )
462  return -2;
463
464 if ( (session = _open_session(NULL, NULL)) == NULL ) {
465  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
466  return -1;
467 }
468
469 if ( (handle = _open_handle(session)) == NULL ) {
470  _close_session(session);
471  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
472  return -1;
473 }
474
475 handle->type       = ptr->type;
476 handle->stream_dir = -1;
477
478 switch (flags & (O_RDONLY|O_WRONLY|O_RDWR)) {
479  case O_RDONLY:
480    switch (ptr->type) {
481     case HT_WAVEFORM:
482       handle->stream_dir = ROAR_DIR_MONITOR;
483      break;
484     case HT_MIDI:
485       handle->stream_dir = ROAR_DIR_MIDI_OUT;
486      break;
487     case HT_DMX:
488       handle->stream_dir = ROAR_DIR_LIGHT_OUT;
489      break;
490     case HT_MIXER:
491      break;
492     default:
493       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
494       return -1;
495    }
496   break;
497  case O_WRONLY:
498    switch (ptr->type) {
499     case HT_WAVEFORM:
500       handle->stream_dir = ROAR_DIR_PLAY;
501      break;
502     case HT_MIDI:
503       handle->stream_dir = ROAR_DIR_MIDI_IN;
504      break;
505     case HT_DMX:
506       handle->stream_dir = ROAR_DIR_LIGHT_IN;
507      break;
508     default:
509       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
510       return -1;
511    }
512   break;
513  case O_RDWR:
514    switch (ptr->type) {
515     case HT_WAVEFORM:
516       handle->stream_dir = ROAR_DIR_BIDIR;
517      break;
518     default:
519       ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
520       return -1;
521    }
522   break;
523 }
524
525 switch (handle->type) {
526  case HT_WAVEFORM:
527    handle->type = HT_STREAM;
528   break;
529  case HT_MIDI:
530    handle->type = HT_STREAM;
531    handle->stream.info.rate     = 0;
532    handle->stream.info.bits     = ROAR_MIDI_BITS;
533    handle->stream.info.channels = ROAR_MIDI_CHANNELS_DEFAULT;
534    handle->stream.info.codec    = ROAR_CODEC_MIDI;
535   break;
536  case HT_DMX:
537    handle->stream.info.rate     = 0;
538    handle->stream.info.bits     = ROAR_LIGHT_BITS;
539    handle->stream.info.channels = 512;
540    handle->stream.info.codec    = ROAR_CODEC_ROARDMX;
541   break;
542 }
543
544 if ( (pointer = _open_pointer(handle)) == NULL ) {
545  _close_handle(handle);
546  ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = -1", pathname, flags);
547  return -1;
548 }
549
550 ROAR_DBG("_open_file(pathname='%s', flags=0x%x) = %i", pathname, flags, pointer->fh);
551
552 return pointer->fh;
553}
554
555// -------------------------------------
556// open function for streams:
557// -------------------------------------
558
559static int _open_stream (struct handle * handle) {
560  // FIXME: this should be re-written much more cleanly:
561
562 if ( handle == NULL )
563  return -1;
564
565 if ( roar_vio_simple_new_stream_obj(&(handle->stream_vio),
566                                     &(handle->session->con), &(handle->stream),
567                                     handle->stream.info.rate,
568                                     handle->stream.info.channels,
569                                     handle->stream.info.bits,
570                                     handle->stream.info.codec,
571                                     handle->stream_dir
572                                    ) == -1 )
573  return -1;
574
575 handle->stream_opened++;
576
577 _mix_settings.sid.pcm = roar_stream_get_id(&(handle->stream));
578
579 return 0;
580}
581
582// -------------------------------------
583// function to parse format:
584// -------------------------------------
585
586static int _ioctl_stream_format (struct handle * handle, int format) {
587 struct roar_audio_info * info = &(handle->stream.info);
588
589 switch (format) {
590  case AFMT_S8:
591    info->bits  = 8;
592    info->codec = ROAR_CODEC_PCM_S_LE;
593   break;
594  case AFMT_U8:
595    info->bits  = 8;
596    info->codec = ROAR_CODEC_PCM_U_LE;
597   break;
598  case AFMT_S16_BE:
599    info->bits  = 16;
600    info->codec = ROAR_CODEC_PCM_S_BE;
601   break;
602  case AFMT_S16_LE:
603    info->bits  = 16;
604    info->codec = ROAR_CODEC_PCM_S_LE;
605   break;
606  case AFMT_U16_BE:
607    info->bits  = 16;
608    info->codec = ROAR_CODEC_PCM_U_BE;
609   break;
610  case AFMT_U16_LE:
611    info->bits  = 16;
612    info->codec = ROAR_CODEC_PCM_U_LE;
613   break;
614#ifdef AFMT_S32_BE
615  case AFMT_S32_BE:
616    info->bits  = 32;
617    info->codec = ROAR_CODEC_PCM_S_BE;
618   break;
619#endif
620#ifdef AFMT_S32_LE
621  case AFMT_S32_LE:
622    info->bits  = 32;
623    info->codec = ROAR_CODEC_PCM_S_LE;
624   break;
625#endif
626  case AFMT_A_LAW:
627    info->bits  = 8;
628    info->codec = ROAR_CODEC_ALAW;
629   break;
630  case AFMT_MU_LAW:
631    info->bits  = 8;
632    info->codec = ROAR_CODEC_MULAW;
633   break;
634#ifdef AFMT_VORBIS
635  case AFMT_VORBIS:
636    info->codec = ROAR_CODEC_OGG_VORBIS;
637   break;
638#endif
639  default:
640    ROAR_DBG("_ioctl_stream_format(*): unsupported format");
641    errno = ENOSYS;
642    return -1;
643   break;
644 }
645
646 return 0;
647}
648
649static inline int _ioctl_stream_format_list (void) {
650 int format = 0;
651
652 format |= AFMT_S8;
653 format |= AFMT_U8;
654
655 format |= AFMT_S16_BE;
656 format |= AFMT_S16_LE;
657
658 format |= AFMT_U16_BE;
659 format |= AFMT_U16_LE;
660
661#ifdef AFMT_S32_BE
662 format |= AFMT_S32_BE;
663#endif
664#ifdef AFMT_S32_LE
665 format |= AFMT_S32_LE;
666#endif
667
668 format |= AFMT_A_LAW;
669 format |= AFMT_MU_LAW;
670
671#ifdef AFMT_VORBIS
672 format |= AFMT_VORBIS;
673#endif
674
675 return format;
676}
677
678// -------------------------------------
679// mixer ioctls:
680// -------------------------------------
681
682static int _ioctl_mixer (struct handle * handle, long unsigned int req, void * vp) {
683 mixer_info * info;
684 int channels;
685 struct roar_mixer_settings mixer;
686 int o_w    =  0;
687 int o_sid  = -1;
688 int * ip   = vp;
689#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
690 char * name = NULL;
691#endif
692
693#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
694 switch (req) {
695#if 0
696  case SNDCTL_MIX_DESCRIPTION: name = "SNDCTL_MIX_DESCRIPTION"; break;
697  case SNDCTL_MIX_ENUMINFO:    name = "SNDCTL_MIX_ENUMINFO";    break;
698  case SNDCTL_MIX_EXTINFO:     name = "SNDCTL_MIX_EXTINFO";     break;
699  case SNDCTL_MIX_NREXT:       name = "SNDCTL_MIX_NREXT";       break;
700  case SNDCTL_MIX_NRMIX:       name = "SNDCTL_MIX_NRMIX";       break;
701  case SNDCTL_MIX_READ:        name = "SNDCTL_MIX_READ";        break;
702  case SNDCTL_MIX_WRITE:       name = "SNDCTL_MIX_WRITE";       break;
703#endif
704//  case SOUND_MIXER_INFO:             name = "SOUND_MIXER_INFO";             break;
705  case SOUND_OLD_MIXER_INFO:         name = "SOUND_OLD_MIXER_INFO";         break;
706  case SOUND_MIXER_ACCESS:           name = "SOUND_MIXER_ACCESS";           break;
707  case SOUND_MIXER_AGC:              name = "SOUND_MIXER_AGC";              break;
708  case SOUND_MIXER_3DSE:             name = "SOUND_MIXER_3DSE";             break;
709  case SOUND_MIXER_GETLEVELS:        name = "SOUND_MIXER_GETLEVELS";        break;
710  case SOUND_MIXER_SETLEVELS:        name = "SOUND_MIXER_SETLEVELS";        break;
711  case SOUND_MIXER_PRIVATE1:         name = "SOUND_MIXER_PRIVATE1";         break;
712  case SOUND_MIXER_PRIVATE2:         name = "SOUND_MIXER_PRIVATE2";         break;
713  case SOUND_MIXER_PRIVATE3:         name = "SOUND_MIXER_PRIVATE3";         break;
714  case SOUND_MIXER_PRIVATE4:         name = "SOUND_MIXER_PRIVATE4";         break;
715  case SOUND_MIXER_PRIVATE5:         name = "SOUND_MIXER_PRIVATE5";         break;
716  case OSS_GETVERSION:               name = "OSS_GETVERSION";               break;
717//  case SOUND_MIXER_READ_CAPS:        name = "SOUND_MIXER_READ_CAPS";        break;
718  case SOUND_MIXER_READ_MUTE:        name = "SOUND_MIXER_READ_MUTE";        break;
719/*
720  case :     name = "";     break;
721  case :     name = "";     break;
722*/
723 }
724 if ( name != NULL ) {
725  ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p): unspported mixer command %s", handle, req, ip, name);
726  ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p) = -1 // errno = ENOSYS", handle, req, ip);
727  errno = ENOSYS;
728  return -1;
729 }
730#endif
731
732 switch (req) {
733  case SOUND_MIXER_READ_VOLUME:    o_w = 0; o_sid = _mix_settings.sid.volume;   break;
734  case SOUND_MIXER_READ_LINE:      o_w = 0; o_sid = _mix_settings.sid.line;     break;
735  case SOUND_MIXER_READ_LINE1:     o_w = 0; o_sid = _mix_settings.sid.line1;    break;
736  case SOUND_MIXER_READ_LINE2:     o_w = 0; o_sid = _mix_settings.sid.line2;    break;
737  case SOUND_MIXER_READ_LINE3:     o_w = 0; o_sid = _mix_settings.sid.line3;    break;
738#if 0
739  case SOUND_MIXER_READ_DIGITAL1:  o_w = 0; o_sid = _mix_settings.sid.digital1; break;
740  case SOUND_MIXER_READ_DIGITAL2:  o_w = 0; o_sid = _mix_settings.sid.digital2; break;
741  case SOUND_MIXER_READ_DIGITAL3:  o_w = 0; o_sid = _mix_settings.sid.digital3; break;
742#endif
743  case SOUND_MIXER_WRITE_VOLUME:   o_w = 1; o_sid = _mix_settings.sid.volume;   break;
744  case SOUND_MIXER_WRITE_LINE:     o_w = 1; o_sid = _mix_settings.sid.line;     break;
745  case SOUND_MIXER_WRITE_LINE1:    o_w = 1; o_sid = _mix_settings.sid.line1;    break;
746  case SOUND_MIXER_WRITE_LINE2:    o_w = 1; o_sid = _mix_settings.sid.line2;    break;
747  case SOUND_MIXER_WRITE_LINE3:    o_w = 1; o_sid = _mix_settings.sid.line3;    break;
748#if 0
749  case SOUND_MIXER_WRITE_DIGITAL1: o_w = 1; o_sid = _mix_settings.sid.digital1; break;
750  case SOUND_MIXER_WRITE_DIGITAL2: o_w = 1; o_sid = _mix_settings.sid.digital2; break;
751  case SOUND_MIXER_WRITE_DIGITAL3: o_w = 1; o_sid = _mix_settings.sid.digital3; break;
752#endif
753  // we handle PCM seperatly as we want to be abled to abled to handle it on a stream (not mixer), too:
754  case SOUND_MIXER_READ_PCM:
755    o_w = 0;
756    if ( handle->type == HT_STREAM ) {
757     o_sid = roar_stream_get_id(&(handle->stream));
758    } else {
759     o_sid = _mix_settings.sid.pcm;
760    }
761   break;
762  case SOUND_MIXER_WRITE_PCM:
763    o_w = 1;
764    if ( handle->type == HT_STREAM ) {
765     o_sid = roar_stream_get_id(&(handle->stream));
766    } else {
767     o_sid = _mix_settings.sid.pcm;
768    }
769   break;
770 }
771 if ( o_sid != -1 ) {
772  // set/get volume
773  if ( o_w ) {
774   mixer.scale    = OSS_VOLUME_SCALE;
775   mixer.mixer[0] = ( *ip       & 0xFF);
776   mixer.mixer[1] = ((*ip >> 8) & 0xFF);
777   if ( roar_set_vol(&(handle->session->con), o_sid, &mixer, 2) == -1 ) {
778    errno = EIO;
779    return -1;
780   }
781   return 0;
782  } else {
783   if ( roar_get_vol(&(handle->session->con), o_sid, &mixer, &channels) == -1 ) {
784    errno = EIO;
785    return -1;
786   }
787   *ip = ((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale) | (((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale)<<8);
788   return 0;
789  }
790 }
791
792 switch (req) {
793  case SOUND_MIXER_READ_STEREODEVS: /* FIXME: check the streams for channel config */
794  case SOUND_MIXER_READ_DEVMASK:
795    *ip = 0;
796
797    if ( _mix_settings.sid.volume != -1 )
798     *ip |= SOUND_MASK_VOLUME;
799    if ( _mix_settings.sid.pcm != -1 )
800     *ip |= SOUND_MASK_PCM;
801    if ( _mix_settings.sid.line != -1 )
802     *ip |= SOUND_MASK_LINE;
803    if ( _mix_settings.sid.line1 != -1 )
804     *ip |= SOUND_MASK_LINE1;
805    if ( _mix_settings.sid.line2 != -1 )
806     *ip |= SOUND_MASK_LINE2;
807    if ( _mix_settings.sid.line3 != -1 )
808     *ip |= SOUND_MASK_LINE3;
809    if ( _mix_settings.sid.digital1 != -1 )
810#if 0
811     *ip |= SOUND_MASK_DIGITAL1;
812    if ( _mix_settings.sid.digital2 != -1 )
813     *ip |= SOUND_MASK_DIGITAL2;
814    if ( _mix_settings.sid.digital3 != -1 )
815     *ip |= SOUND_MASK_DIGITAL3;
816#endif
817
818    return 0;
819   break;
820  case SOUND_MIXER_READ_RECMASK:
821  case SOUND_MIXER_READ_RECSRC:
822    *ip = SOUND_MASK_VOLUME; // we can currently only read from mixer
823    return 0;
824   break;
825  case SOUND_MIXER_WRITE_RECSRC:
826    if ( *ip == SOUND_MASK_VOLUME ) {
827     return  0;
828    } else {
829     errno = ENOTSUP;
830     return -1;
831    }
832   break;
833  case SOUND_MIXER_READ_CAPS:
834    *ip = 0;
835    return 0;
836   break;
837  case SOUND_MIXER_INFO:
838    info = vp;
839    memset(info, 0, sizeof(*info));
840    strcpy(info->id, "RoarAudio");
841    strcpy(info->name, "RoarAudio");
842    return 0;
843   break;
844 }
845
846 ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p): unknown mixer CTL", handle, req, ip);
847// _os.ioctl(-1, req, ip);
848 ROAR_DBG("_ioctl_mixer(handle=%p, req=0x%lX, ip=%p) = -1 // errno = ENOSYS", handle, req, ip);
849 errno = ENOSYS;
850 return -1;
851}
852
853// -------------------------------------
854// buffer size calculation:
855// -------------------------------------
856
857static size_t _get_stream_buffersize (struct handle * handle) {
858 if ( handle->stream_buffersize )
859  return handle->stream_buffersize;
860
861 return handle->stream_buffersize = handle->stream.info.rate     *
862                                    handle->stream.info.channels *
863                                    handle->stream.info.bits     / 800;
864}
865
866// -------------------------------------
867// emulated functions follow:
868// -------------------------------------
869
870int     open(const char *pathname, int flags, ...) {
871 int     ret;
872 mode_t  mode = 0;
873 va_list args;
874
875 _init();
876
877 if ( pathname == NULL ) {
878  errno = EFAULT;
879  return -1;
880 }
881
882 ROAR_DBG("open(pathname='%s', flags=%x, ...) = ?\n", pathname, flags);
883 ret = _open_file(pathname, flags);
884
885 switch (ret) {
886  case -2:       // continue as normal, use _op.open()
887   break;
888  case -1:       // pass error to caller
889    return -1;
890   break;
891  default:       // return successfully opened pointer to caller
892    return ret;
893   break;
894 }
895
896 if (flags & O_CREAT) {
897  va_start(args, flags);
898  mode = va_arg(args, mode_t);
899  va_end(args);
900 }
901
902 return _os.open(pathname, flags, mode);
903}
904
905int     close(int fd) {
906 struct pointer * pointer;
907 _init();
908
909 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
910  _close_pointer(pointer);
911  return 0;
912 }
913
914 return _os.close(fd);
915}
916
917ssize_t write(int fd, const void *buf, size_t count) {
918 struct roar_roardmx_message roardmxmsg;
919 struct pointer * pointer;
920 ssize_t ret;
921 size_t i;
922
923 _init();
924
925 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
926  ROAR_DBG("write(fd=%i, buf=%p, count=%lu) = ? // pointer write", fd, buf, (long unsigned int) count);
927  switch (pointer->handle->type) {
928   case HT_STREAM: // handle stream specific stuff
929     if ( pointer->handle->stream_opened == 0 ) {
930      if ( _open_stream(pointer->handle) == -1 ) {
931       errno = EIO;
932       return -1;
933      }
934     }
935   case HT_VIO: // from here we only look at the VIO object of streams, or handle simple VIOs
936     ret = roar_vio_write(&(pointer->handle->stream_vio), (char*)buf, count);
937     if ( ret > 0 )
938      pointer->handle->writec += ret;
939     return ret;
940    break;
941   case HT_DMX: // DMX need specal handling as we need to convert the protocol
942     if ( pointer->handle->stream_opened == 0 ) {
943      if ( _open_stream(pointer->handle) == -1 ) {
944       errno = EIO;
945       return -1;
946      }
947     }
948     if ( count > 0 ) {
949      if ( roar_roardmx_message_new_sset(&roardmxmsg) == -1 ) {
950       errno = EIO;
951       return -1;
952      }
953      for (i = 0; i < count; i++) {
954       if ( roar_roardmx_message_add_chanval(&roardmxmsg, pointer->handle->pos + i, ((unsigned char*)buf)[i]) == -1 ) {
955#ifdef EMSGSIZE
956        errno = EMSGSIZE;
957#else
958        errno = EIO;
959#endif
960        return -1;
961       }
962      }
963      if ( roar_roardmx_message_send(&roardmxmsg, &(pointer->handle->stream_vio)) == -1 ) {
964       errno = EIO;
965       return -1;
966      }
967     }
968     pointer->handle->pos += count;
969     return count;
970    break;
971   default: // we don't know what to do with other types
972     errno = EINVAL;
973     return -1;
974    break;
975  }
976 }
977
978 return _os.write(fd, buf, count);
979}
980
981ssize_t read(int fd, void *buf, size_t count) {
982 struct pointer * pointer;
983 ssize_t ret;
984
985 _init();
986
987 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
988  switch (pointer->handle->type) {
989   case HT_STREAM:
990     if ( pointer->handle->stream_opened == 0 ) {
991      if ( _open_stream(pointer->handle) == -1 ) {
992       errno = EIO;
993       return -1;
994      }
995     }
996   case HT_VIO:
997     ret = roar_vio_read(&(pointer->handle->stream_vio), buf, count);
998     if ( ret > 0 )
999      pointer->handle->readc += ret;
1000     return ret;
1001    break;
1002   default:
1003     errno = EINVAL;
1004     return -1;
1005    break;
1006  }
1007 }
1008
1009 return _os.read(fd, buf, count);
1010}
1011
1012off_t lseek(int fildes, off_t offset, int whence) {
1013 struct pointer * pointer;
1014
1015 _init();
1016
1017 if ( (pointer = _get_pointer_by_fh(fildes)) != NULL ) {
1018  switch (pointer->handle->type) {
1019   case HT_DMX:
1020     switch (whence) {
1021      case SEEK_SET:
1022        pointer->handle->pos  = offset;
1023       break;
1024      case SEEK_CUR:
1025        pointer->handle->pos += offset;
1026       break;
1027      case SEEK_END:
1028      default:
1029        errno = EINVAL;
1030        return -1;
1031       break;
1032     }
1033     return pointer->handle->pos;
1034    break;
1035   case HT_VIO:
1036     return roar_vio_lseek(&(pointer->handle->stream_vio), offset, whence);
1037    break;
1038   default:
1039     errno = EINVAL;
1040     return -1;
1041    break;
1042  }
1043 }
1044
1045 return _os.lseek(fildes, offset, whence);
1046}
1047
1048IOCTL() {
1049 map_args;
1050 struct pointer * pointer;
1051 struct handle  * handle;
1052 int * ip = NULL;
1053 size_t tmp;
1054 audio_buf_info * bi;
1055 count_info     * ci;
1056#ifdef __FIXME__
1057 char * nosys_reqname = NULL;
1058#endif
1059#ifdef va_argp
1060 va_list args;
1061#endif
1062
1063 _init();
1064
1065// ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = ?", __fd, (long unsigned int) __request);
1066
1067#ifdef va_argp
1068 va_start (args, ioctl_lastarg);
1069 argp = va_arg (args, void *);
1070 va_end (args);
1071#endif
1072
1073// ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): argp=%p", __fd, (long unsigned int) __request, argp);
1074
1075 if ( (pointer = _get_pointer_by_fh(__fd)) != NULL ) {
1076  ip = argp;
1077//  ROAR_DBG("ioctl(__fd=%i, __request=0x%lx): ip=%p", __fd, (long unsigned int) __request, ip);
1078#ifdef __FIXME__
1079  switch ((handle = pointer->handle)->type) {
1080   case SOUND_PCM_READ_RATE: nosys_reqname = "SOUND_PCM_READ_RATE"; break;
1081   case SOUND_PCM_READ_CHANNELS: nosys_reqname = "SOUND_PCM_READ_CHANNELS"; break;
1082   case SOUND_PCM_READ_BITS: nosys_reqname = "SOUND_PCM_READ_BITS"; break;
1083   case SOUND_PCM_READ_FILTER: nosys_reqname = "SOUND_PCM_READ_FILTER"; break;
1084   case SNDCTL_COPR_RESET: nosys_reqname = "SNDCTL_COPR_RESET"; break;
1085   case SNDCTL_COPR_LOAD: nosys_reqname = "SNDCTL_COPR_LOAD"; break;
1086   case SNDCTL_COPR_HALT: nosys_reqname = "SNDCTL_COPR_HALT"; break;
1087   case SNDCTL_COPR_RDATA: nosys_reqname = "SNDCTL_COPR_RDATA"; break;
1088   case SNDCTL_COPR_RCODE: nosys_reqname = "SNDCTL_COPR_RCODE"; break;
1089   case SNDCTL_COPR_WDATA: nosys_reqname = "SNDCTL_COPR_WDATA"; break;
1090   case SNDCTL_COPR_WCODE: nosys_reqname = "SNDCTL_COPR_WCODE"; break;
1091   case SNDCTL_COPR_RUN: nosys_reqname = "SNDCTL_COPR_RUN"; break;
1092   case SNDCTL_COPR_SENDMSG: nosys_reqname = "SNDCTL_COPR_SENDMSG"; break;
1093   case SNDCTL_COPR_RCVMSG: nosys_reqname = "SNDCTL_COPR_RCVMSG"; break;
1094   case SNDCTL_DSP_GETCAPS: nosys_reqname = "SNDCTL_DSP_GETCAPS"; break;
1095   default: nosys_reqname = "<<<UNKNOWN>>>"; break;
1096/*
1097   case : nosys_reqname = ""; break;
1098   case : nosys_reqname = ""; break;
1099   case : nosys_reqname = ""; break;
1100*/
1101  }
1102#endif
1103  switch ((handle = pointer->handle)->type) {
1104   case HT_STREAM:
1105     switch (__request) {
1106      case SNDCTL_DSP_RESET:
1107      case SNDCTL_DSP_POST:
1108      case SNDCTL_DSP_SYNC: // ignore for the moment.
1109      case SNDCTL_DSP_SETFRAGMENT: // any fragments should be ok for us...
1110      case SNDCTL_DSP_SETTRIGGER: // we should implement this using PAUSE flag.
1111        return 0;
1112       break;
1113      case SNDCTL_DSP_SPEED:
1114        handle->stream.info.rate = *ip;
1115        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): rate=%i", __fd, (long unsigned int) __request, *ip);
1116        return 0;
1117       break;
1118      case SNDCTL_DSP_CHANNELS:
1119        handle->stream.info.channels = *ip;
1120        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): channels=%i", __fd, (long unsigned int) __request, *ip);
1121        return 0;
1122       break;
1123      case SNDCTL_DSP_STEREO:
1124        handle->stream.info.channels = *ip ? 2 : 1;
1125        return 0;
1126       break;
1127      case SNDCTL_DSP_GETBLKSIZE:
1128        *ip = _get_stream_buffersize(handle);
1129        return 0;
1130       break;
1131      case SNDCTL_DSP_SETFMT:
1132        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): fmt=0x%x", __fd, (long unsigned int) __request, *ip);
1133        return _ioctl_stream_format(handle, *ip);
1134       break;
1135      case SNDCTL_DSP_GETFMTS:
1136//        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): ip=%p", __fd, (long unsigned int) __request, ip);
1137        *ip = _ioctl_stream_format_list();
1138        return 0;
1139       break;
1140      case SNDCTL_DSP_GETOSPACE:
1141      case SNDCTL_DSP_GETISPACE:
1142        bi = argp;
1143        memset(bi, 0, sizeof(*bi));
1144        bi->bytes      = _get_stream_buffersize(handle);
1145        bi->fragments  = 1;
1146        bi->fragsize   = bi->bytes;
1147        bi->fragstotal = 1;
1148        return 0;
1149       break;
1150      case SNDCTL_DSP_GETOPTR:
1151        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): writec=%lu", __fd, (long unsigned int) __request, (long unsigned int) handle->writec);
1152        ci = argp;
1153        memset(ci, 0, sizeof(*ci));
1154        ci->bytes  = handle->writec;
1155        ci->blocks = ci->bytes / (tmp = _get_stream_buffersize(handle));
1156        ci->ptr    = ci->bytes % tmp;
1157        return 0;
1158       break;
1159      case SNDCTL_DSP_GETIPTR:
1160        ci = argp;
1161        memset(ci, 0, sizeof(*ci));
1162        ci->bytes  = handle->readc;
1163        ci->blocks = ci->bytes / (tmp = _get_stream_buffersize(handle));
1164        ci->ptr    = ci->bytes % tmp;
1165        return 0;
1166       break;
1167#ifdef SNDCTL_DSP_GETPLAYVOL
1168      case SNDCTL_DSP_GETPLAYVOL:
1169        return _ioctl_mixer(handle, SOUND_MIXER_READ_PCM, argp);
1170       break;
1171#endif
1172#ifdef SNDCTL_DSP_SETPLAYVOL
1173      case SNDCTL_DSP_SETPLAYVOL:
1174        return _ioctl_mixer(handle, SOUND_MIXER_WRITE_PCM, argp);
1175       break;
1176#endif
1177      default:
1178#ifdef __FIXME__
1179        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX (%s)) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request, nosys_reqname);
1180#else
1181        ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
1182#endif
1183        errno = ENOSYS;
1184        return -1;
1185     }
1186    break;
1187   case HT_MIXER:
1188     return _ioctl_mixer(handle, __request, argp);
1189    break;
1190   default:
1191     ROAR_DBG("ioctl(__fd=%i, __request=0x%lX): unknown handle type: no ioctl()s supported", __fd, (long unsigned int) __request);
1192     ROAR_DBG("ioctl(__fd=%i, __request=0x%lX) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
1193     errno = EINVAL;
1194     return -1;
1195    break;
1196  }
1197 }
1198
1199#ifdef IOCTL_IS_ALIAS
1200 errno = ENOSYS;
1201 return -1;
1202#else
1203 return _os.ioctl(__fd, __request, argp);
1204#endif
1205}
1206
1207int dup(int oldfd) {
1208 struct pointer * pointer;
1209 int ret;
1210
1211 _init();
1212
1213 ret = _os.dup(oldfd);
1214
1215 if (ret == -1)
1216  return -1;
1217
1218 if ( (pointer = _get_pointer_by_fh(oldfd)) != NULL ) {
1219  if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1220   _os.close(ret);
1221   return -1;
1222  }
1223 }
1224
1225 return ret;
1226}
1227
1228int dup2(int oldfd, int newfd) {
1229 struct pointer * pointer;
1230 int ret;
1231
1232 _init();
1233
1234 ret = _os.dup2(oldfd, newfd);
1235
1236 if (ret == -1)
1237  return -1;
1238
1239 if ( (pointer = _get_pointer_by_fh(oldfd)) != NULL ) {
1240  if ( _attach_pointer(pointer->handle, ret) == NULL ) {
1241   _os.close(ret);
1242   return -1;
1243  }
1244 }
1245
1246 return ret;
1247}
1248
1249// -------------------------------------
1250// emulated stdio functions follow:
1251// -------------------------------------
1252
1253//roar_vio_to_stdio
1254
1255FILE *fopen(const char *path, const char *mode) {
1256 struct pointer * pointer;
1257 FILE  * fr;
1258 int     ret;
1259 int     r = 0, w = 0;
1260 int     flags = 0;
1261 int     i;
1262 register char c;
1263
1264 _init();
1265
1266 if ( path == NULL || mode == NULL ) {
1267  errno = EFAULT;
1268  return NULL;
1269 }
1270
1271 ROAR_DBG("open(path='%s', mode='%s') = ?\n", path, mode);
1272
1273 for (i = 0; (c = mode[i]) != 0; i++) {
1274  switch (c) {
1275   case 'r': r = 1; break;
1276   case 'w': w = 1; break;
1277   case 'a': w = 1; break;
1278   case '+':
1279     r = 1;
1280     w = 1;
1281    break;
1282  }
1283 }
1284
1285 if ( r && w ) {
1286  flags = O_RDWR;
1287 } else if ( r ) {
1288  flags = O_RDONLY;
1289 } else if ( w ) {
1290  flags = O_WRONLY;
1291 } else {
1292  errno = EINVAL;
1293  return NULL;
1294 }
1295
1296 ret = _open_file(path, flags);
1297
1298 switch (ret) {
1299  case -2:       // continue as normal, use _op.open()
1300   break;
1301  case -1:       // pass error to caller
1302    return NULL;
1303   break;
1304  default:       // return successfully opened pointer to caller
1305    if ( (pointer = _get_pointer_by_fh(ret)) != NULL ) {
1306     if ( (fr = roar_vio_to_stdio(&(pointer->handle->stream_vio), flags)) == NULL ) {
1307      errno = EIO;
1308      return NULL;
1309     } else {
1310      return fr;
1311     }
1312    } else {
1313     errno = EIO;
1314     return NULL;
1315    }
1316   break;
1317 }
1318
1319 return _os.fopen(path, mode);
1320}
1321
1322#endif
1323
1324//ll
Note: See TracBrowser for help on using the repository browser.