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

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

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

File size: 33.9 KB
RevLine 
[4173]1//vs.c:
2
3/*
[4708]4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2011
[4173]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
[4719]38#if defined(ROAR_HAVE_GETSOCKOPT) && defined(ROAR_HAVE_SETSOCKOPT)
39#define _HAVE_SOCKOPT
40#endif
41
[5068]42#define LOCAL_CLOCK    ROAR_CLOCK_DEFAULT
43
[4580]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
[4850]49#define FLAG_FREE_VOL  0x0010
[5025]50#define FLAG_DEF_PAUSE 0x0020
[4580]51#define FLAG_DIR_IN    0x1000
52#define FLAG_DIR_OUT   0x2000
[4174]53
[4873]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)
[4260]58#define _ckvss(ret) do { if ( vss == NULL ) { _seterr(ROAR_ERROR_INVAL); return (ret); } } while(0)
[4174]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;
[4206]66 struct roar_audio_info   info;
67 size_t                   readc, writec;
68 int                      mixerid;
69 int                      first_primid;
[4580]70 struct roar_buffer     * readbuffer, * writebuffer;
71 struct roar_vio_calls    file_store;
72 struct roar_vio_calls  * file;
[4626]73 struct roar_buffer     * readring, * writering;
[4719]74#ifdef _HAVE_SOCKOPT
75 struct {
76  float target;
77  float window;
78  float minlag;
79  float p;
80 } latc;
81#endif
[5068]82 struct {
83  ssize_t last_pos;
84  struct roar_time last_time;
85 } latmes;
[4174]86};
87
[4206]88static int _roar_vs_find_first_prim(roar_vs_t * vss);
89
[4174]90const char * roar_vs_strerr(int error) {
[4793]91 const char * ret = roar_error2str(error);
[4174]92
[4793]93 if ( ret == NULL )
94  return "(unknown)";
[4174]95
[4793]96 return ret;
[4174]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 ) {
[4186]103  _seterrse();
[4174]104  return NULL;
105 }
106
107 memset(vss, 0, sizeof(roar_vs_t));
108
[4206]109 vss->mixerid      = -1;
110 vss->first_primid = -1;
111
[4719]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
[5068]119 vss->latmes.last_pos = -1;
120
[4174]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
[4186]144 _initerr();
145
[4174]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);
[4186]150  _seterrre();
[4174]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) {
[4206]158 struct roar_stream_info sinfo;
[4174]159 int ret;
160
[4260]161 _ckvss(-1);
162
[4174]163 if ( vss->flags & FLAG_STREAM ) {
164  _seterr(ROAR_ERROR_INVAL);
165  return -1;
166 }
167
[5025]168 if ( dir == ROAR_DIR_FILTER )
169  vss->flags |= FLAG_DEF_PAUSE;
170
[4186]171 _initerr();
172
[4206]173 if ( info != &(vss->info) )
174  memcpy(&(vss->info), info, sizeof(struct roar_audio_info));
175
[4174]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 ) {
[4186]182  _seterrre();
[4174]183  return -1;
184 }
185
[4206]186 if ( roar_stream_get_info(vss->con, &(vss->stream), &sinfo) != -1 ) {
[4622]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
[4206]196  vss->mixerid = sinfo.mixer;
197  _roar_vs_find_first_prim(vss);
198 }
199
[4174]200 vss->flags |= FLAG_STREAM;
201
[4580]202 switch (dir) {
203  case ROAR_DIR_PLAY: vss->flags |= FLAG_DIR_OUT; break;
204 }
205
[4174]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
[4206]216 memset(&(vss->info), 0, sizeof(vss->info));
[4174]217
[4206]218 vss->info.rate     = rate;
219 vss->info.channels = channels;
220 vss->info.codec    = codec;
221 vss->info.bits     = bits;
[4174]222
[4206]223 ret = roar_vs_stream(vss, &(vss->info), dir, error);
[4174]224
225 if (ret == -1) {
226  roar_vs_close(vss, ROAR_VS_TRUE, NULL);
227  return NULL;
228 }
229
230 return vss;
231}
232
[4580]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;
[4584]259 int codec = -1;
260 const char * content_type;
[4580]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;
[4616]274   default:
275     _seterr(ROAR_ERROR_INVAL);
276     return -1;
[4580]277  }
278 }
279
280 file = &(vss->file_store);
281
[4618]282 _initerr();
[4580]283
[4618]284 if ( roar_vio_dstr_init_defaults(&def, ROAR_VIO_DEF_TYPE_NONE, dir, 0644) == -1 ) {
285  _seterrre();
286  return -1;
287 }
[4580]288
289 if ( roar_vio_open_dstr(file, filename, &def, 1) == -1 ) {
[4618]290  _seterrre();
[4580]291  return -1;
292 }
293
294 if ( !(vss->flags & FLAG_STREAM) ) {
[4584]295  if ( roar_vio_ctl(file, ROAR_VIO_CTL_GET_MIMETYPE, &content_type) != -1 ) {
296   codec = roar_mime2codec(content_type);
297  }
[4580]298
[4584]299  if ( codec == -1 ) {
300   ret = roar_vio_read(file, buf, sizeof(buf));
301
302   codec = roar_file_codecdetect(buf, ret);
[4580]303
[4584]304   if ( codec == -1 ) {
305    roar_vio_close(file);
[4618]306    _seterr(ROAR_ERROR_INVAL); // Other value?
[4584]307    return -1;
308   }
309
310   if ( roar_vio_lseek(file, 0, SEEK_SET) != 0 ) {
311    roar_vio_close(file);
[4618]312   _seterrre();
[4584]313    return -1;
314   }
[4580]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
[4626]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
[4174]377int roar_vs_close(roar_vs_t * vss, int killit, int * error) {
[4178]378 if ( killit != ROAR_VS_TRUE && killit != ROAR_VS_FALSE ) {
[4618]379  _seterr(ROAR_ERROR_INVAL);
[4178]380  return -1;
381 }
382
[4260]383 _ckvss(-1);
384
[4580]385 if ( vss->readbuffer != NULL )
386  roar_buffer_free(vss->readbuffer);
387 if ( vss->writebuffer != NULL )
388  roar_buffer_free(vss->writebuffer);
389
[4626]390 if ( vss->readring != NULL )
391  roar_buffer_free(vss->readring);
392 if ( vss->writering != NULL )
393  roar_buffer_free(vss->writering);
394
[4580]395 if ( vss->file != NULL && vss->flags & FLAG_CLOSEFILE )
396  roar_vio_close(vss->file);
397
[4174]398 if ( vss->flags & FLAG_STREAM ) {
[4178]399  if ( killit == ROAR_VS_TRUE ) {
[4174]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
[4626]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);
[4174]416
417 if ( ret == -1 ) {
[4199]418#ifdef EAGAIN
[4873]419  if ( roar_error == ROAR_ERROR_AGAIN )
[4199]420   return 0;
421#endif
422
[4186]423  _seterrre();
[4206]424 } else {
[4717]425  if ( !(vss->flags & FLAG_BUFFERED) ) {
426   //printf("A: vss->writec=%zu, ret=%zi\n", vss->writec, ret);
[4636]427   vss->writec += ret;
[4717]428  }
[4174]429 }
430
[4717]431 //printf("B: vss->writec=%zu, ret=%zi\n", vss->writec, ret);
[4174]432 return ret;
433}
434
[4626]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
[4174]465ssize_t roar_vs_read (roar_vs_t * vss,       void * buf, size_t len, int * error) {
466 ssize_t ret;
467
[4260]468 _ckvss(-1);
469
[4174]470 if ( !(vss->flags & FLAG_STREAM) ) {
471  _seterr(ROAR_ERROR_INVAL);
472  return -1;
473 }
474
[4186]475 _initerr();
476
[4174]477 ret = roar_vio_read(&(vss->vio), buf, len);
478
479 if ( ret == -1 ) {
[4186]480  _seterrre();
[4206]481 } else {
482  vss->readc += ret;
[4174]483 }
484
485 return ret;
486}
487
[4175]488int     roar_vs_sync (roar_vs_t * vss, int wait, int * error) {
[4579]489 struct roar_event waits, triggered;
490
[4260]491 _ckvss(-1);
492
[4175]493 if ( !(vss->flags & FLAG_STREAM) ) {
494  _seterr(ROAR_ERROR_INVAL);
495  return -1;
496 }
497
[4579]498 if ( wait != ROAR_VS_NOWAIT && wait != ROAR_VS_WAIT ) {
[4175]499  _seterr(ROAR_ERROR_INVAL);
500  return -1;
501 }
502
[4186]503 _initerr();
504
505 if ( roar_vio_sync(&(vss->vio)) == -1 ) {
506  _seterrre();
507  return -1;
508 }
[4175]509
[4579]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
[4175]523 return 0;
524}
525
526int     roar_vs_blocking (roar_vs_t * vss, int val, int * error) {
527 int old = -1;
528
[4260]529 _ckvss(-1);
530
[4175]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
[4186]538 _initerr();
539
[4175]540 switch (val) {
541  case ROAR_VS_TRUE:
542    if ( roar_vio_nonblock(&(vss->vio), ROAR_SOCKET_BLOCK) == -1 ) {
[4186]543     _seterrre();
[4175]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 ) {
[4186]552     _seterrre();
[4175]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
[4206]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;
[4637]614 size_t offset = 0;
[4206]615
[4260]616 _ckvss(-1);
617
[4206]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
[4638]630 if ( backend == ROAR_VS_BACKEND_DEFAULT ) {
631  backend = ROAR_VS_BACKEND_FIRST;
632 }
633
[4206]634 switch (backend) {
635  case ROAR_VS_BACKEND_NONE:
[5068]636//    return stream.pos;
637    // do nothing.
[4206]638   break;
639  case ROAR_VS_BACKEND_FIRST:
640    if ( vss->first_primid == -1 ) {
641     _seterr(ROAR_ERROR_UNKNOWN);
642     return -1;
643    }
644
[4637]645    backend = vss->first_primid;
646   break;
647  default:
648    if ( backend < 0 ) {
649     _seterr(ROAR_ERROR_INVAL);
[4206]650     return -1;
651    }
652   break;
653 }
654
[4637]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
[5068]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
[4637]674 return stream.pos + offset;
[4175]675}
676
[4719]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
[4206]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
[4636]709 signed long long int lag;
[4206]710
[4717]711// printf("pos=%zi\n", pos);
712
[4215]713 _initerr();
714
[5068]715 _ckvss(0);
[4260]716
[4215]717 if (pos == -1) {
718  _seterrre();
719  return 0;
720 }
[4206]721
722 if ( !(vss->flags & FLAG_STREAM) ) {
723  _seterr(ROAR_ERROR_INVAL);
[4213]724  return 0;
[4206]725 }
726
727 if ( vss->writec == 0 ) {
728  lioc = vss->readc;
729 } else {
[4717]730  //printf("writec=%zu\n", vss->writec);
[4206]731  lioc = vss->writec;
732 }
733
734 bps = roar_info2samplesize(&(vss->info));
735
736 if ( bps == -1 ) {
737  _seterrre();
[4213]738  return 0;
[4206]739 }
740
[4636]741 lpos = (lioc*8) / bps;
[4206]742
[4717]743 //printf("pos=%zi, lpos=%zi, bps=%zi, diff[lpos-pos]=%zi\n", pos, lpos, bps, (lpos - pos));
[4636]744
745 lag = (signed long long int)lpos - (signed long long int)pos;
746 lag /= vss->info.channels;
[4206]747
748 // we now have the lag in frames
[4636]749 // return value are mus
750 // so we need to multiply with 1s/mus and
[4206]751 // multiply by 1/rate
752
[4636]753 lag *= 1000000; // 1s/mus
[4206]754 lag /= vss->info.rate;
755
[4213]756 if ( lag == 0 ) {
757  _seterr(ROAR_ERROR_NONE);
758 }
759
[4719]760#ifdef _HAVE_SOCKOPT
761 if (vss->latc.target > vss->latc.minlag) {
762  roar_vs_latency_managed(vss, lag);
763 }
764#endif
765
[4206]766 return lag;
767}
768
[5068]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
[4175]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
[4260]848 _ckvss(-1);
849
[4175]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
[4186]858 _initerr();
859
[4175]860 switch (val) {
861  case ROAR_VS_TRUE:
862  case ROAR_VS_FALSE:
[5051]863    if ( roar_stream_set_flags2(vss->con, &(vss->stream), flag,
864                                val == ROAR_VS_TRUE ? ROAR_SET_FLAG : ROAR_RESET_FLAG) == -1 ) {
[4186]865     _seterrre();
[4175]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 ) {
[4186]875     _seterrre();
[4175]876     return -1;
877    }
878    return info.flags & flag ? ROAR_VS_TRUE : ROAR_VS_FALSE;
879   break;
880 }
881
[4187]882 _seterr(ROAR_ERROR_INVAL);
[4175]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;
[4850]897 register float s, max_s = -100.0, scale = 65535.0;
[4182]898 int oldchannels;
[4740]899 int mode = ROAR_SET_VOL_ALL;
[4175]900
[4260]901 _ckvss(-1);
902
[4175]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
[4186]913 _initerr();
914
[4182]915 if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &oldchannels) == -1 ) {
[4186]916  _seterrre();
[4182]917  return -1;
918 }
919
[4850]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
[4179]935 for (i = 0; i < channels; i++) {
[4850]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   }
[4179]950  }
951  mixer.mixer[i] = s;
952 }
[4175]953
[4850]954 if ( vss->flags & FLAG_FREE_VOL ) {
955  mixer.scale = scale;
956 } else {
957  mixer.scale = 65535;
958 }
[4182]959
[4740]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;
[4182]969 }
[4175]970
[4740]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 ) {
[4186]980  _seterrre();
[4175]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
[4186]1010 _initerr();
1011
[4175]1012 if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &channels) == -1 ) {
[4186]1013  _seterrre();
[4175]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
[4176]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;
[4180]1030 int ret = 0;
[4176]1031
[4260]1032 _ckvss(-1);
1033
[4176]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
[4186]1043 _initerr();
[4176]1044
[4180]1045 if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_CLEAR, &meta) == -1 ) {
[4186]1046  _seterrre();
[4180]1047  ret = -1;
1048 }
[4176]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
[4180]1055  if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_ADD, &meta) == -1 ) {
[4186]1056   _seterrre();
[4180]1057   ret = -1;
1058  }
[4176]1059 }
1060
1061 meta.type   = ROAR_META_TYPE_NONE;
1062 meta.key[0] = 0;
1063 meta.value  = NULL;
[4180]1064 if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_FINALIZE, &meta) == -1 ) {
[4186]1065  _seterrre();
[4180]1066  ret = -1;
1067 }
[4176]1068
[4180]1069 return ret;
[4176]1070}
[4174]1071
[4212]1072int     roar_vs_role          (roar_vs_t * vss, int role, int * error) {
[4260]1073 _ckvss(-1);
1074
[4212]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
[4580]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;
[4626]1101 size_t tmp;
1102
1103 // TODO: fix error handling below.
[4580]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.
[4626]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  }
[4580]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);
[4626]1161  } else if ( vss->file != NULL && vios[i].ud.vp == vss->file ) {
[4580]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
[4626]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
[4628]1177// no check here to just let the read return zero and we do EOF handling.
1178/*
[4626]1179  if ( roar_buffer_ring_avail(vss->writering, &tmp, NULL) != -1 )
1180   if ( tmp > 0 )
[4628]1181*/
[4626]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
[4580]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
[4626]1196  ret = roar_vs_write_direct(vss, data, len, error);
[4580]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
[4626]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   }
[4580]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
[4626]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  }
[4580]1287
[4581]1288  ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p): ret=%lli", vss, wait, error, (long long int)ret);
1289
[4580]1290  if ( ret == -1 ) {
[4581]1291   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1292
[4580]1293   roar_buffer_free(vss->writebuffer);
[4581]1294   vss->writebuffer = NULL;
[4580]1295   return -1;
1296  } else if ( ret == 0 ) {
[4581]1297   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1298
[4580]1299   is_eof = 1;
1300   roar_buffer_free(vss->writebuffer);
[4581]1301   vss->writebuffer = NULL;
[4580]1302  } else {
[4581]1303   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1304
[4580]1305   if ( len != ret ) {
1306    len = ret;
[4581]1307    if ( roar_buffer_set_len(vss->writebuffer, len) == -1 )
[4580]1308     return -1;
1309   }
1310
[4581]1311   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1312
[4626]1313   ret = roar_vs_write_direct(vss, data, len, error);
[4580]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
[4639]1327 return is_eof ? 0 : 2;
[4580]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
[4581]1337 ROAR_DBG("roar_vs_run(vss=%p, error=%p): ret=%i", vss, error, ret);
1338
[4580]1339 if ( ret == 0 ) {
1340  // flush buffers:
1341  roar_vs_iterate(vss, ROAR_VS_WAIT, error);
1342 }
1343
[4581]1344 if ( roar_vs_sync(vss, ROAR_VS_WAIT, error) == -1 )
1345  return -1;
1346
[4580]1347 return ret;
1348}
1349
[4626]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
[4629]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
[4622]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;
[4719]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
[4850]1461  case ROAR_VS_CMD_SET_FREE_VOLUME:
[5025]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;
[4850]1481    }
1482   break;
1483  case ROAR_VS_CMD_GET_FREE_VOLUME:
[5025]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;
[4850]1510   break;
[4719]1511// use ifndef here so warnings of unhandled enum values will be shown in DEBUG mode.
1512#ifndef DEBUG
1513  default:
[5025]1514    _seterr(ROAR_ERROR_INVAL);
[4719]1515    return -1;
1516   break;
1517#endif
[4622]1518 }
1519
1520 return 0;
1521}
[4580]1522
[4183]1523struct roar_connection * roar_vs_connection_obj(roar_vs_t * vss, int * error) {
[4260]1524 _ckvss(NULL);
1525
[4183]1526 return vss->con;
1527}
1528
1529struct roar_stream     * roar_vs_stream_obj    (roar_vs_t * vss, int * error) {
[4260]1530 _ckvss(NULL);
1531
[4183]1532 if ( !(vss->flags & FLAG_STREAM) ) {
1533  _seterr(ROAR_ERROR_INVAL);
[4186]1534  return NULL;
[4183]1535 }
1536
1537 return &(vss->stream);
1538}
1539
1540struct roar_vio_calls  * roar_vs_vio_obj       (roar_vs_t * vss, int * error) {
[4260]1541 _ckvss(NULL);
1542
[4183]1543 if ( !(vss->flags & FLAG_STREAM) ) {
1544  _seterr(ROAR_ERROR_INVAL);
[4186]1545  return NULL;
[4183]1546 }
1547
1548 return &(vss->vio);
1549}
1550
[4173]1551//ll
Note: See TracBrowser for help on using the repository browser.