source: roaraudio/libroar/vs.c @ 5068:f11a0c0bacdd

Last change on this file since 5068:f11a0c0bacdd was 5068:f11a0c0bacdd, checked in by phi, 11 years ago

Support non-blocking latency request in VS API (Closes: #97)

File size: 33.9 KB
Line 
1//vs.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2011
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#if defined(ROAR_HAVE_GETSOCKOPT) && defined(ROAR_HAVE_SETSOCKOPT)
39#define _HAVE_SOCKOPT
40#endif
41
42#define LOCAL_CLOCK    ROAR_CLOCK_DEFAULT
43
44#define FLAG_NONE      0x0000
45#define FLAG_STREAM    0x0001
46#define FLAG_NONBLOCK  0x0002
47#define FLAG_BUFFERED  0x0004
48#define FLAG_CLOSEFILE 0x0008
49#define FLAG_FREE_VOL  0x0010
50#define FLAG_DEF_PAUSE 0x0020
51#define FLAG_DIR_IN    0x1000
52#define FLAG_DIR_OUT   0x2000
53
54#define _initerr()  roar_err_clear_all()
55#define _seterr(x)  do { if ( error != NULL ) *error = (x); roar_err_set((x)); ROAR_DBG("roar_vs_*(*): *error=%s(%i)", roar_vs_strerr((x)), (x)); } while(0)
56#define _seterrre() do { _seterr(roar_error); } while(0)
57#define _seterrse() do { roar_err_from_errno(); _seterr(roar_error); } while(0)
58#define _ckvss(ret) do { if ( vss == NULL ) { _seterr(ROAR_ERROR_INVAL); return (ret); } } while(0)
59
60struct roar_vs {
61 int flags;
62 struct roar_connection con_store;
63 struct roar_connection * con;
64 struct roar_stream       stream;
65 struct roar_vio_calls    vio;
66 struct roar_audio_info   info;
67 size_t                   readc, writec;
68 int                      mixerid;
69 int                      first_primid;
70 struct roar_buffer     * readbuffer, * writebuffer;
71 struct roar_vio_calls    file_store;
72 struct roar_vio_calls  * file;
73 struct roar_buffer     * readring, * writering;
74#ifdef _HAVE_SOCKOPT
75 struct {
76  float target;
77  float window;
78  float minlag;
79  float p;
80 } latc;
81#endif
82 struct {
83  ssize_t last_pos;
84  struct roar_time last_time;
85 } latmes;
86};
87
88static int _roar_vs_find_first_prim(roar_vs_t * vss);
89
90const char * roar_vs_strerr(int error) {
91 const char * ret = roar_error2str(error);
92
93 if ( ret == NULL )
94  return "(unknown)";
95
96 return ret;
97}
98
99static roar_vs_t * roar_vs_init(int * error) {
100 roar_vs_t * vss = roar_mm_malloc(sizeof(roar_vs_t));
101
102 if ( vss == NULL ) {
103  _seterrse();
104  return NULL;
105 }
106
107 memset(vss, 0, sizeof(roar_vs_t));
108
109 vss->mixerid      = -1;
110 vss->first_primid = -1;
111
112#ifdef _HAVE_SOCKOPT
113 vss->latc.target = -2.; // must be less than latc.minlag!
114 vss->latc.window = -1.;
115 vss->latc.minlag = -1.;
116 vss->latc.p      =  0.005;
117#endif
118
119 vss->latmes.last_pos = -1;
120
121 return vss;
122}
123
124roar_vs_t * roar_vs_new_from_con(struct roar_connection * con, int * error) {
125 roar_vs_t * vss = roar_vs_init(error);
126
127 if ( vss == NULL )
128  return NULL;
129
130 vss->con = con;
131
132 return vss;
133}
134
135roar_vs_t * roar_vs_new(const char * server, const char * name, int * error) {
136 roar_vs_t * vss = roar_vs_init(error);
137 int ret;
138
139 if ( vss == NULL )
140  return NULL;
141
142 vss->con = &(vss->con_store);
143
144 _initerr();
145
146 ret = roar_simple_connect(vss->con, (char*)server, (char*)name);
147
148 if ( ret == -1 ) {
149  roar_vs_close(vss, ROAR_VS_TRUE, NULL);
150  _seterrre();
151  return NULL;
152 }
153
154 return vss;
155}
156
157int roar_vs_stream(roar_vs_t * vss, const struct roar_audio_info * info, int dir, int * error) {
158 struct roar_stream_info sinfo;
159 int ret;
160
161 _ckvss(-1);
162
163 if ( vss->flags & FLAG_STREAM ) {
164  _seterr(ROAR_ERROR_INVAL);
165  return -1;
166 }
167
168 if ( dir == ROAR_DIR_FILTER )
169  vss->flags |= FLAG_DEF_PAUSE;
170
171 _initerr();
172
173 if ( info != &(vss->info) )
174  memcpy(&(vss->info), info, sizeof(struct roar_audio_info));
175
176 ret = roar_vio_simple_new_stream_obj(&(vss->vio), vss->con, &(vss->stream),
177                                      info->rate, info->channels, info->bits, info->codec,
178                                      dir
179                                     );
180
181 if ( ret == -1 ) {
182  _seterrre();
183  return -1;
184 }
185
186 if ( roar_stream_get_info(vss->con, &(vss->stream), &sinfo) != -1 ) {
187  // TODO: fix this:
188  // as we currently do not support to select mixer we just check if we hit the
189  // right one.
190  if ( vss->mixerid != -1 && vss->mixerid != sinfo.mixer ) {
191   _seterr(ROAR_ERROR_INVAL); // TODO: should we maybe use a diffrent value?
192   roar_vio_close(&(vss->vio));
193   return -1;
194  }
195
196  vss->mixerid = sinfo.mixer;
197  _roar_vs_find_first_prim(vss);
198 }
199
200 vss->flags |= FLAG_STREAM;
201
202 switch (dir) {
203  case ROAR_DIR_PLAY: vss->flags |= FLAG_DIR_OUT; break;
204 }
205
206 return 0;
207}
208
209roar_vs_t * roar_vs_new_simple(const char * server, const char * name, int rate, int channels, int codec, int bits, int dir, int * error) {
210 roar_vs_t * vss = roar_vs_new(server, name, error);
211 int ret;
212
213 if (vss == NULL)
214  return NULL;
215
216 memset(&(vss->info), 0, sizeof(vss->info));
217
218 vss->info.rate     = rate;
219 vss->info.channels = channels;
220 vss->info.codec    = codec;
221 vss->info.bits     = bits;
222
223 ret = roar_vs_stream(vss, &(vss->info), dir, error);
224
225 if (ret == -1) {
226  roar_vs_close(vss, ROAR_VS_TRUE, NULL);
227  return NULL;
228 }
229
230 return vss;
231}
232
233int roar_vs_file(roar_vs_t * vss, struct roar_vio_calls * vio, int closefile, int * error) {
234 _ckvss(-1);
235
236 if ( vio == NULL || (closefile != ROAR_VS_TRUE && closefile != ROAR_VS_FALSE)) {
237  _seterr(ROAR_ERROR_INVAL);
238  return -1;
239 }
240
241 if ( vss->file != NULL ) {
242  _seterr(ROAR_ERROR_INVAL);
243  return -1;
244 }
245
246 vss->file = vio;
247 if ( closefile == ROAR_VS_TRUE )
248  vss->flags |= FLAG_CLOSEFILE;
249
250 return 0;
251}
252
253int roar_vs_file_simple(roar_vs_t * vss, char * filename, int * error) {
254 struct roar_vio_defaults def;
255 struct roar_vio_calls * file;
256 char buf[64];
257 ssize_t ret;
258 int dir = O_RDONLY;
259 int codec = -1;
260 const char * content_type;
261
262 _ckvss(-1);
263
264 if ( vss->file != NULL ) {
265  _seterr(ROAR_ERROR_INVAL);
266  return -1;
267 }
268
269 if ( vss->flags & FLAG_STREAM ) {
270  switch (vss->flags & (FLAG_DIR_IN|FLAG_DIR_OUT)) {
271   case FLAG_DIR_IN:  dir = O_WRONLY; break;
272   case FLAG_DIR_OUT: dir = O_RDONLY; break;
273   case FLAG_DIR_IN|FLAG_DIR_OUT: dir = O_RDWR; break;
274   default:
275     _seterr(ROAR_ERROR_INVAL);
276     return -1;
277  }
278 }
279
280 file = &(vss->file_store);
281
282 _initerr();
283
284 if ( roar_vio_dstr_init_defaults(&def, ROAR_VIO_DEF_TYPE_NONE, dir, 0644) == -1 ) {
285  _seterrre();
286  return -1;
287 }
288
289 if ( roar_vio_open_dstr(file, filename, &def, 1) == -1 ) {
290  _seterrre();
291  return -1;
292 }
293
294 if ( !(vss->flags & FLAG_STREAM) ) {
295  if ( roar_vio_ctl(file, ROAR_VIO_CTL_GET_MIMETYPE, &content_type) != -1 ) {
296   codec = roar_mime2codec(content_type);
297  }
298
299  if ( codec == -1 ) {
300   ret = roar_vio_read(file, buf, sizeof(buf));
301
302   codec = roar_file_codecdetect(buf, ret);
303
304   if ( codec == -1 ) {
305    roar_vio_close(file);
306    _seterr(ROAR_ERROR_INVAL); // Other value?
307    return -1;
308   }
309
310   if ( roar_vio_lseek(file, 0, SEEK_SET) != 0 ) {
311    roar_vio_close(file);
312   _seterrre();
313    return -1;
314   }
315  }
316
317  memset(&(vss->info), 0, sizeof(vss->info));
318
319  vss->info.rate     = ROAR_RATE_DEFAULT;
320  vss->info.channels = ROAR_CHANNELS_DEFAULT;
321  vss->info.codec    = codec;
322  vss->info.bits     = ROAR_BITS_DEFAULT;
323
324  ret = roar_vs_stream(vss, &(vss->info), ROAR_DIR_PLAY, error);
325
326  if ( ret == -1 ) {
327   roar_vio_close(file);
328   return -1;
329  }
330 }
331
332 if ( roar_vs_file(vss, file, ROAR_VS_TRUE, error) == -1 ) {
333  roar_vio_close(file);
334  return -1;
335 }
336
337 return 0;
338}
339
340roar_vs_t * roar_vs_new_from_file(const char * server, const char * name, char * filename, int * error) {
341 roar_vs_t * vss = roar_vs_new(server, name, error);
342
343 if ( vss == NULL )
344  return NULL;
345
346 if ( roar_vs_file_simple(vss, filename, error) != 0 ) {
347  roar_vs_close(vss, ROAR_VS_TRUE, NULL);
348  return NULL;
349 }
350
351 return vss;
352}
353
354int roar_vs_buffer(roar_vs_t * vss, size_t buffer, int * error) {
355 _ckvss(-1);
356
357 if ( vss->flags & FLAG_BUFFERED )
358  return -1;
359
360 if ( roar_buffer_ring_new(&(vss->readring), buffer, 0) == -1 ) {
361  _seterrre();
362  return -1;
363 }
364
365 if ( roar_buffer_ring_new(&(vss->writering), buffer, 0) == -1 ) {
366  _seterrre();
367  roar_buffer_free(vss->readring);
368  vss->readring = NULL;
369  return -1;
370 }
371
372 vss->flags |= FLAG_BUFFERED;
373
374 return 0;
375}
376
377int roar_vs_close(roar_vs_t * vss, int killit, int * error) {
378 if ( killit != ROAR_VS_TRUE && killit != ROAR_VS_FALSE ) {
379  _seterr(ROAR_ERROR_INVAL);
380  return -1;
381 }
382
383 _ckvss(-1);
384
385 if ( vss->readbuffer != NULL )
386  roar_buffer_free(vss->readbuffer);
387 if ( vss->writebuffer != NULL )
388  roar_buffer_free(vss->writebuffer);
389
390 if ( vss->readring != NULL )
391  roar_buffer_free(vss->readring);
392 if ( vss->writering != NULL )
393  roar_buffer_free(vss->writering);
394
395 if ( vss->file != NULL && vss->flags & FLAG_CLOSEFILE )
396  roar_vio_close(vss->file);
397
398 if ( vss->flags & FLAG_STREAM ) {
399  if ( killit == ROAR_VS_TRUE ) {
400   roar_kick(vss->con, ROAR_OT_STREAM, roar_stream_get_id(&(vss->stream)));
401  }
402
403  roar_vio_close(&(vss->vio));
404 }
405
406 if ( vss->con == &(vss->con_store) ) {
407  roar_disconnect(vss->con);
408 }
409
410 roar_mm_free(vss);
411 return 0;
412}
413
414static ssize_t roar_vs_write_direct(roar_vs_t * vss, const void * buf, size_t len, int * error) {
415 ssize_t ret = roar_vio_write(&(vss->vio), (void*)buf, len);
416
417 if ( ret == -1 ) {
418#ifdef EAGAIN
419  if ( roar_error == ROAR_ERROR_AGAIN )
420   return 0;
421#endif
422
423  _seterrre();
424 } else {
425  if ( !(vss->flags & FLAG_BUFFERED) ) {
426   //printf("A: vss->writec=%zu, ret=%zi\n", vss->writec, ret);
427   vss->writec += ret;
428  }
429 }
430
431 //printf("B: vss->writec=%zu, ret=%zi\n", vss->writec, ret);
432 return ret;
433}
434
435ssize_t roar_vs_write(roar_vs_t * vss, const void * buf, size_t len, int * error) {
436 ssize_t ret;
437 size_t writelen;
438
439 _ckvss(-1);
440
441 if ( !(vss->flags & FLAG_STREAM) ) {
442  _seterr(ROAR_ERROR_INVAL);
443  return -1;
444 }
445
446 _initerr();
447
448 if ( vss->flags & FLAG_BUFFERED ) {
449  writelen = len;
450
451  if ( roar_buffer_ring_write(vss->writering, (void*)buf, &writelen) == -1 ) {
452   _seterrre();
453   return -1;
454  }
455
456  ret = writelen;
457  vss->writec += ret;
458 } else {
459  ret = roar_vs_write_direct(vss, buf, len, error);
460 }
461
462 return ret;
463}
464
465ssize_t roar_vs_read (roar_vs_t * vss,       void * buf, size_t len, int * error) {
466 ssize_t ret;
467
468 _ckvss(-1);
469
470 if ( !(vss->flags & FLAG_STREAM) ) {
471  _seterr(ROAR_ERROR_INVAL);
472  return -1;
473 }
474
475 _initerr();
476
477 ret = roar_vio_read(&(vss->vio), buf, len);
478
479 if ( ret == -1 ) {
480  _seterrre();
481 } else {
482  vss->readc += ret;
483 }
484
485 return ret;
486}
487
488int     roar_vs_sync (roar_vs_t * vss, int wait, int * error) {
489 struct roar_event waits, triggered;
490
491 _ckvss(-1);
492
493 if ( !(vss->flags & FLAG_STREAM) ) {
494  _seterr(ROAR_ERROR_INVAL);
495  return -1;
496 }
497
498 if ( wait != ROAR_VS_NOWAIT && wait != ROAR_VS_WAIT ) {
499  _seterr(ROAR_ERROR_INVAL);
500  return -1;
501 }
502
503 _initerr();
504
505 if ( roar_vio_sync(&(vss->vio)) == -1 ) {
506  _seterrre();
507  return -1;
508 }
509
510 if ( wait == ROAR_VS_WAIT ) {
511  memset(&waits, 0, sizeof(waits));
512  waits.event       = ROAR_OE_STREAM_XRUN;
513  waits.emitter     = -1;
514  waits.target      = roar_stream_get_id(&(vss->stream));
515  waits.target_type = ROAR_OT_STREAM;
516
517  if ( roar_wait(vss->con, &triggered, &waits, 1) == -1 ) {
518   _seterrre();
519   return -1;
520  }
521 }
522
523 return 0;
524}
525
526int     roar_vs_blocking (roar_vs_t * vss, int val, int * error) {
527 int old = -1;
528
529 _ckvss(-1);
530
531  if ( !(vss->flags & FLAG_STREAM) ) {
532  _seterr(ROAR_ERROR_INVAL);
533  return -1;
534 }
535
536 old = vss->flags & FLAG_NONBLOCK ? ROAR_VS_FALSE : ROAR_VS_TRUE;
537
538 _initerr();
539
540 switch (val) {
541  case ROAR_VS_TRUE:
542    if ( roar_vio_nonblock(&(vss->vio), ROAR_SOCKET_BLOCK) == -1 ) {
543     _seterrre();
544     return -1;
545    }
546    vss->flags |= FLAG_NONBLOCK;
547    vss->flags -= FLAG_NONBLOCK;
548    return old;
549   break;
550  case ROAR_VS_FALSE:
551    if ( roar_vio_nonblock(&(vss->vio), ROAR_SOCKET_NONBLOCK) == -1 ) {
552     _seterrre();
553     return -1;
554    }
555    vss->flags |= FLAG_NONBLOCK;
556    return old;
557   break;
558  case ROAR_VS_TOGGLE:
559    if ( old == ROAR_VS_TRUE ) {
560     return roar_vs_blocking(vss, ROAR_VS_FALSE, error);
561    } else {
562     return roar_vs_blocking(vss, ROAR_VS_TRUE, error);
563    }
564   break;
565  case ROAR_VS_ASK:
566    return old;
567   break;
568 }
569
570 _seterr(ROAR_ERROR_INVAL);
571 return -1;
572}
573
574static int _roar_vs_find_first_prim(roar_vs_t * vss) {
575 struct roar_stream stream;
576 struct roar_stream_info info;
577 int id[ROAR_STREAMS_MAX];
578 int num;
579 int i;
580
581 if ( vss->first_primid != -1 )
582  return vss->first_primid;
583
584 if ( vss->mixerid == -1 )
585  return -1;
586
587 if ( (num = roar_list_streams(vss->con, id, ROAR_STREAMS_MAX)) == -1 ) {
588  return -1;
589 }
590
591 for (i = 0; i < num; i++) {
592  if ( roar_get_stream(vss->con, &stream, id[i]) == -1 )
593   continue;
594
595  if ( stream.dir != ROAR_DIR_OUTPUT )
596   continue;
597
598  if ( roar_stream_get_info(vss->con, &stream, &info) == -1 )
599   continue;
600
601  if ( info.mixer == vss->mixerid ) {
602   vss->first_primid = id[i];
603   return id[i];
604  }
605 }
606
607 return -1;
608}
609
610ssize_t roar_vs_position(roar_vs_t * vss, int backend, int * error) {
611 struct roar_stream stream;
612 struct roar_stream      out_stream;
613 struct roar_stream_info out_info;
614 size_t offset = 0;
615
616 _ckvss(-1);
617
618 if ( !(vss->flags & FLAG_STREAM) ) {
619  _seterr(ROAR_ERROR_INVAL);
620  return -1;
621 }
622
623 _initerr();
624
625 if ( roar_get_stream(vss->con, &stream, roar_stream_get_id(&(vss->stream))) == -1 ) {
626  _seterrre();
627  return -1;
628 }
629
630 if ( backend == ROAR_VS_BACKEND_DEFAULT ) {
631  backend = ROAR_VS_BACKEND_FIRST;
632 }
633
634 switch (backend) {
635  case ROAR_VS_BACKEND_NONE:
636//    return stream.pos;
637    // do nothing.
638   break;
639  case ROAR_VS_BACKEND_FIRST:
640    if ( vss->first_primid == -1 ) {
641     _seterr(ROAR_ERROR_UNKNOWN);
642     return -1;
643    }
644
645    backend = vss->first_primid;
646   break;
647  default:
648    if ( backend < 0 ) {
649     _seterr(ROAR_ERROR_INVAL);
650     return -1;
651    }
652   break;
653 }
654
655
656 if ( backend >= 0 ) {
657  roar_stream_new_by_id(&out_stream, backend);
658
659  if ( roar_stream_get_info(vss->con, &out_stream, &out_info) == -1 ) {
660   _seterrre();
661   return -1;
662  }
663
664  offset  = out_info.delay * vss->info.rate;
665  offset /= 1000000;
666 }
667
668 if ( roar_clock_gettime(&(vss->latmes.last_time), LOCAL_CLOCK) == -1 ) {
669  vss->latmes.last_pos = -1;
670 } else {
671  vss->latmes.last_pos = stream.pos + offset;
672 }
673
674 return stream.pos + offset;
675}
676
677#ifdef _HAVE_SOCKOPT
678static void roar_vs_latency_managed(roar_vs_t * vss, roar_mus_t lat) {
679 struct roar_vio_sysio_sockopt sockopt;
680 float tmp = ((float)lat/1000.0) - vss->latc.target;
681 int val;
682
683 tmp *= vss->latc.p;
684
685 sockopt.level   = SOL_SOCKET;
686 sockopt.optname = SO_SNDBUF;
687 sockopt.optval  = &val;
688 sockopt.optlen  = sizeof(val);
689
690 roar_vio_ctl(&(vss->vio), ROAR_VIO_CTL_GET_SYSIO_SOCKOPT, &sockopt);
691
692 val /= 2;
693
694 tmp = 1.0 - tmp;
695
696 val = (float)val*tmp;
697
698 sockopt.optlen  = sizeof(val);
699
700 roar_vio_ctl(&(vss->vio), ROAR_VIO_CTL_SET_SYSIO_SOCKOPT, &sockopt);
701}
702#endif
703
704roar_mus_t roar_vs_latency(roar_vs_t * vss, int backend, int * error) {
705 ssize_t pos  = roar_vs_position(vss, backend, error);
706 ssize_t bps;  // byte per sample
707 size_t  lioc; // local IO (byte) counter
708 size_t  lpos; // local possition
709 signed long long int lag;
710
711// printf("pos=%zi\n", pos);
712
713 _initerr();
714
715 _ckvss(0);
716
717 if (pos == -1) {
718  _seterrre();
719  return 0;
720 }
721
722 if ( !(vss->flags & FLAG_STREAM) ) {
723  _seterr(ROAR_ERROR_INVAL);
724  return 0;
725 }
726
727 if ( vss->writec == 0 ) {
728  lioc = vss->readc;
729 } else {
730  //printf("writec=%zu\n", vss->writec);
731  lioc = vss->writec;
732 }
733
734 bps = roar_info2samplesize(&(vss->info));
735
736 if ( bps == -1 ) {
737  _seterrre();
738  return 0;
739 }
740
741 lpos = (lioc*8) / bps;
742
743 //printf("pos=%zi, lpos=%zi, bps=%zi, diff[lpos-pos]=%zi\n", pos, lpos, bps, (lpos - pos));
744
745 lag = (signed long long int)lpos - (signed long long int)pos;
746 lag /= vss->info.channels;
747
748 // we now have the lag in frames
749 // return value are mus
750 // so we need to multiply with 1s/mus and
751 // multiply by 1/rate
752
753 lag *= 1000000; // 1s/mus
754 lag /= vss->info.rate;
755
756 if ( lag == 0 ) {
757  _seterr(ROAR_ERROR_NONE);
758 }
759
760#ifdef _HAVE_SOCKOPT
761 if (vss->latc.target > vss->latc.minlag) {
762  roar_vs_latency_managed(vss, lag);
763 }
764#endif
765
766 return lag;
767}
768
769roar_mus_t roar_vs_latency2(roar_vs_t * vss, int backend, int wait, int * error) {
770 ssize_t bps;  // byte per sample
771 size_t  lioc; // local IO (byte) counter
772 size_t  lpos; // local possition
773 signed long long int lag;
774 struct roar_time rt;
775
776 _initerr();
777
778 _ckvss(0);
779
780 if ( !(vss->flags & FLAG_STREAM) ) {
781  _seterr(ROAR_ERROR_INVAL);
782  return 0;
783 }
784
785 if ( wait == ROAR_VS_WAIT ) {
786  return roar_vs_latency(vss, backend, error);
787 } else if ( wait == ROAR_VS_NOWAIT ) {
788  if ( vss->latmes.last_pos == -1 ) {
789   _seterr(ROAR_ERROR_NODATA);
790   return 0;
791  }
792
793  if ( vss->writec == 0 ) {
794   lioc = vss->readc;
795  } else {
796   //printf("writec=%zu\n", vss->writec);
797   lioc = vss->writec;
798  }
799
800  bps = roar_info2samplesize(&(vss->info));
801
802  if ( bps == -1 ) {
803   _seterrre();
804   return 0;
805  }
806
807  lpos = (lioc*8) / bps;
808
809  //printf("pos=%zi, lpos=%zi, bps=%zi, diff[lpos-pos]=%zi\n", pos, lpos, bps, (lpos - pos));
810
811  lag = (signed long long int)lpos - (signed long long int)vss->latmes.last_pos;
812  lag /= vss->info.channels;
813
814  // we now have the lag in frames
815  // return value are mus
816  // so we need to multiply with 1s/mus and
817  // multiply by 1/rate
818
819  lag *= 1000000; // 1s/mus
820  lag /= vss->info.rate;
821
822  _initerr();
823  if ( roar_clock_gettime(&rt, LOCAL_CLOCK) == -1 ) {
824   _seterrre();
825   return 0;
826  }
827
828//  printf("%lli, %lli\n", (rt.t_sec  - vss->latmes.last_time.t_sec ), (rt.t_ssec/2 - vss->latmes.last_time.t_ssec/2)/ 18446744073710LL);
829//  printf("%lli, %llu\n", rt.t_sec, rt.t_ssec);
830  lag -= (rt.t_sec  - vss->latmes.last_time.t_sec ) * 1000000LL;
831  lag -= ((int64_t)(rt.t_ssec/2) - (int64_t)(vss->latmes.last_time.t_ssec/2)) / 9223372036855LL;
832
833  if ( lag == 0 ) {
834   _seterr(ROAR_ERROR_NONE);
835  }
836
837  return lag;
838 }
839
840 _seterr(ROAR_ERROR_INVAL);
841 return 0;
842}
843
844static int roar_vs_flag(roar_vs_t * vss, int flag, int val, int * error) {
845 struct roar_stream_info info;
846 int old = -1;
847
848 _ckvss(-1);
849
850 if ( !(vss->flags & FLAG_STREAM) ) {
851  _seterr(ROAR_ERROR_INVAL);
852  return -1;
853 }
854
855 if ( val != ROAR_VS_ASK )
856  old = roar_vs_flag(vss, flag, ROAR_VS_ASK, error);
857
858 _initerr();
859
860 switch (val) {
861  case ROAR_VS_TRUE:
862  case ROAR_VS_FALSE:
863    if ( roar_stream_set_flags2(vss->con, &(vss->stream), flag,
864                                val == ROAR_VS_TRUE ? ROAR_SET_FLAG : ROAR_RESET_FLAG) == -1 ) {
865     _seterrre();
866     return -1;
867    }
868    return old;
869   break;
870  case ROAR_VS_TOGGLE:
871    return roar_vs_flag(vss, flag, old == ROAR_VS_TRUE ? ROAR_VS_FALSE : ROAR_VS_TRUE, error);
872   break;
873  case ROAR_VS_ASK:
874    if ( roar_stream_get_info(vss->con, &(vss->stream), &info) == -1 ) {
875     _seterrre();
876     return -1;
877    }
878    return info.flags & flag ? ROAR_VS_TRUE : ROAR_VS_FALSE;
879   break;
880 }
881
882 _seterr(ROAR_ERROR_INVAL);
883 return -1;
884}
885
886int     roar_vs_pause(roar_vs_t * vss, int val, int * error) {
887 return roar_vs_flag(vss, ROAR_FLAG_PAUSE, val, error);
888}
889
890int     roar_vs_mute (roar_vs_t * vss, int val, int * error) {
891 return roar_vs_flag(vss, ROAR_FLAG_MUTE, val, error);
892}
893
894static int roar_vs_volume (roar_vs_t * vss, float * c, size_t channels, int * error) {
895 struct roar_mixer_settings mixer;
896 size_t i;
897 register float s, max_s = -100.0, scale = 65535.0;
898 int oldchannels;
899 int mode = ROAR_SET_VOL_ALL;
900
901 _ckvss(-1);
902
903 if ( !(vss->flags & FLAG_STREAM) ) {
904  _seterr(ROAR_ERROR_INVAL);
905  return -1;
906 }
907
908 if ( channels > ROAR_MAX_CHANNELS ) {
909  _seterr(ROAR_ERROR_INVAL);
910  return -1;
911 }
912
913 _initerr();
914
915 if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &oldchannels) == -1 ) {
916  _seterrre();
917  return -1;
918 }
919
920 if ( vss->flags & FLAG_FREE_VOL ) {
921  for (i = 0; i < channels; i++) {
922   if ( c[i] > max_s ) {
923    max_s = c[i];
924   } else if ( c[i] < -0.01 ) {
925    _seterr(ROAR_ERROR_RANGE);
926    return -1;
927   }
928  }
929
930  if ( max_s > 1.00 ) {
931   scale = 65535.0 / max_s;
932  }
933 }
934
935 for (i = 0; i < channels; i++) {
936  if ( vss->flags & FLAG_FREE_VOL ) {
937   s = c[i] * scale;
938   if ( s < 0.0 )
939    s = 0.0;
940  } else {
941   s = c[i] * 65535.0;
942   if ( s > 66190.0 || s < -655.0 ) {
943    _seterr(ROAR_ERROR_RANGE);
944    return -1;
945   } else if ( s > 65535.0 ) {
946    s = 65535.0;
947   } else if ( s <     0.0 ) {
948    s = 0.0;
949   }
950  }
951  mixer.mixer[i] = s;
952 }
953
954 if ( vss->flags & FLAG_FREE_VOL ) {
955  mixer.scale = scale;
956 } else {
957  mixer.scale = 65535;
958 }
959
960 if ( channels != oldchannels )
961  mode = ROAR_SET_VOL_UNMAPPED;
962
963 if ( roar_set_vol2(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, channels, mode) == 0 )
964  return 0;
965
966 if ( mode == ROAR_SET_VOL_ALL ) {
967  _seterrre();
968  return -1;
969 }
970
971 if ( roar_conv_volume(&mixer, &mixer, oldchannels, channels) == -1 ) {
972  _seterrre();
973  return -1;
974 }
975
976 channels = oldchannels;
977 mode     = ROAR_SET_VOL_ALL;
978
979 if ( roar_set_vol2(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, channels, mode) == -1 ) {
980  _seterrre();
981  return -1;
982 }
983
984 return 0;
985}
986
987int     roar_vs_volume_mono   (roar_vs_t * vss, float c, int * error) {
988 return roar_vs_volume(vss, &c, 1, error);
989}
990
991int     roar_vs_volume_stereo (roar_vs_t * vss, float l, float r, int * error) {
992 float c[2] = {l, r};
993 return roar_vs_volume(vss, c, 2, error);
994}
995
996int     roar_vs_volume_get    (roar_vs_t * vss, float * l, float * r, int * error) {
997 struct roar_mixer_settings mixer;
998 int channels;
999
1000 if ( vss == NULL || l == NULL || r == NULL ) {
1001  _seterr(ROAR_ERROR_INVAL);
1002  return -1;
1003 }
1004
1005 if ( !(vss->flags & FLAG_STREAM) ) {
1006  _seterr(ROAR_ERROR_INVAL);
1007  return -1;
1008 }
1009
1010 _initerr();
1011
1012 if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &channels) == -1 ) {
1013  _seterrre();
1014  return -1;
1015 }
1016
1017 if ( channels == 1 )
1018  mixer.mixer[1] = mixer.mixer[0];
1019
1020 *l = mixer.mixer[0] / (float)mixer.scale;
1021 *r = mixer.mixer[1] / (float)mixer.scale;
1022
1023 return 0;
1024}
1025
1026int     roar_vs_meta          (roar_vs_t * vss, struct roar_keyval * kv, size_t len, int * error) {
1027 struct roar_meta meta;
1028 size_t i;
1029 int type;
1030 int ret = 0;
1031
1032 _ckvss(-1);
1033
1034 if ( !(vss->flags & FLAG_STREAM) ) {
1035  _seterr(ROAR_ERROR_INVAL);
1036  return -1;
1037 }
1038
1039 meta.type   = ROAR_META_TYPE_NONE;
1040 meta.key[0] = 0;
1041 meta.value  = NULL;
1042
1043 _initerr();
1044
1045 if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_CLEAR, &meta) == -1 ) {
1046  _seterrre();
1047  ret = -1;
1048 }
1049
1050 for (i = 0; i < len; i++) {
1051  type = roar_meta_inttype(kv[i].key);
1052  meta.type  = type;
1053  meta.value = kv[i].value;
1054
1055  if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_ADD, &meta) == -1 ) {
1056   _seterrre();
1057   ret = -1;
1058  }
1059 }
1060
1061 meta.type   = ROAR_META_TYPE_NONE;
1062 meta.key[0] = 0;
1063 meta.value  = NULL;
1064 if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_FINALIZE, &meta) == -1 ) {
1065  _seterrre();
1066  ret = -1;
1067 }
1068
1069 return ret;
1070}
1071
1072int     roar_vs_role          (roar_vs_t * vss, int role, int * error) {
1073 _ckvss(-1);
1074
1075 if ( !(vss->flags & FLAG_STREAM) ) {
1076  _seterr(ROAR_ERROR_INVAL);
1077  return -1;
1078 }
1079
1080 _initerr();
1081
1082 if ( roar_stream_set_role(vss->con, &(vss->stream), role) == -1 ) {
1083  _seterrre();
1084  return -1;
1085 }
1086
1087 return 0;
1088}
1089
1090
1091int     roar_vs_iterate       (roar_vs_t * vss, int wait, int * error) {
1092 struct roar_vio_select vios[3];
1093 struct roar_vio_selecttv rtv = {.sec = 0, .nsec = 1};
1094 size_t len = 0;
1095 ssize_t i;
1096 ssize_t ret;
1097 int can_read = 0, can_write = 0;
1098 int can_flush_stream = 0, can_flush_file = 0;
1099 int is_eof = 0;
1100 void * data;
1101 size_t tmp;
1102
1103 // TODO: fix error handling below.
1104
1105 _ckvss(-1);
1106
1107 if ( wait != ROAR_VS_WAIT && wait != ROAR_VS_NOWAIT ) {
1108  _seterr(ROAR_ERROR_INVAL);
1109  return -1;
1110 }
1111
1112 ROAR_VIO_SELECT_SETVIO(&(vios[len]), &(vss->vio), ((vss->flags & FLAG_DIR_IN  ? ROAR_VIO_SELECT_READ  : 0) |
1113                                                    (vss->flags & FLAG_DIR_OUT ? ROAR_VIO_SELECT_WRITE : 0)));
1114 vios[len].ud.vp = &(vss->vio);
1115 len++;
1116
1117 ROAR_VIO_SELECT_SETVIO(&(vios[len]), roar_get_connection_vio2(vss->con), ROAR_VIO_SELECT_READ);
1118 vios[len].ud.vp = vss->con;
1119 len++;
1120
1121
1122// TODO: FIXME: need to do two select()s so we can sleep more efficently and test for both directions.
1123// for the moment we disable file direction and hope it will not block anyway...
1124/*
1125 if ( vss->file != NULL ) {
1126  ROAR_VIO_SELECT_SETVIO(&(vios[len]), vss->file, ((vss->flags & FLAG_DIR_IN  ? ROAR_VIO_SELECT_WRITE : 0) |
1127                                                   (vss->flags & FLAG_DIR_OUT ? ROAR_VIO_SELECT_READ  : 0)));
1128  vios[len].ud.vp = vss->file;
1129  len++;
1130 }
1131*/
1132
1133 ret = roar_vio_select(vios, len, (wait == ROAR_VS_NOWAIT ? &rtv : NULL), NULL);
1134
1135// part 2 of above hack:
1136// emulate read handle.
1137  if ( vss->file != NULL ) {
1138   vios[len].ud.vp   = vss->file;
1139   vios[len].eventsa = ROAR_VIO_SELECT_WRITE|ROAR_VIO_SELECT_READ;
1140   len++;
1141  }
1142
1143 // no error here nor EOF.
1144 if ( ret == 0 )
1145  return 1;
1146
1147 for (i = 0; i < len; i++) {
1148  if ( !vios[i].eventsa )
1149   continue;
1150
1151  if ( vios[i].ud.vp == &(vss->vio) ) {
1152   if ( vios[i].eventsa & ROAR_VIO_SELECT_READ )
1153    can_read++;
1154
1155   if ( vios[i].eventsa & ROAR_VIO_SELECT_WRITE ) {
1156    can_write++;
1157    can_flush_stream = 1;
1158   }
1159  } else if ( vios[i].ud.vp == vss->con ) {
1160   roar_sync(vss->con);
1161  } else if ( vss->file != NULL && vios[i].ud.vp == vss->file ) {
1162   if ( vios[i].eventsa & ROAR_VIO_SELECT_READ )
1163    can_write++;
1164
1165   if ( vios[i].eventsa & ROAR_VIO_SELECT_WRITE ) {
1166    can_read++;
1167    can_flush_file = 1;
1168   }
1169  }
1170 }
1171
1172 if ( vss->flags & FLAG_BUFFERED ) {
1173  if ( roar_buffer_ring_avail(vss->readring, NULL, &tmp) != -1 )
1174   if ( tmp > 0 )
1175    can_read++;
1176
1177// no check here to just let the read return zero and we do EOF handling.
1178/*
1179  if ( roar_buffer_ring_avail(vss->writering, &tmp, NULL) != -1 )
1180   if ( tmp > 0 )
1181*/
1182    can_write++;
1183 }
1184
1185 ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p): can_read=%i, can_write=%i", vss, wait, error, can_read, can_write);
1186
1187 // TODO: FIXME: Need to correct error handling here!
1188
1189 if ( can_flush_stream && vss->writebuffer != NULL ) {
1190  if ( roar_buffer_get_data(vss->writebuffer, &data) == -1 )
1191   return -1;
1192
1193  if ( roar_buffer_get_len(vss->writebuffer, &len) == -1 )
1194   return -1;
1195
1196  ret = roar_vs_write_direct(vss, data, len, error);
1197
1198  if ( ret == -1 ) {
1199   return -1;
1200  } else if ( ret == len ) {
1201   roar_buffer_free(vss->writebuffer);
1202   vss->writebuffer = NULL;
1203  } else {
1204   if ( roar_buffer_set_offset(vss->writebuffer, ret) == -1 )
1205    return -1;
1206  }
1207 }
1208
1209 if ( can_flush_file && vss->readbuffer != NULL ) {
1210  if ( roar_buffer_get_data(vss->readbuffer, &data) == -1 )
1211   return -1;
1212
1213  if ( roar_buffer_get_len(vss->readbuffer, &len) == -1 )
1214   return -1;
1215
1216  ret = roar_vio_write(vss->file, data, len);
1217
1218  if ( ret == -1 ) {
1219   return -1;
1220  } else if ( ret == len ) {
1221   roar_buffer_free(vss->readbuffer);
1222   vss->readbuffer = NULL;
1223  } else {
1224   if ( roar_buffer_set_offset(vss->readbuffer, ret) == -1 )
1225    return -1;
1226  }
1227 }
1228
1229#define _READ_SIZE 1024
1230
1231 if ( can_read == 2 && vss->readbuffer == NULL ) {
1232  if ( roar_buffer_new_data(&(vss->readbuffer), (len = _READ_SIZE), &data) == -1 )
1233   return -1;
1234
1235  ret = roar_vs_read(vss, data, len, error);
1236
1237  if ( ret == -1 ) {
1238   roar_buffer_free(vss->readbuffer);
1239   vss->readbuffer = NULL;
1240   return -1;
1241  } else if ( ret == 0 ) {
1242   is_eof = 1;
1243   roar_buffer_free(vss->readbuffer);
1244   vss->readbuffer = NULL;
1245  } else {
1246   len = ret;
1247   if ( roar_buffer_set_len(vss->readbuffer, len) == -1 )
1248    return -1;
1249
1250   if ( vss->flags & FLAG_BUFFERED ) {
1251    tmp = len;
1252    if ( roar_buffer_ring_write(vss->readring, data, &tmp) == -1 ) {
1253     ret = -1;
1254    } else {
1255     ret = tmp;
1256    }
1257   } else {
1258    ret = roar_vio_write(vss->file, data, len);
1259   }
1260
1261   if ( ret == -1 ) {
1262    return -1;
1263   } else if ( ret == len ) {
1264    roar_buffer_free(vss->readbuffer);
1265    vss->readbuffer = NULL;
1266   } else {
1267    if ( roar_buffer_set_offset(vss->readbuffer, ret) == -1 )
1268     return -1;
1269   }
1270  }
1271 }
1272
1273 if ( can_write == 2 && vss->writebuffer == NULL ) {
1274  if ( roar_buffer_new_data(&(vss->writebuffer), (len = _READ_SIZE), &data) == -1 )
1275   return -1;
1276
1277  if ( vss->flags & FLAG_BUFFERED ) {
1278   tmp = len;
1279   if ( roar_buffer_ring_read(vss->writering, data, &tmp) == -1 ) {
1280    ret = -1;
1281   } else {
1282    ret = tmp;
1283   }
1284  } else {
1285   ret = roar_vio_read(vss->file, data, len);
1286  }
1287
1288  ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p): ret=%lli", vss, wait, error, (long long int)ret);
1289
1290  if ( ret == -1 ) {
1291   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1292
1293   roar_buffer_free(vss->writebuffer);
1294   vss->writebuffer = NULL;
1295   return -1;
1296  } else if ( ret == 0 ) {
1297   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1298
1299   is_eof = 1;
1300   roar_buffer_free(vss->writebuffer);
1301   vss->writebuffer = NULL;
1302  } else {
1303   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1304
1305   if ( len != ret ) {
1306    len = ret;
1307    if ( roar_buffer_set_len(vss->writebuffer, len) == -1 )
1308     return -1;
1309   }
1310
1311   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1312
1313   ret = roar_vs_write_direct(vss, data, len, error);
1314
1315   if ( ret == -1 ) {
1316    return -1;
1317   } else if ( ret == len ) {
1318    roar_buffer_free(vss->writebuffer);
1319    vss->writebuffer = NULL;
1320   } else {
1321    if ( roar_buffer_set_offset(vss->writebuffer, ret) == -1 )
1322     return -1;
1323   }
1324  }
1325 }
1326
1327 return is_eof ? 0 : 2;
1328}
1329
1330int     roar_vs_run           (roar_vs_t * vss, int * error) {
1331 int ret;
1332
1333 _ckvss(-1);
1334
1335 while ((ret = roar_vs_iterate(vss, ROAR_VS_WAIT, error)) > 0);
1336
1337 ROAR_DBG("roar_vs_run(vss=%p, error=%p): ret=%i", vss, error, ret);
1338
1339 if ( ret == 0 ) {
1340  // flush buffers:
1341  roar_vs_iterate(vss, ROAR_VS_WAIT, error);
1342 }
1343
1344 if ( roar_vs_sync(vss, ROAR_VS_WAIT, error) == -1 )
1345  return -1;
1346
1347 return ret;
1348}
1349
1350ssize_t roar_vs_get_avail_read(roar_vs_t * vss, int * error) {
1351 size_t len;
1352
1353 _ckvss(-1);
1354
1355 if ( !(vss->flags & FLAG_BUFFERED) ) {
1356  _seterr(ROAR_ERROR_INVAL);
1357  return -1;
1358 }
1359
1360 if ( roar_buffer_ring_avail(vss->readring, &len, NULL) == -1 ) {
1361  _seterrre();
1362  return -1;
1363 }
1364
1365 return len;
1366}
1367
1368ssize_t roar_vs_get_avail_write(roar_vs_t * vss, int * error) {
1369 size_t len;
1370
1371 _ckvss(-1);
1372
1373 if ( !(vss->flags & FLAG_BUFFERED) ) {
1374  _seterr(ROAR_ERROR_INVAL);
1375  return -1;
1376 }
1377
1378 if ( roar_buffer_ring_avail(vss->writering, NULL, &len) == -1 ) {
1379  _seterrre();
1380  return -1;
1381 }
1382
1383 return len;
1384}
1385
1386int     roar_vs_reset_buffer(roar_vs_t * vss, int writering, int readring, int * error) {
1387 _ckvss(-1);
1388
1389 if ( !(vss->flags & FLAG_BUFFERED) ) {
1390  _seterr(ROAR_ERROR_INVAL);
1391  return -1;
1392 }
1393
1394 if ( writering != ROAR_VS_TRUE || writering != ROAR_VS_FALSE ||
1395      readring  != ROAR_VS_TRUE || readring  != ROAR_VS_FALSE ) {
1396  _seterr(ROAR_ERROR_INVAL);
1397  return -1;
1398 }
1399
1400 if ( writering ) {
1401  if ( roar_buffer_ring_reset(vss->writering) == -1 ) {
1402   _seterrre();
1403   return -1;
1404  }
1405 }
1406
1407 if ( readring ) {
1408  if ( roar_buffer_ring_reset(vss->readring) == -1 ) {
1409   _seterrre();
1410   return -1;
1411  }
1412 }
1413
1414 return 0;
1415}
1416
1417int     roar_vs_ctl           (roar_vs_t * vss, roar_vs_ctlcmd cmd, void * argp, int * error) {
1418 _ckvss(-1);
1419
1420 switch (cmd) {
1421  case ROAR_VS_CMD_NOOP:
1422   break;
1423  case ROAR_VS_CMD_SET_MIXER:
1424    vss->mixerid = *(int*)argp;
1425   break;
1426  case ROAR_VS_CMD_GET_MIXER:
1427    *(int*)argp = vss->mixerid;
1428   break;
1429  case ROAR_VS_CMD_SET_FIRST_PRIM:
1430    vss->first_primid = *(int*)argp;
1431   break;
1432  case ROAR_VS_CMD_GET_FIRST_PRIM:
1433    *(int*)argp = vss->first_primid;
1434   break;
1435#ifdef _HAVE_SOCKOPT
1436  case ROAR_VS_CMD_SET_LATC_P:
1437    vss->latc.p = *(float*)argp;
1438   break;
1439  case ROAR_VS_CMD_GET_LATC_P:
1440    *(float*)argp = vss->latc.p;
1441   break;
1442  case ROAR_VS_CMD_SET_LATC_TARGET:
1443    vss->latc.target = *(float*)argp;
1444   break;
1445  case ROAR_VS_CMD_GET_LATC_TARGET:
1446    *(float*)argp = vss->latc.target;
1447   break;
1448  case ROAR_VS_CMD_SET_LATC_WINDOW:
1449    vss->latc.window = *(float*)argp;
1450   break;
1451  case ROAR_VS_CMD_GET_LATC_WINDOW:
1452    *(float*)argp = vss->latc.window;
1453   break;
1454  case ROAR_VS_CMD_SET_LATC_MINLAG:
1455    vss->latc.minlag = *(float*)argp;
1456   break;
1457  case ROAR_VS_CMD_GET_LATC_MINLAG:
1458    *(float*)argp = vss->latc.minlag;
1459   break;
1460#endif
1461  case ROAR_VS_CMD_SET_FREE_VOLUME:
1462    switch (*(int*)argp) {
1463     case ROAR_VS_TRUE:
1464       vss->flags |= FLAG_FREE_VOL;
1465      break;
1466     case ROAR_VS_FALSE:
1467       vss->flags |= FLAG_FREE_VOL;
1468       vss->flags -= FLAG_FREE_VOL;
1469      break;
1470     case ROAR_VS_TOGGLE:
1471       if ( vss->flags & FLAG_FREE_VOL ) {
1472        vss->flags -= FLAG_FREE_VOL;
1473       } else {
1474        vss->flags |= FLAG_FREE_VOL;
1475       }
1476      break;
1477     default:
1478       _seterr(ROAR_ERROR_INVAL);
1479       return -1;
1480      break;
1481    }
1482   break;
1483  case ROAR_VS_CMD_GET_FREE_VOLUME:
1484    *(int*)argp = vss->flags & FLAG_FREE_VOL ? ROAR_VS_TRUE : ROAR_VS_FALSE;
1485   break;
1486  case ROAR_VS_CMD_SET_DEFAULT_PAUSED:
1487    switch (*(int*)argp) {
1488     case ROAR_VS_TRUE:
1489       vss->flags |= FLAG_DEF_PAUSE;
1490      break;
1491     case ROAR_VS_FALSE:
1492       vss->flags |= FLAG_DEF_PAUSE;
1493       vss->flags -= FLAG_DEF_PAUSE;
1494      break;
1495     case ROAR_VS_TOGGLE:
1496       if ( vss->flags & FLAG_DEF_PAUSE ) {
1497        vss->flags -= FLAG_DEF_PAUSE;
1498       } else {
1499        vss->flags |= FLAG_DEF_PAUSE;
1500       }
1501      break;
1502     default:
1503       _seterr(ROAR_ERROR_INVAL);
1504       return -1;
1505      break;
1506    }
1507   break;
1508  case ROAR_VS_CMD_GET_DEFAULT_PAUSED:
1509    *(int*)argp = vss->flags & FLAG_DEF_PAUSE ? ROAR_VS_TRUE : ROAR_VS_FALSE;
1510   break;
1511// use ifndef here so warnings of unhandled enum values will be shown in DEBUG mode.
1512#ifndef DEBUG
1513  default:
1514    _seterr(ROAR_ERROR_INVAL);
1515    return -1;
1516   break;
1517#endif
1518 }
1519
1520 return 0;
1521}
1522
1523struct roar_connection * roar_vs_connection_obj(roar_vs_t * vss, int * error) {
1524 _ckvss(NULL);
1525
1526 return vss->con;
1527}
1528
1529struct roar_stream     * roar_vs_stream_obj    (roar_vs_t * vss, int * error) {
1530 _ckvss(NULL);
1531
1532 if ( !(vss->flags & FLAG_STREAM) ) {
1533  _seterr(ROAR_ERROR_INVAL);
1534  return NULL;
1535 }
1536
1537 return &(vss->stream);
1538}
1539
1540struct roar_vio_calls  * roar_vs_vio_obj       (roar_vs_t * vss, int * error) {
1541 _ckvss(NULL);
1542
1543 if ( !(vss->flags & FLAG_STREAM) ) {
1544  _seterr(ROAR_ERROR_INVAL);
1545  return NULL;
1546 }
1547
1548 return &(vss->vio);
1549}
1550
1551//ll
Note: See TracBrowser for help on using the repository browser.