source: roaraudio/libroaross/libroaross.c @ 3264:e38f65edb159

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

support for fopen()

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