diff options
Diffstat (limited to 'lib/libossmix')
-rw-r--r-- | lib/libossmix/.config | 3 | ||||
-rw-r--r-- | lib/libossmix/libossmix_cache.c | 210 | ||||
-rw-r--r-- | lib/libossmix/libossmix_impl.h | 36 | ||||
-rw-r--r-- | lib/libossmix/libossmix_local.c | 332 | ||||
-rw-r--r-- | lib/libossmix/libossmix_main.c | 238 | ||||
-rw-r--r-- | lib/libossmix/libossmix_tcp.c | 813 |
6 files changed, 1632 insertions, 0 deletions
diff --git a/lib/libossmix/.config b/lib/libossmix/.config new file mode 100644 index 0000000..3d02eca --- /dev/null +++ b/lib/libossmix/.config @@ -0,0 +1,3 @@ +mode=shlib +forgetos=BeOS +forgetos=VxWorks diff --git a/lib/libossmix/libossmix_cache.c b/lib/libossmix/libossmix_cache.c new file mode 100644 index 0000000..a15fbf4 --- /dev/null +++ b/lib/libossmix/libossmix_cache.c @@ -0,0 +1,210 @@ +/* + * + * This file is part of Open Sound System. + * + * Copyright (C) 4Front Technologies 1996-2008. + * + * This this source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + */ +/* + * Settings cache for libossmix + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <soundcard.h> +#include <fcntl.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <fcntl.h> +#include <errno.h> +#include <netdb.h> + +#define OSSMIX_REMOTE + +#include "libossmix.h" +#include "libossmix_impl.h" + +static local_mixer_t *mixers[MAX_TMP_MIXER] = { NULL }; + +void +mixc_add_node (int mixernum, int node, oss_mixext * ext) +{ + local_mixer_t *lmixer; + oss_mixext *lnode; + + if (mixers[mixernum] == NULL) + { + int i; + + mixers[mixernum] = lmixer = malloc (sizeof (*lmixer)); + if (lmixer == NULL) + { + fprintf (stderr, "mixc_add_node: Out of memory\n"); + exit (EXIT_FAILURE); + } + + memset (lmixer, 0, sizeof (*lmixer)); + for (i = 0; i < MAX_TMP_NODES; i++) + lmixer->values[i] = -1; // Invalid + } + else + lmixer = mixers[mixernum]; + + if (ext->ctrl >= lmixer->nrext) + lmixer->nrext = ext->ctrl + 1; + + if (node >= MAX_TMP_NODES) + { + fprintf (stderr, "mixc_add_node: Node number too large %d\n", node); + exit (EXIT_FAILURE); + } + + lnode = lmixer->nodes[node]; + + if (lnode == NULL) + { + lmixer->nodes[node] = lnode = malloc (sizeof (*lnode)); + + if (lnode == NULL) + { + fprintf (stderr, "mixc_get_node: Out of memory\n"); + exit (EXIT_FAILURE); + } + } + + memcpy (lnode, ext, sizeof (*ext)); + +} + +oss_mixext * +mixc_get_node (int mixernum, int node) +{ + local_mixer_t *lmixer; + oss_mixext *lnode; + + if (mixers[mixernum] == NULL) + { + return NULL; + } + lmixer = mixers[mixernum]; + + if (node >= MAX_TMP_NODES) + { + fprintf (stderr, "mixc_get_node: Node number too large %d\n", node); + exit (EXIT_FAILURE); + } + + lnode = lmixer->nodes[node]; + + return lnode; +} + +void +mixc_clear_changeflags(int mixernum) +{ + local_mixer_t *lmixer; + + if (mixers[mixernum] == NULL) + { + return; + } + lmixer = mixers[mixernum]; + + memset(lmixer->changemask, 0, sizeof(lmixer->changemask)); +} + +void +mixc_set_value (int mixernum, int node, int value) +{ + local_mixer_t *lmixer; + + if (mixers[mixernum] == NULL) + { + return; + } + lmixer = mixers[mixernum]; + + if (node >= MAX_TMP_NODES) + { + fprintf (stderr, "mixc_set_value: Node number too large %d\n", node); + exit (EXIT_FAILURE); + } + + if (lmixer->values[node] != value) + lmixer->changemask[node / 8] |= (1 << (node % 8)); + + lmixer->values[node] = value; +} + +int +mixc_get_value (int mixernum, int node) +{ + local_mixer_t *lmixer; + + if (mixers[mixernum] == NULL) + { + return -1; + } + lmixer = mixers[mixernum]; + + if (node >= MAX_TMP_NODES) + { + fprintf (stderr, "mixc_get_value: Node number too large %d\n", node); + exit (EXIT_FAILURE); + } + lmixer->changemask[node / 8] &= ~(1 << (node % 8)); + + return lmixer->values[node]; +} + +int +mixc_get_all_values (int mixernum, value_packet_t value_packet, int changecheck) +{ + int i, n = 0; + oss_mixext *lnode; + local_mixer_t *lmixer; + + if (mixers[mixernum] == NULL) + { + fprintf (stderr, "mixc_get_all_values: Mixer %d doesn't exist\n", + mixernum); + return 0; + } + lmixer = mixers[mixernum]; + + for (i = 0; i < lmixer->nrext; i++) + { + lnode = lmixer->nodes[i]; + + if (lnode == NULL) + { + fprintf (stderr, "mixc_get_all_values: Mixer %d, node %d == NULL\n", + mixernum, i); + continue; + } + + if (changecheck) // Not changed since the last time + if (!(lmixer->changemask[i / 8] & (1 << (i % 8)) )) + continue; + + if (lnode->type != MIXT_DEVROOT && lnode->type != MIXT_GROUP + && lnode->type != MIXT_MARKER) + { + value_packet[n].node = i; + value_packet[n].value = lmixer->values[i]; + + lmixer->changemask[i / 8] &= ~(1 << (i % 8)); + +//printf("Send %d = %08x\n", i, lmixer->values[i]); + n++; + } + } + + return n; +} diff --git a/lib/libossmix/libossmix_impl.h b/lib/libossmix/libossmix_impl.h new file mode 100644 index 0000000..3848166 --- /dev/null +++ b/lib/libossmix/libossmix_impl.h @@ -0,0 +1,36 @@ +/* + * + * This file is part of Open Sound System. + * + * Copyright (C) 4Front Technologies 1996-2008. + * + * This this source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + */ + +extern int mixlib_trace; + +typedef struct +{ + int (*connect) (const char *hostname, int port); + int (*get_fd) (ossmix_select_poll_t * cb); + void (*disconnect) (void); + void (*enable_events) (void); + int (*get_nmixers) (void); + int (*get_mixerinfo) (int mixernum, oss_mixerinfo * mi); + int (*open_mixer) (int mixernum); + void (*close_mixer) (int mixernum); + int (*get_nrext) (int mixernum); + int (*get_nodeinfo) (int mixernum, int node, oss_mixext * ext); + int (*get_enuminfo) (int mixernum, int node, oss_mixer_enuminfo * ei); + int (*get_description) (int mixernum, int node, oss_mixer_enuminfo * desc); + int (*get_value) (int mixernum, int ctl, int timestamp); + void (*set_value) (int mixernum, int ctl, int timestamp, int value); + void (*timertick)(void); +} ossmix_driver_t; + +extern ossmix_driver_t ossmix_local_driver, ossmix_tcp_driver; +extern void _client_event (int cmd, int p1, int p2, int p3, int p4, int p5); +extern int _ossmix_refresh_mixer(int mixernum, int prev_nmixers); diff --git a/lib/libossmix/libossmix_local.c b/lib/libossmix/libossmix_local.c new file mode 100644 index 0000000..22d39f7 --- /dev/null +++ b/lib/libossmix/libossmix_local.c @@ -0,0 +1,332 @@ +/* + * + * This file is part of Open Sound System. + * + * Copyright (C) 4Front Technologies 1996-2008. + * + * This this source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + */ +/* + * Local driver for libossmix + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <errno.h> + +#include <soundcard.h> + +#define OSSMIX_REMOTE + +#include "libossmix.h" +#include "libossmix_impl.h" + +static int global_fd = -1; +static int num_mixers=0; + +static int mixer_fd[MAX_TMP_MIXER]; + +static int +local_connect (const char *hostname, int port) +{ + char *devmixer; + int i; + + if (mixlib_trace > 0) + fprintf (stderr, "Entered local_connect()\n"); + + for (i = 0; i < MAX_TMP_MIXER; i++) + mixer_fd[i] = -1; + + if ((devmixer = getenv ("OSS_MIXERDEV")) == NULL) + devmixer = "/dev/mixer"; + +/* + * Open the mixer device + */ + if ((global_fd = open (devmixer, O_RDWR, 0)) == -1) + { + perror (devmixer); + return -1; + } + + return 0; +} + +static void +local_disconnect (void) +{ + if (mixlib_trace > 0) + fprintf (stderr, "Entered local_disconnect()\n"); + + if (global_fd >= 0) + close (global_fd); + + global_fd = -1; +} + +static void +local_enable_events (void) +{ +} + +static int +local_get_fd (ossmix_select_poll_t * cb) +{ + *cb = NULL; + return -1; /* No poll handling required */ +} + +static int +local_get_nmixers (void) +{ + oss_sysinfo si; + + if (ioctl (global_fd, SNDCTL_SYSINFO, &si) == -1) + { + perror ("SNDCTL_SYSINFO"); + return -1; + } + + return num_mixers = si.nummixers; +} + +static int +local_get_mixerinfo (int mixernum, oss_mixerinfo * mi) +{ + mi->dev = mixernum; + + if (ioctl (global_fd, SNDCTL_MIXERINFO, mi) == -1) + { + perror ("SNDCTL_MIXERINFO"); + return -1; + } + + return 0; +} + +static int +local_open_mixer (int mixernum) +{ + oss_mixerinfo mi; + + if (mixer_fd[mixernum] > -1) + return 0; + + if (ossmix_get_mixerinfo (mixernum, &mi) < 0) + return -1; + +//fprintf(stderr, "local_open_mixer(%d: %s)\n", mixernum, mi.devnode); + + if ((mixer_fd[mixernum] = open (mi.devnode, O_RDWR, 0)) == -1) + { + perror (mi.devnode); + return -1; + } + + return 0; +} + +static void +local_close_mixer (int mixernum) +{ +//fprintf(stderr, "local_close_mixer(%d)\n", mixernum); + + if (mixer_fd[mixernum] == -1) + return; + + close (mixer_fd[mixernum]); + mixer_fd[mixernum] = -1; +} + +static int +local_get_nrext (int mixernum) +{ + int n = -1; + + if (ioctl (mixer_fd[mixernum], SNDCTL_MIX_NREXT, &n) == -1) + { + perror ("SNDCTL_MIX_NREXT"); + return -1; + } + + return n; +} + +static int +local_get_nodeinfo (int mixernum, int node, oss_mixext * ext) +{ + ext->dev = mixernum; + ext->ctrl = node; + + if (ioctl (mixer_fd[mixernum], SNDCTL_MIX_EXTINFO, ext) == -1) + { + perror ("SNDCTL_MIX_EXTINFO"); + return -1; + } + + mixc_add_node (mixernum, node, ext); + return 0; +} + +static int +local_get_enuminfo (int mixernum, int node, oss_mixer_enuminfo * ei) +{ + ei->dev = mixernum; + ei->ctrl = node; + + if (ioctl (mixer_fd[mixernum], SNDCTL_MIX_ENUMINFO, ei) == -1) + { + perror ("SNDCTL_MIX_ENUMINFO"); + return -1; + } + + return 0; +} + +static int +local_get_description (int mixernum, int node, oss_mixer_enuminfo * desc) +{ + desc->dev = mixernum; + desc->ctrl = node; + + if (ioctl (mixer_fd[mixernum], SNDCTL_MIX_DESCRIPTION, desc) == -1) + { + perror ("SNDCTL_MIX_DESCRIPTION"); + return -1; + } + + return 0; +} + +static int +local_get_value (int mixernum, int ctl, int timestamp) +{ + oss_mixer_value val; + + val.dev = mixernum; + val.ctrl = ctl; + val.timestamp = timestamp; + + if (ioctl (mixer_fd[mixernum], SNDCTL_MIX_READ, &val) == -1) + { + perror ("SNDCTL_MIX_READ"); + return -1; + } + + mixc_set_value (mixernum, ctl, val.value); + return val.value; +} + +static int +private_get_value (int mixernum, int ctl, int timestamp) +{ + oss_mixer_value val; + + val.dev = mixernum; + val.ctrl = ctl; + val.timestamp = timestamp; + + if (ioctl (mixer_fd[mixernum], SNDCTL_MIX_READ, &val) == -1) + { + perror ("SNDCTL_MIX_READ"); + return -1; + } + + return val.value; +} + +static void +local_set_value (int mixernum, int ctl, int timestamp, int value) +{ + oss_mixer_value val; + + val.dev = mixernum; + val.ctrl = ctl; + val.timestamp = timestamp; + val.value = value; + + if (ioctl (mixer_fd[mixernum], SNDCTL_MIX_WRITE, &val) == -1) + { + perror ("SNDCTL_MIX_WRITE"); + } + mixc_set_value (mixernum, ctl, val.value); +} + +static void +update_values (int mixernum) +{ + oss_mixext *ext; + int i; + int nrext; + int value, prev_value; + + nrext = ossmix_get_nrext (mixernum); + + for (i = 0; i < nrext; i++) + { + if ((ext = mixc_get_node (mixernum, i)) == NULL) + { + continue; + } + + if (ext->type == MIXT_DEVROOT || ext->type == MIXT_GROUP + || ext->type == MIXT_MARKER) + continue; + + prev_value = mixc_get_value (mixernum, i); + + if ((value = private_get_value (mixernum, i, ext->timestamp)) < 0) + continue; + // TODO check for EIDRM + + if (value != prev_value) + { + mixc_set_value (mixernum, i, value); + _client_event (OSSMIX_EVENT_VALUE, mixernum, i, value, 0, 0); + } + + } +} + +static void +local_timertick(void) +{ + int mixernum, n; + + for (mixernum=0;mixernum<num_mixers;mixernum++) + if (mixer_fd[mixernum] >= 0) /* Open */ + { + update_values (mixernum); + } + + n=ossmix_get_nmixers(); + if (n>num_mixers) + { + num_mixers=n; + _client_event (OSSMIX_EVENT_NEWMIXER, n, 0, 0, 0, 0); + } +} + +ossmix_driver_t ossmix_local_driver = { + local_connect, + local_get_fd, + local_disconnect, + local_enable_events, + local_get_nmixers, + local_get_mixerinfo, + local_open_mixer, + local_close_mixer, + local_get_nrext, + local_get_nodeinfo, + local_get_enuminfo, + local_get_description, + local_get_value, + local_set_value, + local_timertick +}; diff --git a/lib/libossmix/libossmix_main.c b/lib/libossmix/libossmix_main.c new file mode 100644 index 0000000..a2b3597 --- /dev/null +++ b/lib/libossmix/libossmix_main.c @@ -0,0 +1,238 @@ +/* + * + * This file is part of Open Sound System. + * + * Copyright (C) 4Front Technologies 1996-2008. + * + * This this source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + */ +/* + * Main module for libossmix + */ +#include <stdio.h> +#include <soundcard.h> + +#include "libossmix.h" +#include "libossmix_impl.h" + +static ossmix_driver_t *mixer_driver = NULL; +int mixlib_trace = 0; +static int num_mixers = 0; + +ossmix_callback_t event_callback = NULL; + +int +ossmix_init (void) +{ + if (mixlib_trace > 0) + fprintf (stderr, "ossmix_init() called\n"); + return 0; +} + +void +ossmix_close (void) +{ + if (mixlib_trace > 0) + fprintf (stderr, "ossmix_close() called\n"); +} + +void +_client_event (int event, int p1, int p2, int p3, int p4, int p5) +{ + /* + * To be called only by the internals of ossmixlib + */ + + if (event_callback != NULL) + { + ossmix_callback_parm_t parm; + + parm.event = event; + parm.p1 = p1; + parm.p2 = p2; + parm.p3 = p3; + parm.p4 = p4; + parm.p5 = p5; + event_callback (&parm); + } +} + +int +ossmix_connect (const char *hostname, int port) +{ + if (mixlib_trace > 0) + fprintf (stderr, "ossmix_connect(%s, %d)) called\n", hostname, port); + + if (hostname == NULL) + mixer_driver = &ossmix_local_driver; + else + mixer_driver = &ossmix_tcp_driver; + + event_callback = NULL; + + return mixer_driver->connect (hostname, port); +} + +int +ossmix_get_fd (ossmix_select_poll_t * cb) +{ + return mixer_driver->get_fd (cb); +} + +void +ossmix_set_callback (ossmix_callback_t cb) +{ + event_callback = cb; + mixer_driver->enable_events (); +} + +void +ossmix_disconnect (void) +{ + if (mixlib_trace > 0) + fprintf (stderr, "ossmix_disconnect() called\n"); + + event_callback = NULL; + + mixer_driver->disconnect (); +} + +int +ossmix_get_nmixers (void) +{ + if (mixlib_trace > 0) + fprintf (stderr, "ossmix_get_nmixes() called\n"); + return (num_mixers = mixer_driver->get_nmixers ()); +} + +int +ossmix_get_mixerinfo (int mixernum, oss_mixerinfo * mi) +{ + if (mixernum >= num_mixers) + { + fprintf (stderr, "ossmix_get_mixerinfo: Bad mixer number (%d >= %d)\n", + mixernum, num_mixers); + return -1; + } + + return mixer_driver->get_mixerinfo (mixernum, mi); +} + +int +ossmix_open_mixer (int mixernum) +{ + if (mixernum >= num_mixers) + { + fprintf (stderr, "ossmix_open_mixer: Bad mixer number (%d >= %d)\n", + mixernum, num_mixers); + return -1; + } + return mixer_driver->open_mixer (mixernum); +} + +void +ossmix_close_mixer (int mixernum) +{ + if (mixernum >= num_mixers) + { + fprintf (stderr, "ossmix_close_mixer: Bad mixer number (%d >= %d)\n", + mixernum, num_mixers); + return; + } + + mixer_driver->close_mixer (mixernum); +} + +int +ossmix_get_nrext (int mixernum) +{ + if (mixernum >= num_mixers) + { + fprintf (stderr, "ossmix_get_nrext: Bad mixer number (%d >= %d)\n", + mixernum, num_mixers); + return -1; + } + return mixer_driver->get_nrext (mixernum); +} + +int +ossmix_get_nodeinfo (int mixernum, int node, oss_mixext * ext) +{ + if (mixernum >= num_mixers) + { + fprintf (stderr, "ossmix_get_nodeinfo: Bad mixer number (%d >= %d)\n", + mixernum, num_mixers); + return -1; + } + return mixer_driver->get_nodeinfo (mixernum, node, ext); +} + +int +ossmix_get_enuminfo (int mixernum, int node, oss_mixer_enuminfo * ei) +{ + if (mixernum >= num_mixers) + { + fprintf (stderr, "ossmix_get_enuminfo: Bad mixer number (%d >= %d)\n", + mixernum, num_mixers); + return -1; + } + return mixer_driver->get_enuminfo (mixernum, node, ei); +} + +int +ossmix_get_description (int mixernum, int node, oss_mixer_enuminfo * desc) +{ + if (mixernum >= num_mixers) + { + fprintf (stderr, + "ossmix_get_description: Bad mixer number (%d >= %d)\n", + mixernum, num_mixers); + return -1; + } + return mixer_driver->get_description (mixernum, node, desc); +} + +int +ossmix_get_value (int mixernum, int node, int timestamp) +{ + if (mixernum >= num_mixers) + { + fprintf (stderr, "ossmix_get_value: Bad mixer number (%d >= %d)\n", + mixernum, num_mixers); + return -1; + } + return mixer_driver->get_value (mixernum, node, timestamp); +} + +void +ossmix_set_value (int mixernum, int node, int timestamp, int value) +{ + if (mixernum >= num_mixers) + { + fprintf (stderr, "ossmix_set_value: Bad mixer number (%d >= %d)\n", + mixernum, num_mixers); + return; + } + + mixer_driver->set_value (mixernum, node, timestamp, value); +} + +void +ossmix_timertick(void) +{ + mixer_driver->timertick(); +} + +/* + * Internal use functions (not to be used by applications) + */ +int +_ossmix_refresh_mixer(int mixernum, int prev_nmixers) +{ +printf("_ossmix_refresh_mixer(%d, %d) called\n", mixernum, prev_nmixers); + + return prev_nmixers; // TODO +} diff --git a/lib/libossmix/libossmix_tcp.c b/lib/libossmix/libossmix_tcp.c new file mode 100644 index 0000000..a5da6f6 --- /dev/null +++ b/lib/libossmix/libossmix_tcp.c @@ -0,0 +1,813 @@ +/* + * + * This file is part of Open Sound System. + * + * Copyright (C) 4Front Technologies 1996-2008. + * + * This this source file is released under GPL v2 license (no other versions). + * See the COPYING file included in the main directory of this source + * distribution for the license terms and conditions. + * + */ +/* + * TCP driver for libossmix + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <soundcard.h> +#include <fcntl.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <fcntl.h> +#include <errno.h> +#include <netdb.h> + +#define OSSMIX_REMOTE + +#include "libossmix.h" +#include "libossmix_impl.h" + +static int initialized = 0; +static void tcp_disconnect (void); +static int sockfd = -1; +static int do_byteswap = 0; + +static void poll_callback (void); +static void handle_packet (ossmix_commad_packet_t * msg, char *payload, + int payload_size); + +static int +read_all (int sock, void *b, int count) +{ + unsigned char *buf = b; + int l = 0; + + while (l < count) + { + int c, n = count - l; + + if ((c = read (sock, buf + l, n)) <= 0) + return c; + + l += c; + } + + return l; +} + +static inline int +bswap32 (int x) +{ + + int y = 0; + unsigned char *a = ((unsigned char *) &x) + 3; + unsigned char *b = (unsigned char *) &y; + + *b++ = *a--; + *b++ = *a--; + *b++ = *a--; + *b++ = *a--; + + return y; +} + +#define BSWAP32(x) x=bswap32(x) + +static void +byteswap_msg (ossmix_commad_packet_t * msg) +{ + BSWAP32 (msg->cmd); + BSWAP32 (msg->p1); + BSWAP32 (msg->p2); + BSWAP32 (msg->p3); + BSWAP32 (msg->p4); + BSWAP32 (msg->p5); + BSWAP32 (msg->ack_rq); + BSWAP32 (msg->unsolicited); + BSWAP32 (msg->payload_size); +} + +typedef void (*bswap_func_t) (void *data, int len); + +static void +bswap_int_array (void *data, int len) +{ + int *arr = (int *) data; + int i; + + if (len % sizeof (int) != 0) + { + fprintf (stderr, "bswap_int_array: Bad size %d\n", len); + exit (EXIT_FAILURE); + } + + for (i = 0; i < len / sizeof (int); i++) + BSWAP32 (arr[i]); +} + +static void +bswap_mixerinfo (void *data, int len) +{ + oss_mixerinfo *mi = (oss_mixerinfo *) data; + + if (len != sizeof (*mi)) + { + fprintf (stderr, "bswap_mixerinfo: Bad size (%d/%lu)\n", len, + (unsigned long)sizeof (*mi)); + exit (EXIT_FAILURE); + } + + BSWAP32 (mi->dev); + BSWAP32 (mi->modify_counter); + BSWAP32 (mi->card_number); + BSWAP32 (mi->port_number); + BSWAP32 (mi->magic); + BSWAP32 (mi->enabled); + BSWAP32 (mi->caps); + BSWAP32 (mi->flags); + BSWAP32 (mi->nrext); + BSWAP32 (mi->priority); + BSWAP32 (mi->legacy_device); +} + +static void +bswap_nodeinfo (void *data, int len) +{ + oss_mixext *ei = (oss_mixext *) data; + + if (len != sizeof (*ei)) + { + fprintf (stderr, "bswap_nodeinfo: Bad size (%d/%lu)\n", len, + (unsigned long)sizeof (*ei)); + exit (EXIT_FAILURE); + } + + BSWAP32 (ei->dev); + BSWAP32 (ei->ctrl); + BSWAP32 (ei->type); + BSWAP32 (ei->maxvalue); + BSWAP32 (ei->minvalue); + BSWAP32 (ei->flags); + BSWAP32 (ei->parent); + BSWAP32 (ei->dummy); + BSWAP32 (ei->timestamp); + BSWAP32 (ei->control_no); + BSWAP32 (ei->desc); + BSWAP32 (ei->update_counter); + BSWAP32 (ei->rgbcolor); +} + +static void +bswap_nodeinfo_array (void *data, int len) +{ + oss_mixext *ei = (oss_mixext *) data; + int i, n; + + n = len / sizeof (oss_mixext); + + if (len != n * sizeof (oss_mixext)) + { + fprintf (stderr, "bswap_enuminfo_array: Bad size (%d/%d*%lu)\n", len, n, + (unsigned long)sizeof (*ei)); + exit (EXIT_FAILURE); + } + + for (i = 0; i < n; i++) + bswap_nodeinfo ((void *) &ei[i], sizeof (oss_mixext)); + +} + + +static void +bswap_enuminfo (void *data, int len) +{ + oss_mixer_enuminfo *ei = (oss_mixer_enuminfo *) data; + + int i; + + if (len != sizeof (*ei)) + { + fprintf (stderr, "bswap_enuminfo: Bad size (%d/%lu)\n", len, + (unsigned long)sizeof (*ei)); + exit (EXIT_FAILURE); + } + + BSWAP32 (ei->dev); + BSWAP32 (ei->ctrl); + BSWAP32 (ei->nvalues); + BSWAP32 (ei->version); + + for (i = 0; i < OSS_ENUM_MAXVALUE; i++) + BSWAP32 (ei->strindex[i]); +} + +static int +get_response (void) +{ + ossmix_commad_packet_t msg; + char payload[4096]; + int l; + + if (sockfd == -1) + return -1; + + while (1) + { + payload[0] = 0; + + if ((l = read_all (sockfd, &msg, sizeof (msg))) != sizeof (msg)) + { + if (l == 0) /* Connection closed */ + return -1; + + perror ("get response"); + return -1; + } + + if (do_byteswap) + byteswap_msg (&msg); + + if (msg.payload_size > 0) + { + if ((l = + read_all (sockfd, payload, + msg.payload_size)) != msg.payload_size) + { + perror ("Get response payload"); + fprintf (stderr, "Payload size %d/%d\n", l, msg.payload_size); + return -1; + } + + payload[l] = 0; + } + + if (msg.cmd == OSSMIX_CMD_ERROR) + { + fprintf (stderr, "Remote error: %s\n", payload); + } + + /* + * Return if this was not an async notification message sent by the + * server. + */ + if (!msg.unsolicited) + return msg.cmd; + + handle_packet (&msg, payload, msg.payload_size); + } +} + +static int +check_welcome (void) +{ + ossmix_commad_packet_t msg; + int l; + + if (sockfd == -1) + return 0; + + if ((l = read_all (sockfd, &msg, sizeof (msg))) != sizeof (msg)) + { + if (l == 0) /* Connection closed */ + return 0; + + perror ("get response"); + return 0; + } + + if (msg.cmd != OSSMIX_CMD_HALOO) + { + fprintf (stderr, "Bad welcome from the remote server\n"); + return 0; + } + + do_byteswap = 0; + + if (msg.p1 != OSSMIX_P1_MAGIC) + { + byteswap_msg (&msg); + + if (msg.p1 != OSSMIX_P1_MAGIC) + { + fprintf (stderr, "Unrecognized endianess\n"); + return 0; + } + + fprintf (stderr, "Using alien endianess\n"); + do_byteswap = 1; + } + + return 1; +} + +static int +wait_payload (void *payload, int len, bswap_func_t swapper, int *truelen) +{ + ossmix_commad_packet_t msg; + int l; + + if (sockfd == -1) + return -1; + + while (1) + { + if ((l = read_all (sockfd, &msg, sizeof (msg))) != sizeof (msg)) + { + if (l == 0) /* Connection closed */ + return -1; + + perror ("get response"); + return -1; + } + + if (do_byteswap) + byteswap_msg (&msg); + + if (msg.payload_size > 0) + { + if ((l = + read_all (sockfd, payload, + msg.payload_size)) != msg.payload_size) + { + perror ("Get error message"); + fprintf (stderr, "Payload size %d/%d\n", l, msg.payload_size); + return -1; + } + } + + if (msg.cmd == OSSMIX_CMD_ERROR) + { + fprintf (stderr, "Remote error: %s\n", (char *)payload); + } + + if (!msg.unsolicited) + if (truelen == NULL) + if (msg.payload_size != len) + { + fprintf (stderr, "Payload size mismatch (%d/%d)\n", + msg.payload_size, len); + return -1; + } + + if (truelen != NULL) + *truelen = msg.payload_size; + + /* + * Return if this was not an async notification message sent by the + * server. + */ + if (!msg.unsolicited) + return msg.cmd; + + handle_packet (&msg, payload, msg.payload_size); + } +} + +int +send_request (int cmd, int p1, int p2, int p3, int p4, int p5) +{ + ossmix_commad_packet_t msg; + + memset (&msg, 0, sizeof (msg)); + + msg.cmd = cmd; + msg.p1 = p1; + msg.p2 = p2; + msg.p3 = p3; + msg.p4 = p4; + msg.p5 = p5; + msg.ack_rq = 1; + + if (do_byteswap) + byteswap_msg (&msg); + + if (write (sockfd, &msg, sizeof (msg)) != sizeof (msg)) + { + fprintf (stderr, "Write to socket failed\n"); + } + return get_response (); +} + +void +send_request_noreply (int cmd, int p1, int p2, int p3, int p4, int p5) +{ + ossmix_commad_packet_t msg; + + memset (&msg, 0, sizeof (msg)); + + msg.cmd = cmd; + msg.p1 = p1; + msg.p2 = p2; + msg.p3 = p3; + msg.p4 = p4; + msg.p5 = p5; + msg.ack_rq = 0; + + if (do_byteswap) + byteswap_msg (&msg); + + if (write (sockfd, &msg, sizeof (msg)) != sizeof (msg)) + { + fprintf (stderr, "Write to socket failed\n"); + } + //send(sockfd, &msg, sizeof(msg), 0); +} + +int +send_request_long (int cmd, int p1, int p2, int p3, int p4, int p5, + const char *payload) +{ + ossmix_commad_packet_t msg; + + memset (&msg, 0, sizeof (msg)); + + msg.cmd = cmd; + msg.p1 = p1; + msg.p2 = p2; + msg.p3 = p3; + msg.p4 = p4; + msg.p5 = p5; + msg.ack_rq = 1; + msg.payload_size = strlen (payload); + + if (do_byteswap) + byteswap_msg (&msg); + + if (write (sockfd, &msg, sizeof (msg)) != sizeof (msg)) + { + fprintf (stderr, "Write to socket failed\n"); + } + if (write (sockfd, payload, msg.payload_size) != msg.payload_size) + { + fprintf (stderr, "Write to socket failed\n"); + } + return get_response (); +} + +static int +tcp_connect (const char *remotehost, int port) +{ + struct sockaddr_in sa; + struct hostent *he; + + if (mixlib_trace > 0) + fprintf (stderr, "Entered tcp_connect(%s, %d)\n", remotehost, port); + + if (port == 0) + port = 7777; + + if (initialized) + { + fprintf (stderr, "Panic: ossmixlib already initialized\n"); + exit (EXIT_FAILURE); + } + + initialized = 1; + + /* + * Open the network connection + */ + + if ((sockfd = socket (PF_INET, SOCK_STREAM, 0)) == -1) + { + perror ("socket"); + return -1; + } + + if ((he = gethostbyname (remotehost)) == NULL) + { + herror (remotehost); + fprintf (stderr, "Cannot find the OSSMIX server \"%s\"\n", remotehost); + return -1; + } + + sa.sin_family = AF_INET; + sa.sin_port = htons (port); + + memcpy ((void *) &sa.sin_addr, *he->h_addr_list, he->h_length); + if (connect (sockfd, (void *) &sa, sizeof (sa)) == -1) + { + switch (errno) + { + case ECONNREFUSED: + fprintf (stderr, + "Remote OSSMIX server is not running (Connection refused)\n"); + break; + + default: + perror ("connect"); + } + fprintf (stderr, "Cannot connect OSSMIX server %s:%d\n", remotehost, + port); + return -1; + } +#if 0 +// For some reason this doesn't work under Linux + atexit (tcp_disconnect); +#endif + + if (!check_welcome ()) + return -1; + return send_request (OSSMIX_CMD_INIT, 0, 0, 0, 0, 0); +} + +static int +tcp_get_fd (ossmix_select_poll_t * cb) +{ + *cb = poll_callback; + + return sockfd; +} + +static void +tcp_enable_events (void) +{ + send_request_noreply (OSSMIX_CMD_START_EVENTS, 0, 0, 0, 0, 0); +} + +static void +tcp_disconnect (void) +{ + if (mixlib_trace > 0) + fprintf (stderr, "Entered tcp_disconnect()\n"); + + if (sockfd < 0) + return; + + send_request (OSSMIX_CMD_EXIT, 0, 0, 0, 0, 0); + close (sockfd); + sockfd = -1; +} + +static int +tcp_get_nmixers (void) +{ + int nmixers; + + nmixers = send_request (OSSMIX_CMD_GET_NMIXERS, 0, 0, 0, 0, 0); + + // TODO: num_mixers = nmixers; + + return nmixers; +} + +static int +tcp_get_mixerinfo (int mixernum, oss_mixerinfo * mi) +{ + send_request_noreply (OSSMIX_CMD_GET_MIXERINFO, mixernum, 0, 0, 0, 0); + return wait_payload (mi, sizeof (*mi), bswap_mixerinfo, NULL); +} + +static int +tcp_open_mixer (int mixernum) +{ + int nrext, nrext2; + oss_mixext nodes[MAX_NODES]; + value_packet_t value_packet; + + if (send_request (OSSMIX_CMD_OPEN_MIXER, mixernum, 0, 0, 0, 0) < 0) + return -1; + + if (mixernum >= MAX_TMP_MIXER) + { + fprintf (stderr, "tcp_open_mixer: Mixer number too large %d\n", + mixernum); + return -1; + } + + if ((nrext = send_request (OSSMIX_CMD_GET_NREXT, mixernum, 0, 0, 0, 0)) < 0) + return -1; + + nrext2 = nrext; // Save the value for the next step +/* + * Load all node info records + */ + + send_request_noreply (OSSMIX_CMD_GET_NODEINFO, mixernum, 0, nrext - 1, 0, + 0); + while (nrext > 0) + { + int i; + int n; + + n = nrext; + if (n > MAX_NODES) + n = MAX_NODES; + + if (wait_payload + (nodes, n * sizeof (oss_mixext), bswap_nodeinfo_array, NULL) < 0) + return -1; + + for (i = 0; i < n; i++) + { + oss_mixext *node; + + node = &nodes[i]; + + mixc_add_node (mixernum, node->ctrl, node); + } + + nrext -= n; + } + + nrext = nrext2; + +/* + * Load all values + */ + send_request_noreply (OSSMIX_CMD_GET_ALL_VALUES, mixernum, 0, 0, 0, 0); + + if (wait_payload + (value_packet, nrext * sizeof (value_record_t), bswap_int_array, + &nrext2) < 0) + return -1; + else + { + int i; + + for (i = 0; i < nrext2 / sizeof (value_record_t); i++) + { + mixc_set_value (mixernum, value_packet[i].node, + value_packet[i].value); + } + } + + return 0; +} + +static void +tcp_close_mixer (int mixernum) +{ + send_request_noreply (OSSMIX_CMD_CLOSE_MIXER, mixernum, 0, 0, 0, 0); +} + +static int +tcp_get_nrext (int mixernum) +{ + // TODO: Cache this information locally + return send_request (OSSMIX_CMD_GET_NREXT, mixernum, 0, 0, 0, 0); +} + +static int +tcp_get_nodeinfo (int mixernum, int node, oss_mixext * ext) +{ + oss_mixext *lnode; + + lnode = mixc_get_node (mixernum, node); + + if (lnode == NULL) + { + send_request_noreply (OSSMIX_CMD_GET_NODEINFO, mixernum, node, 0, 0, 0); + if (wait_payload (ext, sizeof (*ext), bswap_nodeinfo, NULL) < 0) + { + fprintf (stderr, + "tcp_get_nodeinfo: Mixer %d: Cannot load nodeinfo for %d\n", + mixernum, node); + return -1; + } + mixc_add_node (mixernum, node, lnode); + } + + memcpy (ext, lnode, sizeof (*ext)); + + return 0; +} + +static int +tcp_get_enuminfo (int mixernum, int node, oss_mixer_enuminfo * ei) +{ + send_request_noreply (OSSMIX_CMD_GET_ENUMINFO, mixernum, node, 0, 0, 0); + return wait_payload (ei, sizeof (*ei), bswap_enuminfo, NULL); +} + +static int +tcp_get_description (int mixernum, int node, oss_mixer_enuminfo * desc) +{ + send_request_noreply (OSSMIX_CMD_GET_DESCRIPTION, mixernum, node, 0, 0, 0); + return wait_payload (desc, sizeof (*desc), bswap_enuminfo, NULL); +} + +static int +tcp_get_value (int mixernum, int ctl, int timestamp) +{ + // return send_request(OSSMIX_CMD_GET_VALUE, mixernum, ctl, timestamp, 0, 0); + return mixc_get_value (mixernum, ctl); +} + +static void +tcp_set_value (int mixernum, int ctl, int timestamp, int value) +{ + send_request_noreply (OSSMIX_CMD_SET_VALUE, mixernum, ctl, timestamp, value, + 0); +} + +static void +tcp_timertick(void) +{ + // NOP +} + +ossmix_driver_t ossmix_tcp_driver = { + tcp_connect, + tcp_get_fd, + tcp_disconnect, + tcp_enable_events, + tcp_get_nmixers, + tcp_get_mixerinfo, + tcp_open_mixer, + tcp_close_mixer, + tcp_get_nrext, + tcp_get_nodeinfo, + tcp_get_enuminfo, + tcp_get_description, + tcp_get_value, + tcp_set_value, + tcp_timertick +}; + +static void +handle_values(int mixnum, int nvalues, value_record_t values[], int len) +{ + int i; + + if (nvalues*sizeof(value_record_t) > len) + { + fprintf(stderr, "Short value record (%lu, %d)\n", + (unsigned long)(nvalues*sizeof(value_record_t)), len); + exit(EXIT_FAILURE); + } + + for (i=0;i<nvalues;i++) + { + _client_event (OSSMIX_EVENT_VALUE, mixnum, values[i].node, values[i].value, 0, 0); + } + +} + +static void +handle_packet (ossmix_commad_packet_t * msg, char *payload, int payload_size) +{ +//printf("Got packet %d, p=0x%08x, %d, %d, %d, %d\n", +// msg->cmd, msg->p1, msg->p2, msg->p3, msg->p4, msg->p5); + +// _client_event (msg->cmd, msg->p1, msg->p2, msg->p3, msg->p4, msg->p5); + + switch(msg->cmd) + { + case OSSMIX_EVENT_VALUE: + handle_values(msg->p2, msg->p1, (value_record_t *)payload, payload_size); + break; + + case OSSMIX_EVENT_NEWMIXER: + //num_mixers=msg->p1; + _client_event (OSSMIX_EVENT_NEWMIXER, msg->p1, 0, 0, 0, 0); + break; + + default: + fprintf(stderr, "Unrecognized event packet %d\n", msg->cmd); + exit(EXIT_FAILURE); + } +} + +static void +poll_callback (void) +{ + ossmix_commad_packet_t msg; + char payload[4096]; + int l; + + if (sockfd == -1) + return; + + payload[0] = 0; + + if ((l = read_all (sockfd, &msg, sizeof (msg))) != sizeof (msg)) + { + if (l == 0) /* Connection closed */ + return; + + perror ("get response"); + return; + } + + if (do_byteswap) + byteswap_msg (&msg); + + if (msg.payload_size > 0) + { + if ((l = + read_all (sockfd, payload, msg.payload_size)) != msg.payload_size) + { + perror ("Get response payload"); + fprintf (stderr, "Payload size %d/%d\n", l, msg.payload_size); + return; + } + + payload[l] = 0; + } + + handle_packet (&msg, payload, msg.payload_size); +} |