source: roaraudio/libroaross/libroaross.c @ 3166:944d784785c2

Last change on this file since 3166:944d784785c2 was 3166:944d784785c2, checked in by phi, 14 years ago

some macro tests

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