source: roaraudio/libroar/vs.c @ 4186:8052a0fa5ec2

Last change on this file since 4186:8052a0fa5ec2 was 4186:8052a0fa5ec2, checked in by phi, 14 years ago

read error value from RoarAudio's own errno

File size: 12.2 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  _seterrre();
217 }
218
219 return ret;
220}
221
222ssize_t roar_vs_read (roar_vs_t * vss,       void * buf, size_t len, int * error) {
223 ssize_t ret;
224
225 if ( !(vss->flags & FLAG_STREAM) ) {
226  _seterr(ROAR_ERROR_INVAL);
227  return -1;
228 }
229
230 _initerr();
231
232 ret = roar_vio_read(&(vss->vio), buf, len);
233
234 if ( ret == -1 ) {
235  _seterrre();
236 }
237
238 return ret;
239}
240
241int     roar_vs_sync (roar_vs_t * vss, int wait, int * error) {
242 if ( !(vss->flags & FLAG_STREAM) ) {
243  _seterr(ROAR_ERROR_INVAL);
244  return -1;
245 }
246
247 if ( wait != ROAR_VS_NOWAIT ) {
248  _seterr(ROAR_ERROR_INVAL);
249  return -1;
250 }
251
252 _initerr();
253
254 if ( roar_vio_sync(&(vss->vio)) == -1 ) {
255  _seterrre();
256  return -1;
257 }
258
259 return 0;
260}
261
262int     roar_vs_blocking (roar_vs_t * vss, int val, int * error) {
263 int old = -1;
264
265  if ( !(vss->flags & FLAG_STREAM) ) {
266  _seterr(ROAR_ERROR_INVAL);
267  return -1;
268 }
269
270 old = vss->flags & FLAG_NONBLOCK ? ROAR_VS_FALSE : ROAR_VS_TRUE;
271
272 _initerr();
273
274 switch (val) {
275  case ROAR_VS_TRUE:
276    if ( roar_vio_nonblock(&(vss->vio), ROAR_SOCKET_BLOCK) == -1 ) {
277     _seterrre();
278     return -1;
279    }
280    vss->flags |= FLAG_NONBLOCK;
281    vss->flags -= FLAG_NONBLOCK;
282    return old;
283   break;
284  case ROAR_VS_FALSE:
285    if ( roar_vio_nonblock(&(vss->vio), ROAR_SOCKET_NONBLOCK) == -1 ) {
286     _seterrre();
287     return -1;
288    }
289    vss->flags |= FLAG_NONBLOCK;
290    return old;
291   break;
292  case ROAR_VS_TOGGLE:
293    if ( old == ROAR_VS_TRUE ) {
294     return roar_vs_blocking(vss, ROAR_VS_FALSE, error);
295    } else {
296     return roar_vs_blocking(vss, ROAR_VS_TRUE, error);
297    }
298   break;
299  case ROAR_VS_ASK:
300    return old;
301   break;
302 }
303
304 _seterr(ROAR_ERROR_INVAL);
305 return -1;
306}
307
308ssize_t roar_vs_latency(roar_vs_t * vss, int backend, int * error) {
309 _seterr(ROAR_ERROR_NOSYS);
310 return -1;
311}
312
313static int roar_vs_flag(roar_vs_t * vss, int flag, int val, int * error) {
314 struct roar_stream_info info;
315 int old = -1;
316
317 if ( !(vss->flags & FLAG_STREAM) ) {
318  _seterr(ROAR_ERROR_INVAL);
319  return -1;
320 }
321
322 if ( val != ROAR_VS_ASK )
323  old = roar_vs_flag(vss, flag, ROAR_VS_ASK, error);
324
325 _initerr();
326
327 switch (val) {
328  case ROAR_VS_TRUE:
329  case ROAR_VS_FALSE:
330    if ( roar_stream_set_flags(vss->con, &(vss->stream), flag,
331                               val == ROAR_VS_TRUE ? ROAR_SET_FLAG : ROAR_RESET_FLAG) == -1 ) {
332     _seterrre();
333     return -1;
334    }
335    return old;
336   break;
337  case ROAR_VS_TOGGLE:
338    return roar_vs_flag(vss, flag, old == ROAR_VS_TRUE ? ROAR_VS_FALSE : ROAR_VS_TRUE, error);
339   break;
340  case ROAR_VS_ASK:
341    if ( roar_stream_get_info(vss->con, &(vss->stream), &info) == -1 ) {
342     _seterrre();
343     return -1;
344    }
345    return info.flags & flag ? ROAR_VS_TRUE : ROAR_VS_FALSE;
346   break;
347 }
348
349 _seterr(ROAR_ERROR_NOTSUP);
350 return -1;
351}
352
353int     roar_vs_pause(roar_vs_t * vss, int val, int * error) {
354 return roar_vs_flag(vss, ROAR_FLAG_PAUSE, val, error);
355}
356
357int     roar_vs_mute (roar_vs_t * vss, int val, int * error) {
358 return roar_vs_flag(vss, ROAR_FLAG_MUTE, val, error);
359}
360
361static int roar_vs_volume (roar_vs_t * vss, float * c, size_t channels, int * error) {
362 struct roar_mixer_settings mixer;
363 size_t i;
364 register float s;
365 int oldchannels;
366 int handled;
367
368 if ( !(vss->flags & FLAG_STREAM) ) {
369  _seterr(ROAR_ERROR_INVAL);
370  return -1;
371 }
372
373 if ( channels > ROAR_MAX_CHANNELS ) {
374  _seterr(ROAR_ERROR_INVAL);
375  return -1;
376 }
377
378 _initerr();
379
380 if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &oldchannels) == -1 ) {
381  _seterrre();
382  return -1;
383 }
384
385 for (i = 0; i < channels; i++) {
386  s = c[i] * 65535.0;
387  if ( s > 66190.0 || s < -655.0 ) {
388   _seterr(ROAR_ERROR_RANGE);
389   return -1;
390  } else if ( s > 65535.0 ) {
391   s = 65535.0;
392  } else if ( s <     0.0 ) {
393   s = 0.0;
394  }
395  mixer.mixer[i] = s;
396 }
397
398 mixer.scale = 65535;
399
400 if ( channels != oldchannels ) {
401  handled = 0;
402  switch (oldchannels) {
403   case 1:
404     if ( channels == 2 ) {
405      mixer.mixer[0] = (mixer.mixer[0] + mixer.mixer[1]) / 2;
406      handled = 1;
407     }
408    break;
409   case 2:
410     if ( channels == 1 ) {
411      mixer.mixer[1] = mixer.mixer[0];
412      handled = 1;
413     }
414    break;
415   case 4:
416     if ( channels == 1 ) {
417      mixer.mixer[1] = mixer.mixer[0];
418      mixer.mixer[2] = mixer.mixer[0];
419      mixer.mixer[3] = mixer.mixer[0];
420      handled = 1;
421     } else if ( channels == 2 ) {
422      mixer.mixer[2] = mixer.mixer[0];
423      mixer.mixer[3] = mixer.mixer[1];
424      handled = 1;
425     }
426    break;
427  }
428  if ( handled ) {
429   channels = oldchannels;
430  } else {
431   _seterr(ROAR_ERROR_INVAL);
432   return -1;
433  }
434 }
435
436 if ( roar_set_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, channels) == -1 ) {
437  _seterrre();
438  return -1;
439 }
440
441 return 0;
442}
443
444int     roar_vs_volume_mono   (roar_vs_t * vss, float c, int * error) {
445 return roar_vs_volume(vss, &c, 1, error);
446}
447
448int     roar_vs_volume_stereo (roar_vs_t * vss, float l, float r, int * error) {
449 float c[2] = {l, r};
450 return roar_vs_volume(vss, c, 2, error);
451}
452
453int     roar_vs_volume_get    (roar_vs_t * vss, float * l, float * r, int * error) {
454 struct roar_mixer_settings mixer;
455 int channels;
456
457 if ( vss == NULL || l == NULL || r == NULL ) {
458  _seterr(ROAR_ERROR_INVAL);
459  return -1;
460 }
461
462 if ( !(vss->flags & FLAG_STREAM) ) {
463  _seterr(ROAR_ERROR_INVAL);
464  return -1;
465 }
466
467 _initerr();
468
469 if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &channels) == -1 ) {
470  _seterrre();
471  return -1;
472 }
473
474 if ( channels == 1 )
475  mixer.mixer[1] = mixer.mixer[0];
476
477 *l = mixer.mixer[0] / (float)mixer.scale;
478 *r = mixer.mixer[1] / (float)mixer.scale;
479
480 return 0;
481}
482
483int     roar_vs_meta          (roar_vs_t * vss, struct roar_keyval * kv, size_t len, int * error) {
484 struct roar_meta meta;
485 size_t i;
486 int type;
487 int ret = 0;
488
489 if ( !(vss->flags & FLAG_STREAM) ) {
490  _seterr(ROAR_ERROR_INVAL);
491  return -1;
492 }
493
494 meta.type   = ROAR_META_TYPE_NONE;
495 meta.key[0] = 0;
496 meta.value  = NULL;
497
498 _initerr();
499
500 if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_CLEAR, &meta) == -1 ) {
501  _seterrre();
502  ret = -1;
503 }
504
505 for (i = 0; i < len; i++) {
506  type = roar_meta_inttype(kv[i].key);
507  meta.type  = type;
508  meta.value = kv[i].value;
509
510  if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_ADD, &meta) == -1 ) {
511   _seterrre();
512   ret = -1;
513  }
514 }
515
516 meta.type   = ROAR_META_TYPE_NONE;
517 meta.key[0] = 0;
518 meta.value  = NULL;
519 if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_FINALIZE, &meta) == -1 ) {
520  _seterrre();
521  ret = -1;
522 }
523
524 return ret;
525}
526
527struct roar_connection * roar_vs_connection_obj(roar_vs_t * vss, int * error) {
528 return vss->con;
529}
530
531struct roar_stream     * roar_vs_stream_obj    (roar_vs_t * vss, int * error) {
532 if ( !(vss->flags & FLAG_STREAM) ) {
533  _seterr(ROAR_ERROR_INVAL);
534  return NULL;
535 }
536
537 return &(vss->stream);
538}
539
540struct roar_vio_calls  * roar_vs_vio_obj       (roar_vs_t * vss, int * error) {
541 if ( !(vss->flags & FLAG_STREAM) ) {
542  _seterr(ROAR_ERROR_INVAL);
543  return NULL;
544 }
545
546 return &(vss->vio);
547}
548
549//ll
Note: See TracBrowser for help on using the repository browser.