source: roaraudio/libroaross/libroaross.c @ 3655:db9b17e0f504

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

get it work with ALSA oss plugin!

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