//vs.c: /* * Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010 * * This file is part of libroar a part of RoarAudio, * a cross-platform sound system for both, home and professional use. * See README for details. * * This file is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 * as published by the Free Software Foundation. * * libroar is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; see the file COPYING. If not, write to * the Free Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * * NOTE for everyone want's to change something and send patches: * read README and HACKING! There a addition information on * the license of this document you need to read before you send * any patches. * * NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc * or libpulse*: * The libs libroaresd, libroararts and libroarpulse link this lib * and are therefore GPL. Because of this it may be illigal to use * them with any software that uses libesd, libartsc or libpulse*. */ #include "libroar.h" #define FLAG_NONE 0x0000 #define FLAG_STREAM 0x0001 #define FLAG_NONBLOCK 0x0002 #define _seterr(x) do { if ( error != NULL ) *error = (x); } while(1) struct roar_vs { int flags; struct roar_connection con_store; struct roar_connection * con; struct roar_stream stream; struct roar_vio_calls vio; }; const char * roar_vs_strerr(int error) { const struct { int err; const char * msg; } msgs[] = { {ROAR_ERROR_NONE, "none"}, {ROAR_ERROR_PERM, "perm"}, {ROAR_ERROR_NOENT, "noent"}, {ROAR_ERROR_BADMSG, "badmsg"}, {ROAR_ERROR_BUSY, "busy"}, {ROAR_ERROR_CONNREFUSED, "connrefused"}, {ROAR_ERROR_NOSYS, "nosys"}, {ROAR_ERROR_NOTSUP, "notsup"}, {ROAR_ERROR_PIPE, "pipe"}, {ROAR_ERROR_PROTO, "proto"}, {ROAR_ERROR_RANGE, "range"}, {ROAR_ERROR_MSGSIZE, "msgsize"}, {ROAR_ERROR_NOMEM, "nomem"}, {ROAR_ERROR_INVAL, "inval"}, {-1, NULL} }; int i; for (i = 0; msgs[i].msg != NULL; i++) if ( msgs[i].err == error ) return msgs[i].msg; return "(unknown)"; } static roar_vs_t * roar_vs_init(int * error) { roar_vs_t * vss = roar_mm_malloc(sizeof(roar_vs_t)); if ( vss == NULL ) { _seterr(ROAR_ERROR_NOMEM); return NULL; } memset(vss, 0, sizeof(roar_vs_t)); return vss; } roar_vs_t * roar_vs_new_from_con(struct roar_connection * con, int * error) { roar_vs_t * vss = roar_vs_init(error); if ( vss == NULL ) return NULL; vss->con = con; return vss; } roar_vs_t * roar_vs_new(const char * server, const char * name, int * error) { roar_vs_t * vss = roar_vs_init(error); int ret; if ( vss == NULL ) return NULL; vss->con = &(vss->con_store); ret = roar_simple_connect(vss->con, (char*)server, (char*)name); if ( ret == -1 ) { roar_vs_close(vss, ROAR_VS_TRUE, NULL); _seterr(ROAR_ERROR_UNKNOWN); return NULL; } return vss; } int roar_vs_stream(roar_vs_t * vss, const struct roar_audio_info * info, int dir, int * error) { int ret; if ( vss->flags & FLAG_STREAM ) { _seterr(ROAR_ERROR_INVAL); return -1; } ret = roar_vio_simple_new_stream_obj(&(vss->vio), vss->con, &(vss->stream), info->rate, info->channels, info->bits, info->codec, dir ); if ( ret == -1 ) { _seterr(ROAR_ERROR_UNKNOWN); return -1; } vss->flags |= FLAG_STREAM; return 0; } roar_vs_t * roar_vs_new_simple(const char * server, const char * name, int rate, int channels, int codec, int bits, int dir, int * error) { roar_vs_t * vss = roar_vs_new(server, name, error); struct roar_audio_info info; int ret; if (vss == NULL) return NULL; memset(&info, 0, sizeof(info)); info.rate = rate; info.channels = channels; info.codec = codec; info.bits = bits; ret = roar_vs_stream(vss, &info, dir, error); if (ret == -1) { roar_vs_close(vss, ROAR_VS_TRUE, NULL); return NULL; } return vss; } int roar_vs_close(roar_vs_t * vss, int killit, int * error) { if ( vss->flags & FLAG_STREAM ) { if ( killit ) { roar_kick(vss->con, ROAR_OT_STREAM, roar_stream_get_id(&(vss->stream))); } roar_vio_close(&(vss->vio)); } if ( vss->con == &(vss->con_store) ) { roar_disconnect(vss->con); } roar_mm_free(vss); return 0; } ssize_t roar_vs_write(roar_vs_t * vss, const void * buf, size_t len, int * error) { ssize_t ret; if ( !(vss->flags & FLAG_STREAM) ) { _seterr(ROAR_ERROR_INVAL); return -1; } ret = roar_vio_write(&(vss->vio), (void*)buf, len); if ( ret == -1 ) { _seterr(ROAR_ERROR_UNKNOWN); } return ret; } ssize_t roar_vs_read (roar_vs_t * vss, void * buf, size_t len, int * error) { ssize_t ret; if ( !(vss->flags & FLAG_STREAM) ) { _seterr(ROAR_ERROR_INVAL); return -1; } ret = roar_vio_read(&(vss->vio), buf, len); if ( ret == -1 ) { _seterr(ROAR_ERROR_UNKNOWN); } return ret; } int roar_vs_sync (roar_vs_t * vss, int wait, int * error) { if ( !(vss->flags & FLAG_STREAM) ) { _seterr(ROAR_ERROR_INVAL); return -1; } if ( wait != ROAR_VS_NOWAIT ) { _seterr(ROAR_ERROR_INVAL); return -1; } roar_vio_sync(&(vss->vio)); return 0; } int roar_vs_blocking (roar_vs_t * vss, int val, int * error) { int old = -1; if ( !(vss->flags & FLAG_STREAM) ) { _seterr(ROAR_ERROR_INVAL); return -1; } old = vss->flags & FLAG_NONBLOCK ? ROAR_VS_FALSE : ROAR_VS_TRUE; switch (val) { case ROAR_VS_TRUE: if ( roar_vio_nonblock(&(vss->vio), ROAR_SOCKET_BLOCK) == -1 ) { _seterr(ROAR_ERROR_UNKNOWN); return -1; } vss->flags |= FLAG_NONBLOCK; vss->flags -= FLAG_NONBLOCK; return old; break; case ROAR_VS_FALSE: if ( roar_vio_nonblock(&(vss->vio), ROAR_SOCKET_NONBLOCK) == -1 ) { _seterr(ROAR_ERROR_UNKNOWN); return -1; } vss->flags |= FLAG_NONBLOCK; return old; break; case ROAR_VS_TOGGLE: if ( old == ROAR_VS_TRUE ) { return roar_vs_blocking(vss, ROAR_VS_FALSE, error); } else { return roar_vs_blocking(vss, ROAR_VS_TRUE, error); } break; case ROAR_VS_ASK: return old; break; } _seterr(ROAR_ERROR_INVAL); return -1; } // .................... ssize_t roar_vs_latency(roar_vs_t * vss, int backend, int * error) { _seterr(ROAR_ERROR_NOTSUP); return -1; } static int roar_vs_flag(roar_vs_t * vss, int flag, int val, int * error) { struct roar_stream_info info; int old = -1; if ( !(vss->flags & FLAG_STREAM) ) { _seterr(ROAR_ERROR_INVAL); return -1; } if ( val != ROAR_VS_ASK ) old = roar_vs_flag(vss, flag, ROAR_VS_ASK, error); switch (val) { case ROAR_VS_TRUE: case ROAR_VS_FALSE: if ( roar_stream_set_flags(vss->con, &(vss->stream), flag, val == ROAR_VS_TRUE ? ROAR_SET_FLAG : ROAR_RESET_FLAG) == -1 ) { _seterr(ROAR_ERROR_UNKNOWN); return -1; } return old; break; case ROAR_VS_TOGGLE: return roar_vs_flag(vss, flag, old == ROAR_VS_TRUE ? ROAR_VS_FALSE : ROAR_VS_TRUE, error); break; case ROAR_VS_ASK: if ( roar_stream_get_info(vss->con, &(vss->stream), &info) == -1 ) { _seterr(ROAR_ERROR_UNKNOWN); return -1; } return info.flags & flag ? ROAR_VS_TRUE : ROAR_VS_FALSE; break; } _seterr(ROAR_ERROR_NOTSUP); return -1; } int roar_vs_pause(roar_vs_t * vss, int val, int * error) { return roar_vs_flag(vss, ROAR_FLAG_PAUSE, val, error); } int roar_vs_mute (roar_vs_t * vss, int val, int * error) { return roar_vs_flag(vss, ROAR_FLAG_MUTE, val, error); } static int roar_vs_volume (roar_vs_t * vss, float * c, size_t channels, int * error) { struct roar_mixer_settings mixer; size_t i; if ( !(vss->flags & FLAG_STREAM) ) { _seterr(ROAR_ERROR_INVAL); return -1; } if ( channels > ROAR_MAX_CHANNELS ) { _seterr(ROAR_ERROR_INVAL); return -1; } for (i = 0; i < channels; i++) mixer.mixer[i] = c[i] * 65535.0; mixer.scale = 65535; mixer.rpg_mul = 1; mixer.rpg_div = 1; if ( roar_set_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, channels) == -1 ) { _seterr(ROAR_ERROR_UNKNOWN); return -1; } return 0; } int roar_vs_volume_mono (roar_vs_t * vss, float c, int * error) { return roar_vs_volume(vss, &c, 1, error); } int roar_vs_volume_stereo (roar_vs_t * vss, float l, float r, int * error) { float c[2] = {l, r}; return roar_vs_volume(vss, c, 2, error); } int roar_vs_volume_get (roar_vs_t * vss, float * l, float * r, int * error) { struct roar_mixer_settings mixer; int channels; if ( vss == NULL || l == NULL || r == NULL ) { _seterr(ROAR_ERROR_INVAL); return -1; } if ( !(vss->flags & FLAG_STREAM) ) { _seterr(ROAR_ERROR_INVAL); return -1; } if ( roar_get_vol(vss->con, roar_stream_get_id(&(vss->stream)), &mixer, &channels) == -1 ) { _seterr(ROAR_ERROR_UNKNOWN); return -1; } if ( channels == 1 ) mixer.mixer[1] = mixer.mixer[0]; *l = mixer.mixer[0] / (float)mixer.scale; *r = mixer.mixer[1] / (float)mixer.scale; return 0; } int roar_vs_meta (roar_vs_t * vss, struct roar_keyval * kv, size_t len, int * error); //ll