source: roaraudio/libroaross/libroaross.c @ 3164:91b9ef47ed6f

Last change on this file since 3164:91b9ef47ed6f was 3164:91b9ef47ed6f, checked in by phi, 14 years ago

alias ENOTSUP to ENOSYS if nit defined

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