source: roaraudio/libroar/vs.c @ 5229:d7e314825b8a

Last change on this file since 5229:d7e314825b8a was 5227:beb26bba0901, checked in by phi, 12 years ago

added const keywords to roar_vio_open_dstr(), roar_vio_open_dstr_vio(), roar_vs_file_simple() and roar_vs_new_from_file()

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