source: roaraudio/libroar/vs.c @ 4199:9907744fffbc

Last change on this file since 4199:9907744fffbc was 4199:9907744fffbc, checked in by phi, 14 years ago

return zero in case of blocking

File size: 12.3 KB
Line 
1//vs.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, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
36#include "libroar.h"
37
38#define FLAG_NONE     0x0000
39#define FLAG_STREAM   0x0001
40#define FLAG_NONBLOCK 0x0002
41
42#define _initerr()  do { errno = 0; roar_err_clear(); } while(0)
43#define _seterr(x)  do { if ( error != NULL ) *error = (x); } while(0)
44#define _seterrre() do { _seterr(roar_errno); } while(0)
45#define _seterrse() do { roar_err_from_errno(); _seterr(roar_errno); } while(0)
46
47struct roar_vs {
48 int flags;
49 struct roar_connection con_store;
50 struct roar_connection * con;
51 struct roar_stream       stream;
52 struct roar_vio_calls    vio;
53};
54
55const char * roar_vs_strerr(int error) {
56 const struct {
57  int err;
58  const char * msg;
59 } msgs[] = {
60  {ROAR_ERROR_NONE,        "No error"},
61  {ROAR_ERROR_PERM,        "Operation not permitted"},
62  {ROAR_ERROR_NOENT,       "No such object, file or directory"},
63  {ROAR_ERROR_BADMSG,      "Bad message"},
64  {ROAR_ERROR_BUSY,        "Device or resource busy"},
65  {ROAR_ERROR_CONNREFUSED, "Connection refused"},
66  {ROAR_ERROR_NOSYS,       "Function not implemented"},
67  {ROAR_ERROR_NOTSUP,      "Operation not supported"},
68  {ROAR_ERROR_PIPE,        "Broken pipe"},
69  {ROAR_ERROR_PROTO,       "Protocol error"},
70  {ROAR_ERROR_RANGE,       "Result too large or parameter out of range"},
71  {ROAR_ERROR_MSGSIZE,     "Message too long"},
72  {ROAR_ERROR_NOMEM,       "Not enough space"},
73  {ROAR_ERROR_INVAL,       "Invalid argument"},
74  {-1, NULL}
75 };
76 int i;
77
78 for (i = 0; msgs[i].msg != NULL; i++)
79  if ( msgs[i].err == error )
80   return msgs[i].msg;
81
82 return "(unknown)";
83}
84
85static roar_vs_t * roar_vs_init(int * error) {
86 roar_vs_t * vss = roar_mm_malloc(sizeof(roar_vs_t));
87
88 if ( vss == NULL ) {
89  _seterrse();
90  return NULL;
91 }
92
93 memset(vss, 0, sizeof(roar_vs_t));
94
95 return vss;
96}
97
98roar_vs_t * roar_vs_new_from_con(struct roar_connection * con, int * error) {
99 roar_vs_t * vss = roar_vs_init(error);
100
101 if ( vss == NULL )
102  return NULL;
103
104 vss->con = con;
105
106 return vss;
107}
108
109roar_vs_t * roar_vs_new(const char * server, const char * name, int * error) {
110 roar_vs_t * vss = roar_vs_init(error);
111 int ret;
112
113 if ( vss == NULL )
114  return NULL;
115
116 vss->con = &(vss->con_store);
117
118 _initerr();
119
120 ret = roar_simple_connect(vss->con, (char*)server, (char*)name);
121
122 if ( ret == -1 ) {
123  roar_vs_close(vss, ROAR_VS_TRUE, NULL);
124  _seterrre();
125  return NULL;
126 }
127
128 return vss;
129}
130
131int roar_vs_stream(roar_vs_t * vss, const struct roar_audio_info * info, int dir, int * error) {
132 int ret;
133
134 if ( vss->flags & FLAG_STREAM ) {
135  _seterr(ROAR_ERROR_INVAL);
136  return -1;
137 }
138
139 _initerr();
140
141 ret = roar_vio_simple_new_stream_obj(&(vss->vio), vss->con, &(vss->stream),
142                                      info->rate, info->channels, info->bits, info->codec,
143                                      dir
144                                     );
145
146 if ( ret == -1 ) {
147  _seterrre();
148  return -1;
149 }
150
151 vss->flags |= FLAG_STREAM;
152
153 return 0;
154}
155
156roar_vs_t * roar_vs_new_simple(const char * server, const char * name, int rate, int channels, int codec, int bits, int dir, int * error) {
157 roar_vs_t * vss = roar_vs_new(server, name, error);
158 struct roar_audio_info info;
159 int ret;
160
161 if (vss == NULL)
162  return NULL;
163
164 memset(&info, 0, sizeof(info));
165
166 info.rate     = rate;
167 info.channels = channels;
168 info.codec    = codec;
169 info.bits     = bits;
170
171 ret = roar_vs_stream(vss, &info, dir, error);
172
173 if (ret == -1) {
174  roar_vs_close(vss, ROAR_VS_TRUE, NULL);
175  return NULL;
176 }
177
178 return vss;
179}
180
181int roar_vs_close(roar_vs_t * vss, int killit, int * error) {
182 if ( killit != ROAR_VS_TRUE && killit != ROAR_VS_FALSE ) {
183  _seterr(ROAR_ERROR_UNKNOWN);
184  return -1;
185 }
186
187 if ( vss->flags & FLAG_STREAM ) {
188  if ( killit == ROAR_VS_TRUE ) {
189   roar_kick(vss->con, ROAR_OT_STREAM, roar_stream_get_id(&(vss->stream)));
190  }
191
192  roar_vio_close(&(vss->vio));
193 }
194
195 if ( vss->con == &(vss->con_store) ) {
196  roar_disconnect(vss->con);
197 }
198
199 roar_mm_free(vss);
200 return 0;
201}
202
203ssize_t roar_vs_write(roar_vs_t * vss, const void * buf, size_t len, int * error) {
204 ssize_t ret;
205
206 if ( !(vss->flags & FLAG_STREAM) ) {
207  _seterr(ROAR_ERROR_INVAL);
208  return -1;
209 }
210
211 _initerr();
212
213 ret = roar_vio_write(&(vss->vio), (void*)buf, len);
214
215 if ( ret == -1 ) {
216#ifdef EAGAIN
217  if ( errno == EAGAIN )
218   return 0;
219#endif
220
221#ifdef EWOULDBLOCK
222  if ( errno == EWOULDBLOCK )
223   return 0;
224#endif
225
226  _seterrre();
227 }
228
229 return ret;
230}
231
232ssize_t roar_vs_read (roar_vs_t * vss,       void * buf, size_t len, int * error) {
233 ssize_t ret;
234
235 if ( !(vss->flags & FLAG_STREAM) ) {
236  _seterr(ROAR_ERROR_INVAL);
237  return -1;
238 }
239
240 _initerr();
241
242 ret = roar_vio_read(&(vss->vio), buf, len);
243
244 if ( ret == -1 ) {
245  _seterrre();
246 }
247
248 return ret;
249}
250
251int     roar_vs_sync (roar_vs_t * vss, int wait, int * error) {
252 if ( !(vss->flags & FLAG_STREAM) ) {
253  _seterr(ROAR_ERROR_INVAL);
254  return -1;
255 }
256
257 if ( wait != ROAR_VS_NOWAIT ) {
258  _seterr(ROAR_ERROR_INVAL);
259  return -1;
260 }
261
262 _initerr();
263
264 if ( roar_vio_sync(&(vss->vio)) == -1 ) {
265  _seterrre();
266  return -1;
267 }
268
269 return 0;
270}
271
272int     roar_vs_blocking (roar_vs_t * vss, int val, int * error) {
273 int old = -1;
274
275  if ( !(vss->flags & FLAG_STREAM) ) {
276  _seterr(ROAR_ERROR_INVAL);
277  return -1;
278 }
279
280 old = vss->flags & FLAG_NONBLOCK ? ROAR_VS_FALSE : ROAR_VS_TRUE;
281
282 _initerr();
283
284 switch (val) {
285  case ROAR_VS_TRUE:
286    if ( roar_vio_nonblock(&(vss->vio), ROAR_SOCKET_BLOCK) == -1 ) {
287     _seterrre();
288     return -1;
289    }
290    vss->flags |= FLAG_NONBLOCK;
291    vss->flags -= FLAG_NONBLOCK;
292    return old;
293   break;
294  case ROAR_VS_FALSE:
295    if ( roar_vio_nonblock(&(vss->vio), ROAR_SOCKET_NONBLOCK) == -1 ) {
296     _seterrre();
297     return -1;
298    }
299    vss->flags |= FLAG_NONBLOCK;
300    return old;
301   break;
302  case ROAR_VS_TOGGLE:
303    if ( old == ROAR_VS_TRUE ) {
304     return roar_vs_blocking(vss, ROAR_VS_FALSE, error);
305    } else {
306     return roar_vs_blocking(vss, ROAR_VS_TRUE, error);
307    }
308   break;
309  case ROAR_VS_ASK:
310    return old;
311   break;
312 }
313
314 _seterr(ROAR_ERROR_INVAL);
315 return -1;
316}
317
318ssize_t roar_vs_latency(roar_vs_t * vss, int backend, int * error) {
319 _seterr(ROAR_ERROR_NOSYS);
320 return -1;
321}
322
323static int roar_vs_flag(roar_vs_t * vss, int flag, int val, int * error) {
324 struct roar_stream_info info;
325 int old = -1;
326
327 if ( !(vss->flags & FLAG_STREAM) ) {
328  _seterr(ROAR_ERROR_INVAL);
329  return -1;
330 }
331
332 if ( val != ROAR_VS_ASK )
333  old = roar_vs_flag(vss, flag, ROAR_VS_ASK, error);
334
335 _initerr();
336
337 switch (val) {
338  case ROAR_VS_TRUE:
339  case ROAR_VS_FALSE:
340    if ( roar_stream_set_flags(vss->con, &(vss->stream), flag,
341                               val == ROAR_VS_TRUE ? ROAR_SET_FLAG : ROAR_RESET_FLAG) == -1 ) {
342     _seterrre();
343     return -1;
344    }
345    return old;
346   break;
347  case ROAR_VS_TOGGLE:
348    return roar_vs_flag(vss, flag, old == ROAR_VS_TRUE ? ROAR_VS_FALSE : ROAR_VS_TRUE, error);
349   break;
350  case ROAR_VS_ASK:
351    if ( roar_stream_get_info(vss->con, &(vss->stream), &info) == -1 ) {
352     _seterrre();
353     return -1;
354    }
355    return info.flags & flag ? ROAR_VS_TRUE : ROAR_VS_FALSE;
356   break;
357 }
358
359 _seterr(ROAR_ERROR_INVAL);
360 return -1;
361}
362
363int     roar_vs_pause(roar_vs_t * vss, int val, int * error) {
364 return roar_vs_flag(vss, ROAR_FLAG_PAUSE, val, error);
365}
366
367int     roar_vs_mute (roar_vs_t * vss, int val, int * error) {
368 return roar_vs_flag(vss, ROAR_FLAG_MUTE, val, error);
369}
370
371static int roar_vs_volume (roar_vs_t * vss, float * c, size_t channels, int * error) {
372 struct roar_mixer_settings mixer;
373 size_t i;
374 register float s;
375 int oldchannels;
376 int handled;
377
378 if ( !(vss->flags & FLAG_STREAM) ) {
379  _seterr(ROAR_ERROR_INVAL);
380  return -1;
381 }
382
383 if ( channels > ROAR_MAX_CHANNELS ) {
384  _seterr(ROAR_ERROR_INVAL);
385  return -1;
386 }
387
388 _initerr();
389
390 if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &oldchannels) == -1 ) {
391  _seterrre();
392  return -1;
393 }
394
395 for (i = 0; i < channels; i++) {
396  s = c[i] * 65535.0;
397  if ( s > 66190.0 || s < -655.0 ) {
398   _seterr(ROAR_ERROR_RANGE);
399   return -1;
400  } else if ( s > 65535.0 ) {
401   s = 65535.0;
402  } else if ( s <     0.0 ) {
403   s = 0.0;
404  }
405  mixer.mixer[i] = s;
406 }
407
408 mixer.scale = 65535;
409
410 if ( channels != oldchannels ) {
411  handled = 0;
412  switch (oldchannels) {
413   case 1:
414     if ( channels == 2 ) {
415      mixer.mixer[0] = (mixer.mixer[0] + mixer.mixer[1]) / 2;
416      handled = 1;
417     }
418    break;
419   case 2:
420     if ( channels == 1 ) {
421      mixer.mixer[1] = mixer.mixer[0];
422      handled = 1;
423     }
424    break;
425   case 4:
426     if ( channels == 1 ) {
427      mixer.mixer[1] = mixer.mixer[0];
428      mixer.mixer[2] = mixer.mixer[0];
429      mixer.mixer[3] = mixer.mixer[0];
430      handled = 1;
431     } else if ( channels == 2 ) {
432      mixer.mixer[2] = mixer.mixer[0];
433      mixer.mixer[3] = mixer.mixer[1];
434      handled = 1;
435     }
436    break;
437  }
438  if ( handled ) {
439   channels = oldchannels;
440  } else {
441   _seterr(ROAR_ERROR_INVAL);
442   return -1;
443  }
444 }
445
446 if ( roar_set_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, channels) == -1 ) {
447  _seterrre();
448  return -1;
449 }
450
451 return 0;
452}
453
454int     roar_vs_volume_mono   (roar_vs_t * vss, float c, int * error) {
455 return roar_vs_volume(vss, &c, 1, error);
456}
457
458int     roar_vs_volume_stereo (roar_vs_t * vss, float l, float r, int * error) {
459 float c[2] = {l, r};
460 return roar_vs_volume(vss, c, 2, error);
461}
462
463int     roar_vs_volume_get    (roar_vs_t * vss, float * l, float * r, int * error) {
464 struct roar_mixer_settings mixer;
465 int channels;
466
467 if ( vss == NULL || l == NULL || r == NULL ) {
468  _seterr(ROAR_ERROR_INVAL);
469  return -1;
470 }
471
472 if ( !(vss->flags & FLAG_STREAM) ) {
473  _seterr(ROAR_ERROR_INVAL);
474  return -1;
475 }
476
477 _initerr();
478
479 if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &channels) == -1 ) {
480  _seterrre();
481  return -1;
482 }
483
484 if ( channels == 1 )
485  mixer.mixer[1] = mixer.mixer[0];
486
487 *l = mixer.mixer[0] / (float)mixer.scale;
488 *r = mixer.mixer[1] / (float)mixer.scale;
489
490 return 0;
491}
492
493int     roar_vs_meta          (roar_vs_t * vss, struct roar_keyval * kv, size_t len, int * error) {
494 struct roar_meta meta;
495 size_t i;
496 int type;
497 int ret = 0;
498
499 if ( !(vss->flags & FLAG_STREAM) ) {
500  _seterr(ROAR_ERROR_INVAL);
501  return -1;
502 }
503
504 meta.type   = ROAR_META_TYPE_NONE;
505 meta.key[0] = 0;
506 meta.value  = NULL;
507
508 _initerr();
509
510 if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_CLEAR, &meta) == -1 ) {
511  _seterrre();
512  ret = -1;
513 }
514
515 for (i = 0; i < len; i++) {
516  type = roar_meta_inttype(kv[i].key);
517  meta.type  = type;
518  meta.value = kv[i].value;
519
520  if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_ADD, &meta) == -1 ) {
521   _seterrre();
522   ret = -1;
523  }
524 }
525
526 meta.type   = ROAR_META_TYPE_NONE;
527 meta.key[0] = 0;
528 meta.value  = NULL;
529 if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_FINALIZE, &meta) == -1 ) {
530  _seterrre();
531  ret = -1;
532 }
533
534 return ret;
535}
536
537struct roar_connection * roar_vs_connection_obj(roar_vs_t * vss, int * error) {
538 return vss->con;
539}
540
541struct roar_stream     * roar_vs_stream_obj    (roar_vs_t * vss, int * error) {
542 if ( !(vss->flags & FLAG_STREAM) ) {
543  _seterr(ROAR_ERROR_INVAL);
544  return NULL;
545 }
546
547 return &(vss->stream);
548}
549
550struct roar_vio_calls  * roar_vs_vio_obj       (roar_vs_t * vss, int * error) {
551 if ( !(vss->flags & FLAG_STREAM) ) {
552  _seterr(ROAR_ERROR_INVAL);
553  return NULL;
554 }
555
556 return &(vss->vio);
557}
558
559//ll
Note: See TracBrowser for help on using the repository browser.