source: roaraudio/libroar/vs.c @ 4586:a740993657d7

Last change on this file since 4586:a740993657d7 was 4584:959c2d722ca8, checked in by phi, 13 years ago

enable VS file API to handle mime-types

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