source: roaraudio/libroaross/libroaross.c @ 3248:93efae2764f5

Last change on this file since 3248:93efae2764f5 was 3248:93efae2764f5, checked in by phi, 14 years ago

reject invalide open

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