source: roaraudio/libroaross/libroaross.c @ 3662:04f27c561695

Last change on this file since 3662:04f27c561695 was 3662:04f27c561695, checked in by phi, 14 years ago

device list should be global!

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