source: roaraudio/libroar/vs.c @ 5075:fd02b8a97aea

Last change on this file since 5075:fd02b8a97aea was 5075:fd02b8a97aea, checked in by phi, 13 years ago

added support ROAR_VS_ASYNC to roar_vs_latency2()

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