source: roaraudio/libroaross/libroaross.c @ 3517:1a3218a3fc5b

Last change on this file since 3517:1a3218a3fc5b was 3517:1a3218a3fc5b, checked in by phi, 14 years ago

updated license headers, FSF moved office

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, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
36#include "roaraudio.h"
37#include "libroarlight/libroarlight.h"
38
39#if defined(ROAR_HAVE_OSS_BSD) || defined(ROAR_HAVE_OSS)
40#if defined(__OpenBSD__) || defined(__NetBSD__)
41#include <soundcard.h>
42#else
43#include <sys/soundcard.h>
44#endif
45#include <sys/ioctl.h>
46
47#ifdef ROAR_HAVE_H_SYS_TYPES
48#include <sys/types.h>
49#endif
50
51#ifdef ROAR_HAVE_H_FCNTL
52#include <fcntl.h>
53#endif
54
55#ifdef ROAR_HAVE_H_UNISTD
56#include <unistd.h>
57#endif
58
59#include <sys/stat.h>
60#include <dlfcn.h>
61
62#if defined(RTLD_NEXT)
63#define REAL_LIBC RTLD_NEXT
64#else
65#define REAL_LIBC ((void *) -1L)
66#endif
67
68#ifndef ENOTSUP
69#define ENOTSUP ENOSYS
70#endif
71
72#if defined(ROAR_OS_NETBSD) && defined(ioctl)
73#define IOCTL_IS_ALIAS
74#endif
75
76#ifdef ROAR_OS_FREEBSD
77#define mode_t int
78#endif
79
80#ifdef ROAR_OS_NETBSD
81#define IOCTL() int _oss_ioctl __P((int fd, unsigned long com, void *argp))
82#define map_args int __fd = fd; unsigned long int __request = com
83#elif defined(ROAR_TARGET_CYGWIN)
84#define IOCTL() int ioctl (int __fd, int __cmd, ...)
85#define map_args unsigned long int __request = __cmd; void * argp
86#define va_argp
87#define ioctl_lastarg __cmd
88#else
89#define IOCTL() int ioctl (int __fd, unsigned long int __request, ...)
90#define map_args void * argp
91#define va_argp
92#define ioctl_lastarg __request
93#endif
94
95#define OSS_VOLUME_SCALE 100
96
97#define _MAX_POINTER  8
98
99// handle type:
100#define HT_NONE       0
101#define HT_STREAM     1
102#define HT_MIXER      2
103#define HT_WAVEFORM   3
104#define HT_MIDI       4
105#define HT_DMX        5
106
107struct session {
108 int refc;
109 struct roar_connection con;
110};
111
112static struct session _session = {.refc = 0};
113
114struct handle {
115 int refc; // refrence counter
116 struct session * session;
117 int type;
118 struct roar_stream    stream;
119 struct roar_vio_calls stream_vio;
120 int                   stream_dir;
121 int                   stream_opened;
122 size_t                stream_buffersize;
123 size_t                readc, writec;
124 size_t                pos;
125};
126
127static struct {
128 int     (*open)(const char *pathname, int flags, mode_t mode);
129 int     (*close)(int fd);
130 ssize_t (*write)(int fd, const void *buf, size_t count);
131 ssize_t (*read)(int fd, void *buf, size_t count);
132#ifndef IOCTL_IS_ALIAS
133 int     (*ioctl)(int d, int request, ...);
134#endif
135 off_t   (*lseek)(int fildes, off_t offset, int whence);
136 FILE   *(*fopen)(const char *path, const char *mode);
137} _os;
138
139static struct {
140 struct {
141  int volume;
142  int pcm;
143  int line;
144  int line1;
145  int line2;
146  int line3;
147  int digital1;
148  int digital2;
149  int digital3;
150 } sid;
151} _mix_settings = {
152                   .sid = {
153                           .volume   = -1,
154                           .pcm      = -1,
155                           .line     =  0,
156                           .line1    =  1,
157                           .line2    =  2,
158                           .line3    =  3,
159                           .digital1 =  1,
160                           .digital2 =  2,
161                           .digital3 =  3
162                          }
163                  };
164
165static struct pointer {
166 int fh;
167 struct handle * handle;
168} _ptr[_MAX_POINTER];
169
170static void _init_os (void) {
171 memset(&_os, 0, sizeof(_os));
172
173 _os.open  = dlsym(REAL_LIBC, "open");
174 _os.close = dlsym(REAL_LIBC, "close");
175 _os.write = dlsym(REAL_LIBC, "write");
176 _os.read  = dlsym(REAL_LIBC, "read");
177#ifndef IOCTL_IS_ALIAS
178 _os.ioctl = dlsym(REAL_LIBC, "ioctl");
179#endif
180 _os.lseek = dlsym(REAL_LIBC, "lseek");
181 _os.fopen = dlsym(REAL_LIBC, "fopen");
182}
183
184static void _init_ptr (void) {
185 int i;
186
187 for (i = 0; i < _MAX_POINTER; i++) {
188  _ptr[i].fh = -1;
189 }
190}
191
192static void _init (void) {
193 static int inited = 0;
194
195 if ( !inited ) {
196  _init_os();
197  _init_ptr();
198  inited++;
199 }
200}
201
202static void _find_volume_sid (struct session * session) {
203 int i;
204 int num;
205 int id[ROAR_STREAMS_MAX];
206 struct roar_stream s;
207 char name[1024];
208
209 ROAR_DBG("_find_volume_sid(session=%p) = ?", session);
210
211 if ( (num = roar_list_streams(&(session->con), id, ROAR_STREAMS_MAX)) == -1 ) {
212  return;
213 }
214
215 for (i = 0; i < num; i++) {
216  if ( roar_get_stream(&(session->con), &s, id[i]) == -1 )
217   continue;
218
219  if ( s.dir != ROAR_DIR_MIXING )
220   continue;
221
222  if ( roar_stream_get_name(&(session->con), &s, name, 1024) == -1 )
223   continue;
224
225  if ( !strcasecmp(name, "Waveform Mixer") ) {
226   _mix_settings.sid.volume = id[i];
227   ROAR_DBG("_find_volume_sid(session=%p): found waveform mixer at sid %i", session, id[i]);
228   ROAR_DBG("_find_volume_sid(session=%p) = (void)", session);
229   return;
230  }
231 }
232}
233
234static int _open_dummy (void) {
235 int p[2];
236
237 if ( pipe(p) == -1 )
238  return -1;
239
240 close(p[1]);
241
242 return p[0];
243}
244
245static struct session * _open_session (char * server, char * name) {
246 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
249 if ( _session.refc == 0 ) {
250
251  if ( name == NULL )
252   name = getenv("ROAR_OSS_CLIENT_NAME");
253
254  if ( name == NULL )
255   name = "libroaross client";
256
257  if ( roar_simple_connect(&(_session.con), server, name) == -1 )
258   return NULL;
259
260  _find_volume_sid(&_session);
261
262  if ( getenv("ROAR_OSS_KEEP_SESSION") != NULL )
263   _session.refc++;
264 }
265
266 _session.refc++;
267
268 ROAR_DBG("_open_session(server='%s', name='%s') = %p", server, name, &_session);
269 return &_session;
270}
271
272static void _close_session(struct session * session) {
273 if ( session == NULL )
274  return;
275
276 session->refc--;
277
278 ROAR_DBG("_close_session(session=%p): session->refc=%i", session, session->refc);
279
280 if ( session->refc == 0 ) {
281  roar_disconnect(&(session->con));
282 }
283}
284
285static struct handle * _open_handle(struct session * session) {
286 struct handle * handle;
287
288 ROAR_DBG("_open_handle(session=%p) = ?", session);
289
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;
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);
301
302 ROAR_DBG("_open_handle(session=%p) = %p", session, handle);
303 return handle;
304}
305
306static void _close_handle(struct handle * handle) {
307 if (handle == NULL)
308  return;
309
310 handle->refc--;
311
312 ROAR_DBG("_close_handle(handle=%p): handle->refc=%i", handle, handle->refc);
313
314 if ( handle->refc == 0 ) {
315  if ( handle->stream_opened )
316   roar_vio_close(&(handle->stream_vio));
317
318  handle->session->refc--;
319
320  _close_session(handle->session);
321
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}
361
362// -------------------------------------
363// central open function:
364// -------------------------------------
365
366static int _open_file (const char *pathname, int flags) {
367 struct session * session;
368 struct handle  * handle;
369 struct pointer * pointer;
370 struct {
371  char * prefix;
372  int type;
373 } * ptr = NULL, p[] = {
374  {"/dev/dsp",           HT_WAVEFORM},
375  {"/dev/audio",         HT_WAVEFORM},
376  {"/dev/sound/dsp",     HT_WAVEFORM},
377  {"/dev/sound/audio",   HT_WAVEFORM},
378  {"/dev/mixer",         HT_MIXER},
379  {"/dev/sound/mixer",   HT_MIXER},
380  {"/dev/midi",          HT_MIDI},
381  {"/dev/rmidi",         HT_MIDI},
382  {"/dev/sound/midi",    HT_MIDI},
383  {"/dev/sound/rmidi",   HT_MIDI},
384  {"/dev/dmx",           HT_DMX},
385  {"/dev/misc/dmx",      HT_DMX},
386  {"/dev/dmxin",         HT_DMX},
387  {"/dev/misc/dmxin",    HT_DMX},
388#ifdef ROAR_DEFAULT_OSS_DEV
389  {ROAR_DEFAULT_OSS_DEV, HT_WAVEFORM},
390#endif
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
413 handle->type       = ptr->type;
414 handle->stream_dir = -1;
415
416 switch (flags & (O_RDONLY|O_WRONLY|O_RDWR)) {
417  case O_RDONLY:
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;
425     case HT_DMX:
426       handle->stream_dir = ROAR_DIR_LIGHT_OUT;
427      break;
428     default:
429       return -1;
430    }
431   break;
432  case O_WRONLY:
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;
440     case HT_DMX:
441       handle->stream_dir = ROAR_DIR_LIGHT_IN;
442      break;
443     default:
444       return -1;
445    }
446   break;
447  case O_RDWR:
448    switch (ptr->type) {
449     case HT_WAVEFORM:
450       handle->stream_dir = ROAR_DIR_BIDIR;
451      break;
452     default:
453       return -1;
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;
468   break;
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;
475 }
476
477 if ( (pointer = _open_pointer(handle)) == NULL ) {
478  _close_handle(handle);
479  return -1;
480 }
481
482 return pointer->fh;
483}
484
485// -------------------------------------
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
507 _mix_settings.sid.pcm = roar_stream_get_id(&(handle->stream));
508
509 return 0;
510}
511
512// -------------------------------------
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
569  default:
570    ROAR_DBG("_ioctl_stream_format(*): unsupported format");
571    errno = ENOSYS;
572    return -1;
573   break;
574 }
575
576 return 0;
577}
578
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
608// -------------------------------------
609// mixer ioctls:
610// -------------------------------------
611
612static int _ioctl_mixer (struct handle * handle, long unsigned int req, void * vp) {
613 mixer_info * info;
614 int channels;
615 struct roar_mixer_settings mixer;
616 int o_w    =  0;
617 int o_sid  = -1;
618 int * ip   = vp;
619#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
620 char * name = NULL;
621#endif
622
623#if defined(DEBUG) && defined(DEBUG_IOCTL_NAMES)
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
634//  case SOUND_MIXER_INFO:             name = "SOUND_MIXER_INFO";             break;
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;
639  case SOUND_MIXER_GETLEVELS:        name = "SOUND_MIXER_GETLEVELS";        break;
640  case SOUND_MIXER_SETLEVELS:        name = "SOUND_MIXER_SETLEVELS";        break;
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;
647//  case SOUND_MIXER_READ_CAPS:        name = "SOUND_MIXER_READ_CAPS";        break;
648  case SOUND_MIXER_READ_MUTE:        name = "SOUND_MIXER_READ_MUTE";        break;
649/*
650  case :     name = "";     break;
651  case :     name = "";     break;
652*/
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 }
660#endif
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
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;
700 }
701 if ( o_sid != -1 ) {
702  // set/get volume
703  if ( o_w ) {
704   mixer.scale    = 65535;
705   mixer.mixer[0] = ( *ip       & 0xFF)*65535/OSS_VOLUME_SCALE;
706   mixer.mixer[1] = ((*ip >> 8) & 0xFF)*65535/OSS_VOLUME_SCALE;
707   if ( roar_set_vol(&(handle->session->con), o_sid, &mixer, 2) == -1 ) {
708    errno = EIO;
709    return -1;
710   }
711   return 0;
712  } else {
713   if ( roar_get_vol(&(handle->session->con), o_sid, &mixer, &channels) == -1 ) {
714    errno = EIO;
715    return -1;
716   }
717   *ip = ((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale) | (((OSS_VOLUME_SCALE*mixer.mixer[0])/mixer.scale)<<8);
718   return 0;
719  }
720 }
721
722 switch (req) {
723  case SOUND_MIXER_READ_STEREODEVS: /* FIXME: check the streams for channel config */
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 )
740#if 0
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;
746#endif
747
748    return 0;
749   break;
750  case SOUND_MIXER_READ_RECMASK:
751  case SOUND_MIXER_READ_RECSRC:
752    *ip = SOUND_MASK_VOLUME; // we can currently only read from mixer
753    return 0;
754   break;
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;
763  case SOUND_MIXER_READ_CAPS:
764    *ip = 0;
765    return 0;
766   break;
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;
774 }
775
776 ROAR_DBG("_ioctl_mixer(handle=%p, req=%lu, ip=%p): unknown mixer CTL", handle, req, ip);
777// _os.ioctl(-1, req, ip);
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// -------------------------------------
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// -------------------------------------
797// emulated functions follow:
798// -------------------------------------
799
800int     open(const char *pathname, int flags, ...) {
801 int     ret;
802 mode_t  mode = 0;
803 va_list args;
804
805 _init();
806
807 if ( pathname == NULL ) {
808  errno = EFAULT;
809  return -1;
810 }
811
812 ROAR_DBG("open(pathname='%s', flags=%x, ...) = ?\n", pathname, flags);
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
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) {
836 struct pointer * pointer;
837 _init();
838
839 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
840  _close_pointer(pointer);
841  return 0;
842 }
843
844 return _os.close(fd);
845}
846
847ssize_t write(int fd, const void *buf, size_t count) {
848 struct roar_roardmx_message roardmxmsg;
849 struct pointer * pointer;
850 ssize_t ret;
851 int i;
852
853 _init();
854
855 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
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;
901     return -1;
902    break;
903  }
904 }
905
906 return _os.write(fd, buf, count);
907}
908
909ssize_t read(int fd, void *buf, size_t count) {
910 struct pointer * pointer;
911 ssize_t ret;
912
913 _init();
914
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   }
923   ret = roar_vio_read(&(pointer->handle->stream_vio), buf, count);
924   if ( ret > 0 )
925    pointer->handle->readc += ret;
926   return ret;
927  } else {
928   errno = EINVAL;
929   return -1;
930  }
931 }
932
933 return _os.read(fd, buf, count);
934}
935
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
966IOCTL() {
967 map_args;
968 struct pointer * pointer;
969 struct handle  * handle;
970 int * ip = NULL;
971 audio_buf_info * bi;
972 count_info     * ci;
973#ifdef __FIXME__
974 char * nosys_reqname = NULL;
975#endif
976#ifdef va_argp
977 va_list args;
978#endif
979
980 _init();
981
982// ROAR_DBG("ioctl(__fd=%i, __request=%lu) = ?", __fd, (long unsigned int) __request);
983
984#ifdef va_argp
985 va_start (args, ioctl_lastarg);
986 argp = va_arg (args, void *);
987 va_end (args);
988#endif
989
990// ROAR_DBG("ioctl(__fd=%i, __request=%lu): argp=%p", __fd, (long unsigned int) __request, argp);
991
992 if ( (pointer = _get_pointer_by_fh(__fd)) != NULL ) {
993  ip = argp;
994//  ROAR_DBG("ioctl(__fd=%i, __request=%lu): ip=%p", __fd, (long unsigned int) __request, ip);
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
1019  switch ((handle = pointer->handle)->type) {
1020   case HT_STREAM:
1021     switch (__request) {
1022      case SNDCTL_DSP_RESET:
1023      case SNDCTL_DSP_POST:
1024      case SNDCTL_DSP_SETFRAGMENT: // any fragments should be ok for us...
1025        return 0;
1026       break;
1027      case SNDCTL_DSP_SPEED:
1028        handle->stream.info.rate = *ip;
1029        ROAR_DBG("ioctl(__fd=%i, __request=%lu): rate=%i", __fd, (long unsigned int) __request, *ip);
1030        return 0;
1031       break;
1032      case SNDCTL_DSP_CHANNELS:
1033        handle->stream.info.channels = *ip;
1034        ROAR_DBG("ioctl(__fd=%i, __request=%lu): channels=%i", __fd, (long unsigned int) __request, *ip);
1035        return 0;
1036       break;
1037      case SNDCTL_DSP_STEREO:
1038        handle->stream.info.channels = *ip ? 2 : 1;
1039        return 0;
1040       break;
1041      case SNDCTL_DSP_GETBLKSIZE:
1042        *ip = _get_stream_buffersize(handle);
1043        return 0;
1044       break;
1045      case SNDCTL_DSP_SETFMT:
1046        ROAR_DBG("ioctl(__fd=%i, __request=%lu): fmt=0x%x", __fd, (long unsigned int) __request, *ip);
1047        return _ioctl_stream_format(handle, *ip);
1048       break;
1049      case SNDCTL_DSP_GETFMTS:
1050//        ROAR_DBG("ioctl(__fd=%i, __request=%lu): ip=%p", __fd, (long unsigned int) __request, ip);
1051        *ip = _ioctl_stream_format_list();
1052        return 0;
1053       break;
1054      case SNDCTL_DSP_GETOSPACE:
1055      case SNDCTL_DSP_GETISPACE:
1056        bi = argp;
1057        memset(bi, 0, sizeof(*bi));
1058        bi->bytes      = _get_stream_buffersize(handle);
1059        bi->fragments  = 1;
1060        bi->fragsize   = bi->bytes;
1061        bi->fragstotal = 1;
1062        return 0;
1063       break;
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;
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
1090      default:
1091#ifdef __FIXME__
1092        ROAR_DBG("ioctl(__fd=%i, __request=%lu (%s)) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request, nosys_reqname);
1093#else
1094        ROAR_DBG("ioctl(__fd=%i, __request=%lu) = -1 // errno = ENOSYS", __fd, (long unsigned int) __request);
1095#endif
1096        errno = ENOSYS;
1097        return -1;
1098     }
1099    break;
1100   case HT_MIXER:
1101     return _ioctl_mixer(handle, __request, argp);
1102    break;
1103   default:
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);
1106     errno = EINVAL;
1107     return -1;
1108    break;
1109  }
1110 }
1111
1112#ifdef IOCTL_IS_ALIAS
1113 errno = ENOSYS;
1114 return -1;
1115#else
1116 return _os.ioctl(__fd, __request, argp);
1117#endif
1118}
1119
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
1143 ROAR_DBG("open(path='%s', mode='%s') = ?\n", path, mode);
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
1194#endif
1195
1196//ll
Note: See TracBrowser for help on using the repository browser.