source: roaraudio/libroaross/libroaross.c @ 3263:b410416352c6

Last change on this file since 3263:b410416352c6 was 3261:6c96218934f2, checked in by phi, 14 years ago

write-only DMX4Linux support

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