source: roaraudio/libroar/vs.c @ 4618:950031048258

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

Corrected error codes in VS API (Closes: #90)

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