source: roaraudio/libroar/vs.c @ 4793:a5f42917b666

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

Moved error string lookup from VS into error.c (pr1)

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