source: roaraudio/libroar/vs.c @ 5295:5914c84e72be

Last change on this file since 5295:5914c84e72be was 5295:5914c84e72be, checked in by phi, 12 years ago

converted message (protocol) rutunes to use roar_mm_*() (Closes: #129)

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