source: roaraudio/libroaross/libroaross.c @ 3160:b26e4a8c978f

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

support old (pre v3) SNDCTL_DSP_STEREO

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