source: roaraudio/libroaross/libroaross.c @ 3639:a76479cf4ef4

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

use -Wextra

File size: 30.7 KB
RevLine 
[3138]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
[3517]21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
[3138]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"
[3261]37#include "libroarlight/libroarlight.h"
[3138]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>
[3139]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
[3138]67
[3164]68#ifndef ENOTSUP
69#define ENOTSUP ENOSYS
70#endif
71
[3166]72#if defined(ROAR_OS_NETBSD) && defined(ioctl)
73#define IOCTL_IS_ALIAS
74#endif
75
[3167]76#ifdef ROAR_OS_FREEBSD
77#define mode_t int
78#endif
79
[3169]80#ifdef ROAR_OS_NETBSD
81#define IOCTL() int _oss_ioctl __P((int fd, unsigned long com, void *argp))
[3171]82#define map_args int __fd = fd; unsigned long int __request = com
[3180]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
[3169]88#else
89#define IOCTL() int ioctl (int __fd, unsigned long int __request, ...)
[3171]90#define map_args void * argp
[3169]91#define va_argp
[3180]92#define ioctl_lastarg __request
[3169]93#endif
94
[3153]95#define OSS_VOLUME_SCALE 100
96
[3138]97#define _MAX_POINTER  8
98
[3140]99// handle type:
100#define HT_NONE       0
101#define HT_STREAM     1
102#define HT_MIXER      2
[3244]103#define HT_WAVEFORM   3
104#define HT_MIDI       4
[3246]105#define HT_DMX        5
[3140]106
[3138]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;
[3140]117 int type;
118 struct roar_stream    stream;
119 struct roar_vio_calls stream_vio;
[3144]120 int                   stream_dir;
[3140]121 int                   stream_opened;
[3178]122 size_t                stream_buffersize;
123 size_t                readc, writec;
[3246]124 size_t                pos;
[3138]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);
[3166]132#ifndef IOCTL_IS_ALIAS
[3146]133 int     (*ioctl)(int d, int request, ...);
[3166]134#endif
[3246]135 off_t   (*lseek)(int fildes, off_t offset, int whence);
[3264]136 FILE   *(*fopen)(const char *path, const char *mode);
[3138]137} _os;
138
[3150]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
[3140]165static struct pointer {
[3138]166 int fh;
167 struct handle * handle;
168} _ptr[_MAX_POINTER];
169
170static void _init_os (void) {
171 memset(&_os, 0, sizeof(_os));
[3139]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");
[3166]177#ifndef IOCTL_IS_ALIAS
[3146]178 _os.ioctl = dlsym(REAL_LIBC, "ioctl");
[3166]179#endif
[3246]180 _os.lseek = dlsym(REAL_LIBC, "lseek");
[3264]181 _os.fopen = dlsym(REAL_LIBC, "fopen");
[3138]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
[3157]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
[3138]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) {
[3183]246 ROAR_DBG("_open_session(server='%s', name='%s') = ?", server, name);
247 ROAR_DBG("_open_session(server='%s', name='%s'): _session.refc=%i", server, name, _session.refc);
248
[3138]249 if ( _session.refc == 0 ) {
250
251  if ( name == NULL )
[3500]252   name = getenv("ROAR_OSS_CLIENT_NAME");
253
254  if ( name == NULL )
[3138]255   name = "libroaross client";
256
257  if ( roar_simple_connect(&(_session.con), server, name) == -1 )
258   return NULL;
[3157]259
260  _find_volume_sid(&_session);
[3184]261
262  if ( getenv("ROAR_OSS_KEEP_SESSION") != NULL )
263   _session.refc++;
[3143]264 }
[3138]265
[3143]266 _session.refc++;
[3183]267
268 ROAR_DBG("_open_session(server='%s', name='%s') = %p", server, name, &_session);
[3143]269 return &_session;
[3138]270}
271
272static void _close_session(struct session * session) {
273 if ( session == NULL )
274  return;
275
276 session->refc--;
277
[3144]278 ROAR_DBG("_close_session(session=%p): session->refc=%i", session, session->refc);
279
[3138]280 if ( session->refc == 0 ) {
281  roar_disconnect(&(session->con));
282 }
283}
284
[3140]285static struct handle * _open_handle(struct session * session) {
286 struct handle * handle;
287
[3183]288 ROAR_DBG("_open_handle(session=%p) = ?", session);
289
[3140]290 if ( (handle = roar_mm_malloc(sizeof(struct handle))) == NULL )
291  return NULL;
292
293 memset(handle, 0, sizeof(struct handle));
294
295 handle->refc = 1;
296 handle->session = session;
297 session->refc++; // TODO: better warp this
298 handle->type = HT_NONE;
[3144]299 handle->stream_dir = ROAR_DIR_PLAY;
300 roar_stream_new(&(handle->stream), ROAR_RATE_DEFAULT, ROAR_CHANNELS_DEFAULT, ROAR_BITS_DEFAULT, ROAR_CODEC_DEFAULT);
[3140]301
[3183]302 ROAR_DBG("_open_handle(session=%p) = %p", session, handle);
[3140]303 return handle;
304}
305
306static void _close_handle(struct handle * handle) {
307 if (handle == NULL)
308  return;
309
310 handle->refc--;
311
[3144]312 ROAR_DBG("_close_handle(handle=%p): handle->refc=%i", handle, handle->refc);
313
[3140]314 if ( handle->refc == 0 ) {
315  if ( handle->stream_opened )
316   roar_vio_close(&(handle->stream_vio));
317
[3144]318  handle->session->refc--;
319
320  _close_session(handle->session);
321
[3140]322  roar_mm_free(handle);
323 }
324}
325
326static struct pointer * _get_pointer_by_fh (int fh) {
327 int i;
328
329 for (i = 0; i < _MAX_POINTER; i++) {
330  if ( _ptr[i].fh == fh )
331   return &(_ptr[i]);
332 }
333
334 return NULL;
335}
336
337static struct pointer * _open_pointer(struct handle * handle) {
338 struct pointer * ret = _get_pointer_by_fh(-1);
339
340 if ( ret == NULL )
341  return NULL;
342
343 if ( (ret->fh = _open_dummy()) == -1 )
344  return NULL;
345
346 ret->handle = handle;
347
348 return ret;
349}
350
351static void _close_pointer(struct pointer * pointer) {
352 if ( pointer == NULL )
353  return;
354
355 _os.close(pointer->fh);
356
357 pointer->fh = -1;
358
359 _close_handle(pointer->handle);
360}
[3138]361
362// -------------------------------------
[3142]363// central open function:
364// -------------------------------------
365
366static int _open_file (const char *pathname, int flags) {
[3143]367 struct session * session;
368 struct handle  * handle;
369 struct pointer * pointer;
370 struct {
371  char * prefix;
372  int type;
373 } * ptr = NULL, p[] = {
[3244]374  {"/dev/dsp",           HT_WAVEFORM},
375  {"/dev/audio",         HT_WAVEFORM},
376  {"/dev/sound/dsp",     HT_WAVEFORM},
377  {"/dev/sound/audio",   HT_WAVEFORM},
[3242]378  {"/dev/mixer",         HT_MIXER},
379  {"/dev/sound/mixer",   HT_MIXER},
[3244]380  {"/dev/midi",          HT_MIDI},
[3245]381  {"/dev/rmidi",         HT_MIDI},
382  {"/dev/sound/midi",    HT_MIDI},
383  {"/dev/sound/rmidi",   HT_MIDI},
[3246]384  {"/dev/dmx",           HT_DMX},
[3247]385  {"/dev/misc/dmx",      HT_DMX},
386  {"/dev/dmxin",         HT_DMX},
387  {"/dev/misc/dmxin",    HT_DMX},
[3174]388#ifdef ROAR_DEFAULT_OSS_DEV
[3244]389  {ROAR_DEFAULT_OSS_DEV, HT_WAVEFORM},
[3174]390#endif
[3143]391  {NULL, HT_NONE},
392 };
393 int i;
394
395 for (i = 0; p[i].prefix != NULL; i++) {
396  if ( !strcmp(pathname, p[i].prefix) ) {
397   ptr = &(p[i]);
398  }
399 }
400
401 if ( ptr == NULL )
402  return -2;
403
404 if ( (session = _open_session(NULL, NULL)) == NULL ) {
405  return -1;
406 }
407
408 if ( (handle = _open_handle(session)) == NULL ) {
409  _close_session(session);
410  return -1;
411 }
412
[3244]413 handle->type       = ptr->type;
414 handle->stream_dir = -1;
[3143]415
[3145]416 switch (flags & (O_RDONLY|O_WRONLY|O_RDWR)) {
417  case O_RDONLY:
[3244]418    switch (ptr->type) {
419     case HT_WAVEFORM:
420       handle->stream_dir = ROAR_DIR_MONITOR;
421      break;
422     case HT_MIDI:
423       handle->stream_dir = ROAR_DIR_MIDI_OUT;
424      break;
[3246]425     case HT_DMX:
426       handle->stream_dir = ROAR_DIR_LIGHT_OUT;
427      break;
[3248]428     default:
429       return -1;
[3244]430    }
[3145]431   break;
432  case O_WRONLY:
[3244]433    switch (ptr->type) {
434     case HT_WAVEFORM:
435       handle->stream_dir = ROAR_DIR_PLAY;
436      break;
437     case HT_MIDI:
438       handle->stream_dir = ROAR_DIR_MIDI_IN;
439      break;
[3246]440     case HT_DMX:
441       handle->stream_dir = ROAR_DIR_LIGHT_IN;
442      break;
[3248]443     default:
444       return -1;
[3244]445    }
[3145]446   break;
447  case O_RDWR:
[3244]448    switch (ptr->type) {
449     case HT_WAVEFORM:
450       handle->stream_dir = ROAR_DIR_BIDIR;
451      break;
[3248]452     default:
453       return -1;
[3244]454    }
455   break;
456 }
457
458 switch (handle->type) {
459  case HT_WAVEFORM:
460    handle->type = HT_STREAM;
461   break;
462  case HT_MIDI:
463    handle->type = HT_STREAM;
464    handle->stream.info.rate     = 0;
465    handle->stream.info.bits     = ROAR_MIDI_BITS;
466    handle->stream.info.channels = ROAR_MIDI_CHANNELS_DEFAULT;
467    handle->stream.info.codec    = ROAR_CODEC_MIDI;
[3145]468   break;
[3261]469  case HT_DMX:
470    handle->stream.info.rate     = 0;
471    handle->stream.info.bits     = ROAR_LIGHT_BITS;
472    handle->stream.info.channels = 512;
473    handle->stream.info.codec    = ROAR_CODEC_ROARDMX;
474   break;
[3145]475 }
476
[3143]477 if ( (pointer = _open_pointer(handle)) == NULL ) {
478  _close_handle(handle);
479  return -1;
480 }
481
482 return pointer->fh;
[3142]483}
484
485// -------------------------------------
[3144]486// open function for streams:
487// -------------------------------------
488
489static int _open_stream (struct handle * handle) {
490  // FIXME: this should be re-written much more cleanly:
491
492 if ( handle == NULL )
493  return -1;
494
495 if ( roar_vio_simple_new_stream_obj(&(handle->stream_vio),
496                                     &(handle->session->con), &(handle->stream),
497                                     handle->stream.info.rate,
498                                     handle->stream.info.channels,
499                                     handle->stream.info.bits,
500                                     handle->stream.info.codec,
501                                     handle->stream_dir
502                                    ) == -1 )
503  return -1;
504
505 handle->stream_opened++;
506
[3150]507 _mix_settings.sid.pcm = roar_stream_get_id(&(handle->stream));
508
[3144]509 return 0;
510}
511
512// -------------------------------------
[3147]513// function to parse format:
514// -------------------------------------
515
516static int _ioctl_stream_format (struct handle * handle, int format) {
517 struct roar_audio_info * info = &(handle->stream.info);
518
519 switch (format) {
520  case AFMT_S8:
521    info->bits  = 8;
522    info->codec = ROAR_CODEC_PCM_S_LE;
523   break;
524  case AFMT_U8:
525    info->bits  = 8;
526    info->codec = ROAR_CODEC_PCM_U_LE;
527   break;
528  case AFMT_S16_BE:
529    info->bits  = 16;
530    info->codec = ROAR_CODEC_PCM_S_BE;
531   break;
532  case AFMT_S16_LE:
533    info->bits  = 16;
534    info->codec = ROAR_CODEC_PCM_S_LE;
535   break;
536  case AFMT_U16_BE:
537    info->bits  = 16;
538    info->codec = ROAR_CODEC_PCM_U_BE;
539   break;
540  case AFMT_U16_LE:
541    info->bits  = 16;
542    info->codec = ROAR_CODEC_PCM_U_LE;
543   break;
544#ifdef AFMT_S32_BE
545  case AFMT_S32_BE:
546    info->bits  = 32;
547    info->codec = ROAR_CODEC_PCM_S_BE;
548   break;
549#endif
550#ifdef AFMT_S32_LE
551  case AFMT_S32_LE:
552    info->bits  = 32;
553    info->codec = ROAR_CODEC_PCM_S_LE;
554   break;
555#endif
556  case AFMT_A_LAW:
557    info->bits  = 8;
558    info->codec = ROAR_CODEC_ALAW;
559   break;
560  case AFMT_MU_LAW:
561    info->bits  = 8;
562    info->codec = ROAR_CODEC_MULAW;
563   break;
564#ifdef AFMT_VORBIS
565  case AFMT_VORBIS:
566    info->codec = ROAR_CODEC_OGG_VORBIS;
567   break;
568#endif
[3148]569  default:
[3229]570    ROAR_DBG("_ioctl_stream_format(*): unsupported format");
[3148]571    errno = ENOSYS;
572    return -1;
573   break;
[3147]574 }
575
[3148]576 return 0;
[3147]577}
578
[3149]579static inline int _ioctl_stream_format_list (void) {
580 int format = 0;
581
582 format |= AFMT_S8;
583 format |= AFMT_U8;
584
585 format |= AFMT_S16_BE;
586 format |= AFMT_S16_LE;
587
588 format |= AFMT_U16_BE;
589 format |= AFMT_U16_LE;
590
591#ifdef AFMT_S32_BE
592 format |= AFMT_S32_BE;
593#endif
594#ifdef AFMT_S32_LE
595 format |= AFMT_S32_LE;
596#endif
597
598 format |= AFMT_A_LAW;
599 format |= AFMT_MU_LAW;
600
601#ifdef AFMT_VORBIS
602 format |= AFMT_VORBIS;
603#endif
604
605 return format;
606}
607
[3147]608// -------------------------------------
[3150]609// mixer ioctls:
610// -------------------------------------
611
[3158]612static int _ioctl_mixer (struct handle * handle, long unsigned int req, void * vp) {
[3159]613 mixer_info * info;
[3150]614 int channels;
615 struct roar_mixer_settings mixer;
[3155]616 int o_w    =  0;
[3150]617 int o_sid  = -1;
[3158]618 int * ip   = vp;
[3165]619#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
620 char * name = NULL;
621#endif
[3150]622
[3165]623#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
[3150]624 switch (req) {
625#if 0
626  case SNDCTL_MIX_DESCRIPTION: name = "SNDCTL_MIX_DESCRIPTION"; break;
627  case SNDCTL_MIX_ENUMINFO:    name = "SNDCTL_MIX_ENUMINFO";    break;
628  case SNDCTL_MIX_EXTINFO:     name = "SNDCTL_MIX_EXTINFO";     break;
629  case SNDCTL_MIX_NREXT:       name = "SNDCTL_MIX_NREXT";       break;
630  case SNDCTL_MIX_NRMIX:       name = "SNDCTL_MIX_NRMIX";       break;
631  case SNDCTL_MIX_READ:        name = "SNDCTL_MIX_READ";        break;
632  case SNDCTL_MIX_WRITE:       name = "SNDCTL_MIX_WRITE";       break;
633#endif
[3159]634//  case SOUND_MIXER_INFO:             name = "SOUND_MIXER_INFO";             break;
[3152]635  case SOUND_OLD_MIXER_INFO:         name = "SOUND_OLD_MIXER_INFO";         break;
636  case SOUND_MIXER_ACCESS:           name = "SOUND_MIXER_ACCESS";           break;
637  case SOUND_MIXER_AGC:              name = "SOUND_MIXER_AGC";              break;
638  case SOUND_MIXER_3DSE:             name = "SOUND_MIXER_3DSE";             break;
[3156]639  case SOUND_MIXER_GETLEVELS:        name = "SOUND_MIXER_GETLEVELS";        break;
640  case SOUND_MIXER_SETLEVELS:        name = "SOUND_MIXER_SETLEVELS";        break;
[3152]641  case SOUND_MIXER_PRIVATE1:         name = "SOUND_MIXER_PRIVATE1";         break;
642  case SOUND_MIXER_PRIVATE2:         name = "SOUND_MIXER_PRIVATE2";         break;
643  case SOUND_MIXER_PRIVATE3:         name = "SOUND_MIXER_PRIVATE3";         break;
644  case SOUND_MIXER_PRIVATE4:         name = "SOUND_MIXER_PRIVATE4";         break;
645  case SOUND_MIXER_PRIVATE5:         name = "SOUND_MIXER_PRIVATE5";         break;
646  case OSS_GETVERSION:               name = "OSS_GETVERSION";               break;
[3156]647//  case SOUND_MIXER_READ_CAPS:        name = "SOUND_MIXER_READ_CAPS";        break;
648  case SOUND_MIXER_READ_MUTE:        name = "SOUND_MIXER_READ_MUTE";        break;
[3152]649/*
650  case :     name = "";     break;
[3156]651  case :     name = "";     break;
[3152]652*/
[3150]653 }
654 if ( name != NULL ) {
655  ROAR_DBG("_ioctl_mixer(handle=%p, req=%lu, ip=%p): unspported mixer command %s", handle, req, ip, name);
656  ROAR_DBG("_ioctl_mixer(handle=%p, req=%lu, ip=%p) = -1 // errno = ENOSYS", handle, req, ip);
657  errno = ENOSYS;
658  return -1;
659 }
[3165]660#endif
[3150]661
662 switch (req) {
663  case SOUND_MIXER_READ_VOLUME:    o_w = 0; o_sid = _mix_settings.sid.volume;   break;
664  case SOUND_MIXER_READ_LINE:      o_w = 0; o_sid = _mix_settings.sid.line;     break;
665  case SOUND_MIXER_READ_LINE1:     o_w = 0; o_sid = _mix_settings.sid.line1;    break;
666  case SOUND_MIXER_READ_LINE2:     o_w = 0; o_sid = _mix_settings.sid.line2;    break;
667  case SOUND_MIXER_READ_LINE3:     o_w = 0; o_sid = _mix_settings.sid.line3;    break;
668#if 0
669  case SOUND_MIXER_READ_DIGITAL1:  o_w = 0; o_sid = _mix_settings.sid.digital1; break;
670  case SOUND_MIXER_READ_DIGITAL2:  o_w = 0; o_sid = _mix_settings.sid.digital2; break;
671  case SOUND_MIXER_READ_DIGITAL3:  o_w = 0; o_sid = _mix_settings.sid.digital3; break;
672#endif
673  case SOUND_MIXER_WRITE_VOLUME:   o_w = 1; o_sid = _mix_settings.sid.volume;   break;
674  case SOUND_MIXER_WRITE_LINE:     o_w = 1; o_sid = _mix_settings.sid.line;     break;
675  case SOUND_MIXER_WRITE_LINE1:    o_w = 1; o_sid = _mix_settings.sid.line1;    break;
676  case SOUND_MIXER_WRITE_LINE2:    o_w = 1; o_sid = _mix_settings.sid.line2;    break;
677  case SOUND_MIXER_WRITE_LINE3:    o_w = 1; o_sid = _mix_settings.sid.line3;    break;
678#if 0
679  case SOUND_MIXER_WRITE_DIGITAL1: o_w = 1; o_sid = _mix_settings.sid.digital1; break;
680  case SOUND_MIXER_WRITE_DIGITAL2: o_w = 1; o_sid = _mix_settings.sid.digital2; break;
681  case SOUND_MIXER_WRITE_DIGITAL3: o_w = 1; o_sid = _mix_settings.sid.digital3; break;
682#endif
[3177]683  // we handle PCM seperatly as we want to be abled to abled to handle it on a stream (not mixer), too:
684  case SOUND_MIXER_READ_PCM:
685    o_w = 0;
686    if ( handle->type == HT_STREAM ) {
687     o_sid = roar_stream_get_id(&(handle->stream));
688    } else {
689     o_sid = _mix_settings.sid.pcm;
690    }
691   break;
692  case SOUND_MIXER_WRITE_PCM:
693    o_w = 1;
694    if ( handle->type == HT_STREAM ) {
695     o_sid = roar_stream_get_id(&(handle->stream));
696    } else {
697     o_sid = _mix_settings.sid.pcm;
698    }
699   break;
[3150]700 }
701 if ( o_sid != -1 ) {
702  // set/get volume
703  if ( o_w ) {
[3536]704   mixer.scale    = OSS_VOLUME_SCALE;
705   mixer.mixer[0] = ( *ip       & 0xFF);
706   mixer.mixer[1] = ((*ip >> 8) & 0xFF);
[3150]707   if ( roar_set_vol(&(handle->session->con), o_sid, &mixer, 2) == -1 ) {
[3156]708    errno = EIO;
[3150]709    return -1;
710   }
711   return 0;
712  } else {
713   if ( roar_get_vol(&(handle->session->con), o_sid, &mixer, &channels) == -1 ) {
[3156]714    errno = EIO;
[3150]715    return -1;
716   }
[3153]717   *ip = ((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale) | (((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale)<<8);
[3150]718   return 0;
719  }
720 }
721
722 switch (req) {
[3155]723  case SOUND_MIXER_READ_STEREODEVS: /* FIXME: check the streams for channel config */
[3150]724  case SOUND_MIXER_READ_DEVMASK:
725    *ip = 0;
726
727    if ( _mix_settings.sid.volume != -1 )
728     *ip |= SOUND_MASK_VOLUME;
729    if ( _mix_settings.sid.pcm != -1 )
730     *ip |= SOUND_MASK_PCM;
731    if ( _mix_settings.sid.line != -1 )
732     *ip |= SOUND_MASK_LINE;
733    if ( _mix_settings.sid.line1 != -1 )
734     *ip |= SOUND_MASK_LINE1;
735    if ( _mix_settings.sid.line2 != -1 )
736     *ip |= SOUND_MASK_LINE2;
737    if ( _mix_settings.sid.line3 != -1 )
738     *ip |= SOUND_MASK_LINE3;
739    if ( _mix_settings.sid.digital1 != -1 )
[3156]740#if 0
[3150]741     *ip |= SOUND_MASK_DIGITAL1;
742    if ( _mix_settings.sid.digital2 != -1 )
743     *ip |= SOUND_MASK_DIGITAL2;
744    if ( _mix_settings.sid.digital3 != -1 )
745     *ip |= SOUND_MASK_DIGITAL3;
[3156]746#endif
[3150]747
748    return 0;
749   break;
[3153]750  case SOUND_MIXER_READ_RECMASK:
[3154]751  case SOUND_MIXER_READ_RECSRC:
[3153]752    *ip = SOUND_MASK_VOLUME; // we can currently only read from mixer
753    return 0;
754   break;
[3154]755  case SOUND_MIXER_WRITE_RECSRC:
756    if ( *ip == SOUND_MASK_VOLUME ) {
757     return  0;
758    } else {
759     errno = ENOTSUP;
760     return -1;
761    }
762   break;
[3156]763  case SOUND_MIXER_READ_CAPS:
764    *ip = 0;
765    return 0;
766   break;
[3159]767  case SOUND_MIXER_INFO:
768    info = vp;
769    memset(info, 0, sizeof(*info));
770    strcpy(info->id, "RoarAudio");
771    strcpy(info->name, "RoarAudio");
772    return 0;
773   break;
[3150]774 }
775
776 ROAR_DBG("_ioctl_mixer(handle=%p, req=%lu, ip=%p): unknown mixer CTL", handle, req, ip);
[3156]777// _os.ioctl(-1, req, ip);
[3150]778 ROAR_DBG("_ioctl_mixer(handle=%p, req=%lu, ip=%p) = -1 // errno = ENOSYS", handle, req, ip);
779 errno = ENOSYS;
780 return -1;
781}
782
783// -------------------------------------
[3178]784// buffer size calculation:
785// -------------------------------------
786
787static size_t _get_stream_buffersize (struct handle * handle) {
788 if ( handle->stream_buffersize )
789  return handle->stream_buffersize;
790
791 return handle->stream_buffersize = handle->stream.info.rate     *
792                                    handle->stream.info.channels *
793                                    handle->stream.info.bits     / 800;
794}
795
796// -------------------------------------
[3138]797// emulated functions follow:
798// -------------------------------------
799
800int     open(const char *pathname, int flags, ...) {
[3142]801 int     ret;
802 mode_t  mode = 0;
[3138]803 va_list args;
804
805 _init();
806
[3261]807 if ( pathname == NULL ) {
808  errno = EFAULT;
809  return -1;
810 }
811
812 ROAR_DBG("open(pathname='%s', flags=%x, ...) = ?\n", pathname, flags);
[3142]813 ret = _open_file(pathname, flags);
814
815 switch (ret) {
816  case -2:       // continue as normal, use _op.open()
817   break;
818  case -1:       // pass error to caller
819    return -1;
820   break;
821  default:       // return successfully opened pointer to caller
822    return ret;
823   break;
824 }
825
[3138]826 if (flags & O_CREAT) {
827  va_start(args, flags);
828  mode = va_arg(args, mode_t);
829  va_end(args);
830 }
831
832 return _os.open(pathname, flags, mode);
833}
834
835int     close(int fd) {
[3140]836 struct pointer * pointer;
[3138]837 _init();
838
[3140]839 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
840  _close_pointer(pointer);
841  return 0;
842 }
843
[3138]844 return _os.close(fd);
845}
846
847ssize_t write(int fd, const void *buf, size_t count) {
[3261]848 struct roar_roardmx_message roardmxmsg;
[3140]849 struct pointer * pointer;
[3178]850 ssize_t ret;
[3639]851 size_t i;
[3140]852
[3138]853 _init();
854
[3140]855 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
[3261]856  switch (pointer->handle->type) {
857   case HT_STREAM:
858     if ( pointer->handle->stream_opened == 0 ) {
859      if ( _open_stream(pointer->handle) == -1 ) {
860       errno = EIO;
861       return -1;
862      }
863     }
864     ret = roar_vio_write(&(pointer->handle->stream_vio), (char*)buf, count);
865     if ( ret > 0 )
866      pointer->handle->writec += ret;
867     return ret;
868    break;
869   case HT_DMX:
870     if ( pointer->handle->stream_opened == 0 ) {
871      if ( _open_stream(pointer->handle) == -1 ) {
872       errno = EIO;
873       return -1;
874      }
875     }
876     if ( count > 0 ) {
877      if ( roar_roardmx_message_new_sset(&roardmxmsg) == -1 ) {
878       errno = EIO;
879       return -1;
880      }
881      for (i = 0; i < count; i++) {
882       if ( roar_roardmx_message_add_chanval(&roardmxmsg, pointer->handle->pos + i, ((unsigned char*)buf)[i]) == -1 ) {
883#ifdef EMSGSIZE
884        errno = EMSGSIZE;
885#else
886        errno = EIO;
887#endif
888        return -1;
889       }
890      }
891      if ( roar_roardmx_message_send(&roardmxmsg, &(pointer->handle->stream_vio)) == -1 ) {
892       errno = EIO;
893       return -1;
894      }
895     }
896     pointer->handle->pos += count;
897     return count;
898    break;
899   default:
900     errno = EINVAL;
[3140]901     return -1;
[3261]902    break;
[3140]903  }
904 }
905
[3138]906 return _os.write(fd, buf, count);
907}
908
909ssize_t read(int fd, void *buf, size_t count) {
[3140]910 struct pointer * pointer;
[3178]911 ssize_t ret;
[3140]912
[3138]913 _init();
914
[3140]915 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
916  if ( pointer->handle->type == HT_STREAM ) {
917   if ( pointer->handle->stream_opened == 0 ) {
918    if ( _open_stream(pointer->handle) == -1 ) {
919     errno = EIO;
920     return -1;
921    }
922   }
[3178]923   ret = roar_vio_read(&(pointer->handle->stream_vio), buf, count);
924   if ( ret > 0 )
[3243]925    pointer->handle->readc += ret;
[3178]926   return ret;
[3140]927  } else {
928   errno = EINVAL;
929   return -1;
930  }
931 }
932
[3138]933 return _os.read(fd, buf, count);
934}
935
[3246]936off_t lseek(int fildes, off_t offset, int whence) {
937 struct pointer * pointer;
938
939 _init();
940
941 if ( (pointer = _get_pointer_by_fh(fildes)) != NULL ) {
942  if ( pointer->handle->type == HT_DMX ) {
943   switch (whence) {
944    case SEEK_SET:
945      pointer->handle->pos  = offset;
946     break;
947    case SEEK_CUR:
948      pointer->handle->pos += offset;
949     break;
950    case SEEK_END:
951    default:
952      errno = EINVAL;
953      return -1;
954     break;
955   }
956   return pointer->handle->pos;
957  } else {
958   errno = EINVAL;
959   return -1;
960  }
961 }
962
963 return _os.lseek(fildes, offset, whence);
964}
965
[3169]966IOCTL() {
967 map_args;
[3147]968 struct pointer * pointer;
969 struct handle  * handle;
[3169]970 int * ip = NULL;
[3176]971 audio_buf_info * bi;
[3178]972 count_info     * ci;
[3229]973#ifdef __FIXME__
974 char * nosys_reqname = NULL;
975#endif
[3169]976#ifdef va_argp
[3146]977 va_list args;
[3169]978#endif
[3146]979
980 _init();
981
[3150]982// ROAR_DBG("ioctl(__fd=%i, __request=%lu) = ?", __fd, (long unsigned int) __request);
[3148]983
[3169]984#ifdef va_argp
[3180]985 va_start (args, ioctl_lastarg);
[3146]986 argp = va_arg (args, void *);
987 va_end (args);
[3169]988#endif
[3146]989
[3150]990// ROAR_DBG("ioctl(__fd=%i, __request=%lu): argp=%p", __fd, (long unsigned int) __request, argp);
[3148]991
[3147]992 if ( (pointer = _get_pointer_by_fh(__fd)) != NULL ) {
[3148]993  ip = argp;
[3150]994//  ROAR_DBG("ioctl(__fd=%i, __request=%lu): ip=%p", __fd, (long unsigned int) __request, ip);
[3229]995#ifdef __FIXME__
996  switch ((handle = pointer->handle)->type) {
997   case SOUND_PCM_READ_RATE: nosys_reqname = "SOUND_PCM_READ_RATE"; break;
998   case SOUND_PCM_READ_CHANNELS: nosys_reqname = "SOUND_PCM_READ_CHANNELS"; break;
999   case SOUND_PCM_READ_BITS: nosys_reqname = "SOUND_PCM_READ_BITS"; break;
1000   case SOUND_PCM_READ_FILTER: nosys_reqname = "SOUND_PCM_READ_FILTER"; break;
1001   case SNDCTL_COPR_RESET: nosys_reqname = "SNDCTL_COPR_RESET"; break;
1002   case SNDCTL_COPR_LOAD: nosys_reqname = "SNDCTL_COPR_LOAD"; break;
1003   case SNDCTL_COPR_HALT: nosys_reqname = "SNDCTL_COPR_HALT"; break;
1004   case SNDCTL_COPR_RDATA: nosys_reqname = "SNDCTL_COPR_RDATA"; break;
1005   case SNDCTL_COPR_RCODE: nosys_reqname = "SNDCTL_COPR_RCODE"; break;
1006   case SNDCTL_COPR_WDATA: nosys_reqname = "SNDCTL_COPR_WDATA"; break;
1007   case SNDCTL_COPR_WCODE: nosys_reqname = "SNDCTL_COPR_WCODE"; break;
1008   case SNDCTL_COPR_RUN: nosys_reqname = "SNDCTL_COPR_RUN"; break;
1009   case SNDCTL_COPR_SENDMSG: nosys_reqname = "SNDCTL_COPR_SENDMSG"; break;
1010   case SNDCTL_COPR_RCVMSG: nosys_reqname = "SNDCTL_COPR_RCVMSG"; break;
1011   case SNDCTL_DSP_SPEED: nosys_reqname = "SNDCTL_DSP_SPEED"; break;
1012/*
1013   case : nosys_reqname = ""; break;
1014   case : nosys_reqname = ""; break;
1015   case : nosys_reqname = ""; break;
1016*/
1017  }
1018#endif
[3147]1019  switch ((handle = pointer->handle)->type) {
1020   case HT_STREAM:
1021     switch (__request) {
1022      case SNDCTL_DSP_RESET:
1023      case SNDCTL_DSP_POST:
[3162]1024      case SNDCTL_DSP_SETFRAGMENT: // any fragments should be ok for us...
[3175]1025        return 0;
[3147]1026       break;
1027      case SNDCTL_DSP_SPEED:
1028        handle->stream.info.rate = *ip;
[3229]1029        ROAR_DBG("ioctl(__fd=%i, __request=%lu): rate=%i", __fd, (long unsigned int) __request, *ip);
[3147]1030        return 0;
1031       break;
1032      case SNDCTL_DSP_CHANNELS:
1033        handle->stream.info.channels = *ip;
[3229]1034        ROAR_DBG("ioctl(__fd=%i, __request=%lu): channels=%i", __fd, (long unsigned int) __request, *ip);
[3147]1035        return 0;
1036       break;
[3160]1037      case SNDCTL_DSP_STEREO:
1038        handle->stream.info.channels = *ip ? 2 : 1;
1039        return 0;
1040       break;
[3161]1041      case SNDCTL_DSP_GETBLKSIZE:
[3178]1042        *ip = _get_stream_buffersize(handle);
[3161]1043        return 0;
1044       break;
[3147]1045      case SNDCTL_DSP_SETFMT:
[3229]1046        ROAR_DBG("ioctl(__fd=%i, __request=%lu): fmt=0x%x", __fd, (long unsigned int) __request, *ip);
[3147]1047        return _ioctl_stream_format(handle, *ip);
1048       break;
[3148]1049      case SNDCTL_DSP_GETFMTS:
[3150]1050//        ROAR_DBG("ioctl(__fd=%i, __request=%lu): ip=%p", __fd, (long unsigned int) __request, ip);
[3149]1051        *ip = _ioctl_stream_format_list();
[3148]1052        return 0;
1053       break;
[3176]1054      case SNDCTL_DSP_GETOSPACE:
1055      case SNDCTL_DSP_GETISPACE:
1056        bi = argp;
1057        memset(bi, 0, sizeof(*bi));
[3178]1058        bi->bytes      = _get_stream_buffersize(handle);
[3176]1059        bi->fragments  = 1;
1060        bi->fragsize   = bi->bytes;
1061        bi->fragstotal = 1;
1062        return 0;
1063       break;
[3178]1064      case SNDCTL_DSP_GETOPTR:
1065        ci = argp;
1066        memset(ci, 0, sizeof(*ci));
1067        ci->bytes  = handle->writec;
1068        ci->blocks = ci->bytes / _get_stream_buffersize(handle);
1069        ci->ptr    = 0;
1070        return 0;
1071       break;
1072      case SNDCTL_DSP_GETIPTR:
1073        ci = argp;
1074        memset(ci, 0, sizeof(*ci));
1075        ci->bytes  = handle->readc;
1076        ci->blocks = ci->bytes / _get_stream_buffersize(handle);
1077        ci->ptr    = 0;
1078        return 0;
1079       break;
[3177]1080#ifdef SNDCTL_DSP_GETPLAYVOL
1081      case SNDCTL_DSP_GETPLAYVOL:
1082        return _ioctl_mixer(handle, SOUND_MIXER_READ_PCM, argp);
1083       break;
1084#endif
1085#ifdef SNDCTL_DSP_SETPLAYVOL
1086      case SNDCTL_DSP_SETPLAYVOL:
1087        return _ioctl_mixer(handle, SOUND_MIXER_WRITE_PCM, argp);
1088       break;
1089#endif
[3147]1090      default:
[3229]1091#ifdef __FIXME__
1092        ROAR_DBG("ioctl(__fd=%i, __request=%lu (%s)) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request, nosys_reqname);
1093#else
[3148]1094        ROAR_DBG("ioctl(__fd=%i, __request=%lu) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
[3229]1095#endif
[3147]1096        errno = ENOSYS;
1097        return -1;
1098     }
1099    break;
1100   case HT_MIXER:
[3158]1101     return _ioctl_mixer(handle, __request, argp);
[3147]1102    break;
1103   default:
[3150]1104     ROAR_DBG("ioctl(__fd=%i, __request=%lu): unknown handle type: no ioctl()s supported", __fd, (long unsigned int) __request);
1105     ROAR_DBG("ioctl(__fd=%i, __request=%lu) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
[3147]1106     errno = EINVAL;
1107     return -1;
1108    break;
1109  }
1110 }
1111
[3166]1112#ifdef IOCTL_IS_ALIAS
1113 errno = ENOSYS;
1114 return -1;
1115#else
[3146]1116 return _os.ioctl(__fd, __request, argp);
[3166]1117#endif
[3146]1118}
1119
[3264]1120
1121// -------------------------------------
1122// emulated stdio functions follow:
1123// -------------------------------------
1124
1125//roar_vio_to_stdio
1126
1127FILE *fopen(const char *path, const char *mode) {
1128 struct pointer * pointer;
1129 FILE  * fr;
1130 int     ret;
1131 int     r = 0, w = 0;
1132 int     flags = 0;
1133 int     i;
1134 register char c;
1135
1136 _init();
1137
1138 if ( path == NULL || mode == NULL ) {
1139  errno = EFAULT;
1140  return NULL;
1141 }
1142
[3265]1143 ROAR_DBG("open(path='%s', mode='%s') = ?\n", path, mode);
[3264]1144
1145 for (i = 0; (c = mode[i]) != 0; i++) {
1146  switch (c) {
1147   case 'r': r = 1; break;
1148   case 'w': w = 1; break;
1149   case 'a': w = 1; break;
1150   case '+':
1151     r = 1;
1152     w = 1;
1153    break;
1154  }
1155 }
1156
1157 if ( r && w ) {
1158  flags = O_RDWR;
1159 } else if ( r ) {
1160  flags = O_RDONLY;
1161 } else if ( w ) {
1162  flags = O_WRONLY;
1163 } else {
1164  errno = EINVAL;
1165  return NULL;
1166 }
1167
1168 ret = _open_file(path, flags);
1169
1170 switch (ret) {
1171  case -2:       // continue as normal, use _op.open()
1172   break;
1173  case -1:       // pass error to caller
1174    return NULL;
1175   break;
1176  default:       // return successfully opened pointer to caller
1177    if ( (pointer = _get_pointer_by_fh(ret)) != NULL ) {
1178     if ( (fr = roar_vio_to_stdio(&(pointer->handle->stream_vio), flags)) == NULL ) {
1179      errno = EIO;
1180      return NULL;
1181     } else {
1182      return fr;
1183     }
1184    } else {
1185     errno = EIO;
1186     return NULL;
1187    }
1188   break;
1189 }
1190
1191 return _os.fopen(path, mode);
1192}
1193
[3138]1194#endif
1195
1196//ll
Note: See TracBrowser for help on using the repository browser.