source: roaraudio/libroar/vs.c @ 4215:2b184cedaf1f

Last change on this file since 4215:2b184cedaf1f was 4215:2b184cedaf1f, checked in by phi, 14 years ago

very small error and return value fix

File size: 15.7 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#define FLAG_BUFFERED 0x0004
42
43#define _initerr()  do { errno = 0; roar_err_clear(); } while(0)
44#define _seterr(x)  do { if ( error != NULL ) *error = (x); } while(0)
45#define _seterrre() do { _seterr(roar_errno); } while(0)
46#define _seterrse() do { roar_err_from_errno(); _seterr(roar_errno); } while(0)
47
48struct roar_vs {
49 int flags;
50 struct roar_connection con_store;
51 struct roar_connection * con;
52 struct roar_stream       stream;
53 struct roar_vio_calls    vio;
54 struct roar_audio_info   info;
55 size_t                   readc, writec;
56 int                      mixerid;
57 int                      first_primid;
58};
59
60static int _roar_vs_find_first_prim(roar_vs_t * vss);
61
62const char * roar_vs_strerr(int error) {
63 const struct {
64  int err;
65  const char * msg;
66 } msgs[] = {
67  {ROAR_ERROR_NONE,        "No error"},
68  {ROAR_ERROR_PERM,        "Operation not permitted"},
69  {ROAR_ERROR_NOENT,       "No such object, file or directory"},
70  {ROAR_ERROR_BADMSG,      "Bad message"},
71  {ROAR_ERROR_BUSY,        "Device or resource busy"},
72  {ROAR_ERROR_CONNREFUSED, "Connection refused"},
73  {ROAR_ERROR_NOSYS,       "Function not implemented"},
74  {ROAR_ERROR_NOTSUP,      "Operation not supported"},
75  {ROAR_ERROR_PIPE,        "Broken pipe"},
76  {ROAR_ERROR_PROTO,       "Protocol error"},
77  {ROAR_ERROR_RANGE,       "Result too large or parameter out of range"},
78  {ROAR_ERROR_MSGSIZE,     "Message too long"},
79  {ROAR_ERROR_NOMEM,       "Not enough space"},
80  {ROAR_ERROR_INVAL,       "Invalid argument"},
81  {-1, NULL}
82 };
83 int i;
84
85 for (i = 0; msgs[i].msg != NULL; i++)
86  if ( msgs[i].err == error )
87   return msgs[i].msg;
88
89 return "(unknown)";
90}
91
92static roar_vs_t * roar_vs_init(int * error) {
93 roar_vs_t * vss = roar_mm_malloc(sizeof(roar_vs_t));
94
95 if ( vss == NULL ) {
96  _seterrse();
97  return NULL;
98 }
99
100 memset(vss, 0, sizeof(roar_vs_t));
101
102 vss->mixerid      = -1;
103 vss->first_primid = -1;
104
105 return vss;
106}
107
108roar_vs_t * roar_vs_new_from_con(struct roar_connection * con, int * error) {
109 roar_vs_t * vss = roar_vs_init(error);
110
111 if ( vss == NULL )
112  return NULL;
113
114 vss->con = con;
115
116 return vss;
117}
118
119roar_vs_t * roar_vs_new(const char * server, const char * name, int * error) {
120 roar_vs_t * vss = roar_vs_init(error);
121 int ret;
122
123 if ( vss == NULL )
124  return NULL;
125
126 vss->con = &(vss->con_store);
127
128 _initerr();
129
130 ret = roar_simple_connect(vss->con, (char*)server, (char*)name);
131
132 if ( ret == -1 ) {
133  roar_vs_close(vss, ROAR_VS_TRUE, NULL);
134  _seterrre();
135  return NULL;
136 }
137
138 return vss;
139}
140
141int roar_vs_stream(roar_vs_t * vss, const struct roar_audio_info * info, int dir, int * error) {
142 struct roar_stream_info sinfo;
143 int ret;
144
145 if ( vss->flags & FLAG_STREAM ) {
146  _seterr(ROAR_ERROR_INVAL);
147  return -1;
148 }
149
150 _initerr();
151
152 if ( info != &(vss->info) )
153  memcpy(&(vss->info), info, sizeof(struct roar_audio_info));
154
155 ret = roar_vio_simple_new_stream_obj(&(vss->vio), vss->con, &(vss->stream),
156                                      info->rate, info->channels, info->bits, info->codec,
157                                      dir
158                                     );
159
160 if ( ret == -1 ) {
161  _seterrre();
162  return -1;
163 }
164
165 if ( roar_stream_get_info(vss->con, &(vss->stream), &sinfo) != -1 ) {
166  vss->mixerid = sinfo.mixer;
167  _roar_vs_find_first_prim(vss);
168 }
169
170 vss->flags |= FLAG_STREAM;
171
172 return 0;
173}
174
175roar_vs_t * roar_vs_new_simple(const char * server, const char * name, int rate, int channels, int codec, int bits, int dir, int * error) {
176 roar_vs_t * vss = roar_vs_new(server, name, error);
177 int ret;
178
179 if (vss == NULL)
180  return NULL;
181
182 memset(&(vss->info), 0, sizeof(vss->info));
183
184 vss->info.rate     = rate;
185 vss->info.channels = channels;
186 vss->info.codec    = codec;
187 vss->info.bits     = bits;
188
189 ret = roar_vs_stream(vss, &(vss->info), dir, error);
190
191 if (ret == -1) {
192  roar_vs_close(vss, ROAR_VS_TRUE, NULL);
193  return NULL;
194 }
195
196 return vss;
197}
198
199int roar_vs_close(roar_vs_t * vss, int killit, int * error) {
200 if ( killit != ROAR_VS_TRUE && killit != ROAR_VS_FALSE ) {
201  _seterr(ROAR_ERROR_UNKNOWN);
202  return -1;
203 }
204
205 if ( vss->flags & FLAG_STREAM ) {
206  if ( killit == ROAR_VS_TRUE ) {
207   roar_kick(vss->con, ROAR_OT_STREAM, roar_stream_get_id(&(vss->stream)));
208  }
209
210  roar_vio_close(&(vss->vio));
211 }
212
213 if ( vss->con == &(vss->con_store) ) {
214  roar_disconnect(vss->con);
215 }
216
217 roar_mm_free(vss);
218 return 0;
219}
220
221ssize_t roar_vs_write(roar_vs_t * vss, const void * buf, size_t len, int * error) {
222 ssize_t ret;
223
224 if ( !(vss->flags & FLAG_STREAM) ) {
225  _seterr(ROAR_ERROR_INVAL);
226  return -1;
227 }
228
229 _initerr();
230
231 ret = roar_vio_write(&(vss->vio), (void*)buf, len);
232
233 if ( ret == -1 ) {
234#ifdef EAGAIN
235  if ( errno == EAGAIN )
236   return 0;
237#endif
238
239#ifdef EWOULDBLOCK
240  if ( errno == EWOULDBLOCK )
241   return 0;
242#endif
243
244  _seterrre();
245 } else {
246  vss->writec += ret;
247 }
248
249 return ret;
250}
251
252ssize_t roar_vs_read (roar_vs_t * vss,       void * buf, size_t len, int * error) {
253 ssize_t ret;
254
255 if ( !(vss->flags & FLAG_STREAM) ) {
256  _seterr(ROAR_ERROR_INVAL);
257  return -1;
258 }
259
260 _initerr();
261
262 ret = roar_vio_read(&(vss->vio), buf, len);
263
264 if ( ret == -1 ) {
265  _seterrre();
266 } else {
267  vss->readc += ret;
268 }
269
270 return ret;
271}
272
273int     roar_vs_sync (roar_vs_t * vss, int wait, int * error) {
274 if ( !(vss->flags & FLAG_STREAM) ) {
275  _seterr(ROAR_ERROR_INVAL);
276  return -1;
277 }
278
279 if ( wait != ROAR_VS_NOWAIT ) {
280  _seterr(ROAR_ERROR_INVAL);
281  return -1;
282 }
283
284 _initerr();
285
286 if ( roar_vio_sync(&(vss->vio)) == -1 ) {
287  _seterrre();
288  return -1;
289 }
290
291 return 0;
292}
293
294int     roar_vs_blocking (roar_vs_t * vss, int val, int * error) {
295 int old = -1;
296
297  if ( !(vss->flags & FLAG_STREAM) ) {
298  _seterr(ROAR_ERROR_INVAL);
299  return -1;
300 }
301
302 old = vss->flags & FLAG_NONBLOCK ? ROAR_VS_FALSE : ROAR_VS_TRUE;
303
304 _initerr();
305
306 switch (val) {
307  case ROAR_VS_TRUE:
308    if ( roar_vio_nonblock(&(vss->vio), ROAR_SOCKET_BLOCK) == -1 ) {
309     _seterrre();
310     return -1;
311    }
312    vss->flags |= FLAG_NONBLOCK;
313    vss->flags -= FLAG_NONBLOCK;
314    return old;
315   break;
316  case ROAR_VS_FALSE:
317    if ( roar_vio_nonblock(&(vss->vio), ROAR_SOCKET_NONBLOCK) == -1 ) {
318     _seterrre();
319     return -1;
320    }
321    vss->flags |= FLAG_NONBLOCK;
322    return old;
323   break;
324  case ROAR_VS_TOGGLE:
325    if ( old == ROAR_VS_TRUE ) {
326     return roar_vs_blocking(vss, ROAR_VS_FALSE, error);
327    } else {
328     return roar_vs_blocking(vss, ROAR_VS_TRUE, error);
329    }
330   break;
331  case ROAR_VS_ASK:
332    return old;
333   break;
334 }
335
336 _seterr(ROAR_ERROR_INVAL);
337 return -1;
338}
339
340static int _roar_vs_find_first_prim(roar_vs_t * vss) {
341 struct roar_stream stream;
342 struct roar_stream_info info;
343 int id[ROAR_STREAMS_MAX];
344 int num;
345 int i;
346
347 if ( vss->first_primid != -1 )
348  return vss->first_primid;
349
350 if ( vss->mixerid == -1 )
351  return -1;
352
353 if ( (num = roar_list_streams(vss->con, id, ROAR_STREAMS_MAX)) == -1 ) {
354  return -1;
355 }
356
357 for (i = 0; i < num; i++) {
358  if ( roar_get_stream(vss->con, &stream, id[i]) == -1 )
359   continue;
360
361  if ( stream.dir != ROAR_DIR_OUTPUT )
362   continue;
363
364  if ( roar_stream_get_info(vss->con, &stream, &info) == -1 )
365   continue;
366
367  if ( info.mixer == vss->mixerid ) {
368   vss->first_primid = id[i];
369   return id[i];
370  }
371 }
372
373 return -1;
374}
375
376ssize_t roar_vs_position(roar_vs_t * vss, int backend, int * error) {
377 struct roar_stream stream;
378 struct roar_stream      out_stream;
379 struct roar_stream_info out_info;
380 size_t offset;
381
382 if ( !(vss->flags & FLAG_STREAM) ) {
383  _seterr(ROAR_ERROR_INVAL);
384  return -1;
385 }
386
387 _initerr();
388
389 if ( roar_get_stream(vss->con, &stream, roar_stream_get_id(&(vss->stream))) == -1 ) {
390  _seterrre();
391  return -1;
392 }
393
394 switch (backend) {
395  case ROAR_VS_BACKEND_NONE:
396    return stream.pos;
397   break;
398  case ROAR_VS_BACKEND_FIRST:
399   // _roar_vs_find_first_prim(vss);
400    if ( vss->first_primid == -1 ) {
401     _seterr(ROAR_ERROR_UNKNOWN);
402     return -1;
403    }
404
405    roar_stream_new_by_id(&out_stream, vss->first_primid);
406
407    if ( roar_stream_get_info(vss->con, &out_stream, &out_info) == -1 ) {
408     _seterrre();
409     return -1;
410    }
411
412    offset  = out_info.delay * vss->info.rate;
413    offset /= 1000000;
414
415    return stream.pos + offset;
416   break;
417  default:
418    _seterr(ROAR_ERROR_NOTSUP);
419    return -1;
420   break;
421 }
422
423 _seterr(ROAR_ERROR_NOSYS);
424 return -1;
425}
426
427roar_mus_t roar_vs_latency(roar_vs_t * vss, int backend, int * error) {
428 ssize_t pos  = roar_vs_position(vss, backend, error);
429 ssize_t bps;  // byte per sample
430 size_t  lioc; // local IO (byte) counter
431 size_t  lpos; // local possition
432 roar_mus_t  lag;
433
434 _initerr();
435
436 if (pos == -1) {
437  _seterrre();
438  return 0;
439 }
440
441 if ( !(vss->flags & FLAG_STREAM) ) {
442  _seterr(ROAR_ERROR_INVAL);
443  return 0;
444 }
445
446 if ( vss->writec == 0 ) {
447  lioc = vss->readc;
448 } else {
449  lioc = vss->writec;
450 }
451
452 bps = roar_info2samplesize(&(vss->info));
453
454 if ( bps == -1 ) {
455  _seterrre();
456  return 0;
457 }
458
459 lpos = lioc / bps;
460
461 lag = (roar_mus_t)lpos - (roar_mus_t)pos;
462
463 // we now have the lag in frames
464 // return value are ms
465 // so we need to multiply with 1s/ms and
466 // multiply by 1/rate
467
468 lag *= 1000000; // 1s/ms
469 lag /= vss->info.rate;
470
471 if ( lag == 0 ) {
472  _seterr(ROAR_ERROR_NONE);
473 }
474
475 return lag;
476}
477
478static int roar_vs_flag(roar_vs_t * vss, int flag, int val, int * error) {
479 struct roar_stream_info info;
480 int old = -1;
481
482 if ( !(vss->flags & FLAG_STREAM) ) {
483  _seterr(ROAR_ERROR_INVAL);
484  return -1;
485 }
486
487 if ( val != ROAR_VS_ASK )
488  old = roar_vs_flag(vss, flag, ROAR_VS_ASK, error);
489
490 _initerr();
491
492 switch (val) {
493  case ROAR_VS_TRUE:
494  case ROAR_VS_FALSE:
495    if ( roar_stream_set_flags(vss->con, &(vss->stream), flag,
496                               val == ROAR_VS_TRUE ? ROAR_SET_FLAG : ROAR_RESET_FLAG) == -1 ) {
497     _seterrre();
498     return -1;
499    }
500    return old;
501   break;
502  case ROAR_VS_TOGGLE:
503    return roar_vs_flag(vss, flag, old == ROAR_VS_TRUE ? ROAR_VS_FALSE : ROAR_VS_TRUE, error);
504   break;
505  case ROAR_VS_ASK:
506    if ( roar_stream_get_info(vss->con, &(vss->stream), &info) == -1 ) {
507     _seterrre();
508     return -1;
509    }
510    return info.flags & flag ? ROAR_VS_TRUE : ROAR_VS_FALSE;
511   break;
512 }
513
514 _seterr(ROAR_ERROR_INVAL);
515 return -1;
516}
517
518int     roar_vs_pause(roar_vs_t * vss, int val, int * error) {
519 return roar_vs_flag(vss, ROAR_FLAG_PAUSE, val, error);
520}
521
522int     roar_vs_mute (roar_vs_t * vss, int val, int * error) {
523 return roar_vs_flag(vss, ROAR_FLAG_MUTE, val, error);
524}
525
526static int roar_vs_volume (roar_vs_t * vss, float * c, size_t channels, int * error) {
527 struct roar_mixer_settings mixer;
528 size_t i;
529 register float s;
530 int oldchannels;
531 int handled;
532
533 if ( !(vss->flags & FLAG_STREAM) ) {
534  _seterr(ROAR_ERROR_INVAL);
535  return -1;
536 }
537
538 if ( channels > ROAR_MAX_CHANNELS ) {
539  _seterr(ROAR_ERROR_INVAL);
540  return -1;
541 }
542
543 _initerr();
544
545 if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &oldchannels) == -1 ) {
546  _seterrre();
547  return -1;
548 }
549
550 for (i = 0; i < channels; i++) {
551  s = c[i] * 65535.0;
552  if ( s > 66190.0 || s < -655.0 ) {
553   _seterr(ROAR_ERROR_RANGE);
554   return -1;
555  } else if ( s > 65535.0 ) {
556   s = 65535.0;
557  } else if ( s <     0.0 ) {
558   s = 0.0;
559  }
560  mixer.mixer[i] = s;
561 }
562
563 mixer.scale = 65535;
564
565 if ( channels != oldchannels ) {
566  handled = 0;
567  switch (oldchannels) {
568   case 1:
569     if ( channels == 2 ) {
570      mixer.mixer[0] = (mixer.mixer[0] + mixer.mixer[1]) / 2;
571      handled = 1;
572     }
573    break;
574   case 2:
575     if ( channels == 1 ) {
576      mixer.mixer[1] = mixer.mixer[0];
577      handled = 1;
578     }
579    break;
580   case 4:
581     if ( channels == 1 ) {
582      mixer.mixer[1] = mixer.mixer[0];
583      mixer.mixer[2] = mixer.mixer[0];
584      mixer.mixer[3] = mixer.mixer[0];
585      handled = 1;
586     } else if ( channels == 2 ) {
587      mixer.mixer[2] = mixer.mixer[0];
588      mixer.mixer[3] = mixer.mixer[1];
589      handled = 1;
590     }
591    break;
592  }
593  if ( handled ) {
594   channels = oldchannels;
595  } else {
596   _seterr(ROAR_ERROR_INVAL);
597   return -1;
598  }
599 }
600
601 if ( roar_set_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, channels) == -1 ) {
602  _seterrre();
603  return -1;
604 }
605
606 return 0;
607}
608
609int     roar_vs_volume_mono   (roar_vs_t * vss, float c, int * error) {
610 return roar_vs_volume(vss, &c, 1, error);
611}
612
613int     roar_vs_volume_stereo (roar_vs_t * vss, float l, float r, int * error) {
614 float c[2] = {l, r};
615 return roar_vs_volume(vss, c, 2, error);
616}
617
618int     roar_vs_volume_get    (roar_vs_t * vss, float * l, float * r, int * error) {
619 struct roar_mixer_settings mixer;
620 int channels;
621
622 if ( vss == NULL || l == NULL || r == NULL ) {
623  _seterr(ROAR_ERROR_INVAL);
624  return -1;
625 }
626
627 if ( !(vss->flags & FLAG_STREAM) ) {
628  _seterr(ROAR_ERROR_INVAL);
629  return -1;
630 }
631
632 _initerr();
633
634 if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &channels) == -1 ) {
635  _seterrre();
636  return -1;
637 }
638
639 if ( channels == 1 )
640  mixer.mixer[1] = mixer.mixer[0];
641
642 *l = mixer.mixer[0] / (float)mixer.scale;
643 *r = mixer.mixer[1] / (float)mixer.scale;
644
645 return 0;
646}
647
648int     roar_vs_meta          (roar_vs_t * vss, struct roar_keyval * kv, size_t len, int * error) {
649 struct roar_meta meta;
650 size_t i;
651 int type;
652 int ret = 0;
653
654 if ( !(vss->flags & FLAG_STREAM) ) {
655  _seterr(ROAR_ERROR_INVAL);
656  return -1;
657 }
658
659 meta.type   = ROAR_META_TYPE_NONE;
660 meta.key[0] = 0;
661 meta.value  = NULL;
662
663 _initerr();
664
665 if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_CLEAR, &meta) == -1 ) {
666  _seterrre();
667  ret = -1;
668 }
669
670 for (i = 0; i < len; i++) {
671  type = roar_meta_inttype(kv[i].key);
672  meta.type  = type;
673  meta.value = kv[i].value;
674
675  if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_ADD, &meta) == -1 ) {
676   _seterrre();
677   ret = -1;
678  }
679 }
680
681 meta.type   = ROAR_META_TYPE_NONE;
682 meta.key[0] = 0;
683 meta.value  = NULL;
684 if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_FINALIZE, &meta) == -1 ) {
685  _seterrre();
686  ret = -1;
687 }
688
689 return ret;
690}
691
692int     roar_vs_role          (roar_vs_t * vss, int role, int * error) {
693 if ( !(vss->flags & FLAG_STREAM) ) {
694  _seterr(ROAR_ERROR_INVAL);
695  return -1;
696 }
697
698 _initerr();
699
700 if ( roar_stream_set_role(vss->con, &(vss->stream), role) == -1 ) {
701  _seterrre();
702  return -1;
703 }
704
705 return 0;
706}
707
708struct roar_connection * roar_vs_connection_obj(roar_vs_t * vss, int * error) {
709 return vss->con;
710}
711
712struct roar_stream     * roar_vs_stream_obj    (roar_vs_t * vss, int * error) {
713 if ( !(vss->flags & FLAG_STREAM) ) {
714  _seterr(ROAR_ERROR_INVAL);
715  return NULL;
716 }
717
718 return &(vss->stream);
719}
720
721struct roar_vio_calls  * roar_vs_vio_obj       (roar_vs_t * vss, int * error) {
722 if ( !(vss->flags & FLAG_STREAM) ) {
723  _seterr(ROAR_ERROR_INVAL);
724  return NULL;
725 }
726
727 return &(vss->vio);
728}
729
730//ll
Note: See TracBrowser for help on using the repository browser.