source: roaraudio/libroar/vs.c @ 4850:fe9aec03046c

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

allow amps > 1.0 for VS API in some kind of expert mode (needed by VLC, requested by maister)

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