source: roaraudio/libroar/vs.c @ 5239:eb474b0b1805

Last change on this file since 5239:eb474b0b1805 was 5239:eb474b0b1805, checked in by phi, 12 years ago

Removed roar_vs_latency().

File size: 39.4 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_FAULT); 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, server, 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, const 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, const 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 if ( roar_vio_ctl(&(vss->vio), ROAR_VIO_CTL_GET_SYSIO_SOCKOPT, &sockopt) == -1 )
857  return;
858
859 val /= 2;
860
861 tmp = 1.0 - tmp;
862
863 val = (float)val*tmp;
864
865 sockopt.optlen  = sizeof(val);
866
867 if ( roar_vio_ctl(&(vss->vio), ROAR_VIO_CTL_SET_SYSIO_SOCKOPT, &sockopt) == -1 )
868  return;
869}
870#endif
871
872roar_mus_t roar_vs_latency(roar_vs_t * vss, int backend, int wait, int * error) {
873 ssize_t pos;
874 ssize_t bps;  // byte per sample
875 size_t  lioc; // local IO (byte) counter
876 size_t  lpos; // local possition
877 signed long long int lag;
878 struct roar_time rt;
879
880 _initerr();
881
882 _ckvss(0);
883
884 if ( !(vss->flags & FLAG_STREAM) ) {
885  _seterr(ROAR_ERROR_INVAL);
886  return 0;
887 }
888
889 _check_async(vss);
890
891 if ( wait == ROAR_VS_WAIT ) {
892  _ckasync(0);
893
894  pos = roar_vs_position(vss, backend, error);
895  if (pos == -1) {
896   _seterrre();
897   return 0;
898  }
899
900  if ( vss->writec == 0 ) {
901   lioc = vss->readc;
902  } else {
903   //printf("writec=%zu\n", vss->writec);
904   lioc = vss->writec;
905  }
906
907  bps = roar_info2samplesize(&(vss->info));
908
909  if ( bps == -1 ) {
910   _seterrre();
911   return 0;
912  }
913
914  lpos = (lioc*8) / bps;
915
916  lag = (signed long long int)lpos - (signed long long int)pos;
917  lag /= vss->info.channels;
918
919  // we now have the lag in frames
920  // return value are mus
921  // so we need to multiply with 1s/mus and
922  // multiply by 1/rate
923
924  lag *= 1000000; // 1s/mus
925  lag /= vss->info.rate;
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  if ( lag == 0 ) {
936   _seterr(ROAR_ERROR_NONE);
937  }
938
939  return lag;
940 } else if ( wait == ROAR_VS_NOWAIT ) {
941  vss->async.read_latency = 1;
942
943  if ( vss->latmes.last_pos == -1 ) {
944   _seterr(ROAR_ERROR_NODATA);
945   return 0;
946  }
947
948  if ( vss->writec == 0 ) {
949   lioc = vss->readc;
950  } else {
951   //printf("writec=%zu\n", vss->writec);
952   lioc = vss->writec;
953  }
954
955  bps = roar_info2samplesize(&(vss->info));
956
957  if ( bps == -1 ) {
958   _seterrre();
959   return 0;
960  }
961
962  lpos = (lioc*8) / bps;
963
964  //printf("pos=%zi, lpos=%zi, bps=%zi, diff[lpos-pos]=%zi\n", pos, lpos, bps, (lpos - pos));
965
966  lag = (signed long long int)lpos - (signed long long int)(vss->latmes.last_pos + vss->latmes.last_offset);
967  lag /= vss->info.channels;
968
969  // we now have the lag in frames
970  // return value are mus
971  // so we need to multiply with 1s/mus and
972  // multiply by 1/rate
973
974  lag *= 1000000; // 1s/mus
975  lag /= vss->info.rate;
976
977  _initerr();
978  if ( roar_clock_gettime(&rt, LOCAL_CLOCK) == -1 ) {
979   _seterrre();
980   return 0;
981  }
982
983//  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);
984//  printf("%lli, %llu\n", rt.t_sec, rt.t_ssec);
985  lag -= (rt.t_sec  - vss->latmes.last_time.t_sec ) * 1000000LL;
986  lag -= ((int64_t)(rt.t_ssec/2) - (int64_t)(vss->latmes.last_time.t_ssec/2)) / 9223372036855LL;
987
988  if ( lag == 0 ) {
989   _seterr(ROAR_ERROR_NONE);
990  }
991
992  return lag;
993 } else if ( wait == ROAR_VS_ASYNC ) {
994  if ( _send_async_req(vss, ROAR_CMD_GET_STREAM, -1, roar_stream_get_id(&(vss->stream)), error) == -1 )
995   return 0;
996  switch (backend) {
997   case ROAR_VS_BACKEND_NONE:
998    break;
999   case ROAR_VS_BACKEND_FIRST:
1000     if ( vss->first_primid == -1 ) {
1001      _seterr(ROAR_ERROR_UNKNOWN);
1002      return 0;
1003     }
1004
1005     backend = vss->first_primid;
1006    break;
1007   default:
1008     if ( backend < 0 ) {
1009      _seterr(ROAR_ERROR_INVAL);
1010      return -1;
1011     }
1012    break;
1013  }
1014
1015  vss->async.last_backend = backend;
1016
1017  if ( backend >= 0 )
1018   if ( _send_async_req(vss, ROAR_CMD_GET_STREAM_PARA, ROAR_STREAM_PARA_INFO, backend, error) == -1 )
1019    return 0;
1020  _seterr(ROAR_ERROR_NODATA);
1021  return 0;
1022 }
1023
1024 _seterr(ROAR_ERROR_INVAL);
1025 return 0;
1026}
1027
1028static int roar_vs_flag(roar_vs_t * vss, int flag, int val, int * error) {
1029 struct roar_stream_info info;
1030 int old = -1;
1031
1032 _ckvss(-1);
1033 _ckasync(-1);
1034
1035 if ( !(vss->flags & FLAG_STREAM) ) {
1036  _seterr(ROAR_ERROR_INVAL);
1037  return -1;
1038 }
1039
1040 if ( val != ROAR_VS_ASK )
1041  old = roar_vs_flag(vss, flag, ROAR_VS_ASK, error);
1042
1043 _initerr();
1044
1045 switch (val) {
1046  case ROAR_VS_TRUE:
1047  case ROAR_VS_FALSE:
1048    if ( roar_stream_set_flags(vss->con, &(vss->stream), flag,
1049                                val == ROAR_VS_TRUE ? ROAR_SET_FLAG : ROAR_RESET_FLAG) == -1 ) {
1050     _seterrre();
1051     return -1;
1052    }
1053    return old;
1054   break;
1055  case ROAR_VS_TOGGLE:
1056    return roar_vs_flag(vss, flag, old == ROAR_VS_TRUE ? ROAR_VS_FALSE : ROAR_VS_TRUE, error);
1057   break;
1058  case ROAR_VS_ASK:
1059    if ( roar_stream_get_info(vss->con, &(vss->stream), &info) == -1 ) {
1060     _seterrre();
1061     return -1;
1062    }
1063    return info.flags & flag ? ROAR_VS_TRUE : ROAR_VS_FALSE;
1064   break;
1065 }
1066
1067 _seterr(ROAR_ERROR_INVAL);
1068 return -1;
1069}
1070
1071int     roar_vs_pause(roar_vs_t * vss, int val, int * error) {
1072 return roar_vs_flag(vss, ROAR_FLAG_PAUSE, val, error);
1073}
1074
1075int     roar_vs_mute (roar_vs_t * vss, int val, int * error) {
1076 return roar_vs_flag(vss, ROAR_FLAG_MUTE, val, error);
1077}
1078
1079static int roar_vs_volume (roar_vs_t * vss, float * c, size_t channels, int * error) {
1080 struct roar_mixer_settings mixer;
1081 size_t i;
1082 register float s, max_s = -100.0, scale = 65535.0;
1083 int oldchannels;
1084 int mode = ROAR_SET_VOL_ALL;
1085
1086 _ckvss(-1);
1087 _ckasync(-1);
1088
1089 if ( !(vss->flags & FLAG_STREAM) ) {
1090  _seterr(ROAR_ERROR_INVAL);
1091  return -1;
1092 }
1093
1094 if ( channels > ROAR_MAX_CHANNELS ) {
1095  _seterr(ROAR_ERROR_INVAL);
1096  return -1;
1097 }
1098
1099 _initerr();
1100
1101 if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &oldchannels) == -1 ) {
1102  _seterrre();
1103  return -1;
1104 }
1105
1106 if ( vss->flags & FLAG_FREE_VOL ) {
1107  for (i = 0; i < channels; i++) {
1108   if ( c[i] > max_s ) {
1109    max_s = c[i];
1110   } else if ( c[i] < -0.01 ) {
1111    _seterr(ROAR_ERROR_RANGE);
1112    return -1;
1113   }
1114  }
1115
1116  if ( max_s > 1.00 ) {
1117   scale = 65535.0 / max_s;
1118  }
1119 }
1120
1121 for (i = 0; i < channels; i++) {
1122  if ( vss->flags & FLAG_FREE_VOL ) {
1123   s = c[i] * scale;
1124   if ( s < 0.0 )
1125    s = 0.0;
1126  } else {
1127   s = c[i] * 65535.0;
1128   if ( s > 66190.0 || s < -655.0 ) {
1129    _seterr(ROAR_ERROR_RANGE);
1130    return -1;
1131   } else if ( s > 65535.0 ) {
1132    s = 65535.0;
1133   } else if ( s <     0.0 ) {
1134    s = 0.0;
1135   }
1136  }
1137  mixer.mixer[i] = s;
1138 }
1139
1140 if ( vss->flags & FLAG_FREE_VOL ) {
1141  mixer.scale = scale;
1142 } else {
1143  mixer.scale = 65535;
1144 }
1145
1146 if ( channels != oldchannels )
1147  mode = ROAR_SET_VOL_UNMAPPED;
1148
1149 if ( roar_set_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, channels, mode) == 0 )
1150  return 0;
1151
1152 if ( mode == ROAR_SET_VOL_ALL ) {
1153  _seterrre();
1154  return -1;
1155 }
1156
1157 if ( roar_conv_volume(&mixer, &mixer, oldchannels, channels) == -1 ) {
1158  _seterrre();
1159  return -1;
1160 }
1161
1162 channels = oldchannels;
1163 mode     = ROAR_SET_VOL_ALL;
1164
1165 if ( roar_set_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, channels, mode) == -1 ) {
1166  _seterrre();
1167  return -1;
1168 }
1169
1170 return 0;
1171}
1172
1173int     roar_vs_volume_mono   (roar_vs_t * vss, float c, int * error) {
1174 return roar_vs_volume(vss, &c, 1, error);
1175}
1176
1177int     roar_vs_volume_stereo (roar_vs_t * vss, float l, float r, int * error) {
1178 float c[2] = {l, r};
1179 return roar_vs_volume(vss, c, 2, error);
1180}
1181
1182int     roar_vs_volume_get    (roar_vs_t * vss, float * l, float * r, int * error) {
1183 struct roar_mixer_settings mixer;
1184 int channels;
1185
1186 if ( vss == NULL || l == NULL || r == NULL ) {
1187  _seterr(ROAR_ERROR_INVAL);
1188  return -1;
1189 }
1190
1191 if ( !(vss->flags & FLAG_STREAM) ) {
1192  _seterr(ROAR_ERROR_INVAL);
1193  return -1;
1194 }
1195
1196 _ckasync(-1);
1197
1198 _initerr();
1199
1200 if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &channels) == -1 ) {
1201  _seterrre();
1202  return -1;
1203 }
1204
1205 if ( channels == 1 )
1206  mixer.mixer[1] = mixer.mixer[0];
1207
1208 *l = mixer.mixer[0] / (float)mixer.scale;
1209 *r = mixer.mixer[1] / (float)mixer.scale;
1210
1211 return 0;
1212}
1213
1214int     roar_vs_meta          (roar_vs_t * vss, struct roar_keyval * kv, size_t len, int * error) {
1215 struct roar_meta meta;
1216 size_t i;
1217 int type;
1218 int ret = 0;
1219
1220 _ckvss(-1);
1221 _ckasync(-1);
1222
1223 if ( !(vss->flags & FLAG_STREAM) ) {
1224  _seterr(ROAR_ERROR_INVAL);
1225  return -1;
1226 }
1227
1228 meta.type   = ROAR_META_TYPE_NONE;
1229 meta.key[0] = 0;
1230 meta.value  = NULL;
1231
1232 _initerr();
1233
1234 if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_CLEAR, &meta) == -1 ) {
1235  _seterrre();
1236  ret = -1;
1237 }
1238
1239 for (i = 0; i < len; i++) {
1240  type = roar_meta_inttype(kv[i].key);
1241  meta.type  = type;
1242  meta.value = kv[i].value;
1243
1244  if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_ADD, &meta) == -1 ) {
1245   _seterrre();
1246   ret = -1;
1247  }
1248 }
1249
1250 meta.type   = ROAR_META_TYPE_NONE;
1251 meta.key[0] = 0;
1252 meta.value  = NULL;
1253 if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_FINALIZE, &meta) == -1 ) {
1254  _seterrre();
1255  ret = -1;
1256 }
1257
1258 return ret;
1259}
1260
1261int     roar_vs_role          (roar_vs_t * vss, int role, int * error) {
1262 _ckvss(-1);
1263 _ckasync(-1);
1264
1265 if ( !(vss->flags & FLAG_STREAM) ) {
1266  _seterr(ROAR_ERROR_INVAL);
1267  return -1;
1268 }
1269
1270 _initerr();
1271
1272 if ( roar_stream_set_role(vss->con, &(vss->stream), role) == -1 ) {
1273  _seterrre();
1274  return -1;
1275 }
1276
1277 return 0;
1278}
1279
1280
1281int     roar_vs_iterate       (roar_vs_t * vss, int wait, int * error) {
1282 struct roar_vio_select vios[3];
1283 struct roar_vio_selecttv rtv = {.sec = 0, .nsec = 1};
1284 size_t len = 0;
1285 ssize_t i;
1286 ssize_t ret;
1287 int can_read = 0, can_write = 0;
1288 int can_flush_stream = 0, can_flush_file = 0;
1289 int is_eof = 0;
1290 void * data;
1291 size_t tmp;
1292
1293 // TODO: fix error handling below.
1294
1295 ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1296
1297 _ckvss(-1);
1298
1299 if ( wait != ROAR_VS_WAIT && wait != ROAR_VS_NOWAIT ) {
1300  _seterr(ROAR_ERROR_INVAL);
1301  return -1;
1302 }
1303
1304 ROAR_VIO_SELECT_SETVIO(&(vios[len]), &(vss->vio), ((vss->flags & FLAG_DIR_IN  ? ROAR_VIO_SELECT_READ  : 0) |
1305                                                    (vss->flags & FLAG_DIR_OUT ? ROAR_VIO_SELECT_WRITE : 0)));
1306 vios[len].ud.vp = &(vss->vio);
1307 len++;
1308
1309 ROAR_VIO_SELECT_SETVIO(&(vios[len]), roar_get_connection_vio2(vss->con), ROAR_VIO_SELECT_READ);
1310 vios[len].ud.vp = vss->con;
1311 len++;
1312
1313
1314// TODO: FIXME: need to do two select()s so we can sleep more efficently and test for both directions.
1315// for the moment we disable file direction and hope it will not block anyway...
1316/*
1317 if ( vss->file != NULL ) {
1318  ROAR_VIO_SELECT_SETVIO(&(vios[len]), vss->file, ((vss->flags & FLAG_DIR_IN  ? ROAR_VIO_SELECT_WRITE : 0) |
1319                                                   (vss->flags & FLAG_DIR_OUT ? ROAR_VIO_SELECT_READ  : 0)));
1320  vios[len].ud.vp = vss->file;
1321  len++;
1322 }
1323*/
1324
1325 ret = roar_vio_select(vios, len, (wait == ROAR_VS_NOWAIT ? &rtv : NULL), NULL);
1326
1327// part 2 of above hack:
1328// emulate read handle.
1329  if ( vss->file != NULL ) {
1330   vios[len].ud.vp   = vss->file;
1331   vios[len].eventsa = ROAR_VIO_SELECT_WRITE|ROAR_VIO_SELECT_READ;
1332   len++;
1333  }
1334
1335 // no error here nor EOF.
1336 if ( ret == 0 )
1337  return 1;
1338
1339 for (i = 0; i < len; i++) {
1340  if ( !vios[i].eventsa )
1341   continue;
1342
1343  if ( vios[i].ud.vp == &(vss->vio) ) {
1344   if ( vios[i].eventsa & ROAR_VIO_SELECT_READ )
1345    can_read++;
1346
1347   if ( vios[i].eventsa & ROAR_VIO_SELECT_WRITE ) {
1348    can_write++;
1349    can_flush_stream = 1;
1350   }
1351  } else if ( vios[i].ud.vp == vss->con ) {
1352   if ( vss->async.qlen ) {
1353    _handle_async_req(vss, NULL);
1354   } else {
1355    roar_sync(vss->con);
1356   }
1357  } else if ( vss->file != NULL && vios[i].ud.vp == vss->file ) {
1358   if ( vios[i].eventsa & ROAR_VIO_SELECT_READ )
1359    can_write++;
1360
1361   if ( vios[i].eventsa & ROAR_VIO_SELECT_WRITE ) {
1362    can_read++;
1363    can_flush_file = 1;
1364   }
1365  }
1366 }
1367
1368 if ( vss->flags & FLAG_BUFFERED ) {
1369  if ( roar_buffer_ring_avail(vss->readring, NULL, &tmp) != -1 )
1370   if ( tmp > 0 )
1371    can_read++;
1372
1373// no check here to just let the read return zero and we do EOF handling.
1374/*
1375  if ( roar_buffer_ring_avail(vss->writering, &tmp, NULL) != -1 )
1376   if ( tmp > 0 )
1377*/
1378    can_write++;
1379 }
1380
1381 ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p): can_read=%i, can_write=%i", vss, wait, error, can_read, can_write);
1382
1383 // TODO: FIXME: Need to correct error handling here!
1384
1385 if ( can_flush_stream && vss->writebuffer != NULL ) {
1386  if ( roar_buffer_get_data(vss->writebuffer, &data) == -1 )
1387   return -1;
1388
1389  if ( roar_buffer_get_len(vss->writebuffer, &len) == -1 )
1390   return -1;
1391
1392  ret = roar_vs_write_direct(vss, data, len, error);
1393
1394  if ( ret == -1 ) {
1395   return -1;
1396  } else if ( ret == len ) {
1397   roar_buffer_free(vss->writebuffer);
1398   vss->writebuffer = NULL;
1399  } else {
1400   if ( roar_buffer_set_offset(vss->writebuffer, ret) == -1 )
1401    return -1;
1402  }
1403 }
1404
1405 if ( can_flush_file && vss->readbuffer != NULL ) {
1406  if ( roar_buffer_get_data(vss->readbuffer, &data) == -1 )
1407   return -1;
1408
1409  if ( roar_buffer_get_len(vss->readbuffer, &len) == -1 )
1410   return -1;
1411
1412  ret = roar_vio_write(vss->file, data, len);
1413
1414  if ( ret == -1 ) {
1415   return -1;
1416  } else if ( ret == len ) {
1417   roar_buffer_free(vss->readbuffer);
1418   vss->readbuffer = NULL;
1419  } else {
1420   if ( roar_buffer_set_offset(vss->readbuffer, ret) == -1 )
1421    return -1;
1422  }
1423 }
1424
1425#define _READ_SIZE 1024
1426
1427 if ( can_read == 2 && vss->readbuffer == NULL ) {
1428  if ( roar_buffer_new_data(&(vss->readbuffer), (len = _READ_SIZE), &data) == -1 )
1429   return -1;
1430
1431  ret = roar_vs_read(vss, data, len, error);
1432
1433  if ( ret == -1 ) {
1434   roar_buffer_free(vss->readbuffer);
1435   vss->readbuffer = NULL;
1436   return -1;
1437  } else if ( ret == 0 ) {
1438   is_eof = 1;
1439   roar_buffer_free(vss->readbuffer);
1440   vss->readbuffer = NULL;
1441  } else {
1442   len = ret;
1443   if ( roar_buffer_set_len(vss->readbuffer, len) == -1 )
1444    return -1;
1445
1446   if ( vss->flags & FLAG_BUFFERED ) {
1447    tmp = len;
1448    if ( roar_buffer_ring_write(vss->readring, data, &tmp) == -1 ) {
1449     ret = -1;
1450    } else {
1451     ret = tmp;
1452    }
1453   } else {
1454    ret = roar_vio_write(vss->file, data, len);
1455   }
1456
1457   if ( ret == -1 ) {
1458    return -1;
1459   } else if ( ret == len ) {
1460    roar_buffer_free(vss->readbuffer);
1461    vss->readbuffer = NULL;
1462   } else {
1463    if ( roar_buffer_set_offset(vss->readbuffer, ret) == -1 )
1464     return -1;
1465   }
1466  }
1467 }
1468
1469 if ( can_write == 2 && vss->writebuffer == NULL ) {
1470  if ( roar_buffer_new_data(&(vss->writebuffer), (len = _READ_SIZE), &data) == -1 )
1471   return -1;
1472
1473  if ( vss->flags & FLAG_BUFFERED ) {
1474   tmp = len;
1475   if ( roar_buffer_ring_read(vss->writering, data, &tmp) == -1 ) {
1476    ret = -1;
1477   } else {
1478    ret = tmp;
1479   }
1480  } else {
1481   ret = roar_vio_read(vss->file, data, len);
1482  }
1483
1484  ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p): ret=%lli", vss, wait, error, (long long int)ret);
1485
1486  if ( ret == -1 ) {
1487   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1488
1489   roar_buffer_free(vss->writebuffer);
1490   vss->writebuffer = NULL;
1491   return -1;
1492  } else if ( ret == 0 ) {
1493   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1494
1495   is_eof = 1;
1496   roar_buffer_free(vss->writebuffer);
1497   vss->writebuffer = NULL;
1498  } else {
1499   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1500
1501   if ( len != ret ) {
1502    len = ret;
1503    if ( roar_buffer_set_len(vss->writebuffer, len) == -1 )
1504     return -1;
1505   }
1506
1507   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1508
1509   ret = roar_vs_write_direct(vss, data, len, error);
1510
1511   if ( ret == -1 ) {
1512    return -1;
1513   } else if ( ret == len ) {
1514    roar_buffer_free(vss->writebuffer);
1515    vss->writebuffer = NULL;
1516   } else {
1517    if ( roar_buffer_set_offset(vss->writebuffer, ret) == -1 )
1518     return -1;
1519   }
1520  }
1521 }
1522
1523 if ( vss->async.level == ROAR_VS_ASYNCLEVEL_AUTO && !vss->async.lock &&
1524      vss->async.read_latency                     && !vss->async.qlen ) {
1525  _LIBROAR_IGNORE_RET(roar_vs_latency(vss,
1526                                      vss->async.last_backend < 0 ? ROAR_VS_BACKEND_NONE : vss->async.last_backend,
1527                                      ROAR_VS_ASYNC, NULL));
1528 }
1529
1530 return is_eof ? 0 : 2;
1531}
1532
1533int     roar_vs_run           (roar_vs_t * vss, int * error) {
1534 int ret;
1535
1536 _ckvss(-1);
1537
1538 while ((ret = roar_vs_iterate(vss, ROAR_VS_WAIT, error)) > 0);
1539
1540 ROAR_DBG("roar_vs_run(vss=%p, error=%p): ret=%i", vss, error, ret);
1541
1542 if ( ret == 0 ) {
1543  // flush buffers:
1544  roar_vs_iterate(vss, ROAR_VS_WAIT, error);
1545 }
1546
1547 if ( roar_vs_sync(vss, ROAR_VS_WAIT, error) == -1 )
1548  return -1;
1549
1550 return ret;
1551}
1552
1553ssize_t roar_vs_get_avail_read(roar_vs_t * vss, int * error) {
1554 size_t len;
1555
1556 _ckvss(-1);
1557
1558 if ( !(vss->flags & FLAG_BUFFERED) ) {
1559  _seterr(ROAR_ERROR_INVAL);
1560  return -1;
1561 }
1562
1563 if ( roar_buffer_ring_avail(vss->readring, &len, NULL) == -1 ) {
1564  _seterrre();
1565  return -1;
1566 }
1567
1568 return len;
1569}
1570
1571ssize_t roar_vs_get_avail_write(roar_vs_t * vss, int * error) {
1572 size_t len;
1573
1574 _ckvss(-1);
1575
1576 if ( !(vss->flags & FLAG_BUFFERED) ) {
1577  _seterr(ROAR_ERROR_INVAL);
1578  return -1;
1579 }
1580
1581 if ( roar_buffer_ring_avail(vss->writering, NULL, &len) == -1 ) {
1582  _seterrre();
1583  return -1;
1584 }
1585
1586 return len;
1587}
1588
1589int     roar_vs_reset_buffer(roar_vs_t * vss, int writering, int readring, int * error) {
1590 _ckvss(-1);
1591
1592 if ( !(vss->flags & FLAG_BUFFERED) ) {
1593  _seterr(ROAR_ERROR_INVAL);
1594  return -1;
1595 }
1596
1597 if ( writering != ROAR_VS_TRUE || writering != ROAR_VS_FALSE ||
1598      readring  != ROAR_VS_TRUE || readring  != ROAR_VS_FALSE ) {
1599  _seterr(ROAR_ERROR_INVAL);
1600  return -1;
1601 }
1602
1603 if ( writering ) {
1604  if ( roar_buffer_ring_reset(vss->writering) == -1 ) {
1605   _seterrre();
1606   return -1;
1607  }
1608 }
1609
1610 if ( readring ) {
1611  if ( roar_buffer_ring_reset(vss->readring) == -1 ) {
1612   _seterrre();
1613   return -1;
1614  }
1615 }
1616
1617 return 0;
1618}
1619
1620int     roar_vs_ctl           (roar_vs_t * vss, roar_vs_ctlcmd cmd, void * argp, int * error) {
1621 _ckvss(-1);
1622
1623 switch (cmd) {
1624  case ROAR_VS_CMD_NOOP:
1625   break;
1626  case ROAR_VS_CMD_SET_MIXER:
1627    vss->mixerid = *(int*)argp;
1628   break;
1629  case ROAR_VS_CMD_GET_MIXER:
1630    *(int*)argp = vss->mixerid;
1631   break;
1632  case ROAR_VS_CMD_SET_FIRST_PRIM:
1633    vss->first_primid = *(int*)argp;
1634   break;
1635  case ROAR_VS_CMD_GET_FIRST_PRIM:
1636    *(int*)argp = vss->first_primid;
1637   break;
1638#ifdef _HAVE_SOCKOPT
1639  case ROAR_VS_CMD_SET_LATC_P:
1640    vss->latc.p = *(float*)argp;
1641   break;
1642  case ROAR_VS_CMD_GET_LATC_P:
1643    *(float*)argp = vss->latc.p;
1644   break;
1645  case ROAR_VS_CMD_SET_LATC_TARGET:
1646    vss->latc.target = *(float*)argp;
1647   break;
1648  case ROAR_VS_CMD_GET_LATC_TARGET:
1649    *(float*)argp = vss->latc.target;
1650   break;
1651  case ROAR_VS_CMD_SET_LATC_WINDOW:
1652    vss->latc.window = *(float*)argp;
1653   break;
1654  case ROAR_VS_CMD_GET_LATC_WINDOW:
1655    *(float*)argp = vss->latc.window;
1656   break;
1657  case ROAR_VS_CMD_SET_LATC_MINLAG:
1658    vss->latc.minlag = *(float*)argp;
1659   break;
1660  case ROAR_VS_CMD_GET_LATC_MINLAG:
1661    *(float*)argp = vss->latc.minlag;
1662   break;
1663#endif
1664  case ROAR_VS_CMD_SET_FREE_VOLUME:
1665    switch (*(int*)argp) {
1666     case ROAR_VS_TRUE:
1667       vss->flags |= FLAG_FREE_VOL;
1668      break;
1669     case ROAR_VS_FALSE:
1670       vss->flags |= FLAG_FREE_VOL;
1671       vss->flags -= FLAG_FREE_VOL;
1672      break;
1673     case ROAR_VS_TOGGLE:
1674       if ( vss->flags & FLAG_FREE_VOL ) {
1675        vss->flags -= FLAG_FREE_VOL;
1676       } else {
1677        vss->flags |= FLAG_FREE_VOL;
1678       }
1679      break;
1680     default:
1681       _seterr(ROAR_ERROR_INVAL);
1682       return -1;
1683      break;
1684    }
1685   break;
1686  case ROAR_VS_CMD_GET_FREE_VOLUME:
1687    *(int*)argp = vss->flags & FLAG_FREE_VOL ? ROAR_VS_TRUE : ROAR_VS_FALSE;
1688   break;
1689  case ROAR_VS_CMD_SET_DEFAULT_PAUSED:
1690    switch (*(int*)argp) {
1691     case ROAR_VS_TRUE:
1692       vss->flags |= FLAG_DEF_PAUSE;
1693      break;
1694     case ROAR_VS_FALSE:
1695       vss->flags |= FLAG_DEF_PAUSE;
1696       vss->flags -= FLAG_DEF_PAUSE;
1697      break;
1698     case ROAR_VS_TOGGLE:
1699       if ( vss->flags & FLAG_DEF_PAUSE ) {
1700        vss->flags -= FLAG_DEF_PAUSE;
1701       } else {
1702        vss->flags |= FLAG_DEF_PAUSE;
1703       }
1704      break;
1705     default:
1706       _seterr(ROAR_ERROR_INVAL);
1707       return -1;
1708      break;
1709    }
1710   break;
1711  case ROAR_VS_CMD_GET_DEFAULT_PAUSED:
1712    *(int*)argp = vss->flags & FLAG_DEF_PAUSE ? ROAR_VS_TRUE : ROAR_VS_FALSE;
1713   break;
1714  case ROAR_VS_CMD_SET_ASYNC:
1715    vss->async.level = *(int*)argp;
1716   break;
1717  case ROAR_VS_CMD_GET_ASYNC:
1718    *(int*)argp = vss->async.level;
1719   break;
1720  case ROAR_VS_CMD_LOCK_ASYNC:
1721    _ckasync(-1);
1722    if ( argp == NULL ) {
1723     vss->async.lock++;
1724    } else {
1725     vss->async.lock -= *(int*)argp;
1726    }
1727   break;
1728  case ROAR_VS_CMD_UNLOCK_ASYNC:
1729    if ( argp == NULL ) {
1730     if ( !vss->async.lock ) {
1731      _seterr(ROAR_ERROR_LOSTSYNC);
1732      return -1;
1733     } else {
1734      vss->async.lock--;
1735     }
1736    } else {
1737     if ( vss->async.lock < (size_t)*(int*)argp ) {
1738      _seterr(ROAR_ERROR_LOSTSYNC);
1739      return -1;
1740     } else {
1741      vss->async.lock -= *(int*)argp;
1742     }
1743    }
1744   break;
1745// use ifndef here so warnings of unhandled enum values will be shown in DEBUG mode.
1746#ifndef DEBUG
1747  default:
1748    _seterr(ROAR_ERROR_INVAL);
1749    return -1;
1750   break;
1751#endif
1752 }
1753
1754 return 0;
1755}
1756
1757struct roar_connection * roar_vs_connection_obj(roar_vs_t * vss, int * error) {
1758 _ckvss(NULL);
1759
1760 return vss->con;
1761}
1762
1763struct roar_stream     * roar_vs_stream_obj    (roar_vs_t * vss, int * error) {
1764 _ckvss(NULL);
1765
1766 if ( !(vss->flags & FLAG_STREAM) ) {
1767  _seterr(ROAR_ERROR_INVAL);
1768  return NULL;
1769 }
1770
1771 return &(vss->stream);
1772}
1773
1774struct roar_vio_calls  * roar_vs_vio_obj       (roar_vs_t * vss, int * error) {
1775 _ckvss(NULL);
1776
1777 if ( !(vss->flags & FLAG_STREAM) ) {
1778  _seterr(ROAR_ERROR_INVAL);
1779  return NULL;
1780 }
1781
1782 return &(vss->vio);
1783}
1784
1785//ll
Note: See TracBrowser for help on using the repository browser.