source: roaraudio/libroar/vs.c @ 4581:f1a58ffe0be6

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

fixed some minor bugs and flushing problems

File size: 24.6 KB
Line 
1//vs.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010
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#define FLAG_NONE      0x0000
39#define FLAG_STREAM    0x0001
40#define FLAG_NONBLOCK  0x0002
41#define FLAG_BUFFERED  0x0004
42#define FLAG_CLOSEFILE 0x0008
43#define FLAG_DIR_IN    0x1000
44#define FLAG_DIR_OUT   0x2000
45
46#define _initerr()  do { errno = 0; roar_err_clear(); } while(0)
47#define _seterr(x)  do { if ( error != NULL ) *error = (x); } while(0)
48#define _seterrre() do { _seterr(roar_errno); } while(0)
49#define _seterrse() do { roar_err_from_errno(); _seterr(roar_errno); } while(0)
50#define _ckvss(ret) do { if ( vss == NULL ) { _seterr(ROAR_ERROR_INVAL); return (ret); } } while(0)
51
52struct roar_vs {
53 int flags;
54 struct roar_connection con_store;
55 struct roar_connection * con;
56 struct roar_stream       stream;
57 struct roar_vio_calls    vio;
58 struct roar_audio_info   info;
59 size_t                   readc, writec;
60 int                      mixerid;
61 int                      first_primid;
62 struct roar_buffer     * readbuffer, * writebuffer;
63 struct roar_vio_calls    file_store;
64 struct roar_vio_calls  * file;
65};
66
67static int _roar_vs_find_first_prim(roar_vs_t * vss);
68
69const char * roar_vs_strerr(int error) {
70 const struct {
71  int err;
72  const char * msg;
73 } msgs[] = {
74  {ROAR_ERROR_NONE,        "No error"},
75  {ROAR_ERROR_PERM,        "Operation not permitted"},
76  {ROAR_ERROR_NOENT,       "No such object, file or directory"},
77  {ROAR_ERROR_BADMSG,      "Bad message"},
78  {ROAR_ERROR_BUSY,        "Device or resource busy"},
79  {ROAR_ERROR_CONNREFUSED, "Connection refused"},
80  {ROAR_ERROR_NOSYS,       "Function not implemented"},
81  {ROAR_ERROR_NOTSUP,      "Operation not supported"},
82  {ROAR_ERROR_PIPE,        "Broken pipe"},
83  {ROAR_ERROR_PROTO,       "Protocol error"},
84  {ROAR_ERROR_RANGE,       "Result too large or parameter out of range"},
85  {ROAR_ERROR_MSGSIZE,     "Message too long"},
86  {ROAR_ERROR_NOMEM,       "Not enough space"},
87  {ROAR_ERROR_INVAL,       "Invalid argument"},
88  {-1, NULL}
89 };
90 int i;
91
92 for (i = 0; msgs[i].msg != NULL; i++)
93  if ( msgs[i].err == error )
94   return msgs[i].msg;
95
96 return "(unknown)";
97}
98
99static roar_vs_t * roar_vs_init(int * error) {
100 roar_vs_t * vss = roar_mm_malloc(sizeof(roar_vs_t));
101
102 if ( vss == NULL ) {
103  _seterrse();
104  return NULL;
105 }
106
107 memset(vss, 0, sizeof(roar_vs_t));
108
109 vss->mixerid      = -1;
110 vss->first_primid = -1;
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  vss->mixerid = sinfo.mixer;
176  _roar_vs_find_first_prim(vss);
177 }
178
179 vss->flags |= FLAG_STREAM;
180
181 switch (dir) {
182  case ROAR_DIR_PLAY: vss->flags |= FLAG_DIR_OUT; break;
183 }
184
185 return 0;
186}
187
188roar_vs_t * roar_vs_new_simple(const char * server, const char * name, int rate, int channels, int codec, int bits, int dir, int * error) {
189 roar_vs_t * vss = roar_vs_new(server, name, error);
190 int ret;
191
192 if (vss == NULL)
193  return NULL;
194
195 memset(&(vss->info), 0, sizeof(vss->info));
196
197 vss->info.rate     = rate;
198 vss->info.channels = channels;
199 vss->info.codec    = codec;
200 vss->info.bits     = bits;
201
202 ret = roar_vs_stream(vss, &(vss->info), dir, error);
203
204 if (ret == -1) {
205  roar_vs_close(vss, ROAR_VS_TRUE, NULL);
206  return NULL;
207 }
208
209 return vss;
210}
211
212int roar_vs_file(roar_vs_t * vss, struct roar_vio_calls * vio, int closefile, int * error) {
213 _ckvss(-1);
214
215 if ( vio == NULL || (closefile != ROAR_VS_TRUE && closefile != ROAR_VS_FALSE)) {
216  _seterr(ROAR_ERROR_INVAL);
217  return -1;
218 }
219
220 if ( vss->file != NULL ) {
221  _seterr(ROAR_ERROR_INVAL);
222  return -1;
223 }
224
225 vss->file = vio;
226 if ( closefile == ROAR_VS_TRUE )
227  vss->flags |= FLAG_CLOSEFILE;
228
229 return 0;
230}
231
232int roar_vs_file_simple(roar_vs_t * vss, char * filename, int * error) {
233 struct roar_vio_defaults def;
234 struct roar_vio_calls * file;
235 char buf[64];
236 ssize_t ret;
237 int dir = O_RDONLY;
238 int codec;
239
240 _ckvss(-1);
241
242 if ( vss->file != NULL ) {
243  _seterr(ROAR_ERROR_INVAL);
244  return -1;
245 }
246
247 if ( vss->flags & FLAG_STREAM ) {
248  switch (vss->flags & (FLAG_DIR_IN|FLAG_DIR_OUT)) {
249   case FLAG_DIR_IN:  dir = O_WRONLY; break;
250   case FLAG_DIR_OUT: dir = O_RDONLY; break;
251   case FLAG_DIR_IN|FLAG_DIR_OUT: dir = O_RDWR; break;
252   default: return -1;
253  }
254 }
255
256 file = &(vss->file_store);
257
258 // TODO: FIXME: correct error handling bellow.
259
260 if ( roar_vio_dstr_init_defaults(&def, ROAR_VIO_DEF_TYPE_NONE, dir, 0644) == -1 )
261  return -11;
262
263 if ( roar_vio_open_dstr(file, filename, &def, 1) == -1 ) {
264  return -1;
265 }
266
267 if ( !(vss->flags & FLAG_STREAM) ) {
268  ret = roar_vio_read(file, buf, sizeof(buf));
269
270  codec = roar_file_codecdetect(buf, ret);
271
272  if ( vss->info.codec == -1 ) {
273   roar_vio_close(file);
274   return -1;
275  }
276
277  memset(&(vss->info), 0, sizeof(vss->info));
278
279  vss->info.rate     = ROAR_RATE_DEFAULT;
280  vss->info.channels = ROAR_CHANNELS_DEFAULT;
281  vss->info.codec    = codec;
282  vss->info.bits     = ROAR_BITS_DEFAULT;
283
284  if ( roar_vio_lseek(file, 0, SEEK_SET) != 0 ) {
285   roar_vio_close(file);
286   return -1;
287  }
288
289  ret = roar_vs_stream(vss, &(vss->info), ROAR_DIR_PLAY, error);
290
291  if ( ret == -1 ) {
292   roar_vio_close(file);
293   return -1;
294  }
295 }
296
297 if ( roar_vs_file(vss, file, ROAR_VS_TRUE, error) == -1 ) {
298  roar_vio_close(file);
299  return -1;
300 }
301
302 return 0;
303}
304
305roar_vs_t * roar_vs_new_from_file(const char * server, const char * name, char * filename, int * error) {
306 roar_vs_t * vss = roar_vs_new(server, name, error);
307
308 if ( vss == NULL )
309  return NULL;
310
311 if ( roar_vs_file_simple(vss, filename, error) != 0 ) {
312  roar_vs_close(vss, ROAR_VS_TRUE, NULL);
313  return NULL;
314 }
315
316 return vss;
317}
318
319int roar_vs_close(roar_vs_t * vss, int killit, int * error) {
320 if ( killit != ROAR_VS_TRUE && killit != ROAR_VS_FALSE ) {
321  _seterr(ROAR_ERROR_UNKNOWN);
322  return -1;
323 }
324
325 _ckvss(-1);
326
327 if ( vss->readbuffer != NULL )
328  roar_buffer_free(vss->readbuffer);
329 if ( vss->writebuffer != NULL )
330  roar_buffer_free(vss->writebuffer);
331
332 if ( vss->file != NULL && vss->flags & FLAG_CLOSEFILE )
333  roar_vio_close(vss->file);
334
335 if ( vss->flags & FLAG_STREAM ) {
336  if ( killit == ROAR_VS_TRUE ) {
337   roar_kick(vss->con, ROAR_OT_STREAM, roar_stream_get_id(&(vss->stream)));
338  }
339
340  roar_vio_close(&(vss->vio));
341 }
342
343 if ( vss->con == &(vss->con_store) ) {
344  roar_disconnect(vss->con);
345 }
346
347 roar_mm_free(vss);
348 return 0;
349}
350
351ssize_t roar_vs_write(roar_vs_t * vss, const void * buf, size_t len, int * error) {
352 ssize_t ret;
353
354 _ckvss(-1);
355
356 if ( !(vss->flags & FLAG_STREAM) ) {
357  _seterr(ROAR_ERROR_INVAL);
358  return -1;
359 }
360
361 _initerr();
362
363 ret = roar_vio_write(&(vss->vio), (void*)buf, len);
364
365 if ( ret == -1 ) {
366#ifdef EAGAIN
367  if ( errno == EAGAIN )
368   return 0;
369#endif
370
371#ifdef EWOULDBLOCK
372  if ( errno == EWOULDBLOCK )
373   return 0;
374#endif
375
376  _seterrre();
377 } else {
378  vss->writec += ret;
379 }
380
381 return ret;
382}
383
384ssize_t roar_vs_read (roar_vs_t * vss,       void * buf, size_t len, int * error) {
385 ssize_t ret;
386
387 _ckvss(-1);
388
389 if ( !(vss->flags & FLAG_STREAM) ) {
390  _seterr(ROAR_ERROR_INVAL);
391  return -1;
392 }
393
394 _initerr();
395
396 ret = roar_vio_read(&(vss->vio), buf, len);
397
398 if ( ret == -1 ) {
399  _seterrre();
400 } else {
401  vss->readc += ret;
402 }
403
404 return ret;
405}
406
407int     roar_vs_sync (roar_vs_t * vss, int wait, int * error) {
408 struct roar_event waits, triggered;
409
410 _ckvss(-1);
411
412 if ( !(vss->flags & FLAG_STREAM) ) {
413  _seterr(ROAR_ERROR_INVAL);
414  return -1;
415 }
416
417 if ( wait != ROAR_VS_NOWAIT && wait != ROAR_VS_WAIT ) {
418  _seterr(ROAR_ERROR_INVAL);
419  return -1;
420 }
421
422 _initerr();
423
424 if ( roar_vio_sync(&(vss->vio)) == -1 ) {
425  _seterrre();
426  return -1;
427 }
428
429 if ( wait == ROAR_VS_WAIT ) {
430  memset(&waits, 0, sizeof(waits));
431  waits.event       = ROAR_OE_STREAM_XRUN;
432  waits.emitter     = -1;
433  waits.target      = roar_stream_get_id(&(vss->stream));
434  waits.target_type = ROAR_OT_STREAM;
435
436  if ( roar_wait(vss->con, &triggered, &waits, 1) == -1 ) {
437   _seterrre();
438   return -1;
439  }
440 }
441
442 return 0;
443}
444
445int     roar_vs_blocking (roar_vs_t * vss, int val, int * error) {
446 int old = -1;
447
448 _ckvss(-1);
449
450  if ( !(vss->flags & FLAG_STREAM) ) {
451  _seterr(ROAR_ERROR_INVAL);
452  return -1;
453 }
454
455 old = vss->flags & FLAG_NONBLOCK ? ROAR_VS_FALSE : ROAR_VS_TRUE;
456
457 _initerr();
458
459 switch (val) {
460  case ROAR_VS_TRUE:
461    if ( roar_vio_nonblock(&(vss->vio), ROAR_SOCKET_BLOCK) == -1 ) {
462     _seterrre();
463     return -1;
464    }
465    vss->flags |= FLAG_NONBLOCK;
466    vss->flags -= FLAG_NONBLOCK;
467    return old;
468   break;
469  case ROAR_VS_FALSE:
470    if ( roar_vio_nonblock(&(vss->vio), ROAR_SOCKET_NONBLOCK) == -1 ) {
471     _seterrre();
472     return -1;
473    }
474    vss->flags |= FLAG_NONBLOCK;
475    return old;
476   break;
477  case ROAR_VS_TOGGLE:
478    if ( old == ROAR_VS_TRUE ) {
479     return roar_vs_blocking(vss, ROAR_VS_FALSE, error);
480    } else {
481     return roar_vs_blocking(vss, ROAR_VS_TRUE, error);
482    }
483   break;
484  case ROAR_VS_ASK:
485    return old;
486   break;
487 }
488
489 _seterr(ROAR_ERROR_INVAL);
490 return -1;
491}
492
493static int _roar_vs_find_first_prim(roar_vs_t * vss) {
494 struct roar_stream stream;
495 struct roar_stream_info info;
496 int id[ROAR_STREAMS_MAX];
497 int num;
498 int i;
499
500 if ( vss->first_primid != -1 )
501  return vss->first_primid;
502
503 if ( vss->mixerid == -1 )
504  return -1;
505
506 if ( (num = roar_list_streams(vss->con, id, ROAR_STREAMS_MAX)) == -1 ) {
507  return -1;
508 }
509
510 for (i = 0; i < num; i++) {
511  if ( roar_get_stream(vss->con, &stream, id[i]) == -1 )
512   continue;
513
514  if ( stream.dir != ROAR_DIR_OUTPUT )
515   continue;
516
517  if ( roar_stream_get_info(vss->con, &stream, &info) == -1 )
518   continue;
519
520  if ( info.mixer == vss->mixerid ) {
521   vss->first_primid = id[i];
522   return id[i];
523  }
524 }
525
526 return -1;
527}
528
529ssize_t roar_vs_position(roar_vs_t * vss, int backend, int * error) {
530 struct roar_stream stream;
531 struct roar_stream      out_stream;
532 struct roar_stream_info out_info;
533 size_t offset;
534
535 _ckvss(-1);
536
537 if ( !(vss->flags & FLAG_STREAM) ) {
538  _seterr(ROAR_ERROR_INVAL);
539  return -1;
540 }
541
542 _initerr();
543
544 if ( roar_get_stream(vss->con, &stream, roar_stream_get_id(&(vss->stream))) == -1 ) {
545  _seterrre();
546  return -1;
547 }
548
549 switch (backend) {
550  case ROAR_VS_BACKEND_NONE:
551    return stream.pos;
552   break;
553  case ROAR_VS_BACKEND_FIRST:
554   // _roar_vs_find_first_prim(vss);
555    if ( vss->first_primid == -1 ) {
556     _seterr(ROAR_ERROR_UNKNOWN);
557     return -1;
558    }
559
560    roar_stream_new_by_id(&out_stream, vss->first_primid);
561
562    if ( roar_stream_get_info(vss->con, &out_stream, &out_info) == -1 ) {
563     _seterrre();
564     return -1;
565    }
566
567    offset  = out_info.delay * vss->info.rate;
568    offset /= 1000000;
569
570    return stream.pos + offset;
571   break;
572  default:
573    _seterr(ROAR_ERROR_NOTSUP);
574    return -1;
575   break;
576 }
577
578 _seterr(ROAR_ERROR_NOSYS);
579 return -1;
580}
581
582roar_mus_t roar_vs_latency(roar_vs_t * vss, int backend, int * error) {
583 ssize_t pos  = roar_vs_position(vss, backend, error);
584 ssize_t bps;  // byte per sample
585 size_t  lioc; // local IO (byte) counter
586 size_t  lpos; // local possition
587 roar_mus_t  lag;
588
589 _initerr();
590
591 _ckvss(-1);
592
593 if (pos == -1) {
594  _seterrre();
595  return 0;
596 }
597
598 if ( !(vss->flags & FLAG_STREAM) ) {
599  _seterr(ROAR_ERROR_INVAL);
600  return 0;
601 }
602
603 if ( vss->writec == 0 ) {
604  lioc = vss->readc;
605 } else {
606  lioc = vss->writec;
607 }
608
609 bps = roar_info2samplesize(&(vss->info));
610
611 if ( bps == -1 ) {
612  _seterrre();
613  return 0;
614 }
615
616 lpos = lioc / bps;
617
618 lag = (roar_mus_t)lpos - (roar_mus_t)pos;
619
620 // we now have the lag in frames
621 // return value are ms
622 // so we need to multiply with 1s/ms and
623 // multiply by 1/rate
624
625 lag *= 1000000; // 1s/ms
626 lag /= vss->info.rate;
627
628 if ( lag == 0 ) {
629  _seterr(ROAR_ERROR_NONE);
630 }
631
632 return lag;
633}
634
635static int roar_vs_flag(roar_vs_t * vss, int flag, int val, int * error) {
636 struct roar_stream_info info;
637 int old = -1;
638
639 _ckvss(-1);
640
641 if ( !(vss->flags & FLAG_STREAM) ) {
642  _seterr(ROAR_ERROR_INVAL);
643  return -1;
644 }
645
646 if ( val != ROAR_VS_ASK )
647  old = roar_vs_flag(vss, flag, ROAR_VS_ASK, error);
648
649 _initerr();
650
651 switch (val) {
652  case ROAR_VS_TRUE:
653  case ROAR_VS_FALSE:
654    if ( roar_stream_set_flags(vss->con, &(vss->stream), flag,
655                               val == ROAR_VS_TRUE ? ROAR_SET_FLAG : ROAR_RESET_FLAG) == -1 ) {
656     _seterrre();
657     return -1;
658    }
659    return old;
660   break;
661  case ROAR_VS_TOGGLE:
662    return roar_vs_flag(vss, flag, old == ROAR_VS_TRUE ? ROAR_VS_FALSE : ROAR_VS_TRUE, error);
663   break;
664  case ROAR_VS_ASK:
665    if ( roar_stream_get_info(vss->con, &(vss->stream), &info) == -1 ) {
666     _seterrre();
667     return -1;
668    }
669    return info.flags & flag ? ROAR_VS_TRUE : ROAR_VS_FALSE;
670   break;
671 }
672
673 _seterr(ROAR_ERROR_INVAL);
674 return -1;
675}
676
677int     roar_vs_pause(roar_vs_t * vss, int val, int * error) {
678 return roar_vs_flag(vss, ROAR_FLAG_PAUSE, val, error);
679}
680
681int     roar_vs_mute (roar_vs_t * vss, int val, int * error) {
682 return roar_vs_flag(vss, ROAR_FLAG_MUTE, val, error);
683}
684
685static int roar_vs_volume (roar_vs_t * vss, float * c, size_t channels, int * error) {
686 struct roar_mixer_settings mixer;
687 size_t i;
688 register float s;
689 int oldchannels;
690 int handled;
691
692 _ckvss(-1);
693
694 if ( !(vss->flags & FLAG_STREAM) ) {
695  _seterr(ROAR_ERROR_INVAL);
696  return -1;
697 }
698
699 if ( channels > ROAR_MAX_CHANNELS ) {
700  _seterr(ROAR_ERROR_INVAL);
701  return -1;
702 }
703
704 _initerr();
705
706 if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &oldchannels) == -1 ) {
707  _seterrre();
708  return -1;
709 }
710
711 for (i = 0; i < channels; i++) {
712  s = c[i] * 65535.0;
713  if ( s > 66190.0 || s < -655.0 ) {
714   _seterr(ROAR_ERROR_RANGE);
715   return -1;
716  } else if ( s > 65535.0 ) {
717   s = 65535.0;
718  } else if ( s <     0.0 ) {
719   s = 0.0;
720  }
721  mixer.mixer[i] = s;
722 }
723
724 mixer.scale = 65535;
725
726 if ( channels != oldchannels ) {
727  handled = 0;
728  switch (oldchannels) {
729   case 1:
730     if ( channels == 2 ) {
731      mixer.mixer[0] = (mixer.mixer[0] + mixer.mixer[1]) / 2;
732      handled = 1;
733     }
734    break;
735   case 2:
736     if ( channels == 1 ) {
737      mixer.mixer[1] = mixer.mixer[0];
738      handled = 1;
739     }
740    break;
741   case 4:
742     if ( channels == 1 ) {
743      mixer.mixer[1] = mixer.mixer[0];
744      mixer.mixer[2] = mixer.mixer[0];
745      mixer.mixer[3] = mixer.mixer[0];
746      handled = 1;
747     } else if ( channels == 2 ) {
748      mixer.mixer[2] = mixer.mixer[0];
749      mixer.mixer[3] = mixer.mixer[1];
750      handled = 1;
751     }
752    break;
753  }
754  if ( handled ) {
755   channels = oldchannels;
756  } else {
757   _seterr(ROAR_ERROR_INVAL);
758   return -1;
759  }
760 }
761
762 if ( roar_set_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, channels) == -1 ) {
763  _seterrre();
764  return -1;
765 }
766
767 return 0;
768}
769
770int     roar_vs_volume_mono   (roar_vs_t * vss, float c, int * error) {
771 return roar_vs_volume(vss, &c, 1, error);
772}
773
774int     roar_vs_volume_stereo (roar_vs_t * vss, float l, float r, int * error) {
775 float c[2] = {l, r};
776 return roar_vs_volume(vss, c, 2, error);
777}
778
779int     roar_vs_volume_get    (roar_vs_t * vss, float * l, float * r, int * error) {
780 struct roar_mixer_settings mixer;
781 int channels;
782
783 if ( vss == NULL || l == NULL || r == NULL ) {
784  _seterr(ROAR_ERROR_INVAL);
785  return -1;
786 }
787
788 if ( !(vss->flags & FLAG_STREAM) ) {
789  _seterr(ROAR_ERROR_INVAL);
790  return -1;
791 }
792
793 _initerr();
794
795 if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &channels) == -1 ) {
796  _seterrre();
797  return -1;
798 }
799
800 if ( channels == 1 )
801  mixer.mixer[1] = mixer.mixer[0];
802
803 *l = mixer.mixer[0] / (float)mixer.scale;
804 *r = mixer.mixer[1] / (float)mixer.scale;
805
806 return 0;
807}
808
809int     roar_vs_meta          (roar_vs_t * vss, struct roar_keyval * kv, size_t len, int * error) {
810 struct roar_meta meta;
811 size_t i;
812 int type;
813 int ret = 0;
814
815 _ckvss(-1);
816
817 if ( !(vss->flags & FLAG_STREAM) ) {
818  _seterr(ROAR_ERROR_INVAL);
819  return -1;
820 }
821
822 meta.type   = ROAR_META_TYPE_NONE;
823 meta.key[0] = 0;
824 meta.value  = NULL;
825
826 _initerr();
827
828 if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_CLEAR, &meta) == -1 ) {
829  _seterrre();
830  ret = -1;
831 }
832
833 for (i = 0; i < len; i++) {
834  type = roar_meta_inttype(kv[i].key);
835  meta.type  = type;
836  meta.value = kv[i].value;
837
838  if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_ADD, &meta) == -1 ) {
839   _seterrre();
840   ret = -1;
841  }
842 }
843
844 meta.type   = ROAR_META_TYPE_NONE;
845 meta.key[0] = 0;
846 meta.value  = NULL;
847 if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_FINALIZE, &meta) == -1 ) {
848  _seterrre();
849  ret = -1;
850 }
851
852 return ret;
853}
854
855int     roar_vs_role          (roar_vs_t * vss, int role, int * error) {
856 _ckvss(-1);
857
858 if ( !(vss->flags & FLAG_STREAM) ) {
859  _seterr(ROAR_ERROR_INVAL);
860  return -1;
861 }
862
863 _initerr();
864
865 if ( roar_stream_set_role(vss->con, &(vss->stream), role) == -1 ) {
866  _seterrre();
867  return -1;
868 }
869
870 return 0;
871}
872
873
874int     roar_vs_iterate       (roar_vs_t * vss, int wait, int * error) {
875 struct roar_vio_select vios[3];
876 struct roar_vio_selecttv rtv = {.sec = 0, .nsec = 1};
877 size_t len = 0;
878 ssize_t i;
879 ssize_t ret;
880 int can_read = 0, can_write = 0;
881 int can_flush_stream = 0, can_flush_file = 0;
882 int is_eof = 0;
883 void * data;
884
885 _ckvss(-1);
886
887 if ( wait != ROAR_VS_WAIT && wait != ROAR_VS_NOWAIT ) {
888  _seterr(ROAR_ERROR_INVAL);
889  return -1;
890 }
891
892 ROAR_VIO_SELECT_SETVIO(&(vios[len]), &(vss->vio), ((vss->flags & FLAG_DIR_IN  ? ROAR_VIO_SELECT_READ  : 0) |
893                                                    (vss->flags & FLAG_DIR_OUT ? ROAR_VIO_SELECT_WRITE : 0)));
894 vios[len].ud.vp = &(vss->vio);
895 len++;
896
897 ROAR_VIO_SELECT_SETVIO(&(vios[len]), roar_get_connection_vio2(vss->con), ROAR_VIO_SELECT_READ);
898 vios[len].ud.vp = vss->con;
899 len++;
900
901
902// TODO: FIXME: need to do two select()s so we can sleep more efficently and test for both directions.
903// for the moment we disable file direction and hope it will not block anyway...
904/*
905 if ( vss->file != NULL ) {
906  ROAR_VIO_SELECT_SETVIO(&(vios[len]), vss->file, ((vss->flags & FLAG_DIR_IN  ? ROAR_VIO_SELECT_WRITE : 0) |
907                                                   (vss->flags & FLAG_DIR_OUT ? ROAR_VIO_SELECT_READ  : 0)));
908  vios[len].ud.vp = vss->file;
909  len++;
910 }
911*/
912
913 ret = roar_vio_select(vios, len, (wait == ROAR_VS_NOWAIT ? &rtv : NULL), NULL);
914
915// part 2 of above hack:
916// emulate read handle.
917  vios[len].ud.vp   = vss->file;
918  vios[len].eventsa = ROAR_VIO_SELECT_WRITE|ROAR_VIO_SELECT_READ;;
919  len++;
920
921 // no error here nor EOF.
922 if ( ret == 0 )
923  return 1;
924
925 for (i = 0; i < len; i++) {
926  if ( !vios[i].eventsa )
927   continue;
928
929  if ( vios[i].ud.vp == &(vss->vio) ) {
930   if ( vios[i].eventsa & ROAR_VIO_SELECT_READ )
931    can_read++;
932
933   if ( vios[i].eventsa & ROAR_VIO_SELECT_WRITE ) {
934    can_write++;
935    can_flush_stream = 1;
936   }
937  } else if ( vios[i].ud.vp == vss->con ) {
938   roar_sync(vss->con);
939  } else if ( vios[i].ud.vp == vss->file ) {
940   if ( vios[i].eventsa & ROAR_VIO_SELECT_READ )
941    can_write++;
942
943   if ( vios[i].eventsa & ROAR_VIO_SELECT_WRITE ) {
944    can_read++;
945    can_flush_file = 1;
946   }
947  }
948 }
949
950 // TODO: FIXME: Need to correct error handling here!
951
952 if ( can_flush_stream && vss->writebuffer != NULL ) {
953  if ( roar_buffer_get_data(vss->writebuffer, &data) == -1 )
954   return -1;
955
956  if ( roar_buffer_get_len(vss->writebuffer, &len) == -1 )
957   return -1;
958
959  ret = roar_vs_write(vss, data, len, error);
960
961  if ( ret == -1 ) {
962   return -1;
963  } else if ( ret == len ) {
964   roar_buffer_free(vss->writebuffer);
965   vss->writebuffer = NULL;
966  } else {
967   if ( roar_buffer_set_offset(vss->writebuffer, ret) == -1 )
968    return -1;
969  }
970 }
971
972 if ( can_flush_file && vss->readbuffer != NULL ) {
973  if ( roar_buffer_get_data(vss->readbuffer, &data) == -1 )
974   return -1;
975
976  if ( roar_buffer_get_len(vss->readbuffer, &len) == -1 )
977   return -1;
978
979  ret = roar_vio_write(vss->file, data, len);
980
981  if ( ret == -1 ) {
982   return -1;
983  } else if ( ret == len ) {
984   roar_buffer_free(vss->readbuffer);
985   vss->readbuffer = NULL;
986  } else {
987   if ( roar_buffer_set_offset(vss->readbuffer, ret) == -1 )
988    return -1;
989  }
990 }
991
992#define _READ_SIZE 1024
993
994 if ( can_read == 2 && vss->readbuffer == NULL ) {
995  if ( roar_buffer_new_data(&(vss->readbuffer), (len = _READ_SIZE), &data) == -1 )
996   return -1;
997
998  ret = roar_vs_read(vss, data, len, error);
999
1000  if ( ret == -1 ) {
1001   roar_buffer_free(vss->readbuffer);
1002   vss->readbuffer = NULL;
1003   return -1;
1004  } else if ( ret == 0 ) {
1005   is_eof = 1;
1006   roar_buffer_free(vss->readbuffer);
1007   vss->readbuffer = NULL;
1008  } else {
1009   len = ret;
1010   if ( roar_buffer_set_len(vss->readbuffer, len) == -1 )
1011    return -1;
1012
1013   ret = roar_vio_write(vss->file, data, len);
1014
1015   if ( ret == -1 ) {
1016    return -1;
1017   } else if ( ret == len ) {
1018    roar_buffer_free(vss->readbuffer);
1019    vss->readbuffer = NULL;
1020   } else {
1021    if ( roar_buffer_set_offset(vss->readbuffer, ret) == -1 )
1022     return -1;
1023   }
1024  }
1025 }
1026
1027 if ( can_write == 2 && vss->writebuffer == NULL ) {
1028  if ( roar_buffer_new_data(&(vss->writebuffer), (len = _READ_SIZE), &data) == -1 )
1029   return -1;
1030
1031  ret = roar_vio_read(vss->file, data, len);
1032
1033  ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p): ret=%lli", vss, wait, error, (long long int)ret);
1034
1035  if ( ret == -1 ) {
1036   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1037
1038   roar_buffer_free(vss->writebuffer);
1039   vss->writebuffer = NULL;
1040   return -1;
1041  } else if ( ret == 0 ) {
1042   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1043
1044   is_eof = 1;
1045   roar_buffer_free(vss->writebuffer);
1046   vss->writebuffer = NULL;
1047  } else {
1048   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1049
1050   if ( len != ret ) {
1051    len = ret;
1052    if ( roar_buffer_set_len(vss->writebuffer, len) == -1 )
1053     return -1;
1054   }
1055
1056   ROAR_DBG("roar_vs_iterate(vss=%p, wait=%i, error=%p) = ?", vss, wait, error);
1057
1058   ret = roar_vs_write(vss, data, len, error);
1059
1060   if ( ret == -1 ) {
1061    return -1;
1062   } else if ( ret == len ) {
1063    roar_buffer_free(vss->writebuffer);
1064    vss->writebuffer = NULL;
1065   } else {
1066    if ( roar_buffer_set_offset(vss->writebuffer, ret) == -1 )
1067     return -1;
1068   }
1069  }
1070 }
1071
1072 return is_eof ? 0 : 1;
1073}
1074
1075int     roar_vs_run           (roar_vs_t * vss, int * error) {
1076 int ret;
1077
1078 _ckvss(-1);
1079
1080 while ((ret = roar_vs_iterate(vss, ROAR_VS_WAIT, error)) > 0);
1081
1082 ROAR_DBG("roar_vs_run(vss=%p, error=%p): ret=%i", vss, error, ret);
1083
1084 if ( ret == 0 ) {
1085  // flush buffers:
1086  roar_vs_iterate(vss, ROAR_VS_WAIT, error);
1087 }
1088
1089 if ( roar_vs_sync(vss, ROAR_VS_WAIT, error) == -1 )
1090  return -1;
1091
1092 return ret;
1093}
1094
1095
1096struct roar_connection * roar_vs_connection_obj(roar_vs_t * vss, int * error) {
1097 _ckvss(NULL);
1098
1099 return vss->con;
1100}
1101
1102struct roar_stream     * roar_vs_stream_obj    (roar_vs_t * vss, int * error) {
1103 _ckvss(NULL);
1104
1105 if ( !(vss->flags & FLAG_STREAM) ) {
1106  _seterr(ROAR_ERROR_INVAL);
1107  return NULL;
1108 }
1109
1110 return &(vss->stream);
1111}
1112
1113struct roar_vio_calls  * roar_vs_vio_obj       (roar_vs_t * vss, int * error) {
1114 _ckvss(NULL);
1115
1116 if ( !(vss->flags & FLAG_STREAM) ) {
1117  _seterr(ROAR_ERROR_INVAL);
1118  return NULL;
1119 }
1120
1121 return &(vss->vio);
1122}
1123
1124//ll
Note: See TracBrowser for help on using the repository browser.