source: roaraudio/libroaross/libroaross.c @ 3177:7576b55416ad

Last change on this file since 3177:7576b55416ad was 3177:7576b55416ad, checked in by phi, 14 years ago

added OSSv4 SNDCTL_DSP_GETPLAYVOL/SNDCTL_DSP_SETPLAYVOL

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