source: roaraudio/libroar/vs.c @ 4182:b669a0fb30b8

Last change on this file since 4182:b669a0fb30b8 was 4182:b669a0fb30b8, checked in by phi, 14 years ago

handle setting volume even if stream has diffrent channel setup

File size: 11.6 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
42#define _seterr(x) do { if ( error != NULL ) *error = (x); } while(0)
43
44struct roar_vs {
45 int flags;
46 struct roar_connection con_store;
47 struct roar_connection * con;
48 struct roar_stream       stream;
49 struct roar_vio_calls    vio;
50};
51
52const char * roar_vs_strerr(int error) {
53 const struct {
54  int err;
55  const char * msg;
56 } msgs[] = {
57  {ROAR_ERROR_NONE,        "No error"},
58  {ROAR_ERROR_PERM,        "Operation not permitted"},
59  {ROAR_ERROR_NOENT,       "No such object, file or directory"},
60  {ROAR_ERROR_BADMSG,      "Bad message"},
61  {ROAR_ERROR_BUSY,        "Device or resource busy"},
62  {ROAR_ERROR_CONNREFUSED, "Connection refused"},
63  {ROAR_ERROR_NOSYS,       "Function not implemented"},
64  {ROAR_ERROR_NOTSUP,      "Operation not supported"},
65  {ROAR_ERROR_PIPE,        "Broken pipe"},
66  {ROAR_ERROR_PROTO,       "Protocol error"},
67  {ROAR_ERROR_RANGE,       "Result too large or parameter out of range"},
68  {ROAR_ERROR_MSGSIZE,     "Message too long"},
69  {ROAR_ERROR_NOMEM,       "Not enough space"},
70  {ROAR_ERROR_INVAL,       "Invalid argument"},
71  {-1, NULL}
72 };
73 int i;
74
75 for (i = 0; msgs[i].msg != NULL; i++)
76  if ( msgs[i].err == error )
77   return msgs[i].msg;
78
79 return "(unknown)";
80}
81
82static roar_vs_t * roar_vs_init(int * error) {
83 roar_vs_t * vss = roar_mm_malloc(sizeof(roar_vs_t));
84
85 if ( vss == NULL ) {
86  _seterr(ROAR_ERROR_NOMEM);
87  return NULL;
88 }
89
90 memset(vss, 0, sizeof(roar_vs_t));
91
92 return vss;
93}
94
95roar_vs_t * roar_vs_new_from_con(struct roar_connection * con, int * error) {
96 roar_vs_t * vss = roar_vs_init(error);
97
98 if ( vss == NULL )
99  return NULL;
100
101 vss->con = con;
102
103 return vss;
104}
105
106roar_vs_t * roar_vs_new(const char * server, const char * name, int * error) {
107 roar_vs_t * vss = roar_vs_init(error);
108 int ret;
109
110 if ( vss == NULL )
111  return NULL;
112
113 vss->con = &(vss->con_store);
114
115 ret = roar_simple_connect(vss->con, (char*)server, (char*)name);
116
117 if ( ret == -1 ) {
118  roar_vs_close(vss, ROAR_VS_TRUE, NULL);
119  _seterr(ROAR_ERROR_UNKNOWN);
120  return NULL;
121 }
122
123 return vss;
124}
125
126int roar_vs_stream(roar_vs_t * vss, const struct roar_audio_info * info, int dir, int * error) {
127 int ret;
128
129 if ( vss->flags & FLAG_STREAM ) {
130  _seterr(ROAR_ERROR_INVAL);
131  return -1;
132 }
133
134 ret = roar_vio_simple_new_stream_obj(&(vss->vio), vss->con, &(vss->stream),
135                                      info->rate, info->channels, info->bits, info->codec,
136                                      dir
137                                     );
138
139 if ( ret == -1 ) {
140  _seterr(ROAR_ERROR_UNKNOWN);
141  return -1;
142 }
143
144 vss->flags |= FLAG_STREAM;
145
146 return 0;
147}
148
149roar_vs_t * roar_vs_new_simple(const char * server, const char * name, int rate, int channels, int codec, int bits, int dir, int * error) {
150 roar_vs_t * vss = roar_vs_new(server, name, error);
151 struct roar_audio_info info;
152 int ret;
153
154 if (vss == NULL)
155  return NULL;
156
157 memset(&info, 0, sizeof(info));
158
159 info.rate     = rate;
160 info.channels = channels;
161 info.codec    = codec;
162 info.bits     = bits;
163
164 ret = roar_vs_stream(vss, &info, dir, error);
165
166 if (ret == -1) {
167  roar_vs_close(vss, ROAR_VS_TRUE, NULL);
168  return NULL;
169 }
170
171 return vss;
172}
173
174int roar_vs_close(roar_vs_t * vss, int killit, int * error) {
175 if ( killit != ROAR_VS_TRUE && killit != ROAR_VS_FALSE ) {
176  _seterr(ROAR_ERROR_UNKNOWN);
177  return -1;
178 }
179
180 if ( vss->flags & FLAG_STREAM ) {
181  if ( killit == ROAR_VS_TRUE ) {
182   roar_kick(vss->con, ROAR_OT_STREAM, roar_stream_get_id(&(vss->stream)));
183  }
184
185  roar_vio_close(&(vss->vio));
186 }
187
188 if ( vss->con == &(vss->con_store) ) {
189  roar_disconnect(vss->con);
190 }
191
192 roar_mm_free(vss);
193 return 0;
194}
195
196ssize_t roar_vs_write(roar_vs_t * vss, const void * buf, size_t len, int * error) {
197 ssize_t ret;
198
199 if ( !(vss->flags & FLAG_STREAM) ) {
200  _seterr(ROAR_ERROR_INVAL);
201  return -1;
202 }
203
204 ret = roar_vio_write(&(vss->vio), (void*)buf, len);
205
206 if ( ret == -1 ) {
207  _seterr(ROAR_ERROR_UNKNOWN);
208 }
209
210 return ret;
211}
212
213ssize_t roar_vs_read (roar_vs_t * vss,       void * buf, size_t len, int * error) {
214 ssize_t ret;
215
216 if ( !(vss->flags & FLAG_STREAM) ) {
217  _seterr(ROAR_ERROR_INVAL);
218  return -1;
219 }
220
221 ret = roar_vio_read(&(vss->vio), buf, len);
222
223 if ( ret == -1 ) {
224  _seterr(ROAR_ERROR_UNKNOWN);
225 }
226
227 return ret;
228}
229
230int     roar_vs_sync (roar_vs_t * vss, int wait, int * error) {
231 if ( !(vss->flags & FLAG_STREAM) ) {
232  _seterr(ROAR_ERROR_INVAL);
233  return -1;
234 }
235
236 if ( wait != ROAR_VS_NOWAIT ) {
237  _seterr(ROAR_ERROR_INVAL);
238  return -1;
239 }
240
241 roar_vio_sync(&(vss->vio));
242
243 return 0;
244}
245
246int     roar_vs_blocking (roar_vs_t * vss, int val, int * error) {
247 int old = -1;
248
249  if ( !(vss->flags & FLAG_STREAM) ) {
250  _seterr(ROAR_ERROR_INVAL);
251  return -1;
252 }
253
254 old = vss->flags & FLAG_NONBLOCK ? ROAR_VS_FALSE : ROAR_VS_TRUE;
255
256 switch (val) {
257  case ROAR_VS_TRUE:
258    if ( roar_vio_nonblock(&(vss->vio), ROAR_SOCKET_BLOCK) == -1 ) {
259     _seterr(ROAR_ERROR_UNKNOWN);
260     return -1;
261    }
262    vss->flags |= FLAG_NONBLOCK;
263    vss->flags -= FLAG_NONBLOCK;
264    return old;
265   break;
266  case ROAR_VS_FALSE:
267    if ( roar_vio_nonblock(&(vss->vio), ROAR_SOCKET_NONBLOCK) == -1 ) {
268     _seterr(ROAR_ERROR_UNKNOWN);
269     return -1;
270    }
271    vss->flags |= FLAG_NONBLOCK;
272    return old;
273   break;
274  case ROAR_VS_TOGGLE:
275    if ( old == ROAR_VS_TRUE ) {
276     return roar_vs_blocking(vss, ROAR_VS_FALSE, error);
277    } else {
278     return roar_vs_blocking(vss, ROAR_VS_TRUE, error);
279    }
280   break;
281  case ROAR_VS_ASK:
282    return old;
283   break;
284 }
285
286 _seterr(ROAR_ERROR_INVAL);
287 return -1;
288}
289
290ssize_t roar_vs_latency(roar_vs_t * vss, int backend, int * error) {
291 _seterr(ROAR_ERROR_NOTSUP);
292 return -1;
293}
294
295static int roar_vs_flag(roar_vs_t * vss, int flag, int val, int * error) {
296 struct roar_stream_info info;
297 int old = -1;
298
299 if ( !(vss->flags & FLAG_STREAM) ) {
300  _seterr(ROAR_ERROR_INVAL);
301  return -1;
302 }
303
304 if ( val != ROAR_VS_ASK )
305  old = roar_vs_flag(vss, flag, ROAR_VS_ASK, error);
306
307 switch (val) {
308  case ROAR_VS_TRUE:
309  case ROAR_VS_FALSE:
310    if ( roar_stream_set_flags(vss->con, &(vss->stream), flag,
311                               val == ROAR_VS_TRUE ? ROAR_SET_FLAG : ROAR_RESET_FLAG) == -1 ) {
312     _seterr(ROAR_ERROR_UNKNOWN);
313     return -1;
314    }
315    return old;
316   break;
317  case ROAR_VS_TOGGLE:
318    return roar_vs_flag(vss, flag, old == ROAR_VS_TRUE ? ROAR_VS_FALSE : ROAR_VS_TRUE, error);
319   break;
320  case ROAR_VS_ASK:
321    if ( roar_stream_get_info(vss->con, &(vss->stream), &info) == -1 ) {
322     _seterr(ROAR_ERROR_UNKNOWN);
323     return -1;
324    }
325    return info.flags & flag ? ROAR_VS_TRUE : ROAR_VS_FALSE;
326   break;
327 }
328
329 _seterr(ROAR_ERROR_NOTSUP);
330 return -1;
331}
332
333int     roar_vs_pause(roar_vs_t * vss, int val, int * error) {
334 return roar_vs_flag(vss, ROAR_FLAG_PAUSE, val, error);
335}
336
337int     roar_vs_mute (roar_vs_t * vss, int val, int * error) {
338 return roar_vs_flag(vss, ROAR_FLAG_MUTE, val, error);
339}
340
341static int roar_vs_volume (roar_vs_t * vss, float * c, size_t channels, int * error) {
342 struct roar_mixer_settings mixer;
343 size_t i;
344 register float s;
345 int oldchannels;
346 int handled;
347
348 if ( !(vss->flags & FLAG_STREAM) ) {
349  _seterr(ROAR_ERROR_INVAL);
350  return -1;
351 }
352
353 if ( channels > ROAR_MAX_CHANNELS ) {
354  _seterr(ROAR_ERROR_INVAL);
355  return -1;
356 }
357
358 if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &oldchannels) == -1 ) {
359  _seterr(ROAR_ERROR_UNKNOWN);
360  return -1;
361 }
362
363 for (i = 0; i < channels; i++) {
364  s = c[i] * 65535.0;
365  if ( s > 66190.0 || s < -655.0 ) {
366   _seterr(ROAR_ERROR_RANGE);
367   return -1;
368  } else if ( s > 65535.0 ) {
369   s = 65535.0;
370  } else if ( s <     0.0 ) {
371   s = 0.0;
372  }
373  mixer.mixer[i] = s;
374 }
375
376 mixer.scale = 65535;
377
378 if ( channels != oldchannels ) {
379  handled = 0;
380  switch (oldchannels) {
381   case 1:
382     if ( channels == 2 ) {
383      mixer.mixer[0] = (mixer.mixer[0] + mixer.mixer[1]) / 2;
384      handled = 1;
385     }
386    break;
387   case 2:
388     if ( channels == 1 ) {
389      mixer.mixer[1] = mixer.mixer[0];
390      handled = 1;
391     }
392    break;
393   case 4:
394     if ( channels == 1 ) {
395      mixer.mixer[1] = mixer.mixer[0];
396      mixer.mixer[2] = mixer.mixer[0];
397      mixer.mixer[3] = mixer.mixer[0];
398      handled = 1;
399     } else if ( channels == 2 ) {
400      mixer.mixer[2] = mixer.mixer[0];
401      mixer.mixer[3] = mixer.mixer[1];
402      handled = 1;
403     }
404    break;
405  }
406  if ( handled ) {
407   channels = oldchannels;
408  } else {
409   _seterr(ROAR_ERROR_INVAL);
410   return -1;
411  }
412 }
413
414 if ( roar_set_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, channels) == -1 ) {
415  _seterr(ROAR_ERROR_UNKNOWN);
416  return -1;
417 }
418
419 return 0;
420}
421
422int     roar_vs_volume_mono   (roar_vs_t * vss, float c, int * error) {
423 return roar_vs_volume(vss, &c, 1, error);
424}
425
426int     roar_vs_volume_stereo (roar_vs_t * vss, float l, float r, int * error) {
427 float c[2] = {l, r};
428 return roar_vs_volume(vss, c, 2, error);
429}
430
431int     roar_vs_volume_get    (roar_vs_t * vss, float * l, float * r, int * error) {
432 struct roar_mixer_settings mixer;
433 int channels;
434
435 if ( vss == NULL || l == NULL || r == NULL ) {
436  _seterr(ROAR_ERROR_INVAL);
437  return -1;
438 }
439
440 if ( !(vss->flags & FLAG_STREAM) ) {
441  _seterr(ROAR_ERROR_INVAL);
442  return -1;
443 }
444
445 if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &channels) == -1 ) {
446  _seterr(ROAR_ERROR_UNKNOWN);
447  return -1;
448 }
449
450 if ( channels == 1 )
451  mixer.mixer[1] = mixer.mixer[0];
452
453 *l = mixer.mixer[0] / (float)mixer.scale;
454 *r = mixer.mixer[1] / (float)mixer.scale;
455
456 return 0;
457}
458
459int     roar_vs_meta          (roar_vs_t * vss, struct roar_keyval * kv, size_t len, int * error) {
460 struct roar_meta meta;
461 size_t i;
462 int type;
463 int ret = 0;
464
465 if ( !(vss->flags & FLAG_STREAM) ) {
466  _seterr(ROAR_ERROR_INVAL);
467  return -1;
468 }
469
470 meta.type   = ROAR_META_TYPE_NONE;
471 meta.key[0] = 0;
472 meta.value  = NULL;
473
474 // TODO: add error hadnling here.
475
476 if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_CLEAR, &meta) == -1 ) {
477  _seterr(ROAR_ERROR_UNKNOWN);
478  ret = -1;
479 }
480
481 for (i = 0; i < len; i++) {
482  type = roar_meta_inttype(kv[i].key);
483  meta.type  = type;
484  meta.value = kv[i].value;
485
486  if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_ADD, &meta) == -1 ) {
487   _seterr(ROAR_ERROR_UNKNOWN);
488   ret = -1;
489  }
490 }
491
492 meta.type   = ROAR_META_TYPE_NONE;
493 meta.key[0] = 0;
494 meta.value  = NULL;
495 if ( roar_stream_meta_set(vss->con, &(vss->stream), ROAR_META_MODE_FINALIZE, &meta) == -1 ) {
496  _seterr(ROAR_ERROR_UNKNOWN);
497  ret = -1;
498 }
499
500 return ret;
501}
502
503//ll
Note: See TracBrowser for help on using the repository browser.