source: roaraudio/libroaross/libroaross.c @ 3500:124ab465ee2d

Last change on this file since 3500:124ab465ee2d was 3500:124ab465ee2d, checked in by phi, 14 years ago

added $ROAR_OSS_CLIENT_NAME

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