diff options
Diffstat (limited to 'src/polyp')
54 files changed, 0 insertions, 13160 deletions
diff --git a/src/polyp/Makefile b/src/polyp/Makefile deleted file mode 100644 index 7c8875f3..00000000 --- a/src/polyp/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# This is a dirty trick just to ease compilation with emacs -# -# This file is not intended to be distributed or anything -# -# So: don't touch it, even better ignore it! - -all: - $(MAKE) -C .. - -clean: - $(MAKE) -C .. clean - -.PHONY: all clean diff --git a/src/polyp/browser.c b/src/polyp/browser.c deleted file mode 100644 index 69760d8d..00000000 --- a/src/polyp/browser.c +++ /dev/null @@ -1,334 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio 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 Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <assert.h> -#include <howl.h> - -#include <polyp/xmalloc.h> - -#include <polypcore/log.h> -#include <polypcore/core-util.h> - -#include "browser.h" - -#define SERVICE_NAME_SINK "_polypaudio-sink._tcp." -#define SERVICE_NAME_SOURCE "_polypaudio-source._tcp." -#define SERVICE_NAME_SERVER "_polypaudio-server._tcp." - -struct pa_browser { - int ref; - pa_mainloop_api *mainloop; - - pa_browse_cb_t callback; - void *userdata; - - sw_discovery discovery; - pa_io_event *io_event; -}; - -static void io_callback(pa_mainloop_api*a, PA_GCC_UNUSED pa_io_event*e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void *userdata) { - pa_browser *b = userdata; - assert(a && b && b->mainloop == a); - - if (events != PA_IO_EVENT_INPUT || sw_discovery_read_socket(b->discovery) != SW_OKAY) { - pa_log(__FILE__": connection to HOWL daemon failed."); - b->mainloop->io_free(b->io_event); - b->io_event = NULL; - return; - } -} - -static int type_equal(const char *a, const char *b) { - size_t la, lb; - - if (strcasecmp(a, b) == 0) - return 1; - - la = strlen(a); - lb = strlen(b); - - if (la > 0 && a[la-1] == '.' && la == lb+1 && strncasecmp(a, b, la-1) == 0) - return 1; - - if (lb > 0 && b[lb-1] == '.' && lb == la+1 && strncasecmp(a, b, lb-1) == 0) - return 1; - - return 0; -} - -static int map_to_opcode(const char *type, int new) { - if (type_equal(type, SERVICE_NAME_SINK)) - return new ? PA_BROWSE_NEW_SINK : PA_BROWSE_REMOVE_SINK; - else if (type_equal(type, SERVICE_NAME_SOURCE)) - return new ? PA_BROWSE_NEW_SOURCE : PA_BROWSE_REMOVE_SOURCE; - else if (type_equal(type, SERVICE_NAME_SERVER)) - return new ? PA_BROWSE_NEW_SERVER : PA_BROWSE_REMOVE_SERVER; - - return -1; -} - -static sw_result resolve_reply( - sw_discovery discovery, - sw_discovery_oid oid, - sw_uint32 interface_index, - sw_const_string name, - sw_const_string type, - sw_const_string domain, - sw_ipv4_address address, - sw_port port, - sw_octets text_record, - sw_ulong text_record_len, - sw_opaque extra) { - - pa_browser *b = extra; - pa_browse_info i; - char ip[256], a[256]; - int opcode; - int device_found = 0; - uint32_t cookie; - pa_sample_spec ss; - int ss_valid = 0; - sw_text_record_iterator iterator; - int free_iterator = 0; - char *c = NULL; - - assert(b); - - sw_discovery_cancel(discovery, oid); - - memset(&i, 0, sizeof(i)); - i.name = name; - - if (!b->callback) - goto fail; - - opcode = map_to_opcode(type, 1); - assert(opcode >= 0); - - snprintf(a, sizeof(a), "tcp:%s:%u", sw_ipv4_address_name(address, ip, sizeof(ip)), port); - i.server = a; - - if (text_record && text_record_len) { - char key[SW_TEXT_RECORD_MAX_LEN]; - uint8_t val[SW_TEXT_RECORD_MAX_LEN]; - uint32_t val_len; - - if (sw_text_record_iterator_init(&iterator, text_record, text_record_len) != SW_OKAY) { - pa_log_error(__FILE__": sw_text_record_string_iterator_init() failed."); - goto fail; - } - - free_iterator = 1; - - while (sw_text_record_iterator_next(iterator, key, val, &val_len) == SW_OKAY) { - c = pa_xstrndup((char*) val, val_len); - - if (!strcmp(key, "device")) { - device_found = 1; - pa_xfree((char*) i.device); - i.device = c; - c = NULL; - } else if (!strcmp(key, "server-version")) { - pa_xfree((char*) i.server_version); - i.server_version = c; - c = NULL; - } else if (!strcmp(key, "user-name")) { - pa_xfree((char*) i.user_name); - i.user_name = c; - c = NULL; - } else if (!strcmp(key, "fqdn")) { - size_t l; - - pa_xfree((char*) i.fqdn); - i.fqdn = c; - c = NULL; - - l = strlen(a); - assert(l+1 <= sizeof(a)); - strncat(a, " ", sizeof(a)-l-1); - strncat(a, i.fqdn, sizeof(a)-l-2); - } else if (!strcmp(key, "cookie")) { - - if (pa_atou(c, &cookie) < 0) - goto fail; - - i.cookie = &cookie; - } else if (!strcmp(key, "description")) { - pa_xfree((char*) i.description); - i.description = c; - c = NULL; - } else if (!strcmp(key, "channels")) { - uint32_t ch; - - if (pa_atou(c, &ch) < 0 || ch <= 0 || ch > 255) - goto fail; - - ss.channels = (uint8_t) ch; - ss_valid |= 1; - - } else if (!strcmp(key, "rate")) { - if (pa_atou(c, &ss.rate) < 0) - goto fail; - ss_valid |= 2; - } else if (!strcmp(key, "format")) { - - if ((ss.format = pa_parse_sample_format(c)) == PA_SAMPLE_INVALID) - goto fail; - - ss_valid |= 4; - } - - pa_xfree(c); - c = NULL; - } - - } - - /* No device txt record was sent for a sink or source service */ - if (opcode != PA_BROWSE_NEW_SERVER && !device_found) - goto fail; - - if (ss_valid == 7) - i.sample_spec = &ss; - - - b->callback(b, opcode, &i, b->userdata); - -fail: - pa_xfree((void*) i.device); - pa_xfree((void*) i.fqdn); - pa_xfree((void*) i.server_version); - pa_xfree((void*) i.user_name); - pa_xfree((void*) i.description); - pa_xfree(c); - - if (free_iterator) - sw_text_record_iterator_fina(iterator); - - - return SW_OKAY; -} - -static sw_result browse_reply( - sw_discovery discovery, - sw_discovery_oid id, - sw_discovery_browse_status status, - sw_uint32 interface_index, - sw_const_string name, - sw_const_string type, - sw_const_string domain, - sw_opaque extra) { - - pa_browser *b = extra; - assert(b); - - switch (status) { - case SW_DISCOVERY_BROWSE_ADD_SERVICE: { - sw_discovery_oid oid; - - if (sw_discovery_resolve(b->discovery, 0, name, type, domain, resolve_reply, b, &oid) != SW_OKAY) - pa_log_error(__FILE__": sw_discovery_resolve() failed"); - - break; - } - - case SW_DISCOVERY_BROWSE_REMOVE_SERVICE: - if (b->callback) { - pa_browse_info i; - int opcode; - - memset(&i, 0, sizeof(i)); - i.name = name; - - opcode = map_to_opcode(type, 0); - assert(opcode >= 0); - - b->callback(b, opcode, &i, b->userdata); - } - break; - - default: - ; - } - - return SW_OKAY; -} - -pa_browser *pa_browser_new(pa_mainloop_api *mainloop) { - pa_browser *b; - sw_discovery_oid oid; - - b = pa_xnew(pa_browser, 1); - b->mainloop = mainloop; - b->ref = 1; - b->callback = NULL; - b->userdata = NULL; - - if (sw_discovery_init(&b->discovery) != SW_OKAY) { - pa_log_error(__FILE__": sw_discovery_init() failed."); - pa_xfree(b); - return NULL; - } - - if (sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SERVER, NULL, browse_reply, b, &oid) != SW_OKAY || - sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SINK, NULL, browse_reply, b, &oid) != SW_OKAY || - sw_discovery_browse(b->discovery, 0, SERVICE_NAME_SOURCE, NULL, browse_reply, b, &oid) != SW_OKAY) { - - pa_log_error(__FILE__": sw_discovery_browse() failed."); - - sw_discovery_fina(b->discovery); - pa_xfree(b); - return NULL; - } - - b->io_event = mainloop->io_new(mainloop, sw_discovery_socket(b->discovery), PA_IO_EVENT_INPUT, io_callback, b); - return b; -} - -static void browser_free(pa_browser *b) { - assert(b && b->mainloop); - - if (b->io_event) - b->mainloop->io_free(b->io_event); - - sw_discovery_fina(b->discovery); - pa_xfree(b); -} - -pa_browser *pa_browser_ref(pa_browser *b) { - assert(b && b->ref >= 1); - b->ref++; - return b; -} - -void pa_browser_unref(pa_browser *b) { - assert(b && b->ref >= 1); - - if ((-- (b->ref)) <= 0) - browser_free(b); -} - -void pa_browser_set_callback(pa_browser *b, pa_browse_cb_t cb, void *userdata) { - assert(b); - - b->callback = cb; - b->userdata = userdata; -} diff --git a/src/polyp/browser.h b/src/polyp/browser.h deleted file mode 100644 index 1ff58d8c..00000000 --- a/src/polyp/browser.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef foobrowserhfoo -#define foobrowserhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - polypaudio 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 Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <polyp/mainloop-api.h> -#include <polyp/sample.h> -#include <polyp/channelmap.h> -#include <polyp/cdecl.h> - -PA_C_DECL_BEGIN - -typedef struct pa_browser pa_browser; - -typedef enum pa_browse_opcode { - PA_BROWSE_NEW_SERVER = 0, - PA_BROWSE_NEW_SINK, - PA_BROWSE_NEW_SOURCE, - PA_BROWSE_REMOVE_SERVER, - PA_BROWSE_REMOVE_SINK, - PA_BROWSE_REMOVE_SOURCE -} pa_browse_opcode_t; - -pa_browser *pa_browser_new(pa_mainloop_api *mainloop); -pa_browser *pa_browser_ref(pa_browser *z); -void pa_browser_unref(pa_browser *z); - -typedef struct pa_browse_info { - /* Unique service name */ - const char *name; /* always available */ - - /* Server info */ - const char *server; /* always available */ - const char *server_version, *user_name, *fqdn; /* optional */ - const uint32_t *cookie; /* optional */ - - /* Device info */ - const char *device; /* always available when this information is of a sink/source */ - const char *description; /* optional */ - const pa_sample_spec *sample_spec; /* optional */ -} pa_browse_info; - -typedef void (*pa_browse_cb_t)(pa_browser *z, pa_browse_opcode_t c, const pa_browse_info *i, void *userdata); - -void pa_browser_set_callback(pa_browser *z, pa_browse_cb_t cb, void *userdata); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/cdecl.h b/src/polyp/cdecl.h deleted file mode 100644 index d51ae026..00000000 --- a/src/polyp/cdecl.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef foocdeclhfoo -#define foocdeclhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -/** \file - * C++ compatibility support */ - -#ifdef __cplusplus -/** If using C++ this macro enables C mode, otherwise does nothing */ -#define PA_C_DECL_BEGIN extern "C" { -/** If using C++ this macros switches back to C++ mode, otherwise does nothing */ -#define PA_C_DECL_END } - -#else -/** If using C++ this macro enables C mode, otherwise does nothing */ -#define PA_C_DECL_BEGIN -/** If using C++ this macros switches back to C++ mode, otherwise does nothing */ -#define PA_C_DECL_END - -#endif - -#endif diff --git a/src/polyp/channelmap.c b/src/polyp/channelmap.c deleted file mode 100644 index 653331ba..00000000 --- a/src/polyp/channelmap.c +++ /dev/null @@ -1,445 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdlib.h> -#include <assert.h> -#include <stdio.h> -#include <string.h> - -#include <polyp/xmalloc.h> -#include <polypcore/core-util.h> - -#include "channelmap.h" - -const char *const table[] = { - [PA_CHANNEL_POSITION_MONO] = "mono", - - [PA_CHANNEL_POSITION_FRONT_CENTER] = "front-center", - [PA_CHANNEL_POSITION_FRONT_LEFT] = "front-left", - [PA_CHANNEL_POSITION_FRONT_RIGHT] = "front-right", - - [PA_CHANNEL_POSITION_REAR_CENTER] = "rear-center", - [PA_CHANNEL_POSITION_REAR_LEFT] = "rear-left", - [PA_CHANNEL_POSITION_REAR_RIGHT] = "rear-right", - - [PA_CHANNEL_POSITION_LFE] = "lfe", - - [PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER] = "front-left-of-center", - [PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER] = "front-right-of-center", - - [PA_CHANNEL_POSITION_SIDE_LEFT] = "side-left", - [PA_CHANNEL_POSITION_SIDE_RIGHT] = "side-right", - - [PA_CHANNEL_POSITION_AUX0] = "aux0", - [PA_CHANNEL_POSITION_AUX1] = "aux1", - [PA_CHANNEL_POSITION_AUX2] = "aux2", - [PA_CHANNEL_POSITION_AUX3] = "aux3", - [PA_CHANNEL_POSITION_AUX4] = "aux4", - [PA_CHANNEL_POSITION_AUX5] = "aux5", - [PA_CHANNEL_POSITION_AUX6] = "aux6", - [PA_CHANNEL_POSITION_AUX7] = "aux7", - [PA_CHANNEL_POSITION_AUX8] = "aux8", - [PA_CHANNEL_POSITION_AUX9] = "aux9", - [PA_CHANNEL_POSITION_AUX10] = "aux10", - [PA_CHANNEL_POSITION_AUX11] = "aux11", - [PA_CHANNEL_POSITION_AUX12] = "aux12", - [PA_CHANNEL_POSITION_AUX13] = "aux13", - [PA_CHANNEL_POSITION_AUX14] = "aux14", - [PA_CHANNEL_POSITION_AUX15] = "aux15", - - [PA_CHANNEL_POSITION_TOP_CENTER] = "top-center", - - [PA_CHANNEL_POSITION_TOP_FRONT_LEFT] = "top-front-left", - [PA_CHANNEL_POSITION_TOP_FRONT_RIGHT] = "top-front-right", - [PA_CHANNEL_POSITION_TOP_FRONT_CENTER] = "top-front-center", - - [PA_CHANNEL_POSITION_TOP_REAR_LEFT] = "top-rear-left", - [PA_CHANNEL_POSITION_TOP_REAR_RIGHT] = "top-rear-right", - [PA_CHANNEL_POSITION_TOP_REAR_CENTER] = "top-rear-center" -}; - -pa_channel_map* pa_channel_map_init(pa_channel_map *m) { - unsigned c; - assert(m); - - m->channels = 0; - - for (c = 0; c < PA_CHANNELS_MAX; c++) - m->map[c] = PA_CHANNEL_POSITION_INVALID; - - return m; -} - -pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m) { - assert(m); - - pa_channel_map_init(m); - - m->channels = 1; - m->map[0] = PA_CHANNEL_POSITION_MONO; - return m; -} - -pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m) { - assert(m); - - pa_channel_map_init(m); - - m->channels = 2; - m->map[0] = PA_CHANNEL_POSITION_LEFT; - m->map[1] = PA_CHANNEL_POSITION_RIGHT; - return m; -} - -pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def) { - assert(m); - assert(channels > 0); - assert(channels <= PA_CHANNELS_MAX); - - pa_channel_map_init(m); - - m->channels = channels; - - switch (def) { - case PA_CHANNEL_MAP_AIFF: - - /* This is somewhat compatible with RFC3551 */ - - switch (channels) { - case 1: - m->map[0] = PA_CHANNEL_POSITION_MONO; - return m; - - case 6: - m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - m->map[1] = PA_CHANNEL_POSITION_SIDE_LEFT; - m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; - m->map[3] = PA_CHANNEL_POSITION_FRONT_RIGHT; - m->map[4] = PA_CHANNEL_POSITION_SIDE_RIGHT; - m->map[5] = PA_CHANNEL_POSITION_LFE; - return m; - - case 5: - m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; - m->map[3] = PA_CHANNEL_POSITION_REAR_LEFT; - m->map[4] = PA_CHANNEL_POSITION_REAR_RIGHT; - /* Fall through */ - - case 2: - m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - return m; - - case 3: - m->map[0] = PA_CHANNEL_POSITION_LEFT; - m->map[1] = PA_CHANNEL_POSITION_RIGHT; - m->map[2] = PA_CHANNEL_POSITION_CENTER; - return m; - - case 4: - m->map[0] = PA_CHANNEL_POSITION_LEFT; - m->map[1] = PA_CHANNEL_POSITION_CENTER; - m->map[2] = PA_CHANNEL_POSITION_RIGHT; - m->map[3] = PA_CHANNEL_POSITION_LFE; - return m; - - default: - return NULL; - } - - case PA_CHANNEL_MAP_ALSA: - - switch (channels) { - case 1: - m->map[0] = PA_CHANNEL_POSITION_MONO; - return m; - - case 8: - m->map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; - m->map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; - /* Fall through */ - - case 6: - m->map[5] = PA_CHANNEL_POSITION_LFE; - /* Fall through */ - - case 5: - m->map[4] = PA_CHANNEL_POSITION_FRONT_CENTER; - /* Fall through */ - - case 4: - m->map[2] = PA_CHANNEL_POSITION_REAR_LEFT; - m->map[3] = PA_CHANNEL_POSITION_REAR_RIGHT; - /* Fall through */ - - case 2: - m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - return m; - - default: - return NULL; - } - - case PA_CHANNEL_MAP_AUX: { - unsigned i; - - if (channels >= PA_CHANNELS_MAX) - return NULL; - - for (i = 0; i < channels; i++) - m->map[i] = PA_CHANNEL_POSITION_AUX0 + i; - - return m; - } - - case PA_CHANNEL_MAP_WAVEEX: - - switch (channels) { - case 1: - m->map[0] = PA_CHANNEL_POSITION_MONO; - return m; - - case 18: - m->map[15] = PA_CHANNEL_POSITION_TOP_REAR_LEFT; - m->map[16] = PA_CHANNEL_POSITION_TOP_REAR_CENTER; - m->map[17] = PA_CHANNEL_POSITION_TOP_REAR_RIGHT; - /* Fall through */ - - case 15: - m->map[12] = PA_CHANNEL_POSITION_TOP_FRONT_LEFT; - m->map[13] = PA_CHANNEL_POSITION_TOP_FRONT_CENTER; - m->map[14] = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT; - /* Fall through */ - - case 12: - m->map[11] = PA_CHANNEL_POSITION_TOP_CENTER; - /* Fall through */ - - case 11: - m->map[9] = PA_CHANNEL_POSITION_SIDE_LEFT; - m->map[10] = PA_CHANNEL_POSITION_SIDE_RIGHT; - /* Fall through */ - - case 9: - m->map[8] = PA_CHANNEL_POSITION_REAR_CENTER; - /* Fall through */ - - case 8: - m->map[6] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER; - m->map[7] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER; - /* Fall through */ - - case 6: - m->map[4] = PA_CHANNEL_POSITION_REAR_LEFT; - m->map[5] = PA_CHANNEL_POSITION_REAR_RIGHT; - /* Fall through */ - - case 4: - m->map[3] = PA_CHANNEL_POSITION_LFE; - /* Fall through */ - - case 3: - m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; - /* Fall through */ - - case 2: - m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - return m; - - default: - return NULL; - } - - case PA_CHANNEL_MAP_OSS: - - switch (channels) { - case 1: - m->map[0] = PA_CHANNEL_POSITION_MONO; - return m; - - case 8: - m->map[6] = PA_CHANNEL_POSITION_REAR_LEFT; - m->map[7] = PA_CHANNEL_POSITION_REAR_RIGHT; - /* Fall through */ - - case 6: - m->map[4] = PA_CHANNEL_POSITION_SIDE_LEFT; - m->map[5] = PA_CHANNEL_POSITION_SIDE_RIGHT; - /* Fall through */ - - case 4: - m->map[3] = PA_CHANNEL_POSITION_LFE; - /* Fall through */ - - case 3: - m->map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; - /* Fall through */ - - case 2: - m->map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; - m->map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; - return m; - - default: - return NULL; - } - - - default: - return NULL; - } -} - - -const char* pa_channel_position_to_string(pa_channel_position_t pos) { - - if (pos < 0 || pos >= PA_CHANNEL_POSITION_MAX) - return NULL; - - return table[pos]; -} - -int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b) { - unsigned c; - - assert(a); - assert(b); - - if (a->channels != b->channels) - return 0; - - for (c = 0; c < a->channels; c++) - if (a->map[c] != b->map[c]) - return 0; - - return 1; -} - -char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map) { - unsigned channel; - int first = 1; - char *e; - - assert(s); - assert(l > 0); - assert(map); - - *(e = s) = 0; - - for (channel = 0; channel < map->channels && l > 1; channel++) { - l -= snprintf(e, l, "%s%s", - first ? "" : ",", - pa_channel_position_to_string(map->map[channel])); - - e = strchr(e, 0); - first = 0; - } - - return s; -} - -pa_channel_map *pa_channel_map_parse(pa_channel_map *rmap, const char *s) { - const char *state; - pa_channel_map map; - char *p; - - assert(rmap); - assert(s); - - memset(&map, 0, sizeof(map)); - - if (strcmp(s, "stereo") == 0) { - map.channels = 2; - map.map[0] = PA_CHANNEL_POSITION_LEFT; - map.map[1] = PA_CHANNEL_POSITION_RIGHT; - goto finish; - } - - state = NULL; - map.channels = 0; - - while ((p = pa_split(s, ",", &state))) { - - if (map.channels >= PA_CHANNELS_MAX) { - pa_xfree(p); - return NULL; - } - - /* Some special aliases */ - if (strcmp(p, "left") == 0) - map.map[map.channels++] = PA_CHANNEL_POSITION_LEFT; - else if (strcmp(p, "right") == 0) - map.map[map.channels++] = PA_CHANNEL_POSITION_RIGHT; - else if (strcmp(p, "center") == 0) - map.map[map.channels++] = PA_CHANNEL_POSITION_CENTER; - else if (strcmp(p, "subwoofer") == 0) - map.map[map.channels++] = PA_CHANNEL_POSITION_SUBWOOFER; - else { - pa_channel_position_t i; - - for (i = 0; i < PA_CHANNEL_POSITION_MAX; i++) - if (strcmp(p, table[i]) == 0) { - map.map[map.channels++] = i; - break; - } - - if (i >= PA_CHANNEL_POSITION_MAX) { - pa_xfree(p); - return NULL; - } - } - - pa_xfree(p); - } - -finish: - - if (!pa_channel_map_valid(&map)) - return NULL; - - *rmap = map; - return rmap; -} - -int pa_channel_map_valid(const pa_channel_map *map) { - unsigned c; - - assert(map); - - if (map->channels <= 0 || map->channels > PA_CHANNELS_MAX) - return 0; - - for (c = 0; c < map->channels; c++) { - - if (map->map[c] < 0 ||map->map[c] >= PA_CHANNEL_POSITION_MAX) - return 0; - - } - - return 1; -} - diff --git a/src/polyp/channelmap.h b/src/polyp/channelmap.h deleted file mode 100644 index 645a8a38..00000000 --- a/src/polyp/channelmap.h +++ /dev/null @@ -1,191 +0,0 @@ -#ifndef foochannelmaphfoo -#define foochannelmaphfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <polyp/sample.h> -#include <polyp/cdecl.h> - -/** \page channelmap Channel Maps - * - * \section overv_sec Overview - * - * Channel maps provide a way to associate channels in a stream with a - * specific speaker position. This relieves applications of having to - * make sure their channel order is identical to the final output. - * - * \section init_sec Initialisation - * - * A channel map consists of an array of \ref pa_channel_position values, - * one for each channel. This array is stored together with a channel count - * in a pa_channel_map structure. - * - * Before filling the structure, the application must initialise it using - * pa_channel_map_init(). There are also a number of convenience functions - * for standard channel mappings: - * - * \li pa_channel_map_init_mono() - Create a channel map with only mono audio. - * \li pa_channel_map_init_stereo() - Create a standard stereo mapping. - * \li pa_channel_map_init_auto() - Create a standard channel map for up to - * six channels. - * - * \section conv_sec Convenience Functions - * - * The library contains a number of convenience functions for dealing with - * channel maps: - * - * \li pa_channel_map_valid() - Tests if a channel map is valid. - * \li pa_channel_map_equal() - Tests if two channel maps are identical. - * \li pa_channel_map_snprint() - Creates a textual description of a channel - * map. - */ - -/** \file - * Constants and routines for channel mapping handling */ - -PA_C_DECL_BEGIN - -/** A list of channel labels */ -typedef enum pa_channel_position { - PA_CHANNEL_POSITION_INVALID = -1, - PA_CHANNEL_POSITION_MONO = 0, - - PA_CHANNEL_POSITION_LEFT, - PA_CHANNEL_POSITION_RIGHT, - PA_CHANNEL_POSITION_CENTER, - - PA_CHANNEL_POSITION_FRONT_LEFT = PA_CHANNEL_POSITION_LEFT, - PA_CHANNEL_POSITION_FRONT_RIGHT = PA_CHANNEL_POSITION_RIGHT, - PA_CHANNEL_POSITION_FRONT_CENTER = PA_CHANNEL_POSITION_CENTER, - - PA_CHANNEL_POSITION_REAR_CENTER, - PA_CHANNEL_POSITION_REAR_LEFT, - PA_CHANNEL_POSITION_REAR_RIGHT, - - PA_CHANNEL_POSITION_LFE, - PA_CHANNEL_POSITION_SUBWOOFER = PA_CHANNEL_POSITION_LFE, - - PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, - PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, - - PA_CHANNEL_POSITION_SIDE_LEFT, - PA_CHANNEL_POSITION_SIDE_RIGHT, - - PA_CHANNEL_POSITION_AUX0, - PA_CHANNEL_POSITION_AUX1, - PA_CHANNEL_POSITION_AUX2, - PA_CHANNEL_POSITION_AUX3, - PA_CHANNEL_POSITION_AUX4, - PA_CHANNEL_POSITION_AUX5, - PA_CHANNEL_POSITION_AUX6, - PA_CHANNEL_POSITION_AUX7, - PA_CHANNEL_POSITION_AUX8, - PA_CHANNEL_POSITION_AUX9, - PA_CHANNEL_POSITION_AUX10, - PA_CHANNEL_POSITION_AUX11, - PA_CHANNEL_POSITION_AUX12, - PA_CHANNEL_POSITION_AUX13, - PA_CHANNEL_POSITION_AUX14, - PA_CHANNEL_POSITION_AUX15, - PA_CHANNEL_POSITION_AUX16, - PA_CHANNEL_POSITION_AUX17, - PA_CHANNEL_POSITION_AUX18, - PA_CHANNEL_POSITION_AUX19, - PA_CHANNEL_POSITION_AUX20, - PA_CHANNEL_POSITION_AUX21, - PA_CHANNEL_POSITION_AUX22, - PA_CHANNEL_POSITION_AUX23, - PA_CHANNEL_POSITION_AUX24, - PA_CHANNEL_POSITION_AUX25, - PA_CHANNEL_POSITION_AUX26, - PA_CHANNEL_POSITION_AUX27, - PA_CHANNEL_POSITION_AUX28, - PA_CHANNEL_POSITION_AUX29, - PA_CHANNEL_POSITION_AUX30, - PA_CHANNEL_POSITION_AUX31, - - PA_CHANNEL_POSITION_TOP_CENTER, - - PA_CHANNEL_POSITION_TOP_FRONT_LEFT, - PA_CHANNEL_POSITION_TOP_FRONT_RIGHT, - PA_CHANNEL_POSITION_TOP_FRONT_CENTER, - - PA_CHANNEL_POSITION_TOP_REAR_LEFT, - PA_CHANNEL_POSITION_TOP_REAR_RIGHT, - PA_CHANNEL_POSITION_TOP_REAR_CENTER, - - PA_CHANNEL_POSITION_MAX -} pa_channel_position_t; - -/** A list of channel mapping definitions for pa_channel_map_init_auto() */ -typedef enum pa_channel_map_def { - PA_CHANNEL_MAP_AIFF, /**< The mapping from RFC3551, which is based on AIFF-C */ - PA_CHANNEL_MAP_ALSA, /**< The default mapping used by ALSA */ - PA_CHANNEL_MAP_AUX, /**< Only aux channels */ - PA_CHANNEL_MAP_WAVEEX, /**< Microsoft's WAVEFORMATEXTENSIBLE mapping */ - PA_CHANNEL_MAP_OSS, /**< The default channel mapping used by OSS as defined in the OSS 4.0 API specs */ - - PA_CHANNEL_MAP_DEFAULT = PA_CHANNEL_MAP_AIFF /**< The default channel map */ -} pa_channel_map_def_t; - -/** A channel map which can be used to attach labels to specific - * channels of a stream. These values are relevant for conversion and - * mixing of streams */ -typedef struct pa_channel_map { - uint8_t channels; /**< Number of channels */ - pa_channel_position_t map[PA_CHANNELS_MAX]; /**< Channel labels */ -} pa_channel_map; - -/** Initialize the specified channel map and return a pointer to it */ -pa_channel_map* pa_channel_map_init(pa_channel_map *m); - -/** Initialize the specified channel map for monoaural audio and return a pointer to it */ -pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m); - -/** Initialize the specified channel map for stereophonic audio and return a pointer to it */ -pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m); - -/** Initialize the specified channel map for the specified number - * of channels using default labels and return a pointer to it. */ -pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels, pa_channel_map_def_t def); - -/** Return a text label for the specified channel position */ -const char* pa_channel_position_to_string(pa_channel_position_t pos); - -/** The maximum length of strings returned by pa_channel_map_snprint() */ -#define PA_CHANNEL_MAP_SNPRINT_MAX 336 - -/** Make a humand readable string from the specified channel map */ -char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map); - -/** Parse a channel position list into a channel map structure. \since 0.8.1 */ -pa_channel_map *pa_channel_map_parse(pa_channel_map *map, const char *s); - -/** Compare two channel maps. Return 1 if both match. */ -int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b); - -/** Return non-zero of the specified channel map is considered valid */ -int pa_channel_map_valid(const pa_channel_map *map); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/client-conf-x11.c b/src/polyp/client-conf-x11.c deleted file mode 100644 index fb67df2f..00000000 --- a/src/polyp/client-conf-x11.c +++ /dev/null @@ -1,93 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-13071 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> -#include <assert.h> - -#include <X11/Xlib.h> -#include <X11/Xatom.h> - -#include <polyp/xmalloc.h> - -#include <polypcore/x11prop.h> -#include <polypcore/log.h> -#include <polypcore/core-util.h> - -#include "client-conf-x11.h" - -int pa_client_conf_from_x11(pa_client_conf *c, const char *dname) { - Display *d = NULL; - int ret = -1; - char t[1024]; - - if (!dname && !getenv("DISPLAY")) - goto finish; - - if (!(d = XOpenDisplay(dname))) { - pa_log(__FILE__": XOpenDisplay() failed"); - goto finish; - } - - if (pa_x11_get_prop(d, "POLYP_SERVER", t, sizeof(t))) { - pa_xfree(c->default_server); - c->default_server = pa_xstrdup(t); - } - - if (pa_x11_get_prop(d, "POLYP_SINK", t, sizeof(t))) { - pa_xfree(c->default_sink); - c->default_sink = pa_xstrdup(t); - } - - if (pa_x11_get_prop(d, "POLYP_SOURCE", t, sizeof(t))) { - pa_xfree(c->default_source); - c->default_source = pa_xstrdup(t); - } - - if (pa_x11_get_prop(d, "POLYP_COOKIE", t, sizeof(t))) { - uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; - - if (pa_parsehex(t, cookie, sizeof(cookie)) != sizeof(cookie)) { - pa_log(__FILE__": failed to parse cookie data"); - goto finish; - } - - assert(sizeof(cookie) == sizeof(c->cookie)); - memcpy(c->cookie, cookie, sizeof(cookie)); - - c->cookie_valid = 1; - - pa_xfree(c->cookie_file); - c->cookie_file = NULL; - } - - ret = 0; - -finish: - if (d) - XCloseDisplay(d); - - return ret; - -} diff --git a/src/polyp/client-conf-x11.h b/src/polyp/client-conf-x11.h deleted file mode 100644 index 64459224..00000000 --- a/src/polyp/client-conf-x11.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef fooclientconfx11hfoo -#define fooclientconfx11hfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include "client-conf.h" - -/* Load client configuration data from the specified X11 display, - * overwriting the current settings in *c */ -int pa_client_conf_from_x11(pa_client_conf *c, const char *display); - -#endif diff --git a/src/polyp/client-conf.c b/src/polyp/client-conf.c deleted file mode 100644 index e1934ce1..00000000 --- a/src/polyp/client-conf.c +++ /dev/null @@ -1,193 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdlib.h> -#include <assert.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> - -#include <polypcore/core-error.h> -#include <polyp/xmalloc.h> - -#include <polypcore/log.h> -#include <polypcore/conf-parser.h> -#include <polypcore/core-util.h> -#include <polypcore/authkey.h> - -#include "client-conf.h" - -#ifndef DEFAULT_CONFIG_DIR -# ifndef OS_IS_WIN32 -# define DEFAULT_CONFIG_DIR "/etc/polypaudio" -# else -# define DEFAULT_CONFIG_DIR "%POLYP_ROOT%" -# endif -#endif - -#ifndef OS_IS_WIN32 -# define PATH_SEP "/" -#else -# define PATH_SEP "\\" -#endif - -#define DEFAULT_CLIENT_CONFIG_FILE DEFAULT_CONFIG_DIR PATH_SEP "client.conf" -#define DEFAULT_CLIENT_CONFIG_FILE_USER ".polypaudio" PATH_SEP "client.conf" - -#define ENV_CLIENT_CONFIG_FILE "POLYP_CLIENTCONFIG" -#define ENV_DEFAULT_SINK "POLYP_SINK" -#define ENV_DEFAULT_SOURCE "POLYP_SOURCE" -#define ENV_DEFAULT_SERVER "POLYP_SERVER" -#define ENV_DAEMON_BINARY "POLYP_BINARY" -#define ENV_COOKIE_FILE "POLYP_COOKIE" - -static const pa_client_conf default_conf = { - .daemon_binary = NULL, - .extra_arguments = NULL, - .default_sink = NULL, - .default_source = NULL, - .default_server = NULL, - .autospawn = 0, - .cookie_file = NULL, - .cookie_valid = 0 -}; - -pa_client_conf *pa_client_conf_new(void) { - pa_client_conf *c = pa_xmemdup(&default_conf, sizeof(default_conf)); - - c->daemon_binary = pa_xstrdup(POLYPAUDIO_BINARY); - c->extra_arguments = pa_xstrdup("--log-target=syslog --exit-idle-time=5"); - c->cookie_file = pa_xstrdup(PA_NATIVE_COOKIE_FILE); - - return c; -} - -void pa_client_conf_free(pa_client_conf *c) { - assert(c); - pa_xfree(c->daemon_binary); - pa_xfree(c->extra_arguments); - pa_xfree(c->default_sink); - pa_xfree(c->default_source); - pa_xfree(c->default_server); - pa_xfree(c->cookie_file); - pa_xfree(c); -} -int pa_client_conf_load(pa_client_conf *c, const char *filename) { - FILE *f = NULL; - char *fn = NULL; - int r = -1; - - /* Prepare the configuration parse table */ - pa_config_item table[] = { - { "daemon-binary", pa_config_parse_string, NULL }, - { "extra-arguments", pa_config_parse_string, NULL }, - { "default-sink", pa_config_parse_string, NULL }, - { "default-source", pa_config_parse_string, NULL }, - { "default-server", pa_config_parse_string, NULL }, - { "autospawn", pa_config_parse_bool, NULL }, - { "cookie-file", pa_config_parse_string, NULL }, - { NULL, NULL, NULL }, - }; - - table[0].data = &c->daemon_binary; - table[1].data = &c->extra_arguments; - table[2].data = &c->default_sink; - table[3].data = &c->default_source; - table[4].data = &c->default_server; - table[5].data = &c->autospawn; - table[6].data = &c->cookie_file; - - f = filename ? - fopen((fn = pa_xstrdup(filename)), "r") : - pa_open_config_file(DEFAULT_CLIENT_CONFIG_FILE, DEFAULT_CLIENT_CONFIG_FILE_USER, ENV_CLIENT_CONFIG_FILE, &fn, "r"); - - if (!f && errno != EINTR) { - pa_log(__FILE__": WARNING: failed to open configuration file '%s': %s", filename, pa_cstrerror(errno)); - goto finish; - } - - r = f ? pa_config_parse(fn, f, table, NULL) : 0; - - if (!r) - r = pa_client_conf_load_cookie(c); - - -finish: - pa_xfree(fn); - - if (f) - fclose(f); - - return r; -} - -int pa_client_conf_env(pa_client_conf *c) { - char *e; - - if ((e = getenv(ENV_DEFAULT_SINK))) { - pa_xfree(c->default_sink); - c->default_sink = pa_xstrdup(e); - } - - if ((e = getenv(ENV_DEFAULT_SOURCE))) { - pa_xfree(c->default_source); - c->default_source = pa_xstrdup(e); - } - - if ((e = getenv(ENV_DEFAULT_SERVER))) { - pa_xfree(c->default_server); - c->default_server = pa_xstrdup(e); - } - - if ((e = getenv(ENV_DAEMON_BINARY))) { - pa_xfree(c->daemon_binary); - c->daemon_binary = pa_xstrdup(e); - } - - if ((e = getenv(ENV_COOKIE_FILE))) { - pa_xfree(c->cookie_file); - c->cookie_file = pa_xstrdup(e); - - return pa_client_conf_load_cookie(c); - } - - return 0; -} - -int pa_client_conf_load_cookie(pa_client_conf* c) { - assert(c); - - c->cookie_valid = 0; - - if (!c->cookie_file) - return -1; - - if (pa_authkey_load_auto(c->cookie_file, c->cookie, sizeof(c->cookie)) < 0) - return -1; - - c->cookie_valid = 1; - return 0; -} - diff --git a/src/polyp/client-conf.h b/src/polyp/client-conf.h deleted file mode 100644 index de3efae7..00000000 --- a/src/polyp/client-conf.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef fooclientconfhfoo -#define fooclientconfhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <polypcore/native-common.h> - -/* A structure containing configuration data for polypaudio clients. */ - -typedef struct pa_client_conf { - char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server, *cookie_file; - int autospawn; - uint8_t cookie[PA_NATIVE_COOKIE_LENGTH]; - int cookie_valid; /* non-zero, when cookie is valid */ -} pa_client_conf; - -/* Create a new configuration data object and reset it to defaults */ -pa_client_conf *pa_client_conf_new(void); -void pa_client_conf_free(pa_client_conf *c); - -/* Load the configuration data from the speicified file, overwriting - * the current settings in *c. When the filename is NULL, the - * default client configuration file name is used. */ -int pa_client_conf_load(pa_client_conf *c, const char *filename); - -/* Load the configuration data from the environment of the current - process, overwriting the current settings in *c. */ -int pa_client_conf_env(pa_client_conf *c); - -/* Load cookie data from c->cookie_file into c->cookie */ -int pa_client_conf_load_cookie(pa_client_conf* c); - -#endif diff --git a/src/polyp/client.conf.in b/src/polyp/client.conf.in deleted file mode 100644 index fbf645a4..00000000 --- a/src/polyp/client.conf.in +++ /dev/null @@ -1,39 +0,0 @@ -# $Id$ -# -# This file is part of polypaudio. -# -# polypaudio is free software; you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# polypaudio 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 Lesser General Public License -# along with polypaudio; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA. - -## Configuration file for polypaudio clients. Default values are -## commented out. Use either ; or # for commenting - -## Path to the polypaudio daemon to run when autospawning. -; daemon-binary = @POLYPAUDIO_BINARY@ - -## Extra arguments to pass to the polypaudio daemon -; extra-arguments = --log-target=syslog --exit-idle-time=5 - -## The default sink to connect to -; default-sink = - -## The default source to connect to -; default-source = - -## The default sever to connect to -; default-server = - -## Autospawn daemons? -; autospawn = 0 diff --git a/src/polyp/context.c b/src/polyp/context.c deleted file mode 100644 index 68fb4bf3..00000000 --- a/src/polyp/context.c +++ /dev/null @@ -1,980 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <assert.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <unistd.h> -#include <sys/stat.h> -#include <errno.h> -#include <signal.h> -#include <limits.h> - -#ifdef HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif - -#ifdef HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#ifdef HAVE_NETDB_H -#include <netdb.h> -#endif - -#include "../polypcore/winsock.h" - -#include <polypcore/core-error.h> -#include <polyp/version.h> -#include <polyp/xmalloc.h> - -#include <polypcore/native-common.h> -#include <polypcore/pdispatch.h> -#include <polypcore/pstream.h> -#include <polypcore/dynarray.h> -#include <polypcore/socket-client.h> -#include <polypcore/pstream-util.h> -#include <polypcore/core-util.h> -#include <polypcore/log.h> -#include <polypcore/socket-util.h> - -#include "internal.h" - -#include "client-conf.h" - -#ifdef HAVE_X11 -#include "client-conf-x11.h" -#endif - -#include "context.h" - -#define AUTOSPAWN_LOCK "autospawn.lock" - -static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { - [PA_COMMAND_REQUEST] = pa_command_request, - [PA_COMMAND_OVERFLOW] = pa_command_overflow_or_underflow, - [PA_COMMAND_UNDERFLOW] = pa_command_overflow_or_underflow, - [PA_COMMAND_PLAYBACK_STREAM_KILLED] = pa_command_stream_killed, - [PA_COMMAND_RECORD_STREAM_KILLED] = pa_command_stream_killed, - [PA_COMMAND_SUBSCRIBE_EVENT] = pa_command_subscribe_event -}; - -static void unlock_autospawn_lock_file(pa_context *c) { - assert(c); - - if (c->autospawn_lock_fd >= 0) { - char lf[PATH_MAX]; - pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); - - pa_unlock_lockfile(lf, c->autospawn_lock_fd); - c->autospawn_lock_fd = -1; - } -} - -pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) { - pa_context *c; - - assert(mainloop); - assert(name); - - c = pa_xnew(pa_context, 1); - c->ref = 1; - c->name = pa_xstrdup(name); - c->mainloop = mainloop; - c->client = NULL; - c->pstream = NULL; - c->pdispatch = NULL; - c->playback_streams = pa_dynarray_new(); - c->record_streams = pa_dynarray_new(); - - PA_LLIST_HEAD_INIT(pa_stream, c->streams); - PA_LLIST_HEAD_INIT(pa_operation, c->operations); - - c->error = PA_OK; - c->state = PA_CONTEXT_UNCONNECTED; - c->ctag = 0; - c->csyncid = 0; - - c->state_callback = NULL; - c->state_userdata = NULL; - - c->subscribe_callback = NULL; - c->subscribe_userdata = NULL; - - c->memblock_stat = pa_memblock_stat_new(); - c->local = -1; - c->server_list = NULL; - c->server = NULL; - c->autospawn_lock_fd = -1; - memset(&c->spawn_api, 0, sizeof(c->spawn_api)); - c->do_autospawn = 0; - -#ifdef SIGPIPE - pa_check_signal_is_blocked(SIGPIPE); -#endif - - c->conf = pa_client_conf_new(); - pa_client_conf_load(c->conf, NULL); -#ifdef HAVE_X11 - pa_client_conf_from_x11(c->conf, NULL); -#endif - pa_client_conf_env(c->conf); - - return c; -} - -static void context_free(pa_context *c) { - assert(c); - - unlock_autospawn_lock_file(c); - - while (c->operations) - pa_operation_cancel(c->operations); - - while (c->streams) - pa_stream_set_state(c->streams, PA_STREAM_TERMINATED); - - if (c->client) - pa_socket_client_unref(c->client); - if (c->pdispatch) - pa_pdispatch_unref(c->pdispatch); - if (c->pstream) { - pa_pstream_close(c->pstream); - pa_pstream_unref(c->pstream); - } - - if (c->record_streams) - pa_dynarray_free(c->record_streams, NULL, NULL); - if (c->playback_streams) - pa_dynarray_free(c->playback_streams, NULL, NULL); - - pa_memblock_stat_unref(c->memblock_stat); - - if (c->conf) - pa_client_conf_free(c->conf); - - pa_strlist_free(c->server_list); - - pa_xfree(c->name); - pa_xfree(c->server); - pa_xfree(c); -} - -pa_context* pa_context_ref(pa_context *c) { - assert(c); - assert(c->ref >= 1); - - c->ref++; - return c; -} - -void pa_context_unref(pa_context *c) { - assert(c); - assert(c->ref >= 1); - - if (--c->ref <= 0) - context_free(c); -} - -void pa_context_set_state(pa_context *c, pa_context_state_t st) { - assert(c); - assert(c->ref >= 1); - - if (c->state == st) - return; - - pa_context_ref(c); - - c->state = st; - if (c->state_callback) - c->state_callback(c, c->state_userdata); - - if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED) { - pa_stream *s; - - s = c->streams ? pa_stream_ref(c->streams) : NULL; - while (s) { - pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL; - pa_stream_set_state(s, st == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED); - pa_stream_unref(s); - s = n; - } - - if (c->pdispatch) - pa_pdispatch_unref(c->pdispatch); - c->pdispatch = NULL; - - if (c->pstream) { - pa_pstream_close(c->pstream); - pa_pstream_unref(c->pstream); - } - c->pstream = NULL; - - if (c->client) - pa_socket_client_unref(c->client); - c->client = NULL; - } - - pa_context_unref(c); -} - -void pa_context_fail(pa_context *c, int error) { - assert(c); - assert(c->ref >= 1); - - pa_context_set_error(c, error); - pa_context_set_state(c, PA_CONTEXT_FAILED); -} - -int pa_context_set_error(pa_context *c, int error) { - assert(error >= 0); - assert(error < PA_ERR_MAX); - - if (c) - c->error = error; - - return error; -} - -static void pstream_die_callback(pa_pstream *p, void *userdata) { - pa_context *c = userdata; - - assert(p); - assert(c); - - pa_context_fail(c, PA_ERR_CONNECTIONTERMINATED); -} - -static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const void *creds, void *userdata) { - pa_context *c = userdata; - - assert(p); - assert(packet); - assert(c); - - pa_context_ref(c); - - if (pa_pdispatch_run(c->pdispatch, packet, creds, c) < 0) - pa_context_fail(c, PA_ERR_PROTOCOL); - - pa_context_unref(c); -} - -static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t offset, pa_seek_mode_t seek, const pa_memchunk *chunk, void *userdata) { - pa_context *c = userdata; - pa_stream *s; - - assert(p); - assert(chunk); - assert(chunk->memblock); - assert(chunk->length); - assert(c); - assert(c->ref >= 1); - - pa_context_ref(c); - - if ((s = pa_dynarray_get(c->record_streams, channel))) { - - assert(seek == PA_SEEK_RELATIVE && offset == 0); - - pa_memblockq_seek(s->record_memblockq, offset, seek); - pa_memblockq_push_align(s->record_memblockq, chunk); - - if (s->read_callback) { - size_t l; - - if ((l = pa_memblockq_get_length(s->record_memblockq)) > 0) - s->read_callback(s, l, s->read_userdata); - } - } - - pa_context_unref(c); -} - -int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t) { - assert(c); - assert(c->ref >= 1); - - if (command == PA_COMMAND_ERROR) { - assert(t); - - if (pa_tagstruct_getu32(t, &c->error) < 0) { - pa_context_fail(c, PA_ERR_PROTOCOL); - return -1; - - } - } else if (command == PA_COMMAND_TIMEOUT) - c->error = PA_ERR_TIMEOUT; - else { - pa_context_fail(c, PA_ERR_PROTOCOL); - return -1; - } - - return 0; -} - -static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_context *c = userdata; - - assert(pd); - assert(c); - assert(c->state == PA_CONTEXT_AUTHORIZING || c->state == PA_CONTEXT_SETTING_NAME); - - pa_context_ref(c); - - if (command != PA_COMMAND_REPLY) { - - if (pa_context_handle_error(c, command, t) < 0) - pa_context_fail(c, PA_ERR_PROTOCOL); - - pa_context_fail(c, c->error); - goto finish; - } - - switch(c->state) { - case PA_CONTEXT_AUTHORIZING: { - pa_tagstruct *reply; - - if (pa_tagstruct_getu32(t, &c->version) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(c, PA_ERR_PROTOCOL); - goto finish; - } - - /* Minimum supported version */ - if (c->version < 8) { - pa_context_fail(c, PA_ERR_VERSION); - goto finish; - } - - reply = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag); - pa_tagstruct_puts(reply, c->name); - pa_pstream_send_tagstruct(c->pstream, reply); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL); - - pa_context_set_state(c, PA_CONTEXT_SETTING_NAME); - break; - } - - case PA_CONTEXT_SETTING_NAME : - pa_context_set_state(c, PA_CONTEXT_READY); - break; - - default: - assert(0); - } - -finish: - pa_context_unref(c); -} - -static void setup_context(pa_context *c, pa_iochannel *io) { - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(io); - - pa_context_ref(c); - - assert(!c->pstream); - c->pstream = pa_pstream_new(c->mainloop, io, c->memblock_stat); - - pa_pstream_set_die_callback(c->pstream, pstream_die_callback, c); - pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); - pa_pstream_set_recieve_memblock_callback(c->pstream, pstream_memblock_callback, c); - - assert(!c->pdispatch); - c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX); - - if (!c->conf->cookie_valid) { - pa_context_fail(c, PA_ERR_AUTHKEY); - goto finish; - } - - t = pa_tagstruct_command(c, PA_COMMAND_AUTH, &tag); - pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION); - pa_tagstruct_put_arbitrary(t, c->conf->cookie, sizeof(c->conf->cookie)); - pa_pstream_send_tagstruct_with_creds(c->pstream, t, 1); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL); - - pa_context_set_state(c, PA_CONTEXT_AUTHORIZING); - -finish: - - pa_context_unref(c); -} - -static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata); - -#ifndef OS_IS_WIN32 - -static int context_connect_spawn(pa_context *c) { - pid_t pid; - int status, r; - int fds[2] = { -1, -1} ; - pa_iochannel *io; - - pa_context_ref(c); - - if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { - pa_log(__FILE__": socketpair(): %s", pa_cstrerror(errno)); - pa_context_fail(c, PA_ERR_INTERNAL); - goto fail; - } - - pa_fd_set_cloexec(fds[0], 1); - - pa_socket_low_delay(fds[0]); - pa_socket_low_delay(fds[1]); - - if (c->spawn_api.prefork) - c->spawn_api.prefork(); - - if ((pid = fork()) < 0) { - pa_log(__FILE__": fork(): %s", pa_cstrerror(errno)); - pa_context_fail(c, PA_ERR_INTERNAL); - - if (c->spawn_api.postfork) - c->spawn_api.postfork(); - - goto fail; - } else if (!pid) { - /* Child */ - - char t[128]; - const char *state = NULL; -#define MAX_ARGS 64 - const char * argv[MAX_ARGS+1]; - int n; - - /* Not required, since fds[0] has CLOEXEC enabled anyway */ - close(fds[0]); - - if (c->spawn_api.atfork) - c->spawn_api.atfork(); - - /* Setup argv */ - - n = 0; - - argv[n++] = c->conf->daemon_binary; - argv[n++] = "--daemonize=yes"; - - snprintf(t, sizeof(t), "-Lmodule-native-protocol-fd fd=%i", fds[1]); - argv[n++] = strdup(t); - - while (n < MAX_ARGS) { - char *a; - - if (!(a = pa_split_spaces(c->conf->extra_arguments, &state))) - break; - - argv[n++] = a; - } - - argv[n++] = NULL; - - execv(argv[0], (char * const *) argv); - _exit(1); -#undef MAX_ARGS - } - - /* Parent */ - - r = waitpid(pid, &status, 0); - - if (c->spawn_api.postfork) - c->spawn_api.postfork(); - - if (r < 0) { - pa_log(__FILE__": waitpid(): %s", pa_cstrerror(errno)); - pa_context_fail(c, PA_ERR_INTERNAL); - goto fail; - } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); - goto fail; - } - - close(fds[1]); - - c->local = 1; - - io = pa_iochannel_new(c->mainloop, fds[0], fds[0]); - - setup_context(c, io); - unlock_autospawn_lock_file(c); - - pa_context_unref(c); - - return 0; - -fail: - if (fds[0] != -1) - close(fds[0]); - if (fds[1] != -1) - close(fds[1]); - - unlock_autospawn_lock_file(c); - - pa_context_unref(c); - - return -1; -} - -#endif /* OS_IS_WIN32 */ - -static int try_next_connection(pa_context *c) { - char *u = NULL; - int r = -1; - - assert(c); - assert(!c->client); - - for (;;) { - pa_xfree(u); - u = NULL; - - c->server_list = pa_strlist_pop(c->server_list, &u); - - if (!u) { - -#ifndef OS_IS_WIN32 - if (c->do_autospawn) { - r = context_connect_spawn(c); - goto finish; - } -#endif - - pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); - goto finish; - } - - pa_log_debug(__FILE__": Trying to connect to %s...", u); - - pa_xfree(c->server); - c->server = pa_xstrdup(u); - - if (!(c->client = pa_socket_client_new_string(c->mainloop, u, PA_NATIVE_DEFAULT_PORT))) - continue; - - c->local = pa_socket_client_is_local(c->client); - pa_socket_client_set_callback(c->client, on_connection, c); - break; - } - - r = 0; - -finish: - pa_xfree(u); - - return r; -} - -static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata) { - pa_context *c = userdata; - - assert(client); - assert(c); - assert(c->state == PA_CONTEXT_CONNECTING); - - pa_context_ref(c); - - pa_socket_client_unref(client); - c->client = NULL; - - if (!io) { - /* Try the item in the list */ - if (errno == ECONNREFUSED || errno == ETIMEDOUT || errno == EHOSTUNREACH) { - try_next_connection(c); - goto finish; - } - - pa_context_fail(c, PA_ERR_CONNECTIONREFUSED); - goto finish; - } - - unlock_autospawn_lock_file(c); - setup_context(c, io); - -finish: - pa_context_unref(c); -} - -int pa_context_connect( - pa_context *c, - const char *server, - pa_context_flags_t flags, - const pa_spawn_api *api) { - - int r = -1; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY(c, c->state == PA_CONTEXT_UNCONNECTED, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(c, !(flags & ~PA_CONTEXT_NOAUTOSPAWN), PA_ERR_INVALID); - PA_CHECK_VALIDITY(c, !server || *server, PA_ERR_INVALID); - - if (!server) - server = c->conf->default_server; - - pa_context_ref(c); - - assert(!c->server_list); - - if (server) { - if (!(c->server_list = pa_strlist_parse(server))) { - pa_context_fail(c, PA_ERR_INVALIDSERVER); - goto finish; - } - } else { - char *d; - char ufn[PATH_MAX]; - - /* Prepend in reverse order */ - - if ((d = getenv("DISPLAY"))) { - char *e; - d = pa_xstrdup(d); - if ((e = strchr(d, ':'))) - *e = 0; - - if (*d) - c->server_list = pa_strlist_prepend(c->server_list, d); - - pa_xfree(d); - } - - c->server_list = pa_strlist_prepend(c->server_list, "tcp6:localhost"); - c->server_list = pa_strlist_prepend(c->server_list, "localhost"); - c->server_list = pa_strlist_prepend(c->server_list, pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET, ufn, sizeof(ufn))); - - /* Wrap the connection attempts in a single transaction for sane autospawn locking */ - if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) { - char lf[PATH_MAX]; - - pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf)); - pa_make_secure_parent_dir(lf); - assert(c->autospawn_lock_fd <= 0); - c->autospawn_lock_fd = pa_lock_lockfile(lf); - - if (api) - c->spawn_api = *api; - c->do_autospawn = 1; - } - - } - - pa_context_set_state(c, PA_CONTEXT_CONNECTING); - r = try_next_connection(c); - -finish: - pa_context_unref(c); - - return r; -} - -void pa_context_disconnect(pa_context *c) { - assert(c); - assert(c->ref >= 1); - - pa_context_set_state(c, PA_CONTEXT_TERMINATED); -} - -pa_context_state_t pa_context_get_state(pa_context *c) { - assert(c); - assert(c->ref >= 1); - - return c->state; -} - -int pa_context_errno(pa_context *c) { - assert(c); - assert(c->ref >= 1); - - return c->error; -} - -void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata) { - assert(c); - assert(c->ref >= 1); - - c->state_callback = cb; - c->state_userdata = userdata; -} - -int pa_context_is_pending(pa_context *c) { - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY(c, - c->state == PA_CONTEXT_CONNECTING || - c->state == PA_CONTEXT_AUTHORIZING || - c->state == PA_CONTEXT_SETTING_NAME || - c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - return (c->pstream && pa_pstream_is_pending(c->pstream)) || - (c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) || - c->client; -} - -static void set_dispatch_callbacks(pa_operation *o); - -static void pdispatch_drain_callback(PA_GCC_UNUSED pa_pdispatch*pd, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void pstream_drain_callback(PA_GCC_UNUSED pa_pstream *s, void *userdata) { - set_dispatch_callbacks(userdata); -} - -static void set_dispatch_callbacks(pa_operation *o) { - int done = 1; - - assert(o); - assert(o->ref >= 1); - assert(o->context); - assert(o->context->ref >= 1); - assert(o->context->state == PA_CONTEXT_READY); - - pa_pstream_set_drain_callback(o->context->pstream, NULL, NULL); - pa_pdispatch_set_drain_callback(o->context->pdispatch, NULL, NULL); - - if (pa_pdispatch_is_pending(o->context->pdispatch)) { - pa_pdispatch_set_drain_callback(o->context->pdispatch, pdispatch_drain_callback, o); - done = 0; - } - - if (pa_pstream_is_pending(o->context->pstream)) { - pa_pstream_set_drain_callback(o->context->pstream, pstream_drain_callback, o); - done = 0; - } - - if (done) { - if (o->callback) { - pa_context_notify_cb_t cb = (pa_context_notify_cb_t) o->callback; - cb(o->context, o->userdata); - } - - pa_operation_done(o); - pa_operation_unref(o); - } -} - -pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata) { - pa_operation *o; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, pa_context_is_pending(c), PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - set_dispatch_callbacks(pa_operation_ref(o)); - - return o; -} - -void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int success = 1; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - success = 0; - } else if (!pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_context_success_cb_t cb = (pa_context_success_cb_t) o->callback; - cb(o->context, success, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_EXIT, &tag); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, pa_pdispatch_cb_t internal_cb, pa_operation_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, cb, userdata); - - t = pa_tagstruct_command(c, command, &tag); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, internal_cb, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SINK, &tag); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SOURCE, &tag); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -int pa_context_is_local(pa_context *c) { - assert(c); - - return c->local; -} - -pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(name); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -const char* pa_get_library_version(void) { - return PACKAGE_VERSION; -} - -const char* pa_context_get_server(pa_context *c) { - assert(c); - assert(c->ref >= 1); - - if (!c->server) - return NULL; - - if (*c->server == '{') { - char *e = strchr(c->server+1, '}'); - return e ? e+1 : c->server; - } - - return c->server; -} - -uint32_t pa_context_get_protocol_version(PA_GCC_UNUSED pa_context *c) { - return PA_PROTOCOL_VERSION; -} - -uint32_t pa_context_get_server_protocol_version(pa_context *c) { - assert(c); - assert(c->ref >= 1); - - return c->version; -} - -pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *tag) { - pa_tagstruct *t; - - assert(c); - assert(tag); - - t = pa_tagstruct_new(NULL, 0); - pa_tagstruct_putu32(t, command); - pa_tagstruct_putu32(t, *tag = c->ctag++); - - return t; -} diff --git a/src/polyp/context.h b/src/polyp/context.h deleted file mode 100644 index 04e2af4d..00000000 --- a/src/polyp/context.h +++ /dev/null @@ -1,230 +0,0 @@ -#ifndef foocontexthfoo -#define foocontexthfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <polyp/sample.h> -#include <polyp/def.h> -#include <polyp/mainloop-api.h> -#include <polyp/cdecl.h> -#include <polyp/operation.h> - -/** \page async Asynchronous API - * - * \section overv_sec Overview - * - * The asynchronous API is the native interface to the polypaudio library. - * It allows full access to all available functions. This also means that - * it is rather complex and can take some time to fully master. - * - * \section mainloop_sec Main Loop Abstraction - * - * The API is based around an asynchronous event loop, or main loop, - * abstraction. This abstraction contains three basic elements: - * - * \li Deferred events - Events that will trigger as soon as possible. Note - * that some implementations may block all other events - * when a deferred event is active. - * \li I/O events - Events that trigger on file descriptor activities. - * \li Times events - Events that trigger after a fixed ammount of time. - * - * The abstraction is represented as a number of function pointers in the - * pa_mainloop_api structure. - * - * To actually be able to use these functions, an implementation needs to - * be coupled to the abstraction. There are three of these shipped with - * polypaudio, but any other can be used with a minimal ammount of work, - * provided it supports the three basic events listed above. - * - * The implementations shipped with polypaudio are: - * - * \li \subpage mainloop - A minimal but fast implementation based on poll(). - * \li \subpage threaded_mainloop - A special version of the previous - * implementation where all of Polypaudio's - * internal handling runs in a separate - * thread. - * \li \subpage glib-mainloop - A wrapper around GLIB's main loop. Available - * for both GLIB 1.2 and GLIB 2.x. - * - * UNIX signals may be hooked to a main loop using the functions from - * \ref mainloop-signal.h. These rely only on the main loop abstraction - * and can therefore be used with any of the implementations. - * - * \section refcnt_sec Reference Counting - * - * Almost all objects in polypaudio are reference counted. What that means - * is that you rarely malloc() or free() any objects. Instead you increase - * and decrease their reference counts. Whenever an object's reference - * count reaches zero, that object gets destroy and any resources it uses - * get freed. - * - * The benefit of this design is that an application need not worry about - * whether or not it needs to keep an object around in case the library is - * using it internally. If it is, then it has made sure it has its own - * reference to it. - * - * Whenever the library creates an object, it will have an initial - * reference count of one. Most of the time, this single reference will be - * sufficient for the application, so all required reference count - * interaction will be a single call to the objects unref function. - * - * \section context_sec Context - * - * A context is the basic object for a connection to a polypaudio server. - * It multiplexes commands, data streams and events through a single - * channel. - * - * There is no need for more than one context per application, unless - * connections to multiple servers are needed. - * - * \subsection ops_subsec Operations - * - * All operations on the context are performed asynchronously. I.e. the - * client will not wait for the server to complete the request. To keep - * track of all these in-flight operations, the application is given a - * pa_operation object for each asynchronous operation. - * - * There are only two actions (besides reference counting) that can be - * performed on a pa_operation: querying its state with - * pa_operation_get_state() and aborting it with pa_operation_cancel(). - * - * A pa_operation object is reference counted, so an application must - * make sure to unreference it, even if it has no intention of using it. - * - * \subsection conn_subsec Connecting - * - * A context must be connected to a server before any operation can be - * issued. Calling pa_context_connect() will initiate the connection - * procedure. Unlike most asynchronous operations, connecting does not - * result in a pa_operation object. Instead, the application should - * register a callback using pa_context_set_state_callback(). - * - * \subsection disc_subsec Disconnecting - * - * When the sound support is no longer needed, the connection needs to be - * closed using pa_context_disconnect(). This is an immediate function that - * works synchronously. - * - * Since the context object has references to other objects it must be - * disconnected after use or there is a high risk of memory leaks. If the - * connection has terminated by itself, then there is no need to explicitly - * disconnect the context using pa_context_disconnect(). - * - * \section Functions - * - * The sound server's functionality can be divided into a number of - * subsections: - * - * \li \subpage streams - * \li \subpage scache - * \li \subpage introspect - * \li \subpage subscribe - */ - -/** \file - * Connection contexts for asynchrononous communication with a - * server. A pa_context object wraps a connection to a polypaudio - * server using its native protocol. */ - -/** \example pacat.c - * A playback and recording tool using the asynchronous API */ - -/** \example paplay.c - * A sound file playback tool using the asynchronous API, based on libsndfile */ - -PA_C_DECL_BEGIN - -/** An opaque connection context to a daemon */ -typedef struct pa_context pa_context; - -/** Generic notification callback prototype */ -typedef void (*pa_context_notify_cb_t)(pa_context *c, void *userdata); - -/** A generic callback for operation completion */ -typedef void (*pa_context_success_cb_t) (pa_context *c, int success, void *userdata); - -/** Instantiate a new connection context with an abstract mainloop API - * and an application name */ -pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name); - -/** Decrease the reference counter of the context by one */ -void pa_context_unref(pa_context *c); - -/** Increase the reference counter of the context by one */ -pa_context* pa_context_ref(pa_context *c); - -/** Set a callback function that is called whenever the context status changes */ -void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, void *userdata); - -/** Return the error number of the last failed operation */ -int pa_context_errno(pa_context *c); - -/** Return non-zero if some data is pending to be written to the connection */ -int pa_context_is_pending(pa_context *c); - -/** Return the current context status */ -pa_context_state_t pa_context_get_state(pa_context *c); - -/** Connect the context to the specified server. If server is NULL, -connect to the default server. This routine may but will not always -return synchronously on error. Use pa_context_set_state_callback() to -be notified when the connection is established. If flags doesn't have -PA_NOAUTOSPAWN set and no specific server is specified or accessible a -new daemon is spawned. If api is non-NULL, the functions specified in -the structure are used when forking a new child process. */ -int pa_context_connect(pa_context *c, const char *server, pa_context_flags_t flags, const pa_spawn_api *api); - -/** Terminate the context connection immediately */ -void pa_context_disconnect(pa_context *c); - -/** Drain the context. If there is nothing to drain, the function returns NULL */ -pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *userdata); - -/** Tell the daemon to exit. The returned operation is unlikely to - * complete succesfully, since the daemon probably died before - * returning a success notification */ -pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata); - -/** Set the name of the default sink. \since 0.4 */ -pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata); - -/** Set the name of the default source. \since 0.4 */ -pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata); - -/** Returns 1 when the connection is to a local daemon. Returns negative when no connection has been made yet. \since 0.5 */ -int pa_context_is_local(pa_context *c); - -/** Set a different application name for context on the server. \since 0.5 */ -pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata); - -/** Return the server name this context is connected to. \since 0.7 */ -const char* pa_context_get_server(pa_context *c); - -/** Return the protocol version of the library. \since 0.8 */ -uint32_t pa_context_get_protocol_version(pa_context *c); - -/** Return the protocol version of the connected server. \since 0.8 */ -uint32_t pa_context_get_server_protocol_version(pa_context *c); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/def.h b/src/polyp/def.h deleted file mode 100644 index 57997163..00000000 --- a/src/polyp/def.h +++ /dev/null @@ -1,312 +0,0 @@ -#ifndef foodefhfoo -#define foodefhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <inttypes.h> -#include <sys/time.h> -#include <time.h> - -#include <polyp/cdecl.h> -#include <polyp/sample.h> - -/** \file - * Global definitions */ - -PA_C_DECL_BEGIN - -/** The state of a connection context */ -typedef enum pa_context_state { - PA_CONTEXT_UNCONNECTED, /**< The context hasn't been connected yet */ - PA_CONTEXT_CONNECTING, /**< A connection is being established */ - PA_CONTEXT_AUTHORIZING, /**< The client is authorizing itself to the daemon */ - PA_CONTEXT_SETTING_NAME, /**< The client is passing its application name to the daemon */ - PA_CONTEXT_READY, /**< The connection is established, the context is ready to execute operations */ - PA_CONTEXT_FAILED, /**< The connection failed or was disconnected */ - PA_CONTEXT_TERMINATED /**< The connection was terminated cleanly */ -} pa_context_state_t; - -/** The state of a stream */ -typedef enum pa_stream_state { - PA_STREAM_UNCONNECTED, /**< The stream is not yet connected to any sink or source */ - PA_STREAM_CREATING, /**< The stream is being created */ - PA_STREAM_READY, /**< The stream is established, you may pass audio data to it now */ - PA_STREAM_FAILED, /**< An error occured that made the stream invalid */ - PA_STREAM_TERMINATED /**< The stream has been terminated cleanly */ -} pa_stream_state_t; - -/** The state of an operation */ -typedef enum pa_operation_state { - PA_OPERATION_RUNNING, /**< The operation is still running */ - PA_OPERATION_DONE, /**< The operation has been completed */ - PA_OPERATION_CANCELED /**< The operation has been canceled */ -} pa_operation_state_t; - -/** An invalid index */ -#define PA_INVALID_INDEX ((uint32_t) -1) - -/** Some special flags for contexts. \since 0.8 */ -typedef enum pa_context_flags { - PA_CONTEXT_NOAUTOSPAWN = 1 /**< Disabled autospawning of the polypaudio daemon if required */ -} pa_context_flags_t; - -/** The direction of a pa_stream object */ -typedef enum pa_stream_direction { - PA_STREAM_NODIRECTION, /**< Invalid direction */ - PA_STREAM_PLAYBACK, /**< Playback stream */ - PA_STREAM_RECORD, /**< Record stream */ - PA_STREAM_UPLOAD /**< Sample upload stream */ -} pa_stream_direction_t; - -/** Some special flags for stream connections. \since 0.6 */ -typedef enum pa_stream_flags { - PA_STREAM_START_CORKED = 1, /**< Create the stream corked, requiring an explicit pa_stream_cork() call to uncork it. */ - PA_STREAM_INTERPOLATE_TIMING = 2, /**< Interpolate the latency for - * this stream. When enabled, - * pa_stream_get_latency() and - * pa_stream_get_time() will try - * to estimate the current - * record/playback time based on - * the local time that passed - * since the last timing info - * update. Using this option - * has the advantage of not - * requiring a whole roundtrip - * when the current - * playback/recording time is - * needed. Consider using this - * option when requesting - * latency information - * frequently. This is - * especially useful on long - * latency network - * connections. It makes a lot - * of sense to combine this - * option with - * PA_STREAM_AUTO_TIMING_UPDATE. */ - PA_STREAM_NOT_MONOTONOUS = 4, /**< Don't force the time to - * increase monotonically. If - * this option is enabled, - * pa_stream_get_time() will not - * necessarily return always - * monotonically increasing time - * values on each call. This may - * confuse applications which - * cannot deal with time going - * 'backwards', but has the - * advantage that bad transport - * latency estimations that - * caused the time to to jump - * ahead can be corrected - * quickly, without the need to - * wait. */ - PA_STREAM_AUTO_TIMING_UPDATE = 8 /**< If set timing update requests - * are issued periodically - * automatically. Combined with - * PA_STREAM_INTERPOLATE_TIMING - * you will be able to query the - * current time and latency with - * pa_stream_get_time() and - * pa_stream_get_latency() at - * all times without a packet - * round trip.*/ -} pa_stream_flags_t; - -/** Playback and record buffer metrics */ -typedef struct pa_buffer_attr { - uint32_t maxlength; /**< Maximum length of the buffer */ - uint32_t tlength; /**< Playback only: target length of the buffer. The server tries to assure that at least tlength bytes are always available in the buffer */ - uint32_t prebuf; /**< Playback only: pre-buffering. The server does not start with playback before at least prebug bytes are available in the buffer */ - uint32_t minreq; /**< Playback only: minimum request. The server does not request less than minreq bytes from the client, instead waints until the buffer is free enough to request more bytes at once */ - uint32_t fragsize; /**< Recording only: fragment size. The server sends data in blocks of fragsize bytes size. Large values deminish interactivity with other operations on the connection context but decrease control overhead. */ -} pa_buffer_attr; - -/** Error values as used by pa_context_errno(). Use pa_strerror() to convert these values to human readable strings */ -enum { - PA_OK = 0, /**< No error */ - PA_ERR_ACCESS, /**< Access failure */ - PA_ERR_COMMAND, /**< Unknown command */ - PA_ERR_INVALID, /**< Invalid argument */ - PA_ERR_EXIST, /**< Entity exists */ - PA_ERR_NOENTITY, /**< No such entity */ - PA_ERR_CONNECTIONREFUSED, /**< Connection refused */ - PA_ERR_PROTOCOL, /**< Protocol error */ - PA_ERR_TIMEOUT, /**< Timeout */ - PA_ERR_AUTHKEY, /**< No authorization key */ - PA_ERR_INTERNAL, /**< Internal error */ - PA_ERR_CONNECTIONTERMINATED, /**< Connection terminated */ - PA_ERR_KILLED, /**< Entity killed */ - PA_ERR_INVALIDSERVER, /**< Invalid server */ - PA_ERR_MODINITFAILED, /**< Module initialization failed */ - PA_ERR_BADSTATE, /**< Bad state */ - PA_ERR_NODATA, /**< No data */ - PA_ERR_VERSION, /**< Incompatible protocol version \since 0.8 */ - PA_ERR_TOOLARGE, /**< Data too large \since 0.8.1 */ - PA_ERR_MAX /**< Not really an error but the first invalid error code */ -}; - -/** Subscription event mask, as used by pa_context_subscribe() */ -typedef enum pa_subscription_mask { - PA_SUBSCRIPTION_MASK_NULL = 0, /**< No events */ - PA_SUBSCRIPTION_MASK_SINK = 1, /**< Sink events */ - PA_SUBSCRIPTION_MASK_SOURCE = 2, /**< Source events */ - PA_SUBSCRIPTION_MASK_SINK_INPUT = 4, /**< Sink input events */ - PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT = 8, /**< Source output events */ - PA_SUBSCRIPTION_MASK_MODULE = 16, /**< Module events */ - PA_SUBSCRIPTION_MASK_CLIENT = 32, /**< Client events */ - PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, /**< Sample cache events */ - PA_SUBSCRIPTION_MASK_SERVER = 128, /**< Other global server changes. \since 0.4 */ - PA_SUBSCRIPTION_MASK_AUTOLOAD = 256, /**< Autoload table events. \since 0.5 */ - PA_SUBSCRIPTION_MASK_ALL = 511 /**< Catch all events \since 0.8 */ -} pa_subscription_mask_t; - -/** Subscription event types, as used by pa_context_subscribe() */ -typedef enum pa_subscription_event_type { - PA_SUBSCRIPTION_EVENT_SINK = 0, /**< Event type: Sink */ - PA_SUBSCRIPTION_EVENT_SOURCE = 1, /**< Event type: Source */ - PA_SUBSCRIPTION_EVENT_SINK_INPUT = 2, /**< Event type: Sink input */ - PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT = 3, /**< Event type: Source output */ - PA_SUBSCRIPTION_EVENT_MODULE = 4, /**< Event type: Module */ - PA_SUBSCRIPTION_EVENT_CLIENT = 5, /**< Event type: Client */ - PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6, /**< Event type: Sample cache item */ - PA_SUBSCRIPTION_EVENT_SERVER = 7, /**< Event type: Global server change, only occuring with PA_SUBSCRIPTION_EVENT_CHANGE. \since 0.4 */ - PA_SUBSCRIPTION_EVENT_AUTOLOAD = 8, /**< Event type: Autoload table changes. \since 0.5 */ - PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 15, /**< A mask to extract the event type from an event value */ - - PA_SUBSCRIPTION_EVENT_NEW = 0, /**< A new object was created */ - PA_SUBSCRIPTION_EVENT_CHANGE = 16, /**< A property of the object was modified */ - PA_SUBSCRIPTION_EVENT_REMOVE = 32, /**< An object was removed */ - PA_SUBSCRIPTION_EVENT_TYPE_MASK = 16+32 /**< A mask to extract the event operation from an event value */ -} pa_subscription_event_type_t; - -/** Return one if an event type t matches an event mask bitfield */ -#define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK)))) - -/** A structure for all kinds of timing information of a stream. See - * pa_stream_update_timing_info() and pa_stream_get_timing_info(). The - * total output latency a sample that is written with - * pa_stream_write() takes to be played may be estimated by - * sink_usec+buffer_usec+transport_usec. (where buffer_usec is defined - * as pa_bytes_to_usec(write_index-read_index)) The output buffer - * which buffer_usec relates to may be manipulated freely (with - * pa_stream_write()'s seek argument, pa_stream_flush() and friends), - * the buffers sink_usec and source_usec relate to are first-in - * first-out (FIFO) buffers which cannot be flushed or manipulated in - * any way. The total input latency a sample that is recorded takes to - * be delivered to the application is: - * source_usec+buffer_usec+transport_usec-sink_usec. (Take care of - * sign issues!) When connected to a monitor source sink_usec contains - * the latency of the owning sink. The two latency estimations - * described here are implemented in pa_stream_get_latency().*/ -typedef struct pa_timing_info { - struct timeval timestamp; /**< The time when this timing info structure was current */ - int synchronized_clocks; /**< Non-zero if the local and the - * remote machine have synchronized - * clocks. If synchronized clocks are - * detected transport_usec becomes much - * more reliable. However, the code that - * detects synchronized clocks is very - * limited und unreliable itself. \since - * 0.5 */ - - pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. For playback streams and record streams connected to a monitor source. */ - pa_usec_t source_usec; /**< Time in usecs a sample takes from being recorded to being delivered to the application. Only for record streams. \since 0.5*/ - pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to/from the daemon. For both playback and record streams. \since 0.5 */ - - int playing; /**< Non-zero when the stream is currently playing. Only for playback streams. */ - - int write_index_corrupt; /**< Non-zero if write_index is not - * up-to-date because a local write - * command that corrupted it has been - * issued in the time since this latency - * info was current . Only write - * commands with SEEK_RELATIVE_ON_READ - * and SEEK_RELATIVE_END can corrupt - * write_index. \since 0.8 */ - int64_t write_index; /**< Current write index into the - * playback buffer in bytes. Think twice before - * using this for seeking purposes: it - * might be out of date a the time you - * want to use it. Consider using - * PA_SEEK_RELATIVE instead. \since - * 0.8 */ - - int read_index_corrupt; /**< Non-zero if read_index is not - * up-to-date because a local pause or - * flush request that corrupted it has - * been issued in the time since this - * latency info was current. \since 0.8 */ - - int64_t read_index; /**< Current read index into the - * playback buffer in bytes. Think twice before - * using this for seeking purposes: it - * might be out of date a the time you - * want to use it. Consider using - * PA_SEEK_RELATIVE_ON_READ - * instead. \since 0.8 */ -} pa_timing_info; - -/** A structure for the spawn api. This may be used to integrate auto - * spawned daemons into your application. For more information see - * pa_context_connect(). When spawning a new child process the - * waitpid() is used on the child's PID. The spawn routine will not - * block or ignore SIGCHLD signals, since this cannot be done in a - * thread compatible way. You might have to do this in - * prefork/postfork. \since 0.4 */ -typedef struct pa_spawn_api { - void (*prefork)(void); /**< Is called just before the fork in the parent process. May be NULL. */ - void (*postfork)(void); /**< Is called immediately after the fork in the parent process. May be NULL.*/ - void (*atfork)(void); /**< Is called immediately after the - * fork in the child process. May be - * NULL. It is not safe to close all - * file descriptors in this function - * unconditionally, since a UNIX socket - * (created using socketpair()) is - * passed to the new process. */ -} pa_spawn_api; - -/** Seek type for pa_stream_write(). \since 0.8*/ -typedef enum pa_seek_mode { - PA_SEEK_RELATIVE = 0, /**< Seek relatively to the write index */ - PA_SEEK_ABSOLUTE = 1, /**< Seek relatively to the start of the buffer queue */ - PA_SEEK_RELATIVE_ON_READ = 2, /**< Seek relatively to the read index. */ - PA_SEEK_RELATIVE_END = 3 /**< Seek relatively to the current end of the buffer queue. */ -} pa_seek_mode_t; - -/** Special sink flags. \since 0.8 */ -typedef enum pa_sink_flags { - PA_SINK_HW_VOLUME_CTRL = 1, /**< Supports hardware volume control */ - PA_SINK_LATENCY = 2 /**< Supports latency querying */ -} pa_sink_flags_t; - -/** Special source flags. \since 0.8 */ -typedef enum pa_source_flags { - PA_SOURCE_HW_VOLUME_CTRL = 1, /**< Supports hardware volume control */ - PA_SOURCE_LATENCY = 2 /**< Supports latency querying */ -} pa_source_flags_t; - -/** A generic free() like callback prototype */ -typedef void (*pa_free_cb_t)(void *p); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/error.c b/src/polyp/error.c deleted file mode 100644 index 27da7eae..00000000 --- a/src/polyp/error.c +++ /dev/null @@ -1,66 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <polyp/xmalloc.h> - -#include <polypcore/core-util.h> -#include <polypcore/native-common.h> - -#include "error.h" - -const char*pa_strerror(int error) { - - static const char* const errortab[PA_ERR_MAX] = { - [PA_OK] = "OK", - [PA_ERR_ACCESS] = "Access denied", - [PA_ERR_COMMAND] = "Unknown command", - [PA_ERR_INVALID] = "Invalid argument", - [PA_ERR_EXIST] = "Entity exists", - [PA_ERR_NOENTITY] = "No such entity", - [PA_ERR_CONNECTIONREFUSED] = "Connection refused", - [PA_ERR_PROTOCOL] = "Protocol error", - [PA_ERR_TIMEOUT] = "Timeout", - [PA_ERR_AUTHKEY] = "No authorization key", - [PA_ERR_INTERNAL] = "Internal error", - [PA_ERR_CONNECTIONTERMINATED] = "Connection terminated", - [PA_ERR_KILLED] = "Entity killed", - [PA_ERR_INVALIDSERVER] = "Invalid server", - [PA_ERR_MODINITFAILED] = "Module initalization failed", - [PA_ERR_BADSTATE] = "Bad state", - [PA_ERR_NODATA] = "No data", - [PA_ERR_VERSION] = "Incompatible protocol version", - [PA_ERR_TOOLARGE] = "Too large" - }; - - if (error < 0 || error >= PA_ERR_MAX) - return NULL; - - return errortab[error]; -} diff --git a/src/polyp/error.h b/src/polyp/error.h deleted file mode 100644 index 9856c1af..00000000 --- a/src/polyp/error.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef fooerrorhfoo -#define fooerrorhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <inttypes.h> -#include <polyp/cdecl.h> - -/** \file - * Error management */ - -PA_C_DECL_BEGIN - -/** Return a human readable error message for the specified numeric error code */ -const char* pa_strerror(int error); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/glib-mainloop.c b/src/polyp/glib-mainloop.c deleted file mode 100644 index d5fce767..00000000 --- a/src/polyp/glib-mainloop.c +++ /dev/null @@ -1,541 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <assert.h> - -#include <polyp/xmalloc.h> -#include <polyp/timeval.h> - -#include <polypcore/idxset.h> -#include <polypcore/core-util.h> - -#include "glib.h" -#include "glib-mainloop.h" - -struct pa_io_event { - pa_glib_mainloop *mainloop; - int dead; - GIOChannel *io_channel; - GSource *source; - GIOCondition io_condition; - int fd; - void (*callback) (pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_io_event *e, void *userdata); - pa_io_event *next, *prev; -}; - -struct pa_time_event { - pa_glib_mainloop *mainloop; - int dead; - GSource *source; - struct timeval timeval; - void (*callback) (pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_time_event*e, void *userdata); - pa_time_event *next, *prev; -}; - -struct pa_defer_event { - pa_glib_mainloop *mainloop; - int dead; - GSource *source; - void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_defer_event*e, void *userdata); - pa_defer_event *next, *prev; -}; - -struct pa_glib_mainloop { - GMainContext *glib_main_context; - pa_mainloop_api api; - GSource *cleanup_source; - pa_io_event *io_events, *dead_io_events; - pa_time_event *time_events, *dead_time_events; - pa_defer_event *defer_events, *dead_defer_events; -}; - -static void schedule_free_dead_events(pa_glib_mainloop *g); - -static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f); - -static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags_t f, void (*callback) (pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata), void *userdata) { - pa_io_event *e; - pa_glib_mainloop *g; - - assert(m && m->userdata && fd >= 0 && callback); - g = m->userdata; - - e = pa_xmalloc(sizeof(pa_io_event)); - e->mainloop = m->userdata; - e->dead = 0; - e->fd = fd; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - - e->io_channel = g_io_channel_unix_new(e->fd); - assert(e->io_channel); - e->source = NULL; - e->io_condition = 0; - - glib_io_enable(e, f); - - e->next = g->io_events; - if (e->next) e->next->prev = e; - g->io_events = e; - e->prev = NULL; - - return e; -} - -/* The callback GLIB calls whenever an IO condition is met */ -static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) { - pa_io_event *e = data; - pa_io_event_flags_t f; - assert(source && e && e->io_channel == source); - - f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | - (condition & G_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) | - (condition & G_IO_ERR ? PA_IO_EVENT_ERROR : 0) | - (condition & G_IO_HUP ? PA_IO_EVENT_HANGUP : 0); - - e->callback(&e->mainloop->api, e, e->fd, f, e->userdata); - return TRUE; -} - -static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) { - GIOCondition c; - assert(e && !e->dead); - - c = (f & PA_IO_EVENT_INPUT ? G_IO_IN : 0) | (f & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0); - - if (c == e->io_condition) - return; - - if (e->source) { - g_source_destroy(e->source); - g_source_unref(e->source); - } - - e->source = g_io_create_watch(e->io_channel, c | G_IO_ERR | G_IO_HUP); - assert(e->source); - - g_source_set_callback(e->source, (GSourceFunc) io_cb, e, NULL); - g_source_attach(e->source, e->mainloop->glib_main_context); - g_source_set_priority(e->source, G_PRIORITY_DEFAULT); - - e->io_condition = c; -} - -static void glib_io_free(pa_io_event*e) { - assert(e && !e->dead); - - if (e->source) { - g_source_destroy(e->source); - g_source_unref(e->source); - e->source = NULL; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->io_events = e->next; - - if (e->next) - e->next->prev = e->prev; - - if ((e->next = e->mainloop->dead_io_events)) - e->next->prev = e; - - e->mainloop->dead_io_events = e; - e->prev = NULL; - - e->dead = 1; - schedule_free_dead_events(e->mainloop); -} - -static void glib_io_set_destroy(pa_io_event*e, void (*callback)(pa_mainloop_api*m, pa_io_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* Time sources */ - -static void glib_time_restart(pa_time_event*e, const struct timeval *tv); - -static pa_time_event* glib_time_new(pa_mainloop_api*m, const struct timeval *tv, void (*callback) (pa_mainloop_api*m, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { - pa_glib_mainloop *g; - pa_time_event *e; - - assert(m && m->userdata && tv && callback); - g = m->userdata; - - e = pa_xmalloc(sizeof(pa_time_event)); - e->mainloop = g; - e->dead = 0; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - e->source = NULL; - - glib_time_restart(e, tv); - - e->next = g->time_events; - if (e->next) e->next->prev = e; - g->time_events = e; - e->prev = NULL; - - return e; -} - -static guint msec_diff(const struct timeval *a, const struct timeval *b) { - guint r; - assert(a && b); - - if (a->tv_sec < b->tv_sec) - return 0; - - if (a->tv_sec == b->tv_sec && a->tv_sec <= b->tv_sec) - return 0; - - r = (a->tv_sec-b->tv_sec)*1000; - - if (a->tv_usec >= b->tv_usec) - r += (a->tv_usec - b->tv_usec) / 1000; - else - r -= (b->tv_usec - a->tv_usec) / 1000; - - return r; -} - -static gboolean time_cb(gpointer data) { - pa_time_event* e = data; - assert(e && e->mainloop && e->source); - - g_source_unref(e->source); - e->source = NULL; - - e->callback(&e->mainloop->api, e, &e->timeval, e->userdata); - return FALSE; -} - -static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { - struct timeval now; - assert(e && e->mainloop && !e->dead); - - pa_gettimeofday(&now); - if (e->source) { - g_source_destroy(e->source); - g_source_unref(e->source); - } - - if (tv) { - e->timeval = *tv; - e->source = g_timeout_source_new(msec_diff(tv, &now)); - assert(e->source); - g_source_set_callback(e->source, time_cb, e, NULL); - g_source_set_priority(e->source, G_PRIORITY_DEFAULT); - g_source_attach(e->source, e->mainloop->glib_main_context); - } else - e->source = NULL; - } - -static void glib_time_free(pa_time_event *e) { - assert(e && e->mainloop && !e->dead); - - if (e->source) { - g_source_destroy(e->source); - g_source_unref(e->source); - e->source = NULL; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->time_events = e->next; - - if (e->next) - e->next->prev = e->prev; - - if ((e->next = e->mainloop->dead_time_events)) - e->next->prev = e; - - e->mainloop->dead_time_events = e; - e->prev = NULL; - - e->dead = 1; - schedule_free_dead_events(e->mainloop); -} - -static void glib_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*m, pa_time_event*e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* Deferred sources */ - -static void glib_defer_enable(pa_defer_event *e, int b); - -static pa_defer_event* glib_defer_new(pa_mainloop_api*m, void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata), void *userdata) { - pa_defer_event *e; - pa_glib_mainloop *g; - - assert(m && m->userdata && callback); - g = m->userdata; - - e = pa_xmalloc(sizeof(pa_defer_event)); - e->mainloop = g; - e->dead = 0; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - e->source = NULL; - - glib_defer_enable(e, 1); - - e->next = g->defer_events; - if (e->next) e->next->prev = e; - g->defer_events = e; - e->prev = NULL; - return e; -} - -static gboolean idle_cb(gpointer data) { - pa_defer_event* e = data; - assert(e && e->mainloop && e->source); - - e->callback(&e->mainloop->api, e, e->userdata); - return TRUE; -} - -static void glib_defer_enable(pa_defer_event *e, int b) { - assert(e && e->mainloop); - - if (e->source && !b) { - g_source_destroy(e->source); - g_source_unref(e->source); - e->source = NULL; - } else if (!e->source && b) { - e->source = g_idle_source_new(); - assert(e->source); - g_source_set_callback(e->source, idle_cb, e, NULL); - g_source_attach(e->source, e->mainloop->glib_main_context); - g_source_set_priority(e->source, G_PRIORITY_HIGH); - } -} - -static void glib_defer_free(pa_defer_event *e) { - assert(e && e->mainloop && !e->dead); - - if (e->source) { - g_source_destroy(e->source); - g_source_unref(e->source); - e->source = NULL; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->defer_events = e->next; - - if (e->next) - e->next->prev = e->prev; - - if ((e->next = e->mainloop->dead_defer_events)) - e->next->prev = e; - - e->mainloop->dead_defer_events = e; - e->prev = NULL; - - e->dead = 1; - schedule_free_dead_events(e->mainloop); -} - -static void glib_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api *m, pa_defer_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* quit() */ - -static void glib_quit(pa_mainloop_api*a, PA_GCC_UNUSED int retval) { - pa_glib_mainloop *g; - assert(a && a->userdata); - g = a->userdata; - - /* NOOP */ -} - -static const pa_mainloop_api vtable = { - .userdata = NULL, - - .io_new = glib_io_new, - .io_enable = glib_io_enable, - .io_free = glib_io_free, - .io_set_destroy= glib_io_set_destroy, - - .time_new = glib_time_new, - .time_restart = glib_time_restart, - .time_free = glib_time_free, - .time_set_destroy = glib_time_set_destroy, - - .defer_new = glib_defer_new, - .defer_enable = glib_defer_enable, - .defer_free = glib_defer_free, - .defer_set_destroy = glib_defer_set_destroy, - - .quit = glib_quit, -}; - -pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c) { - pa_glib_mainloop *g; - - g = pa_xmalloc(sizeof(pa_glib_mainloop)); - if (c) { - g->glib_main_context = c; - g_main_context_ref(c); - } else - g->glib_main_context = g_main_context_default(); - - g->api = vtable; - g->api.userdata = g; - - g->io_events = g->dead_io_events = NULL; - g->time_events = g->dead_time_events = NULL; - g->defer_events = g->dead_defer_events = NULL; - - g->cleanup_source = NULL; - return g; -} - -static void free_io_events(pa_io_event *e) { - while (e) { - pa_io_event *r = e; - e = r->next; - - if (r->source) { - g_source_destroy(r->source); - g_source_unref(r->source); - } - - if (r->io_channel) - g_io_channel_unref(r->io_channel); - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -static void free_time_events(pa_time_event *e) { - while (e) { - pa_time_event *r = e; - e = r->next; - - if (r->source) { - g_source_destroy(r->source); - g_source_unref(r->source); - } - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -static void free_defer_events(pa_defer_event *e) { - while (e) { - pa_defer_event *r = e; - e = r->next; - - if (r->source) { - g_source_destroy(r->source); - g_source_unref(r->source); - } - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -void pa_glib_mainloop_free(pa_glib_mainloop* g) { - assert(g); - - free_io_events(g->io_events); - free_io_events(g->dead_io_events); - free_defer_events(g->defer_events); - free_defer_events(g->dead_defer_events); - free_time_events(g->time_events); - free_time_events(g->dead_time_events); - - if (g->cleanup_source) { - g_source_destroy(g->cleanup_source); - g_source_unref(g->cleanup_source); - } - - g_main_context_unref(g->glib_main_context); - pa_xfree(g); -} - -pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) { - assert(g); - return &g->api; -} - -static gboolean free_dead_events(gpointer p) { - pa_glib_mainloop *g = p; - assert(g); - - free_io_events(g->dead_io_events); - free_defer_events(g->dead_defer_events); - free_time_events(g->dead_time_events); - - g->dead_io_events = NULL; - g->dead_defer_events = NULL; - g->dead_time_events = NULL; - - g_source_destroy(g->cleanup_source); - g_source_unref(g->cleanup_source); - g->cleanup_source = NULL; - - return FALSE; -} - -static void schedule_free_dead_events(pa_glib_mainloop *g) { - assert(g && g->glib_main_context); - - if (g->cleanup_source) - return; - - g->cleanup_source = g_idle_source_new(); - assert(g->cleanup_source); - g_source_set_callback(g->cleanup_source, free_dead_events, g, NULL); - g_source_attach(g->cleanup_source, g->glib_main_context); -} diff --git a/src/polyp/glib-mainloop.h b/src/polyp/glib-mainloop.h deleted file mode 100644 index ce885e13..00000000 --- a/src/polyp/glib-mainloop.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef fooglibmainloophfoo -#define fooglibmainloophfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <glib.h> - -#include <polyp/mainloop-api.h> -#include <polyp/cdecl.h> - -/** \page glib-mainloop GLIB Main Loop Bindings - * - * \section overv_sec Overview - * - * The GLIB main loop bindings are extremely easy to use. All that is - * required is to create a pa_glib_mainloop object using - * pa_glib_mainloop_new(). When the main loop abstraction is needed, it is - * provided by pa_glib_mainloop_get_api(). - * - */ - -/** \file - * GLIB main loop support */ - -PA_C_DECL_BEGIN - -/** An opaque GLIB main loop object */ -typedef struct pa_glib_mainloop pa_glib_mainloop; - -/** Create a new GLIB main loop object for the specified GLIB main - * loop context. The GLIB 2.0 version takes an argument c for the - * GMainContext to use. If c is NULL the default context is used. */ -#if GLIB_MAJOR_VERSION >= 2 -pa_glib_mainloop *pa_glib_mainloop_new(GMainContext *c); -#else -pa_glib_mainloop *pa_glib_mainloop_new(void); -#endif - -/** Free the GLIB main loop object */ -void pa_glib_mainloop_free(pa_glib_mainloop* g); - -/** Return the abstract main loop API vtable for the GLIB main loop object */ -pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/glib12-mainloop.c b/src/polyp/glib12-mainloop.c deleted file mode 100644 index dfd6ff2f..00000000 --- a/src/polyp/glib12-mainloop.c +++ /dev/null @@ -1,503 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <assert.h> - -#include <polyp/timeval.h> -#include <polyp/xmalloc.h> - -#include <polypcore/idxset.h> -#include <polypcore/core-util.h> - -#include "glib-mainloop.h" - -/* A mainloop implementation based on GLIB 1.2 */ - -struct pa_io_event { - pa_glib_mainloop *mainloop; - int dead; - GIOChannel *io_channel; - guint source; - GIOCondition io_condition; - int fd; - void (*callback) (pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_io_event*e, void *userdata); - pa_io_event *next, *prev; -}; - -struct pa_time_event { - pa_glib_mainloop *mainloop; - int dead; - guint source; - struct timeval timeval; - void (*callback) (pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_time_event*e, void *userdata); - pa_time_event *next, *prev; -}; - -struct pa_defer_event { - pa_glib_mainloop *mainloop; - int dead; - guint source; - void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api *m, pa_defer_event*e, void *userdata); - pa_defer_event *next, *prev; -}; - -struct pa_glib_mainloop { - pa_mainloop_api api; - guint cleanup_source; - pa_io_event *io_events, *dead_io_events; - pa_time_event *time_events, *dead_time_events; - pa_defer_event *defer_events, *dead_defer_events; -}; - -static void schedule_free_dead_events(pa_glib_mainloop *g); - -static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f); - -static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags_t f, void (*callback) (pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags_t f, void *userdata), void *userdata) { - pa_io_event *e; - pa_glib_mainloop *g; - - assert(m && m->userdata && fd >= 0 && callback); - g = m->userdata; - - e = pa_xmalloc(sizeof(pa_io_event)); - e->mainloop = m->userdata; - e->dead = 0; - e->fd = fd; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - - e->io_channel = g_io_channel_unix_new(e->fd); - assert(e->io_channel); - e->source = (guint) -1; - e->io_condition = 0; - - glib_io_enable(e, f); - - e->next = g->io_events; - if (e->next) e->next->prev = e; - g->io_events = e; - e->prev = NULL; - - return e; -} - -static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) { - pa_io_event *e = data; - pa_io_event_flags_t f; - assert(source && e && e->io_channel == source); - - f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | - (condition & G_IO_OUT ? PA_IO_EVENT_OUTPUT : 0) | - (condition & G_IO_ERR ? PA_IO_EVENT_ERROR : 0) | - (condition & G_IO_HUP ? PA_IO_EVENT_HANGUP : 0); - - e->callback(&e->mainloop->api, e, e->fd, f, e->userdata); - return TRUE; -} - -static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) { - GIOCondition c; - assert(e && !e->dead); - - c = (f & PA_IO_EVENT_INPUT ? G_IO_IN : 0) | (f & PA_IO_EVENT_OUTPUT ? G_IO_OUT : 0); - - if (c == e->io_condition) - return; - - if (e->source != (guint) -1) - g_source_remove(e->source); - - e->source = g_io_add_watch_full(e->io_channel, G_PRIORITY_DEFAULT, c | G_IO_ERR | G_IO_HUP, io_cb, e, NULL); - assert(e->source != (guint) -1); - e->io_condition = c; -} - -static void glib_io_free(pa_io_event*e) { - assert(e && !e->dead); - - if (e->source != (guint) -1) { - g_source_remove(e->source); - e->source = (guint) -1; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->io_events = e->next; - - if (e->next) - e->next->prev = e->prev; - - if ((e->next = e->mainloop->dead_io_events)) - e->next->prev = e; - - e->mainloop->dead_io_events = e; - e->prev = NULL; - - e->dead = 1; - schedule_free_dead_events(e->mainloop); -} - -static void glib_io_set_destroy(pa_io_event*e, void (*callback)(pa_mainloop_api*m, pa_io_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* Time sources */ - -static void glib_time_restart(pa_time_event*e, const struct timeval *tv); - -static pa_time_event* glib_time_new(pa_mainloop_api*m, const struct timeval *tv, void (*callback) (pa_mainloop_api*m, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { - pa_glib_mainloop *g; - pa_time_event *e; - - assert(m && m->userdata && tv && callback); - g = m->userdata; - - e = pa_xmalloc(sizeof(pa_time_event)); - e->mainloop = g; - e->dead = 0; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - e->source = (guint) -1; - - glib_time_restart(e, tv); - - e->next = g->time_events; - if (e->next) e->next->prev = e; - g->time_events = e; - e->prev = NULL; - - return e; -} - -static guint msec_diff(const struct timeval *a, const struct timeval *b) { - guint r; - assert(a && b); - - if (a->tv_sec < b->tv_sec) - return 0; - - if (a->tv_sec == b->tv_sec && a->tv_sec <= b->tv_sec) - return 0; - - r = (a->tv_sec-b->tv_sec)*1000; - - if (a->tv_usec >= b->tv_usec) - r += (a->tv_usec - b->tv_usec) / 1000; - else - r -= (b->tv_usec - a->tv_usec) / 1000; - - return r; -} - -static gboolean time_cb(gpointer data) { - pa_time_event* e = data; - assert(e && e->mainloop && e->source != (guint) -1); - - g_source_remove(e->source); - e->source = (guint) -1; - - e->callback(&e->mainloop->api, e, &e->timeval, e->userdata); - return FALSE; -} - -static void glib_time_restart(pa_time_event*e, const struct timeval *tv) { - struct timeval now; - assert(e && e->mainloop && !e->dead); - - pa_gettimeofday(&now); - if (e->source != (guint) -1) - g_source_remove(e->source); - - if (tv) { - e->timeval = *tv; - e->source = g_timeout_add_full(G_PRIORITY_DEFAULT, msec_diff(tv, &now), time_cb, e, NULL); - assert(e->source != (guint) -1); - } else - e->source = (guint) -1; - } - -static void glib_time_free(pa_time_event *e) { - assert(e && e->mainloop && !e->dead); - - if (e->source != (guint) -1) { - g_source_remove(e->source); - e->source = (guint) -1; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->time_events = e->next; - - if (e->next) - e->next->prev = e->prev; - - if ((e->next = e->mainloop->dead_time_events)) - e->next->prev = e; - - e->mainloop->dead_time_events = e; - e->prev = NULL; - - e->dead = 1; - schedule_free_dead_events(e->mainloop); -} - -static void glib_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*m, pa_time_event*e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* Deferred sources */ - -static void glib_defer_enable(pa_defer_event *e, int b); - -static pa_defer_event* glib_defer_new(pa_mainloop_api*m, void (*callback) (pa_mainloop_api*m, pa_defer_event *e, void *userdata), void *userdata) { - pa_defer_event *e; - pa_glib_mainloop *g; - - assert(m && m->userdata && callback); - g = m->userdata; - - e = pa_xmalloc(sizeof(pa_defer_event)); - e->mainloop = g; - e->dead = 0; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - e->source = (guint) -1; - - glib_defer_enable(e, 1); - - e->next = g->defer_events; - if (e->next) e->next->prev = e; - g->defer_events = e; - e->prev = NULL; - return e; -} - -static gboolean idle_cb(gpointer data) { - pa_defer_event* e = data; - assert(e && e->mainloop && e->source != (guint) -1); - - e->callback(&e->mainloop->api, e, e->userdata); - return TRUE; -} - -static void glib_defer_enable(pa_defer_event *e, int b) { - assert(e && e->mainloop); - - if (e->source != (guint) -1 && !b) { - g_source_remove(e->source); - e->source = (guint) -1; - } else if (e->source == (guint) -1 && b) { - e->source = g_idle_add_full(G_PRIORITY_HIGH, idle_cb, e, NULL); - assert(e->source != (guint) -1); - } -} - -static void glib_defer_free(pa_defer_event *e) { - assert(e && e->mainloop && !e->dead); - - if (e->source != (guint) -1) { - g_source_remove(e->source); - e->source = (guint) -1; - } - - if (e->prev) - e->prev->next = e->next; - else - e->mainloop->defer_events = e->next; - - if (e->next) - e->next->prev = e->prev; - - if ((e->next = e->mainloop->dead_defer_events)) - e->next->prev = e; - - e->mainloop->dead_defer_events = e; - e->prev = NULL; - - e->dead = 1; - schedule_free_dead_events(e->mainloop); -} - -static void glib_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api *m, pa_defer_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* quit() */ - -static void glib_quit(pa_mainloop_api*a, PA_GCC_UNUSED int retval) { - pa_glib_mainloop *g; - assert(a && a->userdata); - g = a->userdata; - - /* NOOP */ -} - -static const pa_mainloop_api vtable = { - .userdata = NULL, - - .io_new = glib_io_new, - .io_enable = glib_io_enable, - .io_free = glib_io_free, - .io_set_destroy= glib_io_set_destroy, - - .time_new = glib_time_new, - .time_restart = glib_time_restart, - .time_free = glib_time_free, - .time_set_destroy = glib_time_set_destroy, - - .defer_new = glib_defer_new, - .defer_enable = glib_defer_enable, - .defer_free = glib_defer_free, - .defer_set_destroy = glib_defer_set_destroy, - - .quit = glib_quit, -}; - -pa_glib_mainloop *pa_glib_mainloop_new(void) { - pa_glib_mainloop *g; - - g = pa_xmalloc(sizeof(pa_glib_mainloop)); - - g->api = vtable; - g->api.userdata = g; - - g->io_events = g->dead_io_events = NULL; - g->time_events = g->dead_time_events = NULL; - g->defer_events = g->dead_defer_events = NULL; - - g->cleanup_source = (guint) -1; - return g; -} - -static void free_io_events(pa_io_event *e) { - while (e) { - pa_io_event *r = e; - e = r->next; - - if (r->source != (guint) -1) - g_source_remove(r->source); - - if (r->io_channel) - g_io_channel_unref(r->io_channel); - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -static void free_time_events(pa_time_event *e) { - while (e) { - pa_time_event *r = e; - e = r->next; - - if (r->source != (guint) -1) - g_source_remove(r->source); - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -static void free_defer_events(pa_defer_event *e) { - while (e) { - pa_defer_event *r = e; - e = r->next; - - if (r->source != (guint) -1) - g_source_remove(r->source); - - if (r->destroy_callback) - r->destroy_callback(&r->mainloop->api, r, r->userdata); - - pa_xfree(r); - } -} - -void pa_glib_mainloop_free(pa_glib_mainloop* g) { - assert(g); - - free_io_events(g->io_events); - free_io_events(g->dead_io_events); - free_defer_events(g->defer_events); - free_defer_events(g->dead_defer_events); - free_time_events(g->time_events); - free_time_events(g->dead_time_events); - - if (g->cleanup_source != (guint) -1) - g_source_remove(g->cleanup_source); - - pa_xfree(g); -} - -pa_mainloop_api* pa_glib_mainloop_get_api(pa_glib_mainloop *g) { - assert(g); - return &g->api; -} - -static gboolean free_dead_events(gpointer p) { - pa_glib_mainloop *g = p; - assert(g); - - free_io_events(g->dead_io_events); - free_defer_events(g->dead_defer_events); - free_time_events(g->dead_time_events); - - g->dead_io_events = NULL; - g->dead_defer_events = NULL; - g->dead_time_events = NULL; - - g_source_remove(g->cleanup_source); - g->cleanup_source = (guint) -1; - - return FALSE; -} - -static void schedule_free_dead_events(pa_glib_mainloop *g) { - assert(g); - - if (g->cleanup_source != (guint) -1) - return; - - g->cleanup_source = g_idle_add_full(G_PRIORITY_HIGH, free_dead_events, g, NULL); -} diff --git a/src/polyp/internal.h b/src/polyp/internal.h deleted file mode 100644 index e659553d..00000000 --- a/src/polyp/internal.h +++ /dev/null @@ -1,210 +0,0 @@ -#ifndef foointernalhfoo -#define foointernalhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <polyp/mainloop-api.h> -#include <polyp/context.h> -#include <polyp/stream.h> -#include <polyp/operation.h> -#include <polyp/subscribe.h> - -#include <polypcore/socket-client.h> -#include <polypcore/pstream.h> -#include <polypcore/pdispatch.h> -#include <polypcore/dynarray.h> -#include <polypcore/llist.h> -#include <polypcore/native-common.h> -#include <polypcore/strlist.h> -#include <polypcore/mcalign.h> -#include <polypcore/memblockq.h> -#include <polypcore/hashmap.h> - -#include "client-conf.h" - -#define DEFAULT_TIMEOUT (10) - -struct pa_context { - int ref; - - char *name; - pa_mainloop_api* mainloop; - - pa_socket_client *client; - pa_pstream *pstream; - pa_pdispatch *pdispatch; - - pa_dynarray *record_streams, *playback_streams; - PA_LLIST_HEAD(pa_stream, streams); - PA_LLIST_HEAD(pa_operation, operations); - - uint32_t version; - uint32_t ctag; - uint32_t csyncid; - uint32_t error; - pa_context_state_t state; - - pa_context_notify_cb_t state_callback; - void *state_userdata; - - pa_context_subscribe_cb_t subscribe_callback; - void *subscribe_userdata; - - pa_memblock_stat *memblock_stat; - - int local; - int do_autospawn; - int autospawn_lock_fd; - pa_spawn_api spawn_api; - - pa_strlist *server_list; - - char *server; - - pa_client_conf *conf; -}; - -#define PA_MAX_WRITE_INDEX_CORRECTIONS 10 - -typedef struct pa_index_correction { - uint32_t tag; - int valid; - int64_t value; - int absolute, corrupt; -} pa_index_correction; - -struct pa_stream { - int ref; - pa_context *context; - pa_mainloop_api *mainloop; - PA_LLIST_FIELDS(pa_stream); - - char *name; - pa_buffer_attr buffer_attr; - pa_sample_spec sample_spec; - pa_channel_map channel_map; - pa_stream_flags_t flags; - uint32_t channel; - uint32_t syncid; - int channel_valid; - uint32_t device_index; - pa_stream_direction_t direction; - pa_stream_state_t state; - - uint32_t requested_bytes; - - pa_memchunk peek_memchunk; - pa_memblockq *record_memblockq; - - int corked; - - /* Store latest latency info */ - pa_timing_info timing_info; - int timing_info_valid; - - /* Use to make sure that time advances monotonically */ - pa_usec_t previous_time; - - /* time updates with tags older than these are invalid */ - uint32_t write_index_not_before; - uint32_t read_index_not_before; - - /* Data about individual timing update correctoins */ - pa_index_correction write_index_corrections[PA_MAX_WRITE_INDEX_CORRECTIONS]; - int current_write_index_correction; - - /* Latency interpolation stuff */ - pa_time_event *auto_timing_update_event; - int auto_timing_update_requested; - - pa_usec_t cached_time; - int cached_time_valid; - - /* Callbacks */ - pa_stream_notify_cb_t state_callback; - void *state_userdata; - pa_stream_request_cb_t read_callback; - void *read_userdata; - pa_stream_request_cb_t write_callback; - void *write_userdata; - pa_stream_notify_cb_t overflow_callback; - void *overflow_userdata; - pa_stream_notify_cb_t underflow_callback; - void *underflow_userdata; - pa_stream_notify_cb_t latency_update_callback; - void *latency_update_userdata; -}; - -typedef void (*pa_operation_cb_t)(void); - -struct pa_operation { - int ref; - pa_context *context; - pa_stream *stream; - - PA_LLIST_FIELDS(pa_operation); - - pa_operation_state_t state; - void *userdata; - pa_operation_cb_t callback; -}; - -void pa_command_request(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); - -pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t callback, void *userdata); -void pa_operation_done(pa_operation *o); - -void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); - -void pa_context_fail(pa_context *c, int error); -int pa_context_set_error(pa_context *c, int error); -void pa_context_set_state(pa_context *c, pa_context_state_t st); -int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t); -pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, void (*internal_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata), void (*cb)(void), void *userdata); - -void pa_stream_set_state(pa_stream *s, pa_stream_state_t st); - -pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *tag); - -#define PA_CHECK_VALIDITY(context, expression, error) do { \ - if (!(expression)) \ - return -pa_context_set_error((context), (error)); \ -} while(0) - - -#define PA_CHECK_VALIDITY_RETURN_ANY(context, expression, error, value) do { \ - if (!(expression)) { \ - pa_context_set_error((context), (error)); \ - return value; \ - } \ -} while(0) - -#define PA_CHECK_VALIDITY_RETURN_NULL(context, expression, error) PA_CHECK_VALIDITY_RETURN_ANY(context, expression, error, NULL) - - -#endif diff --git a/src/polyp/introspect.c b/src/polyp/introspect.c deleted file mode 100644 index 9d002669..00000000 --- a/src/polyp/introspect.c +++ /dev/null @@ -1,1240 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <assert.h> - -#include <polyp/context.h> - -#include <polypcore/gccmacro.h> -#include <polypcore/pstream-util.h> - -#include "internal.h" - -#include "introspect.h" - -/*** Statistics ***/ - -static void context_stat_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - pa_stat_info i, *p = &i; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - p = NULL; - } else if (pa_tagstruct_getu32(t, &i.memblock_total) < 0 || - pa_tagstruct_getu32(t, &i.memblock_total_size) < 0 || - pa_tagstruct_getu32(t, &i.memblock_allocated) < 0 || - pa_tagstruct_getu32(t, &i.memblock_allocated_size) < 0 || - pa_tagstruct_getu32(t, &i.scache_size) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_stat_info_cb_t cb = (pa_stat_info_cb_t) o->callback; - cb(o->context, p, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_stat(pa_context *c, pa_stat_info_cb_t cb, void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_STAT, context_stat_callback, (pa_operation_cb_t) cb, userdata); -} - -/*** Server Info ***/ - -static void context_get_server_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - pa_server_info i, *p = &i; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - p = NULL; - } else if (pa_tagstruct_gets(t, &i.server_name) < 0 || - pa_tagstruct_gets(t, &i.server_version) < 0 || - pa_tagstruct_gets(t, &i.user_name) < 0 || - pa_tagstruct_gets(t, &i.host_name) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_gets(t, &i.default_sink_name) < 0 || - pa_tagstruct_gets(t, &i.default_source_name) < 0 || - pa_tagstruct_getu32(t, &i.cookie) < 0 || - !pa_tagstruct_eof(t)) { - - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_server_info_cb_t cb = (pa_server_info_cb_t) o->callback; - cb(o->context, p, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_server_info(pa_context *c, pa_server_info_cb_t cb, void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SERVER_INFO, context_get_server_info_callback, (pa_operation_cb_t) cb, userdata); -} - -/*** Sink Info ***/ - -static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eol = 1; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eol = -1; - } else { - uint32_t flags; - - while (!pa_tagstruct_eof(t)) { - pa_sink_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_get_cvolume(t, &i.volume) < 0 || - pa_tagstruct_get_boolean(t, &i.mute) < 0 || - pa_tagstruct_getu32(t, &i.monitor_source) < 0 || - pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || - pa_tagstruct_get_usec(t, &i.latency) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0 || - pa_tagstruct_getu32(t, &flags) < 0) { - - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - i.flags = (pa_sink_flags_t) flags; - - if (o->callback) { - pa_sink_info_cb_t cb = (pa_sink_info_cb_t) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - pa_sink_info_cb_t cb = (pa_sink_info_cb_t) o->callback; - cb(o->context, NULL, eol, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_sink_info_list(pa_context *c, pa_sink_info_cb_t cb, void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INFO_LIST, context_get_sink_info_callback, (pa_operation_cb_t) cb, userdata); -} - -pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t idx, pa_sink_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_SINK_INFO, &tag); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, pa_sink_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_SINK_INFO, &tag); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -/*** Source info ***/ - -static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eol = 1; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eol = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_source_info i; - uint32_t flags; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.description) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_get_cvolume(t, &i.volume) < 0 || - pa_tagstruct_get_boolean(t, &i.mute) < 0 || - pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || - pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 || - pa_tagstruct_get_usec(t, &i.latency) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0 || - pa_tagstruct_getu32(t, &flags) < 0) { - - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - i.flags = (pa_source_flags_t) flags; - - if (o->callback) { - pa_source_info_cb_t cb = (pa_source_info_cb_t) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - pa_source_info_cb_t cb = (pa_source_info_cb_t) o->callback; - cb(o->context, NULL, eol, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_source_info_list(pa_context *c, pa_source_info_cb_t cb, void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_INFO_LIST, context_get_source_info_callback, (pa_operation_cb_t) cb, userdata); -} - -pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t idx, pa_source_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_SOURCE_INFO, &tag); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, pa_source_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_SOURCE_INFO, &tag); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -/*** Client info ***/ - -static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eol = 1; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eol = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_client_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0 ) { - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_client_info_cb_t cb = (pa_client_info_cb_t) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - pa_client_info_cb_t cb = (pa_client_info_cb_t) o->callback; - cb(o->context, NULL, eol, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, pa_client_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_CLIENT_INFO, &tag); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_client_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_get_client_info_list(pa_context *c, pa_client_info_cb_t cb, void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_CLIENT_INFO_LIST, context_get_client_info_callback, (pa_operation_cb_t) cb, userdata); -} - -/*** Module info ***/ - -static void context_get_module_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eol = 1; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eol = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_module_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0 || - pa_tagstruct_getu32(t, &i.n_used) < 0 || - pa_tagstruct_get_boolean(t, &i.auto_unload) < 0) { - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_module_info_cb_t cb = (pa_module_info_cb_t) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - pa_module_info_cb_t cb = (pa_module_info_cb_t) o->callback; - cb(o->context, NULL, eol, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, pa_module_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_MODULE_INFO, &tag); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_module_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_get_module_info_list(pa_context *c, pa_module_info_cb_t cb, void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_MODULE_INFO_LIST, context_get_module_info_callback, (pa_operation_cb_t) cb, userdata); -} - -/*** Sink input info ***/ - -static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eol = 1; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eol = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_sink_input_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.client) < 0 || - pa_tagstruct_getu32(t, &i.sink) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || - pa_tagstruct_get_cvolume(t, &i.volume) < 0 || - pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || - pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || - pa_tagstruct_gets(t, &i.resample_method) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0) { - - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_sink_input_info_cb_t cb = (pa_sink_input_info_cb_t) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - pa_sink_input_info_cb_t cb = (pa_sink_input_info_cb_t) o->callback; - cb(o->context, NULL, eol, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_SINK_INPUT_INFO, &tag); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sink_input_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_get_sink_input_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_sink_input_info*i, int is_last, void *userdata), void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SINK_INPUT_INFO_LIST, context_get_sink_input_info_callback, (pa_operation_cb_t) cb, userdata); -} - -/*** Source output info ***/ - -static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eol = 1; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eol = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_source_output_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_getu32(t, &i.owner_module) < 0 || - pa_tagstruct_getu32(t, &i.client) < 0 || - pa_tagstruct_getu32(t, &i.source) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || - pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 || - pa_tagstruct_get_usec(t, &i.source_usec) < 0 || - pa_tagstruct_gets(t, &i.resample_method) < 0 || - pa_tagstruct_gets(t, &i.driver) < 0) { - - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_source_output_info_cb_t cb = (pa_source_output_info_cb_t) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - pa_source_output_info_cb_t cb = (pa_source_output_info_cb_t) o->callback; - cb(o->context, NULL, eol, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, pa_source_output_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_SOURCE_OUTPUT_INFO, &tag); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_source_output_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_get_source_output_info_list(pa_context *c, pa_source_output_info_cb_t cb, void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST, context_get_source_output_info_callback, (pa_operation_cb_t) cb, userdata); -} - -/*** Volume manipulation ***/ - -pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(volume); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_VOLUME, &tag); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_tagstruct_put_cvolume(t, volume); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(name); - assert(volume); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_VOLUME, &tag); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_cvolume(t, volume); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_set_sink_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_MUTE, &tag); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_tagstruct_put_boolean(t, mute); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_set_sink_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(name); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_MUTE, &tag); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_boolean(t, mute); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(volume); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_SINK_INPUT_VOLUME, &tag); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_put_cvolume(t, volume); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(volume); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_VOLUME, &tag); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_tagstruct_put_cvolume(t, volume); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(name); - assert(volume); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, pa_cvolume_valid(volume), PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_VOLUME, &tag); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_cvolume(t, volume); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_set_source_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_MUTE, &tag); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_tagstruct_put_boolean(t, mute); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_set_source_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(name); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, !name || *name, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SET_SOURCE_MUTE, &tag); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_tagstruct_put_boolean(t, mute); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -/** Sample Cache **/ - -static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eol = 1; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eol = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_sample_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_get_cvolume(t, &i.volume) < 0 || - pa_tagstruct_get_usec(t, &i.duration) < 0 || - pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 || - pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 || - pa_tagstruct_getu32(t, &i.bytes) < 0 || - pa_tagstruct_get_boolean(t, &i.lazy) < 0 || - pa_tagstruct_gets(t, &i.filename) < 0) { - - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_sample_info_cb_t cb = (pa_sample_info_cb_t) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - pa_sample_info_cb_t cb = (pa_sample_info_cb_t) o->callback; - cb(o->context, NULL, eol, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, pa_sample_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_SAMPLE_INFO, &tag); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, pa_sample_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_SAMPLE_INFO, &tag); - pa_tagstruct_putu32(t, idx); - pa_tagstruct_puts(t, NULL); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_sample_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_get_sample_info_list(pa_context *c, pa_sample_info_cb_t cb, void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_SAMPLE_INFO_LIST, context_get_sample_info_callback, (pa_operation_cb_t) cb, userdata); -} - -static pa_operation* command_kill(pa_context *c, uint32_t command, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, command, &tag); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { - return command_kill(c, PA_COMMAND_KILL_CLIENT, idx, cb, userdata); -} - -pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { - return command_kill(c, PA_COMMAND_KILL_SINK_INPUT, idx, cb, userdata); -} - -pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { - return command_kill(c, PA_COMMAND_KILL_SOURCE_OUTPUT, idx, cb, userdata); -} - -static void context_index_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - uint32_t idx; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - idx = PA_INVALID_INDEX; - } else if (pa_tagstruct_getu32(t, &idx) || - !pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_context_index_cb_t cb = (pa_context_index_cb_t) o->callback; - cb(o->context, idx, o->userdata); - } - - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, pa_context_index_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_LOAD_MODULE, &tag); - pa_tagstruct_puts(t, name); - pa_tagstruct_puts(t, argument); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_index_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata) { - return command_kill(c, PA_COMMAND_UNLOAD_MODULE, idx, cb, userdata); -} - -/*** Autoload stuff ***/ - -static void context_get_autoload_info_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int eol = 1; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - eol = -1; - } else { - - while (!pa_tagstruct_eof(t)) { - pa_autoload_info i; - - if (pa_tagstruct_getu32(t, &i.index) < 0 || - pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_getu32(t, &i.type) < 0 || - pa_tagstruct_gets(t, &i.module) < 0 || - pa_tagstruct_gets(t, &i.argument) < 0) { - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_autoload_info_cb_t cb = (pa_autoload_info_cb_t) o->callback; - cb(o->context, &i, 0, o->userdata); - } - } - } - - if (o->callback) { - pa_autoload_info_cb_t cb = (pa_autoload_info_cb_t) o->callback; - cb(o->context, NULL, eol, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_autoload_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, type == PA_AUTOLOAD_SINK || type == PA_AUTOLOAD_SOURCE, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_AUTOLOAD_INFO, &tag); - pa_tagstruct_puts(t, name); - pa_tagstruct_putu32(t, type); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, pa_autoload_info_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - assert(cb); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_GET_AUTOLOAD_INFO, &tag); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_get_autoload_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_get_autoload_info_list(pa_context *c, pa_autoload_info_cb_t cb, void *userdata) { - return pa_context_send_simple_command(c, PA_COMMAND_GET_AUTOLOAD_INFO_LIST, context_get_autoload_info_callback, (pa_operation_cb_t) cb, userdata); -} - -pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, pa_context_index_cb_t cb, void* userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, type == PA_AUTOLOAD_SINK || type == PA_AUTOLOAD_SOURCE, PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, module && *module, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_ADD_AUTOLOAD, &tag); - pa_tagstruct_puts(t, name); - pa_tagstruct_putu32(t, type); - pa_tagstruct_puts(t, module); - pa_tagstruct_puts(t, argument); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, context_index_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_context_success_cb_t cb, void* userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, type == PA_AUTOLOAD_SINK || type == PA_AUTOLOAD_SOURCE, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_AUTOLOAD, &tag); - pa_tagstruct_puts(t, name); - pa_tagstruct_putu32(t, type); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void* userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, idx != PA_INVALID_INDEX, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_AUTOLOAD, &tag); - pa_tagstruct_putu32(t, idx); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} diff --git a/src/polyp/introspect.h b/src/polyp/introspect.h deleted file mode 100644 index 9a0edb79..00000000 --- a/src/polyp/introspect.h +++ /dev/null @@ -1,490 +0,0 @@ -#ifndef foointrospecthfoo -#define foointrospecthfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <inttypes.h> - -#include <polyp/operation.h> -#include <polyp/context.h> -#include <polyp/cdecl.h> -#include <polyp/channelmap.h> -#include <polyp/volume.h> - -/** \page introspect Server Query and Control - * - * \section overv_sec Overview - * - * Sometimes it is necessary to query and modify global settings in the - * server. For this, Polypaudio has the introspection API. It can list sinks, - * sources, samples and other aspects of the server. It can also modify the - * attributes of the server that will affect operations on a global level, - * and not just the application's context. - * - * \section query_sec Querying - * - * All querying is done through callbacks. This design is necessary to - * maintain an asynchronous design. The client will request the information - * and some time later, the server will respond with the desired data. - * - * Some objects can have multiple entries at the server. When requesting all - * of these at once, the callback will be called multiple times, once for - * each object. When the list has been exhausted, the callback will be called - * without an information structure and the eol parameter set to a non-zero - * value. - * - * Note that even if a single object is requested, and not the entire list, - * the terminating call will still be made. - * - * If an error occurs, the callback will be called without and information - * structure and eol set to zero. - * - * Data members in the information structures are only valid during the - * duration of the callback. If they are required after the callback is - * finished, a deep copy must be performed. - * - * \subsection server_subsec Server Information - * - * The server can be queried about its name, the environment it's running on - * and the currently active global defaults. Calling - * pa_context_get_server_info() will get access to a pa_server_info structure - * containing all of these. - * - * \subsection memstat_subsec Memory Usage - * - * Statistics about memory usage can be fetched using pa_context_stat(), - * giving a pa_stat_info structure. - * - * \subsection sinksrc_subsec Sinks and Sources - * - * The server can have an arbitrary number of sinks and sources. Each sink - * and source have both an index and a name associated with it. As such - * there are three ways to get access to them: - * - * \li By index - pa_context_get_sink_info_by_index() / - * pa_context_get_source_info_by_index() - * \li By name - pa_context_get_sink_info_by_name() / - * pa_context_get_source_info_by_name() - * \li All - pa_context_get_sink_info_list() / - * pa_context_get_source_info_list() - * - * All three method use the same callback and will provide a pa_sink_info or - * pa_source_info structure. - * - * \subsection siso_subsec Sink Inputs and Source Outputs - * - * Sink inputs and source outputs are the representations of the client ends - * of streams inside the server. I.e. they connect a client stream to one of - * the global sinks or sources. - * - * Sink inputs and source outputs only have an index to identify them. As - * such, there are only two ways to get information about them: - * - * \li By index - pa_context_get_sink_input_info() / - * pa_context_get_source_output_info() - * \li All - pa_context_get_sink_input_info_list() / - * pa_context_get_source_output_info_list() - * - * The structure returned is the pa_sink_input_info or pa_source_output_info - * structure. - * - * \subsection samples_subsec Samples - * - * The list of cached samples can be retrieved from the server. Three methods - * exist for querying the sample cache list: - * - * \li By index - pa_context_get_sample_info_by_index() - * \li By name - pa_context_get_sample_info_by_name() - * \li All - pa_context_get_sample_info_list() - * - * Note that this only retrieves information about the sample, not the sample - * data itself. - * - * \subsection module_subsec Driver Modules - * - * Polypaudio driver modules are identified by index and are retrieved using either - * pa_context_get_module_info() or pa_context_get_module_info_list(). The - * information structure is called pa_module_info. - * - * \subsection autoload_subsec Autoload Entries - * - * Modules can be autoloaded as a result of a client requesting a certain - * sink or source. This mapping between sink/source names and modules can be - * queried from the server: - * - * \li By index - pa_context_get_autoload_info_by_index() - * \li By sink/source name - pa_context_get_autoload_info_by_name() - * \li All - pa_context_get_autoload_info_list() - * - * \subsection client_subsec Clients - * - * Polypaudio clients are also identified by index and are retrieved using - * either pa_context_get_client_info() or pa_context_get_client_info_list(). - * The information structure is called pa_client_info. - * - * \section ctrl_sec Control - * - * Some parts of the server are only possible to read, but most can also be - * modified in different ways. Note that these changes will affect all - * connected clients and not just the one issuing the request. - * - * \subsection sinksrc_subsec Sinks and Sources - * - * The most common change one would want to do to sinks and sources is to - * modify the volume of the audio. Identical to how sinks and sources can - * be queried, there are two ways of identifying them: - * - * \li By index - pa_context_set_sink_volume_by_index() / - * pa_context_set_source_volume_by_index() - * \li By name - pa_context_set_sink_volume_by_name() / - * pa_context_set_source_volume_by_name() - * - * It is also possible to mute a sink or source: - * - * \li By index - pa_context_set_sink_mute_by_index() / - * pa_context_set_source_mute_by_index() - * \li By name - pa_context_set_sink_mute_by_name() / - * pa_context_set_source_mute_by_name() - * - * \subsection siso_subsec Sink Inputs and Source Outputs - * - * If an application desires to modify the volume of just a single stream - * (commonly one of its own streams), this can be done by setting the volume - * of its associated sink input, using pa_context_set_sink_input_volume(). - * - * There is no support for modifying the volume of source outputs. - * - * It is also possible to remove sink inputs and source outputs, terminating - * the streams associated with them: - * - * \li Sink input - pa_context_kill_sink_input() - * \li Source output - pa_context_kill_source_output() - * - * \subsection module_subsec Modules - * - * Server modules can be remotely loaded and unloaded using - * pa_context_load_module() and pa_context_unload_module(). - * - * \subsection autoload_subsec Autoload Entries - * - * New module autoloading rules can be added, and existing can be removed - * using pa_context_add_autoload() and pa_context_remove_autoload_by_index() - * / pa_context_remove_autoload_by_name(). - * - * \subsection client_subsec Clients - * - * The only operation supported on clients, is the possibility of kicking - * them off the server using pa_context_kill_client(). - */ - -/** \file - * - * Routines for daemon introspection. - */ - -PA_C_DECL_BEGIN - -/** Stores information about sinks */ -typedef struct pa_sink_info { - const char *name; /**< Name of the sink */ - uint32_t index; /**< Index of the sink */ - const char *description; /**< Description of this sink */ - pa_sample_spec sample_spec; /**< Sample spec of this sink */ - pa_channel_map channel_map; /**< Channel map \since 0.8 */ - uint32_t owner_module; /**< Index of the owning module of this sink, or PA_INVALID_INDEX */ - pa_cvolume volume; /**< Volume of the sink */ - int mute; /**< Mute switch of the sink \since 0.8 */ - uint32_t monitor_source; /**< Index of the monitor source connected to this sink */ - const char *monitor_source_name; /**< The name of the monitor source */ - pa_usec_t latency; /**< Length of filled playback buffer of this sink */ - const char *driver; /**< Driver name. \since 0.8 */ - pa_sink_flags_t flags; /**< Flags \since 0.8 */ -} pa_sink_info; - -/** Callback prototype for pa_context_get_sink_info_by_name() and friends */ -typedef void (*pa_sink_info_cb_t)(pa_context *c, const pa_sink_info *i, int eol, void *userdata); - -/** Get information about a sink by its name */ -pa_operation* pa_context_get_sink_info_by_name(pa_context *c, const char *name, pa_sink_info_cb_t cb, void *userdata); - -/** Get information about a sink by its index */ -pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t id, pa_sink_info_cb_t cb, void *userdata); - -/** Get the complete sink list */ -pa_operation* pa_context_get_sink_info_list(pa_context *c, pa_sink_info_cb_t cb, void *userdata); - -/** Stores information about sources */ -typedef struct pa_source_info { - const char *name ; /**< Name of the source */ - uint32_t index; /**< Index of the source */ - const char *description; /**< Description of this source */ - pa_sample_spec sample_spec; /**< Sample spec of this source */ - pa_channel_map channel_map; /**< Channel map \since 0.8 */ - uint32_t owner_module; /**< Owning module index, or PA_INVALID_INDEX */ - pa_cvolume volume; /**< Volume of the source \since 0.8 */ - int mute; /**< Mute switch of the sink \since 0.8 */ - uint32_t monitor_of_sink; /**< If this is a monitor source the index of the owning sink, otherwise PA_INVALID_INDEX */ - const char *monitor_of_sink_name; /**< Name of the owning sink, or PA_INVALID_INDEX */ - pa_usec_t latency; /**< Length of filled record buffer of this source. \since 0.5 */ - const char *driver; /**< Driver name \since 0.8 */ - pa_source_flags_t flags; /**< Flags \since 0.8 */ -} pa_source_info; - -/** Callback prototype for pa_context_get_source_info_by_name() and friends */ -typedef void (*pa_source_info_cb_t)(pa_context *c, const pa_source_info *i, int eol, void *userdata); - -/** Get information about a source by its name */ -pa_operation* pa_context_get_source_info_by_name(pa_context *c, const char *name, pa_source_info_cb_t cb, void *userdata); - -/** Get information about a source by its index */ -pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t id, pa_source_info_cb_t cb, void *userdata); - -/** Get the complete source list */ -pa_operation* pa_context_get_source_info_list(pa_context *c, pa_source_info_cb_t cb, void *userdata); - -/** Server information */ -typedef struct pa_server_info { - const char *user_name; /**< User name of the daemon process */ - const char *host_name; /**< Host name the daemon is running on */ - const char *server_version; /**< Version string of the daemon */ - const char *server_name; /**< Server package name (usually "polypaudio") */ - pa_sample_spec sample_spec; /**< Default sample specification */ - const char *default_sink_name; /**< Name of default sink. \since 0.4 */ - const char *default_source_name; /**< Name of default sink. \since 0.4*/ - uint32_t cookie; /**< A random cookie for identifying this instance of polypaudio. \since 0.8 */ -} pa_server_info; - -/** Callback prototype for pa_context_get_server_info() */ -typedef void (*pa_server_info_cb_t) (pa_context *c, const pa_server_info*i, void *userdata); - -/** Get some information about the server */ -pa_operation* pa_context_get_server_info(pa_context *c, pa_server_info_cb_t cb, void *userdata); - -/** Stores information about modules */ -typedef struct pa_module_info { - uint32_t index; /**< Index of the module */ - const char*name, /**< Name of the module */ - *argument; /**< Argument string of the module */ - uint32_t n_used; /**< Usage counter or PA_INVALID_INDEX */ - int auto_unload; /**< Non-zero if this is an autoloaded module */ -} pa_module_info; - -/** Callback prototype for pa_context_get_module_info() and firends*/ -typedef void (*pa_module_info_cb_t) (pa_context *c, const pa_module_info*i, int eol, void *userdata); - -/** Get some information about a module by its index */ -pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, pa_module_info_cb_t cb, void *userdata); - -/** Get the complete list of currently loaded modules */ -pa_operation* pa_context_get_module_info_list(pa_context *c, pa_module_info_cb_t cb, void *userdata); - -/** Stores information about clients */ -typedef struct pa_client_info { - uint32_t index; /**< Index of this client */ - const char *name; /**< Name of this client */ - uint32_t owner_module; /**< Index of the owning module, or PA_INVALID_INDEX */ - const char *driver; /**< Driver name \since 0.8 */ -} pa_client_info; - -/** Callback prototype for pa_context_get_client_info() and firends*/ -typedef void (*pa_client_info_cb_t) (pa_context *c, const pa_client_info*i, int eol, void *userdata); - -/** Get information about a client by its index */ -pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, pa_client_info_cb_t cb, void *userdata); - -/** Get the complete client list */ -pa_operation* pa_context_get_client_info_list(pa_context *c, pa_client_info_cb_t cb, void *userdata); - -/** Stores information about sink inputs */ -typedef struct pa_sink_input_info { - uint32_t index; /**< Index of the sink input */ - const char *name; /**< Name of the sink input */ - uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ - uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ - uint32_t sink; /**< Index of the connected sink */ - pa_sample_spec sample_spec; /**< The sample specification of the sink input */ - pa_channel_map channel_map; /**< Channel map */ - pa_cvolume volume; /**< The volume of this sink input */ - pa_usec_t buffer_usec; /**< Latency due to buffering in sink input, see pa_latency_info for details */ - pa_usec_t sink_usec; /**< Latency of the sink device, see pa_latency_info for details */ - const char *resample_method; /**< Thre resampling method used by this sink input. \since 0.7 */ - const char *driver; /**< Driver name \since 0.8 */ -} pa_sink_input_info; - -/** Callback prototype for pa_context_get_sink_input_info() and firends*/ -typedef void (*pa_sink_input_info_cb_t) (pa_context *c, const pa_sink_input_info *i, int eol, void *userdata); - -/** Get some information about a sink input by its index */ -pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sink_input_info_cb_t cb, void *userdata); - -/** Get the complete sink input list */ -pa_operation* pa_context_get_sink_input_info_list(pa_context *c, pa_sink_input_info_cb_t cb, void *userdata); - -/** Stores information about source outputs */ -typedef struct pa_source_output_info { - uint32_t index; /**< Index of the sink input */ - const char *name; /**< Name of the sink input */ - uint32_t owner_module; /**< Index of the module this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any module */ - uint32_t client; /**< Index of the client this sink input belongs to, or PA_INVALID_INDEX when it does not belong to any client */ - uint32_t source; /**< Index of the connected source */ - pa_sample_spec sample_spec; /**< The sample specification of the source output */ - pa_channel_map channel_map; /**< Channel map */ - pa_usec_t buffer_usec; /**< Latency due to buffering in the source output, see pa_latency_info for details. \since 0.5 */ - pa_usec_t source_usec; /**< Latency of the source device, see pa_latency_info for details. \since 0.5 */ - const char *resample_method; /**< Thre resampling method used by this source output. \since 0.7 */ - const char *driver; /**< Driver name \since 0.8 */ -} pa_source_output_info; - -/** Callback prototype for pa_context_get_source_output_info() and firends*/ -typedef void (*pa_source_output_info_cb_t) (pa_context *c, const pa_source_output_info *i, int eol, void *userdata); - -/** Get information about a source output by its index */ -pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, pa_source_output_info_cb_t cb, void *userdata); - -/** Get the complete list of source outputs */ -pa_operation* pa_context_get_source_output_info_list(pa_context *c, pa_source_output_info_cb_t cb, void *userdata); - -/** Set the volume of a sink device specified by its index */ -pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); - -/** Set the volume of a sink device specified by its name */ -pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); - -/** Set the mute switch of a sink device specified by its index \since 0.8 */ -pa_operation* pa_context_set_sink_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata); - -/** Set the mute switch of a sink device specified by its name \since 0.8 */ -pa_operation* pa_context_set_sink_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata); - -/** Set the volume of a sink input stream */ -pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); - -/** Set the volume of a source device specified by its index \since 0.8 */ -pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); - -/** Set the volume of a source device specified by its name \since 0.8 */ -pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata); - -/** Set the mute switch of a source device specified by its index \since 0.8 */ -pa_operation* pa_context_set_source_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata); - -/** Set the mute switch of a source device specified by its name \since 0.8 */ -pa_operation* pa_context_set_source_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata); - -/** Memory block statistics */ -typedef struct pa_stat_info { - uint32_t memblock_total; /**< Currently allocated memory blocks */ - uint32_t memblock_total_size; /**< Currentl total size of allocated memory blocks */ - uint32_t memblock_allocated; /**< Allocated memory blocks during the whole lifetime of the daemon */ - uint32_t memblock_allocated_size; /**< Total size of all memory blocks allocated during the whole lifetime of the daemon */ - uint32_t scache_size; /**< Total size of all sample cache entries. \since 0.4 */ -} pa_stat_info; - -/** Callback prototype for pa_context_stat() */ -typedef void (*pa_stat_info_cb_t) (pa_context *c, const pa_stat_info *i, void *userdata); - -/** Get daemon memory block statistics */ -pa_operation* pa_context_stat(pa_context *c, pa_stat_info_cb_t cb, void *userdata); - -/** Stores information about sample cache entries */ -typedef struct pa_sample_info { - uint32_t index; /**< Index of this entry */ - const char *name; /**< Name of this entry */ - pa_cvolume volume; /**< Default volume of this entry */ - pa_sample_spec sample_spec; /**< Sample specification of the sample */ - pa_channel_map channel_map; /**< The channel map */ - pa_usec_t duration; /**< Duration of this entry */ - uint32_t bytes; /**< Length of this sample in bytes. \since 0.4 */ - int lazy; /**< Non-zero when this is a lazy cache entry. \since 0.5 */ - const char *filename; /**< In case this is a lazy cache entry, the filename for the sound file to be loaded on demand. \since 0.5 */ -} pa_sample_info; - -/** Callback prototype for pa_context_get_sample_info_by_name() and firends */ -typedef void (*pa_sample_info_cb_t)(pa_context *c, const pa_sample_info *i, int eol, void *userdata); - -/** Get information about a sample by its name */ -pa_operation* pa_context_get_sample_info_by_name(pa_context *c, const char *name, pa_sample_info_cb_t cb, void *userdata); - -/** Get information about a sample by its index */ -pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, pa_sample_info_cb_t cb, void *userdata); - -/** Get the complete list of samples stored in the daemon. */ -pa_operation* pa_context_get_sample_info_list(pa_context *c, pa_sample_info_cb_t cb, void *userdata); - -/** Kill a client. \since 0.5 */ -pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); - -/** Kill a sink input. \since 0.5 */ -pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); - -/** Kill a source output. \since 0.5 */ -pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); - -/** Callback prototype for pa_context_load_module() and pa_context_add_autoload() */ -typedef void (*pa_context_index_cb_t)(pa_context *c, uint32_t idx, void *userdata); - -/** Load a module. \since 0.5 */ -pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, pa_context_index_cb_t cb, void *userdata); - -/** Unload a module. \since 0.5 */ -pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata); - -/** Type of an autoload entry. \since 0.5 */ -typedef enum pa_autoload_type { - PA_AUTOLOAD_SINK = 0, - PA_AUTOLOAD_SOURCE = 1 -} pa_autoload_type_t; - -/** Stores information about autoload entries. \since 0.5 */ -typedef struct pa_autoload_info { - uint32_t index; /**< Index of this autoload entry */ - const char *name; /**< Name of the sink or source */ - pa_autoload_type_t type; /**< Type of the autoload entry */ - const char *module; /**< Module name to load */ - const char *argument; /**< Argument string for module */ -} pa_autoload_info; - -/** Callback prototype for pa_context_get_autoload_info_by_name() and firends */ -typedef void (*pa_autoload_info_cb_t)(pa_context *c, const pa_autoload_info *i, int eol, void *userdata); - -/** Get info about a specific autoload entry. \since 0.6 */ -pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_autoload_info_cb_t cb, void *userdata); - -/** Get info about a specific autoload entry. \since 0.6 */ -pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, pa_autoload_info_cb_t cb, void *userdata); - -/** Get the complete list of autoload entries. \since 0.5 */ -pa_operation* pa_context_get_autoload_info_list(pa_context *c, pa_autoload_info_cb_t cb, void *userdata); - -/** Add a new autoload entry. \since 0.5 */ -pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, pa_context_index_cb_t, void* userdata); - -/** Remove an autoload entry. \since 0.6 */ -pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_context_success_cb_t cb, void* userdata); - -/** Remove an autoload entry. \since 0.6 */ -pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void* userdata); - - -PA_C_DECL_END - -#endif diff --git a/src/polyp/mainloop-api.c b/src/polyp/mainloop-api.c deleted file mode 100644 index f29598dc..00000000 --- a/src/polyp/mainloop-api.c +++ /dev/null @@ -1,70 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <assert.h> -#include <stdlib.h> - -#include <polyp/xmalloc.h> - -#include <polypcore/gccmacro.h> - -#include "mainloop-api.h" - -struct once_info { - void (*callback)(pa_mainloop_api*m, void *userdata); - void *userdata; -}; - -static void once_callback(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { - struct once_info *i = userdata; - assert(m && i && i->callback); - - i->callback(m, i->userdata); - - assert(m->defer_free); - m->defer_free(e); -} - -static void free_callback(pa_mainloop_api *m, PA_GCC_UNUSED pa_defer_event *e, void *userdata) { - struct once_info *i = userdata; - assert(m && i); - pa_xfree(i); -} - -void pa_mainloop_api_once(pa_mainloop_api* m, void (*callback)(pa_mainloop_api *m, void *userdata), void *userdata) { - struct once_info *i; - pa_defer_event *e; - assert(m && callback); - - i = pa_xnew(struct once_info, 1); - i->callback = callback; - i->userdata = userdata; - - assert(m->defer_new); - e = m->defer_new(m, once_callback, i); - assert(e); - m->defer_set_destroy(e, free_callback); -} - diff --git a/src/polyp/mainloop-api.h b/src/polyp/mainloop-api.h deleted file mode 100644 index 12d74aa1..00000000 --- a/src/polyp/mainloop-api.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef foomainloopapihfoo -#define foomainloopapihfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <sys/time.h> -#include <time.h> - -#include <polyp/cdecl.h> - -/** \file - * - * Main loop abstraction layer. Both the polypaudio core and the - * polypaudio client library use a main loop abstraction layer. Due to - * this it is possible to embed polypaudio into other - * applications easily. Two main loop implemenations are - * currently available: - * \li A minimal implementation based on the C library's poll() function (See \ref mainloop.h) - * \li A wrapper around the GLIB main loop. Use this to embed polypaudio into your GLIB/GTK+/GNOME programs (See \ref glib-mainloop.h) - * - * The structure pa_mainloop_api is used as vtable for the main loop abstraction. - * - * This mainloop abstraction layer has no direct support for UNIX signals. Generic, mainloop implementation agnostic support is available throught \ref mainloop-signal.h. - * */ - -PA_C_DECL_BEGIN - -/** A bitmask for IO events */ -typedef enum pa_io_event_flags { - PA_IO_EVENT_NULL = 0, /**< No event */ - PA_IO_EVENT_INPUT = 1, /**< Input event */ - PA_IO_EVENT_OUTPUT = 2, /**< Output event */ - PA_IO_EVENT_HANGUP = 4, /**< Hangup event */ - PA_IO_EVENT_ERROR = 8 /**< Error event */ -} pa_io_event_flags_t; - -/** An opaque IO event source object */ -typedef struct pa_io_event pa_io_event; - -/** An opaque deferred event source object. Events of this type are triggered once in every main loop iteration */ -typedef struct pa_defer_event pa_defer_event; - -/** An opaque timer event source object */ -typedef struct pa_time_event pa_time_event; - -/** An abstract mainloop API vtable */ -typedef struct pa_mainloop_api pa_mainloop_api; - -/** An abstract mainloop API vtable */ -struct pa_mainloop_api { - /** A pointer to some private, arbitrary data of the main loop implementation */ - void *userdata; - - /** Create a new IO event source object */ - pa_io_event* (*io_new)(pa_mainloop_api*a, int fd, pa_io_event_flags_t events, void (*callback) (pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata); - - /** Enable or disable IO events on this object */ - void (*io_enable)(pa_io_event* e, pa_io_event_flags_t events); - - /** Free a IO event source object */ - void (*io_free)(pa_io_event* e); - - /** Set a function that is called when the IO event source is destroyed. Use this to free the userdata argument if required */ - void (*io_set_destroy)(pa_io_event *e, void (*callback) (pa_mainloop_api*a, pa_io_event *e, void *userdata)); - - /** Create a new timer event source object for the specified Unix time */ - pa_time_event* (*time_new)(pa_mainloop_api*a, const struct timeval *tv, void (*callback) (pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata), void *userdata); - - /** Restart a running or expired timer event source with a new Unix time */ - void (*time_restart)(pa_time_event* e, const struct timeval *tv); - - /** Free a deferred timer event source object */ - void (*time_free)(pa_time_event* e); - - /** Set a function that is called when the timer event source is destroyed. Use this to free the userdata argument if required */ - void (*time_set_destroy)(pa_time_event *e, void (*callback) (pa_mainloop_api*a, pa_time_event *e, void *userdata)); - - /** Create a new deferred event source object */ - pa_defer_event* (*defer_new)(pa_mainloop_api*a, void (*callback) (pa_mainloop_api*a, pa_defer_event* e, void *userdata), void *userdata); - - /** Enable or disable a deferred event source temporarily */ - void (*defer_enable)(pa_defer_event* e, int b); - - /** Free a deferred event source object */ - void (*defer_free)(pa_defer_event* e); - - /** Set a function that is called when the deferred event source is destroyed. Use this to free the userdata argument if required */ - void (*defer_set_destroy)(pa_defer_event *e, void (*callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata)); - - /** Exit the main loop and return the specfied retval*/ - void (*quit)(pa_mainloop_api*a, int retval); -}; - -/** Run the specified callback function once from the main loop using an anonymous defer event. */ -void pa_mainloop_api_once(pa_mainloop_api*m, void (*callback)(pa_mainloop_api*m, void *userdata), void *userdata); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/mainloop-signal.c b/src/polyp/mainloop-signal.c deleted file mode 100644 index 92702814..00000000 --- a/src/polyp/mainloop-signal.c +++ /dev/null @@ -1,210 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <assert.h> -#include <signal.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> - -#ifdef HAVE_WINDOWS_H -#include <windows.h> -#endif - -#include <polypcore/core-error.h> -#include <polyp/xmalloc.h> - -#include <polypcore/core-util.h> -#include <polypcore/log.h> -#include <polypcore/gccmacro.h> - -#include "mainloop-signal.h" - -struct pa_signal_event { - int sig; -#ifdef HAVE_SIGACTION - struct sigaction saved_sigaction; -#else - void (*saved_handler)(int sig); -#endif - void (*callback) (pa_mainloop_api*a, pa_signal_event *e, int sig, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api*a, pa_signal_event*e, void *userdata); - pa_signal_event *previous, *next; -}; - -static pa_mainloop_api *api = NULL; -static int signal_pipe[2] = { -1, -1 }; -static pa_io_event* io_event = NULL; -static pa_signal_event *signals = NULL; - -static void signal_handler(int sig) { -#ifndef HAVE_SIGACTION - signal(sig, signal_handler); -#endif - pa_write(signal_pipe[1], &sig, sizeof(sig)); -} - -static void dispatch(pa_mainloop_api*a, int sig) { - pa_signal_event*s; - - for (s = signals; s; s = s->next) - if (s->sig == sig) { - assert(s->callback); - s->callback(a, s, sig, s->userdata); - break; - } -} - -static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags_t f, PA_GCC_UNUSED void *userdata) { - ssize_t r; - int sig; - assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]); - - if ((r = pa_read(signal_pipe[0], &sig, sizeof(sig))) < 0) { - if (errno == EAGAIN) - return; - - pa_log(__FILE__": read(): %s", pa_cstrerror(errno)); - return; - } - - if (r != sizeof(sig)) { - pa_log(__FILE__": short read()"); - return; - } - - dispatch(a, sig); -} - -int pa_signal_init(pa_mainloop_api *a) { - - assert(!api && a && signal_pipe[0] == -1 && signal_pipe[1] == -1 && !io_event); - - if (pipe(signal_pipe) < 0) { - pa_log(__FILE__": pipe(): %s", pa_cstrerror(errno)); - return -1; - } - - pa_make_nonblock_fd(signal_pipe[0]); - pa_make_nonblock_fd(signal_pipe[1]); - pa_fd_set_cloexec(signal_pipe[0], 1); - pa_fd_set_cloexec(signal_pipe[1], 1); - - api = a; - - io_event = api->io_new(api, signal_pipe[0], PA_IO_EVENT_INPUT, callback, NULL); - assert(io_event); - - return 0; -} - -void pa_signal_done(void) { - assert(api && signal_pipe[0] >= 0 && signal_pipe[1] >= 0 && io_event); - - while (signals) - pa_signal_free(signals); - - api->io_free(io_event); - io_event = NULL; - - close(signal_pipe[0]); - close(signal_pipe[1]); - signal_pipe[0] = signal_pipe[1] = -1; - - api = NULL; -} - -pa_signal_event* pa_signal_new(int sig, void (*_callback) (pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata), void *userdata) { - pa_signal_event *e = NULL; - -#ifdef HAVE_SIGACTION - struct sigaction sa; -#endif - - assert(sig > 0 && _callback); - - for (e = signals; e; e = e->next) - if (e->sig == sig) - goto fail; - - e = pa_xmalloc(sizeof(pa_signal_event)); - e->sig = sig; - e->callback = _callback; - e->userdata = userdata; - e->destroy_callback = NULL; - -#ifdef HAVE_SIGACTION - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = signal_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - - if (sigaction(sig, &sa, &e->saved_sigaction) < 0) -#else - if ((e->saved_handler = signal(sig, signal_handler)) == SIG_ERR) -#endif - goto fail; - - e->previous = NULL; - e->next = signals; - signals = e; - - return e; -fail: - if (e) - pa_xfree(e); - return NULL; -} - -void pa_signal_free(pa_signal_event *e) { - assert(e); - - if (e->next) - e->next->previous = e->previous; - if (e->previous) - e->previous->next = e->next; - else - signals = e->next; - -#ifdef HAVE_SIGACTION - sigaction(e->sig, &e->saved_sigaction, NULL); -#else - signal(e->sig, e->saved_handler); -#endif - - if (e->destroy_callback) - e->destroy_callback(api, e, e->userdata); - - pa_xfree(e); -} - -void pa_signal_set_destroy(pa_signal_event *e, void (*_callback) (pa_mainloop_api *api, pa_signal_event*e, void *userdata)) { - assert(e); - e->destroy_callback = _callback; -} diff --git a/src/polyp/mainloop-signal.h b/src/polyp/mainloop-signal.h deleted file mode 100644 index 20e97988..00000000 --- a/src/polyp/mainloop-signal.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef foomainloopsignalhfoo -#define foomainloopsignalhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <polyp/mainloop-api.h> -#include <polyp/cdecl.h> - -PA_C_DECL_BEGIN - -/** \file - * UNIX signal support for main loops. In contrast to other - * main loop event sources such as timer and IO events, UNIX signal - * support requires modification of the global process - * environment. Due to this the generic main loop abstraction layer as - * defined in \ref mainloop-api.h doesn't have direct support for UNIX - * signals. However, you may hook signal support into an abstract main loop via the routines defined herein. - */ - -/** Initialize the UNIX signal subsystem and bind it to the specified main loop */ -int pa_signal_init(pa_mainloop_api *api); - -/** Cleanup the signal subsystem */ -void pa_signal_done(void); - -/** An opaque UNIX signal event source object */ -typedef struct pa_signal_event pa_signal_event; - -/** Create a new UNIX signal event source object */ -pa_signal_event* pa_signal_new(int sig, void (*callback) (pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata), void *userdata); - -/** Free a UNIX signal event source object */ -void pa_signal_free(pa_signal_event *e); - -/** Set a function that is called when the signal event source is destroyed. Use this to free the userdata argument if required */ -void pa_signal_set_destroy(pa_signal_event *e, void (*callback) (pa_mainloop_api *api, pa_signal_event*e, void *userdata)); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/mainloop.c b/src/polyp/mainloop.c deleted file mode 100644 index 61d8b488..00000000 --- a/src/polyp/mainloop.c +++ /dev/null @@ -1,839 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <signal.h> -#include <unistd.h> -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include <fcntl.h> -#include <errno.h> - -#ifdef HAVE_SYS_POLL_H -#include <sys/poll.h> -#else -#include "../polypcore/poll.h" -#endif - -#include "../polypcore/winsock.h" - -#ifndef HAVE_PIPE -#include "../polypcore/pipe.h" -#endif - -#include <polypcore/core-error.h> -#include <polyp/timeval.h> -#include <polyp/xmalloc.h> - -#include <polypcore/core-util.h> -#include <polypcore/idxset.h> -#include <polypcore/log.h> - -#include "mainloop.h" - -struct pa_io_event { - pa_mainloop *mainloop; - int dead; - int fd; - pa_io_event_flags_t events; - void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata); - struct pollfd *pollfd; - void *userdata; - void (*destroy_callback) (pa_mainloop_api*a, pa_io_event *e, void *userdata); -}; - -struct pa_time_event { - pa_mainloop *mainloop; - int dead; - int enabled; - struct timeval timeval; - void (*callback)(pa_mainloop_api*a, pa_time_event *e, const struct timeval*tv, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api*a, pa_time_event *e, void *userdata); -}; - -struct pa_defer_event { - pa_mainloop *mainloop; - int dead; - int enabled; - void (*callback)(pa_mainloop_api*a, pa_defer_event*e, void *userdata); - void *userdata; - void (*destroy_callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata); -}; - -struct pa_mainloop { - pa_idxset *io_events, *time_events, *defer_events; - int io_events_scan_dead, defer_events_scan_dead, time_events_scan_dead; - - struct pollfd *pollfds; - unsigned max_pollfds, n_pollfds; - int rebuild_pollfds; - - int prepared_timeout; - - int quit, retval; - pa_mainloop_api api; - - int deferred_pending; - - int wakeup_pipe[2]; - - enum { - STATE_PASSIVE, - STATE_PREPARED, - STATE_POLLING, - STATE_POLLED, - STATE_QUIT - } state; - - pa_poll_func poll_func; - void *poll_func_userdata; -}; - -/* IO events */ -static pa_io_event* mainloop_io_new( - pa_mainloop_api*a, - int fd, - pa_io_event_flags_t events, - void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), - void *userdata) { - - pa_mainloop *m; - pa_io_event *e; - - assert(a && a->userdata && fd >= 0 && callback); - m = a->userdata; - assert(a == &m->api); - - e = pa_xmalloc(sizeof(pa_io_event)); - e->mainloop = m; - e->dead = 0; - - e->fd = fd; - e->events = events; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - e->pollfd = NULL; - -#ifdef OS_IS_WIN32 - { - fd_set xset; - struct timeval tv; - - tv.tv_sec = 0; - tv.tv_usec = 0; - - FD_ZERO (&xset); - FD_SET (fd, &xset); - - if ((select((SELECT_TYPE_ARG1) fd, NULL, NULL, SELECT_TYPE_ARG234 &xset, - SELECT_TYPE_ARG5 &tv) == -1) && - (WSAGetLastError() == WSAENOTSOCK)) { - pa_log_warn(__FILE__": WARNING: cannot monitor non-socket file descriptors."); - e->dead = 1; - } - } -#endif - - pa_idxset_put(m->io_events, e, NULL); - m->rebuild_pollfds = 1; - - pa_mainloop_wakeup(m); - - return e; -} - -static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags_t events) { - assert(e && e->mainloop); - - e->events = events; - e->mainloop->rebuild_pollfds = 1; - - pa_mainloop_wakeup(e->mainloop); -} - -static void mainloop_io_free(pa_io_event *e) { - assert(e && e->mainloop); - - e->dead = e->mainloop->io_events_scan_dead = e->mainloop->rebuild_pollfds = 1; - - pa_mainloop_wakeup(e->mainloop); -} - -static void mainloop_io_set_destroy(pa_io_event *e, void (*callback)(pa_mainloop_api*a, pa_io_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* Defer events */ -static pa_defer_event* mainloop_defer_new(pa_mainloop_api*a, void (*callback) (pa_mainloop_api*a, pa_defer_event *e, void *userdata), void *userdata) { - pa_mainloop *m; - pa_defer_event *e; - - assert(a && a->userdata && callback); - m = a->userdata; - assert(a == &m->api); - - e = pa_xmalloc(sizeof(pa_defer_event)); - e->mainloop = m; - e->dead = 0; - - e->enabled = 1; - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - - pa_idxset_put(m->defer_events, e, NULL); - - m->deferred_pending++; - - pa_mainloop_wakeup(e->mainloop); - - return e; -} - -static void mainloop_defer_enable(pa_defer_event *e, int b) { - assert(e); - - if (e->enabled && !b) { - assert(e->mainloop->deferred_pending > 0); - e->mainloop->deferred_pending--; - } else if (!e->enabled && b) { - e->mainloop->deferred_pending++; - pa_mainloop_wakeup(e->mainloop); - } - - e->enabled = b; -} - -static void mainloop_defer_free(pa_defer_event *e) { - assert(e); - e->dead = e->mainloop->defer_events_scan_dead = 1; - - if (e->enabled) { - e->enabled = 0; - assert(e->mainloop->deferred_pending > 0); - e->mainloop->deferred_pending--; - } -} - -static void mainloop_defer_set_destroy(pa_defer_event *e, void (*callback)(pa_mainloop_api*a, pa_defer_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* Time events */ -static pa_time_event* mainloop_time_new(pa_mainloop_api*a, const struct timeval *tv, void (*callback) (pa_mainloop_api*a, pa_time_event*e, const struct timeval *tv, void *userdata), void *userdata) { - pa_mainloop *m; - pa_time_event *e; - - assert(a && a->userdata && callback); - m = a->userdata; - assert(a == &m->api); - - e = pa_xmalloc(sizeof(pa_time_event)); - e->mainloop = m; - e->dead = 0; - - e->enabled = !!tv; - if (tv) - e->timeval = *tv; - - e->callback = callback; - e->userdata = userdata; - e->destroy_callback = NULL; - - pa_idxset_put(m->time_events, e, NULL); - - if (e->enabled) - pa_mainloop_wakeup(m); - - return e; -} - -static void mainloop_time_restart(pa_time_event *e, const struct timeval *tv) { - assert(e); - - if (tv) { - e->enabled = 1; - e->timeval = *tv; - - pa_mainloop_wakeup(e->mainloop); - } else - e->enabled = 0; -} - -static void mainloop_time_free(pa_time_event *e) { - assert(e); - - e->dead = e->mainloop->time_events_scan_dead = 1; - - /* no wakeup needed here. Think about it! */ -} - -static void mainloop_time_set_destroy(pa_time_event *e, void (*callback)(pa_mainloop_api*a, pa_time_event *e, void *userdata)) { - assert(e); - e->destroy_callback = callback; -} - -/* quit() */ - -static void mainloop_quit(pa_mainloop_api*a, int retval) { - pa_mainloop *m; - assert(a && a->userdata); - m = a->userdata; - assert(a == &m->api); - - pa_mainloop_quit(m, retval); -} - -static const pa_mainloop_api vtable = { - .userdata = NULL, - - .io_new= mainloop_io_new, - .io_enable= mainloop_io_enable, - .io_free= mainloop_io_free, - .io_set_destroy= mainloop_io_set_destroy, - - .time_new = mainloop_time_new, - .time_restart = mainloop_time_restart, - .time_free = mainloop_time_free, - .time_set_destroy = mainloop_time_set_destroy, - - .defer_new = mainloop_defer_new, - .defer_enable = mainloop_defer_enable, - .defer_free = mainloop_defer_free, - .defer_set_destroy = mainloop_defer_set_destroy, - - .quit = mainloop_quit, -}; - -pa_mainloop *pa_mainloop_new(void) { - pa_mainloop *m; - - m = pa_xmalloc(sizeof(pa_mainloop)); - - if (pipe(m->wakeup_pipe) < 0) { - pa_log_error(__FILE__": ERROR: cannot create wakeup pipe"); - pa_xfree(m); - return NULL; - } - - pa_make_nonblock_fd(m->wakeup_pipe[0]); - pa_make_nonblock_fd(m->wakeup_pipe[1]); - - m->io_events = pa_idxset_new(NULL, NULL); - m->defer_events = pa_idxset_new(NULL, NULL); - m->time_events = pa_idxset_new(NULL, NULL); - - assert(m->io_events && m->defer_events && m->time_events); - - m->io_events_scan_dead = m->defer_events_scan_dead = m->time_events_scan_dead = 0; - - m->pollfds = NULL; - m->max_pollfds = m->n_pollfds = 0; - m->rebuild_pollfds = 1; - - m->quit = m->retval = 0; - - m->api = vtable; - m->api.userdata = m; - - m->deferred_pending = 0; - - m->state = STATE_PASSIVE; - - m->poll_func = NULL; - m->poll_func_userdata = NULL; - - m->retval = -1; - - return m; -} - -static int io_foreach(void *p, uint32_t PA_GCC_UNUSED idx, int *del, void*userdata) { - pa_io_event *e = p; - int *all = userdata; - assert(e && del && all); - - if (!*all && !e->dead) - return 0; - - if (e->destroy_callback) - e->destroy_callback(&e->mainloop->api, e, e->userdata); - pa_xfree(e); - *del = 1; - return 0; -} - -static int time_foreach(void *p, uint32_t PA_GCC_UNUSED idx, int *del, void*userdata) { - pa_time_event *e = p; - int *all = userdata; - assert(e && del && all); - - if (!*all && !e->dead) - return 0; - - if (e->destroy_callback) - e->destroy_callback(&e->mainloop->api, e, e->userdata); - pa_xfree(e); - *del = 1; - return 0; -} - -static int defer_foreach(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void*userdata) { - pa_defer_event *e = p; - int *all = userdata; - assert(e && del && all); - - if (!*all && !e->dead) - return 0; - - if (e->destroy_callback) - e->destroy_callback(&e->mainloop->api, e, e->userdata); - pa_xfree(e); - *del = 1; - return 0; -} - -void pa_mainloop_free(pa_mainloop* m) { - int all = 1; - assert(m); - - pa_idxset_foreach(m->io_events, io_foreach, &all); - pa_idxset_foreach(m->time_events, time_foreach, &all); - pa_idxset_foreach(m->defer_events, defer_foreach, &all); - - pa_idxset_free(m->io_events, NULL, NULL); - pa_idxset_free(m->time_events, NULL, NULL); - pa_idxset_free(m->defer_events, NULL, NULL); - - pa_xfree(m->pollfds); - - if (m->wakeup_pipe[0] >= 0) - close(m->wakeup_pipe[0]); - if (m->wakeup_pipe[1] >= 0) - close(m->wakeup_pipe[1]); - - pa_xfree(m); -} - -static void scan_dead(pa_mainloop *m) { - int all = 0; - assert(m); - - if (m->io_events_scan_dead) - pa_idxset_foreach(m->io_events, io_foreach, &all); - if (m->time_events_scan_dead) - pa_idxset_foreach(m->time_events, time_foreach, &all); - if (m->defer_events_scan_dead) - pa_idxset_foreach(m->defer_events, defer_foreach, &all); - - m->io_events_scan_dead = m->time_events_scan_dead = m->defer_events_scan_dead = 0; -} - -static void rebuild_pollfds(pa_mainloop *m) { - pa_io_event*e; - struct pollfd *p; - uint32_t idx = PA_IDXSET_INVALID; - unsigned l; - - l = pa_idxset_size(m->io_events) + 1; - if (m->max_pollfds < l) { - m->pollfds = pa_xrealloc(m->pollfds, sizeof(struct pollfd)*l); - m->max_pollfds = l; - } - - m->n_pollfds = 0; - p = m->pollfds; - - if (m->wakeup_pipe[0] >= 0) { - m->pollfds[0].fd = m->wakeup_pipe[0]; - m->pollfds[0].events = POLLIN; - m->pollfds[0].revents = 0; - p++; - m->n_pollfds++; - } - - for (e = pa_idxset_first(m->io_events, &idx); e; e = pa_idxset_next(m->io_events, &idx)) { - if (e->dead) { - e->pollfd = NULL; - continue; - } - - e->pollfd = p; - p->fd = e->fd; - p->events = - ((e->events & PA_IO_EVENT_INPUT) ? POLLIN : 0) | - ((e->events & PA_IO_EVENT_OUTPUT) ? POLLOUT : 0) | - POLLHUP | - POLLERR; - p->revents = 0; - - p++; - m->n_pollfds++; - } - - m->rebuild_pollfds = 0; -} - -static int dispatch_pollfds(pa_mainloop *m) { - uint32_t idx = PA_IDXSET_INVALID; - pa_io_event *e; - int r = 0; - - for (e = pa_idxset_first(m->io_events, &idx); e && !m->quit; e = pa_idxset_next(m->io_events, &idx)) { - if (e->dead || !e->pollfd || !e->pollfd->revents) - continue; - - assert(e->pollfd->fd == e->fd && e->callback); - e->callback(&m->api, e, e->fd, - (e->pollfd->revents & POLLHUP ? PA_IO_EVENT_HANGUP : 0) | - (e->pollfd->revents & POLLIN ? PA_IO_EVENT_INPUT : 0) | - (e->pollfd->revents & POLLOUT ? PA_IO_EVENT_OUTPUT : 0) | - (e->pollfd->revents & POLLERR ? PA_IO_EVENT_ERROR : 0), - e->userdata); - e->pollfd->revents = 0; - r++; - } - - return r; -} - -static int dispatch_defer(pa_mainloop *m) { - uint32_t idx; - pa_defer_event *e; - int r = 0; - - if (!m->deferred_pending) - return 0; - - for (e = pa_idxset_first(m->defer_events, &idx); e && !m->quit; e = pa_idxset_next(m->defer_events, &idx)) { - if (e->dead || !e->enabled) - continue; - - assert(e->callback); - e->callback(&m->api, e, e->userdata); - r++; - } - - return r; -} - -static int calc_next_timeout(pa_mainloop *m) { - uint32_t idx; - pa_time_event *e; - struct timeval now; - int t = -1; - int got_time = 0; - - if (pa_idxset_isempty(m->time_events)) - return -1; - - for (e = pa_idxset_first(m->time_events, &idx); e; e = pa_idxset_next(m->time_events, &idx)) { - int tmp; - - if (e->dead || !e->enabled) - continue; - - /* Let's save a system call */ - if (!got_time) { - pa_gettimeofday(&now); - got_time = 1; - } - - if (e->timeval.tv_sec < now.tv_sec || (e->timeval.tv_sec == now.tv_sec && e->timeval.tv_usec <= now.tv_usec)) - return 0; - - tmp = (e->timeval.tv_sec - now.tv_sec)*1000; - - if (e->timeval.tv_usec > now.tv_usec) - tmp += (e->timeval.tv_usec - now.tv_usec)/1000; - else - tmp -= (now.tv_usec - e->timeval.tv_usec)/1000; - - if (tmp == 0) - return 0; - else if (t == -1 || tmp < t) - t = tmp; - } - - return t; -} - -static int dispatch_timeout(pa_mainloop *m) { - uint32_t idx; - pa_time_event *e; - struct timeval now; - int got_time = 0; - int r = 0; - assert(m); - - if (pa_idxset_isempty(m->time_events)) - return 0; - - for (e = pa_idxset_first(m->time_events, &idx); e && !m->quit; e = pa_idxset_next(m->time_events, &idx)) { - - if (e->dead || !e->enabled) - continue; - - /* Let's save a system call */ - if (!got_time) { - pa_gettimeofday(&now); - got_time = 1; - } - - if (e->timeval.tv_sec < now.tv_sec || (e->timeval.tv_sec == now.tv_sec && e->timeval.tv_usec <= now.tv_usec)) { - assert(e->callback); - - e->enabled = 0; - e->callback(&m->api, e, &e->timeval, e->userdata); - - r++; - } - } - - return r; -} - -void pa_mainloop_wakeup(pa_mainloop *m) { - char c = 'W'; - assert(m); - - if (m->wakeup_pipe[1] >= 0) - pa_write(m->wakeup_pipe[1], &c, sizeof(c)); -} - -static void clear_wakeup(pa_mainloop *m) { - char c[10]; - - assert(m); - - if (m->wakeup_pipe[0] < 0) - return; - - while (pa_read(m->wakeup_pipe[0], &c, sizeof(c)) == sizeof(c)); -} - -int pa_mainloop_prepare(pa_mainloop *m, int timeout) { - assert(m); - assert(m->state == STATE_PASSIVE); - - clear_wakeup(m); - scan_dead(m); - - if (m->quit) - goto quit; - - if (!m->deferred_pending) { - - if (m->rebuild_pollfds) - rebuild_pollfds(m); - - m->prepared_timeout = calc_next_timeout(m); - if (timeout >= 0 && (timeout < m->prepared_timeout || m->prepared_timeout < 0)) - m->prepared_timeout = timeout; - } - - m->state = STATE_PREPARED; - return 0; - -quit: - m->state = STATE_QUIT; - return -2; -} - -int pa_mainloop_poll(pa_mainloop *m) { - int r; - - assert(m); - assert(m->state == STATE_PREPARED); - - if (m->quit) - goto quit; - - m->state = STATE_POLLING; - - if (m->deferred_pending) - r = 0; - else { - if (m->poll_func) - r = m->poll_func(m->pollfds, m->n_pollfds, m->prepared_timeout, m->poll_func_userdata); - else - r = poll(m->pollfds, m->n_pollfds, m->prepared_timeout); - - if (r < 0) { - if (errno == EINTR) - r = 0; - else - pa_log(__FILE__": poll(): %s", pa_cstrerror(errno)); - } - } - - m->state = r < 0 ? STATE_PASSIVE : STATE_POLLED; - return r; - -quit: - m->state = STATE_QUIT; - return -2; -} - -int pa_mainloop_dispatch(pa_mainloop *m) { - int dispatched = 0; - - assert(m); - assert(m->state == STATE_POLLED); - - if (m->quit) - goto quit; - - if (m->deferred_pending) - dispatched += dispatch_defer(m); - else { - dispatched += dispatch_timeout(m); - - if (m->quit) - goto quit; - - dispatched += dispatch_pollfds(m); - - } - - if (m->quit) - goto quit; - - m->state = STATE_PASSIVE; - - return dispatched; - -quit: - m->state = STATE_QUIT; - return -2; -} - -int pa_mainloop_get_retval(pa_mainloop *m) { - assert(m); - return m->retval; -} - -int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval) { - int r; - assert(m); - - if ((r = pa_mainloop_prepare(m, block ? -1 : 0)) < 0) - goto quit; - - if ((r = pa_mainloop_poll(m)) < 0) - goto quit; - - if ((r = pa_mainloop_dispatch(m)) < 0) - goto quit; - - return r; - -quit: - - if ((r == -2) && retval) - *retval = pa_mainloop_get_retval(m); - return r; -} - -int pa_mainloop_run(pa_mainloop *m, int *retval) { - int r; - - while ((r = pa_mainloop_iterate(m, 1, retval)) >= 0); - - if (r == -2) - return 1; - else if (r < 0) - return -1; - else - return 0; -} - -void pa_mainloop_quit(pa_mainloop *m, int retval) { - assert(m); - - m->quit = 1; - m->retval = retval; - pa_mainloop_wakeup(m); -} - -pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m) { - assert(m); - return &m->api; -} - -void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *userdata) { - assert(m); - - m->poll_func = poll_func; - m->poll_func_userdata = userdata; -} - - -#if 0 -void pa_mainloop_dump(pa_mainloop *m) { - assert(m); - - pa_log(__FILE__": Dumping mainloop sources START"); - - { - uint32_t idx = PA_IDXSET_INVALID; - pa_io_event *e; - for (e = pa_idxset_first(m->io_events, &idx); e; e = pa_idxset_next(m->io_events, &idx)) { - if (e->dead) - continue; - - pa_log(__FILE__": kind=io fd=%i events=%i callback=%p userdata=%p", e->fd, (int) e->events, (void*) e->callback, (void*) e->userdata); - } - } - { - uint32_t idx = PA_IDXSET_INVALID; - pa_defer_event *e; - for (e = pa_idxset_first(m->defer_events, &idx); e; e = pa_idxset_next(m->defer_events, &idx)) { - if (e->dead) - continue; - - pa_log(__FILE__": kind=defer enabled=%i callback=%p userdata=%p", e->enabled, (void*) e->callback, (void*) e->userdata); - } - } - { - uint32_t idx = PA_IDXSET_INVALID; - pa_time_event *e; - for (e = pa_idxset_first(m->time_events, &idx); e; e = pa_idxset_next(m->time_events, &idx)) { - if (e->dead) - continue; - - pa_log(__FILE__": kind=time enabled=%i time=%lu.%lu callback=%p userdata=%p", e->enabled, (unsigned long) e->timeval.tv_sec, (unsigned long) e->timeval.tv_usec, (void*) e->callback, (void*) e->userdata); - } - } - - pa_log(__FILE__": Dumping mainloop sources STOP"); - -} -#endif diff --git a/src/polyp/mainloop.h b/src/polyp/mainloop.h deleted file mode 100644 index 4681912b..00000000 --- a/src/polyp/mainloop.h +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef foomainloophfoo -#define foomainloophfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <polyp/mainloop-api.h> -#include <polyp/cdecl.h> - -PA_C_DECL_BEGIN - -struct pollfd; - -/** \page mainloop Main Loop - * - * \section overv_sec Overview - * - * The built-in main loop implementation is based on the poll() system call. - * It supports the functions defined in the main loop abstraction and very - * little else. - * - * The main loop is created using pa_mainloop_new() and destroyed using - * pa_mainloop_free(). To get access to the main loop abstraction, - * pa_mainloop_get_api() is used. - * - * \section iter_sec Iteration - * - * The main loop is designed around the concept of iterations. Each iteration - * consists of three steps that repeat during the application's entire - * lifetime: - * - * -# Prepare - Build a list of file descriptors - * that need to be monitored and calculate the next timeout. - * -# Poll - Execute the actuall poll() system call. - * -# Dispatch - Dispatch any events that have fired. - * - * When using the main loop, the application can either execute each - * iteration, one at a time, using pa_mainloop_iterate(), or let the library - * iterate automatically using pa_mainloop_run(). - * - * \section thread_sec Threads - * - * The main loop functions are designed to be thread safe, but the objects - * are not. What this means is that multiple main loops can be used, but only - * one object per thread. - * - */ - -/** \file - * - * A minimal main loop implementation based on the C library's poll() - * function. Using the routines defined herein you may create a simple - * main loop supporting the generic main loop abstraction layer as - * defined in \ref mainloop-api.h. This implementation is thread safe - * as long as you access the main loop object from a single thread only.*/ - -/** An opaque main loop object */ -typedef struct pa_mainloop pa_mainloop; - -/** Allocate a new main loop object */ -pa_mainloop *pa_mainloop_new(void); - -/** Free a main loop object */ -void pa_mainloop_free(pa_mainloop* m); - -/** Prepare for a single iteration of the main loop. Returns a negative value -on error or exit request. timeout specifies a maximum timeout for the subsequent -poll, or -1 for blocking behaviour. .*/ -int pa_mainloop_prepare(pa_mainloop *m, int timeout); - -/** Execute the previously prepared poll. Returns a negative value on error.*/ -int pa_mainloop_poll(pa_mainloop *m); - -/** Dispatch timeout, io and deferred events from the previously executed poll. Returns -a negative value on error. On success returns the number of source dispatched. */ -int pa_mainloop_dispatch(pa_mainloop *m); - -/** Return the return value as specified with the main loop's quit() routine. */ -int pa_mainloop_get_retval(pa_mainloop *m); - -/** Run a single iteration of the main loop. This is a convenience function -for pa_mainloop_prepare(), pa_mainloop_poll() and pa_mainloop_dispatch(). -Returns a negative value on error or exit request. If block is nonzero, -block for events if none are queued. Optionally return the return value as -specified with the main loop's quit() routine in the integer variable retval points -to. On success returns the number of sources dispatched in this iteration. */ -int pa_mainloop_iterate(pa_mainloop *m, int block, int *retval); - -/** Run unlimited iterations of the main loop object until the main loop's quit() routine is called. */ -int pa_mainloop_run(pa_mainloop *m, int *retval); - -/** Return the abstract main loop abstraction layer vtable for this main loop. */ -pa_mainloop_api* pa_mainloop_get_api(pa_mainloop*m); - -/** Shutdown the main loop */ -void pa_mainloop_quit(pa_mainloop *m, int r); - -/** Interrupt a running poll (for threaded systems) */ -void pa_mainloop_wakeup(pa_mainloop *m); - -/** Generic prototype of a poll() like function */ -typedef int (*pa_poll_func)(struct pollfd *ufds, unsigned long nfds, int timeout, void*userdata); - -/** Change the poll() implementation */ -void pa_mainloop_set_poll_func(pa_mainloop *m, pa_poll_func poll_func, void *userdata); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/operation.c b/src/polyp/operation.c deleted file mode 100644 index 5af9ec0b..00000000 --- a/src/polyp/operation.c +++ /dev/null @@ -1,116 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <assert.h> - -#include <polyp/xmalloc.h> - -#include "internal.h" -#include "operation.h" - -pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t cb, void *userdata) { - pa_operation *o; - assert(c); - - o = pa_xnew(pa_operation, 1); - o->ref = 1; - o->context = c; - o->stream = s; - - o->state = PA_OPERATION_RUNNING; - o->callback = cb; - o->userdata = userdata; - - /* Refcounting is strictly one-way: from the "bigger" to the "smaller" object. */ - PA_LLIST_PREPEND(pa_operation, c->operations, o); - pa_operation_ref(o); - - return o; -} - -pa_operation *pa_operation_ref(pa_operation *o) { - assert(o); - assert(o->ref >= 1); - - o->ref++; - return o; -} - -void pa_operation_unref(pa_operation *o) { - assert(o); - assert(o->ref >= 1); - - if ((--(o->ref)) == 0) { - assert(!o->context); - assert(!o->stream); - pa_xfree(o); - } -} - -static void operation_set_state(pa_operation *o, pa_operation_state_t st) { - assert(o); - assert(o->ref >= 1); - - if (st == o->state) - return; - - o->state = st; - - if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED)) { - - if (o->context) { - assert(o->ref >= 2); - - PA_LLIST_REMOVE(pa_operation, o->context->operations, o); - pa_operation_unref(o); - } - - o->context = NULL; - o->stream = NULL; - o->callback = NULL; - o->userdata = NULL; - } -} - -void pa_operation_cancel(pa_operation *o) { - assert(o); - assert(o->ref >= 1); - - operation_set_state(o, PA_OPERATION_CANCELED); -} - -void pa_operation_done(pa_operation *o) { - assert(o); - assert(o->ref >= 1); - - operation_set_state(o, PA_OPERATION_DONE); -} - -pa_operation_state_t pa_operation_get_state(pa_operation *o) { - assert(o); - assert(o->ref >= 1); - - return o->state; -} diff --git a/src/polyp/operation.h b/src/polyp/operation.h deleted file mode 100644 index 2fbac2e2..00000000 --- a/src/polyp/operation.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef foooperationhfoo -#define foooperationhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <polyp/cdecl.h> -#include <polyp/def.h> - -/** \file - * Asynchronous operations */ - -PA_C_DECL_BEGIN - -/** An asynchronous operation object */ -typedef struct pa_operation pa_operation; - -/** Increase the reference count by one */ -pa_operation *pa_operation_ref(pa_operation *o); - -/** Decrease the reference count by one */ -void pa_operation_unref(pa_operation *o); - -/** Cancel the operation. Beware! This will not necessarily cancel the execution of the operation on the server side. */ -void pa_operation_cancel(pa_operation *o); - -/** Return the current status of the operation */ -pa_operation_state_t pa_operation_get_state(pa_operation *o); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/polypaudio.h b/src/polyp/polypaudio.h deleted file mode 100644 index c172315b..00000000 --- a/src/polyp/polypaudio.h +++ /dev/null @@ -1,115 +0,0 @@ -#ifndef foopolypaudiohfoo -#define foopolypaudiohfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <polyp/mainloop-api.h> -#include <polyp/sample.h> -#include <polyp/def.h> -#include <polyp/context.h> -#include <polyp/stream.h> -#include <polyp/introspect.h> -#include <polyp/subscribe.h> -#include <polyp/scache.h> -#include <polyp/version.h> -#include <polyp/error.h> -#include <polyp/operation.h> -#include <polyp/channelmap.h> -#include <polyp/volume.h> -#include <polyp/xmalloc.h> -#include <polyp/utf8.h> -#include <polyp/thread-mainloop.h> -#include <polyp/mainloop.h> -#include <polyp/mainloop-signal.h> -#include <polyp/util.h> -#include <polyp/timeval.h> - -/** \file - * Include all polyplib header files at once. The following - * files are included: \ref mainloop-api.h, \ref sample.h, \ref def.h, - * \ref context.h, \ref stream.h, \ref introspect.h, \ref subscribe.h, - * \ref scache.h, \ref version.h, \ref error.h, \ref channelmap.h, - * \ref operation.h,\ref volume.h, \ref xmalloc.h, \ref utf8.h, \ref - * thread-mainloop.h, \ref mainloop.h, \ref util.h, \ref timeval.h and - * \ref mainloop-signal.h at once */ - -/** \mainpage - * - * \section intro_sec Introduction - * - * This document describes the client API for the polypaudio sound - * server. The API comes in two flavours to accomodate different styles - * of applications and different needs in complexity: - * - * \li The complete but somewhat complicated to use asynchronous API - * \li The simplified, easy to use, but limited synchronous API - * - * All strings in Polypaudio are in the UTF-8 encoding, regardless of current - * locale. Some functions will filter invalid sequences from the string, some - * will simply fail. To ensure reliable behaviour, make sure everything you - * pass to the API is already in UTF-8. - - * \section simple_sec Simple API - * - * Use this if you develop your program in synchronous style and just - * need a way to play or record data on the sound server. See - * \subpage simple for more details. - * - * \section async_sec Asynchronous API - * - * Use this if you develop your programs in asynchronous, event loop - * based style or if you want to use the advanced features of the - * polypaudio API. A guide can be found in \subpage async. - * - * By using the built-in threaded main loop, it is possible to acheive a - * pseudo-synchronous API, which can be useful in synchronous applications - * where the simple API is insufficient. See the \ref async page for - * details. - * - * \section thread_sec Threads - * - * The polypaudio client libraries are not designed to be used in a - * heavily threaded environment. They are however designed to be reentrant - * safe. - * - * To use a the libraries in a threaded environment, you must assure that - * all objects are only used in one thread at a time. Normally, this means - * that all objects belonging to a single context must be accessed from the - * same thread. - * - * The included main loop implementation is also not thread safe. Take care - * to make sure event lists are not manipulated when any other code is - * using the main loop. - * - * \section pkgconfig pkg-config - * - * The polypaudio libraries provide pkg-config snippets for the different - * modules: - * - * \li polyplib - The asynchronous API and the internal main loop - * implementation. - * \li polyplib-glib12-mainloop - GLIB 1.2 main loop bindings. - * \li polyplib-glib-mainloop - GLIB 2.x main loop bindings. - * \li polyplib-simple - The simple polypaudio API. - */ - -#endif diff --git a/src/polyp/sample.c b/src/polyp/sample.c deleted file mode 100644 index 9c3b9f91..00000000 --- a/src/polyp/sample.c +++ /dev/null @@ -1,156 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <assert.h> -#include <math.h> -#include <string.h> - -#include "sample.h" - -size_t pa_sample_size(const pa_sample_spec *spec) { - assert(spec); - - switch (spec->format) { - case PA_SAMPLE_U8: - case PA_SAMPLE_ULAW: - case PA_SAMPLE_ALAW: - return 1; - case PA_SAMPLE_S16LE: - case PA_SAMPLE_S16BE: - return 2; - case PA_SAMPLE_FLOAT32LE: - case PA_SAMPLE_FLOAT32BE: - return 4; - default: - assert(0); - return 0; - } -} - -size_t pa_frame_size(const pa_sample_spec *spec) { - assert(spec); - - return pa_sample_size(spec) * spec->channels; -} - -size_t pa_bytes_per_second(const pa_sample_spec *spec) { - assert(spec); - return spec->rate*pa_frame_size(spec); -} - -pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec) { - assert(spec); - - return (pa_usec_t) (((double) length/pa_frame_size(spec)*1000000)/spec->rate); -} - -size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec) { - assert(spec); - - return ((double) t * spec->rate / 1000000)*pa_frame_size(spec); -} - -int pa_sample_spec_valid(const pa_sample_spec *spec) { - assert(spec); - - if (spec->rate <= 0 || - spec->channels <= 0 || - spec->channels > PA_CHANNELS_MAX || - spec->format >= PA_SAMPLE_MAX || - spec->format < 0) - return 0; - - return 1; -} - -int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b) { - assert(a && b); - - return (a->format == b->format) && (a->rate == b->rate) && (a->channels == b->channels); -} - -const char *pa_sample_format_to_string(pa_sample_format_t f) { - static const char* const table[]= { - [PA_SAMPLE_U8] = "u8", - [PA_SAMPLE_ALAW] = "aLaw", - [PA_SAMPLE_ULAW] = "uLaw", - [PA_SAMPLE_S16LE] = "s16le", - [PA_SAMPLE_S16BE] = "s16be", - [PA_SAMPLE_FLOAT32LE] = "float32le", - [PA_SAMPLE_FLOAT32BE] = "float32be", - }; - - if (f >= PA_SAMPLE_MAX) - return NULL; - - return table[f]; -} - -char *pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec) { - assert(s && l && spec); - - if (!pa_sample_spec_valid(spec)) - snprintf(s, l, "Invalid"); - else - snprintf(s, l, "%s %uch %uHz", pa_sample_format_to_string(spec->format), spec->channels, spec->rate); - - return s; -} - -void pa_bytes_snprint(char *s, size_t l, unsigned v) { - if (v >= ((unsigned) 1024)*1024*1024) - snprintf(s, l, "%0.1f GiB", ((double) v)/1024/1024/1024); - else if (v >= ((unsigned) 1024)*1024) - snprintf(s, l, "%0.1f MiB", ((double) v)/1024/1024); - else if (v >= (unsigned) 1024) - snprintf(s, l, "%0.1f KiB", ((double) v)/1024); - else - snprintf(s, l, "%u B", (unsigned) v); -} - -pa_sample_format_t pa_parse_sample_format(const char *format) { - - if (strcasecmp(format, "s16le") == 0) - return PA_SAMPLE_S16LE; - else if (strcasecmp(format, "s16be") == 0) - return PA_SAMPLE_S16BE; - else if (strcasecmp(format, "s16ne") == 0 || strcasecmp(format, "s16") == 0 || strcasecmp(format, "16") == 0) - return PA_SAMPLE_S16NE; - else if (strcasecmp(format, "u8") == 0 || strcasecmp(format, "8") == 0) - return PA_SAMPLE_U8; - else if (strcasecmp(format, "float32") == 0 || strcasecmp(format, "float32ne") == 0) - return PA_SAMPLE_FLOAT32; - else if (strcasecmp(format, "float32le") == 0) - return PA_SAMPLE_FLOAT32LE; - else if (strcasecmp(format, "float32be") == 0) - return PA_SAMPLE_FLOAT32BE; - else if (strcasecmp(format, "ulaw") == 0) - return PA_SAMPLE_ULAW; - else if (strcasecmp(format, "alaw") == 0) - return PA_SAMPLE_ALAW; - - return -1; -} diff --git a/src/polyp/sample.h b/src/polyp/sample.h deleted file mode 100644 index 2a9a72fe..00000000 --- a/src/polyp/sample.h +++ /dev/null @@ -1,189 +0,0 @@ -#ifndef foosamplehfoo -#define foosamplehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <inttypes.h> -#include <sys/types.h> -#include <math.h> - -#include <polyp/cdecl.h> - -/** \page sample Sample Format Specifications - * - * \section overv_sec Overview - * - * Polypaudio is capable of handling a multitude of sample formats, rates - * and channels, transparently converting and mixing them as needed. - * - * \section format_sec Sample Format - * - * Polypaudio supports the following sample formats: - * - * \li PA_SAMPLE_U8 - Unsigned 8 bit PCM. - * \li PA_SAMPLE_S16LE - Signed 16 bit PCM, little endian. - * \li PA_SAMPLE_S16BE - Signed 16 bit PCM, big endian. - * \li PA_SAMPLE_FLOAT32LE - 32 bit IEEE floating point PCM, little endian. - * \li PA_SAMPLE_FLOAT32BE - 32 bit IEEE floating point PCM, big endian. - * \li PA_SAMPLE_ALAW - 8 bit a-Law. - * \li PA_SAMPLE_ULAW - 8 bit mu-Law. - * - * The floating point sample formats have the range from -1 to 1. - * - * The sample formats that are sensitive to endianness have convenience - * macros for native endian (NE), and reverse endian (RE). - * - * \section rate_sec Sample Rates - * - * Polypaudio supports any sample rate between 1 Hz and 4 GHz. There is no - * point trying to exceed the sample rate of the output device though as the - * signal will only get downsampled, consuming CPU on the machine running the - * server. - * - * \section chan_sec Channels - * - * Polypaudio supports up to 16 individiual channels. The order of the - * channels is up to the application, but they must be continous. To map - * channels to speakers, see \ref channelmap. - * - * \section calc_sec Calculations - * - * The Polypaudio library contains a number of convenience functions to do - * calculations on sample formats: - * - * \li pa_bytes_per_second() - The number of bytes one second of audio will - * take given a sample format. - * \li pa_frame_size() - The size, in bytes, of one frame (i.e. one set of - * samples, one for each channel). - * \li pa_sample_size() - The size, in bytes, of one sample. - * \li pa_bytes_to_usec() - Calculate the time it would take to play a buffer - * of a certain size. - * - * \section util_sec Convenience Functions - * - * The library also contains a couple of other convenience functions: - * - * \li pa_sample_spec_valid() - Tests if a sample format specification is - * valid. - * \li pa_sample_spec_equal() - Tests if the sample format specifications are - * identical. - * \li pa_sample_format_to_string() - Return a textual description of a - * sample format. - * \li pa_parse_sample_format() - Parse a text string into a sample format. - * \li pa_sample_spec_snprint() - Create a textual description of a complete - * sample format specification. - * \li pa_bytes_snprint() - Pretty print a byte value (e.g. 2.5 MiB). - */ - -/** \file - * Constants and routines for sample type handling */ - -PA_C_DECL_BEGIN - -/** Maximum number of allowed channels */ -#define PA_CHANNELS_MAX 32 - -/** Sample format */ -typedef enum pa_sample_format { - PA_SAMPLE_U8, /**< Unsigned 8 Bit PCM */ - PA_SAMPLE_ALAW, /**< 8 Bit a-Law */ - PA_SAMPLE_ULAW, /**< 8 Bit mu-Law */ - PA_SAMPLE_S16LE, /**< Signed 16 Bit PCM, little endian (PC) */ - PA_SAMPLE_S16BE, /**< Signed 16 Bit PCM, big endian */ - PA_SAMPLE_FLOAT32LE, /**< 32 Bit IEEE floating point, little endian, range -1 to 1 */ - PA_SAMPLE_FLOAT32BE, /**< 32 Bit IEEE floating point, big endian, range -1 to 1 */ - PA_SAMPLE_MAX, /**< Upper limit of valid sample types */ - PA_SAMPLE_INVALID = -1 /**< An invalid value */ -} pa_sample_format_t; - -#ifdef WORDS_BIGENDIAN -/** Signed 16 Bit PCM, native endian */ -#define PA_SAMPLE_S16NE PA_SAMPLE_S16BE -/** 32 Bit IEEE floating point, native endian */ -#define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32BE -/** Signed 16 Bit PCM reverse endian */ -#define PA_SAMPLE_S16RE PA_SAMPLE_S16LE -/** 32 Bit IEEE floating point, reverse endian */ -#define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32LE -#else -/** Signed 16 Bit PCM, native endian */ -#define PA_SAMPLE_S16NE PA_SAMPLE_S16LE -/** 32 Bit IEEE floating point, native endian */ -#define PA_SAMPLE_FLOAT32NE PA_SAMPLE_FLOAT32LE -/** Signed 16 Bit PCM reverse endian */ -#define PA_SAMPLE_S16RE PA_SAMPLE_S16BE -/** 32 Bit IEEE floating point, reverse endian */ -#define PA_SAMPLE_FLOAT32RE PA_SAMPLE_FLOAT32BE -#endif - -/** A Shortcut for PA_SAMPLE_FLOAT32NE */ -#define PA_SAMPLE_FLOAT32 PA_SAMPLE_FLOAT32NE - -/** A sample format and attribute specification */ -typedef struct pa_sample_spec { - pa_sample_format_t format; /**< The sample format */ - uint32_t rate; /**< The sample rate. (e.g. 44100) */ - uint8_t channels; /**< Audio channels. (1 for mono, 2 for stereo, ...) */ -} pa_sample_spec; - -/** Type for usec specifications (unsigned). May be either 32 or 64 bit, depending on the architecture */ -typedef uint64_t pa_usec_t; - -/** Return the amount of bytes playback of a second of audio with the specified sample type takes */ -size_t pa_bytes_per_second(const pa_sample_spec *spec); - -/** Return the size of a frame with the specific sample type */ -size_t pa_frame_size(const pa_sample_spec *spec); - -/** Return the size of a sample with the specific sample type */ -size_t pa_sample_size(const pa_sample_spec *spec); - -/** Calculate the time the specified bytes take to play with the specified sample type */ -pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec); - -/** Calculates the number of bytes that are required for the specified time. \since 0.9 */ -size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec); - -/** Return non-zero when the sample type specification is valid */ -int pa_sample_spec_valid(const pa_sample_spec *spec); - -/** Return non-zero when the two sample type specifications match */ -int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b); - -/** Return a descriptive string for the specified sample format. \since 0.8 */ -const char *pa_sample_format_to_string(pa_sample_format_t f); - -/** Parse a sample format text. Inverse of pa_sample_format_to_string() */ -pa_sample_format_t pa_parse_sample_format(const char *format); - -/** Maximum required string length for pa_sample_spec_snprint() */ -#define PA_SAMPLE_SPEC_SNPRINT_MAX 32 - -/** Pretty print a sample type specification to a string */ -char* pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec); - -/** Pretty print a byte size value. (i.e. "2.5 MiB") */ -void pa_bytes_snprint(char *s, size_t l, unsigned v); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/scache.c b/src/polyp/scache.c deleted file mode 100644 index 22d8a545..00000000 --- a/src/polyp/scache.c +++ /dev/null @@ -1,131 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <assert.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#include <polypcore/pstream-util.h> - -#include "internal.h" - -#include "scache.h" - -int pa_stream_connect_upload(pa_stream *s, size_t length) { - pa_tagstruct *t; - uint32_t tag; - - assert(s); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, length > 0, PA_ERR_INVALID); - - pa_stream_ref(s); - - s->direction = PA_STREAM_UPLOAD; - - t = pa_tagstruct_command(s->context, PA_COMMAND_CREATE_UPLOAD_STREAM, &tag); - pa_tagstruct_puts(t, s->name); - pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_put_channel_map(t, &s->channel_map); - pa_tagstruct_putu32(t, length); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL); - - pa_stream_set_state(s, PA_STREAM_CREATING); - - pa_stream_unref(s); - return 0; -} - -int pa_stream_finish_upload(pa_stream *s) { - pa_tagstruct *t; - uint32_t tag; - assert(s); - - PA_CHECK_VALIDITY(s->context, s->channel_valid, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->context->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pa_stream_ref(s); - - t = pa_tagstruct_command(s->context, PA_COMMAND_FINISH_UPLOAD_STREAM, &tag); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s, NULL); - - pa_stream_unref(s); - return 0; -} - -pa_operation *pa_context_play_sample(pa_context *c, const char *name, const char *dev, pa_volume_t volume, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, !dev || *dev, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - if (!dev) - dev = c->conf->default_sink; - - t = pa_tagstruct_command(c, PA_COMMAND_PLAY_SAMPLE, &tag); - pa_tagstruct_putu32(t, PA_INVALID_INDEX); - pa_tagstruct_puts(t, dev); - pa_tagstruct_putu32(t, volume); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_context_remove_sample(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_SAMPLE, &tag); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - diff --git a/src/polyp/scache.h b/src/polyp/scache.h deleted file mode 100644 index 91890673..00000000 --- a/src/polyp/scache.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef fooscachehfoo -#define fooscachehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <sys/types.h> - -#include <polyp/context.h> -#include <polyp/stream.h> -#include <polyp/cdecl.h> - -/** \page scache Sample Cache - * - * \section overv_sec Overview - * - * The sample cache provides a simple way of overcoming high network latencies - * and reducing bandwidth. Instead of streaming a sound precisely when it - * should be played, it is stored on the server and only the command to start - * playing it needs to be sent. - * - * \section create_sec Creation - * - * To create a sample, the normal stream API is used (see \ref streams). The - * function pa_stream_connect_upload() will make sure the stream is stored as - * a sample on the server. - * - * To complete the upload, pa_stream_finish_upload() is called and the sample - * will receive the same name as the stream. If the upload should be aborted, - * simply call pa_stream_disconnect(). - * - * \section play_sec Playing samples - * - * To play back a sample, simply call pa_context_play_sample(): - * - * \code - * pa_operation *o; - * - * o = pa_context_play_sample(my_context, - * "sample2", // Name of my sample - * NULL, // Use default sink - * PA_VOLUME_NORM, // Full volume - * NULL, // Don't need a callback - * NULL - * ); - * if (o) - * pa_operation_unref(o); - * \endcode - * - * \section rem_sec Removing samples - * - * When a sample is no longer needed, it should be removed on the server to - * save resources. The sample is deleted using pa_context_remove_sample(). - */ - -/** \file - * All sample cache related routines */ - -PA_C_DECL_BEGIN - -/** Make this stream a sample upload stream */ -int pa_stream_connect_upload(pa_stream *s, size_t length); - -/** Finish the sample upload, the stream name will become the sample name. You cancel a samp - * le upload by issuing pa_stream_disconnect() */ -int pa_stream_finish_upload(pa_stream *s); - -/** Play a sample from the sample cache to the specified device. If the latter is NULL use the default sink. Returns an operation object */ -pa_operation* pa_context_play_sample( - pa_context *c /**< Context */, - const char *name /**< Name of the sample to play */, - const char *dev /**< Sink to play this sample on */, - pa_volume_t volume /**< Volume to play this sample with */ , - pa_context_success_cb_t cb /**< Call this function after successfully starting playback, or NULL */, - void *userdata /**< Userdata to pass to the callback */); - -/** Remove a sample from the sample cache. Returns an operation object which may be used to cancel the operation while it is running */ -pa_operation* pa_context_remove_sample(pa_context *c, const char *name, pa_context_success_cb_t, void *userdata); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/simple.c b/src/polyp/simple.c deleted file mode 100644 index 9c2c908c..00000000 --- a/src/polyp/simple.c +++ /dev/null @@ -1,455 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <string.h> -#include <assert.h> -#include <stdlib.h> - -#include <polyp/polypaudio.h> -#include <polyp/thread-mainloop.h> -#include <polyp/xmalloc.h> - -#include <polypcore/native-common.h> -#include <polypcore/log.h> - -#include "simple.h" - -struct pa_simple { - pa_threaded_mainloop *mainloop; - pa_context *context; - pa_stream *stream; - pa_stream_direction_t direction; - - const void *read_data; - size_t read_index, read_length; - - int operation_success; -}; - -#define CHECK_VALIDITY_RETURN_ANY(rerror, expression, error, ret) do { \ -if (!(expression)) { \ - if (rerror) \ - *(rerror) = error; \ - return (ret); \ - } \ -} while(0); - -#define CHECK_SUCCESS_GOTO(p, rerror, expression, label) do { \ -if (!(expression)) { \ - if (rerror) \ - *(rerror) = pa_context_errno((p)->context); \ - goto label; \ - } \ -} while(0); - -#define CHECK_DEAD_GOTO(p, rerror, label) do { \ -if (!(p)->context || pa_context_get_state((p)->context) != PA_CONTEXT_READY || \ - !(p)->stream || pa_stream_get_state((p)->stream) != PA_STREAM_READY) { \ - if (((p)->context && pa_context_get_state((p)->context) == PA_CONTEXT_FAILED) || \ - ((p)->stream && pa_stream_get_state((p)->stream) == PA_STREAM_FAILED)) { \ - if (rerror) \ - *(rerror) = pa_context_errno((p)->context); \ - } else \ - if (rerror) \ - *(rerror) = PA_ERR_BADSTATE; \ - goto label; \ - } \ -} while(0); - -static void context_state_cb(pa_context *c, void *userdata) { - pa_simple *p = userdata; - assert(c); - assert(p); - - switch (pa_context_get_state(c)) { - case PA_CONTEXT_READY: - case PA_CONTEXT_TERMINATED: - case PA_CONTEXT_FAILED: - pa_threaded_mainloop_signal(p->mainloop, 0); - break; - - case PA_CONTEXT_UNCONNECTED: - case PA_CONTEXT_CONNECTING: - case PA_CONTEXT_AUTHORIZING: - case PA_CONTEXT_SETTING_NAME: - break; - } -} - -static void stream_state_cb(pa_stream *s, void * userdata) { - pa_simple *p = userdata; - assert(s); - assert(p); - - switch (pa_stream_get_state(s)) { - - case PA_STREAM_READY: - case PA_STREAM_FAILED: - case PA_STREAM_TERMINATED: - pa_threaded_mainloop_signal(p->mainloop, 0); - break; - - case PA_STREAM_UNCONNECTED: - case PA_STREAM_CREATING: - break; - } -} - -static void stream_request_cb(pa_stream *s, size_t length, void *userdata) { - pa_simple *p = userdata; - assert(p); - - pa_threaded_mainloop_signal(p->mainloop, 0); -} - -static void stream_latency_update_cb(pa_stream *s, void *userdata) { - pa_simple *p = userdata; - - assert(p); - - pa_threaded_mainloop_signal(p->mainloop, 0); -} - -pa_simple* pa_simple_new( - const char *server, - const char *name, - pa_stream_direction_t dir, - const char *dev, - const char *stream_name, - const pa_sample_spec *ss, - const pa_channel_map *map, - const pa_buffer_attr *attr, - int *rerror) { - - pa_simple *p; - int error = PA_ERR_INTERNAL, r; - - CHECK_VALIDITY_RETURN_ANY(rerror, !server || *server, PA_ERR_INVALID, NULL); - CHECK_VALIDITY_RETURN_ANY(rerror, dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD, PA_ERR_INVALID, NULL); - CHECK_VALIDITY_RETURN_ANY(rerror, !dev || *dev, PA_ERR_INVALID, NULL); - CHECK_VALIDITY_RETURN_ANY(rerror, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID, NULL); - CHECK_VALIDITY_RETURN_ANY(rerror, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID, NULL) - - p = pa_xnew(pa_simple, 1); - p->context = NULL; - p->stream = NULL; - p->direction = dir; - p->read_data = NULL; - p->read_index = p->read_length = 0; - - if (!(p->mainloop = pa_threaded_mainloop_new())) - goto fail; - - if (!(p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), name))) - goto fail; - - pa_context_set_state_callback(p->context, context_state_cb, p); - - if (pa_context_connect(p->context, server, 0, NULL) < 0) { - error = pa_context_errno(p->context); - goto fail; - } - - pa_threaded_mainloop_lock(p->mainloop); - - if (pa_threaded_mainloop_start(p->mainloop) < 0) - goto unlock_and_fail; - - /* Wait until the context is ready */ - pa_threaded_mainloop_wait(p->mainloop); - - if (pa_context_get_state(p->context) != PA_CONTEXT_READY) { - error = pa_context_errno(p->context); - goto unlock_and_fail; - } - - if (!(p->stream = pa_stream_new(p->context, stream_name, ss, map))) { - error = pa_context_errno(p->context); - goto unlock_and_fail; - } - - pa_stream_set_state_callback(p->stream, stream_state_cb, p); - pa_stream_set_read_callback(p->stream, stream_request_cb, p); - pa_stream_set_write_callback(p->stream, stream_request_cb, p); - pa_stream_set_latency_update_callback(p->stream, stream_latency_update_cb, p); - - if (dir == PA_STREAM_PLAYBACK) - r = pa_stream_connect_playback(p->stream, dev, attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); - else - r = pa_stream_connect_record(p->stream, dev, attr, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE); - - if (r < 0) { - error = pa_context_errno(p->context); - goto unlock_and_fail; - } - - /* Wait until the stream is ready */ - pa_threaded_mainloop_wait(p->mainloop); - - /* Wait until the stream is ready */ - if (pa_stream_get_state(p->stream) != PA_STREAM_READY) { - error = pa_context_errno(p->context); - goto unlock_and_fail; - } - - pa_threaded_mainloop_unlock(p->mainloop); - - return p; - -unlock_and_fail: - pa_threaded_mainloop_unlock(p->mainloop); - -fail: - if (rerror) - *rerror = error; - pa_simple_free(p); - return NULL; -} - -void pa_simple_free(pa_simple *s) { - assert(s); - - if (s->mainloop) - pa_threaded_mainloop_stop(s->mainloop); - - if (s->stream) - pa_stream_unref(s->stream); - - if (s->context) - pa_context_unref(s->context); - - if (s->mainloop) - pa_threaded_mainloop_free(s->mainloop); - - pa_xfree(s); -} - -int pa_simple_write(pa_simple *p, const void*data, size_t length, int *rerror) { - assert(p); - - CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); - CHECK_VALIDITY_RETURN_ANY(rerror, data && length, PA_ERR_INVALID, -1); - - pa_threaded_mainloop_lock(p->mainloop); - - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - - while (length > 0) { - size_t l; - int r; - - while (!(l = pa_stream_writable_size(p->stream))) { - pa_threaded_mainloop_wait(p->mainloop); - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - } - - CHECK_SUCCESS_GOTO(p, rerror, l != (size_t) -1, unlock_and_fail); - - if (l > length) - l = length; - - r = pa_stream_write(p->stream, data, l, NULL, 0, PA_SEEK_RELATIVE); - CHECK_SUCCESS_GOTO(p, rerror, r >= 0, unlock_and_fail); - - data = (const uint8_t*) data + l; - length -= l; - } - - pa_threaded_mainloop_unlock(p->mainloop); - return 0; - -unlock_and_fail: - pa_threaded_mainloop_unlock(p->mainloop); - return -1; -} - -int pa_simple_read(pa_simple *p, void*data, size_t length, int *rerror) { - assert(p); - - CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, -1); - CHECK_VALIDITY_RETURN_ANY(rerror, data && length, PA_ERR_INVALID, -1); - - pa_threaded_mainloop_lock(p->mainloop); - - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - - while (length > 0) { - size_t l; - - while (!p->read_data) { - int r; - - r = pa_stream_peek(p->stream, &p->read_data, &p->read_length); - CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail); - - if (!p->read_data) { - pa_threaded_mainloop_wait(p->mainloop); - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - } else - p->read_index = 0; - } - - l = p->read_length < length ? p->read_length : length; - memcpy(data, (const uint8_t*) p->read_data+p->read_index, l); - - data = (uint8_t*) data + l; - length -= l; - - p->read_index += l; - p->read_length -= l; - - if (!p->read_length) { - int r; - - r = pa_stream_drop(p->stream); - p->read_data = NULL; - p->read_length = 0; - p->read_index = 0; - - CHECK_SUCCESS_GOTO(p, rerror, r == 0, unlock_and_fail); - } - } - - pa_threaded_mainloop_unlock(p->mainloop); - return 0; - -unlock_and_fail: - pa_threaded_mainloop_unlock(p->mainloop); - return -1; -} - -static void success_cb(pa_stream *s, int success, void *userdata) { - pa_simple *p = userdata; - - assert(s); - assert(p); - - p->operation_success = success; - pa_threaded_mainloop_signal(p->mainloop, 0); -} - -int pa_simple_drain(pa_simple *p, int *rerror) { - pa_operation *o = NULL; - - assert(p); - - CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); - - pa_threaded_mainloop_lock(p->mainloop); - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - - o = pa_stream_drain(p->stream, success_cb, p); - CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); - - p->operation_success = 0; - while (pa_operation_get_state(o) != PA_OPERATION_DONE) { - pa_threaded_mainloop_wait(p->mainloop); - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - } - CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail); - - pa_operation_unref(o); - pa_threaded_mainloop_unlock(p->mainloop); - - return 0; - -unlock_and_fail: - - if (o) { - pa_operation_cancel(o); - pa_operation_unref(o); - } - - pa_threaded_mainloop_unlock(p->mainloop); - return -1; -} - -int pa_simple_flush(pa_simple *p, int *rerror) { - pa_operation *o = NULL; - - assert(p); - - CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); - - pa_threaded_mainloop_lock(p->mainloop); - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - - o = pa_stream_flush(p->stream, success_cb, p); - CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); - - p->operation_success = 0; - while (pa_operation_get_state(o) != PA_OPERATION_DONE) { - pa_threaded_mainloop_wait(p->mainloop); - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - } - CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail); - - pa_operation_unref(o); - pa_threaded_mainloop_unlock(p->mainloop); - - return 0; - -unlock_and_fail: - - if (o) { - pa_operation_cancel(o); - pa_operation_unref(o); - } - - pa_threaded_mainloop_unlock(p->mainloop); - return -1; -} - -pa_usec_t pa_simple_get_latency(pa_simple *p, int *rerror) { - pa_usec_t t; - int negative; - - assert(p); - - pa_threaded_mainloop_lock(p->mainloop); - - for (;;) { - CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); - - if (pa_stream_get_latency(p->stream, &t, &negative) >= 0) - break; - - CHECK_SUCCESS_GOTO(p, rerror, pa_context_errno(p->context) == PA_ERR_NODATA, unlock_and_fail); - - /* Wait until latency data is available again */ - pa_threaded_mainloop_wait(p->mainloop); - } - - pa_threaded_mainloop_unlock(p->mainloop); - - return negative ? 0 : t; - -unlock_and_fail: - - pa_threaded_mainloop_unlock(p->mainloop); - return (pa_usec_t) -1; -} - diff --git a/src/polyp/simple.h b/src/polyp/simple.h deleted file mode 100644 index b97e844b..00000000 --- a/src/polyp/simple.h +++ /dev/null @@ -1,146 +0,0 @@ -#ifndef foosimplehfoo -#define foosimplehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <sys/types.h> - -#include <polyp/sample.h> -#include <polyp/channelmap.h> -#include <polyp/def.h> -#include <polyp/cdecl.h> - -/** \page simple Simple API - * - * \section overv_sec Overview - * - * The simple API is designed for applications with very basic sound - * playback or capture needs. It can only support a single stream per - * connection and has no handling of complex features like events, channel - * mappings and volume control. It is, however, very simple to use and - * quite sufficent for many programs. - * - * \section conn_sec Connecting - * - * The first step before using the sound system is to connect to the - * server. This is normally done this way: - * - * \code - * pa_simple *s; - * pa_sample_spec ss; - * - * ss.format = PA_SAMPLE_S16_NE; - * ss.channels = 2; - * ss.rate = 44100; - * - * s = pa_simple_new(NULL, // Use the default server. - * "Fooapp", // Our application's name. - * PA_STREAM_PLAYBACK, - * NULL, // Use the default device. - * "Music", // Description of our stream. - * &ss, // Our sample format. - * NULL, // Use default channel map - * NULL, // Use default buffering attributes. - * NULL, // Ignore error code. - * ); - * \endcode - * - * At this point a connected object is returned, or NULL if there was a - * problem connecting. - * - * \section transfer_sec Transferring data - * - * Once the connection is established to the server, data can start flowing. - * Using the connection is very similar to the normal read() and write() - * system calls. The main difference is that they're call pa_simple_read() - * and pa_simple_write(). Note that these operations always block. - * - * \section ctrl_sec Buffer control - * - * If a playback stream is used then a few other operations are available: - * - * \li pa_simple_drain() - Will wait for all sent data to finish playing. - * \li pa_simple_flush() - Will throw away all data currently in buffers. - * \li pa_simple_get_playback_latency() - Will return the total latency of - * the playback pipeline. - * - * \section cleanup_sec Cleanup - * - * Once playback or capture is complete, the connection should be closed - * and resources freed. This is done through: - * - * \code - * pa_simple_free(s); - * \endcode - */ - -/** \file - * A simple but limited synchronous playback and recording - * API. This is a synchronous, simplified wrapper around the standard - * asynchronous API. */ - -/** \example pacat-simple.c - * A simple playback tool using the simple API */ - -/** \example parec-simple.c - * A simple recording tool using the simple API */ - -PA_C_DECL_BEGIN - -/** \struct pa_simple - * An opaque simple connection object */ -typedef struct pa_simple pa_simple; - -/** Create a new connection to the server */ -pa_simple* pa_simple_new( - const char *server, /**< Server name, or NULL for default */ - const char *name, /**< A descriptive name for this client (application name, ...) */ - pa_stream_direction_t dir, /**< Open this stream for recording or playback? */ - const char *dev, /**< Sink (resp. source) name, or NULL for default */ - const char *stream_name, /**< A descriptive name for this client (application name, song title, ...) */ - const pa_sample_spec *ss, /**< The sample type to use */ - const pa_channel_map *map, /**< The channel map to use, or NULL for default */ - const pa_buffer_attr *attr, /**< Buffering attributes, or NULL for default */ - int *error /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */ - ); - -/** Close and free the connection to the server. The connection objects becomes invalid when this is called. */ -void pa_simple_free(pa_simple *s); - -/** Write some data to the server */ -int pa_simple_write(pa_simple *s, const void*data, size_t length, int *error); - -/** Wait until all data already written is played by the daemon */ -int pa_simple_drain(pa_simple *s, int *error); - -/** Read some data from the server */ -int pa_simple_read(pa_simple *s, void*data, size_t length, int *error); - -/** Return the playback latency. \since 0.5 */ -pa_usec_t pa_simple_get_latency(pa_simple *s, int *error); - -/** Flush the playback buffer. \since 0.5 */ -int pa_simple_flush(pa_simple *s, int *error); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/stream.c b/src/polyp/stream.c deleted file mode 100644 index 8927805e..00000000 --- a/src/polyp/stream.c +++ /dev/null @@ -1,1366 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <assert.h> -#include <string.h> -#include <stdio.h> -#include <string.h> - -#include <polyp/def.h> -#include <polyp/timeval.h> -#include <polyp/xmalloc.h> - -#include <polypcore/pstream-util.h> -#include <polypcore/log.h> -#include <polypcore/hashmap.h> - -#include "internal.h" - -#define LATENCY_IPOL_INTERVAL_USEC (100000L) - -pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map) { - pa_stream *s; - int i; - - assert(c); - - PA_CHECK_VALIDITY_RETURN_NULL(c, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID); - PA_CHECK_VALIDITY_RETURN_NULL(c, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID); - - s = pa_xnew(pa_stream, 1); - s->ref = 1; - s->context = c; - s->mainloop = c->mainloop; - - s->read_callback = NULL; - s->read_userdata = NULL; - s->write_callback = NULL; - s->write_userdata = NULL; - s->state_callback = NULL; - s->state_userdata = NULL; - s->overflow_callback = NULL; - s->overflow_userdata = NULL; - s->underflow_callback = NULL; - s->underflow_userdata = NULL; - s->latency_update_callback = NULL; - s->latency_update_userdata = NULL; - - s->direction = PA_STREAM_NODIRECTION; - s->name = pa_xstrdup(name); - s->sample_spec = *ss; - s->flags = 0; - - if (map) - s->channel_map = *map; - else - pa_channel_map_init_auto(&s->channel_map, ss->channels, PA_CHANNEL_MAP_DEFAULT); - - s->channel = 0; - s->channel_valid = 0; - s->syncid = c->csyncid++; - s->device_index = PA_INVALID_INDEX; - s->requested_bytes = 0; - s->state = PA_STREAM_UNCONNECTED; - memset(&s->buffer_attr, 0, sizeof(s->buffer_attr)); - - s->peek_memchunk.index = 0; - s->peek_memchunk.length = 0; - s->peek_memchunk.memblock = NULL; - - s->record_memblockq = NULL; - - s->previous_time = 0; - s->timing_info_valid = 0; - s->read_index_not_before = 0; - s->write_index_not_before = 0; - - for (i = 0; i < PA_MAX_WRITE_INDEX_CORRECTIONS; i++) - s->write_index_corrections[i].valid = 0; - s->current_write_index_correction = 0; - - s->corked = 0; - - s->cached_time_valid = 0; - - s->auto_timing_update_event = NULL; - s->auto_timing_update_requested = 0; - - /* Refcounting is strictly one-way: from the "bigger" to the "smaller" object. */ - PA_LLIST_PREPEND(pa_stream, c->streams, s); - pa_stream_ref(s); - - return s; -} - -static void stream_free(pa_stream *s) { - assert(s && !s->context && !s->channel_valid); - - if (s->auto_timing_update_event) { - assert(s->mainloop); - s->mainloop->time_free(s->auto_timing_update_event); - } - - if (s->peek_memchunk.memblock) - pa_memblock_unref(s->peek_memchunk.memblock); - - if (s->record_memblockq) - pa_memblockq_free(s->record_memblockq); - - pa_xfree(s->name); - pa_xfree(s); -} - -void pa_stream_unref(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - if (--(s->ref) == 0) - stream_free(s); -} - -pa_stream* pa_stream_ref(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - s->ref++; - return s; -} - -pa_stream_state_t pa_stream_get_state(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - return s->state; -} - -pa_context* pa_stream_get_context(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - return s->context; -} - -uint32_t pa_stream_get_index(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX); - - return s->device_index; -} - -void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) { - assert(s); - assert(s->ref >= 1); - - if (s->state == st) - return; - - pa_stream_ref(s); - - s->state = st; - if (s->state_callback) - s->state_callback(s, s->state_userdata); - - if ((st == PA_STREAM_FAILED || st == PA_STREAM_TERMINATED) && s->context) { - - /* Detach from context */ - pa_operation *o, *n; - - /* Unref all operatio object that point to us */ - for (o = s->context->operations; o; o = n) { - n = o->next; - - if (o->stream == s) - pa_operation_cancel(o); - } - - /* Drop all outstanding replies for this stream */ - if (s->context->pdispatch) - pa_pdispatch_unregister_reply(s->context->pdispatch, s); - - if (s->channel_valid) - pa_dynarray_put((s->direction == PA_STREAM_PLAYBACK) ? s->context->playback_streams : s->context->record_streams, s->channel, NULL); - - PA_LLIST_REMOVE(pa_stream, s->context->streams, s); - pa_stream_unref(s); - - s->channel = 0; - s->channel_valid = 0; - - s->context = NULL; - } - - pa_stream_unref(s); -} - -void pa_command_stream_killed(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_context *c = userdata; - pa_stream *s; - uint32_t channel; - - assert(pd); - assert(command == PA_COMMAND_PLAYBACK_STREAM_KILLED || command == PA_COMMAND_RECORD_STREAM_KILLED); - assert(t); - assert(c); - - pa_context_ref(c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(c, PA_ERR_PROTOCOL); - goto finish; - } - - if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_STREAM_KILLED ? c->playback_streams : c->record_streams, channel))) - goto finish; - - pa_context_set_error(c, PA_ERR_KILLED); - pa_stream_set_state(s, PA_STREAM_FAILED); - -finish: - pa_context_unref(c); -} - -void pa_command_request(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_stream *s; - pa_context *c = userdata; - uint32_t bytes, channel; - - assert(pd); - assert(command == PA_COMMAND_REQUEST); - assert(t); - assert(c); - - pa_context_ref(c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - pa_tagstruct_getu32(t, &bytes) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(c, PA_ERR_PROTOCOL); - goto finish; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - goto finish; - - if (s->state == PA_STREAM_READY) { - s->requested_bytes += bytes; - - if (s->requested_bytes > 0 && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); - } - -finish: - pa_context_unref(c); -} - -void pa_command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_stream *s; - pa_context *c = userdata; - uint32_t channel; - - assert(pd); - assert(command == PA_COMMAND_OVERFLOW || command == PA_COMMAND_UNDERFLOW); - assert(t); - assert(c); - - pa_context_ref(c); - - if (pa_tagstruct_getu32(t, &channel) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(c, PA_ERR_PROTOCOL); - goto finish; - } - - if (!(s = pa_dynarray_get(c->playback_streams, channel))) - goto finish; - - if (s->state == PA_STREAM_READY) { - - if (command == PA_COMMAND_OVERFLOW) { - if (s->overflow_callback) - s->overflow_callback(s, s->overflow_userdata); - } else if (command == PA_COMMAND_UNDERFLOW) { - if (s->underflow_callback) - s->underflow_callback(s, s->underflow_userdata); - } - } - - finish: - pa_context_unref(c); -} - -static void request_auto_timing_update(pa_stream *s, int force) { - struct timeval next; - assert(s); - - if (!(s->flags & PA_STREAM_AUTO_TIMING_UPDATE)) - return; - - if (s->state == PA_STREAM_READY && - (force || !s->auto_timing_update_requested)) { - pa_operation *o; - -/* pa_log("automatically requesting new timing data"); */ - - if ((o = pa_stream_update_timing_info(s, NULL, NULL))) { - pa_operation_unref(o); - s->auto_timing_update_requested = 1; - } - } - - pa_gettimeofday(&next); - pa_timeval_add(&next, LATENCY_IPOL_INTERVAL_USEC); - s->mainloop->time_restart(s->auto_timing_update_event, &next); -} - -static void invalidate_indexes(pa_stream *s, int r, int w) { - assert(s); - -/* pa_log("invalidate r:%u w:%u tag:%u", r, w, s->context->ctag); */ - - if (s->state != PA_STREAM_READY) - return; - - if (w) { - s->write_index_not_before = s->context->ctag; - - if (s->timing_info_valid) - s->timing_info.write_index_corrupt = 1; - -/* pa_log("write_index invalidated"); */ - } - - if (r) { - s->read_index_not_before = s->context->ctag; - - if (s->timing_info_valid) - s->timing_info.read_index_corrupt = 1; - -/* pa_log("read_index invalidated"); */ - } - - if ((s->direction == PA_STREAM_PLAYBACK && r) || - (s->direction == PA_STREAM_RECORD && w)) - s->cached_time_valid = 0; - - request_auto_timing_update(s, 1); -} - -static void auto_timing_update_callback(PA_GCC_UNUSED pa_mainloop_api *m, PA_GCC_UNUSED pa_time_event *e, PA_GCC_UNUSED const struct timeval *tv, void *userdata) { - pa_stream *s = userdata; - -/* pa_log("time event"); */ - - pa_stream_ref(s); - request_auto_timing_update(s, 0); - pa_stream_unref(s); -} - -void pa_create_stream_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_stream *s = userdata; - - assert(pd); - assert(s); - assert(s->state == PA_STREAM_CREATING); - - pa_stream_ref(s); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(s->context, command, t) < 0) - goto finish; - - pa_stream_set_state(s, PA_STREAM_FAILED); - goto finish; - } - - if (pa_tagstruct_getu32(t, &s->channel) < 0 || - ((s->direction != PA_STREAM_UPLOAD) && pa_tagstruct_getu32(t, &s->device_index) < 0) || - ((s->direction != PA_STREAM_RECORD) && pa_tagstruct_getu32(t, &s->requested_bytes) < 0)) { - pa_context_fail(s->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (pa_context_get_server_protocol_version(s->context) >= 9) { - if (s->direction == PA_STREAM_PLAYBACK) { - if (pa_tagstruct_getu32(t, &s->buffer_attr.maxlength) < 0 || - pa_tagstruct_getu32(t, &s->buffer_attr.tlength) < 0 || - pa_tagstruct_getu32(t, &s->buffer_attr.prebuf) < 0 || - pa_tagstruct_getu32(t, &s->buffer_attr.minreq) < 0) { - pa_context_fail(s->context, PA_ERR_PROTOCOL); - goto finish; - } - } else if (s->direction == PA_STREAM_RECORD) { - if (pa_tagstruct_getu32(t, &s->buffer_attr.maxlength) < 0 || - pa_tagstruct_getu32(t, &s->buffer_attr.fragsize) < 0) { - pa_context_fail(s->context, PA_ERR_PROTOCOL); - goto finish; - } - } - } - - if (!pa_tagstruct_eof(t)) { - pa_context_fail(s->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (s->direction == PA_STREAM_RECORD) { - assert(!s->record_memblockq); - - s->record_memblockq = pa_memblockq_new( - 0, - s->buffer_attr.maxlength, - 0, - pa_frame_size(&s->sample_spec), - 1, - 0, - NULL, - s->context->memblock_stat); - } - - s->channel_valid = 1; - pa_dynarray_put((s->direction == PA_STREAM_RECORD) ? s->context->record_streams : s->context->playback_streams, s->channel, s); - - pa_stream_set_state(s, PA_STREAM_READY); - - if (s->direction != PA_STREAM_UPLOAD && - s->flags & PA_STREAM_AUTO_TIMING_UPDATE) { - struct timeval tv; - - pa_gettimeofday(&tv); - tv.tv_usec += LATENCY_IPOL_INTERVAL_USEC; /* every 100 ms */ - - assert(!s->auto_timing_update_event); - s->auto_timing_update_event = s->mainloop->time_new(s->mainloop, &tv, &auto_timing_update_callback, s); - - request_auto_timing_update(s, 1); - } - - if (s->requested_bytes > 0 && s->ref > 1 && s->write_callback) - s->write_callback(s, s->requested_bytes, s->write_userdata); - -finish: - pa_stream_unref(s); -} - -static int create_stream( - pa_stream_direction_t direction, - pa_stream *s, - const char *dev, - const pa_buffer_attr *attr, - pa_stream_flags_t flags, - const pa_cvolume *volume, - pa_stream *sync_stream) { - - pa_tagstruct *t; - uint32_t tag; - - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_UNCONNECTED, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, !(flags & ~((direction != PA_STREAM_UPLOAD ? - PA_STREAM_START_CORKED| - PA_STREAM_INTERPOLATE_TIMING| - PA_STREAM_NOT_MONOTONOUS| - PA_STREAM_AUTO_TIMING_UPDATE : 0))), PA_ERR_INVALID); - PA_CHECK_VALIDITY(s->context, !volume || volume->channels == s->sample_spec.channels, PA_ERR_INVALID); - PA_CHECK_VALIDITY(s->context, !sync_stream || (direction == PA_STREAM_PLAYBACK && sync_stream->direction == PA_STREAM_PLAYBACK), PA_ERR_INVALID); - - pa_stream_ref(s); - - s->direction = direction; - s->flags = flags; - - if (sync_stream) - s->syncid = sync_stream->syncid; - - if (attr) - s->buffer_attr = *attr; - else { - /* half a second */ - s->buffer_attr.tlength = pa_bytes_per_second(&s->sample_spec)/2; - s->buffer_attr.maxlength = (s->buffer_attr.tlength*3)/2; - s->buffer_attr.minreq = s->buffer_attr.tlength/100; - s->buffer_attr.prebuf = s->buffer_attr.tlength - s->buffer_attr.minreq; - s->buffer_attr.fragsize = s->buffer_attr.tlength/100; - } - - if (!dev) - dev = s->direction == PA_STREAM_PLAYBACK ? s->context->conf->default_sink : s->context->conf->default_source; - - t = pa_tagstruct_command( - s->context, - s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CREATE_PLAYBACK_STREAM : PA_COMMAND_CREATE_RECORD_STREAM, - &tag); - - pa_tagstruct_put( - t, - PA_TAG_STRING, s->name, - PA_TAG_SAMPLE_SPEC, &s->sample_spec, - PA_TAG_CHANNEL_MAP, &s->channel_map, - PA_TAG_U32, PA_INVALID_INDEX, - PA_TAG_STRING, dev, - PA_TAG_U32, s->buffer_attr.maxlength, - PA_TAG_BOOLEAN, !!(flags & PA_STREAM_START_CORKED), - PA_TAG_INVALID); - - if (s->direction == PA_STREAM_PLAYBACK) { - pa_cvolume cv; - - pa_tagstruct_put( - t, - PA_TAG_U32, s->buffer_attr.tlength, - PA_TAG_U32, s->buffer_attr.prebuf, - PA_TAG_U32, s->buffer_attr.minreq, - PA_TAG_U32, s->syncid, - PA_TAG_INVALID); - - if (!volume) - volume = pa_cvolume_reset(&cv, s->sample_spec.channels); - - pa_tagstruct_put_cvolume(t, volume); - } else - pa_tagstruct_putu32(t, s->buffer_attr.fragsize); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL); - - pa_stream_set_state(s, PA_STREAM_CREATING); - - pa_stream_unref(s); - return 0; -} - -int pa_stream_connect_playback( - pa_stream *s, - const char *dev, - const pa_buffer_attr *attr, - pa_stream_flags_t flags, - pa_cvolume *volume, - pa_stream *sync_stream) { - - assert(s); - assert(s->ref >= 1); - - return create_stream(PA_STREAM_PLAYBACK, s, dev, attr, flags, volume, sync_stream); -} - -int pa_stream_connect_record( - pa_stream *s, - const char *dev, - const pa_buffer_attr *attr, - pa_stream_flags_t flags) { - - assert(s); - assert(s->ref >= 1); - - return create_stream(PA_STREAM_RECORD, s, dev, attr, flags, NULL, NULL); -} - -int pa_stream_write( - pa_stream *s, - const void *data, - size_t length, - void (*free_cb)(void *p), - int64_t offset, - pa_seek_mode_t seek) { - - pa_memchunk chunk; - - assert(s); - assert(s->ref >= 1); - assert(data); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || s->direction == PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, seek <= PA_SEEK_RELATIVE_END, PA_ERR_INVALID); - PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_PLAYBACK || (seek == PA_SEEK_RELATIVE && offset == 0), PA_ERR_INVALID); - - if (length <= 0) - return 0; - - if (free_cb) - chunk.memblock = pa_memblock_new_user((void*) data, length, free_cb, 1, s->context->memblock_stat); - else { - chunk.memblock = pa_memblock_new(length, s->context->memblock_stat); - memcpy(chunk.memblock->data, data, length); - } - - chunk.index = 0; - chunk.length = length; - - pa_pstream_send_memblock(s->context->pstream, s->channel, offset, seek, &chunk); - pa_memblock_unref(chunk.memblock); - - if (length < s->requested_bytes) - s->requested_bytes -= length; - else - s->requested_bytes = 0; - - if (s->direction == PA_STREAM_PLAYBACK) { - - /* Update latency request correction */ - if (s->write_index_corrections[s->current_write_index_correction].valid) { - - if (seek == PA_SEEK_ABSOLUTE) { - s->write_index_corrections[s->current_write_index_correction].corrupt = 0; - s->write_index_corrections[s->current_write_index_correction].absolute = 1; - s->write_index_corrections[s->current_write_index_correction].value = offset + length; - } else if (seek == PA_SEEK_RELATIVE) { - if (!s->write_index_corrections[s->current_write_index_correction].corrupt) - s->write_index_corrections[s->current_write_index_correction].value += offset + length; - } else - s->write_index_corrections[s->current_write_index_correction].corrupt = 1; - } - - /* Update the write index in the already available latency data */ - if (s->timing_info_valid) { - - if (seek == PA_SEEK_ABSOLUTE) { - s->timing_info.write_index_corrupt = 0; - s->timing_info.write_index = offset + length; - } else if (seek == PA_SEEK_RELATIVE) { - if (!s->timing_info.write_index_corrupt) - s->timing_info.write_index += offset + length; - } else - s->timing_info.write_index_corrupt = 1; - } - - if (!s->timing_info_valid || s->timing_info.write_index_corrupt) - request_auto_timing_update(s, 1); - } - - return 0; -} - -int pa_stream_peek(pa_stream *s, const void **data, size_t *length) { - assert(s); - assert(s->ref >= 1); - assert(data); - assert(length); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE); - - if (!s->peek_memchunk.memblock) { - - if (pa_memblockq_peek(s->record_memblockq, &s->peek_memchunk) < 0) { - *data = NULL; - *length = 0; - return 0; - } - } - - *data = (const char*) s->peek_memchunk.memblock->data + s->peek_memchunk.index; - *length = s->peek_memchunk.length; - return 0; -} - -int pa_stream_drop(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->peek_memchunk.memblock, PA_ERR_BADSTATE); - - pa_memblockq_drop(s->record_memblockq, &s->peek_memchunk, s->peek_memchunk.length); - - /* Fix the simulated local read index */ - if (s->timing_info_valid && !s->timing_info.read_index_corrupt) - s->timing_info.read_index += s->peek_memchunk.length; - - pa_memblock_unref(s->peek_memchunk.memblock); - s->peek_memchunk.length = 0; - s->peek_memchunk.index = 0; - s->peek_memchunk.memblock = NULL; - - return 0; -} - -size_t pa_stream_writable_size(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (size_t) -1); - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction != PA_STREAM_RECORD, PA_ERR_BADSTATE, (size_t) -1); - - return s->requested_bytes; -} - -size_t pa_stream_readable_size(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE, (size_t) -1); - PA_CHECK_VALIDITY_RETURN_ANY(s->context, s->direction == PA_STREAM_RECORD, PA_ERR_BADSTATE, (size_t) -1); - - return pa_memblockq_get_length(s->record_memblockq); -} - -pa_operation * pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); - - o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(s->context, PA_COMMAND_DRAIN_PLAYBACK_STREAM, &tag); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -static void stream_get_timing_info_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - struct timeval local, remote, now; - pa_timing_info *i; - - assert(pd); - assert(o); - - if (!o->context || !o->stream) - goto finish; - - i = &o->stream->timing_info; - -/* pa_log("pre corrupt w:%u r:%u\n", !o->stream->timing_info_valid || i->write_index_corrupt,!o->stream->timing_info_valid || i->read_index_corrupt); */ - - o->stream->timing_info_valid = 0; - i->write_index_corrupt = 0; - i->read_index_corrupt = 0; - -/* pa_log("timing update %u\n", tag); */ - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - } else if (pa_tagstruct_get_usec(t, &i->sink_usec) < 0 || - pa_tagstruct_get_usec(t, &i->source_usec) < 0 || - pa_tagstruct_get_boolean(t, &i->playing) < 0 || - pa_tagstruct_get_timeval(t, &local) < 0 || - pa_tagstruct_get_timeval(t, &remote) < 0 || - pa_tagstruct_gets64(t, &i->write_index) < 0 || - pa_tagstruct_gets64(t, &i->read_index) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - - } else { - o->stream->timing_info_valid = 1; - - pa_gettimeofday(&now); - - /* Calculcate timestamps */ - if (pa_timeval_cmp(&local, &remote) <= 0 && pa_timeval_cmp(&remote, &now) <= 0) { - /* local and remote seem to have synchronized clocks */ - - if (o->stream->direction == PA_STREAM_PLAYBACK) - i->transport_usec = pa_timeval_diff(&remote, &local); - else - i->transport_usec = pa_timeval_diff(&now, &remote); - - i->synchronized_clocks = 1; - i->timestamp = remote; - } else { - /* clocks are not synchronized, let's estimate latency then */ - i->transport_usec = pa_timeval_diff(&now, &local)/2; - i->synchronized_clocks = 0; - i->timestamp = local; - pa_timeval_add(&i->timestamp, i->transport_usec); - } - - /* Invalidate read and write indexes if necessary */ - if (tag < o->stream->read_index_not_before) - i->read_index_corrupt = 1; - - if (tag < o->stream->write_index_not_before) - i->write_index_corrupt = 1; - - if (o->stream->direction == PA_STREAM_PLAYBACK) { - /* Write index correction */ - - int n, j; - uint32_t ctag = tag; - - /* Go through the saved correction values and add up the total correction.*/ - - for (n = 0, j = o->stream->current_write_index_correction+1; - n < PA_MAX_WRITE_INDEX_CORRECTIONS; - n++, j = (j + 1) % PA_MAX_WRITE_INDEX_CORRECTIONS) { - - /* Step over invalid data or out-of-date data */ - if (!o->stream->write_index_corrections[j].valid || - o->stream->write_index_corrections[j].tag < ctag) - continue; - - /* Make sure that everything is in order */ - ctag = o->stream->write_index_corrections[j].tag+1; - - /* Now fix the write index */ - if (o->stream->write_index_corrections[j].corrupt) { - /* A corrupting seek was made */ - i->write_index = 0; - i->write_index_corrupt = 1; - } else if (o->stream->write_index_corrections[j].absolute) { - /* An absolute seek was made */ - i->write_index = o->stream->write_index_corrections[j].value; - i->write_index_corrupt = 0; - } else if (!i->write_index_corrupt) { - /* A relative seek was made */ - i->write_index += o->stream->write_index_corrections[j].value; - } - } - } - - if (o->stream->direction == PA_STREAM_RECORD) { - /* Read index correction */ - - if (!i->read_index_corrupt) - i->read_index -= pa_memblockq_get_length(o->stream->record_memblockq); - } - - o->stream->cached_time_valid = 0; - } - - o->stream->auto_timing_update_requested = 0; -/* pa_log("post corrupt w:%u r:%u\n", i->write_index_corrupt || !o->stream->timing_info_valid, i->read_index_corrupt || !o->stream->timing_info_valid); */ - - /* Clear old correction entries */ - if (o->stream->direction == PA_STREAM_PLAYBACK) { - int n; - - for (n = 0; n < PA_MAX_WRITE_INDEX_CORRECTIONS; n++) { - if (!o->stream->write_index_corrections[n].valid) - continue; - - if (o->stream->write_index_corrections[n].tag <= tag) - o->stream->write_index_corrections[n].valid = 0; - } - } - - if (o->stream->latency_update_callback) - o->stream->latency_update_callback(o->stream, o->stream->latency_update_userdata); - - if (o->callback && o->stream && o->stream->state == PA_STREAM_READY) { - pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback; - cb(o->stream, o->stream->timing_info_valid, o->userdata); - } - -finish: - - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_stream_update_timing_info(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { - uint32_t tag; - pa_operation *o; - pa_tagstruct *t; - struct timeval now; - int cidx = 0; - - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - if (s->direction == PA_STREAM_PLAYBACK) { - /* Find a place to store the write_index correction data for this entry */ - cidx = (s->current_write_index_correction + 1) % PA_MAX_WRITE_INDEX_CORRECTIONS; - - /* Check if we could allocate a correction slot. If not, there are too many outstanding queries */ - PA_CHECK_VALIDITY_RETURN_NULL(s->context, !s->write_index_corrections[cidx].valid, PA_ERR_INTERNAL); - } - o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command( - s->context, - s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_GET_PLAYBACK_LATENCY : PA_COMMAND_GET_RECORD_LATENCY, - &tag); - pa_tagstruct_putu32(t, s->channel); - pa_tagstruct_put_timeval(t, pa_gettimeofday(&now)); - - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, stream_get_timing_info_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - if (s->direction == PA_STREAM_PLAYBACK) { - /* Fill in initial correction data */ - o->stream->current_write_index_correction = cidx; - o->stream->write_index_corrections[cidx].valid = 1; - o->stream->write_index_corrections[cidx].tag = tag; - o->stream->write_index_corrections[cidx].absolute = 0; - o->stream->write_index_corrections[cidx].value = 0; - o->stream->write_index_corrections[cidx].corrupt = 0; - } - -/* pa_log("requesting update %u\n", tag); */ - - return o; -} - -void pa_stream_disconnect_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_stream *s = userdata; - - assert(pd); - assert(s); - assert(s->ref >= 1); - - pa_stream_ref(s); - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(s->context, command, t) < 0) - goto finish; - - pa_stream_set_state(s, PA_STREAM_FAILED); - goto finish; - } else if (!pa_tagstruct_eof(t)) { - pa_context_fail(s->context, PA_ERR_PROTOCOL); - goto finish; - } - - pa_stream_set_state(s, PA_STREAM_TERMINATED); - -finish: - pa_stream_unref(s); -} - -int pa_stream_disconnect(pa_stream *s) { - pa_tagstruct *t; - uint32_t tag; - - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY(s->context, s->channel_valid, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->context->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - pa_stream_ref(s); - - t = pa_tagstruct_command( - s->context, - s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_DELETE_PLAYBACK_STREAM : - (s->direction == PA_STREAM_RECORD ? PA_COMMAND_DELETE_RECORD_STREAM : PA_COMMAND_DELETE_UPLOAD_STREAM), - &tag); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_disconnect_callback, s, NULL); - - pa_stream_unref(s); - return 0; -} - -void pa_stream_set_read_callback(pa_stream *s, pa_stream_request_cb_t cb, void *userdata) { - assert(s); - assert(s->ref >= 1); - - s->read_callback = cb; - s->read_userdata = userdata; -} - -void pa_stream_set_write_callback(pa_stream *s, pa_stream_request_cb_t cb, void *userdata) { - assert(s); - assert(s->ref >= 1); - - s->write_callback = cb; - s->write_userdata = userdata; -} - -void pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { - assert(s); - assert(s->ref >= 1); - - s->state_callback = cb; - s->state_userdata = userdata; -} - -void pa_stream_set_overflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { - assert(s); - assert(s->ref >= 1); - - s->overflow_callback = cb; - s->overflow_userdata = userdata; -} - -void pa_stream_set_underflow_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { - assert(s); - assert(s->ref >= 1); - - s->underflow_callback = cb; - s->underflow_userdata = userdata; -} - -void pa_stream_set_latency_update_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) { - assert(s); - assert(s->ref >= 1); - - s->latency_update_callback = cb; - s->latency_update_userdata = userdata; -} - -void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_operation *o = userdata; - int success = 1; - - assert(pd); - assert(o); - assert(o->ref >= 1); - - if (!o->context) - goto finish; - - if (command != PA_COMMAND_REPLY) { - if (pa_context_handle_error(o->context, command, t) < 0) - goto finish; - - success = 0; - } else if (!pa_tagstruct_eof(t)) { - pa_context_fail(o->context, PA_ERR_PROTOCOL); - goto finish; - } - - if (o->callback) { - pa_stream_success_cb_t cb = (pa_stream_success_cb_t) o->callback; - cb(o->stream, success, o->userdata); - } - -finish: - pa_operation_done(o); - pa_operation_unref(o); -} - -pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - s->corked = b; - - o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command( - s->context, - s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_CORK_PLAYBACK_STREAM : PA_COMMAND_CORK_RECORD_STREAM, - &tag); - pa_tagstruct_putu32(t, s->channel); - pa_tagstruct_put_boolean(t, !!b); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - if (s->direction == PA_STREAM_PLAYBACK) - invalidate_indexes(s, 1, 0); - - return o; -} - -static pa_operation* stream_send_simple_command(pa_stream *s, uint32_t command, pa_stream_success_cb_t cb, void *userdata) { - pa_tagstruct *t; - pa_operation *o; - uint32_t tag; - - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(s->context, command, &tag); - pa_tagstruct_putu32(t, s->channel); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { - pa_operation *o; - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - if ((o = stream_send_simple_command(s, s->direction == PA_STREAM_PLAYBACK ? PA_COMMAND_FLUSH_PLAYBACK_STREAM : PA_COMMAND_FLUSH_RECORD_STREAM, cb, userdata))) { - - if (s->direction == PA_STREAM_PLAYBACK) { - if (s->write_index_corrections[s->current_write_index_correction].valid) - s->write_index_corrections[s->current_write_index_correction].corrupt = 1; - - if (s->timing_info_valid) - s->timing_info.write_index_corrupt = 1; - - if (s->buffer_attr.prebuf > 0) - invalidate_indexes(s, 1, 0); - else - request_auto_timing_update(s, 1); - } else - invalidate_indexes(s, 0, 1); - } - - return o; -} - -pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { - pa_operation *o; - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE); - - if ((o = stream_send_simple_command(s, PA_COMMAND_PREBUF_PLAYBACK_STREAM, cb, userdata))) - invalidate_indexes(s, 1, 0); - - return o; -} - -pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata) { - pa_operation *o; - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->buffer_attr.prebuf > 0, PA_ERR_BADSTATE); - - if ((o = stream_send_simple_command(s, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, cb, userdata))) - invalidate_indexes(s, 1, 0); - - return o; -} - -pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(s); - assert(s->ref >= 1); - assert(name); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - - o = pa_operation_new(s->context, s, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command( - s->context, - s->direction == PA_STREAM_RECORD ? PA_COMMAND_SET_RECORD_STREAM_NAME : PA_COMMAND_SET_PLAYBACK_STREAM_NAME, - &tag); - pa_tagstruct_putu32(t, s->channel); - pa_tagstruct_puts(t, name); - pa_pstream_send_tagstruct(s->context->pstream, t); - pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_stream_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec) { - pa_usec_t usec = 0; - - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->timing_info_valid, PA_ERR_NODATA); - PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_PLAYBACK || !s->timing_info.read_index_corrupt, PA_ERR_NODATA); - PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_RECORD || !s->timing_info.write_index_corrupt, PA_ERR_NODATA); - - if (s->cached_time_valid) - /* We alredy calculated the time value for this timing info, so let's reuse it */ - usec = s->cached_time; - else { - if (s->direction == PA_STREAM_PLAYBACK) { - /* The last byte that was written into the output device - * had this time value associated */ - usec = pa_bytes_to_usec(s->timing_info.read_index < 0 ? 0 : (uint64_t) s->timing_info.read_index, &s->sample_spec); - - if (!s->corked) { - /* Because the latency info took a little time to come - * to us, we assume that the real output time is actually - * a little ahead */ - usec += s->timing_info.transport_usec; - - /* However, the output device usually maintains a buffer - too, hence the real sample currently played is a little - back */ - if (s->timing_info.sink_usec >= usec) - usec = 0; - else - usec -= s->timing_info.sink_usec; - } - - } else if (s->direction == PA_STREAM_RECORD) { - /* The last byte written into the server side queue had - * this time value associated */ - usec = pa_bytes_to_usec(s->timing_info.write_index < 0 ? 0 : (uint64_t) s->timing_info.write_index, &s->sample_spec); - - if (!s->corked) { - /* Add transport latency */ - usec += s->timing_info.transport_usec; - - /* Add latency of data in device buffer */ - usec += s->timing_info.source_usec; - - /* If this is a monitor source, we need to correct the - * time by the playback device buffer */ - if (s->timing_info.sink_usec >= usec) - usec = 0; - else - usec -= s->timing_info.sink_usec; - } - } - - s->cached_time = usec; - s->cached_time_valid = 1; - } - - /* Interpolate if requested */ - if (s->flags & PA_STREAM_INTERPOLATE_TIMING) { - - /* We just add the time that passed since the latency info was - * current */ - if (!s->corked) { - struct timeval now; - usec += pa_timeval_diff(pa_gettimeofday(&now), &s->timing_info.timestamp); - } - } - - /* Make sure the time runs monotonically */ - if (!(s->flags & PA_STREAM_NOT_MONOTONOUS)) { - if (usec < s->previous_time) - usec = s->previous_time; - else - s->previous_time = usec; - } - - if (r_usec) - *r_usec = usec; - - return 0; -} - -static pa_usec_t time_counter_diff(pa_stream *s, pa_usec_t a, pa_usec_t b, int *negative) { - assert(s); - assert(s->ref >= 1); - - if (negative) - *negative = 0; - - if (a >= b) - return a-b; - else { - if (negative && s->direction == PA_STREAM_RECORD) { - *negative = 1; - return b-a; - } else - return 0; - } -} - -int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative) { - pa_usec_t t, c; - int r; - int64_t cindex; - - assert(s); - assert(s->ref >= 1); - assert(r_usec); - - PA_CHECK_VALIDITY(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY(s->context, s->timing_info_valid, PA_ERR_NODATA); - PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_PLAYBACK || !s->timing_info.write_index_corrupt, PA_ERR_NODATA); - PA_CHECK_VALIDITY(s->context, s->direction != PA_STREAM_RECORD || !s->timing_info.read_index_corrupt, PA_ERR_NODATA); - - if ((r = pa_stream_get_time(s, &t)) < 0) - return r; - - if (s->direction == PA_STREAM_PLAYBACK) - cindex = s->timing_info.write_index; - else - cindex = s->timing_info.read_index; - - if (cindex < 0) - cindex = 0; - - c = pa_bytes_to_usec(cindex, &s->sample_spec); - - if (s->direction == PA_STREAM_PLAYBACK) - *r_usec = time_counter_diff(s, c, t, negative); - else - *r_usec = time_counter_diff(s, t, c, negative); - - return 0; -} - -const pa_timing_info* pa_stream_get_timing_info(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->timing_info_valid, PA_ERR_BADSTATE); - - return &s->timing_info; -} - -const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - return &s->sample_spec; -} - -const pa_channel_map* pa_stream_get_channel_map(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - return &s->channel_map; -} - -const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s) { - assert(s); - assert(s->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->state == PA_STREAM_READY, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, s->direction != PA_STREAM_UPLOAD, PA_ERR_BADSTATE); - PA_CHECK_VALIDITY_RETURN_NULL(s->context, - pa_context_get_server_protocol_version(s->context) >= 9, PA_ERR_NODATA); - - return &s->buffer_attr; -} diff --git a/src/polyp/stream.h b/src/polyp/stream.h deleted file mode 100644 index d1f558ae..00000000 --- a/src/polyp/stream.h +++ /dev/null @@ -1,449 +0,0 @@ -#ifndef foostreamhfoo -#define foostreamhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <sys/types.h> - -#include <polyp/sample.h> -#include <polyp/channelmap.h> -#include <polyp/volume.h> -#include <polyp/def.h> -#include <polyp/cdecl.h> -#include <polyp/operation.h> - -/** \page streams Audio Streams - * - * \section overv_sec Overview - * - * Audio streams form the central functionality of the sound server. Data is - * routed, converted and mixed from several sources before it is passed along - * to a final output. Currently, there are three forms of audio streams: - * - * \li Playback streams - Data flows from the client to the server. - * \li Record streams - Data flows from the server to the client. - * \li Upload streams - Similar to playback streams, but the data is stored in - * the sample cache. See \ref scache for more information - * about controlling the sample cache. - * - * \section create_sec Creating - * - * To access a stream, a pa_stream object must be created using - * pa_stream_new(). At this point the audio sample format and mapping of - * channels must be specified. See \ref sample and \ref channelmap for more - * information about those structures. - * - * This first step will only create a client-side object, representing the - * stream. To use the stream, a server-side object must be created and - * associated with the local object. Depending on which type of stream is - * desired, a different function is needed: - * - * \li Playback stream - pa_stream_connect_playback() - * \li Record stream - pa_stream_connect_record() - * \li Upload stream - pa_stream_connect_upload() (see \ref scache) - * - * Similar to how connections are done in contexts, connecting a stream will - * not generate a pa_operation object. Also like contexts, the application - * should register a state change callback, using - * pa_stream_set_state_callback(), and wait for the stream to enter an active - * state. - * - * \subsection bufattr_subsec Buffer Attributes - * - * Playback and record streams always have a server side buffer as - * part of the data flow. The size of this buffer strikes a - * compromise between low latency and sensitivity for buffer - * overflows/underruns. - * - * The buffer metrics may be controlled by the application. They are - * described with a pa_buffer_attr structure which contains a number - * of fields: - * - * \li maxlength - The absolute maximum number of bytes that can be stored in - * the buffer. If this value is exceeded then data will be - * lost. - * \li tlength - The target length of a playback buffer. The server will only - * send requests for more data as long as the buffer has less - * than this number of bytes of data. - * \li prebuf - Number of bytes that need to be in the buffer before - * playback will commence. Start of playback can be forced using - * pa_stream_trigger() even though the prebuffer size hasn't been - * reached. If a buffer underrun occurs, this prebuffering will be - * again enabled. If the playback shall never stop in case of a buffer - * underrun, this value should be set to 0. In that case the read - * index of the output buffer overtakes the write index, and hence the - * fill level of the buffer is negative. - * \li minreq - Minimum free number of the bytes in the playback buffer before - * the server will request more data. - * \li fragsize - Maximum number of bytes that the server will push in one - * chunk for record streams. - * - * The server side playback buffers are indexed by a write and a read - * index. The application writes to the write index and the sound - * device reads from the read index. The read index is increased - * monotonically, while the write index may be freely controlled by - * the application. Substracting the read index from the write index - * will give you the current fill level of the buffer. The read/write - * indexes are 64bit values and measured in bytes, they will never - * wrap. The current read/write index may be queried using - * pa_stream_get_timing_info() (see below for more information). In - * case of a buffer underrun the read index is equal or larger than - * the write index. Unless the prebuf value is 0, Polypaudio will - * temporarily pause playback in such a case, and wait until the - * buffer is filled up to prebuf bytes again. If prebuf is 0, the - * read index may be larger than the write index, in which case - * silence is played. If the application writes data to indexes lower - * than the read index, the data is immediately lost. - * - * \section transfer_sec Transferring Data - * - * Once the stream is up, data can start flowing between the client and the - * server. Two different access models can be used to transfer the data: - * - * \li Asynchronous - The application register a callback using - * pa_stream_set_write_callback() and - * pa_stream_set_read_callback() to receive notifications - * that data can either be written or read. - * \li Polled - Query the library for available data/space using - * pa_stream_writable_size() and pa_stream_readable_size() and - * transfer data as needed. The sizes are stored locally, in the - * client end, so there is no delay when reading them. - * - * It is also possible to mix the two models freely. - * - * Once there is data/space available, it can be transferred using either - * pa_stream_write() for playback, or pa_stream_peek() / pa_stream_drop() for - * record. Make sure you do not overflow the playback buffers as data will be - * dropped. - * - * \section bufctl_sec Buffer Control - * - * The transfer buffers can be controlled through a number of operations: - * - * \li pa_stream_cork() - Start or stop the playback or recording. - * \li pa_stream_trigger() - Start playback immediatly and do not wait for - * the buffer to fill up to the set trigger level. - * \li pa_stream_prebuf() - Reenable the playback trigger level. - * \li pa_stream_drain() - Wait for the playback buffer to go empty. Will - * return a pa_operation object that will indicate when - * the buffer is completely drained. - * \li pa_stream_flush() - Drop all data from the playback buffer and do not - * wait for it to finish playing. - * - * \section seek_modes Seeking in the Playback Buffer - * - * A client application may freely seek in the playback buffer. To - * accomplish that the pa_stream_write() function takes a seek mode - * and an offset argument. The seek mode is one of: - * - * \li PA_SEEK_RELATIVE - seek relative to the current write index - * \li PA_SEEK_ABSOLUTE - seek relative to the beginning of the playback buffer, (i.e. the first that was ever played in the stream) - * \li PA_SEEK_RELATIVE_ON_READ - seek relative to the current read index. Use this to write data to the output buffer that should be played as soon as possible - * \li PA_SEEK_RELATIVE_END - seek relative to the last byte ever written. - * - * If an application just wants to append some data to the output - * buffer, PA_SEEK_RELATIVE and an offset of 0 should be used. - * - * After a call to pa_stream_write() the write index will be left at - * the position right after the last byte of the written data. - * - * \section latency_sec Latency - * - * A major problem with networked audio is the increased latency caused by - * the network. To remedy this, Polypaudio supports an advanced system of - * monitoring the current latency. - * - * To get the raw data needed to calculate latencies, call - * pa_stream_get_timing_info(). This will give you a pa_timing_info - * structure that contains everything that is known about the server - * side buffer transport delays and the backend active in the - * server. (Besides other things it contains the write and read index - * values mentioned above.) - * - * This structure is updated every time a - * pa_stream_update_timing_info() operation is executed. (i.e. before - * the first call to this function the timing information structure is - * not available!) Since it is a lot of work to keep this structure - * up-to-date manually, Polypaudio can do that automatically for you: - * if PA_STREAM_AUTO_TIMING_UPDATE is passed when connecting the - * stream Polypaudio will automatically update the structure every - * 100ms and every time a function is called that might invalidate the - * previously known timing data (such as pa_stream_write() or - * pa_stream_flush()). Please note however, that there always is a - * short time window when the data in the timing information structure - * is out-of-date. Polypaudio tries to mark these situations by - * setting the write_index_corrupt and read_index_corrupt fields - * accordingly. - * - * The raw timing data in the pa_timing_info structure is usually hard - * to deal with. Therefore a more simplistic interface is available: - * you can call pa_stream_get_time() or pa_stream_get_latency(). The - * former will return the current playback time of the hardware since - * the stream has been started. The latter returns the time a sample - * that you write now takes to be played by the hardware. These two - * functions base their calculations on the same data that is returned - * by pa_stream_get_timing_info(). Hence the same rules for keeping - * the timing data up-to-date apply here. In case the write or read - * index is corrupted, these two functions will fail with - * PA_ERR_NODATA set. - * - * Since updating the timing info structure usually requires a full - * network round trip and some applications monitor the timing very - * often Polypaudio offers a timing interpolation system. If - * PA_STREAM_INTERPOLATE_TIMING is passed when connecting the stream, - * pa_stream_get_time() and pa_stream_get_latency() will try to - * interpolate the current playback time/latency by estimating the - * number of samples that have been played back by the hardware since - * the last regular timing update. It is espcially useful to combine - * this option with PA_STREAM_AUTO_TIMING_UPDATE, which will enable - * you to monitor the current playback time/latency very precisely and - * very frequently without requiring a network round trip every time. - * - * \section flow_sec Overflow and underflow - * - * Even with the best precautions, buffers will sometime over - or - * underflow. To handle this gracefully, the application can be - * notified when this happens. Callbacks are registered using - * pa_stream_set_overflow_callback() and - * pa_stream_set_underflow_callback(). - * - * \section sync_streams Sychronizing Multiple Playback Streams - * - * Polypaudio allows applications to fully synchronize multiple - * playback streams that are connected to the same output device. That - * means the streams will always be played back sample-by-sample - * synchronously. If stream operations like pa_stream_cork() are - * issued on one of the synchronized streams, they are simultaneously - * issued on the others. - * - * To synchronize a stream to another, just pass the "master" stream - * as last argument to pa_stream_connect_playack(). To make sure that - * the freshly created stream doesn't start playback right-away, make - * sure to pass PA_STREAM_START_CORKED and - after all streams have - * been created - uncork them all with a single call to - * pa_stream_cork() for the master stream. - * - * To make sure that a particular stream doesn't stop to play when a - * server side buffer underrun happens on it while the other - * synchronized streams continue playing and hence deviate you need to - * pass a "prebuf" pa_buffer_attr of 0 when connecting it. - * - * \section disc_sec Disconnecting - * - * When a stream has served is purpose it must be disconnected with - * pa_stream_disconnect(). If you only unreference it, then it will live on - * and eat resources both locally and on the server until you disconnect the - * context. - * - */ - -/** \file - * Audio streams for input, output and sample upload */ - -PA_C_DECL_BEGIN - -/** An opaque stream for playback or recording */ -typedef struct pa_stream pa_stream; - -/** A generic callback for operation completion */ -typedef void (*pa_stream_success_cb_t) (pa_stream*s, int success, void *userdata); - -/** A generic request callback */ -typedef void (*pa_stream_request_cb_t)(pa_stream *p, size_t length, void *userdata); - -/** A generic notification callback */ -typedef void (*pa_stream_notify_cb_t)(pa_stream *p, void *userdata); - -/** Create a new, unconnected stream with the specified name and sample type */ -pa_stream* pa_stream_new( - pa_context *c /**< The context to create this stream in */, - const char *name /**< A name for this stream */, - const pa_sample_spec *ss /**< The desired sample format */, - const pa_channel_map *map /**< The desired channel map, or NULL for default */); - -/** Decrease the reference counter by one */ -void pa_stream_unref(pa_stream *s); - -/** Increase the reference counter by one */ -pa_stream *pa_stream_ref(pa_stream *s); - -/** Return the current state of the stream */ -pa_stream_state_t pa_stream_get_state(pa_stream *p); - -/** Return the context this stream is attached to */ -pa_context* pa_stream_get_context(pa_stream *p); - -/** Return the device (sink input or source output) index this stream is connected to */ -uint32_t pa_stream_get_index(pa_stream *s); - -/** Connect the stream to a sink */ -int pa_stream_connect_playback( - pa_stream *s /**< The stream to connect to a sink */, - const char *dev /**< Name of the sink to connect to, or NULL for default */ , - const pa_buffer_attr *attr /**< Buffering attributes, or NULL for default */, - pa_stream_flags_t flags /**< Additional flags, or 0 for default */, - pa_cvolume *volume /**< Initial volume, or NULL for default */, - pa_stream *sync_stream /**< Synchronize this stream with the specified one, or NULL for a standalone stream*/); - -/** Connect the stream to a source */ -int pa_stream_connect_record( - pa_stream *s /**< The stream to connect to a source */ , - const char *dev /**< Name of the source to connect to, or NULL for default */, - const pa_buffer_attr *attr /**< Buffer attributes, or NULL for default */, - pa_stream_flags_t flags /**< Additional flags, or 0 for default */); - -/** Disconnect a stream from a source/sink */ -int pa_stream_disconnect(pa_stream *s); - -/** Write some data to the server (for playback sinks), if free_cb is - * non-NULL this routine is called when all data has been written out - * and an internal reference to the specified data is kept, the data - * is not copied. If NULL, the data is copied into an internal - * buffer. The client my freely seek around in the output buffer. For - * most applications passing 0 and PA_SEEK_RELATIVE as arguments for - * offset and seek should be useful.*/ -int pa_stream_write( - pa_stream *p /**< The stream to use */, - const void *data /**< The data to write */, - size_t length /**< The length of the data to write */, - pa_free_cb_t free_cb /**< A cleanup routine for the data or NULL to request an internal copy */, - int64_t offset, /**< Offset for seeking, must be 0 for upload streams */ - pa_seek_mode_t seek /**< Seek mode, must be PA_SEEK_RELATIVE for upload streams */); - -/** Read the next fragment from the buffer (for recording). - * data will point to the actual data and length will contain the size - * of the data in bytes (which can be less than a complete framgnet). - * Use pa_stream_drop() to actually remove the data from the - * buffer. If no data is available will return a NULL pointer \since 0.8 */ -int pa_stream_peek( - pa_stream *p /**< The stream to use */, - const void **data /**< Pointer to pointer that will point to data */, - size_t *length /**< The length of the data read */); - -/** Remove the current fragment on record streams. It is invalid to do this without first - * calling pa_stream_peek(). \since 0.8 */ -int pa_stream_drop(pa_stream *p); - -/** Return the nember of bytes that may be written using pa_stream_write() */ -size_t pa_stream_writable_size(pa_stream *p); - -/** Return the number of bytes that may be read using pa_stream_read() \since 0.8 */ -size_t pa_stream_readable_size(pa_stream *p); - -/** Drain a playback stream. Use this for notification when the buffer is empty */ -pa_operation* pa_stream_drain(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); - -/** Request a timing info structure update for a stream. Use - * pa_stream_get_timing_info() to get access to the raw timing data, - * or pa_stream_get_time() or pa_stream_get_latency() to get cleaned - * up values. */ -pa_operation* pa_stream_update_timing_info(pa_stream *p, pa_stream_success_cb_t cb, void *userdata); - -/** Set the callback function that is called whenever the state of the stream changes */ -void pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata); - -/** Set the callback function that is called when new data may be - * written to the stream. */ -void pa_stream_set_write_callback(pa_stream *p, pa_stream_request_cb_t cb, void *userdata); - -/** Set the callback function that is called when new data is available from the stream. - * Return the number of bytes read. \since 0.8 */ -void pa_stream_set_read_callback(pa_stream *p, pa_stream_request_cb_t cb, void *userdata); - -/** Set the callback function that is called when a buffer overflow happens. (Only for playback streams) \since 0.8 */ -void pa_stream_set_overflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); - -/** Set the callback function that is called when a buffer underflow happens. (Only for playback streams) \since 0.8 */ -void pa_stream_set_underflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); - -/** Set the callback function that is called whenever a latency information update happens. Useful on PA_STREAM_AUTO_TIMING_UPDATE streams only. (Only for playback streams) \since 0.8.2 */ -void pa_stream_set_latency_update_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata); - -/** Pause (or resume) playback of this stream temporarily. Available on both playback and recording streams. \since 0.3 */ -pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata); - -/** Flush the playback buffer of this stream. Most of the time you're - * better off using the parameter delta of pa_stream_write() instead of this - * function. Available on both playback and recording streams. \since 0.3 */ -pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); - -/** Reenable prebuffering as specified in the pa_buffer_attr - * structure. Available for playback streams only. \since 0.6 */ -pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); - -/** Request immediate start of playback on this stream. This disables - * prebuffering as specified in the pa_buffer_attr - * structure, temporarily. Available for playback streams only. \since 0.3 */ -pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata); - -/** Rename the stream. \since 0.5 */ -pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_success_cb_t cb, void *userdata); - -/** Return the current playback/recording time. This is based on the - * data in the timing info structure returned by - * pa_stream_get_timing_info(). This function will usually only return - * new data if a timing info update has been recieved. Only if timing - * interpolation has been requested (PA_STREAM_INTERPOLATE_TIMING) - * the data from the last timing update is used for an estimation of - * the current playback/recording time based on the local time that - * passed since the timing info structure has been acquired. The time - * value returned by this function is guaranteed to increase - * monotonically. (that means: the returned value is always greater or - * equal to the value returned on the last call) This behaviour can - * be disabled by using PA_STREAM_NOT_MONOTONOUS. This may be - * desirable to deal better with bad estimations of transport - * latencies, but may have strange effects if the application is not - * able to deal with time going 'backwards'. \since 0.6 */ -int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec); - -/** Return the total stream latency. This function is based on - * pa_stream_get_time(). In case the stream is a monitoring stream the - * result can be negative, i.e. the captured samples are not yet - * played. In this case *negative is set to 1. \since 0.6 */ -int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative); - -/** Return the latest raw timing data structure. The returned pointer - * points to an internal read-only instance of the timing - * structure. The user should make a copy of this structure if he - * wants to modify it. An in-place update to this data structure may - * be requested using pa_stream_update_timing_info(). If no - * pa_stream_update_timing_info() call was issued before, this - * function will fail with PA_ERR_NODATA. Please note that the - * write_index member field (and only this field) is updated on each - * pa_stream_write() call, not just when a timing update has been - * recieved. \since 0.8 */ -const pa_timing_info* pa_stream_get_timing_info(pa_stream *s); - -/** Return a pointer to the stream's sample specification. \since 0.6 */ -const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s); - -/** Return a pointer to the stream's channel map. \since 0.8 */ -const pa_channel_map* pa_stream_get_channel_map(pa_stream *s); - -/** Return the buffer metrics of the stream. Only valid after the - * stream has been connected successfuly and if the server is at least - * Polypaudio 0.9. \since 0.9.0 */ -const pa_buffer_attr* pa_stream_get_buffer_attr(pa_stream *s); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/subscribe.c b/src/polyp/subscribe.c deleted file mode 100644 index 21f5f7a5..00000000 --- a/src/polyp/subscribe.c +++ /dev/null @@ -1,89 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <assert.h> -#include <stdio.h> - -#include <polypcore/gccmacro.h> -#include <polypcore/pstream-util.h> - -#include "internal.h" - -#include "subscribe.h" - -void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, PA_GCC_UNUSED uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_context *c = userdata; - pa_subscription_event_type_t e; - uint32_t idx; - - assert(pd); - assert(command == PA_COMMAND_SUBSCRIBE_EVENT); - assert(t); - assert(c); - - pa_context_ref(c); - - if (pa_tagstruct_getu32(t, &e) < 0 || - pa_tagstruct_getu32(t, &idx) < 0 || - !pa_tagstruct_eof(t)) { - pa_context_fail(c, PA_ERR_PROTOCOL); - goto finish; - } - - if (c->subscribe_callback) - c->subscribe_callback(c, e, idx, c->subscribe_userdata); - -finish: - pa_context_unref(c); -} - - -pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, pa_context_success_cb_t cb, void *userdata) { - pa_operation *o; - pa_tagstruct *t; - uint32_t tag; - - assert(c); - assert(c->ref >= 1); - - PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE); - - o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata); - - t = pa_tagstruct_command(c, PA_COMMAND_SUBSCRIBE, &tag); - pa_tagstruct_putu32(t, m); - pa_pstream_send_tagstruct(c->pstream, t); - pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref); - - return o; -} - -void pa_context_set_subscribe_callback(pa_context *c, pa_context_subscribe_cb_t cb, void *userdata) { - assert(c); - assert(c->ref >= 1); - - c->subscribe_callback = cb; - c->subscribe_userdata = userdata; -} diff --git a/src/polyp/subscribe.h b/src/polyp/subscribe.h deleted file mode 100644 index d8326e1c..00000000 --- a/src/polyp/subscribe.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef foosubscribehfoo -#define foosubscribehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <inttypes.h> - -#include <polyp/def.h> -#include <polyp/context.h> -#include <polyp/cdecl.h> - -/** \page subscribe Event Subscription - * - * \section overv_sec Overview - * - * The application can be notified, asynchronously, whenever the internal - * layout of the server changes. Possible notifications are desribed in the - * \ref pa_subscription_event_type and \ref pa_subscription_mask - * enumerations. - * - * The application sets the notification mask using pa_context_subscribe() - * and the function that will be called whenever a notification occurs using - * pa_context_set_subscribe_callback(). - */ - -/** \file - * Daemon introspection event subscription subsystem. */ - -PA_C_DECL_BEGIN - -/** Subscription event callback prototype */ -typedef void (*pa_context_subscribe_cb_t)(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata); - -/** Enable event notification */ -pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, pa_context_success_cb_t cb, void *userdata); - -/** Set the context specific call back function that is called whenever the state of the daemon changes */ -void pa_context_set_subscribe_callback(pa_context *c, pa_context_subscribe_cb_t cb, void *userdata); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/thread-mainloop.c b/src/polyp/thread-mainloop.c deleted file mode 100644 index d036a232..00000000 --- a/src/polyp/thread-mainloop.c +++ /dev/null @@ -1,466 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <assert.h> -#include <signal.h> -#include <stdio.h> - -#ifdef HAVE_SYS_POLL_H -#include <sys/poll.h> -#else -#include "../polypcore/poll.h" -#endif - -#ifdef HAVE_PTHREAD -#include <pthread.h> -#endif - -#ifdef HAVE_WINDOWS_H -#include <windows.h> -#endif - -#include <polyp/xmalloc.h> - -#include <polypcore/log.h> -#include <polypcore/hashmap.h> - -#include "mainloop.h" -#include "thread-mainloop.h" - -#if defined(HAVE_PTHREAD) || defined(OS_IS_WIN32) - -struct pa_threaded_mainloop { - pa_mainloop *real_mainloop; - int n_waiting; - int thread_running; - -#ifdef OS_IS_WIN32 - DWORD thread_id; - HANDLE thread; - CRITICAL_SECTION mutex; - pa_hashmap *cond_events; - HANDLE accept_cond; -#else - pthread_t thread_id; - pthread_mutex_t mutex; - pthread_cond_t cond, accept_cond; -#endif -}; - -static inline int in_worker(pa_threaded_mainloop *m) { -#ifdef OS_IS_WIN32 - return GetCurrentThreadId() == m->thread_id; -#else - return pthread_equal(pthread_self(), m->thread_id); -#endif -} - -static int poll_func(struct pollfd *ufds, unsigned long nfds, int timeout, void *userdata) { -#ifdef OS_IS_WIN32 - CRITICAL_SECTION *mutex = userdata; -#else - pthread_mutex_t *mutex = userdata; -#endif - - int r; - - assert(mutex); - - /* Before entering poll() we unlock the mutex, so that - * avahi_simple_poll_quit() can succeed from another thread. */ - -#ifdef OS_IS_WIN32 - LeaveCriticalSection(mutex); -#else - pthread_mutex_unlock(mutex); -#endif - - r = poll(ufds, nfds, timeout); - -#ifdef OS_IS_WIN32 - EnterCriticalSection(mutex); -#else - pthread_mutex_lock(mutex); -#endif - - return r; -} - -#ifdef OS_IS_WIN32 -static DWORD WINAPI thread(void *userdata) { -#else -static void* thread(void *userdata) { -#endif - pa_threaded_mainloop *m = userdata; - -#ifndef OS_IS_WIN32 - sigset_t mask; - - /* Make sure that signals are delivered to the main thread */ - sigfillset(&mask); - pthread_sigmask(SIG_BLOCK, &mask, NULL); -#endif - -#ifdef OS_IS_WIN32 - EnterCriticalSection(&m->mutex); -#else - pthread_mutex_lock(&m->mutex); -#endif - - pa_mainloop_run(m->real_mainloop, NULL); - -#ifdef OS_IS_WIN32 - LeaveCriticalSection(&m->mutex); -#else - pthread_mutex_unlock(&m->mutex); -#endif - -#ifdef OS_IS_WIN32 - return 0; -#else - return NULL; -#endif -} - -pa_threaded_mainloop *pa_threaded_mainloop_new(void) { - pa_threaded_mainloop *m; -#ifndef OS_IS_WIN32 - pthread_mutexattr_t a; -#endif - - m = pa_xnew(pa_threaded_mainloop, 1); - - if (!(m->real_mainloop = pa_mainloop_new())) { - pa_xfree(m); - return NULL; - } - - pa_mainloop_set_poll_func(m->real_mainloop, poll_func, &m->mutex); - -#ifdef OS_IS_WIN32 - InitializeCriticalSection(&m->mutex); - - m->cond_events = pa_hashmap_new(NULL, NULL); - assert(m->cond_events); - m->accept_cond = CreateEvent(NULL, FALSE, FALSE, NULL); - assert(m->accept_cond); -#else - pthread_mutexattr_init(&a); - pthread_mutexattr_settype(&a, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&m->mutex, &a); - pthread_mutexattr_destroy(&a); - - pthread_cond_init(&m->cond, NULL); - pthread_cond_init(&m->accept_cond, NULL); -#endif - - m->thread_running = 0; - m->n_waiting = 0; - - return m; -} - -void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { - assert(m); - - /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !in_worker(m)); - - if (m->thread_running) - pa_threaded_mainloop_stop(m); - - if (m->real_mainloop) - pa_mainloop_free(m->real_mainloop); - -#ifdef OS_IS_WIN32 - pa_hashmap_free(m->cond_events, NULL, NULL); - CloseHandle(m->accept_cond); -#else - pthread_mutex_destroy(&m->mutex); - pthread_cond_destroy(&m->cond); - pthread_cond_destroy(&m->accept_cond); -#endif - - pa_xfree(m); -} - -int pa_threaded_mainloop_start(pa_threaded_mainloop *m) { - assert(m); - - assert(!m->thread_running); - -#ifdef OS_IS_WIN32 - - EnterCriticalSection(&m->mutex); - - m->thread = CreateThread(NULL, 0, thread, m, 0, &m->thread_id); - if (!m->thread) { - LeaveCriticalSection(&m->mutex); - return -1; - } - -#else - - pthread_mutex_lock(&m->mutex); - - if (pthread_create(&m->thread_id, NULL, thread, m) < 0) { - pthread_mutex_unlock(&m->mutex); - return -1; - } - -#endif - - m->thread_running = 1; - -#ifdef OS_IS_WIN32 - LeaveCriticalSection(&m->mutex); -#else - pthread_mutex_unlock(&m->mutex); -#endif - - return 0; -} - -void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) { - assert(m); - - if (!m->thread_running) - return; - - /* Make sure that this function is not called from the helper thread */ - assert(!in_worker(m)); - -#ifdef OS_IS_WIN32 - EnterCriticalSection(&m->mutex); -#else - pthread_mutex_lock(&m->mutex); -#endif - - pa_mainloop_quit(m->real_mainloop, 0); - -#ifdef OS_IS_WIN32 - LeaveCriticalSection(&m->mutex); -#else - pthread_mutex_unlock(&m->mutex); -#endif - -#ifdef OS_IS_WIN32 - WaitForSingleObject(m->thread, INFINITE); - CloseHandle(m->thread); -#else - pthread_join(m->thread_id, NULL); -#endif - - m->thread_running = 0; - - return; -} - -void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) { - assert(m); - - /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !in_worker(m)); - -#ifdef OS_IS_WIN32 - EnterCriticalSection(&m->mutex); -#else - pthread_mutex_lock(&m->mutex); -#endif -} - -void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) { - assert(m); - - /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !in_worker(m)); - -#ifdef OS_IS_WIN32 - LeaveCriticalSection(&m->mutex); -#else - pthread_mutex_unlock(&m->mutex); -#endif -} - -void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept) { -#ifdef OS_IS_WIN32 - void *iter; - const void *key; - HANDLE event; -#endif - - assert(m); - -#ifdef OS_IS_WIN32 - - iter = NULL; - while (1) { - pa_hashmap_iterate(m->cond_events, &iter, &key); - if (key == NULL) - break; - event = (HANDLE)pa_hashmap_get(m->cond_events, key); - SetEvent(event); - } - -#else - - pthread_cond_broadcast(&m->cond); - -#endif - - if (wait_for_accept && m->n_waiting > 0) { - -#ifdef OS_IS_WIN32 - - /* This is just to make sure it's unsignaled */ - WaitForSingleObject(m->accept_cond, 0); - - LeaveCriticalSection(&m->mutex); - - WaitForSingleObject(m->accept_cond, INFINITE); - - EnterCriticalSection(&m->mutex); - -#else - - pthread_cond_wait(&m->accept_cond, &m->mutex); - -#endif - - } -} - -void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { -#ifdef OS_IS_WIN32 - HANDLE event; - DWORD result; -#endif - - assert(m); - - /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !in_worker(m)); - - m->n_waiting ++; - -#ifdef OS_IS_WIN32 - - event = CreateEvent(NULL, FALSE, FALSE, NULL); - assert(event); - - pa_hashmap_put(m->cond_events, event, event); - - LeaveCriticalSection(&m->mutex); - - result = WaitForSingleObject(event, INFINITE); - assert(result == WAIT_OBJECT_0); - - EnterCriticalSection(&m->mutex); - - pa_hashmap_remove(m->cond_events, event); - - CloseHandle(event); - -#else - - pthread_cond_wait(&m->cond, &m->mutex); - -#endif - - assert(m->n_waiting > 0); - m->n_waiting --; -} - -void pa_threaded_mainloop_accept(pa_threaded_mainloop *m) { - assert(m); - - /* Make sure that this function is not called from the helper thread */ - assert(!m->thread_running || !in_worker(m)); - -#ifdef OS_IS_WIN32 - SetEvent(m->accept_cond); -#else - pthread_cond_signal(&m->accept_cond); -#endif -} - -int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) { - assert(m); - - return pa_mainloop_get_retval(m->real_mainloop); -} - -pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) { - assert(m); - - return pa_mainloop_get_api(m->real_mainloop); -} - -#else /* defined(OS_IS_WIN32) || defined(HAVE_PTHREAD) */ - -pa_threaded_mainloop *pa_threaded_mainloop_new(void) { - pa_log_error(__FILE__": Threaded main loop not supported on this platform"); - return NULL; -} - -void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { - assert(0); -} - -int pa_threaded_mainloop_start(pa_threaded_mainloop *m) { - assert(0); - return -1; -} - -void pa_threaded_mainloop_stop(pa_threaded_mainloop *m) { - assert(0); -} - -void pa_threaded_mainloop_lock(pa_threaded_mainloop *m) { - assert(0); -} - -void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m) { - assert(0); -} - -void pa_threaded_mainloop_wait(pa_threaded_mainloop *m) { - assert(0); -} - -void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_release) { - assert(0); -} - -int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m) { - assert(0); -} - -pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) { - assert(0); - return NULL; -} - -#endif /* defined(OS_IS_WIN32) || defined(HAVE_PTHREAD) */ diff --git a/src/polyp/thread-mainloop.h b/src/polyp/thread-mainloop.h deleted file mode 100644 index 81e8d674..00000000 --- a/src/polyp/thread-mainloop.h +++ /dev/null @@ -1,299 +0,0 @@ -#ifndef foothreadmainloophfoo -#define foothreadmainloophfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <polyp/mainloop-api.h> -#include <polyp/cdecl.h> - -PA_C_DECL_BEGIN - -/** \page threaded_mainloop Threaded Main Loop - * - * \section overv_sec Overview - * - * The threaded main loop implementation is a special version of the primary - * main loop implementation (see \ref mainloop). For the basic design, see - * its documentation. - * - * The added feature in the threaded main loop is that it spawns a new thread - * that runs the real main loop. This allows a synchronous application to use - * the asynchronous API without risking to stall the Polypaudio library. - * - * \section creat_sec Creation - * - * A pa_threaded_mainloop object is created using pa_threaded_mainloop_new(). - * This will only allocate the required structures though, so to use it the - * thread must also be started. This is done through - * pa_threaded_mainloop_start(), after which you can start using the main loop. - * - * \section destr_sec Destruction - * - * When the Polypaudio connection has been terminated, the thread must be - * stopped and the resources freed. Stopping the thread is done using - * pa_threaded_mainloop_stop(), which must be called without the lock (see - * below) held. When that function returns, the thread is stopped and the - * pa_threaded_mainloop object can be freed using pa_threaded_mainloop_free(). - * - * \section lock_sec Locking - * - * Since the Polypaudio API doesn't allow concurrent accesses to objects, - * a locking scheme must be used to guarantee safe usage. The threaded main - * loop API provides such a scheme through the functions - * pa_threaded_mainloop_lock() and pa_threaded_mainloop_unlock(). - * - * The lock is recursive, so it's safe to use it multiple times from the same - * thread. Just make sure you call pa_threaded_mainloop_unlock() the same - * number of times you called pa_threaded_mainloop_lock(). - * - * The lock needs to be held whenever you call any Polypaudio function that - * uses an object associated with this main loop. Make sure you do not hold - * on to the lock more than necessary though, as the threaded main loop stops - * while the lock is held. - * - * Example: - * - * \code - * void my_check_stream_func(pa_threaded_mainloop *m, pa_stream *s) { - * pa_stream_state_t state; - * - * pa_threaded_mainloop_lock(m); - * - * state = pa_stream_get_state(s); - * - * pa_threaded_mainloop_unlock(m); - * - * if (state == PA_STREAM_READY) - * printf("Stream is ready!"); - * else - * printf("Stream is not ready!"); - * } - * \endcode - * - * \section cb_sec Callbacks - * - * Callbacks in Polypaudio are asynchronous, so they require extra care when - * using them together with a threaded main loop. - * - * The easiest way to turn the callback based operations into synchronous - * ones, is to simply wait for the callback to be called and continue from - * there. This is the approach chosen in Polypaudio's threaded API. - * - * \subsection basic_subsec Basic callbacks - * - * For the basic case, where all that is required is to wait for the callback - * to be invoked, the code should look something like this: - * - * Example: - * - * \code - * static void my_drain_callback(pa_stream*s, int success, void *userdata) { - * pa_threaded_mainloop *m; - * - * m = (pa_threaded_mainloop*)userdata; - * assert(m); - * - * pa_threaded_mainloop_signal(m, 0); - * } - * - * void my_drain_stream_func(pa_threaded_mainloop *m, pa_stream *s) { - * pa_operation *o; - * - * pa_threaded_mainloop_lock(m); - * - * o = pa_stream_drain(s, my_drain_callback, m); - * assert(o); - * - * while (pa_operation_get_state(o) != OPERATION_DONE) - * pa_threaded_mainloop_wait(m); - * - * pa_operation_unref(o); - * - * pa_threaded_mainloop_unlock(m); - * } - * \endcode - * - * The main function, my_drain_stream_func(), will wait for the callback to - * be called using pa_threaded_mainloop_wait(). - * - * If your application is multi-threaded, then this waiting must be done - * inside a while loop. The reason for this is that multiple threads might be - * using pa_threaded_mainloop_wait() at the same time. Each thread must - * therefore verify that it was its callback that was invoked. - * - * The callback, my_drain_callback(), indicates to the main function that it - * has been called using pa_threaded_mainloop_signal(). - * - * As you can see, both pa_threaded_mainloop_wait() may only be called with - * the lock held. The same thing is true for pa_threaded_mainloop_signal(), - * but as the lock is held before the callback is invoked, you do not have to - * deal with that. - * - * The functions will not dead lock because the wait function will release - * the lock before waiting and then regrab it once it has been signaled. - * For those of you familiar with threads, the behaviour is that of a - * condition variable. - * - * \subsection data_subsec Data callbacks - * - * For many callbacks, simply knowing that they have been called is - * insufficient. The callback also receives some data that is desired. To - * access this data safely, we must extend our example a bit: - * - * \code - * static int *drain_result; - * - * static void my_drain_callback(pa_stream*s, int success, void *userdata) { - * pa_threaded_mainloop *m; - * - * m = (pa_threaded_mainloop*)userdata; - * assert(m); - * - * drain_result = &success; - * - * pa_threaded_mainloop_signal(m, 1); - * } - * - * void my_drain_stream_func(pa_threaded_mainloop *m, pa_stream *s) { - * pa_operation *o; - * - * pa_threaded_mainloop_lock(m); - * - * o = pa_stream_drain(s, my_drain_callback, m); - * assert(o); - * - * while (pa_operation_get_state(o) != OPERATION_DONE) - * pa_threaded_mainloop_wait(m); - * - * pa_operation_unref(o); - * - * if (*drain_result) - * printf("Success!"); - * else - * printf("Bitter defeat..."); - * - * pa_threaded_mainloop_accept(m); - * - * pa_threaded_mainloop_unlock(m); - * } - * \endcode - * - * The example is a bit silly as it would probably have been easier to just - * copy the contents of success, but for larger data structures this can be - * wasteful. - * - * The difference here compared to the basic callback is the 1 sent to - * pa_threaded_mainloop_signal() and the call to - * pa_threaded_mainloop_accept(). What will happen is that - * pa_threaded_mainloop_signal() will signal the main function and then stop. - * The main function is then free to use the data in the callback until - * pa_threaded_mainloop_accept() is called, which will allow the callback - * to continue. - * - * Note that pa_threaded_mainloop_accept() must be called some time between - * exiting the while loop and unlocking the main loop! Failure to do so will - * result in a race condition. I.e. it is not ok to release the lock and - * regrab it before calling pa_threaded_mainloop_accept(). - * - * \subsection async_subsec Asynchronous callbacks - * - * Polypaudio also has callbacks that are completely asynchronous, meaning - * that they can be called at any time. The threading main loop API provides - * the locking mechanism to handle concurrent accesses, but nothing else. - * Applications will have to handle communication from the callback to the - * main program through some own system. - * - * The callbacks that are completely asynchronous are: - * - * \li State callbacks for contexts, streams, etc. - * \li Subscription notifications - */ - -/** \file - * - * A thread based event loop implementation based on pa_mainloop. The - * event loop is run in a helper thread in the background. A few - * synchronization primitives are available to access the objects - * attached to the event loop safely. */ - -/** An opaque threaded main loop object */ -typedef struct pa_threaded_mainloop pa_threaded_mainloop; - -/** Allocate a new threaded main loop object. You have to call - * pa_threaded_mainloop_start() before the event loop thread starts - * running. */ -pa_threaded_mainloop *pa_threaded_mainloop_new(void); - -/** Free a threaded main loop object. If the event loop thread is - * still running, it is terminated using pa_threaded_mainloop_stop() - * first. */ -void pa_threaded_mainloop_free(pa_threaded_mainloop* m); - -/** Start the event loop thread. */ -int pa_threaded_mainloop_start(pa_threaded_mainloop *m); - -/** Terminate the event loop thread cleanly. Make sure to unlock the - * mainloop object before calling this function. */ -void pa_threaded_mainloop_stop(pa_threaded_mainloop *m); - -/** Lock the event loop object, effectively blocking the event loop - * thread from processing events. You can use this to enforce - * exclusive access to all objects attached to the event loop. This - * lock is recursive. This function may not be called inside the event - * loop thread. Events that are dispatched from the event loop thread - * are executed with this lock held. */ -void pa_threaded_mainloop_lock(pa_threaded_mainloop *m); - -/** Unlock the event loop object, inverse of pa_threaded_mainloop_lock() */ -void pa_threaded_mainloop_unlock(pa_threaded_mainloop *m); - -/** Wait for an event to be signalled by the event loop thread. You - * can use this to pass data from the event loop thread to the main - * thread in synchronized fashion. This function may not be called - * inside the event loop thread. Prior to this call the event loop - * object needs to be locked using pa_threaded_mainloop_lock(). While - * waiting the lock will be released, immediately before returning it - * will be acquired again. */ -void pa_threaded_mainloop_wait(pa_threaded_mainloop *m); - -/** Signal all threads waiting for a signalling event in - * pa_threaded_mainloop_wait(). If wait_for_release is non-zero, do - * not return before the signal was accepted by a - * pa_threaded_mainloop_accept() call. While waiting for that condition - * the event loop object is unlocked. */ -void pa_threaded_mainloop_signal(pa_threaded_mainloop *m, int wait_for_accept); - -/** Accept a signal from the event thread issued with - * pa_threaded_mainloop_signal(). This call should only be used in - * conjunction with pa_threaded_mainloop_signal() with a non-zero - * wait_for_accept value. */ -void pa_threaded_mainloop_accept(pa_threaded_mainloop *m); - -/** Return the return value as specified with the main loop's quit() routine. */ -int pa_threaded_mainloop_get_retval(pa_threaded_mainloop *m); - -/** Return the abstract main loop abstraction layer vtable for this main loop. */ -pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/timeval.c b/src/polyp/timeval.c deleted file mode 100644 index 6043d7fd..00000000 --- a/src/polyp/timeval.c +++ /dev/null @@ -1,142 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <assert.h> -#include <stddef.h> -#include <sys/time.h> - -#ifdef HAVE_WINDOWS_H -#include <windows.h> -#endif - -#include "../polypcore/winsock.h" - -#include "timeval.h" - -struct timeval *pa_gettimeofday(struct timeval *tv) { -#ifdef HAVE_GETTIMEOFDAY - assert(tv); - - return gettimeofday(tv, NULL) < 0 ? NULL : tv; -#elif defined(OS_IS_WIN32) - /* - * Copied from implementation by Steven Edwards (LGPL). - * Found on wine mailing list. - */ - -#if defined(_MSC_VER) || defined(__BORLANDC__) -#define EPOCHFILETIME (116444736000000000i64) -#else -#define EPOCHFILETIME (116444736000000000LL) -#endif - - FILETIME ft; - LARGE_INTEGER li; - __int64 t; - - assert(tv); - - GetSystemTimeAsFileTime(&ft); - li.LowPart = ft.dwLowDateTime; - li.HighPart = ft.dwHighDateTime; - t = li.QuadPart; /* In 100-nanosecond intervals */ - t -= EPOCHFILETIME; /* Offset to the Epoch time */ - t /= 10; /* In microseconds */ - tv->tv_sec = (long)(t / 1000000); - tv->tv_usec = (long)(t % 1000000); - - return tv; -#else -#error "Platform lacks gettimeofday() or equivalent function." -#endif -} - -pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b) { - pa_usec_t r; - assert(a && b); - - /* Check which whan is the earlier time and swap the two arguments if reuqired. */ - if (pa_timeval_cmp(a, b) < 0) { - const struct timeval *c; - c = a; - a = b; - b = c; - } - - /* Calculate the second difference*/ - r = ((pa_usec_t) a->tv_sec - b->tv_sec)* 1000000; - - /* Calculate the microsecond difference */ - if (a->tv_usec > b->tv_usec) - r += ((pa_usec_t) a->tv_usec - b->tv_usec); - else if (a->tv_usec < b->tv_usec) - r -= ((pa_usec_t) b->tv_usec - a->tv_usec); - - return r; -} - -int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) { - assert(a && b); - - if (a->tv_sec < b->tv_sec) - return -1; - - if (a->tv_sec > b->tv_sec) - return 1; - - if (a->tv_usec < b->tv_usec) - return -1; - - if (a->tv_usec > b->tv_usec) - return 1; - - return 0; -} - -pa_usec_t pa_timeval_age(const struct timeval *tv) { - struct timeval now; - assert(tv); - - return pa_timeval_diff(pa_gettimeofday(&now), tv); -} - -struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v) { - unsigned long secs; - assert(tv); - - secs = (v/1000000); - tv->tv_sec += (unsigned long) secs; - v -= secs*1000000; - - tv->tv_usec += v; - - /* Normalize */ - while (tv->tv_usec >= 1000000) { - tv->tv_sec++; - tv->tv_usec -= 1000000; - } - - return tv; -} diff --git a/src/polyp/timeval.h b/src/polyp/timeval.h deleted file mode 100644 index 9990d4ca..00000000 --- a/src/polyp/timeval.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef footimevalhfoo -#define footimevalhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <polyp/cdecl.h> -#include <polyp/sample.h> - -/** \file - * Utility functions for handling timeval calculations */ - -PA_C_DECL_BEGIN - -struct timeval; - -/** Return the current timestamp, just like UNIX gettimeofday() */ -struct timeval *pa_gettimeofday(struct timeval *tv); - -/** Calculate the difference between the two specified timeval - * structs. */ -pa_usec_t pa_timeval_diff(const struct timeval *a, const struct timeval *b); - -/** Compare the two timeval structs and return 0 when equal, negative when a < b, positive otherwse */ -int pa_timeval_cmp(const struct timeval *a, const struct timeval *b); - -/** Return the time difference between now and the specified timestamp */ -pa_usec_t pa_timeval_age(const struct timeval *tv); - -/** Add the specified time inmicroseconds to the specified timeval structure */ -struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/utf8.c b/src/polyp/utf8.c deleted file mode 100644 index 33fa7214..00000000 --- a/src/polyp/utf8.c +++ /dev/null @@ -1,237 +0,0 @@ -/* $Id$ */ - -/* This file is based on the GLIB utf8 validation functions. The - * original license text follows. */ - -/* gutf8.c - Operations on UTF-8 strings. - * - * Copyright (C) 1999 Tom Tromey - * Copyright (C) 2000 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <assert.h> -#include <errno.h> -#include <stdlib.h> -#include <inttypes.h> -#include <string.h> - -#ifdef HAVE_ICONV -#include <iconv.h> -#endif - -#include "utf8.h" -#include "xmalloc.h" - -#define FILTER_CHAR '_' - -static inline int is_unicode_valid(uint32_t ch) { - if (ch >= 0x110000) /* End of unicode space */ - return 0; - if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */ - return 0; - if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */ - return 0; - if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */ - return 0; - return 1; -} - -static inline int is_continuation_char(uint8_t ch) { - if ((ch & 0xc0) != 0x80) /* 10xxxxxx */ - return 0; - return 1; -} - -static inline void merge_continuation_char(uint32_t *u_ch, uint8_t ch) { - *u_ch <<= 6; - *u_ch |= ch & 0x3f; -} - -static char* utf8_validate(const char *str, char *output) { - uint32_t val = 0; - uint32_t min = 0; - const uint8_t *p, *last; - int size; - uint8_t *o; - - o = (uint8_t*) output; - for (p = (const uint8_t*) str; *p; p++) { - if (*p < 128) { - if (o) - *o = *p; - } else { - last = p; - - if ((*p & 0xe0) == 0xc0) { /* 110xxxxx two-char seq. */ - size = 2; - min = 128; - val = *p & 0x1e; - goto ONE_REMAINING; - } else if ((*p & 0xf0) == 0xe0) { /* 1110xxxx three-char seq.*/ - size = 3; - min = (1 << 11); - val = *p & 0x0f; - goto TWO_REMAINING; - } else if ((*p & 0xf8) == 0xf0) { /* 11110xxx four-char seq */ - size = 4; - min = (1 << 16); - val = *p & 0x07; - } else { - size = 1; - goto error; - } - - p++; - if (!is_continuation_char(*p)) - goto error; - merge_continuation_char(&val, *p); - -TWO_REMAINING: - p++; - if (!is_continuation_char(*p)) - goto error; - merge_continuation_char(&val, *p); - -ONE_REMAINING: - p++; - if (!is_continuation_char(*p)) - goto error; - merge_continuation_char(&val, *p); - - if (val < min) - goto error; - - if (!is_unicode_valid(val)) - goto error; - - if (o) { - memcpy(o, last, size); - o += size - 1; - } - - if (o) - o++; - - continue; - -error: - if (o) { - *o = FILTER_CHAR; - p = last; /* We retry at the next character */ - } else - goto failure; - } - - if (o) - o++; - } - - if (o) { - *o = '\0'; - return output; - } - - return (char*) str; - -failure: - return NULL; -} - -const char* pa_utf8_valid (const char *str) { - return utf8_validate(str, NULL); -} - -char* pa_utf8_filter (const char *str) { - char *new_str; - - new_str = pa_xnew(char, strlen(str) + 1); - - return utf8_validate(str, new_str); -} - -#ifdef HAVE_ICONV - -static char* iconv_simple(const char *str, const char *to, const char *from) { - char *new_str; - size_t len, inlen; - - iconv_t cd; - ICONV_CONST char *inbuf; - char *outbuf; - size_t res, inbytes, outbytes; - - cd = iconv_open(to, from); - if (cd == (iconv_t)-1) - return NULL; - - inlen = len = strlen(str) + 1; - new_str = pa_xmalloc(len); - assert(new_str); - - while (1) { - inbuf = (ICONV_CONST char*)str; /* Brain dead prototype for iconv() */ - inbytes = inlen; - outbuf = new_str; - outbytes = len; - - res = iconv(cd, &inbuf, &inbytes, &outbuf, &outbytes); - - if (res != (size_t)-1) - break; - - if (errno != E2BIG) { - pa_xfree(new_str); - new_str = NULL; - break; - } - - assert(inbytes != 0); - - len += inbytes; - new_str = pa_xrealloc(new_str, len); - assert(new_str); - } - - iconv_close(cd); - - return new_str; -} - -char* pa_utf8_to_locale (const char *str) { - return iconv_simple(str, "", "UTF-8"); -} - -char* pa_locale_to_utf8 (const char *str) { - return iconv_simple(str, "UTF-8", ""); -} - -#else - -char* pa_utf8_to_locale (const char *str) { - return NULL; -} - -char* pa_locale_to_utf8 (const char *str) { - return NULL; -} - -#endif diff --git a/src/polyp/utf8.h b/src/polyp/utf8.h deleted file mode 100644 index 55b8d2e4..00000000 --- a/src/polyp/utf8.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef fooutf8hfoo -#define fooutf8hfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <polyp/cdecl.h> - -/** \file - * UTF8 Validation functions - */ - -PA_C_DECL_BEGIN - -/** Test if the specified strings qualifies as valid UTF8. Return the string if so, otherwise NULL */ -const char *pa_utf8_valid(const char *str); - -/** Filter all invalid UTF8 characters from the specified string, returning a new fully UTF8 valid string. Don't forget to free the returned string with pa_xfree() */ -char *pa_utf8_filter(const char *str); - -/** Convert a UTF-8 string to the current locale. Free the string using pa_xfree(). */ -char* pa_utf8_to_locale (const char *str); - -/** Convert a string in the current locale to UTF-8. Free the string using pa_xfree(). */ -char* pa_locale_to_utf8 (const char *str); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/util.c b/src/polyp/util.c deleted file mode 100644 index 842b9e7f..00000000 --- a/src/polyp/util.c +++ /dev/null @@ -1,227 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <assert.h> -#include <errno.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> -#include <sys/types.h> - -#ifdef HAVE_PWD_H -#include <pwd.h> -#endif - -#ifdef HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif - -#ifdef HAVE_NETDB_H -#include <netdb.h> -#endif - -#ifdef HAVE_WINDOWS_H -#include <windows.h> -#endif - -#include "../polypcore/winsock.h" - -#include <polypcore/core-error.h> -#include <polypcore/log.h> -#include <polypcore/core-util.h> - -#include "util.h" - -#ifndef OS_IS_WIN32 -#define PATH_SEP '/' -#else -#define PATH_SEP '\\' -#endif - -char *pa_get_user_name(char *s, size_t l) { - char *p; - char buf[1024]; - -#ifdef HAVE_PWD_H - struct passwd pw, *r; -#endif - - assert(s && l > 0); - - if (!(p = getenv("USER")) && !(p = getenv("LOGNAME")) && !(p = getenv("USERNAME"))) { -#ifdef HAVE_PWD_H - -#ifdef HAVE_GETPWUID_R - if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { -#else - /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) - * that do not support getpwuid_r. */ - if ((r = getpwuid(getuid())) == NULL) { -#endif - snprintf(s, l, "%lu", (unsigned long) getuid()); - return s; - } - - p = r->pw_name; - -#elif defined(OS_IS_WIN32) /* HAVE_PWD_H */ - DWORD size = sizeof(buf); - - if (!GetUserName(buf, &size)) - return NULL; - - p = buf; - -#else /* HAVE_PWD_H */ - return NULL; -#endif /* HAVE_PWD_H */ - } - - return pa_strlcpy(s, p, l); -} - -char *pa_get_host_name(char *s, size_t l) { - assert(s && l > 0); - if (gethostname(s, l) < 0) { - pa_log(__FILE__": gethostname(): %s", pa_cstrerror(errno)); - return NULL; - } - s[l-1] = 0; - return s; -} - -char *pa_get_home_dir(char *s, size_t l) { - char *e; - -#ifdef HAVE_PWD_H - char buf[1024]; - struct passwd pw, *r; -#endif - - assert(s && l); - - if ((e = getenv("HOME"))) - return pa_strlcpy(s, e, l); - - if ((e = getenv("USERPROFILE"))) - return pa_strlcpy(s, e, l); - -#ifdef HAVE_PWD_H -#ifdef HAVE_GETPWUID_R - if (getpwuid_r(getuid(), &pw, buf, sizeof(buf), &r) != 0 || !r) { - pa_log(__FILE__": getpwuid_r() failed"); -#else - /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) - * that do not support getpwuid_r. */ - if ((r = getpwuid(getuid())) == NULL) { - pa_log(__FILE__": getpwuid_r() failed"); -#endif - return NULL; - } - - return pa_strlcpy(s, r->pw_dir, l); -#else /* HAVE_PWD_H */ - return NULL; -#endif -} - -char *pa_get_binary_name(char *s, size_t l) { - -#ifdef HAVE_READLINK - char path[PATH_MAX]; - int i; - assert(s && l); - - /* This works on Linux only */ - - snprintf(path, sizeof(path), "/proc/%u/exe", (unsigned) getpid()); - if ((i = readlink(path, s, l-1)) < 0) - return NULL; - - s[i] = 0; - return s; -#elif defined(OS_IS_WIN32) - char path[PATH_MAX]; - if (!GetModuleFileName(NULL, path, PATH_MAX)) - return NULL; - pa_strlcpy(s, pa_path_get_filename(path), l); - return s; -#else - return NULL; -#endif -} - -const char *pa_path_get_filename(const char *p) { - char *fn; - - if ((fn = strrchr(p, PATH_SEP))) - return fn+1; - - return (const char*) p; -} - -char *pa_get_fqdn(char *s, size_t l) { - char hn[256]; -#ifdef HAVE_GETADDRINFO - struct addrinfo *a, hints; -#endif - - if (!pa_get_host_name(hn, sizeof(hn))) - return NULL; - -#ifdef HAVE_GETADDRINFO - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_flags = AI_CANONNAME; - - if (getaddrinfo(hn, NULL, &hints, &a) < 0 || !a || !a->ai_canonname || !*a->ai_canonname) - return pa_strlcpy(s, hn, l); - - pa_strlcpy(s, a->ai_canonname, l); - freeaddrinfo(a); - return s; -#else - return pa_strlcpy(s, hn, l); -#endif -} - -int pa_msleep(unsigned long t) { -#ifdef OS_IS_WIN32 - Sleep(t); - return 0; -#elif defined(HAVE_NANOSLEEP) - struct timespec ts; - - ts.tv_sec = t/1000; - ts.tv_nsec = (t % 1000) * 1000000; - - return nanosleep(&ts, NULL); -#else -#error "Platform lacks a sleep function." -#endif -} diff --git a/src/polyp/util.h b/src/polyp/util.h deleted file mode 100644 index cd8aab0b..00000000 --- a/src/polyp/util.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef fooutilhfoo -#define fooutilhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - polypaudio 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <stddef.h> - -#include <polyp/cdecl.h> - -/** \file - * Assorted utility functions */ - -PA_C_DECL_BEGIN - -/** Return the current username in the specified string buffer. */ -char *pa_get_user_name(char *s, size_t l); - -/** Return the current hostname in the specified buffer. */ -char *pa_get_host_name(char *s, size_t l); - -/** Return the fully qualified domain name in s */ -char *pa_get_fqdn(char *s, size_t l); - -/** Return the home directory of the current user */ -char *pa_get_home_dir(char *s, size_t l); - -/** Return the binary file name of the current process. This is not - * supported on all architectures, in which case NULL is returned. */ -char *pa_get_binary_name(char *s, size_t l); - -/** Return a pointer to the filename inside a path (which is the last - * component). */ -const char *pa_path_get_filename(const char *p); - -/** Wait t milliseconds */ -int pa_msleep(unsigned long t); - -PA_C_DECL_END - -#endif diff --git a/src/polyp/version.h.in b/src/polyp/version.h.in deleted file mode 100644 index de7b9c1c..00000000 --- a/src/polyp/version.h.in +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef fooversionhfoo /*-*-C-*-*/ -#define fooversionhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -/* WARNING: Make sure to edit the real source file version.h.in! */ - -#include <polyp/cdecl.h> - -/** \file - * Define header version */ - -PA_C_DECL_BEGIN - -/** Return the version of the header files. Keep in mind that this is -a macro and not a function, so it is impossible to get the pointer of -it. */ -#define pa_get_headers_version() ("@PACKAGE_VERSION@") - -/** Return the version of the library the current application is linked to. */ -const char* pa_get_library_version(void); - -/** The current API version. Version 6 relates to polypaudio - * 0.6. Prior versions (i.e. Polypaudio 0.5.1 and older) have - * PA_API_VERSION undefined. */ -#define PA_API_VERSION @PA_API_VERSION@ - -/** The current protocol version. Version 8 relates to polypaudio 0.8. - * \since 0.8 */ -#define PA_PROTOCOL_VERSION @PA_PROTOCOL_VERSION@ - -PA_C_DECL_END - -#endif diff --git a/src/polyp/volume.c b/src/polyp/volume.c deleted file mode 100644 index f10463c3..00000000 --- a/src/polyp/volume.c +++ /dev/null @@ -1,176 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <assert.h> -#include <stdio.h> -#include <string.h> - -#include "volume.h" - -int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) { - int i; - assert(a); - assert(b); - - if (a->channels != b->channels) - return 0; - - for (i = 0; i < a->channels; i++) - if (a->values[i] != b->values[i]) - return 0; - - return 1; -} - -pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) { - int i; - - assert(a); - assert(channels > 0); - assert(channels <= PA_CHANNELS_MAX); - - a->channels = channels; - - for (i = 0; i < a->channels; i++) - a->values[i] = v; - - return a; -} - -pa_volume_t pa_cvolume_avg(const pa_cvolume *a) { - uint64_t sum = 0; - int i; - assert(a); - - for (i = 0; i < a->channels; i++) - sum += a->values[i]; - - sum /= a->channels; - - return (pa_volume_t) sum; -} - -pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) { - return pa_sw_volume_from_linear(pa_sw_volume_to_linear(a)* pa_sw_volume_to_linear(b)); -} - -#define USER_DECIBEL_RANGE 30 - -pa_volume_t pa_sw_volume_from_dB(double dB) { - if (dB <= -USER_DECIBEL_RANGE) - return PA_VOLUME_MUTED; - - return (pa_volume_t) ((dB/USER_DECIBEL_RANGE+1)*PA_VOLUME_NORM); -} - -double pa_sw_volume_to_dB(pa_volume_t v) { - if (v == PA_VOLUME_MUTED) - return PA_DECIBEL_MININFTY; - - return ((double) v/PA_VOLUME_NORM-1)*USER_DECIBEL_RANGE; -} - -pa_volume_t pa_sw_volume_from_linear(double v) { - - if (v <= 0) - return PA_VOLUME_MUTED; - - if (v > .999 && v < 1.001) - return PA_VOLUME_NORM; - - return pa_sw_volume_from_dB(20*log10(v)); -} - -double pa_sw_volume_to_linear(pa_volume_t v) { - - if (v == PA_VOLUME_MUTED) - return 0; - - return pow(10, pa_sw_volume_to_dB(v)/20); -} - -char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c) { - unsigned channel; - int first = 1; - char *e; - - assert(s); - assert(l > 0); - assert(c); - - *(e = s) = 0; - - for (channel = 0; channel < c->channels && l > 1; channel++) { - l -= snprintf(e, l, "%s%u: %3u%%", - first ? "" : " ", - channel, - (c->values[channel]*100)/PA_VOLUME_NORM); - - e = strchr(e, 0); - first = 0; - } - - return s; -} - -/** Return non-zero if the volume of all channels is equal to the specified value */ -int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) { - unsigned c; - assert(a); - - for (c = 0; c < a->channels; c++) - if (a->values[c] != v) - return 0; - - return 1; -} - -pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { - unsigned i; - - assert(dest); - assert(a); - assert(b); - - for (i = 0; i < a->channels && i < b->channels && i < PA_CHANNELS_MAX; i++) { - - dest->values[i] = pa_sw_volume_multiply( - i < a->channels ? a->values[i] : PA_VOLUME_NORM, - i < b->channels ? b->values[i] : PA_VOLUME_NORM); - } - - dest->channels = i; - - return dest; -} - -int pa_cvolume_valid(const pa_cvolume *v) { - assert(v); - - if (v->channels <= 0 || v->channels > PA_CHANNELS_MAX) - return 0; - - return 1; -} diff --git a/src/polyp/volume.h b/src/polyp/volume.h deleted file mode 100644 index 0da5f54f..00000000 --- a/src/polyp/volume.h +++ /dev/null @@ -1,172 +0,0 @@ -#ifndef foovolumehfoo -#define foovolumehfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <inttypes.h> -#include <polyp/cdecl.h> -#include <polyp/sample.h> - -/** \page volume Volume Control - * - * \section overv_sec Overview - * - * Sinks, sources, sink inputs and samples can all have their own volumes. - * To deal with these, The Polypaudio libray contains a number of functions - * that ease handling. - * - * The basic volume type in Polypaudio is the \ref pa_volume_t type. Most of - * the time, applications will use the aggregated pa_cvolume structure that - * can store the volume of all channels at once. - * - * Volumes commonly span between muted (0%), and normal (100%). It is possible - * to set volumes to higher than 100%, but clipping might occur. - * - * \section calc_sec Calculations - * - * The volumes in Polypaudio are logarithmic in nature and applications - * shouldn't perform calculations with them directly. Instead, they should - * be converted to and from either dB or a linear scale: - * - * \li dB - pa_sw_volume_from_dB() / pa_sw_volume_to_dB() - * \li Linear - pa_sw_volume_from_linear() / pa_sw_volume_to_linear() - * - * For simple multiplication, pa_sw_volume_multiply() and - * pa_sw_cvolume_multiply() can be used. - * - * Calculations can only be reliably performed on software volumes - * as it is commonly unknown what scale hardware volumes relate to. - * - * The functions described above are only valid when used with - * software volumes. Hence it is usually a better idea to treat all - * volume values as opaque with a range from PA_VOLUME_MUTE (0%) to - * PA_VOLUME_NORM (100%) and to refrain from any calculations with - * them. - * - * \section conv_sec Convenience Functions - * - * To handle the pa_cvolume structure, the Polypaudio library provides a - * number of convenienc functions: - * - * \li pa_cvolume_valid() - Tests if a pa_cvolume structure is valid. - * \li pa_cvolume_equal() - Tests if two pa_cvolume structures are identical. - * \li pa_cvolume_channels_equal_to() - Tests if all channels of a pa_cvolume - * structure have a given volume. - * \li pa_cvolume_is_muted() - Tests if all channels of a pa_cvolume - * structure are muted. - * \li pa_cvolume_is_norm() - Tests if all channels of a pa_cvolume structure - * are at a normal volume. - * \li pa_cvolume_set() - Set all channels of a pa_cvolume structure to a - * certain volume. - * \li pa_cvolume_reset() - Set all channels of a pa_cvolume structure to a - * normal volume. - * \li pa_cvolume_mute() - Set all channels of a pa_cvolume structure to a - * muted volume. - * \li pa_cvolume_avg() - Return the average volume of all channels. - * \li pa_cvolume_snprint() - Pretty print a pa_cvolume structure. - */ - -/** \file - * Constants and routines for volume handling */ - -PA_C_DECL_BEGIN - -/** Volume specification: - * PA_VOLUME_MUTED: silence; - * < PA_VOLUME_NORM: decreased volume; - * PA_VOLUME_NORM: normal volume; - * > PA_VOLUME_NORM: increased volume */ -typedef uint32_t pa_volume_t; - -/** Normal volume (100%) */ -#define PA_VOLUME_NORM (0x10000) - -/** Muted volume (0%) */ -#define PA_VOLUME_MUTED (0) - -/** A structure encapsulating a per-channel volume */ -typedef struct pa_cvolume { - uint8_t channels; /**< Number of channels */ - pa_volume_t values[PA_CHANNELS_MAX]; /**< Per-channel volume */ -} pa_cvolume; - -/** Return non-zero when *a == *b */ -int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b); - -/** Set the volume of all channels to PA_VOLUME_NORM */ -#define pa_cvolume_reset(a, n) pa_cvolume_set((a), (n), PA_VOLUME_NORM) - -/** Set the volume of all channels to PA_VOLUME_MUTED */ -#define pa_cvolume_mute(a, n) pa_cvolume_set((a), (n), PA_VOLUME_MUTED) - -/** Set the volume of all channels to the specified parameter */ -pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v); - -/** Maximum length of the strings returned by pa_cvolume_snprint() */ -#define PA_CVOLUME_SNPRINT_MAX 64 - -/** Pretty print a volume structure */ -char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c); - -/** Return the average volume of all channels */ -pa_volume_t pa_cvolume_avg(const pa_cvolume *a); - -/** Return TRUE when the passed cvolume structure is valid, FALSE otherwise */ -int pa_cvolume_valid(const pa_cvolume *v); - -/** Return non-zero if the volume of all channels is equal to the specified value */ -int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v); - -/** Return 1 if the specified volume has all channels muted */ -#define pa_cvolume_is_muted(a) pa_cvolume_channels_equal_to((a), PA_VOLUME_MUTED) - -/** Return 1 if the specified volume has all channels on normal level */ -#define pa_cvolume_is_norm(a) pa_cvolume_channels_equal_to((a), PA_VOLUME_NORM) - -/** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. This is only valid for software volumes! */ -pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b); - -/** Multiply to per-channel volumes and return the result in *dest. This is only valid for software volumes! */ -pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b); - -/** Convert a decibel value to a volume. This is only valid for software volumes! \since 0.4 */ -pa_volume_t pa_sw_volume_from_dB(double f); - -/** Convert a volume to a decibel value. This is only valid for software volumes! \since 0.4 */ -double pa_sw_volume_to_dB(pa_volume_t v); - -/** Convert a linear factor to a volume. This is only valid for software volumes! \since 0.8 */ -pa_volume_t pa_sw_volume_from_linear(double v); - -/** Convert a volume to a linear factor. This is only valid for software volumes! \since 0.8 */ -double pa_sw_volume_to_linear(pa_volume_t v); - -#ifdef INFINITY -#define PA_DECIBEL_MININFTY (-INFINITY) -#else -/** This value is used as minus infinity when using pa_volume_{to,from}_dB(). \since 0.4 */ -#define PA_DECIBEL_MININFTY (-200) -#endif - -PA_C_DECL_END - -#endif diff --git a/src/polyp/xmalloc.c b/src/polyp/xmalloc.c deleted file mode 100644 index 7f71a5ed..00000000 --- a/src/polyp/xmalloc.c +++ /dev/null @@ -1,128 +0,0 @@ -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdlib.h> -#include <signal.h> -#include <assert.h> -#include <unistd.h> -#include <string.h> - -#include <polypcore/core-util.h> -#include <polypcore/gccmacro.h> - -#include "xmalloc.h" - -/* Make sure not to allocate more than this much memory. */ -#define MAX_ALLOC_SIZE (1024*1024*20) /* 20MB */ - -/* #undef malloc */ -/* #undef free */ -/* #undef realloc */ -/* #undef strndup */ -/* #undef strdup */ - -static void oom(void) PA_GCC_NORETURN; - -/** called in case of an OOM situation. Prints an error message and - * exits */ -static void oom(void) { - static const char e[] = "Not enough memory\n"; - pa_loop_write(STDERR_FILENO, e, sizeof(e)-1); -#ifdef SIGQUIT - raise(SIGQUIT); -#endif - _exit(1); -} - -void* pa_xmalloc(size_t size) { - void *p; - assert(size > 0); - assert(size < MAX_ALLOC_SIZE); - - if (!(p = malloc(size))) - oom(); - - return p; -} - -void* pa_xmalloc0(size_t size) { - void *p; - assert(size > 0); - assert(size < MAX_ALLOC_SIZE); - - if (!(p = calloc(1, size))) - oom(); - - return p; -} - -void *pa_xrealloc(void *ptr, size_t size) { - void *p; - assert(size > 0); - assert(size < MAX_ALLOC_SIZE); - - if (!(p = realloc(ptr, size))) - oom(); - return p; -} - -void* pa_xmemdup(const void *p, size_t l) { - if (!p) - return NULL; - else { - char *r = pa_xmalloc(l); - memcpy(r, p, l); - return r; - } -} - -char *pa_xstrdup(const char *s) { - if (!s) - return NULL; - - return pa_xmemdup(s, strlen(s)+1); -} - -char *pa_xstrndup(const char *s, size_t l) { - char *e, *r; - - if (!s) - return NULL; - - if ((e = memchr(s, 0, l))) - return pa_xmemdup(s, e-s+1); - - r = pa_xmalloc(l+1); - memcpy(r, s, l); - r[l] = 0; - return r; -} - -void pa_xfree(void *p) { - if (!p) - return; - - free(p); -} diff --git a/src/polyp/xmalloc.h b/src/polyp/xmalloc.h deleted file mode 100644 index 49b6d7bc..00000000 --- a/src/polyp/xmalloc.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef foomemoryhfoo -#define foomemoryhfoo - -/* $Id$ */ - -/*** - This file is part of polypaudio. - - polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published - by the Free Software Foundation; either version 2 of the License, - or (at your option) any later version. - - polypaudio 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 Lesser General Public License - along with polypaudio; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - USA. -***/ - -#include <sys/types.h> -#include <stdlib.h> -#include <limits.h> -#include <assert.h> -#include <polyp/cdecl.h> - -/** \file - * Memory allocation functions. - */ - -PA_C_DECL_BEGIN - -/** Allocate the specified number of bytes, just like malloc() does. However, in case of OOM, terminate */ -void* pa_xmalloc(size_t l); - -/** Same as pa_xmalloc(), but initialize allocated memory to 0 */ -void *pa_xmalloc0(size_t l); - -/** The combination of pa_xmalloc() and realloc() */ -void *pa_xrealloc(void *ptr, size_t size); - -/** Free allocated memory */ -void pa_xfree(void *p); - -/** Duplicate the specified string, allocating memory with pa_xmalloc() */ -char *pa_xstrdup(const char *s); - -/** Duplicate the specified string, but truncate after l characters */ -char *pa_xstrndup(const char *s, size_t l); - -/** Duplicate the specified memory block */ -void* pa_xmemdup(const void *p, size_t l); - -/** Internal helper for pa_xnew() */ -static inline void* pa_xnew_internal(unsigned n, size_t k) { - assert(n < INT_MAX/k); - return pa_xmalloc(n*k); -} - -/** Allocate n new structures of the specified type. */ -#define pa_xnew(type, n) ((type*) pa_xnew_internal((n), sizeof(type))) - -/** Internal helper for pa_xnew0() */ -static inline void* pa_xnew0_internal(unsigned n, size_t k) { - assert(n < INT_MAX/k); - return pa_xmalloc0(n*k); -} - -/** Same as pa_xnew() but set the memory to zero */ -#define pa_xnew0(type, n) ((type*) pa_xnew0_internal((n), sizeof(type))) - -PA_C_DECL_END - -#endif |