source: roaraudio/libroar/vs.c @ 5347:1d76e45ebfd1

Last change on this file since 5347:1d76e45ebfd1 was 5315:a125509a6c22, checked in by phi, 12 years ago

corrected error code

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