source: roaraudio/libroaross/libroaross.c @ 3178:0882f7dc9b71

Last change on this file since 3178:0882f7dc9b71 was 3178:0882f7dc9b71, checked in by phi, 14 years ago

added support for SNDCTL_DSP_GETOPTR and SNDCTL_DSP_GETIPTR!

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