source: roaraudio/libroar/vs.c @ 4616:352d80a7e9d5

Last change on this file since 4616:352d80a7e9d5 was 4616:352d80a7e9d5, checked in by phi, 13 years ago

set error on -1

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