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
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;
[5069]84  ssize_t last_offset;
[5068]85  struct roar_time last_time;
86 } latmes;
[4174]87};
88
[4206]89static int _roar_vs_find_first_prim(roar_vs_t * vss);
90
[4174]91const char * roar_vs_strerr(int error) {
[4793]92 const char * ret = roar_error2str(error);
[4174]93
[4793]94 if ( ret == NULL )
95  return "(unknown)";
[4174]96
[4793]97 return ret;
[4174]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 ) {
[4186]104  _seterrse();
[4174]105  return NULL;
106 }
107
108 memset(vss, 0, sizeof(roar_vs_t));
109
[4206]110 vss->mixerid      = -1;
111 vss->first_primid = -1;
112
[4719]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
[5068]120 vss->latmes.last_pos = -1;
121
[4174]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
[4186]145 _initerr();
146
[4174]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);
[4186]151  _seterrre();
[4174]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) {
[4206]159 struct roar_stream_info sinfo;
[4174]160 int ret;
161
[4260]162 _ckvss(-1);
163
[4174]164 if ( vss->flags & FLAG_STREAM ) {
165  _seterr(ROAR_ERROR_INVAL);
166  return -1;
167 }
168
[5025]169 if ( dir == ROAR_DIR_FILTER )
170  vss->flags |= FLAG_DEF_PAUSE;
171
[4186]172 _initerr();
173
[4206]174 if ( info != &(vss->info) )
175  memcpy(&(vss->info), info, sizeof(struct roar_audio_info));
176
[4174]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 ) {
[4186]183  _seterrre();
[4174]184  return -1;
185 }
186
[4206]187 if ( roar_stream_get_info(vss->con, &(vss->stream), &sinfo) != -1 ) {
[4622]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
[4206]197  vss->mixerid = sinfo.mixer;
198  _roar_vs_find_first_prim(vss);
199 }
200
[4174]201 vss->flags |= FLAG_STREAM;
202
[4580]203 switch (dir) {
204  case ROAR_DIR_PLAY: vss->flags |= FLAG_DIR_OUT; break;
205 }
206
[4174]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
[4206]217 memset(&(vss->info), 0, sizeof(vss->info));
[4174]218
[4206]219 vss->info.rate     = rate;
220 vss->info.channels = channels;
221 vss->info.codec    = codec;
222 vss->info.bits     = bits;
[4174]223
[4206]224 ret = roar_vs_stream(vss, &(vss->info), dir, error);
[4174]225
226 if (ret == -1) {
227  roar_vs_close(vss, ROAR_VS_TRUE, NULL);
228  return NULL;
229 }
230
231 return vss;
232}
233
[4580]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;
[4584]260 int codec = -1;
261 const char * content_type;
[4580]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;
[4616]275   default:
276     _seterr(ROAR_ERROR_INVAL);
277     return -1;
[4580]278  }
279 }
280
281 file = &(vss->file_store);
282
[4618]283 _initerr();
[4580]284
[4618]285 if ( roar_vio_dstr_init_defaults(&def, ROAR_VIO_DEF_TYPE_NONE, dir, 0644) == -1 ) {
286  _seterrre();
287  return -1;
288 }
[4580]289
290 if ( roar_vio_open_dstr(file, filename, &def, 1) == -1 ) {
[4618]291  _seterrre();
[4580]292  return -1;
293 }
294
295 if ( !(vss->flags & FLAG_STREAM) ) {
[4584]296  if ( roar_vio_ctl(file, ROAR_VIO_CTL_GET_MIMETYPE, &content_type) != -1 ) {
297   codec = roar_mime2codec(content_type);
298  }
[4580]299
[4584]300  if ( codec == -1 ) {
301   ret = roar_vio_read(file, buf, sizeof(buf));
302
303   codec = roar_file_codecdetect(buf, ret);
[4580]304
[4584]305   if ( codec == -1 ) {
306    roar_vio_close(file);
[4618]307    _seterr(ROAR_ERROR_INVAL); // Other value?
[4584]308    return -1;
309   }
310
311   if ( roar_vio_lseek(file, 0, SEEK_SET) != 0 ) {
312    roar_vio_close(file);
[4618]313   _seterrre();
[4584]314    return -1;
315   }
[4580]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
[4626]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
[4174]378int roar_vs_close(roar_vs_t * vss, int killit, int * error) {
[4178]379 if ( killit != ROAR_VS_TRUE && killit != ROAR_VS_FALSE ) {
[4618]380  _seterr(ROAR_ERROR_INVAL);
[4178]381  return -1;
382 }
383
[4260]384 _ckvss(-1);
385
[4580]386 if ( vss->readbuffer != NULL )
387  roar_buffer_free(vss->readbuffer);
388 if ( vss->writebuffer != NULL )
389  roar_buffer_free(vss->writebuffer);
390
[4626]391 if ( vss->readring != NULL )
392  roar_buffer_free(vss->readring);
393 if ( vss->writering != NULL )
394  roar_buffer_free(vss->writering);
395
[4580]396 if ( vss->file != NULL && vss->flags & FLAG_CLOSEFILE )
397  roar_vio_close(vss->file);
398
[4174]399 if ( vss->flags & FLAG_STREAM ) {
[4178]400  if ( killit == ROAR_VS_TRUE ) {
[4174]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
[4626]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);
[4174]417
418 if ( ret == -1 ) {
[4199]419#ifdef EAGAIN
[4873]420  if ( roar_error == ROAR_ERROR_AGAIN )
[4199]421   return 0;
422#endif
423
[4186]424  _seterrre();
[4206]425 } else {
[4717]426  if ( !(vss->flags & FLAG_BUFFERED) ) {
427   //printf("A: vss->writec=%zu, ret=%zi\n", vss->writec, ret);
[4636]428   vss->writec += ret;
[4717]429  }
[4174]430 }
431
[4717]432 //printf("B: vss->writec=%zu, ret=%zi\n", vss->writec, ret);
[4174]433 return ret;
434}
435
[4626]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
[4174]466ssize_t roar_vs_read (roar_vs_t * vss,       void * buf, size_t len, int * error) {
467 ssize_t ret;
468
[4260]469 _ckvss(-1);
470
[4174]471 if ( !(vss->flags & FLAG_STREAM) ) {
472  _seterr(ROAR_ERROR_INVAL);
473  return -1;
474 }
475
[4186]476 _initerr();
477
[4174]478 ret = roar_vio_read(&(vss->vio), buf, len);
479
480 if ( ret == -1 ) {
[4186]481  _seterrre();
[4206]482 } else {
483  vss->readc += ret;
[4174]484 }
485
486 return ret;
487}
488
[4175]489int     roar_vs_sync (roar_vs_t * vss, int wait, int * error) {
[4579]490 struct roar_event waits, triggered;
491
[4260]492 _ckvss(-1);
493
[4175]494 if ( !(vss->flags & FLAG_STREAM) ) {
495  _seterr(ROAR_ERROR_INVAL);
496  return -1;
497 }
498
[4579]499 if ( wait != ROAR_VS_NOWAIT && wait != ROAR_VS_WAIT ) {
[4175]500  _seterr(ROAR_ERROR_INVAL);
501  return -1;
502 }
503
[4186]504 _initerr();
505
506 if ( roar_vio_sync(&(vss->vio)) == -1 ) {
507  _seterrre();
508  return -1;
509 }
[4175]510
[4579]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
[4175]524 return 0;
525}
526
527int     roar_vs_blocking (roar_vs_t * vss, int val, int * error) {
528 int old = -1;
529
[4260]530 _ckvss(-1);
531
[4175]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
[4186]539 _initerr();
540
[4175]541 switch (val) {
542  case ROAR_VS_TRUE:
543    if ( roar_vio_nonblock(&(vss->vio), ROAR_SOCKET_BLOCK) == -1 ) {
[4186]544     _seterrre();
[4175]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 ) {
[4186]553     _seterrre();
[4175]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
[4206]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;
[4637]615 size_t offset = 0;
[4206]616
[4260]617 _ckvss(-1);
618
[4206]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
[4638]631 if ( backend == ROAR_VS_BACKEND_DEFAULT ) {
632  backend = ROAR_VS_BACKEND_FIRST;
633 }
634
[4206]635 switch (backend) {
636  case ROAR_VS_BACKEND_NONE:
[5068]637//    return stream.pos;
638    // do nothing.
[4206]639   break;
640  case ROAR_VS_BACKEND_FIRST:
641    if ( vss->first_primid == -1 ) {
642     _seterr(ROAR_ERROR_UNKNOWN);
643     return -1;
644    }
645
[4637]646    backend = vss->first_primid;
647   break;
648  default:
649    if ( backend < 0 ) {
650     _seterr(ROAR_ERROR_INVAL);
[4206]651     return -1;
652    }
653   break;
654 }
655
[4637]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
[5068]669 if ( roar_clock_gettime(&(vss->latmes.last_time), LOCAL_CLOCK) == -1 ) {
670  vss->latmes.last_pos = -1;
671 } else {
[5069]672  vss->latmes.last_pos    = stream.pos;
673  vss->latmes.last_offset = offset;
[5068]674 }
675
[4637]676 return stream.pos + offset;
[4175]677}
678
[4719]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
[4206]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
[4636]711 signed long long int lag;
[4206]712
[4717]713// printf("pos=%zi\n", pos);
714
[4215]715 _initerr();
716
[5068]717 _ckvss(0);
[4260]718
[4215]719 if (pos == -1) {
720  _seterrre();
721  return 0;
722 }
[4206]723
724 if ( !(vss->flags & FLAG_STREAM) ) {
725  _seterr(ROAR_ERROR_INVAL);
[4213]726  return 0;
[4206]727 }
728
729 if ( vss->writec == 0 ) {
730  lioc = vss->readc;
731 } else {
[4717]732  //printf("writec=%zu\n", vss->writec);
[4206]733  lioc = vss->writec;
734 }
735
736 bps = roar_info2samplesize(&(vss->info));
737
738 if ( bps == -1 ) {
739  _seterrre();
[4213]740  return 0;
[4206]741 }
742
[4636]743 lpos = (lioc*8) / bps;
[4206]744
[4717]745 //printf("pos=%zi, lpos=%zi, bps=%zi, diff[lpos-pos]=%zi\n", pos, lpos, bps, (lpos - pos));
[4636]746
747 lag = (signed long long int)lpos - (signed long long int)pos;
748 lag /= vss->info.channels;
[4206]749
750 // we now have the lag in frames
[4636]751 // return value are mus
752 // so we need to multiply with 1s/mus and
[4206]753 // multiply by 1/rate
754
[4636]755 lag *= 1000000; // 1s/mus
[4206]756 lag /= vss->info.rate;
757
[4213]758 if ( lag == 0 ) {
759  _seterr(ROAR_ERROR_NONE);
760 }
761
[4719]762#ifdef _HAVE_SOCKOPT
763 if (vss->latc.target > vss->latc.minlag) {
764  roar_vs_latency_managed(vss, lag);
765 }
766#endif
767
[4206]768 return lag;
769}
770
[5068]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
[5069]813  lag = (signed long long int)lpos - (signed long long int)(vss->latmes.last_pos + vss->latmes.last_offset);
[5068]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
[4175]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
[4260]850 _ckvss(-1);
851
[4175]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
[4186]860 _initerr();
861
[4175]862 switch (val) {
863  case ROAR_VS_TRUE:
864  case ROAR_VS_FALSE:
[5051]865    if ( roar_stream_set_flags2(vss->con, &(vss->stream), flag,
866                                val == ROAR_VS_TRUE ? ROAR_SET_FLAG : ROAR_RESET_FLAG) == -1 ) {
[4186]867     _seterrre();
[4175]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 ) {
[4186]877     _seterrre();
[4175]878     return -1;
879    }
880    return info.flags & flag ? ROAR_VS_TRUE : ROAR_VS_FALSE;
881   break;
882 }
883
[4187]884 _seterr(ROAR_ERROR_INVAL);
[4175]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;
[4850]899 register float s, max_s = -100.0, scale = 65535.0;
[4182]900 int oldchannels;
[4740]901 int mode = ROAR_SET_VOL_ALL;
[4175]902
[4260]903 _ckvss(-1);
904
[4175]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
[4186]915 _initerr();
916
[4182]917 if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &oldchannels) == -1 ) {
[4186]918  _seterrre();
[4182]919  return -1;
920 }
921
[4850]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
[4179]937 for (i = 0; i < channels; i++) {
[4850]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   }
[4179]952  }
953  mixer.mixer[i] = s;
954 }
[4175]955
[4850]956 if ( vss->flags & FLAG_FREE_VOL ) {
957  mixer.scale = scale;
958 } else {
959  mixer.scale = 65535;
960 }
[4182]961
[4740]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;
[4182]971 }
[4175]972
[4740]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 ) {
[4186]982  _seterrre();
[4175]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
[4186]1012 _initerr();
1013
[4175]1014 if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &channels) == -1 ) {
[4186]1015  _seterrre();
[4175]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
[4176]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;
[4180]1032 int ret = 0;
[4176]1033
[4260]1034 _ckvss(-1);
1035
[4176]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
[4186]1045 _initerr();
[4176]1046
[4180]1047 if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_CLEAR, &meta) == -1 ) {
[4186]1048  _seterrre();
[4180]1049  ret = -1;
1050 }
[4176]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
[4180]1057  if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_ADD, &meta) == -1 ) {
[4186]1058   _seterrre();
[4180]1059   ret = -1;
1060  }
[4176]1061 }
1062
1063 meta.type   = ROAR_META_TYPE_NONE;
1064 meta.key[0] = 0;
1065 meta.value  = NULL;
[4180]1066 if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_FINALIZE, &meta) == -1 ) {
[4186]1067  _seterrre();
[4180]1068  ret = -1;
1069 }
[4176]1070
[4180]1071 return ret;
[4176]1072}
[4174]1073
[4212]1074int     roar_vs_role          (roar_vs_t * vss, int role, int * error) {
[4260]1075 _ckvss(-1);
1076
[4212]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
[4580]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;
[4626]1103 size_t tmp;
1104
1105 // TODO: fix error handling below.
[4580]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.
[4626]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  }
[4580]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);
[4626]1163  } else if ( vss->file != NULL && vios[i].ud.vp == vss->file ) {
[4580]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
[4626]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
[4628]1179// no check here to just let the read return zero and we do EOF handling.
1180/*
[4626]1181  if ( roar_buffer_ring_avail(vss->writering, &tmp, NULL) != -1 )
1182   if ( tmp > 0 )
[4628]1183*/
[4626]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
[4580]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
[4626]1198  ret = roar_vs_write_direct(vss, data, len, error);
[4580]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
[4626]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   }
[4580]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
[4626]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  }
[4580]1289
[4581]1290  ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p): ret=%lli", vss, wait, error, (long long int)ret);
1291
[4580]1292  if ( ret == -1 ) {
[4581]1293   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1294
[4580]1295   roar_buffer_free(vss->writebuffer);
[4581]1296   vss->writebuffer = NULL;
[4580]1297   return -1;
1298  } else if ( ret == 0 ) {
[4581]1299   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1300
[4580]1301   is_eof = 1;
1302   roar_buffer_free(vss->writebuffer);
[4581]1303   vss->writebuffer = NULL;
[4580]1304  } else {
[4581]1305   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1306
[4580]1307   if ( len != ret ) {
1308    len = ret;
[4581]1309    if ( roar_buffer_set_len(vss->writebuffer, len) == -1 )
[4580]1310     return -1;
1311   }
1312
[4581]1313   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1314
[4626]1315   ret = roar_vs_write_direct(vss, data, len, error);
[4580]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
[4639]1329 return is_eof ? 0 : 2;
[4580]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
[4581]1339 ROAR_DBG("roar_vs_run(vss=%p, error=%p): ret=%i", vss, error, ret);
1340
[4580]1341 if ( ret == 0 ) {
1342  // flush buffers:
1343  roar_vs_iterate(vss, ROAR_VS_WAIT, error);
1344 }
1345
[4581]1346 if ( roar_vs_sync(vss, ROAR_VS_WAIT, error) == -1 )
1347  return -1;
1348
[4580]1349 return ret;
1350}
1351
[4626]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
[4629]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
[4622]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;
[4719]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
[4850]1463  case ROAR_VS_CMD_SET_FREE_VOLUME:
[5025]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;
[4850]1483    }
1484   break;
1485  case ROAR_VS_CMD_GET_FREE_VOLUME:
[5025]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;
[4850]1512   break;
[4719]1513// use ifndef here so warnings of unhandled enum values will be shown in DEBUG mode.
1514#ifndef DEBUG
1515  default:
[5025]1516    _seterr(ROAR_ERROR_INVAL);
[4719]1517    return -1;
1518   break;
1519#endif
[4622]1520 }
1521
1522 return 0;
1523}
[4580]1524
[4183]1525struct roar_connection * roar_vs_connection_obj(roar_vs_t * vss, int * error) {
[4260]1526 _ckvss(NULL);
1527
[4183]1528 return vss->con;
1529}
1530
1531struct roar_stream     * roar_vs_stream_obj    (roar_vs_t * vss, int * error) {
[4260]1532 _ckvss(NULL);
1533
[4183]1534 if ( !(vss->flags & FLAG_STREAM) ) {
1535  _seterr(ROAR_ERROR_INVAL);
[4186]1536  return NULL;
[4183]1537 }
1538
1539 return &(vss->stream);
1540}
1541
1542struct roar_vio_calls  * roar_vs_vio_obj       (roar_vs_t * vss, int * error) {
[4260]1543 _ckvss(NULL);
1544
[4183]1545 if ( !(vss->flags & FLAG_STREAM) ) {
1546  _seterr(ROAR_ERROR_INVAL);
[4186]1547  return NULL;
[4183]1548 }
1549
1550 return &(vss->vio);
1551}
1552
[4173]1553//ll
Note: See TracBrowser for help on using the repository browser.