source: roaraudio/libroaross/libroaross.c @ 3145:6a7eda75a836

Last change on this file since 3145:6a7eda75a836 was 3145:6a7eda75a836, checked in by phi, 14 years ago

set stream directon based on flags

File size: 8.8 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 _MAX_POINTER  8
67
68// handle type:
69#define HT_NONE       0
70#define HT_STREAM     1
71#define HT_MIXER      2
72
73struct session {
74 int refc;
75 struct roar_connection con;
76};
77
78static struct session _session = {.refc = 0};
79
80struct handle {
81 int refc; // refrence counter
82 struct session * session;
83 int type;
84 struct roar_stream    stream;
85 struct roar_vio_calls stream_vio;
86 int                   stream_dir;
87 int                   stream_opened;
88};
89
90static struct {
91 int     (*open)(const char *pathname, int flags, mode_t mode);
92 int     (*close)(int fd);
93 ssize_t (*write)(int fd, const void *buf, size_t count);
94 ssize_t (*read)(int fd, void *buf, size_t count);
95} _os;
96
97static struct pointer {
98 int fh;
99 struct handle * handle;
100} _ptr[_MAX_POINTER];
101
102static void _init_os (void) {
103 memset(&_os, 0, sizeof(_os));
104
105 _os.open  = dlsym(REAL_LIBC, "open");
106 _os.close = dlsym(REAL_LIBC, "close");
107 _os.write = dlsym(REAL_LIBC, "write");
108 _os.read  = dlsym(REAL_LIBC, "read");
109}
110
111static void _init_ptr (void) {
112 int i;
113
114 for (i = 0; i < _MAX_POINTER; i++) {
115  _ptr[i].fh = -1;
116 }
117}
118
119static void _init (void) {
120 static int inited = 0;
121
122 if ( !inited ) {
123  _init_os();
124  _init_ptr();
125  inited++;
126 }
127}
128
129static int _open_dummy (void) {
130 int p[2];
131
132 if ( pipe(p) == -1 )
133  return -1;
134
135 close(p[1]);
136
137 return p[0];
138}
139
140static struct session * _open_session (char * server, char * name) {
141 if ( _session.refc == 0 ) {
142
143  if ( name == NULL )
144   name = "libroaross client";
145
146  if ( roar_simple_connect(&(_session.con), server, name) == -1 )
147   return NULL;
148 }
149
150 _session.refc++;
151 return &_session;
152}
153
154static void _close_session(struct session * session) {
155 if ( session == NULL )
156  return;
157
158 session->refc--;
159
160 ROAR_DBG("_close_session(session=%p): session->refc=%i", session, session->refc);
161
162 if ( session->refc == 0 ) {
163  roar_disconnect(&(session->con));
164 }
165}
166
167static struct handle * _open_handle(struct session * session) {
168 struct handle * handle;
169
170 if ( (handle = roar_mm_malloc(sizeof(struct handle))) == NULL )
171  return NULL;
172
173 memset(handle, 0, sizeof(struct handle));
174
175 handle->refc = 1;
176 handle->session = session;
177 session->refc++; // TODO: better warp this
178 handle->type = HT_NONE;
179 handle->stream_dir = ROAR_DIR_PLAY;
180 roar_stream_new(&(handle->stream), ROAR_RATE_DEFAULT, ROAR_CHANNELS_DEFAULT, ROAR_BITS_DEFAULT, ROAR_CODEC_DEFAULT);
181
182 return handle;
183}
184
185static void _close_handle(struct handle * handle) {
186 if (handle == NULL)
187  return;
188
189 handle->refc--;
190
191 ROAR_DBG("_close_handle(handle=%p): handle->refc=%i", handle, handle->refc);
192
193 if ( handle->refc == 0 ) {
194  if ( handle->stream_opened )
195   roar_vio_close(&(handle->stream_vio));
196
197  handle->session->refc--;
198
199  _close_session(handle->session);
200
201  roar_mm_free(handle);
202 }
203}
204
205static struct pointer * _get_pointer_by_fh (int fh) {
206 int i;
207
208 for (i = 0; i < _MAX_POINTER; i++) {
209  if ( _ptr[i].fh == fh )
210   return &(_ptr[i]);
211 }
212
213 return NULL;
214}
215
216static struct pointer * _open_pointer(struct handle * handle) {
217 struct pointer * ret = _get_pointer_by_fh(-1);
218
219 if ( ret == NULL )
220  return NULL;
221
222 if ( (ret->fh = _open_dummy()) == -1 )
223  return NULL;
224
225 ret->handle = handle;
226
227 return ret;
228}
229
230static void _close_pointer(struct pointer * pointer) {
231 if ( pointer == NULL )
232  return;
233
234 _os.close(pointer->fh);
235
236 pointer->fh = -1;
237
238 _close_handle(pointer->handle);
239}
240
241// -------------------------------------
242// central open function:
243// -------------------------------------
244
245static int _open_file (const char *pathname, int flags) {
246 struct session * session;
247 struct handle  * handle;
248 struct pointer * pointer;
249 struct {
250  char * prefix;
251  int type;
252 } * ptr = NULL, p[] = {
253  {"/dev/dsp", HT_STREAM},
254  {NULL, HT_NONE},
255 };
256 int i;
257
258 for (i = 0; p[i].prefix != NULL; i++) {
259  if ( !strcmp(pathname, p[i].prefix) ) {
260   ptr = &(p[i]);
261  }
262 }
263
264 if ( ptr == NULL )
265  return -2;
266
267 if ( (session = _open_session(NULL, NULL)) == NULL ) {
268  return -1;
269 }
270
271 if ( (handle = _open_handle(session)) == NULL ) {
272  _close_session(session);
273  return -1;
274 }
275
276 handle->type = ptr->type;
277
278 switch (flags & (O_RDONLY|O_WRONLY|O_RDWR)) {
279  case O_RDONLY:
280    handle->stream_dir = ROAR_DIR_MONITOR;
281   break;
282  case O_WRONLY:
283    handle->stream_dir = ROAR_DIR_PLAY;
284   break;
285  case O_RDWR:
286    handle->stream_dir = ROAR_DIR_BIDIR;
287   break;
288 }
289
290 if ( (pointer = _open_pointer(handle)) == NULL ) {
291  _close_handle(handle);
292  return -1;
293 }
294
295 return pointer->fh;
296}
297
298// -------------------------------------
299// open function for streams:
300// -------------------------------------
301
302static int _open_stream (struct handle * handle) {
303  // FIXME: this should be re-written much more cleanly:
304
305 if ( handle == NULL )
306  return -1;
307
308 if ( roar_vio_simple_new_stream_obj(&(handle->stream_vio),
309                                     &(handle->session->con), &(handle->stream),
310                                     handle->stream.info.rate,
311                                     handle->stream.info.channels,
312                                     handle->stream.info.bits,
313                                     handle->stream.info.codec,
314                                     handle->stream_dir
315                                    ) == -1 )
316  return -1;
317
318 handle->stream_opened++;
319
320 return 0;
321}
322
323// -------------------------------------
324// emulated functions follow:
325// -------------------------------------
326
327int     open(const char *pathname, int flags, ...) {
328 int     ret;
329 mode_t  mode = 0;
330 va_list args;
331
332 _init();
333
334 ret = _open_file(pathname, flags);
335
336 switch (ret) {
337  case -2:       // continue as normal, use _op.open()
338   break;
339  case -1:       // pass error to caller
340    return -1;
341   break;
342  default:       // return successfully opened pointer to caller
343    return ret;
344   break;
345 }
346
347 if (flags & O_CREAT) {
348  va_start(args, flags);
349  mode = va_arg(args, mode_t);
350  va_end(args);
351 }
352
353 return _os.open(pathname, flags, mode);
354}
355
356int     close(int fd) {
357 struct pointer * pointer;
358 _init();
359
360 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
361  _close_pointer(pointer);
362  return 0;
363 }
364
365 return _os.close(fd);
366}
367
368ssize_t write(int fd, const void *buf, size_t count) {
369 struct pointer * pointer;
370
371 _init();
372
373 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
374  if ( pointer->handle->type == HT_STREAM ) {
375   if ( pointer->handle->stream_opened == 0 ) {
376    if ( _open_stream(pointer->handle) == -1 ) {
377     errno = EIO;
378     return -1;
379    }
380   }
381   return roar_vio_write(&(pointer->handle->stream_vio), (char*)buf, count);
382  } else {
383   errno = EINVAL;
384   return -1;
385  }
386 }
387
388 return _os.write(fd, buf, count);
389}
390
391ssize_t read(int fd, void *buf, size_t count) {
392 struct pointer * pointer;
393
394 _init();
395
396 if ( (pointer = _get_pointer_by_fh(fd)) != NULL ) {
397  if ( pointer->handle->type == HT_STREAM ) {
398   if ( pointer->handle->stream_opened == 0 ) {
399    if ( _open_stream(pointer->handle) == -1 ) {
400     errno = EIO;
401     return -1;
402    }
403   }
404   return roar_vio_read(&(pointer->handle->stream_vio), buf, count);
405  } else {
406   errno = EINVAL;
407   return -1;
408  }
409 }
410
411 return _os.read(fd, buf, count);
412}
413
414#endif
415
416//ll
Note: See TracBrowser for help on using the repository browser.