source: roaraudio/libroar/vs.c @ 5271:09aa484b25f4

Last change on this file since 5271:09aa484b25f4 was 5270:e25346c13638, checked in by phi, 12 years ago

fixed some gcc -Wextra warnings

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