source: roaraudio/libroaross/libroaross.c @ 3663:31d8f7ed1737

Last change on this file since 3663:31d8f7ed1737 was 3663:31d8f7ed1737, checked in by phi, 14 years ago

infos on meaning of types

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