source: roaraudio/libroar/vs.c @ 5073:f9b421aec994

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

added code to handle responses to async messages, still need code to send them

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