source: roaraudio/libroar/vs.c @ 5114:82426e175a9d

Last change on this file since 5114:82426e175a9d was 5114:82426e175a9d, checked in by phi, 13 years ago

added extra const keywords for server names as well as client names

File size: 39.8 KB
Line 
1//vs.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2011
5 *
6 *  This file is part of libroar a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  libroar is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
36#include "libroar.h"
37
38#if defined(ROAR_HAVE_GETSOCKOPT) && defined(ROAR_HAVE_SETSOCKOPT)
39#define _HAVE_SOCKOPT
40#endif
41
42#define LOCAL_CLOCK    ROAR_CLOCK_DEFAULT
43#define ASYNC_QLEN     4
44
45#define FLAG_NONE      0x0000
46#define FLAG_STREAM    0x0001
47#define FLAG_NONBLOCK  0x0002
48#define FLAG_BUFFERED  0x0004
49#define FLAG_CLOSEFILE 0x0008
50#define FLAG_FREE_VOL  0x0010
51#define FLAG_DEF_PAUSE 0x0020
52#define FLAG_DIR_IN    0x1000
53#define FLAG_DIR_OUT   0x2000
54
55#define _initerr()  roar_err_clear_all()
56#define _seterr(x)  do { if ( error != NULL ) *error = (x); roar_err_set((x)); ROAR_DBG("roar_vs_*(*): *error=%s(%i)", roar_vs_strerr((x)), (x)); } while(0)
57#define _seterrre() do { _seterr(roar_error); } while(0)
58#define _seterrse() do { roar_err_from_errno(); _seterr(roar_error); } while(0)
59#define _ckvss(ret) do { if ( vss == NULL ) { _seterr(ROAR_ERROR_INVAL); return (ret); } } while(0)
60#define _ckasync(ret) do { if ( _handle_async(vss, error) == -1 ) { return (ret); } } while(0)
61
62struct roar_vs {
63 int flags;
64 struct roar_connection con_store;
65 struct roar_connection * con;
66 struct roar_stream       stream;
67 struct roar_vio_calls    vio;
68 struct roar_audio_info   info;
69 size_t                   readc, writec;
70 int                      mixerid;
71 int                      first_primid;
72 struct roar_buffer     * readbuffer, * writebuffer;
73 struct roar_vio_calls    file_store;
74 struct roar_vio_calls  * file;
75 struct roar_buffer     * readring, * writering;
76#ifdef _HAVE_SOCKOPT
77 struct {
78  float target;
79  float window;
80  float minlag;
81  float p;
82 } latc;
83#endif
84 struct {
85  ssize_t last_pos;
86  ssize_t last_offset;
87  struct roar_time last_time;
88 } latmes;
89 struct {
90  int    level;
91  size_t lock;
92  size_t qlen;
93  int qcmd[ASYNC_QLEN];
94  int qsubcmd[ASYNC_QLEN];
95  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, 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, 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 ssize_t pos  = roar_vs_position(vss, backend, error);
874 ssize_t bps;  // byte per sample
875 size_t  lioc; // local IO (byte) counter
876 size_t  lpos; // local possition
877 signed long long int lag;
878
879// printf("pos=%zi\n", pos);
880
881 _initerr();
882
883 _ckvss(0);
884 _ckasync(-1);
885
886 if (pos == -1) {
887  _seterrre();
888  return 0;
889 }
890
891 if ( !(vss->flags & FLAG_STREAM) ) {
892  _seterr(ROAR_ERROR_INVAL);
893  return 0;
894 }
895
896 if ( vss->writec == 0 ) {
897  lioc = vss->readc;
898 } else {
899  //printf("writec=%zu\n", vss->writec);
900  lioc = vss->writec;
901 }
902
903 bps = roar_info2samplesize(&(vss->info));
904
905 if ( bps == -1 ) {
906  _seterrre();
907  return 0;
908 }
909
910 lpos = (lioc*8) / bps;
911
912 //printf("pos=%zi, lpos=%zi, bps=%zi, diff[lpos-pos]=%zi\n", pos, lpos, bps, (lpos - pos));
913
914 lag = (signed long long int)lpos - (signed long long int)pos;
915 lag /= vss->info.channels;
916
917 // we now have the lag in frames
918 // return value are mus
919 // so we need to multiply with 1s/mus and
920 // multiply by 1/rate
921
922 lag *= 1000000; // 1s/mus
923 lag /= vss->info.rate;
924
925 if ( lag == 0 ) {
926  _seterr(ROAR_ERROR_NONE);
927 }
928
929#ifdef _HAVE_SOCKOPT
930 if (vss->latc.target > vss->latc.minlag) {
931  roar_vs_latency_managed(vss, lag);
932 }
933#endif
934
935 vss->async.read_latency = 1;
936
937 return lag;
938}
939
940roar_mus_t roar_vs_latency2(roar_vs_t * vss, int backend, int wait, int * error) {
941 ssize_t bps;  // byte per sample
942 size_t  lioc; // local IO (byte) counter
943 size_t  lpos; // local possition
944 signed long long int lag;
945 struct roar_time rt;
946
947 _initerr();
948
949 _ckvss(0);
950
951 if ( !(vss->flags & FLAG_STREAM) ) {
952  _seterr(ROAR_ERROR_INVAL);
953  return 0;
954 }
955
956 _check_async(vss);
957
958 if ( wait == ROAR_VS_WAIT ) {
959  return roar_vs_latency(vss, backend, error);
960 } else if ( wait == ROAR_VS_NOWAIT ) {
961  vss->async.read_latency = 1;
962
963  if ( vss->latmes.last_pos == -1 ) {
964   _seterr(ROAR_ERROR_NODATA);
965   return 0;
966  }
967
968  if ( vss->writec == 0 ) {
969   lioc = vss->readc;
970  } else {
971   //printf("writec=%zu\n", vss->writec);
972   lioc = vss->writec;
973  }
974
975  bps = roar_info2samplesize(&(vss->info));
976
977  if ( bps == -1 ) {
978   _seterrre();
979   return 0;
980  }
981
982  lpos = (lioc*8) / bps;
983
984  //printf("pos=%zi, lpos=%zi, bps=%zi, diff[lpos-pos]=%zi\n", pos, lpos, bps, (lpos - pos));
985
986  lag = (signed long long int)lpos - (signed long long int)(vss->latmes.last_pos + vss->latmes.last_offset);
987  lag /= vss->info.channels;
988
989  // we now have the lag in frames
990  // return value are mus
991  // so we need to multiply with 1s/mus and
992  // multiply by 1/rate
993
994  lag *= 1000000; // 1s/mus
995  lag /= vss->info.rate;
996
997  _initerr();
998  if ( roar_clock_gettime(&rt, LOCAL_CLOCK) == -1 ) {
999   _seterrre();
1000   return 0;
1001  }
1002
1003//  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);
1004//  printf("%lli, %llu\n", rt.t_sec, rt.t_ssec);
1005  lag -= (rt.t_sec  - vss->latmes.last_time.t_sec ) * 1000000LL;
1006  lag -= ((int64_t)(rt.t_ssec/2) - (int64_t)(vss->latmes.last_time.t_ssec/2)) / 9223372036855LL;
1007
1008  if ( lag == 0 ) {
1009   _seterr(ROAR_ERROR_NONE);
1010  }
1011
1012  return lag;
1013 } else if ( wait == ROAR_VS_ASYNC ) {
1014  if ( _send_async_req(vss, ROAR_CMD_GET_STREAM, -1, roar_stream_get_id(&(vss->stream)), error) == -1 )
1015   return 0;
1016  switch (backend) {
1017   case ROAR_VS_BACKEND_NONE:
1018    break;
1019   case ROAR_VS_BACKEND_FIRST:
1020     if ( vss->first_primid == -1 ) {
1021      _seterr(ROAR_ERROR_UNKNOWN);
1022      return 0;
1023     }
1024
1025     backend = vss->first_primid;
1026    break;
1027   default:
1028     if ( backend < 0 ) {
1029      _seterr(ROAR_ERROR_INVAL);
1030      return -1;
1031     }
1032    break;
1033  }
1034
1035  vss->async.last_backend = backend;
1036
1037  if ( backend >= 0 )
1038   if ( _send_async_req(vss, ROAR_CMD_GET_STREAM_PARA, ROAR_STREAM_PARA_INFO, backend, error) == -1 )
1039    return 0;
1040  _seterr(ROAR_ERROR_NODATA);
1041  return 0;
1042 }
1043
1044 _seterr(ROAR_ERROR_INVAL);
1045 return 0;
1046}
1047
1048static int roar_vs_flag(roar_vs_t * vss, int flag, int val, int * error) {
1049 struct roar_stream_info info;
1050 int old = -1;
1051
1052 _ckvss(-1);
1053 _ckasync(-1);
1054
1055 if ( !(vss->flags & FLAG_STREAM) ) {
1056  _seterr(ROAR_ERROR_INVAL);
1057  return -1;
1058 }
1059
1060 if ( val != ROAR_VS_ASK )
1061  old = roar_vs_flag(vss, flag, ROAR_VS_ASK, error);
1062
1063 _initerr();
1064
1065 switch (val) {
1066  case ROAR_VS_TRUE:
1067  case ROAR_VS_FALSE:
1068    if ( roar_stream_set_flags2(vss->con, &(vss->stream), flag,
1069                                val == ROAR_VS_TRUE ? ROAR_SET_FLAG : ROAR_RESET_FLAG) == -1 ) {
1070     _seterrre();
1071     return -1;
1072    }
1073    return old;
1074   break;
1075  case ROAR_VS_TOGGLE:
1076    return roar_vs_flag(vss, flag, old == ROAR_VS_TRUE ? ROAR_VS_FALSE : ROAR_VS_TRUE, error);
1077   break;
1078  case ROAR_VS_ASK:
1079    if ( roar_stream_get_info(vss->con, &(vss->stream), &info) == -1 ) {
1080     _seterrre();
1081     return -1;
1082    }
1083    return info.flags & flag ? ROAR_VS_TRUE : ROAR_VS_FALSE;
1084   break;
1085 }
1086
1087 _seterr(ROAR_ERROR_INVAL);
1088 return -1;
1089}
1090
1091int     roar_vs_pause(roar_vs_t * vss, int val, int * error) {
1092 return roar_vs_flag(vss, ROAR_FLAG_PAUSE, val, error);
1093}
1094
1095int     roar_vs_mute (roar_vs_t * vss, int val, int * error) {
1096 return roar_vs_flag(vss, ROAR_FLAG_MUTE, val, error);
1097}
1098
1099static int roar_vs_volume (roar_vs_t * vss, float * c, size_t channels, int * error) {
1100 struct roar_mixer_settings mixer;
1101 size_t i;
1102 register float s, max_s = -100.0, scale = 65535.0;
1103 int oldchannels;
1104 int mode = ROAR_SET_VOL_ALL;
1105
1106 _ckvss(-1);
1107 _ckasync(-1);
1108
1109 if ( !(vss->flags & FLAG_STREAM) ) {
1110  _seterr(ROAR_ERROR_INVAL);
1111  return -1;
1112 }
1113
1114 if ( channels > ROAR_MAX_CHANNELS ) {
1115  _seterr(ROAR_ERROR_INVAL);
1116  return -1;
1117 }
1118
1119 _initerr();
1120
1121 if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &oldchannels) == -1 ) {
1122  _seterrre();
1123  return -1;
1124 }
1125
1126 if ( vss->flags & FLAG_FREE_VOL ) {
1127  for (i = 0; i < channels; i++) {
1128   if ( c[i] > max_s ) {
1129    max_s = c[i];
1130   } else if ( c[i] < -0.01 ) {
1131    _seterr(ROAR_ERROR_RANGE);
1132    return -1;
1133   }
1134  }
1135
1136  if ( max_s > 1.00 ) {
1137   scale = 65535.0 / max_s;
1138  }
1139 }
1140
1141 for (i = 0; i < channels; i++) {
1142  if ( vss->flags & FLAG_FREE_VOL ) {
1143   s = c[i] * scale;
1144   if ( s < 0.0 )
1145    s = 0.0;
1146  } else {
1147   s = c[i] * 65535.0;
1148   if ( s > 66190.0 || s < -655.0 ) {
1149    _seterr(ROAR_ERROR_RANGE);
1150    return -1;
1151   } else if ( s > 65535.0 ) {
1152    s = 65535.0;
1153   } else if ( s <     0.0 ) {
1154    s = 0.0;
1155   }
1156  }
1157  mixer.mixer[i] = s;
1158 }
1159
1160 if ( vss->flags & FLAG_FREE_VOL ) {
1161  mixer.scale = scale;
1162 } else {
1163  mixer.scale = 65535;
1164 }
1165
1166 if ( channels != oldchannels )
1167  mode = ROAR_SET_VOL_UNMAPPED;
1168
1169 if ( roar_set_vol2(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, channels, mode) == 0 )
1170  return 0;
1171
1172 if ( mode == ROAR_SET_VOL_ALL ) {
1173  _seterrre();
1174  return -1;
1175 }
1176
1177 if ( roar_conv_volume(&mixer, &mixer, oldchannels, channels) == -1 ) {
1178  _seterrre();
1179  return -1;
1180 }
1181
1182 channels = oldchannels;
1183 mode     = ROAR_SET_VOL_ALL;
1184
1185 if ( roar_set_vol2(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, channels, mode) == -1 ) {
1186  _seterrre();
1187  return -1;
1188 }
1189
1190 return 0;
1191}
1192
1193int     roar_vs_volume_mono   (roar_vs_t * vss, float c, int * error) {
1194 return roar_vs_volume(vss, &c, 1, error);
1195}
1196
1197int     roar_vs_volume_stereo (roar_vs_t * vss, float l, float r, int * error) {
1198 float c[2] = {l, r};
1199 return roar_vs_volume(vss, c, 2, error);
1200}
1201
1202int     roar_vs_volume_get    (roar_vs_t * vss, float * l, float * r, int * error) {
1203 struct roar_mixer_settings mixer;
1204 int channels;
1205
1206 if ( vss == NULL || l == NULL || r == NULL ) {
1207  _seterr(ROAR_ERROR_INVAL);
1208  return -1;
1209 }
1210
1211 if ( !(vss->flags & FLAG_STREAM) ) {
1212  _seterr(ROAR_ERROR_INVAL);
1213  return -1;
1214 }
1215
1216 _ckasync(-1);
1217
1218 _initerr();
1219
1220 if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &channels) == -1 ) {
1221  _seterrre();
1222  return -1;
1223 }
1224
1225 if ( channels == 1 )
1226  mixer.mixer[1] = mixer.mixer[0];
1227
1228 *l = mixer.mixer[0] / (float)mixer.scale;
1229 *r = mixer.mixer[1] / (float)mixer.scale;
1230
1231 return 0;
1232}
1233
1234int     roar_vs_meta          (roar_vs_t * vss, struct roar_keyval * kv, size_t len, int * error) {
1235 struct roar_meta meta;
1236 size_t i;
1237 int type;
1238 int ret = 0;
1239
1240 _ckvss(-1);
1241 _ckasync(-1);
1242
1243 if ( !(vss->flags & FLAG_STREAM) ) {
1244  _seterr(ROAR_ERROR_INVAL);
1245  return -1;
1246 }
1247
1248 meta.type   = ROAR_META_TYPE_NONE;
1249 meta.key[0] = 0;
1250 meta.value  = NULL;
1251
1252 _initerr();
1253
1254 if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_CLEAR, &meta) == -1 ) {
1255  _seterrre();
1256  ret = -1;
1257 }
1258
1259 for (i = 0; i < len; i++) {
1260  type = roar_meta_inttype(kv[i].key);
1261  meta.type  = type;
1262  meta.value = kv[i].value;
1263
1264  if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_ADD, &meta) == -1 ) {
1265   _seterrre();
1266   ret = -1;
1267  }
1268 }
1269
1270 meta.type   = ROAR_META_TYPE_NONE;
1271 meta.key[0] = 0;
1272 meta.value  = NULL;
1273 if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_FINALIZE, &meta) == -1 ) {
1274  _seterrre();
1275  ret = -1;
1276 }
1277
1278 return ret;
1279}
1280
1281int     roar_vs_role          (roar_vs_t * vss, int role, int * error) {
1282 _ckvss(-1);
1283 _ckasync(-1);
1284
1285 if ( !(vss->flags & FLAG_STREAM) ) {
1286  _seterr(ROAR_ERROR_INVAL);
1287  return -1;
1288 }
1289
1290 _initerr();
1291
1292 if ( roar_stream_set_role(vss->con, &(vss->stream), role) == -1 ) {
1293  _seterrre();
1294  return -1;
1295 }
1296
1297 return 0;
1298}
1299
1300
1301int     roar_vs_iterate       (roar_vs_t * vss, int wait, int * error) {
1302 struct roar_vio_select vios[3];
1303 struct roar_vio_selecttv rtv = {.sec = 0, .nsec = 1};
1304 size_t len = 0;
1305 ssize_t i;
1306 ssize_t ret;
1307 int can_read = 0, can_write = 0;
1308 int can_flush_stream = 0, can_flush_file = 0;
1309 int is_eof = 0;
1310 void * data;
1311 size_t tmp;
1312
1313 // TODO: fix error handling below.
1314
1315 _ckvss(-1);
1316
1317 if ( wait != ROAR_VS_WAIT && wait != ROAR_VS_NOWAIT ) {
1318  _seterr(ROAR_ERROR_INVAL);
1319  return -1;
1320 }
1321
1322 ROAR_VIO_SELECT_SETVIO(&(vios[len]), &(vss->vio), ((vss->flags & FLAG_DIR_IN  ? ROAR_VIO_SELECT_READ  : 0) |
1323                                                    (vss->flags & FLAG_DIR_OUT ? ROAR_VIO_SELECT_WRITE : 0)));
1324 vios[len].ud.vp = &(vss->vio);
1325 len++;
1326
1327 ROAR_VIO_SELECT_SETVIO(&(vios[len]), roar_get_connection_vio2(vss->con), ROAR_VIO_SELECT_READ);
1328 vios[len].ud.vp = vss->con;
1329 len++;
1330
1331
1332// TODO: FIXME: need to do two select()s so we can sleep more efficently and test for both directions.
1333// for the moment we disable file direction and hope it will not block anyway...
1334/*
1335 if ( vss->file != NULL ) {
1336  ROAR_VIO_SELECT_SETVIO(&(vios[len]), vss->file, ((vss->flags & FLAG_DIR_IN  ? ROAR_VIO_SELECT_WRITE : 0) |
1337                                                   (vss->flags & FLAG_DIR_OUT ? ROAR_VIO_SELECT_READ  : 0)));
1338  vios[len].ud.vp = vss->file;
1339  len++;
1340 }
1341*/
1342
1343 ret = roar_vio_select(vios, len, (wait == ROAR_VS_NOWAIT ? &rtv : NULL), NULL);
1344
1345// part 2 of above hack:
1346// emulate read handle.
1347  if ( vss->file != NULL ) {
1348   vios[len].ud.vp   = vss->file;
1349   vios[len].eventsa = ROAR_VIO_SELECT_WRITE|ROAR_VIO_SELECT_READ;
1350   len++;
1351  }
1352
1353 // no error here nor EOF.
1354 if ( ret == 0 )
1355  return 1;
1356
1357 for (i = 0; i < len; i++) {
1358  if ( !vios[i].eventsa )
1359   continue;
1360
1361  if ( vios[i].ud.vp == &(vss->vio) ) {
1362   if ( vios[i].eventsa & ROAR_VIO_SELECT_READ )
1363    can_read++;
1364
1365   if ( vios[i].eventsa & ROAR_VIO_SELECT_WRITE ) {
1366    can_write++;
1367    can_flush_stream = 1;
1368   }
1369  } else if ( vios[i].ud.vp == vss->con ) {
1370   if ( vss->async.qlen ) {
1371    _handle_async_req(vss, NULL);
1372   } else {
1373    roar_sync(vss->con);
1374   }
1375  } else if ( vss->file != NULL && vios[i].ud.vp == vss->file ) {
1376   if ( vios[i].eventsa & ROAR_VIO_SELECT_READ )
1377    can_write++;
1378
1379   if ( vios[i].eventsa & ROAR_VIO_SELECT_WRITE ) {
1380    can_read++;
1381    can_flush_file = 1;
1382   }
1383  }
1384 }
1385
1386 if ( vss->flags & FLAG_BUFFERED ) {
1387  if ( roar_buffer_ring_avail(vss->readring, NULL, &tmp) != -1 )
1388   if ( tmp > 0 )
1389    can_read++;
1390
1391// no check here to just let the read return zero and we do EOF handling.
1392/*
1393  if ( roar_buffer_ring_avail(vss->writering, &tmp, NULL) != -1 )
1394   if ( tmp > 0 )
1395*/
1396    can_write++;
1397 }
1398
1399 ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p): can_read=%i, can_write=%i", vss, wait, error, can_read, can_write);
1400
1401 // TODO: FIXME: Need to correct error handling here!
1402
1403 if ( can_flush_stream && vss->writebuffer != NULL ) {
1404  if ( roar_buffer_get_data(vss->writebuffer, &data) == -1 )
1405   return -1;
1406
1407  if ( roar_buffer_get_len(vss->writebuffer, &len) == -1 )
1408   return -1;
1409
1410  ret = roar_vs_write_direct(vss, data, len, error);
1411
1412  if ( ret == -1 ) {
1413   return -1;
1414  } else if ( ret == len ) {
1415   roar_buffer_free(vss->writebuffer);
1416   vss->writebuffer = NULL;
1417  } else {
1418   if ( roar_buffer_set_offset(vss->writebuffer, ret) == -1 )
1419    return -1;
1420  }
1421 }
1422
1423 if ( can_flush_file && vss->readbuffer != NULL ) {
1424  if ( roar_buffer_get_data(vss->readbuffer, &data) == -1 )
1425   return -1;
1426
1427  if ( roar_buffer_get_len(vss->readbuffer, &len) == -1 )
1428   return -1;
1429
1430  ret = roar_vio_write(vss->file, data, len);
1431
1432  if ( ret == -1 ) {
1433   return -1;
1434  } else if ( ret == len ) {
1435   roar_buffer_free(vss->readbuffer);
1436   vss->readbuffer = NULL;
1437  } else {
1438   if ( roar_buffer_set_offset(vss->readbuffer, ret) == -1 )
1439    return -1;
1440  }
1441 }
1442
1443#define _READ_SIZE 1024
1444
1445 if ( can_read == 2 && vss->readbuffer == NULL ) {
1446  if ( roar_buffer_new_data(&(vss->readbuffer), (len = _READ_SIZE), &data) == -1 )
1447   return -1;
1448
1449  ret = roar_vs_read(vss, data, len, error);
1450
1451  if ( ret == -1 ) {
1452   roar_buffer_free(vss->readbuffer);
1453   vss->readbuffer = NULL;
1454   return -1;
1455  } else if ( ret == 0 ) {
1456   is_eof = 1;
1457   roar_buffer_free(vss->readbuffer);
1458   vss->readbuffer = NULL;
1459  } else {
1460   len = ret;
1461   if ( roar_buffer_set_len(vss->readbuffer, len) == -1 )
1462    return -1;
1463
1464   if ( vss->flags & FLAG_BUFFERED ) {
1465    tmp = len;
1466    if ( roar_buffer_ring_write(vss->readring, data, &tmp) == -1 ) {
1467     ret = -1;
1468    } else {
1469     ret = tmp;
1470    }
1471   } else {
1472    ret = roar_vio_write(vss->file, data, len);
1473   }
1474
1475   if ( ret == -1 ) {
1476    return -1;
1477   } else if ( ret == len ) {
1478    roar_buffer_free(vss->readbuffer);
1479    vss->readbuffer = NULL;
1480   } else {
1481    if ( roar_buffer_set_offset(vss->readbuffer, ret) == -1 )
1482     return -1;
1483   }
1484  }
1485 }
1486
1487 if ( can_write == 2 && vss->writebuffer == NULL ) {
1488  if ( roar_buffer_new_data(&(vss->writebuffer), (len = _READ_SIZE), &data) == -1 )
1489   return -1;
1490
1491  if ( vss->flags & FLAG_BUFFERED ) {
1492   tmp = len;
1493   if ( roar_buffer_ring_read(vss->writering, data, &tmp) == -1 ) {
1494    ret = -1;
1495   } else {
1496    ret = tmp;
1497   }
1498  } else {
1499   ret = roar_vio_read(vss->file, data, len);
1500  }
1501
1502  ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p): ret=%lli", vss, wait, error, (long long int)ret);
1503
1504  if ( ret == -1 ) {
1505   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1506
1507   roar_buffer_free(vss->writebuffer);
1508   vss->writebuffer = NULL;
1509   return -1;
1510  } else if ( ret == 0 ) {
1511   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1512
1513   is_eof = 1;
1514   roar_buffer_free(vss->writebuffer);
1515   vss->writebuffer = NULL;
1516  } else {
1517   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1518
1519   if ( len != ret ) {
1520    len = ret;
1521    if ( roar_buffer_set_len(vss->writebuffer, len) == -1 )
1522     return -1;
1523   }
1524
1525   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1526
1527   ret = roar_vs_write_direct(vss, data, len, error);
1528
1529   if ( ret == -1 ) {
1530    return -1;
1531   } else if ( ret == len ) {
1532    roar_buffer_free(vss->writebuffer);
1533    vss->writebuffer = NULL;
1534   } else {
1535    if ( roar_buffer_set_offset(vss->writebuffer, ret) == -1 )
1536     return -1;
1537   }
1538  }
1539 }
1540
1541 if ( vss->async.level == ROAR_VS_ASYNCLEVEL_AUTO && !vss->async.lock &&
1542      vss->async.read_latency                     && !vss->async.qlen ) {
1543  _LIBROAR_IGNORE_RET(roar_vs_latency2(vss,
1544                                       vss->async.last_backend < 0 ? ROAR_VS_BACKEND_NONE : vss->async.last_backend,
1545                                       ROAR_VS_ASYNC, NULL));
1546 }
1547
1548 return is_eof ? 0 : 2;
1549}
1550
1551int     roar_vs_run           (roar_vs_t * vss, int * error) {
1552 int ret;
1553
1554 _ckvss(-1);
1555
1556 while ((ret = roar_vs_iterate(vss, ROAR_VS_WAIT, error)) > 0);
1557
1558 ROAR_DBG("roar_vs_run(vss=%p, error=%p): ret=%i", vss, error, ret);
1559
1560 if ( ret == 0 ) {
1561  // flush buffers:
1562  roar_vs_iterate(vss, ROAR_VS_WAIT, error);
1563 }
1564
1565 if ( roar_vs_sync(vss, ROAR_VS_WAIT, error) == -1 )
1566  return -1;
1567
1568 return ret;
1569}
1570
1571ssize_t roar_vs_get_avail_read(roar_vs_t * vss, int * error) {
1572 size_t len;
1573
1574 _ckvss(-1);
1575
1576 if ( !(vss->flags & FLAG_BUFFERED) ) {
1577  _seterr(ROAR_ERROR_INVAL);
1578  return -1;
1579 }
1580
1581 if ( roar_buffer_ring_avail(vss->readring, &len, NULL) == -1 ) {
1582  _seterrre();
1583  return -1;
1584 }
1585
1586 return len;
1587}
1588
1589ssize_t roar_vs_get_avail_write(roar_vs_t * vss, int * error) {
1590 size_t len;
1591
1592 _ckvss(-1);
1593
1594 if ( !(vss->flags & FLAG_BUFFERED) ) {
1595  _seterr(ROAR_ERROR_INVAL);
1596  return -1;
1597 }
1598
1599 if ( roar_buffer_ring_avail(vss->writering, NULL, &len) == -1 ) {
1600  _seterrre();
1601  return -1;
1602 }
1603
1604 return len;
1605}
1606
1607int     roar_vs_reset_buffer(roar_vs_t * vss, int writering, int readring, int * error) {
1608 _ckvss(-1);
1609
1610 if ( !(vss->flags & FLAG_BUFFERED) ) {
1611  _seterr(ROAR_ERROR_INVAL);
1612  return -1;
1613 }
1614
1615 if ( writering != ROAR_VS_TRUE || writering != ROAR_VS_FALSE ||
1616      readring  != ROAR_VS_TRUE || readring  != ROAR_VS_FALSE ) {
1617  _seterr(ROAR_ERROR_INVAL);
1618  return -1;
1619 }
1620
1621 if ( writering ) {
1622  if ( roar_buffer_ring_reset(vss->writering) == -1 ) {
1623   _seterrre();
1624   return -1;
1625  }
1626 }
1627
1628 if ( readring ) {
1629  if ( roar_buffer_ring_reset(vss->readring) == -1 ) {
1630   _seterrre();
1631   return -1;
1632  }
1633 }
1634
1635 return 0;
1636}
1637
1638int     roar_vs_ctl           (roar_vs_t * vss, roar_vs_ctlcmd cmd, void * argp, int * error) {
1639 _ckvss(-1);
1640
1641 switch (cmd) {
1642  case ROAR_VS_CMD_NOOP:
1643   break;
1644  case ROAR_VS_CMD_SET_MIXER:
1645    vss->mixerid = *(int*)argp;
1646   break;
1647  case ROAR_VS_CMD_GET_MIXER:
1648    *(int*)argp = vss->mixerid;
1649   break;
1650  case ROAR_VS_CMD_SET_FIRST_PRIM:
1651    vss->first_primid = *(int*)argp;
1652   break;
1653  case ROAR_VS_CMD_GET_FIRST_PRIM:
1654    *(int*)argp = vss->first_primid;
1655   break;
1656#ifdef _HAVE_SOCKOPT
1657  case ROAR_VS_CMD_SET_LATC_P:
1658    vss->latc.p = *(float*)argp;
1659   break;
1660  case ROAR_VS_CMD_GET_LATC_P:
1661    *(float*)argp = vss->latc.p;
1662   break;
1663  case ROAR_VS_CMD_SET_LATC_TARGET:
1664    vss->latc.target = *(float*)argp;
1665   break;
1666  case ROAR_VS_CMD_GET_LATC_TARGET:
1667    *(float*)argp = vss->latc.target;
1668   break;
1669  case ROAR_VS_CMD_SET_LATC_WINDOW:
1670    vss->latc.window = *(float*)argp;
1671   break;
1672  case ROAR_VS_CMD_GET_LATC_WINDOW:
1673    *(float*)argp = vss->latc.window;
1674   break;
1675  case ROAR_VS_CMD_SET_LATC_MINLAG:
1676    vss->latc.minlag = *(float*)argp;
1677   break;
1678  case ROAR_VS_CMD_GET_LATC_MINLAG:
1679    *(float*)argp = vss->latc.minlag;
1680   break;
1681#endif
1682  case ROAR_VS_CMD_SET_FREE_VOLUME:
1683    switch (*(int*)argp) {
1684     case ROAR_VS_TRUE:
1685       vss->flags |= FLAG_FREE_VOL;
1686      break;
1687     case ROAR_VS_FALSE:
1688       vss->flags |= FLAG_FREE_VOL;
1689       vss->flags -= FLAG_FREE_VOL;
1690      break;
1691     case ROAR_VS_TOGGLE:
1692       if ( vss->flags & FLAG_FREE_VOL ) {
1693        vss->flags -= FLAG_FREE_VOL;
1694       } else {
1695        vss->flags |= FLAG_FREE_VOL;
1696       }
1697      break;
1698     default:
1699       _seterr(ROAR_ERROR_INVAL);
1700       return -1;
1701      break;
1702    }
1703   break;
1704  case ROAR_VS_CMD_GET_FREE_VOLUME:
1705    *(int*)argp = vss->flags & FLAG_FREE_VOL ? ROAR_VS_TRUE : ROAR_VS_FALSE;
1706   break;
1707  case ROAR_VS_CMD_SET_DEFAULT_PAUSED:
1708    switch (*(int*)argp) {
1709     case ROAR_VS_TRUE:
1710       vss->flags |= FLAG_DEF_PAUSE;
1711      break;
1712     case ROAR_VS_FALSE:
1713       vss->flags |= FLAG_DEF_PAUSE;
1714       vss->flags -= FLAG_DEF_PAUSE;
1715      break;
1716     case ROAR_VS_TOGGLE:
1717       if ( vss->flags & FLAG_DEF_PAUSE ) {
1718        vss->flags -= FLAG_DEF_PAUSE;
1719       } else {
1720        vss->flags |= FLAG_DEF_PAUSE;
1721       }
1722      break;
1723     default:
1724       _seterr(ROAR_ERROR_INVAL);
1725       return -1;
1726      break;
1727    }
1728   break;
1729  case ROAR_VS_CMD_GET_DEFAULT_PAUSED:
1730    *(int*)argp = vss->flags & FLAG_DEF_PAUSE ? ROAR_VS_TRUE : ROAR_VS_FALSE;
1731   break;
1732  case ROAR_VS_CMD_SET_ASYNC:
1733    vss->async.level = *(int*)argp;
1734   break;
1735  case ROAR_VS_CMD_GET_ASYNC:
1736    *(int*)argp = vss->async.level;
1737   break;
1738  case ROAR_VS_CMD_LOCK_ASYNC:
1739    _ckasync(-1);
1740    if ( argp == NULL ) {
1741     vss->async.lock++;
1742    } else {
1743     vss->async.lock -= *(int*)argp;
1744    }
1745   break;
1746  case ROAR_VS_CMD_UNLOCK_ASYNC:
1747    if ( argp == NULL ) {
1748     if ( !vss->async.lock ) {
1749      _seterr(ROAR_ERROR_LOSTSYNC);
1750      return -1;
1751     } else {
1752      vss->async.lock--;
1753     }
1754    } else {
1755     if ( vss->async.lock < (size_t)*(int*)argp ) {
1756      _seterr(ROAR_ERROR_LOSTSYNC);
1757      return -1;
1758     } else {
1759      vss->async.lock -= *(int*)argp;
1760     }
1761    }
1762   break;
1763// use ifndef here so warnings of unhandled enum values will be shown in DEBUG mode.
1764#ifndef DEBUG
1765  default:
1766    _seterr(ROAR_ERROR_INVAL);
1767    return -1;
1768   break;
1769#endif
1770 }
1771
1772 return 0;
1773}
1774
1775struct roar_connection * roar_vs_connection_obj(roar_vs_t * vss, int * error) {
1776 _ckvss(NULL);
1777
1778 return vss->con;
1779}
1780
1781struct roar_stream     * roar_vs_stream_obj    (roar_vs_t * vss, int * error) {
1782 _ckvss(NULL);
1783
1784 if ( !(vss->flags & FLAG_STREAM) ) {
1785  _seterr(ROAR_ERROR_INVAL);
1786  return NULL;
1787 }
1788
1789 return &(vss->stream);
1790}
1791
1792struct roar_vio_calls  * roar_vs_vio_obj       (roar_vs_t * vss, int * error) {
1793 _ckvss(NULL);
1794
1795 if ( !(vss->flags & FLAG_STREAM) ) {
1796  _seterr(ROAR_ERROR_INVAL);
1797  return NULL;
1798 }
1799
1800 return &(vss->vio);
1801}
1802
1803//ll
Note: See TracBrowser for help on using the repository browser.