source: roaraudio/libroar/vs.c @ 5078:2fffe0b6322c

Last change on this file since 5078:2fffe0b6322c was 5078:2fffe0b6322c, checked in by phi, 13 years ago

added auto mode

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