source: roaraudio/libroar/vs.c @ 5072:c9c5efeb17e7

Last change on this file since 5072:c9c5efeb17e7 was 5071:a550bcffdb13, checked in by phi, 13 years ago

added a function to handle async stuff, still need to integerate it with roar_vs_iterate()

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