source: roaraudio/libroaross/libroaross.c @ 3242:aab6235855b1

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

support /dev/sound/*

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