source: roaraudio/libroar/vs.c @ 5073:f9b421aec994

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

added code to handle responses to async messages, still need code to send them

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