source: roaraudio/libroar/vs.c @ 5077:0e1299f6d344

Last change on this file since 5077:0e1299f6d344 was 5077:0e1299f6d344, checked in by phi, 11 years ago

support backends for ASYNC mode

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