source: roaraudio/libroar/vs.c @ 5069:d7bf200c3aae

Last change on this file since 5069:d7bf200c3aae was 5069:d7bf200c3aae, checked in by phi, 13 years ago

seperate last pos and offset for later ASYNC latency updates

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