source: roaraudio/libroar/vs.c @ 4717:202d623df156

Last change on this file since 4717:202d623df156 was 4717:202d623df156, checked in by phi, 13 years ago

some debug stuff

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