source: roaraudio/libroar/vs.c @ 4622:74ea2f012bb1

Last change on this file since 4622:74ea2f012bb1 was 4622:74ea2f012bb1, checked in by phi, 13 years ago

added roar_vs_ctl() for some very advanced controling of VS object

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