source: roaraudio/libroaross/libroaross.c @ 3245:abadfd8ef462

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

support for some other midi device names

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