From dd10c982414dfa8fbb9aeeeae61c68e4a6f081cc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 27 Jan 2006 16:25:31 +0000 Subject: Mega patch: * implement inner loops using liboil * drop "typeid" stuff * add support for channel maps * add support for seperate volumes per channel * add support for hardware mixer settings (only module-oss implements this for now) * fix a lot of types for _t suffix git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@463 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 26 ++- polyp/alsa-util.c | 2 +- polyp/alsa-util.h | 2 +- polyp/autoload.c | 8 +- polyp/autoload.h | 10 +- polyp/channelmap.c | 202 ++++++++++++++++ polyp/channelmap.h | 94 ++++++++ polyp/cli-command.c | 21 +- polyp/cli-text.c | 129 ++++++---- polyp/cli.c | 3 +- polyp/client.c | 6 +- polyp/client.h | 6 +- polyp/core.h | 2 +- polyp/daemon-conf.c | 2 +- polyp/daemon-conf.h | 8 +- polyp/dllmain.c | 2 +- polyp/glib-mainloop.c | 12 +- polyp/glib12-mainloop.c | 10 +- polyp/inet_ntop.c | 2 +- polyp/iochannel.c | 4 +- polyp/log.c | 26 +-- polyp/log.h | 12 +- polyp/main.c | 3 + polyp/mainloop-api.h | 6 +- polyp/mainloop-signal.c | 2 +- polyp/mainloop-test.c | 2 +- polyp/mainloop.c | 14 +- polyp/memblock.h | 6 +- polyp/module-alsa-sink.c | 8 +- polyp/module-alsa-source.c | 6 +- polyp/module-combine.c | 6 +- polyp/module-esound-sink.c | 6 +- polyp/module-lirc.c | 39 +++- polyp/module-match.c | 6 +- polyp/module-mmkbd-evdev.c | 25 +- polyp/module-null-sink.c | 4 +- polyp/module-oss-mmap.c | 8 +- polyp/module-oss.c | 54 ++++- polyp/module-pipe-sink.c | 4 +- polyp/module-pipe-source.c | 4 +- polyp/module-protocol-stub.c | 2 +- polyp/module-sine.c | 4 +- polyp/module-solaris.c | 2 +- polyp/module-tunnel.c | 6 +- polyp/module-waveout.c | 2 +- polyp/module-x11-bell.c | 3 +- polyp/namereg.c | 8 +- polyp/namereg.h | 8 +- polyp/native-common.h | 5 + polyp/pacat-simple.c | 2 +- polyp/pacat.c | 13 +- polyp/pactl.c | 77 +++--- polyp/paplay.c | 8 +- polyp/parec-simple.c | 2 +- polyp/parseaddr.h | 4 +- polyp/play-memchunk.c | 26 ++- polyp/play-memchunk.h | 8 +- polyp/poll.c | 2 +- polyp/poll.h | 2 +- polyp/polyplib-context.c | 4 +- polyp/polyplib-context.h | 2 +- polyp/polyplib-def.h | 14 +- polyp/polyplib-internal.h | 15 +- polyp/polyplib-introspect.c | 28 ++- polyp/polyplib-introspect.h | 46 ++-- polyp/polyplib-operation.c | 4 +- polyp/polyplib-operation.h | 2 +- polyp/polyplib-simple.c | 13 +- polyp/polyplib-simple.h | 3 +- polyp/polyplib-stream.c | 39 +++- polyp/polyplib-stream.h | 19 +- polyp/polyplib-subscribe.c | 6 +- polyp/polyplib-subscribe.h | 4 +- polyp/protocol-esound.c | 40 ++-- polyp/protocol-native.c | 108 ++++++--- polyp/protocol-simple.c | 8 +- polyp/resampler.c | 546 +++++++++++++++++++++++++++++-------------- polyp/resampler.h | 18 +- polyp/sample-util.c | 354 ++++++++++++++++------------ polyp/sample-util.h | 23 +- polyp/sample.c | 83 ++----- polyp/sample.h | 49 +--- polyp/scache.c | 21 +- polyp/scache.h | 7 +- polyp/sconv-s16be.c | 8 + polyp/sconv-s16be.h | 4 +- polyp/sconv-s16le.c | 64 +++-- polyp/sconv-s16le.h | 4 +- polyp/sconv.c | 155 ++++-------- polyp/sconv.h | 8 +- polyp/sink-input.c | 152 +++++++++--- polyp/sink-input.h | 37 +-- polyp/sink.c | 226 ++++++++++++------ polyp/sink.h | 41 +++- polyp/socket-client.c | 4 +- polyp/socket-server.c | 2 +- polyp/sound-file-stream.c | 11 +- polyp/sound-file-stream.h | 2 +- polyp/source-output.c | 74 ++++-- polyp/source-output.h | 26 ++- polyp/source.c | 65 ++++-- polyp/source.h | 27 ++- polyp/subscribe.c | 10 +- polyp/subscribe.h | 4 +- polyp/tagstruct.c | 91 +++++++- polyp/tagstruct.h | 6 + polyp/typeid.c | 33 --- polyp/typeid.h | 46 ---- polyp/voltest.c | 17 +- polyp/volume.c | 176 ++++++++++++++ polyp/volume.h | 107 +++++++++ polyp/x11prop.c | 2 +- polyp/x11wrap.c | 4 +- 113 files changed, 2544 insertions(+), 1294 deletions(-) create mode 100644 polyp/channelmap.c create mode 100644 polyp/channelmap.h delete mode 100644 polyp/typeid.c delete mode 100644 polyp/typeid.h create mode 100644 polyp/volume.c create mode 100644 polyp/volume.h (limited to 'polyp') diff --git a/polyp/Makefile.am b/polyp/Makefile.am index 0181ae6a..ad9952a5 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -47,6 +47,7 @@ AM_CFLAGS += $(PTHREAD_CFLAGS) -D_POSIX_PTHREAD_SEMANTICS AM_CFLAGS += $(LTDLINCL) AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\" +#AM_CFLAGS += -DDLSEARCHPATH=\"$(shell pwd)\" AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(DEFAULT_CONFIG_DIR)\" AM_CFLAGS += -DPOLYPAUDIO_BINARY=\"$(POLYPAUDIO_BINARY)\" @@ -101,10 +102,10 @@ polypaudio_SOURCES = \ main.c \ pid.c pid.h -polypaudio_CFLAGS = $(AM_CFLAGS) -polypaudio_CPPFLAGS = $(AM_CPPFLAGS) +polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS) +polypaudio_CPPFLAGS = $(AM_CPPFLAGS) polypaudio_LDADD = $(AM_LDADD) libpolypcore.la $(LIBLTDL) \ - $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) + $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) $(LIBOIL_LIBS) polypaudio_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -dlopen force $(foreach f,$(PREOPEN_LIBS),-dlopen $(f)) if PREOPEN_MODS @@ -219,7 +220,7 @@ strlist_test_CFLAGS = $(AM_CFLAGS) strlist_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) strlist_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -voltest_SOURCES = voltest.c sample.c +voltest_SOURCES = voltest.c sample.c volume.c volume.h sample.h voltest_CFLAGS = $(AM_CFLAGS) voltest_LDADD = $(AM_LDADD) voltest_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) @@ -265,8 +266,7 @@ polypinclude_HEADERS = \ polyplib-stream.h \ polyplib-subscribe.h \ polyplib-version.h \ - sample.h \ - typeid.h + sample.h if HAVE_HOWL polypinclude_HEADERS += \ @@ -333,10 +333,11 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = \ strbuf.c strbuf.h \ strlist.c strlist.h \ tagstruct.c tagstruct.h \ - typeid.c typeid.h \ util.c util.h \ winsock.h \ - xmalloc.c xmalloc.h + xmalloc.c xmalloc.h \ + channelmap.c channelmap.h \ + volume.c volume.h if HAVE_X11 libpolyp_@PA_MAJORMINOR@_la_SOURCES += \ @@ -475,14 +476,15 @@ libpolypcore_la_SOURCES = \ strbuf.c strbuf.h \ subscribe.c subscripe.h \ tokenizer.c tokenizer.h \ - typeid.c typeid.h \ util.c util.h \ winsock.h \ - xmalloc.c xmalloc.h + xmalloc.c xmalloc.h \ + volume.c volume.h \ + channelmap.c channelmap.h -libpolypcore_la_CPPFLAGS = $(AM_CPPFLAGS) +libpolypcore_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBOIL_CFLAGS) libpolypcore_la_LDFLAGS = -avoid-version -libpolypcore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) +libpolypcore_la_LIBADD = $(AM_LIBADD) $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSNDFILE_LIBS) $(WINSOCK_LIBS) $(LIBOIL_LIBS) ################################### # Plug-in support libraries # diff --git a/polyp/alsa-util.c b/polyp/alsa-util.c index 73f3be7d..cc65b8de 100644 --- a/polyp/alsa-util.c +++ b/polyp/alsa-util.c @@ -85,7 +85,7 @@ finish: * *io_events. Store the length of that array in *n_io_events. Use the * specified callback function and userdata. The array has to be freed * with pa_free_io_events(). */ -int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api* m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags events, void *userdata), void *userdata) { +int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api* m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata) { unsigned i; struct pollfd *pfds, *ppfd; pa_io_event **ios; diff --git a/polyp/alsa-util.h b/polyp/alsa-util.h index 787519f7..d180db3e 100644 --- a/polyp/alsa-util.h +++ b/polyp/alsa-util.h @@ -29,7 +29,7 @@ int pa_alsa_set_hw_params(snd_pcm_t *pcm_handle, const pa_sample_spec *ss, uint32_t *periods, snd_pcm_uframes_t *period_size); -int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api *m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags events, void *userdata), void *userdata); +int pa_create_io_events(snd_pcm_t *pcm_handle, pa_mainloop_api *m, pa_io_event ***io_events, unsigned *n_io_events, void (*cb)(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata), void *userdata); void pa_free_io_events(pa_mainloop_api* m, pa_io_event **io_sources, unsigned n_io_sources); #endif diff --git a/polyp/autoload.c b/polyp/autoload.c index 7e05c168..ff2916cb 100644 --- a/polyp/autoload.c +++ b/polyp/autoload.c @@ -81,7 +81,7 @@ static pa_autoload_entry* entry_new(pa_core *c, const char *name) { return e; } -int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type type, const char*module, const char *argument, uint32_t *idx) { +int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type_t type, const char*module, const char *argument, uint32_t *idx) { pa_autoload_entry *e = NULL; assert(c && name && module && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); @@ -98,7 +98,7 @@ int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type type, const cha return 0; } -int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type type) { +int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type_t type) { pa_autoload_entry *e; assert(c && name && type); @@ -120,7 +120,7 @@ int pa_autoload_remove_by_index(pa_core *c, uint32_t idx) { return 0; } -void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type type) { +void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type_t type) { pa_autoload_entry *e; pa_module *m; assert(c && name); @@ -159,7 +159,7 @@ void pa_autoload_free(pa_core *c) { } } -const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type type) { +const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type_t type) { pa_autoload_entry *e; assert(c && name); diff --git a/polyp/autoload.h b/polyp/autoload.h index 622a854e..7350c16a 100644 --- a/polyp/autoload.h +++ b/polyp/autoload.h @@ -34,7 +34,7 @@ typedef struct pa_autoload_entry { pa_core *core; uint32_t index; char *name; - pa_namereg_type type; /* Type of the autoload entry */ + pa_namereg_type_t type; /* Type of the autoload entry */ int in_action; /* Currently loaded */ char *module, *argument; } pa_autoload_entry; @@ -42,17 +42,17 @@ typedef struct pa_autoload_entry { /* Add a new autoload entry of the given time, with the speicified * sink/source name, module name and argument. Return the entry's * index in *index */ -int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type type, const char*module, const char *argument, uint32_t *idx); +int pa_autoload_add(pa_core *c, const char*name, pa_namereg_type_t type, const char*module, const char *argument, uint32_t *idx); /* Free all autoload entries */ void pa_autoload_free(pa_core *c); -int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type type); +int pa_autoload_remove_by_name(pa_core *c, const char*name, pa_namereg_type_t type); int pa_autoload_remove_by_index(pa_core *c, uint32_t idx); /* Request an autoload entry by its name, effectively causing a module to be loaded */ -void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type type); +void pa_autoload_request(pa_core *c, const char *name, pa_namereg_type_t type); -const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type type); +const pa_autoload_entry* pa_autoload_get_by_name(pa_core *c, const char*name, pa_namereg_type_t type); const pa_autoload_entry* pa_autoload_get_by_index(pa_core *c, uint32_t idx); #endif diff --git a/polyp/channelmap.c b/polyp/channelmap.c new file mode 100644 index 00000000..7bfd21e6 --- /dev/null +++ b/polyp/channelmap.c @@ -0,0 +1,202 @@ +/* $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 +#endif + +#include +#include +#include +#include + +#include "channelmap.h" + +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) { + assert(m); + assert(channels > 0); + assert(channels <= PA_CHANNELS_MAX); + + pa_channel_map_init(m); + + m->channels = channels; + + 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; + } +} + +const char* pa_channel_position_to_string(pa_channel_position_t pos) { + + 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_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" + }; + + 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%u:%s", + first ? "" : " ", + channel, + pa_channel_position_to_string(map->map[channel])); + + e = strchr(e, 0); + first = 0; + } + + return s; +} + +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/polyp/channelmap.h b/polyp/channelmap.h new file mode 100644 index 00000000..6466eecf --- /dev/null +++ b/polyp/channelmap.h @@ -0,0 +1,94 @@ +#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 +#include + +/** \file + * Constants and routines for channel mapping handling */ + +PA_C_DECL_BEGIN + +typedef enum { + PA_CHANNEL_POSITION_INVALID = -1, + PA_CHANNEL_POSITION_MONO = 0, + + PA_CHANNEL_POSITION_LEFT, + PA_CHANNEL_POSITION_RIGHT, + + PA_CHANNEL_POSITION_FRONT_CENTER, + PA_CHANNEL_POSITION_FRONT_LEFT = PA_CHANNEL_POSITION_LEFT, + PA_CHANNEL_POSITION_FRONT_RIGHT = PA_CHANNEL_POSITION_RIGHT, + + 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_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_MAX +} pa_channel_position_t; + +typedef struct pa_channel_map { + uint8_t channels; + pa_channel_position_t map[PA_CHANNELS_MAX]; +} pa_channel_map; + +pa_channel_map* pa_channel_map_init(pa_channel_map *m); +pa_channel_map* pa_channel_map_init_mono(pa_channel_map *m); +pa_channel_map* pa_channel_map_init_stereo(pa_channel_map *m); +pa_channel_map* pa_channel_map_init_auto(pa_channel_map *m, unsigned channels); + +const char* pa_channel_position_to_string(pa_channel_position_t pos); + +#define PA_CHANNEL_MAP_SNPRINT_MAX 64 +char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map); + +int pa_channel_map_equal(const pa_channel_map *a, const pa_channel_map *b); + +int pa_channel_map_valid(const pa_channel_map *map); + +PA_C_DECL_END + +#endif diff --git a/polyp/cli-command.c b/polyp/cli-command.c index 63241a81..f6192bf8 100644 --- a/polyp/cli-command.c +++ b/polyp/cli-command.c @@ -311,6 +311,7 @@ static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *bu const char *n, *v; pa_sink *sink; uint32_t volume; + pa_cvolume cvolume; if (!(n = pa_tokenizer_get(t, 1))) { pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n"); @@ -332,14 +333,16 @@ static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *bu return -1; } - pa_sink_set_volume(sink, (uint32_t) volume); + pa_cvolume_set(&cvolume, sink->sample_spec.channels, volume); + pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &cvolume); return 0; } static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { const char *n, *v; pa_sink_input *si; - uint32_t volume; + pa_volume_t volume; + pa_cvolume cvolume; uint32_t idx; if (!(n = pa_tokenizer_get(t, 1))) { @@ -367,7 +370,8 @@ static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strb return -1; } - pa_sink_input_set_volume(si, (uint32_t) volume); + pa_cvolume_set(&cvolume, si->sample_spec.channels, volume); + pa_sink_input_set_volume(si, &cvolume); return 0; } @@ -497,7 +501,7 @@ static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *bu return -1; } - if (pa_scache_play_item(c, n, sink, PA_VOLUME_NORM) < 0) { + if (pa_scache_play_item(c, n, sink, NULL) < 0) { pa_strbuf_puts(buf, "Failed to play sample.\n"); return -1; } @@ -576,7 +580,7 @@ static int pa_cli_command_play_file(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, } - return pa_play_file(sink, fname, PA_VOLUME_NORM); + return pa_play_file(sink, fname, NULL); } static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, int *fail) { @@ -663,9 +667,6 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G nl = 0; for (s = pa_idxset_first(c->sinks, &idx); s; s = pa_idxset_next(c->sinks, &idx)) { - if (s->volume == PA_VOLUME_NORM) - continue; - if (s->owner && s->owner->auto_unload) continue; @@ -673,8 +674,8 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G pa_strbuf_puts(buf, "\n"); nl = 1; } - - pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", s->name, s->volume); + + pa_strbuf_printf(buf, "set-sink-volume %s 0x%03x\n", s->name, pa_cvolume_avg(pa_sink_get_volume(s, PA_MIXER_HARDWARE))); } diff --git a/polyp/cli-text.c b/polyp/cli-text.c index a19bfc97..328aca4c 100644 --- a/polyp/cli-text.c +++ b/polyp/cli-text.c @@ -38,6 +38,7 @@ #include "scache.h" #include "autoload.h" #include "xmalloc.h" +#include "volume.h" char *pa_module_list_to_string(pa_core *c) { pa_strbuf *s; @@ -60,7 +61,6 @@ char *pa_client_list_to_string(pa_core *c) { pa_strbuf *s; pa_client *client; uint32_t idx = PA_IDXSET_INVALID; - char tid[5]; assert(c); s = pa_strbuf_new(); @@ -69,7 +69,7 @@ char *pa_client_list_to_string(pa_core *c) { pa_strbuf_printf(s, "%u client(s) logged in.\n", pa_idxset_size(c->clients)); for (client = pa_idxset_first(c->clients, &idx); client; client = pa_idxset_next(c->clients, &idx)) { - pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\ttype: <%s>\n", client->index, client->name, pa_typeid_to_string(client->typeid, tid, sizeof(tid))); + pa_strbuf_printf(s, " index: %u\n\tname: <%s>\n\tdriver: <%s>\n", client->index, client->name, client->driver); if (client->owner) pa_strbuf_printf(s, "\towner module: <%u>\n", client->owner->index); @@ -82,7 +82,6 @@ char *pa_sink_list_to_string(pa_core *c) { pa_strbuf *s; pa_sink *sink; uint32_t idx = PA_IDXSET_INVALID; - char tid[5]; assert(c); s = pa_strbuf_new(); @@ -91,20 +90,26 @@ char *pa_sink_list_to_string(pa_core *c) { pa_strbuf_printf(s, "%u sink(s) available.\n", pa_idxset_size(c->sinks)); for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) { - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; - pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec); - assert(sink->monitor_source); + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + pa_strbuf_printf( s, - " %c index: %u\n\tname: <%s>\n\ttype: <%s>\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%0.0f usec>\n\tmonitor_source: <%u>\n\tsample_spec: <%s>\n", + " %c index: %u\n" + "\tname: <%s>\n" + "\tdriver: <%s>\n" + "\tvolume: <%s>\n" + "\tlatency: <%0.0f usec>\n" + "\tmonitor_source: <%u>\n" + "\tsample spec: <%s>\n" + "\tchannel map: <%s>\n", c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ', sink->index, sink->name, - pa_typeid_to_string(sink->typeid, tid, sizeof(tid)), - (unsigned) sink->volume, - pa_volume_to_dB(sink->volume), + sink->driver, + pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, PA_MIXER_HARDWARE)), (double) pa_sink_get_latency(sink), sink->monitor_source->index, - ss); + pa_sample_spec_snprint(ss, sizeof(ss), &sink->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &sink->channel_map)); if (sink->owner) pa_strbuf_printf(s, "\towner module: <%u>\n", sink->owner->index); @@ -119,7 +124,6 @@ char *pa_source_list_to_string(pa_core *c) { pa_strbuf *s; pa_source *source; uint32_t idx = PA_IDXSET_INVALID; - char tid[5]; assert(c); s = pa_strbuf_new(); @@ -128,15 +132,24 @@ char *pa_source_list_to_string(pa_core *c) { pa_strbuf_printf(s, "%u source(s) available.\n", pa_idxset_size(c->sources)); for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) { - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; - pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec); - pa_strbuf_printf(s, " %c index: %u\n\tname: <%s>\n\ttype: <%s>\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n", - c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ', - source->index, - source->name, - pa_typeid_to_string(source->typeid, tid, sizeof(tid)), - (double) pa_source_get_latency(source), - ss); + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + + + pa_strbuf_printf( + s, + " %c index: %u\n" + "\tname: <%s>\n" + "\tdriver: <%s>\n" + "\tlatency: <%0.0f usec>\n" + "\tsample spec: <%s>\n" + "\tchannel map: <%s>\n", + c->default_source_name && !strcmp(source->name, c->default_source_name) ? '*' : ' ', + source->index, + source->name, + source->driver, + (double) pa_source_get_latency(source), + pa_sample_spec_snprint(ss, sizeof(ss), &source->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &source->channel_map)); if (source->monitor_of) pa_strbuf_printf(s, "\tmonitor_of: <%u>\n", source->monitor_of->index); @@ -154,7 +167,6 @@ char *pa_source_output_list_to_string(pa_core *c) { pa_strbuf *s; pa_source_output *o; uint32_t idx = PA_IDXSET_INVALID; - char tid[5]; static const char* const state_table[] = { "RUNNING", "CORKED", @@ -168,23 +180,28 @@ char *pa_source_output_list_to_string(pa_core *c) { pa_strbuf_printf(s, "%u source outputs(s) available.\n", pa_idxset_size(c->source_outputs)); for (o = pa_idxset_first(c->source_outputs, &idx); o; o = pa_idxset_next(c->source_outputs, &idx)) { - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; - const char *rm; - pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec); + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + assert(o->source); - - if (!(rm = pa_resample_method_to_string(pa_source_output_get_resample_method(o)))) - rm = "invalid"; pa_strbuf_printf( - s, " index: %u\n\tname: '%s'\n\ttype: <%s>\n\tstate: %s\n\tsource: <%u> '%s'\n\tsample_spec: <%s>\n\tresample method: %s\n", + s, + " index: %u\n" + "\tname: '%s'\n" + "\tdriver: <%s>\n" + "\tstate: %s\n" + "\tsource: <%u> '%s'\n" + "\tsample spec: <%s>\n" + "\tchannel map: <%s>\n" + "\tresample method: %s\n", o->index, o->name, - pa_typeid_to_string(o->typeid, tid, sizeof(tid)), + o->driver, state_table[o->state], o->source->index, o->source->name, - ss, - rm); + pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &o->channel_map), + pa_resample_method_to_string(pa_source_output_get_resample_method(o))); if (o->owner) pa_strbuf_printf(s, "\towner module: <%u>\n", o->owner->index); if (o->client) @@ -198,7 +215,6 @@ char *pa_sink_input_list_to_string(pa_core *c) { pa_strbuf *s; pa_sink_input *i; uint32_t idx = PA_IDXSET_INVALID; - char tid[5]; static const char* const state_table[] = { "RUNNING", "CORKED", @@ -212,26 +228,32 @@ char *pa_sink_input_list_to_string(pa_core *c) { pa_strbuf_printf(s, "%u sink input(s) available.\n", pa_idxset_size(c->sink_inputs)); for (i = pa_idxset_first(c->sink_inputs, &idx); i; i = pa_idxset_next(c->sink_inputs, &idx)) { - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; - const char *rm; - - if (!(rm = pa_resample_method_to_string(pa_sink_input_get_resample_method(i)))) - rm = "invalid"; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; - pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec); assert(i->sink); + pa_strbuf_printf( - s, " index: %u\n\tname: <%s>\n\ttype: <%s>\n\tstate: %s\n\tsink: <%u> '%s'\n\tvolume: <0x%04x> (%0.2fdB)\n\tlatency: <%0.0f usec>\n\tsample_spec: <%s>\n\tresample method: %s\n", + s, + " index: %u\n" + "\tname: <%s>\n" + "\tdriver: <%s>\n" + "\tstate: %s\n" + "\tsink: <%u> '%s'\n" + "\tvolume: <%s>\n" + "\tlatency: <%0.0f usec>\n" + "\tsample spec: <%s>\n" + "\tchannel map: <%s>\n" + "\tresample method: %s\n", i->index, i->name, - pa_typeid_to_string(i->typeid, tid, sizeof(tid)), + i->driver, state_table[i->state], i->sink->index, i->sink->name, - (unsigned) i->volume, - pa_volume_to_dB(i->volume), + pa_cvolume_snprint(cv, sizeof(cv), pa_sink_input_get_volume(i)), (double) pa_sink_input_get_latency(i), - ss, - rm); + pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), + pa_resample_method_to_string(pa_sink_input_get_resample_method(i))); if (i->owner) pa_strbuf_printf(s, "\towner module: <%u>\n", i->owner->index); @@ -257,21 +279,32 @@ char *pa_scache_list_to_string(pa_core *c) { for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) { double l = 0; - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = "n/a"; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = "n/a", cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; if (e->memchunk.memblock) { pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec); + pa_channel_map_snprint(cm, sizeof(cm), &e->channel_map); l = (double) e->memchunk.length / pa_bytes_per_second(&e->sample_spec); } pa_strbuf_printf( - s, " name: <%s>\n\tindex: <%u>\n\tsample_spec: <%s>\n\tlength: <%u>\n\tduration: <%0.1fs>\n\tvolume: <0x%04x>\n\tlazy: %s\n\tfilename: %s\n", + s, + " name: <%s>\n" + "\tindex: <%u>\n" + "\tsample spec: <%s>\n" + "\tchannel map: <%s>\n" + "\tlength: <%u>\n" + "\tduration: <%0.1fs>\n" + "\tvolume: <%s>\n" + "\tlazy: %s\n" + "\tfilename: %s\n", e->name, e->index, ss, + cm, e->memchunk.memblock ? e->memchunk.length : 0, l, - e->volume, + pa_cvolume_snprint(cv, sizeof(cv), &e->volume), e->lazy ? "yes" : "no", e->filename ? e->filename : "n/a"); } diff --git a/polyp/cli.c b/polyp/cli.c index 7b1022c1..bc0c285d 100644 --- a/polyp/cli.c +++ b/polyp/cli.c @@ -45,7 +45,6 @@ #include "log.h" #define PROMPT ">>> " -#define PA_TYPEID_CLI PA_TYPEID_MAKE('C', 'L', 'I', '_') struct pa_cli { pa_core *core; @@ -76,7 +75,7 @@ pa_cli* pa_cli_new(pa_core *core, pa_iochannel *io, pa_module *m) { c->eof_callback = NULL; pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); - c->client = pa_client_new(core, PA_TYPEID_CLI, cname); + c->client = pa_client_new(core, __FILE__, cname); assert(c->client); c->client->kill = client_kill; c->client->userdata = c; diff --git a/polyp/client.c b/polyp/client.c index 1938a4e0..3c2084bf 100644 --- a/polyp/client.c +++ b/polyp/client.c @@ -33,16 +33,16 @@ #include "subscribe.h" #include "log.h" -pa_client *pa_client_new(pa_core *core, pa_typeid_t typeid, const char *name) { +pa_client *pa_client_new(pa_core *core, const char *name, const char *driver) { pa_client *c; int r; assert(core); c = pa_xmalloc(sizeof(pa_client)); c->name = pa_xstrdup(name); + c->driver = pa_xstrdup(driver); c->owner = NULL; c->core = core; - c->typeid = typeid; c->kill = NULL; c->userdata = NULL; @@ -68,8 +68,8 @@ void pa_client_free(pa_client *c) { pa_log_info(__FILE__": freed %u \"%s\"\n", c->index, c->name); pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index); pa_xfree(c->name); + pa_xfree(c->driver); pa_xfree(c); - } void pa_client_kill(pa_client *c) { diff --git a/polyp/client.h b/polyp/client.h index 198dbbf6..92430338 100644 --- a/polyp/client.h +++ b/polyp/client.h @@ -24,7 +24,6 @@ #include "core.h" #include "module.h" -#include "typeid.h" /* Every connection to the server should have a pa_client * attached. That way the user may generate a listing of all connected @@ -34,17 +33,16 @@ typedef struct pa_client pa_client; struct pa_client { uint32_t index; - pa_typeid_t typeid; pa_module *owner; - char *name; + char *name, *driver; pa_core *core; void (*kill)(pa_client *c); void *userdata; }; -pa_client *pa_client_new(pa_core *c, pa_typeid_t typeid, const char *name); +pa_client *pa_client_new(pa_core *c, const char *name, const char *driver); /* This function should be called only by the code that created the client */ void pa_client_free(pa_client *c); diff --git a/polyp/core.h b/polyp/core.h index 704246a9..9241fcd8 100644 --- a/polyp/core.h +++ b/polyp/core.h @@ -70,7 +70,7 @@ struct pa_core { pa_time_event *scache_auto_unload_event; - pa_resample_method resample_method; + pa_resample_method_t resample_method; }; pa_core* pa_core_new(pa_mainloop_api *m); diff --git a/polyp/daemon-conf.c b/polyp/daemon-conf.c index 4ad78bab..103cf46a 100644 --- a/polyp/daemon-conf.c +++ b/polyp/daemon-conf.c @@ -126,7 +126,7 @@ int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string) { if (u >= PA_LOG_LEVEL_MAX) return -1; - c->log_level = (pa_log_level) u; + c->log_level = (pa_log_level_t) u; } else if (pa_startswith(string, "debug")) c->log_level = PA_LOG_DEBUG; else if (pa_startswith(string, "info")) diff --git a/polyp/daemon-conf.h b/polyp/daemon-conf.h index 4eb61365..cebc0bd6 100644 --- a/polyp/daemon-conf.h +++ b/polyp/daemon-conf.h @@ -33,11 +33,11 @@ typedef enum pa_daemon_conf_cmd { PA_CMD_DUMP_MODULES, PA_CMD_KILL, PA_CMD_CHECK -} pa_daemon_conf_cmd; +} pa_daemon_conf_cmd_t; /* A structure containing configuration data for the Polypaudio server . */ typedef struct pa_daemon_conf { - pa_daemon_conf_cmd cmd; + pa_daemon_conf_cmd_t cmd; int daemonize, fail, high_priority, @@ -48,8 +48,8 @@ typedef struct pa_daemon_conf { auto_log_target, use_pid_file; char *script_commands, *dl_search_path, *default_script_file; - pa_log_target log_target; - pa_log_level log_level; + pa_log_target_t log_target; + pa_log_level_t log_level; int resample_method; char *config_file; } pa_daemon_conf; diff --git a/polyp/dllmain.c b/polyp/dllmain.c index 34d0eed1..d1d120ab 100644 --- a/polyp/dllmain.c +++ b/polyp/dllmain.c @@ -1,4 +1,4 @@ -/* $Id: dllmain.c 317 2004-12-11 00:10:41Z lennart $ */ +/* $Id$ */ /*** This file is part of polypaudio. diff --git a/polyp/glib-mainloop.c b/polyp/glib-mainloop.c index 6552da15..6f7c1dc5 100644 --- a/polyp/glib-mainloop.c +++ b/polyp/glib-mainloop.c @@ -38,9 +38,9 @@ struct pa_io_event { GSource *source; GIOCondition io_condition; int fd; - void (*callback) (pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata); + 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); + void (*destroy_callback) (pa_mainloop_api *m, pa_io_event *e, void *userdata); pa_io_event *next, *prev; }; @@ -76,9 +76,9 @@ struct pa_glib_mainloop { static void schedule_free_dead_events(pa_glib_mainloop *g); -static void glib_io_enable(pa_io_event*e, pa_io_event_flags f); +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 f, void (*callback) (pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags f, void *userdata), void *userdata) { +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; @@ -111,7 +111,7 @@ static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags f, /* 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 f; + pa_io_event_flags_t f; assert(source && e && e->io_channel == source); f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | @@ -123,7 +123,7 @@ static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) return TRUE; } -static void glib_io_enable(pa_io_event*e, pa_io_event_flags f) { +static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) { GIOCondition c; assert(e && !e->dead); diff --git a/polyp/glib12-mainloop.c b/polyp/glib12-mainloop.c index e322ac07..8bc4483b 100644 --- a/polyp/glib12-mainloop.c +++ b/polyp/glib12-mainloop.c @@ -39,7 +39,7 @@ struct pa_io_event { guint source; GIOCondition io_condition; int fd; - void (*callback) (pa_mainloop_api*m, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata); + 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; @@ -76,9 +76,9 @@ struct pa_glib_mainloop { static void schedule_free_dead_events(pa_glib_mainloop *g); -static void glib_io_enable(pa_io_event*e, pa_io_event_flags f); +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 f, void (*callback) (pa_mainloop_api*m, pa_io_event*e, int fd, pa_io_event_flags f, void *userdata), void *userdata) { +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; @@ -110,7 +110,7 @@ static pa_io_event* glib_io_new(pa_mainloop_api*m, int fd, pa_io_event_flags f, static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) { pa_io_event *e = data; - pa_io_event_flags f; + pa_io_event_flags_t f; assert(source && e && e->io_channel == source); f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | @@ -122,7 +122,7 @@ static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) return TRUE; } -static void glib_io_enable(pa_io_event*e, pa_io_event_flags f) { +static void glib_io_enable(pa_io_event*e, pa_io_event_flags_t f) { GIOCondition c; assert(e && !e->dead); diff --git a/polyp/inet_ntop.c b/polyp/inet_ntop.c index ac2b5295..a25c3c95 100644 --- a/polyp/inet_ntop.c +++ b/polyp/inet_ntop.c @@ -1,4 +1,4 @@ -/* $Id: inet_ntop.c 428 2006-01-09 16:50:39Z ossman $ */ +/* $Id$ */ /*** This file is part of polypaudio. diff --git a/polyp/iochannel.c b/polyp/iochannel.c index e6271319..273d47e0 100644 --- a/polyp/iochannel.c +++ b/polyp/iochannel.c @@ -55,7 +55,7 @@ static void enable_mainloop_sources(pa_iochannel *io) { assert(io); if (io->input_event == io->output_event && io->input_event) { - pa_io_event_flags f = PA_IO_EVENT_NULL; + pa_io_event_flags_t f = PA_IO_EVENT_NULL; assert(io->input_event); if (!io->readable) @@ -72,7 +72,7 @@ static void enable_mainloop_sources(pa_iochannel *io) { } } -static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata) { +static void callback(pa_mainloop_api* m, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { pa_iochannel *io = userdata; int changed = 0; diff --git a/polyp/log.c b/polyp/log.c index c41fbbae..97406f79 100644 --- a/polyp/log.c +++ b/polyp/log.c @@ -38,9 +38,9 @@ #define ENV_LOGLEVEL "POLYP_LOG" static char *log_ident = NULL; -static pa_log_target log_target = PA_LOG_STDERR; -static void (*user_log_func)(pa_log_level l, const char *s) = NULL; -static pa_log_level maximal_level = PA_LOG_NOTICE; +static pa_log_target_t log_target = PA_LOG_STDERR; +static void (*user_log_func)(pa_log_level_t l, const char *s) = NULL; +static pa_log_level_t maximal_level = PA_LOG_NOTICE; #ifdef HAVE_SYSLOG_H static const int level_to_syslog[] = { @@ -59,18 +59,18 @@ void pa_log_set_ident(const char *p) { log_ident = pa_xstrdup(p); } -void pa_log_set_maximal_level(pa_log_level l) { +void pa_log_set_maximal_level(pa_log_level_t l) { assert(l < PA_LOG_LEVEL_MAX); maximal_level = l; } -void pa_log_set_target(pa_log_target t, void (*func)(pa_log_level l, const char*s)) { +void pa_log_set_target(pa_log_target_t t, void (*func)(pa_log_level_t l, const char*s)) { assert(t == PA_LOG_USER || !func); log_target = t; user_log_func = func; } -void pa_log_with_levelv(pa_log_level level, const char *format, va_list ap) { +void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap) { const char *e; assert(level < PA_LOG_LEVEL_MAX); @@ -107,44 +107,44 @@ void pa_log_with_levelv(pa_log_level level, const char *format, va_list ap) { } -void pa_log_with_level(pa_log_level level, const char *format, ...) { +void pa_log_level(pa_log_level_t level, const char *format, ...) { va_list ap; va_start(ap, format); - pa_log_with_levelv(level, format, ap); + pa_log_levelv(level, format, ap); va_end(ap); } void pa_log_debug(const char *format, ...) { va_list ap; va_start(ap, format); - pa_log_with_levelv(PA_LOG_DEBUG, format, ap); + pa_log_levelv(PA_LOG_DEBUG, format, ap); va_end(ap); } void pa_log_info(const char *format, ...) { va_list ap; va_start(ap, format); - pa_log_with_levelv(PA_LOG_INFO, format, ap); + pa_log_levelv(PA_LOG_INFO, format, ap); va_end(ap); } void pa_log_notice(const char *format, ...) { va_list ap; va_start(ap, format); - pa_log_with_levelv(PA_LOG_INFO, format, ap); + pa_log_levelv(PA_LOG_INFO, format, ap); va_end(ap); } void pa_log_warn(const char *format, ...) { va_list ap; va_start(ap, format); - pa_log_with_levelv(PA_LOG_WARN, format, ap); + pa_log_levelv(PA_LOG_WARN, format, ap); va_end(ap); } void pa_log_error(const char *format, ...) { va_list ap; va_start(ap, format); - pa_log_with_levelv(PA_LOG_ERROR, format, ap); + pa_log_levelv(PA_LOG_ERROR, format, ap); va_end(ap); } diff --git a/polyp/log.h b/polyp/log.h index 7c6a8e61..ce8aea98 100644 --- a/polyp/log.h +++ b/polyp/log.h @@ -33,7 +33,7 @@ typedef enum pa_log_target { PA_LOG_SYSLOG, PA_LOG_USER, /* to user specified function */ PA_LOG_NULL /* to /dev/null */ -} pa_log_target; +} pa_log_target_t; typedef enum pa_log_level { PA_LOG_ERROR = 0, /* Error messages */ @@ -42,16 +42,16 @@ typedef enum pa_log_level { PA_LOG_INFO = 3, /* Info messages */ PA_LOG_DEBUG = 4, /* debug message */ PA_LOG_LEVEL_MAX -} pa_log_level; +} pa_log_level_t; /* Set an identification for the current daemon. Used when logging to syslog. */ void pa_log_set_ident(const char *p); /* Set another log target. If t is PA_LOG_USER you may specify a function that is called every log string */ -void pa_log_set_target(pa_log_target t, void (*func)(pa_log_level, const char*s)); +void pa_log_set_target(pa_log_target_t t, void (*func)(pa_log_level_t t, const char*s)); /* Minimal log level */ -void pa_log_set_maximal_level(pa_log_level l); +void pa_log_set_maximal_level(pa_log_level_t l); /* Do a log line */ void pa_log_debug(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); @@ -60,9 +60,9 @@ void pa_log_notice(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); void pa_log_warn(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); void pa_log_error(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); -void pa_log_with_level(pa_log_level level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); +void pa_log_level(pa_log_level_t level, const char *format, ...) PA_GCC_PRINTF_ATTR(2,3); -void pa_log_with_levelv(pa_log_level level, const char *format, va_list ap); +void pa_log_levelv(pa_log_level_t level, const char *format, va_list ap); #define pa_log pa_log_error diff --git a/polyp/main.c b/polyp/main.c index 1c3b566d..c984e28e 100644 --- a/polyp/main.c +++ b/polyp/main.c @@ -37,6 +37,7 @@ #include #include #include +#include #ifdef HAVE_SYS_IOCTL_H #include @@ -386,6 +387,8 @@ int main(int argc, char *argv[]) { pa_signal_new(SIGHUP, signal_callback, c); #endif + oil_init(); + r = pa_cpu_limit_init(pa_mainloop_get_api(mainloop)); assert(r == 0); diff --git a/polyp/mainloop-api.h b/polyp/mainloop-api.h index 1604e740..91ee4111 100644 --- a/polyp/mainloop-api.h +++ b/polyp/mainloop-api.h @@ -51,7 +51,7 @@ typedef enum pa_io_event_flags { 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; +} pa_io_event_flags_t; /** \pa_io_event * An opaque IO event source object */ @@ -73,10 +73,10 @@ struct pa_mainloop_api { void *userdata; /** Create a new IO event source object */ - pa_io_event* (*io_new)(pa_mainloop_api*a, int fd, pa_io_event_flags events, void (*callback) (pa_mainloop_api*a, pa_io_event* e, int fd, pa_io_event_flags events, void *userdata), void *userdata); + 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 events); + 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); diff --git a/polyp/mainloop-signal.c b/polyp/mainloop-signal.c index f225e60b..76936031 100644 --- a/polyp/mainloop-signal.c +++ b/polyp/mainloop-signal.c @@ -119,7 +119,7 @@ static void defer(pa_mainloop_api*a, PA_GCC_UNUSED pa_defer_event*e, PA_GCC_UNUS } } -static void callback(pa_mainloop_api*a, pa_io_event*e, int fd, pa_io_event_flags f, PA_GCC_UNUSED void *userdata) { +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]); diff --git a/polyp/mainloop-test.c b/polyp/mainloop-test.c index 097ce1c7..ee0f8711 100644 --- a/polyp/mainloop-test.c +++ b/polyp/mainloop-test.c @@ -51,7 +51,7 @@ static GMainLoop* glib_main_loop = NULL; static pa_defer_event *de; -static void iocb(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata) { +static void iocb(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { unsigned char c; read(fd, &c, sizeof(c)); fprintf(stderr, "IO EVENT: %c\n", c < 32 ? '.' : c); diff --git a/polyp/mainloop.c b/polyp/mainloop.c index 599a90f8..26ba2425 100644 --- a/polyp/mainloop.c +++ b/polyp/mainloop.c @@ -50,8 +50,8 @@ struct pa_io_event { pa_mainloop *mainloop; int dead; int fd; - pa_io_event_flags events; - void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata); + 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); @@ -91,7 +91,13 @@ struct pa_mainloop { }; /* IO events */ -static pa_io_event* mainloop_io_new(pa_mainloop_api*a, int fd, pa_io_event_flags events, void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags events, void *userdata), void *userdata) { +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; @@ -135,7 +141,7 @@ static pa_io_event* mainloop_io_new(pa_mainloop_api*a, int fd, pa_io_event_flags return e; } -static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags events) { +static void mainloop_io_enable(pa_io_event *e, pa_io_event_flags_t events) { assert(e && e->mainloop); e->events = events; diff --git a/polyp/memblock.h b/polyp/memblock.h index cbf5d684..c5751406 100644 --- a/polyp/memblock.h +++ b/polyp/memblock.h @@ -31,12 +31,12 @@ * memory blocks. */ /* The type of memory this block points to */ -typedef enum { +typedef enum pa_memblock_type { PA_MEMBLOCK_FIXED, /* data is a pointer to fixed memory that needs not to be freed */ PA_MEMBLOCK_APPENDED, /* The most common kind: the data is appended to the memory block */ PA_MEMBLOCK_DYNAMIC, /* data is a pointer to some memory allocated with pa_xmalloc() */ PA_MEMBLOCK_USER /* User supplied memory, to be freed with free_cb */ -} pa_memblock_type ; +} pa_memblock_type_t; /* A structure of keeping memory block statistics */ /* Maintains statistics about memory blocks */ @@ -49,7 +49,7 @@ typedef struct pa_memblock_stat { } pa_memblock_stat; typedef struct pa_memblock { - pa_memblock_type type; + pa_memblock_type_t type; unsigned ref; /* the reference counter */ int read_only; /* boolean */ size_t length; diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index 14070d63..ea6ca424 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -51,8 +51,6 @@ PA_MODULE_DESCRIPTION("ALSA Sink") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("sink_name= device= format= channels= rate= fragments= fragment_size=") -#define PA_TYPEID_ALSA PA_TYPEID_MAKE('A', 'L', 'S', 'A') - struct userdata { snd_pcm_t *pcm_handle; pa_sink *sink; @@ -142,7 +140,7 @@ static void do_write(struct userdata *u) { } } -static void io_callback(pa_mainloop_api*a, pa_io_event *e, PA_GCC_UNUSED int fd, PA_GCC_UNUSED pa_io_event_flags f, void *userdata) { +static void io_callback(pa_mainloop_api*a, pa_io_event *e, PA_GCC_UNUSED int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { struct userdata *u = userdata; assert(u && a && e); @@ -220,7 +218,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - u->sink = pa_sink_new(c, PA_TYPEID_ALSA, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss); + u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; @@ -236,7 +234,7 @@ int pa__init(pa_core *c, pa_module*m) { u->frame_size = frame_size; u->fragment_size = period_size; - pa_log(__FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); + pa_log_info(__FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); u->silence.memblock = pa_memblock_new(u->silence.length = u->fragment_size, c->memblock_stat); assert(u->silence.memblock); diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index 4ad8dd84..2aa47aad 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.c @@ -51,8 +51,6 @@ PA_MODULE_DESCRIPTION("ALSA Source") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("source_name= device= format= channels= rate= fragments= fragment_size=") -#define PA_TYPEID_ALSA PA_TYPEID_MAKE('A', 'L', 'S', 'A') - struct userdata { snd_pcm_t *pcm_handle; pa_source *source; @@ -142,7 +140,7 @@ static void do_read(struct userdata *u) { } } -static void io_callback(pa_mainloop_api*a, pa_io_event *e, PA_GCC_UNUSED int fd, PA_GCC_UNUSED pa_io_event_flags f, void *userdata) { +static void io_callback(pa_mainloop_api*a, pa_io_event *e, PA_GCC_UNUSED int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { struct userdata *u = userdata; assert(u && a && e); @@ -211,7 +209,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - u->source = pa_source_new(c, PA_TYPEID_ALSA, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); + u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); assert(u->source); u->source->userdata = u; diff --git a/polyp/module-combine.c b/polyp/module-combine.c index cee0a5dc..0c21c2f5 100644 --- a/polyp/module-combine.c +++ b/polyp/module-combine.c @@ -43,8 +43,6 @@ PA_MODULE_DESCRIPTION("Combine multiple sinks to one") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("sink_name= master= slaves= adjust_time= resample_method=") -#define PA_TYPEID_COMBINE PA_TYPEID_MAKE('C', 'M', 'B', 'N') - #define DEFAULT_SINK_NAME "combined" #define MEMBLOCKQ_MAXLENGTH (1024*170) #define RENDER_SIZE (1024*10) @@ -216,7 +214,7 @@ static struct output *output_new(struct userdata *u, pa_sink *sink, int resample o->memblockq = pa_memblockq_new(MEMBLOCKQ_MAXLENGTH, MEMBLOCKQ_MAXLENGTH, pa_frame_size(&u->sink->sample_spec), 0, 0, sink->core->memblock_stat); snprintf(t, sizeof(t), "%s: output #%u", u->sink->name, u->n_outputs+1); - if (!(o->sink_input = pa_sink_input_new(sink, PA_TYPEID_COMBINE, t, &u->sink->sample_spec, 1, resample_method))) + if (!(o->sink_input = pa_sink_input_new(sink, __FILE__, t, &u->sink->sample_spec, &u->sink->channel_map, 1, resample_method))) goto fail; o->sink_input->get_latency = sink_input_get_latency_cb; @@ -327,7 +325,7 @@ int pa__init(pa_core *c, pa_module*m) { goto fail; } - if (!(u->sink = pa_sink_new(c, PA_TYPEID_COMBINE, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &master_sink->sample_spec))) { + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &master_sink->sample_spec, &master_sink->channel_map))) { pa_log(__FILE__": failed to create sink\n"); goto fail; } diff --git a/polyp/module-esound-sink.c b/polyp/module-esound-sink.c index ac211a31..afd5feed 100644 --- a/polyp/module-esound-sink.c +++ b/polyp/module-esound-sink.c @@ -46,14 +46,12 @@ #include "authkey.h" PA_MODULE_AUTHOR("Lennart Poettering") -PA_MODULE_DESCRIPTION("Esound ") +PA_MODULE_DESCRIPTION("ESOUND Sink") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("sink_name= server=
cookie= format= channels= rate=") #define DEFAULT_SINK_NAME "esound_output" -#define PA_TYPEID_ESOUND_SINK PA_TYPEID_MAKE('E', 'S', 'D', 'S') - struct userdata { pa_core *core; @@ -354,7 +352,7 @@ int pa__init(pa_core *c, pa_module*m) { u->state = STATE_AUTH; u->latency = 0; - if (!(u->sink = pa_sink_new(c, PA_TYPEID_ESOUND_SINK, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { pa_log(__FILE__": failed to create sink.\n"); goto fail; } diff --git a/polyp/module-lirc.c b/polyp/module-lirc.c index eb71c47f..d2e248aa 100644 --- a/polyp/module-lirc.c +++ b/polyp/module-lirc.c @@ -61,7 +61,7 @@ struct userdata { static int lirc_in_use = 0; -static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags events, void*userdata) { +static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void*userdata) { struct userdata *u = userdata; char *name = NULL, *code = NULL; assert(io); @@ -109,26 +109,45 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) pa_log(__FILE__": failed to get sink '%s'\n", u->sink_name); else { - double v = pa_volume_to_user(s->volume); - + pa_volume_t v = pa_cvolume_avg(pa_sink_get_volume(s, PA_MIXER_HARDWARE)); + pa_cvolume cv; +#define DELTA (PA_VOLUME_NORM/20) + switch (volchange) { - case UP: v += .05; break; - case DOWN: v -= .05; break; - case MUTE: v = 0; break; - case RESET: v = 1; break; + case UP: + v += PA_VOLUME_NORM/20; + break; + + case DOWN: + if (v > DELTA) + v -= DELTA; + else + v = PA_VOLUME_MUTED; + + break; + + case MUTE: + v = PA_VOLUME_MUTED; + break; + + case RESET: + v = PA_VOLUME_NORM; + break; + case MUTE_TOGGLE: { if (v > 0) { u->mute_toggle_save = v; - v = 0; + v = PA_VOLUME_MUTED; } else v = u->mute_toggle_save; } default: ; } - - pa_sink_set_volume(s, pa_volume_from_user(v)); + + pa_cvolume_set(&cv, PA_CHANNELS_MAX, v); + pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); } } } diff --git a/polyp/module-match.c b/polyp/module-match.c index e48d55ca..e3e7b17d 100644 --- a/polyp/module-match.c +++ b/polyp/module-match.c @@ -154,7 +154,7 @@ finish: return ret; } -static void callback(pa_core *c, pa_subscription_event_type t, uint32_t idx, void *userdata) { +static void callback(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) { struct userdata *u = userdata; pa_sink_input *si; struct rule *r; @@ -171,8 +171,10 @@ static void callback(pa_core *c, pa_subscription_event_type t, uint32_t idx, voi for (r = u->rules; r; r = r->next) { if (!regexec(&r->regex, si->name, 0, NULL, 0)) { + pa_cvolume cv; pa_log_debug(__FILE__": changing volume of sink input '%s' to 0x%03x\n", si->name, r->volume); - pa_sink_input_set_volume(si, r->volume); + pa_cvolume_set(&cv, r->volume, si->sample_spec.channels); + pa_sink_input_set_volume(si, &cv); } } } diff --git a/polyp/module-mmkbd-evdev.c b/polyp/module-mmkbd-evdev.c index 5eb55e35..ec45ec4b 100644 --- a/polyp/module-mmkbd-evdev.c +++ b/polyp/module-mmkbd-evdev.c @@ -74,7 +74,7 @@ struct userdata { float mute_toggle_save; }; -static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags events, void*userdata) { +static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags_t events, void*userdata) { struct userdata *u = userdata; assert(io); assert(u); @@ -109,16 +109,28 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC if (!(s = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, 1))) pa_log(__FILE__": failed to get sink '%s'\n", u->sink_name); else { - double v = pa_volume_to_user(s->volume); + pa_volume_t v = pa_cvolume_avg(pa_sink_get_volume(s, PA_MIXER_HARDWARE)); + pa_cvolume cv; +#define DELTA (PA_VOLUME_NORM/20) switch (volchange) { - case UP: v += .05; break; - case DOWN: v -= .05; break; + case UP: + v += DELTA; + break; + + case DOWN: + if (v > DELTA) + v -= DELTA; + else + v = PA_VOLUME_MUTED; + + break; + case MUTE_TOGGLE: { if (v > 0) { u->mute_toggle_save = v; - v = 0; + v = PA_VOLUME_MUTED; } else v = u->mute_toggle_save; } @@ -126,7 +138,8 @@ static void io_callback(pa_mainloop_api *io, PA_GCC_UNUSED pa_io_event *e, PA_GC ; } - pa_sink_set_volume(s, pa_volume_from_user(v)); + pa_cvolume_set(&cv, PA_CHANNELS_MAX, v); + pa_sink_set_volume(s, PA_MIXER_HARDWARE, &cv); } } } diff --git a/polyp/module-null-sink.c b/polyp/module-null-sink.c index b26ea50b..93abca78 100644 --- a/polyp/module-null-sink.c +++ b/polyp/module-null-sink.c @@ -49,8 +49,6 @@ PA_MODULE_USAGE("format= channels= rate=module = m; m->userdata = u; - if (!(u->sink = pa_sink_new(c, PA_TYPEID_NULL, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { pa_log(__FILE__": failed to create sink.\n"); goto fail; } diff --git a/polyp/module-oss-mmap.c b/polyp/module-oss-mmap.c index ac510f96..f976cf81 100644 --- a/polyp/module-oss-mmap.c +++ b/polyp/module-oss-mmap.c @@ -53,8 +53,6 @@ PA_MODULE_DESCRIPTION("OSS Sink/Source (mmap)") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("sink_name= source_name= device= record= playback= format= channels= rate= fragments= fragment_size=") -#define PA_TYPEID_OSS_MMAP PA_TYPEID_MAKE('O', 'S', 'S', 'M') - struct userdata { pa_sink *sink; pa_source *source; @@ -204,7 +202,7 @@ static void do_read(struct userdata *u) { in_clear_memblocks(u, u->in_fragments/2); } -static void io_callback(pa_mainloop_api *m, pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags f, void *userdata) { +static void io_callback(pa_mainloop_api *m, pa_io_event *e, PA_GCC_UNUSED int fd, pa_io_event_flags_t f, void *userdata) { struct userdata *u = userdata; assert (u && u->core->mainloop == m && u->io_event == e); @@ -304,7 +302,7 @@ int pa__init(pa_core *c, pa_module*m) { } } else { - u->source = pa_source_new(c, PA_TYPEID_OSS_MMAP, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &u->sample_spec); + u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &u->sample_spec, NULL); assert(u->source); u->source->userdata = u; pa_source_set_owner(u->source, m); @@ -336,7 +334,7 @@ int pa__init(pa_core *c, pa_module*m) { } else { pa_silence_memory(u->out_mmap, u->out_mmap_length, &u->sample_spec); - u->sink = pa_sink_new(c, PA_TYPEID_OSS_MMAP, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &u->sample_spec); + u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &u->sample_spec, NULL); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; u->sink->userdata = u; diff --git a/polyp/module-oss.c b/polyp/module-oss.c index 06679a97..b5c7ae8c 100644 --- a/polyp/module-oss.c +++ b/polyp/module-oss.c @@ -52,8 +52,6 @@ PA_MODULE_DESCRIPTION("OSS Sink/Source") PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_USAGE("sink_name= source_name= device= record= playback= format= channels= rate= fragments= fragment_size=") -#define PA_TYPEID_OSS PA_TYPEID_MAKE('O', 'S', 'S', '_') - struct userdata { pa_sink *sink; pa_source *source; @@ -222,7 +220,7 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) { assert(s && u && u->sink); if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { - pa_log_info(__FILE__": device doesn't support SNDCTL_DSP_GETODELAY.\n"); + pa_log_info(__FILE__": device doesn't support SNDCTL_DSP_GETODELAY: %s\n", strerror(errno)); s->get_latency = NULL; return 0; } @@ -254,6 +252,46 @@ static pa_usec_t source_get_latency_cb(pa_source *s) { return pa_bytes_to_usec(info.bytes, &s->sample_spec); } +static int sink_get_hw_volume(pa_sink *s) { + struct userdata *u = s->userdata; + char cv[PA_CVOLUME_SNPRINT_MAX]; + unsigned vol; + + if (ioctl(u->fd, SOUND_MIXER_READ_PCM, &vol) < 0) { + pa_log_info(__FILE__": device doesn't support reading mixer settings: %s\n", strerror(errno)); + s->get_hw_volume = NULL; + return -1; + } + + s->hw_volume.values[0] = ((vol & 0xFF) * PA_VOLUME_NORM) / 100; + + if ((s->hw_volume.channels = s->sample_spec.channels) >= 2) + s->hw_volume.values[1] = (((vol >> 8) & 0xFF) * PA_VOLUME_NORM) / 100; + + pa_log_info(__FILE__": Read mixer settings: %s\n", pa_cvolume_snprint(cv, sizeof(cv), &s->hw_volume)); + return 0; +} + +static int sink_set_hw_volume(pa_sink *s) { + struct userdata *u = s->userdata; + char cv[PA_CVOLUME_SNPRINT_MAX]; + unsigned vol; + + vol = (s->hw_volume.values[0]*100)/PA_VOLUME_NORM; + + if (s->sample_spec.channels >= 2) + vol |= ((s->hw_volume.values[1]*100)/PA_VOLUME_NORM) << 8; + + if (ioctl(u->fd, SOUND_MIXER_WRITE_PCM, &vol) < 0) { + pa_log_info(__FILE__": device doesn't support writing mixer settings: %s\n", strerror(errno)); + s->set_hw_volume = NULL; + return -1; + } + + pa_log_info(__FILE__": Wrote mixer settings: %s\n", pa_cvolume_snprint(cv, sizeof(cv), &s->hw_volume)); + return 0; +} + int pa__init(pa_core *c, pa_module*m) { struct audio_buf_info info; struct userdata *u = NULL; @@ -332,7 +370,7 @@ int pa__init(pa_core *c, pa_module*m) { } if (mode != O_WRONLY) { - u->source = pa_source_new(c, PA_TYPEID_OSS, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss); + u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL); assert(u->source); u->source->userdata = u; u->source->notify = source_notify_cb; @@ -343,9 +381,11 @@ int pa__init(pa_core *c, pa_module*m) { u->source = NULL; if (mode != O_RDONLY) { - u->sink = pa_sink_new(c, PA_TYPEID_OSS, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss); + u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL); assert(u->sink); u->sink->get_latency = sink_get_latency_cb; + u->sink->get_hw_volume = sink_get_hw_volume; + u->sink->set_hw_volume = sink_set_hw_volume; u->sink->userdata = u; pa_sink_set_owner(u->sink, m); u->sink->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); @@ -384,6 +424,10 @@ int pa__init(pa_core *c, pa_module*m) { read(u->fd, buf, u->sample_size); } + /* Read mixer settings */ + if (u->sink) + sink_get_hw_volume(u->sink); + return 0; fail: diff --git a/polyp/module-pipe-sink.c b/polyp/module-pipe-sink.c index 537cb86b..20e220ce 100644 --- a/polyp/module-pipe-sink.c +++ b/polyp/module-pipe-sink.c @@ -50,8 +50,6 @@ PA_MODULE_USAGE("sink_name= file= format=module = m; m->userdata = u; - if (!(u->sink = pa_sink_new(c, PA_TYPEID_PIPE, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { pa_log(__FILE__": failed to create sink.\n"); goto fail; } diff --git a/polyp/module-pipe-source.c b/polyp/module-pipe-source.c index 31653627..42f13d4b 100644 --- a/polyp/module-pipe-source.c +++ b/polyp/module-pipe-source.c @@ -50,8 +50,6 @@ PA_MODULE_USAGE("source_name= file= forma #define DEFAULT_FIFO_NAME "/tmp/music.input" #define DEFAULT_SOURCE_NAME "fifo_input" -#define PA_TYPEID_PIPE PA_TYPEID_MAKE('P', 'I', 'P', 'E') - struct userdata { pa_core *core; @@ -154,7 +152,7 @@ int pa__init(pa_core *c, pa_module*m) { u->filename = pa_xstrdup(p); u->core = c; - if (!(u->source = pa_source_new(c, PA_TYPEID_PIPE, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss))) { + if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL))) { pa_log(__FILE__": failed to create source.\n"); goto fail; } diff --git a/polyp/module-protocol-stub.c b/polyp/module-protocol-stub.c index 3cf3d9d4..44d1c022 100644 --- a/polyp/module-protocol-stub.c +++ b/polyp/module-protocol-stub.c @@ -146,7 +146,7 @@ #else #include "module-esound-protocol-unix-symdef.h" #endif - PA_MODULE_DESCRIPTION("EsounD protocol "SOCKET_DESCRIPTION) + PA_MODULE_DESCRIPTION("ESOUND protocol "SOCKET_DESCRIPTION) PA_MODULE_USAGE("sink= source= public= cookie= "SOCKET_USAGE) #else #error "Broken build system" diff --git a/polyp/module-sine.c b/polyp/module-sine.c index c531386a..529c061a 100644 --- a/polyp/module-sine.c +++ b/polyp/module-sine.c @@ -40,8 +40,6 @@ PA_MODULE_DESCRIPTION("Sine wave generator") PA_MODULE_USAGE("sink= frequency=") PA_MODULE_VERSION(PACKAGE_VERSION) -#define PA_TYPEID_SINE PA_TYPEID_MAKE('S', 'I', 'N', 'E') - struct userdata { pa_core *core; pa_module *module; @@ -142,7 +140,7 @@ int pa__init(pa_core *c, pa_module*m) { calc_sine(u->memblock->data, u->memblock->length, frequency); snprintf(t, sizeof(t), "Sine Generator at %u Hz", frequency); - if (!(u->sink_input = pa_sink_input_new(sink, PA_TYPEID_SINE, t, &ss, 0, -1))) + if (!(u->sink_input = pa_sink_input_new(sink, __FILE__, t, &ss, NULL, 0, -1))) goto fail; u->sink_input->peek = sink_input_peek; diff --git a/polyp/module-solaris.c b/polyp/module-solaris.c index 01a151d6..ce9308be 100644 --- a/polyp/module-solaris.c +++ b/polyp/module-solaris.c @@ -1,4 +1,4 @@ -/* $Id: module-oss.c 333 2005-01-08 21:36:53Z lennart $ */ +/* $Id$ */ /*** This file is part of polypaudio. diff --git a/polyp/module-tunnel.c b/polyp/module-tunnel.c index e0eab6c2..c088dae0 100644 --- a/polyp/module-tunnel.c +++ b/polyp/module-tunnel.c @@ -59,8 +59,6 @@ PA_MODULE_USAGE("server=
source= cookie= PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_VERSION(PACKAGE_VERSION) -#define PA_TYPEID_TUNNEL PA_TYPEID_MAKE('T', 'U', 'N', 'L') - #define DEFAULT_SINK_NAME "tunnel" #define DEFAULT_SOURCE_NAME "tunnel" @@ -625,7 +623,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_socket_client_set_callback(u->client, on_connection, u); #ifdef TUNNEL_SINK - if (!(u->sink = pa_sink_new(c, PA_TYPEID_TUNNEL, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss))) { + if (!(u->sink = pa_sink_new(c, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, NULL))) { pa_log(__FILE__": failed to create sink.\n"); goto fail; } @@ -637,7 +635,7 @@ int pa__init(pa_core *c, pa_module*m) { pa_sink_set_owner(u->sink, m); #else - if (!(u->source = pa_source_new(c, PA_TYPEID_TUNNEL, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss))) { + if (!(u->source = pa_source_new(c, __FILE__, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss, NULL))) { pa_log(__FILE__": failed to create source.\n"); goto fail; } diff --git a/polyp/module-waveout.c b/polyp/module-waveout.c index 4d6d8c7b..a5ef847b 100644 --- a/polyp/module-waveout.c +++ b/polyp/module-waveout.c @@ -1,4 +1,4 @@ -/* $Id: module-waveout.c 333 2005-01-08 21:36:53Z lennart $ */ +/* $Id$ */ /*** This file is part of polypaudio. diff --git a/polyp/module-x11-bell.c b/polyp/module-x11-bell.c index 9b08c166..4fc4a60d 100644 --- a/polyp/module-x11-bell.c +++ b/polyp/module-x11-bell.c @@ -66,6 +66,7 @@ static const char* const valid_modargs[] = { static int ring_bell(struct userdata *u, int percent) { pa_sink *s; + pa_cvolume cv; assert(u); if (!(s = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) { @@ -73,7 +74,7 @@ static int ring_bell(struct userdata *u, int percent) { return -1; } - pa_scache_play_item(u->core, u->scache_item, s, percent*2); + pa_scache_play_item(u->core, u->scache_item, s, pa_cvolume_set(&cv, PA_CHANNELS_MAX, percent*PA_VOLUME_NORM/100)); return 0; } diff --git a/polyp/namereg.c b/polyp/namereg.c index 7c53a05d..07fb485c 100644 --- a/polyp/namereg.c +++ b/polyp/namereg.c @@ -38,7 +38,7 @@ #include "util.h" struct namereg_entry { - pa_namereg_type type; + pa_namereg_type_t type; char *name; void *data; }; @@ -51,7 +51,7 @@ void pa_namereg_free(pa_core *c) { pa_hashmap_free(c->namereg, NULL, NULL); } -const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type type, void *data, int fail) { +const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, int fail) { struct namereg_entry *e; char *n = NULL; int r; @@ -110,7 +110,7 @@ void pa_namereg_unregister(pa_core *c, const char *name) { pa_xfree(e); } -void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type type, int autoload) { +void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int autoload) { struct namereg_entry *e; uint32_t idx; assert(c); @@ -152,7 +152,7 @@ void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type type, int aut return NULL; } -void pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type type) { +void pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type) { char **s; assert(c && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); diff --git a/polyp/namereg.h b/polyp/namereg.h index 04f1737b..961fd44b 100644 --- a/polyp/namereg.h +++ b/polyp/namereg.h @@ -28,14 +28,14 @@ typedef enum pa_namereg_type { PA_NAMEREG_SINK, PA_NAMEREG_SOURCE, PA_NAMEREG_SAMPLE -} pa_namereg_type ; +} pa_namereg_type_t; void pa_namereg_free(pa_core *c); -const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type type, void *data, int fail); +const char *pa_namereg_register(pa_core *c, const char *name, pa_namereg_type_t type, void *data, int fail); void pa_namereg_unregister(pa_core *c, const char *name); -void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type type, int autoload); -void pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type type); +void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type_t type, int autoload); +void pa_namereg_set_default(pa_core*c, const char *name, pa_namereg_type_t type); const char *pa_namereg_get_default_sink_name(pa_core *c); const char *pa_namereg_get_default_source_name(pa_core *c); diff --git a/polyp/native-common.h b/polyp/native-common.h index 892629e8..569f3b71 100644 --- a/polyp/native-common.h +++ b/polyp/native-common.h @@ -51,6 +51,7 @@ enum { PA_COMMAND_FINISH_UPLOAD_STREAM, PA_COMMAND_PLAY_SAMPLE, PA_COMMAND_REMOVE_SAMPLE, + PA_COMMAND_GET_SERVER_INFO, PA_COMMAND_GET_SINK_INFO, PA_COMMAND_GET_SINK_INFO_LIST, @@ -68,15 +69,19 @@ enum { PA_COMMAND_GET_SAMPLE_INFO_LIST, PA_COMMAND_SUBSCRIBE, PA_COMMAND_SUBSCRIBE_EVENT, + PA_COMMAND_SET_SINK_VOLUME, PA_COMMAND_SET_SINK_INPUT_VOLUME, PA_COMMAND_CORK_PLAYBACK_STREAM, PA_COMMAND_FLUSH_PLAYBACK_STREAM, PA_COMMAND_TRIGGER_PLAYBACK_STREAM, + PA_COMMAND_SET_DEFAULT_SINK, PA_COMMAND_SET_DEFAULT_SOURCE, + PA_COMMAND_SET_PLAYBACK_STREAM_NAME, PA_COMMAND_SET_RECORD_STREAM_NAME, + PA_COMMAND_KILL_CLIENT, PA_COMMAND_KILL_SINK_INPUT, PA_COMMAND_KILL_SOURCE_OUTPUT, diff --git a/polyp/pacat-simple.c b/polyp/pacat-simple.c index 373cdd57..2825fee5 100644 --- a/polyp/pacat-simple.c +++ b/polyp/pacat-simple.c @@ -48,7 +48,7 @@ int main(PA_GCC_UNUSED int argc, char*argv[]) { int error; /* Create a new playback stream */ - if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, PA_VOLUME_NORM, &error))) { + if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_PLAYBACK, NULL, "playback", &ss, NULL, &error))) { fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); goto finish; } diff --git a/polyp/pacat.c b/polyp/pacat.c index 6842d61a..bd2b64fd 100644 --- a/polyp/pacat.c +++ b/polyp/pacat.c @@ -162,16 +162,17 @@ static void context_state_callback(pa_context *c, void *userdata) { if (verbose) fprintf(stderr, "Connection established.\n"); - stream = pa_stream_new(c, stream_name, &sample_spec); + stream = pa_stream_new(c, stream_name, &sample_spec, NULL); assert(stream); pa_stream_set_state_callback(stream, stream_state_callback, NULL); pa_stream_set_write_callback(stream, stream_write_callback, NULL); pa_stream_set_read_callback(stream, stream_read_callback, NULL); - if (mode == PLAYBACK) - pa_stream_connect_playback(stream, device, NULL, 0, volume); - else + if (mode == PLAYBACK) { + pa_cvolume cv; + pa_stream_connect_playback(stream, device, NULL, 0, pa_cvolume_set(&cv, PA_CHANNELS_MAX, volume)); + } else pa_stream_connect_record(stream, device, NULL, 0); break; @@ -219,7 +220,7 @@ static void stream_drain_complete(pa_stream*s, int success, void *userdata) { } /* New data on STDIN **/ -static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata) { +static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { size_t l, w = 0; ssize_t r; assert(a == mainloop_api && e && stdio_event == e); @@ -257,7 +258,7 @@ static void stdin_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_even } /* Some data may be written to STDOUT */ -static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata) { +static void stdout_callback(pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata) { ssize_t r; assert(a == mainloop_api && e && stdio_event == e); diff --git a/polyp/pactl.c b/polyp/pactl.c index 6943a11f..23bd924b 100644 --- a/polyp/pactl.c +++ b/polyp/pactl.c @@ -149,8 +149,8 @@ static void get_server_info_callback(pa_context *c, const pa_server_info *i, voi } static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) { - char s[PA_SAMPLE_SPEC_SNPRINT_MAX], tid[5]; - + char s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + if (is_last < 0) { fprintf(stderr, "Failed to get sink information: %s\n", pa_strerror(pa_context_errno(c))); quit(1); @@ -168,31 +168,31 @@ static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_ printf("\n"); nl = 1; - pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); - printf("*** Sink #%u ***\n" "Name: %s\n" - "Type: %s\n" + "Driver: %s\n" "Description: %s\n" "Sample Specification: %s\n" + "Channel Map: %s\n" "Owner Module: %u\n" - "Volume: 0x%03x (%0.2f dB)\n" + "Volume: %s\n" "Monitor Source: %u\n" "Latency: %0.0f usec\n", i->index, i->name, - pa_typeid_to_string(i->_typeid, tid, sizeof(tid)), + i->driver, i->description, - s, + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), i->owner_module, - i->volume, pa_volume_to_dB(i->volume), + pa_cvolume_snprint(cv, sizeof(cv), &i->volume), i->monitor_source, (double) i->latency); } static void get_source_info_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) { - char s[PA_SAMPLE_SPEC_SNPRINT_MAX], t[32], tid[5]; + char s[PA_SAMPLE_SPEC_SNPRINT_MAX], t[32], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; if (is_last < 0) { fprintf(stderr, "Failed to get source information: %s\n", pa_strerror(pa_context_errno(c))); @@ -213,21 +213,21 @@ static void get_source_info_callback(pa_context *c, const pa_source_info *i, int snprintf(t, sizeof(t), "%u", i->monitor_of_sink); - pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); - printf("*** Source #%u ***\n" "Name: %s\n" - "Type: %s\n" + "Driver: %s\n" "Description: %s\n" "Sample Specification: %s\n" + "Channel Map: %s\n" "Owner Module: %u\n" "Monitor of Sink: %s\n" "Latency: %0.0f usec\n", i->index, - pa_typeid_to_string(i->_typeid, tid, sizeof(tid)), + i->driver, i->name, i->description, - s, + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), i->owner_module, i->monitor_of_sink != PA_INVALID_INDEX ? t : "no", (double) i->latency); @@ -269,7 +269,7 @@ static void get_module_info_callback(pa_context *c, const pa_module_info *i, int } static void get_client_info_callback(pa_context *c, const pa_client_info *i, int is_last, void *userdata) { - char t[32], tid[5]; + char t[32]; if (is_last < 0) { fprintf(stderr, "Failed to get client information: %s\n", pa_strerror(pa_context_errno(c))); @@ -292,16 +292,16 @@ static void get_client_info_callback(pa_context *c, const pa_client_info *i, int printf("*** Client #%u ***\n" "Name: %s\n" - "Type: %s\n" + "Driver: %s\n" "Owner Module: %s\n", i->index, i->name, - pa_typeid_to_string(i->_typeid, tid, sizeof(tid)), + i->driver, i->owner_module != PA_INVALID_INDEX ? t : "n/a"); } static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) { - char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], tid[5]; + char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; if (is_last < 0) { fprintf(stderr, "Failed to get sink input information: %s\n", pa_strerror(pa_context_errno(c))); @@ -320,29 +320,30 @@ static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info printf("\n"); nl = 1; - pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); snprintf(t, sizeof(t), "%u", i->owner_module); snprintf(k, sizeof(k), "%u", i->client); printf("*** Sink Input #%u ***\n" "Name: %s\n" - "Type: %s\n" + "Driver: %s\n" "Owner Module: %s\n" "Client: %s\n" "Sink: %u\n" "Sample Specification: %s\n" - "Volume: 0x%03x (%0.2f dB)\n" + "Channel Map: %s\n" + "Volume: %s\n" "Buffer Latency: %0.0f usec\n" "Sink Latency: %0.0f usec\n" "Resample method: %s\n", i->index, i->name, - pa_typeid_to_string(i->_typeid, tid, sizeof(tid)), + i->driver, i->owner_module != PA_INVALID_INDEX ? t : "n/a", i->client != PA_INVALID_INDEX ? k : "n/a", i->sink, - s, - i->volume, pa_volume_to_dB(i->volume), + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), + pa_cvolume_snprint(cv, sizeof(cv), &i->volume), (double) i->buffer_usec, (double) i->sink_usec, i->resample_method ? i->resample_method : "n/a"); @@ -350,7 +351,7 @@ static void get_sink_input_info_callback(pa_context *c, const pa_sink_input_info static void get_source_output_info_callback(pa_context *c, const pa_source_output_info *i, int is_last, void *userdata) { - char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], tid[5]; + char t[32], k[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; if (is_last < 0) { fprintf(stderr, "Failed to get source output information: %s\n", pa_strerror(pa_context_errno(c))); @@ -369,34 +370,36 @@ static void get_source_output_info_callback(pa_context *c, const pa_source_outpu printf("\n"); nl = 1; - pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); + snprintf(t, sizeof(t), "%u", i->owner_module); snprintf(k, sizeof(k), "%u", i->client); printf("*** Source Output #%u ***\n" "Name: %s\n" - "Type: %s\n" + "Driver: %s\n" "Owner Module: %s\n" "Client: %s\n" "Source: %u\n" "Sample Specification: %s\n" + "Channel Map: %s\n" "Buffer Latency: %0.0f usec\n" "Source Latency: %0.0f usec\n" "Resample method: %s\n", i->index, i->name, - pa_typeid_to_string(i->_typeid, tid, sizeof(tid)), + i->driver, i->owner_module != PA_INVALID_INDEX ? t : "n/a", i->client != PA_INVALID_INDEX ? k : "n/a", i->source, - s, + pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec), + pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map), (double) i->buffer_usec, (double) i->source_usec, i->resample_method ? i->resample_method : "n/a"); } static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int is_last, void *userdata) { - char t[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX]; + char t[32], s[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; if (is_last < 0) { fprintf(stderr, "Failed to get sample information: %s\n", pa_strerror(pa_context_errno(c))); @@ -415,21 +418,23 @@ static void get_sample_info_callback(pa_context *c, const pa_sample_info *i, int printf("\n"); nl = 1; - pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec); + pa_bytes_snprint(t, sizeof(t), i->bytes); printf("*** Sample #%u ***\n" "Name: %s\n" - "Volume: 0x%03x (%0.2f dB)\n" + "Volume: %s\n" "Sample Specification: %s\n" + "Channel Map: %s\n" "Duration: %0.1fs\n" "Size: %s\n" "Lazy: %s\n" "Filename: %s\n", i->index, i->name, - i->volume, pa_volume_to_dB(i->volume), - pa_sample_spec_valid(&i->sample_spec) ? s : "n/a", + pa_cvolume_snprint(cv, sizeof(cv), &i->volume), + pa_sample_spec_valid(&i->sample_spec) ? pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec) : "n/a", + pa_sample_spec_valid(&i->sample_spec) ? pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map) : "n/a", (double) i->duration/1000000, t, i->lazy ? "yes" : "no", @@ -547,7 +552,7 @@ static void context_state_callback(pa_context *c, void *userdata) { break; case UPLOAD_SAMPLE: - sample_stream = pa_stream_new(c, sample_name, &sample_spec); + sample_stream = pa_stream_new(c, sample_name, &sample_spec, NULL); assert(sample_stream); pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL); diff --git a/polyp/paplay.c b/polyp/paplay.c index d9aa71a6..ddc1cbc1 100644 --- a/polyp/paplay.c +++ b/polyp/paplay.c @@ -155,21 +155,23 @@ static void context_state_callback(pa_context *c, void *userdata) { case PA_CONTEXT_SETTING_NAME: break; - case PA_CONTEXT_READY: + case PA_CONTEXT_READY: { + pa_cvolume cv; assert(c && !stream); if (verbose) fprintf(stderr, "Connection established.\n"); - stream = pa_stream_new(c, stream_name, &sample_spec); + stream = pa_stream_new(c, stream_name, &sample_spec, NULL); assert(stream); pa_stream_set_state_callback(stream, stream_state_callback, NULL); pa_stream_set_write_callback(stream, stream_write_callback, NULL); - pa_stream_connect_playback(stream, device, NULL, 0, volume); + pa_stream_connect_playback(stream, device, NULL, 0, pa_cvolume_set(&cv, PA_CHANNELS_MAX, volume)); break; + } case PA_CONTEXT_TERMINATED: quit(0); diff --git a/polyp/parec-simple.c b/polyp/parec-simple.c index 5f5abe11..524cc4f1 100644 --- a/polyp/parec-simple.c +++ b/polyp/parec-simple.c @@ -67,7 +67,7 @@ int main(PA_GCC_UNUSED int argc, char*argv[]) { int error; /* Create the recording stream */ - if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, 0, &error))) { + if (!(s = pa_simple_new(NULL, argv[0], PA_STREAM_RECORD, NULL, "record", &ss, NULL, &error))) { fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error)); goto finish; } diff --git a/polyp/parseaddr.h b/polyp/parseaddr.h index f0efd766..eff9dd3b 100644 --- a/polyp/parseaddr.h +++ b/polyp/parseaddr.h @@ -29,10 +29,10 @@ typedef enum pa_parsed_address_type { PA_PARSED_ADDRESS_TCP4, PA_PARSED_ADDRESS_TCP6, PA_PARSED_ADDRESS_TCP_AUTO -} pa_parsed_address_type; +} pa_parsed_address_type_t; typedef struct pa_parsed_address { - pa_parsed_address_type type; + pa_parsed_address_type_t type; char *path_or_host; uint16_t port; } pa_parsed_address; diff --git a/polyp/play-memchunk.c b/polyp/play-memchunk.c index c3db1462..e24d4427 100644 --- a/polyp/play-memchunk.c +++ b/polyp/play-memchunk.c @@ -33,8 +33,6 @@ #include "xmalloc.h" #include "gccmacro.h" -#define PA_TYPEID_MEMCHUNK PA_TYPEID_MAKE('M', 'C', 'N', 'K') - static void sink_input_kill(pa_sink_input *i) { pa_memchunk *c; assert(i && i->userdata); @@ -45,7 +43,6 @@ static void sink_input_kill(pa_sink_input *i) { pa_memblock_unref(c->memblock); pa_xfree(c); - } static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { @@ -82,24 +79,35 @@ static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t le pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i); } -int pa_play_memchunk(pa_sink *sink, const char *name, const pa_sample_spec *ss, const pa_memchunk *chunk, pa_volume_t volume) { +int pa_play_memchunk( + pa_sink *sink, + const char *name, + const pa_sample_spec *ss, + const pa_channel_map *map, + const pa_memchunk *chunk, + pa_cvolume *cvolume) { + pa_sink_input *si; pa_memchunk *nchunk; - assert(sink && chunk); + assert(sink); + assert(ss); + assert(chunk); - if (volume <= 0) + if (cvolume && pa_cvolume_is_muted(cvolume)) return 0; - if (!(si = pa_sink_input_new(sink, PA_TYPEID_MEMCHUNK, name, ss, 0, -1))) + if (!(si = pa_sink_input_new(sink, name, __FILE__, ss, map, 0, PA_RESAMPLER_INVALID))) return -1; - si->volume = volume; + if (cvolume) + si->volume = *cvolume; + si->peek = sink_input_peek; si->drop = sink_input_drop; si->kill = sink_input_kill; - si->userdata = nchunk = pa_xmalloc(sizeof(pa_memchunk)); + si->userdata = nchunk = pa_xnew(pa_memchunk, 1); *nchunk = *chunk; pa_memblock_ref(chunk->memblock); diff --git a/polyp/play-memchunk.h b/polyp/play-memchunk.h index 247cc870..fc0654a6 100644 --- a/polyp/play-memchunk.h +++ b/polyp/play-memchunk.h @@ -25,6 +25,12 @@ #include "sink.h" #include "memchunk.h" -int pa_play_memchunk(pa_sink *sink, const char *name, const pa_sample_spec *ss, const pa_memchunk *chunk, pa_volume_t volume); +int pa_play_memchunk( + pa_sink *sink, + const char *name, + const pa_sample_spec *ss, + const pa_channel_map *map, + const pa_memchunk *chunk, + pa_cvolume *cvolume); #endif diff --git a/polyp/poll.c b/polyp/poll.c index 6a260daf..193fc812 100644 --- a/polyp/poll.c +++ b/polyp/poll.c @@ -1,4 +1,4 @@ -/* $Id: mainloop.c 302 2004-11-21 17:02:25Z lennart $ */ +/* $Id$ */ /*** Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc. diff --git a/polyp/poll.h b/polyp/poll.h index 573f90ea..c201014e 100644 --- a/polyp/poll.h +++ b/polyp/poll.h @@ -1,4 +1,4 @@ -/* $Id: mainloop.c 302 2004-11-21 17:02:25Z lennart $ */ +/* $Id$ */ /*** Compatibility definitions for System V `poll' interface. diff --git a/polyp/polyplib-context.c b/polyp/polyplib-context.c index 0cf32490..15f2e4cd 100644 --- a/polyp/polyplib-context.c +++ b/polyp/polyplib-context.c @@ -187,7 +187,7 @@ void pa_context_unref(pa_context *c) { context_free(c); } -void pa_context_set_state(pa_context *c, pa_context_state st) { +void pa_context_set_state(pa_context *c, pa_context_state_t st) { assert(c); if (c->state == st) @@ -644,7 +644,7 @@ void pa_context_disconnect(pa_context *c) { pa_context_set_state(c, PA_CONTEXT_TERMINATED); } -pa_context_state pa_context_get_state(pa_context *c) { +pa_context_state_t pa_context_get_state(pa_context *c) { assert(c && c->ref >= 1); return c->state; } diff --git a/polyp/polyplib-context.h b/polyp/polyplib-context.h index 80c1b601..febb75f4 100644 --- a/polyp/polyplib-context.h +++ b/polyp/polyplib-context.h @@ -75,7 +75,7 @@ int pa_context_errno(pa_context *c); int pa_context_is_pending(pa_context *c); /** Return the current context status */ -pa_context_state pa_context_get_state(pa_context *c); +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 diff --git a/polyp/polyplib-def.h b/polyp/polyplib-def.h index 499282c4..0591ce6c 100644 --- a/polyp/polyplib-def.h +++ b/polyp/polyplib-def.h @@ -43,7 +43,7 @@ typedef enum pa_context_state { 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; +} pa_context_state_t; /** The state of a stream */ typedef enum pa_stream_state { @@ -52,14 +52,14 @@ typedef enum pa_stream_state { 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; +} 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; +} pa_operation_state_t; /** An invalid index */ #define PA_INVALID_INDEX ((uint32_t) -1) @@ -70,7 +70,7 @@ typedef enum pa_stream_direction { PA_STREAM_PLAYBACK, /**< Playback stream */ PA_STREAM_RECORD, /**< Record stream */ PA_STREAM_UPLOAD /**< Sample upload stream */ -} pa_stream_direction; +} pa_stream_direction_t; /** Some special flags for stream connections. \since 0.6 */ typedef enum pa_stream_flags { @@ -90,7 +90,7 @@ typedef enum pa_stream_flags { * information. This is * especially useful on long latency * network connections. */ -} pa_stream_flags; +} pa_stream_flags_t; /** Playback and record buffer metrics */ typedef struct pa_buffer_attr { @@ -133,7 +133,7 @@ typedef enum pa_subscription_mask { 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; +} pa_subscription_mask_t; /** Subscription event types, as used by pa_context_subscribe() */ typedef enum pa_subscription_event_type { @@ -152,7 +152,7 @@ typedef enum pa_subscription_event_type { 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; +} 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)))) diff --git a/polyp/polyplib-internal.h b/polyp/polyplib-internal.h index 09f9473a..29596069 100644 --- a/polyp/polyplib-internal.h +++ b/polyp/polyplib-internal.h @@ -55,12 +55,12 @@ struct pa_context { uint32_t ctag; uint32_t error; - pa_context_state state; + pa_context_state_t state; void (*state_callback)(pa_context*c, void *userdata); void *state_userdata; - void (*subscribe_callback)(pa_context *c, pa_subscription_event_type t, uint32_t idx, void *userdata); + void (*subscribe_callback)(pa_context *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata); void *subscribe_userdata; pa_memblock_stat *memblock_stat; @@ -86,15 +86,16 @@ struct pa_stream { char *name; pa_buffer_attr buffer_attr; pa_sample_spec sample_spec; + pa_channel_map channel_map; uint32_t channel; int channel_valid; uint32_t device_index; - pa_stream_direction direction; + pa_stream_direction_t direction; uint32_t requested_bytes; uint64_t counter; pa_usec_t previous_time; pa_usec_t previous_ipol_time; - pa_stream_state state; + pa_stream_state_t state; pa_mcalign *mcalign; int interpolate; @@ -123,7 +124,7 @@ struct pa_operation { pa_stream *stream; PA_LLIST_FIELDS(pa_operation); - pa_operation_state state; + pa_operation_state_t state; void *userdata; pa_operation_callback callback; }; @@ -141,11 +142,11 @@ void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t 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); -void pa_context_set_state(pa_context *c, pa_context_state st); +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 st); +void pa_stream_set_state(pa_stream *s, pa_stream_state_t st); void pa_stream_trash_ipol(pa_stream *s); diff --git a/polyp/polyplib-introspect.c b/polyp/polyplib-introspect.c index 91105969..8c0c4449 100644 --- a/polyp/polyplib-introspect.c +++ b/polyp/polyplib-introspect.c @@ -128,12 +128,13 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, P 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_getu32(t, &i.volume) < 0 || + pa_tagstruct_get_cvolume(t, &i.volume) < 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_getu32(t, &i._typeid) < 0) { + pa_tagstruct_gets(t, &i.driver) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; @@ -223,11 +224,12 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command, 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_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_getu32(t, &i._typeid) < 0) { + pa_tagstruct_gets(t, &i.driver) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; @@ -316,7 +318,7 @@ static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command, 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._typeid) < 0 ) { + pa_tagstruct_gets(t, &i.driver) < 0 ) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; } @@ -452,11 +454,12 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm 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_getu32(t, &i.volume) < 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_getu32(t, &i._typeid) < 0) { + pa_tagstruct_gets(t, &i.driver) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; @@ -526,10 +529,11 @@ static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t c 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_getu32(t, &i._typeid) < 0) { + pa_tagstruct_gets(t, &i.driver) < 0) { pa_context_fail(o->context, PA_ERROR_PROTOCOL); goto finish; @@ -662,9 +666,10 @@ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command, if (pa_tagstruct_getu32(t, &i.index) < 0 || pa_tagstruct_gets(t, &i.name) < 0 || - pa_tagstruct_getu32(t, &i.volume) < 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) { @@ -861,7 +866,7 @@ finish: pa_operation_unref(o); } -pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type type, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { +pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata) { pa_tagstruct *t; pa_operation *o; uint32_t tag; @@ -933,8 +938,7 @@ finish: pa_operation_unref(o); } - -pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type type, const char *module, const char*argument, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { +pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; @@ -957,7 +961,7 @@ pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autolo return pa_operation_ref(o); } -pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type type, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { +pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, int success, void *userdata), void* userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; diff --git a/polyp/polyplib-introspect.h b/polyp/polyplib-introspect.h index 2848e22f..10e6d0e3 100644 --- a/polyp/polyplib-introspect.h +++ b/polyp/polyplib-introspect.h @@ -27,7 +27,8 @@ #include #include #include -#include +#include +#include /** \file * @@ -52,13 +53,14 @@ 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_sample_spec sample_spec; /**< Sample spec of this sink */ + pa_channel_map channel_map; /**< Channel map \since 0.9 */ uint32_t owner_module; /**< Index of the owning module of this sink, or PA_INVALID_INDEX */ - pa_volume_t volume; /**< Volume of the sink */ + pa_cvolume volume; /**< Volume of the sink */ 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 */ - pa_typeid_t _typeid; /**< Implementation type. \since 0.8 */ + const char *driver; /**< Driver name. \since 0.9 */ } pa_sink_info; /** Get information about a sink by its name */ @@ -75,12 +77,13 @@ 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_sample_spec sample_spec; /**< Sample spec of this source */ + pa_channel_map channel_map; /**< Channel map \since 0.9 */ uint32_t owner_module; /**< Owning module index, or PA_INVALID_INDEX */ 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 */ - pa_typeid_t _typeid; /**< Implementation type. \since 0.8 */ + const char *driver; /**< Driver name \since 0.9 */ } pa_source_info; /** Get information about a source by its name */ @@ -98,7 +101,7 @@ typedef struct pa_server_info { 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 */ + 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 */ @@ -127,7 +130,7 @@ 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 */ - pa_typeid_t _typeid; /**< Implementation type. \since 0.8 */ + const char *driver; /**< Driver name \since 0.9 */ } pa_client_info; /** Get information about a client by its index */ @@ -143,12 +146,13 @@ typedef struct pa_sink_input_info { 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_volume_t volume; /**< The volume of this sink input */ + 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 */ - pa_typeid_t _typeid; /**< Implementation type. \since 0.8 */ + const char *driver; /**< Driver name \since 0.9 */ } pa_sink_input_info; /** Get some information about a sink input by its index */ @@ -164,11 +168,12 @@ typedef struct pa_source_output_info { 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_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 */ - pa_typeid_t _typeid; /**< Implementation type. \since 0.8 */ + const char *driver; /**< Driver name \since 0.9 */ } pa_source_output_info; /** Get information about a source output by its index */ @@ -202,8 +207,9 @@ pa_operation* pa_context_stat(pa_context *c, void (*cb)(pa_context *c, const pa_ typedef struct pa_sample_info { uint32_t index; /**< Index of this entry */ const char *name; /**< Name of this entry */ - pa_volume_t volume; /**< Default volume of this entry */ - pa_sample_spec sample_spec; /**< Sample specification of the sampel */ + 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 */ @@ -238,19 +244,19 @@ pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, void (*cb)(p typedef enum pa_autoload_type { PA_AUTOLOAD_SINK = 0, PA_AUTOLOAD_SOURCE = 1 -} pa_autoload_type; +} 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 type; /**< Type of the autoload entry */ + 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; /** 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 type, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); +pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), 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, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), void *userdata); @@ -259,10 +265,10 @@ pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, pa_operation* pa_context_get_autoload_info_list(pa_context *c, void (*cb)(pa_context *c, const pa_autoload_info *i, int is_last, void *userdata), 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 type, const char *module, const char*argument, void (*cb)(pa_context *c, int idx, void *userdata), void* userdata); +pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, void (*cb)(pa_context *c, int idx, void *userdata), 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 type, void (*cb)(pa_context *c, int success, void *userdata), void* userdata); +pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, void (*cb)(pa_context *c, int success, void *userdata), void* userdata); /** Remove an autoload entry. \since 0.6 */ pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, void (*cb)(pa_context *c, int success, void *userdata), void* userdata); diff --git a/polyp/polyplib-operation.c b/polyp/polyplib-operation.c index 3bee8cc7..68bc8c6a 100644 --- a/polyp/polyplib-operation.c +++ b/polyp/polyplib-operation.c @@ -62,7 +62,7 @@ void pa_operation_unref(pa_operation *o) { } } -static void operation_set_state(pa_operation *o, pa_operation_state st) { +static void operation_set_state(pa_operation *o, pa_operation_state_t st) { assert(o && o->ref >= 1); if (st == o->state) @@ -97,7 +97,7 @@ void pa_operation_done(pa_operation *o) { operation_set_state(o, PA_OPERATION_DONE); } -pa_operation_state pa_operation_get_state(pa_operation *o) { +pa_operation_state_t pa_operation_get_state(pa_operation *o) { assert(o && o->ref >= 1); return o->state; } diff --git a/polyp/polyplib-operation.h b/polyp/polyplib-operation.h index 63dcbc9f..cac03e30 100644 --- a/polyp/polyplib-operation.h +++ b/polyp/polyplib-operation.h @@ -44,7 +44,7 @@ void pa_operation_unref(pa_operation *o); void pa_operation_cancel(pa_operation *o); /** Return the current status of the operation */ -pa_operation_state pa_operation_get_state(pa_operation *o); +pa_operation_state_t pa_operation_get_state(pa_operation *o); PA_C_DECL_END diff --git a/polyp/polyplib-simple.c b/polyp/polyplib-simple.c index b1357128..e5512152 100644 --- a/polyp/polyplib-simple.c +++ b/polyp/polyplib-simple.c @@ -39,7 +39,7 @@ struct pa_simple { pa_mainloop *mainloop; pa_context *context; pa_stream *stream; - pa_stream_direction direction; + pa_stream_direction_t direction; int dead; @@ -51,8 +51,8 @@ struct pa_simple { static void read_callback(pa_stream *s, const void*data, size_t length, void *userdata); static int check_error(pa_simple *p, int *rerror) { - pa_context_state cst; - pa_stream_state sst; + pa_context_state_t cst; + pa_stream_state_t sst; assert(p); if ((cst = pa_context_get_state(p->context)) == PA_CONTEXT_FAILED) @@ -118,12 +118,11 @@ static int iterate(pa_simple *p, int block, int *rerror) { pa_simple* pa_simple_new( const char *server, const char *name, - pa_stream_direction dir, + pa_stream_direction_t dir, const char *dev, const char *stream_name, const pa_sample_spec *ss, const pa_buffer_attr *attr, - pa_volume_t volume, int *rerror) { pa_simple *p; @@ -152,11 +151,11 @@ pa_simple* pa_simple_new( goto fail; } - if (!(p->stream = pa_stream_new(p->context, stream_name, ss))) + if (!(p->stream = pa_stream_new(p->context, stream_name, ss, NULL))) goto fail; if (dir == PA_STREAM_PLAYBACK) - pa_stream_connect_playback(p->stream, dev, attr, 0, volume); + pa_stream_connect_playback(p->stream, dev, attr, 0, NULL); else pa_stream_connect_record(p->stream, dev, attr, 0); diff --git a/polyp/polyplib-simple.h b/polyp/polyplib-simple.h index d1589115..0c80f460 100644 --- a/polyp/polyplib-simple.h +++ b/polyp/polyplib-simple.h @@ -49,12 +49,11 @@ typedef struct pa_simple pa_simple; 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 dir, /**< Open this stream for recording or playback? */ + 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_buffer_attr *attr, /**< Buffering attributes, or NULL for default */ - pa_volume_t volume, /**< Initial volume. Only for playback streams. \since 0.5 */ int *error /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */ ); diff --git a/polyp/polyplib-stream.c b/polyp/polyplib-stream.c index 6c8ed9c5..51ee6a22 100644 --- a/polyp/polyplib-stream.c +++ b/polyp/polyplib-stream.c @@ -36,11 +36,18 @@ #define LATENCY_IPOL_INTERVAL_USEC (10000L) -pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss) { +pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map) { pa_stream *s; - assert(c && ss); + assert(c); + assert(ss); - s = pa_xmalloc(sizeof(pa_stream)); + if (!pa_sample_spec_valid(ss)) + return NULL; + + if (map && !pa_channel_map_valid(map)) + return NULL; + + s = pa_xnew(pa_stream, 1); s->ref = 1; s->context = c; s->mainloop = c->mainloop; @@ -55,6 +62,12 @@ pa_stream *pa_stream_new(pa_context *c, const char *name, const pa_sample_spec * s->direction = PA_STREAM_NODIRECTION; s->name = pa_xstrdup(name); s->sample_spec = *ss; + + if (map) + s->channel_map = *map; + else + pa_channel_map_init_auto(&s->channel_map, ss->channels); + s->channel = 0; s->channel_valid = 0; s->device_index = PA_INVALID_INDEX; @@ -108,7 +121,7 @@ pa_stream* pa_stream_ref(pa_stream *s) { return s; } -pa_stream_state pa_stream_get_state(pa_stream *s) { +pa_stream_state_t pa_stream_get_state(pa_stream *s) { assert(s && s->ref >= 1); return s->state; } @@ -123,7 +136,7 @@ uint32_t pa_stream_get_index(pa_stream *s) { return s->device_index; } -void pa_stream_set_state(pa_stream *s, pa_stream_state st) { +void pa_stream_set_state(pa_stream *s, pa_stream_state_t st) { assert(s && s->ref >= 1); if (s->state == st) @@ -271,7 +284,7 @@ finish: pa_stream_unref(s); } -static void create_stream(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags flags, pa_volume_t volume) { +static void create_stream(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags, const pa_cvolume *volume) { pa_tagstruct *t; uint32_t tag; assert(s && s->ref >= 1 && s->state == PA_STREAM_DISCONNECTED); @@ -308,15 +321,23 @@ static void create_stream(pa_stream *s, const char *dev, const pa_buffer_attr *a pa_tagstruct_putu32(t, tag = s->context->ctag++); 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, PA_INVALID_INDEX); pa_tagstruct_puts(t, dev); pa_tagstruct_putu32(t, s->buffer_attr.maxlength); pa_tagstruct_put_boolean(t, !!(flags & PA_STREAM_START_CORKED)); if (s->direction == PA_STREAM_PLAYBACK) { + pa_cvolume cv; pa_tagstruct_putu32(t, s->buffer_attr.tlength); pa_tagstruct_putu32(t, s->buffer_attr.prebuf); pa_tagstruct_putu32(t, s->buffer_attr.minreq); - pa_tagstruct_putu32(t, volume); + + if (!volume) { + pa_cvolume_reset(&cv, s->sample_spec.channels); + volume = &cv; + } + + pa_tagstruct_put_cvolume(t, volume); } else pa_tagstruct_putu32(t, s->buffer_attr.fragsize); @@ -326,13 +347,13 @@ static void create_stream(pa_stream *s, const char *dev, const pa_buffer_attr *a pa_stream_unref(s); } -void pa_stream_connect_playback(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags flags, pa_volume_t volume) { +void pa_stream_connect_playback(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags, pa_cvolume *volume) { assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); s->direction = PA_STREAM_PLAYBACK; create_stream(s, dev, attr, flags, volume); } -void pa_stream_connect_record(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags flags) { +void pa_stream_connect_record(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags_t flags) { assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1); s->direction = PA_STREAM_RECORD; create_stream(s, dev, attr, flags, 0); diff --git a/polyp/polyplib-stream.h b/polyp/polyplib-stream.h index 806579f5..bc828b71 100644 --- a/polyp/polyplib-stream.h +++ b/polyp/polyplib-stream.h @@ -25,6 +25,8 @@ #include #include +#include +#include #include #include #include @@ -39,7 +41,7 @@ PA_C_DECL_BEGIN typedef struct pa_stream pa_stream; /** Create a new, unconnected stream with the specified name and sample type */ -pa_stream* pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss); +pa_stream* pa_stream_new(pa_context *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map); /** Decrease the reference counter by one */ void pa_stream_unref(pa_stream *s); @@ -48,7 +50,7 @@ void pa_stream_unref(pa_stream *s); pa_stream *pa_stream_ref(pa_stream *s); /** Return the current state of the stream */ -pa_stream_state pa_stream_get_state(pa_stream *p); +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); @@ -57,10 +59,19 @@ pa_context* pa_stream_get_context(pa_stream *p); uint32_t pa_stream_get_index(pa_stream *s); /** Connect the stream to a sink */ -void pa_stream_connect_playback(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags flags, pa_volume_t volume); +void pa_stream_connect_playback( + pa_stream *s, + const char *dev, + const pa_buffer_attr *attr, + pa_stream_flags_t flags, + pa_cvolume *volume); /** Connect the stream to a source */ -void pa_stream_connect_record(pa_stream *s, const char *dev, const pa_buffer_attr *attr, pa_stream_flags flags); +void pa_stream_connect_record( + pa_stream *s, + const char *dev, + const pa_buffer_attr *attr, + pa_stream_flags_t flags); /** Disconnect a stream from a source/sink */ void pa_stream_disconnect(pa_stream *s); diff --git a/polyp/polyplib-subscribe.c b/polyp/polyplib-subscribe.c index 69ae588f..ef90ab0b 100644 --- a/polyp/polyplib-subscribe.c +++ b/polyp/polyplib-subscribe.c @@ -33,7 +33,7 @@ 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 e; + pa_subscription_event_type_t e; uint32_t index; assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); @@ -54,7 +54,7 @@ finish: } -pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask m, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { +pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, void (*cb)(pa_context *c, int success, void *userdata), void *userdata) { pa_operation *o; pa_tagstruct *t; uint32_t tag; @@ -74,7 +74,7 @@ pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask m, void ( return pa_operation_ref(o); } -void pa_context_set_subscribe_callback(pa_context *c, void (*cb)(pa_context *c, pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { +void pa_context_set_subscribe_callback(pa_context *c, void (*cb)(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata) { assert(c); c->subscribe_callback = cb; c->subscribe_userdata = userdata; diff --git a/polyp/polyplib-subscribe.h b/polyp/polyplib-subscribe.h index f2760ee6..920c9853 100644 --- a/polyp/polyplib-subscribe.h +++ b/polyp/polyplib-subscribe.h @@ -37,10 +37,10 @@ PA_C_DECL_BEGIN /** Enable event notification */ -pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask m, void (*cb)(pa_context *c, int success, void *userdata), void *userdata); +pa_operation* pa_context_subscribe(pa_context *c, pa_subscription_mask_t m, void (*cb)(pa_context *c, int success, void *userdata), 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, void (*cb)(pa_context *c, pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); +void pa_context_set_subscribe_callback(pa_context *c, void (*cb)(pa_context *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata); PA_C_DECL_END diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index a97bc25c..ce183a6f 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -64,8 +64,6 @@ #define SCACHE_PREFIX "esound." -#define PA_TYPEID_ESOUND PA_TYPEID_MAKE('E', 'S', 'D', 'P') - /* This is heavily based on esound's code */ struct connection { @@ -326,7 +324,7 @@ static int esd_proto_stream_play(struct connection *c, PA_GCC_UNUSED esd_proto_t assert(!c->sink_input && !c->input_memblockq); - if (!(c->sink_input = pa_sink_input_new(sink, PA_TYPEID_ESOUND, name, &ss, 0, -1))) { + if (!(c->sink_input = pa_sink_input_new(sink, __FILE__, name, &ss, NULL, 0, -1))) { pa_log(__FILE__": failed to create sink input.\n"); return -1; } @@ -398,7 +396,7 @@ static int esd_proto_stream_record(struct connection *c, esd_proto_t request, co assert(!c->output_memblockq && !c->source_output); - if (!(c->source_output = pa_source_output_new(source, PA_TYPEID_ESOUND, name, &ss, -1))) { + if (!(c->source_output = pa_source_output_new(source, __FILE__, name, &ss, NULL, -1))) { pa_log(__FILE__": failed to create source output\n"); return -1; } @@ -476,7 +474,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v assert(k); for (conn = pa_idxset_first(c->protocol->connections, &idx); conn; conn = pa_idxset_next(c->protocol->connections, &idx)) { - int format = ESD_BITS16 | ESD_STEREO, rate = 44100, volume = 0xFF; + int format = ESD_BITS16 | ESD_STEREO, rate = 44100, lvolume = 0xFF, rvolume = 0xFF; if (conn->state != ESD_STREAMING_DATA) continue; @@ -485,7 +483,8 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v if (conn->sink_input) { rate = conn->sink_input->sample_spec.rate; - volume = (conn->sink_input->volume*0xFF)/0x100; + lvolume = (conn->sink_input->volume.values[0]*0xFF)/0x100; + rvolume = (conn->sink_input->volume.values[1]*0xFF)/0x100; format = format_native2esd(&conn->sink_input->sample_spec); } @@ -503,11 +502,11 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v response += sizeof(int); /* left */ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, volume); + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, lvolume); response += sizeof(int); /*right*/ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, volume); + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, rvolume); response += sizeof(int); /*format*/ @@ -545,11 +544,11 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v response += sizeof(int); /* left */ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (ce->volume*0xFF)/0x100); + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (ce->volume.values[0]*0xFF)/0x100); response += sizeof(int); /*right*/ - *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (ce->volume*0xFF)/0x100); + *((int*) response) = maybe_swap_endian_32(c->swap_byte_order, (ce->volume.values[0]*0xFF)/0x100); response += sizeof(int); /*format*/ @@ -572,20 +571,25 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) { int *ok; - uint32_t idx, volume; + uint32_t idx; + pa_volume_t lvolume, rvolume; struct connection *conn; assert(c && data && length == sizeof(int)*3); idx = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *(const int*)data)-1; - volume = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *((const int*)data + 1)); - volume = (volume*0x100)/0xFF; + lvolume = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *((const int*)data + 1)); + lvolume = (lvolume*0x100)/0xFF; + rvolume = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *((const int*)data + 2)); + rvolume = (rvolume*0x100)/0xFF; ok = connection_write(c, sizeof(int)); assert(ok); if ((conn = pa_idxset_get_by_index(c->protocol->connections, idx))) { assert(conn->sink_input); - conn->sink_input->volume = volume; + conn->sink_input->volume.values[0] = lvolume; + conn->sink_input->volume.values[1] = rvolume; + conn->sink_input->volume.channels = 2; *ok = 1; } else *ok = 0; @@ -627,7 +631,7 @@ static int esd_proto_sample_cache(struct connection *c, PA_GCC_UNUSED esd_proto_ c->state = ESD_CACHING_SAMPLE; - pa_scache_add_item(c->protocol->core, c->scache.name, NULL, NULL, &idx); + pa_scache_add_item(c->protocol->core, c->scache.name, NULL, NULL, NULL, &idx); ok = connection_write(c, sizeof(int)); assert(ok); @@ -676,7 +680,7 @@ static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t reque pa_sink *sink; if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) - if (pa_scache_play_item(c->protocol->core, name, sink, PA_VOLUME_NORM) >= 0) + if (pa_scache_play_item(c->protocol->core, name, sink, NULL) >= 0) *ok = (int) idx+1; } else { assert(request == ESD_PROTO_SAMPLE_FREE); @@ -801,7 +805,7 @@ static int do_read(struct connection *c) { int *ok; c->scache.memchunk.index = 0; - pa_scache_add_item(c->protocol->core, c->scache.name, &c->scache.sample_spec, &c->scache.memchunk, &idx); + pa_scache_add_item(c->protocol->core, c->scache.name, &c->scache.sample_spec, NULL, &c->scache.memchunk, &idx); pa_memblock_unref(c->scache.memchunk.memblock); c->scache.memchunk.memblock = NULL; @@ -1067,7 +1071,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); assert(p->core); - c->client = pa_client_new(p->core, PA_TYPEID_ESOUND, cname); + c->client = pa_client_new(p->core, __FILE__, cname); assert(c->client); c->client->owner = p->module; c->client->kill = client_kill_cb; diff --git a/polyp/protocol-native.c b/polyp/protocol-native.c index b19d30d9..0491dc41 100644 --- a/polyp/protocol-native.c +++ b/polyp/protocol-native.c @@ -56,8 +56,6 @@ /* Don't accept more connection than this */ #define MAX_CONNECTIONS 10 -#define PA_TYPEID_NATIVE PA_TYPEID_MAKE('N', 'A', 'T', 'V') - struct connection; struct pa_protocol_native; @@ -88,6 +86,7 @@ struct upload_stream { size_t length; char *name; pa_sample_spec sample_spec; + pa_channel_map channel_map; }; struct output_stream { @@ -235,7 +234,12 @@ static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = { /* structure management */ -static struct upload_stream* upload_stream_new(struct connection *c, const pa_sample_spec *ss, const char *name, size_t length) { +static struct upload_stream* upload_stream_new( + struct connection *c, + const pa_sample_spec *ss, + const pa_channel_map *map, + const char *name, size_t length) { + struct upload_stream *s; assert(c && ss && name && length); @@ -243,6 +247,7 @@ static struct upload_stream* upload_stream_new(struct connection *c, const pa_sa s->type = UPLOAD_STREAM; s->connection = c; s->sample_spec = *ss; + s->channel_map = *map; s->name = pa_xstrdup(name); s->memchunk.memblock = NULL; @@ -268,13 +273,21 @@ static void upload_stream_free(struct upload_stream *o) { pa_xfree(o); } -static struct record_stream* record_stream_new(struct connection *c, pa_source *source, const pa_sample_spec *ss, const char *name, size_t maxlength, size_t fragment_size) { +static struct record_stream* record_stream_new( + struct connection *c, + pa_source *source, + const pa_sample_spec *ss, + const pa_channel_map *map, + const char *name, + size_t maxlength, + size_t fragment_size) { + struct record_stream *s; pa_source_output *source_output; size_t base; assert(c && source && ss && name && maxlength); - if (!(source_output = pa_source_output_new(source, PA_TYPEID_NATIVE, name, ss, -1))) + if (!(source_output = pa_source_output_new(source, __FILE__, name, ss, map, -1))) return NULL; s = pa_xmalloc(sizeof(struct record_stream)); @@ -308,17 +321,23 @@ static void record_stream_free(struct record_stream* r) { pa_xfree(r); } -static struct playback_stream* playback_stream_new(struct connection *c, pa_sink *sink, const pa_sample_spec *ss, const char *name, - size_t maxlength, - size_t tlength, - size_t prebuf, - size_t minreq, - pa_volume_t volume) { +static struct playback_stream* playback_stream_new( + struct connection *c, + pa_sink *sink, + const pa_sample_spec *ss, + const pa_channel_map *map, + const char *name, + size_t maxlength, + size_t tlength, + size_t prebuf, + size_t minreq, + pa_cvolume *volume) { + struct playback_stream *s; pa_sink_input *sink_input; assert(c && sink && ss && name && maxlength); - if (!(sink_input = pa_sink_input_new(sink, PA_TYPEID_NATIVE, name, ss, 0, -1))) + if (!(sink_input = pa_sink_input_new(sink, __FILE__, name, ss, map, 0, -1))) return NULL; s = pa_xmalloc(sizeof(struct playback_stream)); @@ -340,7 +359,7 @@ static struct playback_stream* playback_stream_new(struct connection *c, pa_sink s->requested_bytes = 0; s->drain_request = 0; - s->sink_input->volume = volume; + s->sink_input->volume = *volume; pa_idxset_put(c->output_streams, s, &s->index); return s; @@ -561,14 +580,17 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC uint32_t sink_index; const char *name, *sink_name; pa_sample_spec ss; + pa_channel_map map; pa_tagstruct *reply; pa_sink *sink; - pa_volume_t volume; + pa_cvolume volume; int corked; + assert(c && t && c->protocol && c->protocol->core); if (pa_tagstruct_gets(t, &name) < 0 || !name || pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_get_channel_map(t, &map) < 0 || pa_tagstruct_getu32(t, &sink_index) < 0 || pa_tagstruct_gets(t, &sink_name) < 0 || pa_tagstruct_getu32(t, &maxlength) < 0 || @@ -576,13 +598,12 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC pa_tagstruct_getu32(t, &tlength) < 0 || pa_tagstruct_getu32(t, &prebuf) < 0 || pa_tagstruct_getu32(t, &minreq) < 0 || - pa_tagstruct_getu32(t, &volume) < 0 || + pa_tagstruct_get_cvolume(t, &volume) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; } - if (!c->authorized) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); return; @@ -599,7 +620,7 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC return; } - if (!(s = playback_stream_new(c, sink, &ss, name, maxlength, tlength, prebuf, minreq, volume))) { + if (!(s = playback_stream_new(c, sink, &ss, &map, name, maxlength, tlength, prebuf, minreq, &volume))) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); return; } @@ -671,6 +692,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ uint32_t source_index; const char *name, *source_name; pa_sample_spec ss; + pa_channel_map map; pa_tagstruct *reply; pa_source *source; int corked; @@ -678,6 +700,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ if (pa_tagstruct_gets(t, &name) < 0 || !name || pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_get_channel_map(t, &map) < 0 || pa_tagstruct_getu32(t, &source_index) < 0 || pa_tagstruct_gets(t, &source_name) < 0 || pa_tagstruct_getu32(t, &maxlength) < 0 || @@ -703,7 +726,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ return; } - if (!(s = record_stream_new(c, source, &ss, name, maxlength, fragment_size))) { + if (!(s = record_stream_new(c, source, &ss, &map, name, maxlength, fragment_size))) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); return; } @@ -984,11 +1007,13 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ size_t length; const char *name; pa_sample_spec ss; + pa_channel_map map; pa_tagstruct *reply; assert(c && t && c->protocol && c->protocol->core); if (pa_tagstruct_gets(t, &name) < 0 || !name || pa_tagstruct_get_sample_spec(t, &ss) < 0 || + pa_tagstruct_get_channel_map(t, &map) < 0 || pa_tagstruct_getu32(t, &length) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -1005,7 +1030,7 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ return; } - if (!(s = upload_stream_new(c, &ss, name, length))) { + if (!(s = upload_stream_new(c, &ss, &map, name, length))) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID); return; } @@ -1042,21 +1067,22 @@ static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ return; } - pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->memchunk, &idx); + pa_scache_add_item(c->protocol->core, s->name, &s->sample_spec, &s->channel_map, &s->memchunk, &idx); pa_pstream_send_simple_ack(c->pstream, tag); upload_stream_free(s); } static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - uint32_t sink_index, volume; + uint32_t sink_index; + pa_cvolume volume; pa_sink *sink; const char *name, *sink_name; assert(c && t); if (pa_tagstruct_getu32(t, &sink_index) < 0 || pa_tagstruct_gets(t, &sink_name) < 0 || - pa_tagstruct_getu32(t, &volume) < 0 || + pa_tagstruct_get_cvolume(t, &volume) < 0 || pa_tagstruct_gets(t, &name) < 0 || !name || !pa_tagstruct_eof(t)) { protocol_error(c); @@ -1078,7 +1104,7 @@ static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui return; } - if (pa_scache_play_item(c->protocol->core, name, sink, volume) < 0) { + if (pa_scache_play_item(c->protocol->core, name, sink, &volume) < 0) { pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY); return; } @@ -1116,12 +1142,13 @@ static void sink_fill_tagstruct(pa_tagstruct *t, pa_sink *sink) { pa_tagstruct_puts(t, sink->name); pa_tagstruct_puts(t, sink->description); pa_tagstruct_put_sample_spec(t, &sink->sample_spec); + pa_tagstruct_put_channel_map(t, &sink->channel_map); pa_tagstruct_putu32(t, sink->owner ? sink->owner->index : (uint32_t) -1); - pa_tagstruct_putu32(t, sink->volume); + pa_tagstruct_put_cvolume(t, pa_sink_get_volume(sink, PA_MIXER_HARDWARE)); pa_tagstruct_putu32(t, sink->monitor_source->index); pa_tagstruct_puts(t, sink->monitor_source->name); pa_tagstruct_put_usec(t, pa_sink_get_latency(sink)); - pa_tagstruct_putu32(t, sink->typeid); + pa_tagstruct_puts(t, sink->driver); } static void source_fill_tagstruct(pa_tagstruct *t, pa_source *source) { @@ -1130,11 +1157,12 @@ static void source_fill_tagstruct(pa_tagstruct *t, pa_source *source) { pa_tagstruct_puts(t, source->name); pa_tagstruct_puts(t, source->description); pa_tagstruct_put_sample_spec(t, &source->sample_spec); + pa_tagstruct_put_channel_map(t, &source->channel_map); pa_tagstruct_putu32(t, source->owner ? source->owner->index : (uint32_t) -1); pa_tagstruct_putu32(t, source->monitor_of ? source->monitor_of->index : (uint32_t) -1); pa_tagstruct_puts(t, source->monitor_of ? source->monitor_of->name : NULL); pa_tagstruct_put_usec(t, pa_source_get_latency(source)); - pa_tagstruct_putu32(t, source->typeid); + pa_tagstruct_puts(t, source->driver); } static void client_fill_tagstruct(pa_tagstruct *t, pa_client *client) { @@ -1142,7 +1170,7 @@ static void client_fill_tagstruct(pa_tagstruct *t, pa_client *client) { pa_tagstruct_putu32(t, client->index); pa_tagstruct_puts(t, client->name); pa_tagstruct_putu32(t, client->owner ? client->owner->index : (uint32_t) -1); - pa_tagstruct_putu32(t, client->typeid); + pa_tagstruct_puts(t, client->driver); } static void module_fill_tagstruct(pa_tagstruct *t, pa_module *module) { @@ -1162,11 +1190,12 @@ static void sink_input_fill_tagstruct(pa_tagstruct *t, pa_sink_input *s) { pa_tagstruct_putu32(t, s->client ? s->client->index : (uint32_t) -1); pa_tagstruct_putu32(t, s->sink->index); pa_tagstruct_put_sample_spec(t, &s->sample_spec); - pa_tagstruct_putu32(t, s->volume); + pa_tagstruct_put_channel_map(t, &s->channel_map); + pa_tagstruct_put_cvolume(t, &s->volume); pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s)); pa_tagstruct_put_usec(t, pa_sink_get_latency(s->sink)); pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s))); - pa_tagstruct_putu32(t, s->typeid); + pa_tagstruct_puts(t, s->driver); } static void source_output_fill_tagstruct(pa_tagstruct *t, pa_source_output *s) { @@ -1177,19 +1206,21 @@ static void source_output_fill_tagstruct(pa_tagstruct *t, pa_source_output *s) { pa_tagstruct_putu32(t, s->client ? s->client->index : (uint32_t) -1); pa_tagstruct_putu32(t, s->source->index); pa_tagstruct_put_sample_spec(t, &s->sample_spec); + pa_tagstruct_put_channel_map(t, &s->channel_map); pa_tagstruct_put_usec(t, pa_source_output_get_latency(s)); pa_tagstruct_put_usec(t, pa_source_get_latency(s->source)); pa_tagstruct_puts(t, pa_resample_method_to_string(pa_source_output_get_resample_method(s))); - pa_tagstruct_putu32(t, s->typeid); + pa_tagstruct_puts(t, s->driver); } static void scache_fill_tagstruct(pa_tagstruct *t, pa_scache_entry *e) { assert(t && e); pa_tagstruct_putu32(t, e->index); pa_tagstruct_puts(t, e->name); - pa_tagstruct_putu32(t, e->volume); + pa_tagstruct_put_cvolume(t, &e->volume); pa_tagstruct_put_usec(t, pa_bytes_to_usec(e->memchunk.length, &e->sample_spec)); pa_tagstruct_put_sample_spec(t, &e->sample_spec); + pa_tagstruct_put_channel_map(t, &e->channel_map); pa_tagstruct_putu32(t, e->memchunk.length); pa_tagstruct_put_boolean(t, e->lazy); pa_tagstruct_puts(t, e->filename); @@ -1379,7 +1410,7 @@ static void command_get_server_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSE pa_pstream_send_tagstruct(c->pstream, reply); } -static void subscription_cb(pa_core *core, pa_subscription_event_type e, uint32_t idx, void *userdata) { +static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint32_t idx, void *userdata) { pa_tagstruct *t; struct connection *c = userdata; assert(c && core); @@ -1395,7 +1426,7 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type e, uint32_ static void command_subscribe(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - pa_subscription_mask m; + pa_subscription_mask_t m; assert(c && t); if (pa_tagstruct_getu32(t, &m) < 0 || @@ -1423,7 +1454,8 @@ static void command_subscribe(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint static void command_set_volume(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { struct connection *c = userdata; - uint32_t idx, volume; + uint32_t idx; + pa_cvolume volume; pa_sink *sink = NULL; pa_sink_input *si = NULL; const char *name = NULL; @@ -1431,7 +1463,7 @@ static void command_set_volume(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, if (pa_tagstruct_getu32(t, &idx) < 0 || (command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 0) || - pa_tagstruct_getu32(t, &volume) || + pa_tagstruct_get_cvolume(t, &volume) || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -1458,9 +1490,9 @@ static void command_set_volume(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, } if (sink) - pa_sink_set_volume(sink, volume); + pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &volume); else if (si) - pa_sink_input_set_volume(si, volume); + pa_sink_input_set_volume(si, &volume); pa_pstream_send_simple_ack(c->pstream, tag); } @@ -2032,7 +2064,7 @@ static void on_connection(PA_GCC_UNUSED pa_socket_server*s, pa_iochannel *io, vo c->protocol = p; assert(p->core); - c->client = pa_client_new(p->core, PA_TYPEID_NATIVE, "Client"); + c->client = pa_client_new(p->core, __FILE__, "Client"); assert(c->client); c->client->kill = client_kill_cb; c->client->userdata = c; diff --git a/polyp/protocol-simple.c b/polyp/protocol-simple.c index a3d7099c..113919b3 100644 --- a/polyp/protocol-simple.c +++ b/polyp/protocol-simple.c @@ -42,8 +42,6 @@ /* Don't allow more than this many concurrent connections */ #define MAX_CONNECTIONS 10 -#define PA_TYPEID_SIMPLE PA_TYPEID_MAKE('S', 'M', 'P', 'L') - struct connection { pa_protocol_simple *protocol; pa_iochannel *io; @@ -310,7 +308,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) c->playback.fragment_size = 0; pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); - c->client = pa_client_new(p->core, PA_TYPEID_SIMPLE, cname); + c->client = pa_client_new(p->core, __FILE__, cname); assert(c->client); c->client->owner = p->module; c->client->kill = client_kill_cb; @@ -325,7 +323,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) goto fail; } - if (!(c->sink_input = pa_sink_input_new(sink, PA_TYPEID_SIMPLE, c->client->name, &p->sample_spec, 0, -1))) { + if (!(c->sink_input = pa_sink_input_new(sink, __FILE__, c->client->name, &p->sample_spec, NULL, 0, -1))) { pa_log(__FILE__": Failed to create sink input.\n"); goto fail; } @@ -355,7 +353,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata) goto fail; } - c->source_output = pa_source_output_new(source, PA_TYPEID_SIMPLE, c->client->name, &p->sample_spec, -1); + c->source_output = pa_source_output_new(source, __FILE__, c->client->name, &p->sample_spec, NULL, -1); if (!c->source_output) { pa_log(__FILE__": Failed to create source output.\n"); goto fail; diff --git a/polyp/resampler.c b/polyp/resampler.c index 96a1678f..0417e44e 100644 --- a/polyp/resampler.c +++ b/polyp/resampler.c @@ -27,6 +27,8 @@ #include #include +#include +#include #include "resampler.h" #include "sconv.h" @@ -34,24 +36,28 @@ #include "log.h" struct pa_resampler { + pa_resample_method_t resample_method; pa_sample_spec i_ss, o_ss; + pa_channel_map i_cm, o_cm; size_t i_fz, o_fz; pa_memblock_stat *memblock_stat; - void *impl_data; - int channels; - pa_resample_method resample_method; void (*impl_free)(pa_resampler *r); - void (*impl_set_input_rate)(pa_resampler *r, uint32_t rate); + void (*impl_update_input_rate)(pa_resampler *r, uint32_t rate); void (*impl_run)(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out); + void *impl_data; }; struct impl_libsamplerate { - float* i_buf, *o_buf; - unsigned i_alloc, o_alloc; + float* buf1, *buf2, *buf3, *buf4; + unsigned buf1_samples, buf2_samples, buf3_samples, buf4_samples; + pa_convert_to_float32ne_func_t to_float32ne_func; pa_convert_from_float32ne_func_t from_float32ne_func; SRC_STATE *src_state; + + int map_table[PA_CHANNELS_MAX][PA_CHANNELS_MAX]; + int map_required; }; struct impl_trivial { @@ -62,35 +68,54 @@ struct impl_trivial { static int libsamplerate_init(pa_resampler*r); static int trivial_init(pa_resampler*r); -pa_resampler* pa_resampler_new(const pa_sample_spec *a, const pa_sample_spec *b, pa_memblock_stat *s, pa_resample_method resample_method) { +pa_resampler* pa_resampler_new( + const pa_sample_spec *a, + const pa_channel_map *am, + const pa_sample_spec *b, + const pa_channel_map *bm, + pa_memblock_stat *s, + pa_resample_method_t resample_method) { + pa_resampler *r = NULL; - assert(a && b && pa_sample_spec_valid(a) && pa_sample_spec_valid(b) && resample_method != PA_RESAMPLER_INVALID); - if (a->channels != b->channels && a->channels != 1 && b->channels != 1) - goto fail; + assert(a); + assert(b); + assert(pa_sample_spec_valid(a)); + assert(pa_sample_spec_valid(b)); + assert(resample_method != PA_RESAMPLER_INVALID); - r = pa_xmalloc(sizeof(pa_resampler)); + r = pa_xnew(pa_resampler, 1); r->impl_data = NULL; r->memblock_stat = s; r->resample_method = resample_method; r->impl_free = NULL; - r->impl_set_input_rate = NULL; + r->impl_update_input_rate = NULL; r->impl_run = NULL; /* Fill sample specs */ r->i_ss = *a; r->o_ss = *b; + if (am) + r->i_cm = *am; + else + pa_channel_map_init_auto(&r->i_cm, r->i_ss.channels); + + if (bm) + r->o_cm = *bm; + else + pa_channel_map_init_auto(&r->o_cm, r->o_ss.channels); + r->i_fz = pa_frame_size(a); r->o_fz = pa_frame_size(b); - r->channels = a->channels; - if (b->channels < r->channels) - r->channels = b->channels; - /* Choose implementation */ - if (a->channels != b->channels || a->format != b->format || resample_method != PA_RESAMPLER_TRIVIAL) { + if (a->channels != b->channels || + a->format != b->format || + !pa_channel_map_equal(&r->i_cm, &r->o_cm) || + resample_method != PA_RESAMPLER_TRIVIAL) { + /* Use the libsamplerate based resampler for the complicated cases */ if (resample_method == PA_RESAMPLER_TRIVIAL) r->resample_method = PA_RESAMPLER_SRC_ZERO_ORDER_HOLD; @@ -123,11 +148,16 @@ void pa_resampler_free(pa_resampler *r) { } void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate) { - assert(r && rate); + assert(r); + assert(rate > 0); + if (r->i_ss.rate == rate) + return; + r->i_ss.rate = rate; - if (r->impl_set_input_rate) - r->impl_set_input_rate(r, rate); + + if (r->impl_update_input_rate) + r->impl_update_input_rate(r, rate); } void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { @@ -141,168 +171,342 @@ size_t pa_resampler_request(pa_resampler *r, size_t out_length) { return (((out_length / r->o_fz)*r->i_ss.rate)/r->o_ss.rate) * r->i_fz; } -pa_resample_method pa_resampler_get_method(pa_resampler *r) { +pa_resample_method_t pa_resampler_get_method(pa_resampler *r) { assert(r); return r->resample_method; } -/* Parse a libsamplrate compatible resampling implementation */ -pa_resample_method pa_parse_resample_method(const char *string) { +static const char * const resample_methods[] = { + "src-sinc-best-quality", + "src-sinc-medium-quality", + "src-sinc-fastest", + "src-zero-order-hold", + "src-linear", + "trivial" +}; + +const char *pa_resample_method_to_string(pa_resample_method_t m) { + + if (m < 0 || m >= PA_RESAMPLER_MAX) + return NULL; + + return resample_methods[m]; +} + +pa_resample_method_t pa_parse_resample_method(const char *string) { + pa_resample_method_t m; + assert(string); - if (!strcmp(string, "src-sinc-best-quality")) - return PA_RESAMPLER_SRC_SINC_BEST_QUALITY; - else if (!strcmp(string, "src-sinc-medium-quality")) - return PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY; - else if (!strcmp(string, "src-sinc-fastest")) - return PA_RESAMPLER_SRC_SINC_FASTEST; - else if (!strcmp(string, "src-zero-order-hold")) - return PA_RESAMPLER_SRC_ZERO_ORDER_HOLD; - else if (!strcmp(string, "src-linear")) - return PA_RESAMPLER_SRC_LINEAR; - else if (!strcmp(string, "trivial")) - return PA_RESAMPLER_TRIVIAL; - else - return PA_RESAMPLER_INVALID; + for (m = 0; m < PA_RESAMPLER_MAX; m++) + if (!strcmp(string, resample_methods[m])) + return m; + + return PA_RESAMPLER_INVALID; } + /*** libsamplerate based implementation ***/ static void libsamplerate_free(pa_resampler *r) { - struct impl_libsamplerate *i; - assert(r && r->impl_data); - i = r->impl_data; + struct impl_libsamplerate *u; + + assert(r); + assert(r->impl_data); - if (i->src_state) - src_delete(i->src_state); + u = r->impl_data; + + if (u->src_state) + src_delete(u->src_state); + + pa_xfree(u->buf1); + pa_xfree(u->buf2); + pa_xfree(u->buf3); + pa_xfree(u->buf4); + pa_xfree(u); +} + +static void calc_map_table(pa_resampler *r) { + struct impl_libsamplerate *u; + unsigned oc; + assert(r); + assert(r->impl_data); - pa_xfree(i->i_buf); - pa_xfree(i->o_buf); - pa_xfree(i); + u = r->impl_data; + + if (!(u->map_required = (!pa_channel_map_equal(&r->i_cm, &r->o_cm) || r->i_ss.channels != r->o_ss.channels))) + return; + + for (oc = 0; oc < r->o_ss.channels; oc++) { + unsigned ic, i = 0; + + for (ic = 0; ic < r->i_ss.channels; ic++) { + pa_channel_position_t a, b; + + a = r->i_cm.map[ic]; + b = r->o_cm.map[oc]; + + if (a == b || + (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_LEFT) || + (a == PA_CHANNEL_POSITION_MONO && b == PA_CHANNEL_POSITION_RIGHT) || + (a == PA_CHANNEL_POSITION_LEFT && b == PA_CHANNEL_POSITION_MONO) || + (a == PA_CHANNEL_POSITION_RIGHT && b == PA_CHANNEL_POSITION_MONO)) + + u->map_table[oc][i++] = ic; + } + + /* Add an end marker */ + if (i < PA_CHANNELS_MAX) + u->map_table[oc][i] = -1; + } } -static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { - unsigned i_nchannels, o_nchannels, ins, ons, eff_ins, eff_ons; - float *cbuf; - struct impl_libsamplerate *i; - assert(r && in && out && in->length && in->memblock && (in->length % r->i_fz) == 0 && r->impl_data); - i = r->impl_data; +static float * convert_to_float(pa_resampler *r, float *input, unsigned n_frames) { + struct impl_libsamplerate *u; + unsigned n_samples; - /* How many input samples? */ - ins = in->length/r->i_fz; + assert(r); + assert(input); + assert(r->impl_data); + u = r->impl_data; + + /* Convert the incoming sample into floats and place them in buf1 */ -/* pa_log("%u / %u = %u\n", in->length, r->i_fz, ins); */ + if (!u->to_float32ne_func) + return input; + + n_samples = n_frames * r->i_ss.channels; - /* How much space for output samples? */ - if (i->src_state) - ons = (ins*r->o_ss.rate/r->i_ss.rate)+1024; - else - ons = ins; + if (u->buf1_samples < n_samples) + u->buf1 = pa_xrealloc(u->buf1, sizeof(float) * (u->buf1_samples = n_samples)); - /* How many channels? */ - if (r->i_ss.channels == r->o_ss.channels) { - i_nchannels = o_nchannels = 1; - eff_ins = ins*r->i_ss.channels; /* effective samples */ - eff_ons = ons*r->o_ss.channels; - } else { - i_nchannels = r->i_ss.channels; - o_nchannels = r->o_ss.channels; - eff_ins = ins; - eff_ons = ons; - } + u->to_float32ne_func(n_samples, input, u->buf1); -/* pa_log("eff_ins = %u \n", eff_ins); */ + return u->buf1; +} + +static float *remap_channels(pa_resampler *r, float *input, unsigned n_frames) { + struct impl_libsamplerate *u; + unsigned n_samples; + int i_skip, o_skip; + unsigned oc; + assert(r); + assert(input); + assert(r->impl_data); + u = r->impl_data; + + /* Remap channels and place the result int buf2 */ - out->memblock = pa_memblock_new(out->length = (ons*r->o_fz), r->memblock_stat); - out->index = 0; - assert(out->memblock); + if (!u->map_required) + return input; - if (i->i_alloc < eff_ins) - i->i_buf = pa_xrealloc(i->i_buf, sizeof(float) * (i->i_alloc = eff_ins)); - assert(i->i_buf); + n_samples = n_frames * r->o_ss.channels; -/* pa_log("eff_ins = %u \n", eff_ins); */ + if (u->buf2_samples < n_samples) + u->buf2 = pa_xrealloc(u->buf2, sizeof(float) * (u->buf2_samples = n_samples)); - i->to_float32ne_func(eff_ins, (uint8_t*) in->memblock->data+in->index, i_nchannels, i->i_buf); + memset(u->buf2, 0, n_samples * sizeof(float)); - if (i->src_state) { - int ret; - SRC_DATA data; + o_skip = sizeof(float) * r->o_ss.channels; + i_skip = sizeof(float) * r->i_ss.channels; + + for (oc = 0; oc < r->o_ss.channels; oc++) { + unsigned i; + static const float one = 1.0; + + for (i = 0; i < PA_CHANNELS_MAX && u->map_table[oc][i] >= 0; i++) + oil_vectoradd_f32( + u->buf2 + oc, o_skip, + u->buf2 + oc, o_skip, + input + u->map_table[oc][i], i_skip, + n_frames, + &one, &one); + } - if (i->o_alloc < eff_ons) - i->o_buf = pa_xrealloc(i->o_buf, sizeof(float) * (i->o_alloc = eff_ons)); - assert(i->o_buf); + return u->buf2; +} - data.data_in = i->i_buf; - data.input_frames = ins; +static float *resample(pa_resampler *r, float *input, unsigned *n_frames) { + struct impl_libsamplerate *u; + SRC_DATA data; + unsigned out_n_frames, out_n_samples; + int ret; - data.data_out = i->o_buf; - data.output_frames = ons; - - data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate; - data.end_of_input = 0; + assert(r); + assert(input); + assert(n_frames); + assert(r->impl_data); + u = r->impl_data; + + /* Resample the data and place the result in buf3 */ + + if (!u->src_state) + return input; + + out_n_frames = (*n_frames*r->o_ss.rate/r->i_ss.rate)+1024; + out_n_samples = out_n_frames * r->o_ss.channels; + + if (u->buf3_samples < out_n_samples) + u->buf3 = pa_xrealloc(u->buf3, sizeof(float) * (u->buf3_samples = out_n_samples)); + + data.data_in = input; + data.input_frames = *n_frames; + + data.data_out = u->buf3; + data.output_frames = out_n_frames; - ret = src_process(i->src_state, &data); - assert(ret == 0); - assert((unsigned) data.input_frames_used == ins); + data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate; + data.end_of_input = 0; - cbuf = i->o_buf; - ons = data.output_frames_gen; - - if (r->i_ss.channels == r->o_ss.channels) - eff_ons = ons*r->o_ss.channels; - else - eff_ons = ons; - } else - cbuf = i->i_buf; - - if (eff_ons) - i->from_float32ne_func(eff_ons, cbuf, (uint8_t*)out->memblock->data+out->index, o_nchannels); - out->length = ons*r->o_fz; - - if (!out->length) { - pa_memblock_unref(out->memblock); + ret = src_process(u->src_state, &data); + assert(ret == 0); + assert((unsigned) data.input_frames_used == *n_frames); + + *n_frames = data.output_frames_gen; + + return u->buf3; +} + +static float *convert_from_float(pa_resampler *r, float *input, unsigned n_frames) { + struct impl_libsamplerate *u; + unsigned n_samples; + + assert(r); + assert(input); + assert(r->impl_data); + u = r->impl_data; + + /* Convert the data into the correct sample type and place the result in buf4 */ + + if (!u->from_float32ne_func) + return input; + + n_samples = n_frames * r->o_ss.channels; + + if (u->buf4_samples < n_samples) + u->buf4 = pa_xrealloc(u->buf4, sizeof(float) * (u->buf4_samples = n_samples)); + + u->from_float32ne_func(n_samples, input, u->buf4); + + return u->buf4; +} + +static void libsamplerate_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { + struct impl_libsamplerate *u; + float *buf, *input; + unsigned n_frames; + + assert(r); + assert(in); + assert(out); + assert(in->length); + assert(in->memblock); + assert(in->length % r->i_fz == 0); + assert(r->impl_data); + + u = r->impl_data; + + buf = input = (float*) ((uint8_t*) in->memblock->data + in->index); + n_frames = in->length / r->i_fz; + assert(n_frames > 0); + + buf = convert_to_float(r, buf, n_frames); + buf = remap_channels(r, buf, n_frames); + buf = resample(r, buf, &n_frames); + + if (n_frames) { + buf = convert_from_float(r, buf, n_frames); + + if (buf == input) { + /* Mm, no adjustment has been necessary, so let's return the original block */ + out->memblock = pa_memblock_ref(in->memblock); + out->index = in->index; + out->length = in->length; + } else { + float **p = NULL; + + out->length = n_frames * r->o_fz; + out->index = 0; + + if (buf == u->buf1) { + p = &u->buf1; + u->buf1_samples = 0; + } else if (buf == u->buf2) { + p = &u->buf2; + u->buf2_samples = 0; + } else if (buf == u->buf3) { + p = &u->buf3; + u->buf3_samples = 0; + } else if (buf == u->buf4) { + p = &u->buf4; + u->buf4_samples = 0; + } + + assert(p); + + /* Take the existing buffer and make it a memblock */ + out->memblock = pa_memblock_new_dynamic(*p, out->length, r->memblock_stat); + *p = NULL; + } + } else { out->memblock = NULL; + out->index = out->length = 0; } } -static void libsamplerate_set_input_rate(pa_resampler *r, uint32_t rate) { - int ret; - struct impl_libsamplerate *i; - assert(r && rate > 0 && r->impl_data); - i = r->impl_data; - - ret = src_set_ratio(i->src_state, (double) r->o_ss.rate / r->i_ss.rate); - assert(ret == 0); +static void libsamplerate_update_input_rate(pa_resampler *r, uint32_t rate) { + struct impl_libsamplerate *u; + + assert(r); + assert(rate > 0); + assert(r->impl_data); + u = r->impl_data; + + if (!u->src_state) { + int err; + u->src_state = src_new(r->resample_method, r->o_ss.channels, &err); + assert(u->src_state); + } else { + int ret = src_set_ratio(u->src_state, (double) r->o_ss.rate / rate); + assert(ret == 0); + } } static int libsamplerate_init(pa_resampler *r) { - struct impl_libsamplerate *i = NULL; + struct impl_libsamplerate *u = NULL; int err; - r->impl_data = i = pa_xmalloc(sizeof(struct impl_libsamplerate)); - - i->to_float32ne_func = pa_get_convert_to_float32ne_function(r->i_ss.format); - i->from_float32ne_func = pa_get_convert_from_float32ne_function(r->o_ss.format); + r->impl_data = u = pa_xnew(struct impl_libsamplerate, 1); + + u->buf1 = u->buf2 = u->buf3 = u->buf4 = NULL; + u->buf1_samples = u->buf2_samples = u->buf3_samples = u->buf4_samples = 0; - if (!i->to_float32ne_func || !i->from_float32ne_func) + if (r->i_ss.format == PA_SAMPLE_FLOAT32NE) + u->to_float32ne_func = NULL; + else if (!(u->to_float32ne_func = pa_get_convert_to_float32ne_function(r->i_ss.format))) goto fail; - - if (!(i->src_state = src_new(r->resample_method, r->channels, &err)) || !i->src_state) + + if (r->o_ss.format == PA_SAMPLE_FLOAT32NE) + u->from_float32ne_func = NULL; + else if (!(u->from_float32ne_func = pa_get_convert_from_float32ne_function(r->o_ss.format))) goto fail; - i->i_buf = i->o_buf = NULL; - i->i_alloc = i->o_alloc = 0; + if (r->o_ss.rate == r->i_ss.rate) + u->src_state = NULL; + else if (!(u->src_state = src_new(r->resample_method, r->o_ss.channels, &err))) + goto fail; r->impl_free = libsamplerate_free; - r->impl_set_input_rate = libsamplerate_set_input_rate; + r->impl_update_input_rate = libsamplerate_update_input_rate; r->impl_run = libsamplerate_run; + + calc_map_table(r); return 0; fail: - pa_xfree(i); + pa_xfree(u); return -1; } @@ -310,15 +514,20 @@ fail: static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { size_t fz; - unsigned nframes; - struct impl_trivial *i; - assert(r && in && out && r->impl_data); - i = r->impl_data; + unsigned n_frames; + struct impl_trivial *u; + + assert(r); + assert(in); + assert(out); + assert(r->impl_data); + + u = r->impl_data; fz = r->i_fz; assert(fz == r->o_fz); - nframes = in->length/fz; + n_frames = in->length/fz; if (r->i_ss.rate == r->o_ss.rate) { @@ -326,25 +535,25 @@ static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out *out = *in; pa_memblock_ref(out->memblock); - i->o_counter += nframes; + u->o_counter += n_frames; } else { /* Do real resampling */ size_t l; unsigned o_index; /* The length of the new memory block rounded up */ - l = ((((nframes+1) * r->o_ss.rate) / r->i_ss.rate) + 1) * fz; + l = ((((n_frames+1) * r->o_ss.rate) / r->i_ss.rate) + 1) * fz; out->index = 0; out->memblock = pa_memblock_new(l, r->memblock_stat); - for (o_index = 0;; o_index++, i->o_counter++) { + for (o_index = 0;; o_index++, u->o_counter++) { unsigned j; - j = (i->o_counter * r->i_ss.rate / r->o_ss.rate); - j = j > i->i_counter ? j - i->i_counter : 0; + j = (u->o_counter * r->i_ss.rate / r->o_ss.rate); + j = j > u->i_counter ? j - u->i_counter : 0; - if (j >= nframes) + if (j >= n_frames) break; assert(o_index*fz < out->memblock->length); @@ -357,56 +566,49 @@ static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out out->length = o_index*fz; } - i->i_counter += nframes; + u->i_counter += n_frames; /* Normalize counters */ - while (i->i_counter >= r->i_ss.rate) { - i->i_counter -= r->i_ss.rate; - assert(i->o_counter >= r->o_ss.rate); - i->o_counter -= r->o_ss.rate; + while (u->i_counter >= r->i_ss.rate) { + u->i_counter -= r->i_ss.rate; + assert(u->o_counter >= r->o_ss.rate); + u->o_counter -= r->o_ss.rate; } } static void trivial_free(pa_resampler *r) { assert(r); + pa_xfree(r->impl_data); } -static void trivial_set_input_rate(pa_resampler *r, uint32_t rate) { - struct impl_trivial *i; - assert(r && rate > 0 && r->impl_data); - i = r->impl_data; +static void trivial_update_input_rate(pa_resampler *r, uint32_t rate) { + struct impl_trivial *u; + + assert(r); + assert(rate > 0); + assert(r->impl_data); - i->i_counter = 0; - i->o_counter = 0; + u = r->impl_data; + u->i_counter = 0; + u->o_counter = 0; } static int trivial_init(pa_resampler*r) { - struct impl_trivial *i; - assert(r && r->i_ss.format == r->o_ss.format && r->i_ss.channels == r->o_ss.channels); + struct impl_trivial *u; + + assert(r); + assert(r->i_ss.format == r->o_ss.format); + assert(r->i_ss.channels == r->o_ss.channels); - r->impl_data = i = pa_xmalloc(sizeof(struct impl_trivial)); - i->o_counter = i->i_counter = 0; + r->impl_data = u = pa_xnew(struct impl_trivial, 1); + u->o_counter = u->i_counter = 0; r->impl_run = trivial_run; r->impl_free = trivial_free; - r->impl_set_input_rate = trivial_set_input_rate; + r->impl_update_input_rate = trivial_update_input_rate; return 0; } -const char *pa_resample_method_to_string(pa_resample_method m) { - static const char * const resample_methods[] = { - "src-sinc-best-quality", - "src-sinc-medium-quality", - "src-sinc-fastest", - "src-zero-order-hold", - "src-linear", - "trivial" - }; - if (m < 0 || m >= PA_RESAMPLER_MAX) - return NULL; - - return resample_methods[m]; -} diff --git a/polyp/resampler.h b/polyp/resampler.h index 358c872a..e14942f3 100644 --- a/polyp/resampler.h +++ b/polyp/resampler.h @@ -27,6 +27,7 @@ #include "sample.h" #include "memblock.h" #include "memchunk.h" +#include "channelmap.h" typedef struct pa_resampler pa_resampler; @@ -39,9 +40,16 @@ typedef enum pa_resample_method { PA_RESAMPLER_SRC_LINEAR = SRC_LINEAR, PA_RESAMPLER_TRIVIAL, PA_RESAMPLER_MAX -} pa_resample_method; +} pa_resample_method_t; + +pa_resampler* pa_resampler_new( + const pa_sample_spec *a, + const pa_channel_map *am, + const pa_sample_spec *b, + const pa_channel_map *bm, + pa_memblock_stat *s, + pa_resample_method_t resample_method); -pa_resampler* pa_resampler_new(const pa_sample_spec *a, const pa_sample_spec *b, pa_memblock_stat *s, int resample_method); void pa_resampler_free(pa_resampler *r); /* Returns the size of an input memory block which is required to return the specified amount of output data */ @@ -54,12 +62,12 @@ void pa_resampler_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out); void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate); /* Return the resampling method of the resampler object */ -pa_resample_method pa_resampler_get_method(pa_resampler *r); +pa_resample_method_t pa_resampler_get_method(pa_resampler *r); /* Try to parse the resampler method */ -pa_resample_method pa_parse_resample_method(const char *string); +pa_resample_method_t pa_parse_resample_method(const char *string); /* return a human readable string for the specified resampling method. Inverse of pa_parse_resample_method() */ -const char *pa_resample_method_to_string(pa_resample_method m); +const char *pa_resample_method_to_string(pa_resample_method_t m); #endif diff --git a/polyp/sample-util.c b/polyp/sample-util.c index cb5dd1c3..d2bb3150 100644 --- a/polyp/sample-util.c +++ b/polyp/sample-util.c @@ -28,6 +28,8 @@ #include #include +#include + #include "sample-util.h" pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) { @@ -38,6 +40,7 @@ pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) { void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) { assert(c && c->memblock && c->memblock->data && spec && c->length); + pa_silence_memory((uint8_t*) c->memblock->data+c->index, c->length, spec); } @@ -65,204 +68,255 @@ void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec) { memset(p, c, length); } -size_t pa_mix(pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const pa_sample_spec *spec, pa_volume_t volume) { - assert(channels && data && length && spec); +size_t pa_mix( + const pa_mix_info streams[], + unsigned nstreams, + void *data, + size_t length, + const pa_sample_spec *spec, + const pa_cvolume *volume) { - if (spec->format == PA_SAMPLE_S16NE) { - size_t d; - - for (d = 0;; d += sizeof(int16_t)) { - unsigned c; - int32_t sum = 0; - - if (d >= length) - return d; + assert(streams && data && length && spec); + + switch (spec->format) { + case PA_SAMPLE_S16NE:{ + size_t d; + unsigned channel = 0; - for (c = 0; c < nchannels; c++) { - int32_t v; - pa_volume_t cvolume = channels[c].volume; + for (d = 0;; d += sizeof(int16_t)) { + int32_t sum = 0; - if (d >= channels[c].chunk.length) + if (d >= length) return d; - - if (cvolume == PA_VOLUME_MUTED) - v = 0; - else { - v = *((int16_t*) ((uint8_t*) channels[c].chunk.memblock->data + channels[c].chunk.index + d)); + + if (volume->values[channel] != PA_VOLUME_MUTED) { + unsigned i; - if (cvolume != PA_VOLUME_NORM) { - v *= cvolume; - v /= PA_VOLUME_NORM; + for (i = 0; i < nstreams; i++) { + int32_t v; + pa_volume_t cvolume = streams[i].volume.values[channel]; + + if (d >= streams[i].chunk.length) + return d; + + if (cvolume == PA_VOLUME_MUTED) + v = 0; + else { + v = *((int16_t*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); + + if (cvolume != PA_VOLUME_NORM) { + v *= cvolume; + v /= PA_VOLUME_NORM; + } + } + + sum += v; + } + + if (volume->values[channel] != PA_VOLUME_NORM) { + sum *= volume->values[channel]; + sum /= PA_VOLUME_NORM; } + + if (sum < -0x8000) sum = -0x8000; + if (sum > 0x7FFF) sum = 0x7FFF; + } - sum += v; - } - - if (volume == PA_VOLUME_MUTED) - sum = 0; - else if (volume != PA_VOLUME_NORM) { - sum *= volume; - sum /= PA_VOLUME_NORM; + *((int16_t*) data) = sum; + data = (uint8_t*) data + sizeof(int16_t); + + if (++channel >= spec->channels) + channel = 0; } - - if (sum < -0x8000) sum = -0x8000; - if (sum > 0x7FFF) sum = 0x7FFF; - - *((int16_t*) data) = sum; - data = (uint8_t*) data + sizeof(int16_t); } - } else if (spec->format == PA_SAMPLE_U8) { - size_t d; - - for (d = 0;; d ++) { - int32_t sum = 0; - unsigned c; - if (d >= length) - return d; + case PA_SAMPLE_U8: { + size_t d; + unsigned channel = 0; - for (c = 0; c < nchannels; c++) { - int32_t v; - pa_volume_t cvolume = channels[c].volume; + for (d = 0;; d ++) { + int32_t sum = 0; - if (d >= channels[c].chunk.length) + if (d >= length) return d; - - if (cvolume == PA_VOLUME_MUTED) - v = 0; - else { - v = (int32_t) *((uint8_t*) channels[c].chunk.memblock->data + channels[c].chunk.index + d) - 0x80; + + if (volume->values[channel] != PA_VOLUME_MUTED) { + unsigned i; - if (cvolume != PA_VOLUME_NORM) { - v *= cvolume; - v /= PA_VOLUME_NORM; + for (i = 0; i < nstreams; i++) { + int32_t v; + pa_volume_t cvolume = streams[i].volume.values[channel]; + + if (d >= streams[i].chunk.length) + return d; + + if (cvolume == PA_VOLUME_MUTED) + v = 0; + else { + v = (int32_t) *((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d) - 0x80; + + if (cvolume != PA_VOLUME_NORM) { + v *= cvolume; + v /= PA_VOLUME_NORM; + } + } + + sum += v; + } + + if (volume->values[channel] != PA_VOLUME_NORM) { + sum *= volume->values[channel]; + sum /= PA_VOLUME_NORM; } + + if (sum < -0x80) sum = -0x80; + if (sum > 0x7F) sum = 0x7F; + } - sum += v; - } - - if (volume == PA_VOLUME_MUTED) - sum = 0; - else if (volume != PA_VOLUME_NORM) { - sum *= volume; - sum /= PA_VOLUME_NORM; + *((uint8_t*) data) = (uint8_t) (sum + 0x80); + data = (uint8_t*) data + 1; + + if (++channel >= spec->channels) + channel = 0; } - - if (sum < -0x80) sum = -0x80; - if (sum > 0x7F) sum = 0x7F; - - *((uint8_t*) data) = (uint8_t) (sum + 0x80); - data = (uint8_t*) data + 1; } - - } else if (spec->format == PA_SAMPLE_FLOAT32NE) { - size_t d; - - for (d = 0;; d += sizeof(float)) { - float sum = 0; - unsigned c; - if (d >= length) - return d; + case PA_SAMPLE_FLOAT32NE: { + size_t d; + unsigned channel = 0; - for (c = 0; c < nchannels; c++) { - float v; - pa_volume_t cvolume = channels[c].volume; + for (d = 0;; d += sizeof(float)) { + float sum = 0; - if (d >= channels[c].chunk.length) + if (d >= length) return d; - if (cvolume == PA_VOLUME_MUTED) - v = 0; - else { - v = *((float*) ((uint8_t*) channels[c].chunk.memblock->data + channels[c].chunk.index + d)); + if (volume->values[channel] != PA_VOLUME_MUTED) { + unsigned i; - if (cvolume != PA_VOLUME_NORM) - v = v*cvolume/PA_VOLUME_NORM; - } - - sum += v; - } - - if (volume == PA_VOLUME_MUTED) - sum = 0; - else if (volume != PA_VOLUME_NORM) - sum = sum*volume/PA_VOLUME_NORM; + for (i = 0; i < nstreams; i++) { + float v; + pa_volume_t cvolume = streams[i].volume.values[channel]; + + if (d >= streams[i].chunk.length) + return d; + + if (cvolume == PA_VOLUME_MUTED) + v = 0; + else { + v = *((float*) ((uint8_t*) streams[i].chunk.memblock->data + streams[i].chunk.index + d)); + + if (cvolume != PA_VOLUME_NORM) { + v *= cvolume; + v /= PA_VOLUME_NORM; + } + } + + sum += v; + } - if (sum < -1) sum = -1; - if (sum > 1) sum = 1; + if (volume->values[channel] != PA_VOLUME_NORM) { + sum *= volume->values[channel]; + sum /= PA_VOLUME_NORM; + } + } - *((float*) data) = sum; - data = (uint8_t*) data + sizeof(float); + *((float*) data) = sum; + data = (uint8_t*) data + sizeof(float); + + if (++channel >= spec->channels) + channel = 0; + } } - } else { - abort(); + + default: + abort(); } } -void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, pa_volume_t volume) { +void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, const pa_cvolume *volume) { assert(c && spec && (c->length % pa_frame_size(spec) == 0)); + assert(volume); - if (volume == PA_VOLUME_NORM) + if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_NORM)) return; - if (volume == PA_VOLUME_MUTED) { + if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) { pa_silence_memchunk(c, spec); return; } - if (spec->format == PA_SAMPLE_S16NE) { - int16_t *d; - size_t n; - - for (d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { - int32_t t = (int32_t)(*d); + switch (spec->format) { + case PA_SAMPLE_S16NE: { + int16_t *d; + size_t n; + unsigned channel = 0; - t *= volume; - t /= PA_VOLUME_NORM; + for (d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, n--) { + int32_t t = (int32_t)(*d); + + t *= volume->values[channel]; + t /= PA_VOLUME_NORM; + + if (t < -0x8000) t = -0x8000; + if (t > 0x7FFF) t = 0x7FFF; + + *d = (int16_t) t; + + if (++channel >= spec->channels) + channel = 0; + } + } - if (t < -0x8000) t = -0x8000; - if (t > 0x7FFF) t = 0x7FFF; + case PA_SAMPLE_U8: { + uint8_t *d; + size_t n; + unsigned channel = 0; - *d = (int16_t) t; + for (d = (uint8_t*) c->memblock->data + c->index, n = c->length; n > 0; d++, n--) { + int32_t t = (int32_t) *d - 0x80; + + t *= volume->values[channel]; + t /= PA_VOLUME_NORM; + + if (t < -0x80) t = -0x80; + if (t > 0x7F) t = 0x7F; + + *d = (uint8_t) (t + 0x80); + + if (++channel >= spec->channels) + channel = 0; + } } - } else if (spec->format == PA_SAMPLE_U8) { - uint8_t *d; - size_t n; - - for (d = (uint8_t*) c->memblock->data + c->index, n = c->length; n > 0; d++, n--) { - int32_t t = (int32_t) *d - 0x80; - - t *= volume; - t /= PA_VOLUME_NORM; - - if (t < -0x80) t = -0x80; - if (t > 0x7F) t = 0x7F; - - *d = (uint8_t) (t + 0x80); + case PA_SAMPLE_FLOAT32NE: { + float *d; + int skip; + unsigned n; + unsigned channel; + + d = (float*) ((uint8_t*) c->memblock->data + c->index); + skip = spec->channels * sizeof(float); + n = c->length/sizeof(float)/spec->channels; + + for (channel = 0; channel < spec->channels ; channel ++) { + float v, *t; + + if (volume->values[channel] == PA_VOLUME_NORM) + continue; + + v = (float) volume->values[channel] / PA_VOLUME_NORM; + + t = d + channel; + oil_scalarmult_f32(t, skip, t, skip, &v, n); + } } - } else if (spec->format == PA_SAMPLE_FLOAT32NE) { - float *d; - size_t n; - - for (d = (float*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(float); n > 0; d++, n--) { - float t = *d; - - t *= volume; - t /= PA_VOLUME_NORM; - if (t < -1) t = -1; - if (t > 1) t = 1; - - *d = t; - } - - } else { - abort(); + default: + abort(); } } diff --git a/polyp/sample-util.h b/polyp/sample-util.h index eaebe91d..e433f9c8 100644 --- a/polyp/sample-util.h +++ b/polyp/sample-util.h @@ -25,7 +25,7 @@ #include "sample.h" #include "memblock.h" #include "memchunk.h" - +#include "volume.h" pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec); void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec); @@ -33,12 +33,21 @@ void pa_silence_memory(void *p, size_t length, const pa_sample_spec *spec); typedef struct pa_mix_info { pa_memchunk chunk; - pa_volume_t volume; + pa_cvolume volume; void *userdata; -} pa_mix_info ; - -size_t pa_mix(pa_mix_info channels[], unsigned nchannels, void *data, size_t length, const pa_sample_spec *spec, pa_volume_t volume); - -void pa_volume_memchunk(pa_memchunk*c, const pa_sample_spec *spec, pa_volume_t volume); +} pa_mix_info; + +size_t pa_mix( + const pa_mix_info channels[], + unsigned nchannels, + void *data, + size_t length, + const pa_sample_spec *spec, + const pa_cvolume *volume); + +void pa_volume_memchunk( + pa_memchunk*c, + const pa_sample_spec *spec, + const pa_cvolume *volume); #endif diff --git a/polyp/sample.c b/polyp/sample.c index 37ab96a0..d587170c 100644 --- a/polyp/sample.c +++ b/polyp/sample.c @@ -30,29 +30,29 @@ #include "sample.h" -size_t pa_frame_size(const pa_sample_spec *spec) { - size_t b = 1; +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: - b = 1; - break; + return 1; case PA_SAMPLE_S16LE: case PA_SAMPLE_S16BE: - b = 2; - break; + return 2; case PA_SAMPLE_FLOAT32LE: case PA_SAMPLE_FLOAT32BE: - b = 4; - break; + return 4; default: assert(0); } +} + +size_t pa_frame_size(const pa_sample_spec *spec) { + assert(spec); - return b * spec->channels; + return pa_sample_size(spec) * spec->channels; } size_t pa_bytes_per_second(const pa_sample_spec *spec) { @@ -69,10 +69,11 @@ pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec) { int pa_sample_spec_valid(const pa_sample_spec *spec) { assert(spec); - if (spec->rate <= 0 || spec->channels <= 0) - return 0; - - if (spec->format >= PA_SAMPLE_MAX || spec->format < 0) + if (spec->rate <= 0 || + spec->channels <= 0 || + spec->channels > PA_CHANNELS_MAX || + spec->format >= PA_SAMPLE_MAX || + spec->format < 0) return 0; return 1; @@ -84,15 +85,15 @@ int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b) { return (a->format == b->format) && (a->rate == b->rate) && (a->channels == b->channels); } -const char *pa_sample_format_to_string(pa_sample_format f) { +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", + [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) @@ -112,44 +113,6 @@ char *pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec) { return s; } -pa_volume_t pa_volume_multiply(pa_volume_t a, pa_volume_t b) { - uint64_t p = a; - p *= b; - p /= PA_VOLUME_NORM; - - return (pa_volume_t) p; -} - -pa_volume_t pa_volume_from_dB(double f) { - if (f <= PA_DECIBEL_MININFTY) - return PA_VOLUME_MUTED; - - return (pa_volume_t) (pow(10, f/20)*PA_VOLUME_NORM); -} - -double pa_volume_to_dB(pa_volume_t v) { - if (v == PA_VOLUME_MUTED) - return PA_DECIBEL_MININFTY; - - return 20*log10((double) v/PA_VOLUME_NORM); -} - -#define USER_DECIBEL_RANGE 30 - -double pa_volume_to_user(pa_volume_t v) { - double dB = pa_volume_to_dB(v); - - return dB < -USER_DECIBEL_RANGE ? 0 : dB/USER_DECIBEL_RANGE+1; -} - -pa_volume_t pa_volume_from_user(double v) { - - if (v <= 0) - return PA_VOLUME_MUTED; - - return pa_volume_from_dB((v-1)*USER_DECIBEL_RANGE); -} - void pa_bytes_snprint(char *s, size_t l, unsigned v) { if (v >= ((unsigned) 1024)*1024*1024) snprintf(s, l, "%0.1f GB", ((double) v)/1024/1024/1024); @@ -161,7 +124,7 @@ void pa_bytes_snprint(char *s, size_t l, unsigned v) { snprintf(s, l, "%u B", (unsigned) v); } -pa_sample_format pa_parse_sample_format(const char *format) { +pa_sample_format_t pa_parse_sample_format(const char *format) { if (strcasecmp(format, "s16le") == 0) return PA_SAMPLE_S16LE; diff --git a/polyp/sample.h b/polyp/sample.h index 739cb337..c1b98f1c 100644 --- a/polyp/sample.h +++ b/polyp/sample.h @@ -33,6 +33,9 @@ PA_C_DECL_BEGIN +/* Maximum allowed channels */ +#define PA_CHANNELS_MAX 16 + /** Sample format */ typedef enum pa_sample_format { PA_SAMPLE_U8, /**< Unsigned 8 Bit PCM */ @@ -44,7 +47,7 @@ typedef enum pa_sample_format { PA_SAMPLE_FLOAT32BE, /**< 32 Bit IEEE floating point, big endian, range -1..1 */ PA_SAMPLE_MAX, /**< Upper limit of valid sample types */ PA_SAMPLE_INVALID = -1 /**< An invalid value */ -} pa_sample_format; +} pa_sample_format_t; #ifdef WORDS_BIGENDIAN /** Signed 16 Bit PCM, native endian */ @@ -71,7 +74,7 @@ typedef enum pa_sample_format { /** A sample format and attribute specification */ typedef struct pa_sample_spec { - pa_sample_format format; /**< The sample format */ + 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; @@ -85,6 +88,9 @@ 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); @@ -95,7 +101,10 @@ int pa_sample_spec_valid(const pa_sample_spec *spec); 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 f); +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 @@ -103,43 +112,9 @@ const char *pa_sample_format_to_string(pa_sample_format f); /** Pretty print a sample type specification to a string */ char* pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec); -/** Volume specification: 0: silence; < 256: diminished volume; 256: normal volume; > 256 amplified volume */ -typedef uint32_t pa_volume_t; - -/** Normal volume (100%) */ -#define PA_VOLUME_NORM (0x100) - -/** Muted volume (0%) */ -#define PA_VOLUME_MUTED (0) - -/** Multiply two volumes specifications, return the result. This uses PA_VOLUME_NORM as neutral element of multiplication. */ -pa_volume_t pa_volume_multiply(pa_volume_t a, pa_volume_t b); - -/** Convert volume from decibel to linear level. \since 0.4 */ -pa_volume_t pa_volume_from_dB(double f); - -/** Convert volume from linear level to decibel. \since 0.4 */ -double pa_volume_to_dB(pa_volume_t v); - -/** Convert volume to scaled value understandable by the user (between 0 and 1). \since 0.6 */ -double pa_volume_to_user(pa_volume_t v); - -/** Convert user volume to polypaudio volume. \since 0.6 */ -pa_volume_t pa_volume_from_user(double 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 - /** Pretty print a byte size value. (i.e. "2.5 MB") */ void pa_bytes_snprint(char *s, size_t l, unsigned v); -/** Parse a sample format text. Inverse of pa_sample_format_to_string() */ -pa_sample_format pa_parse_sample_format(const char *format); - PA_C_DECL_END #endif diff --git a/polyp/scache.c b/polyp/scache.c index 32c89a99..39fa26f3 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -52,6 +52,8 @@ #include "sound-file.h" #include "util.h" #include "log.h" +#include "channelmap.h" +#include "volume.h" #define UNLOAD_POLL_TIME 2 @@ -112,7 +114,7 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_NEW, e->index); } - e->volume = PA_VOLUME_NORM; + pa_cvolume_reset(&e->volume, PA_CHANNELS_MAX); e->last_used_time = 0; e->memchunk.memblock = NULL; e->memchunk.index = e->memchunk.length = 0; @@ -125,15 +127,20 @@ static pa_scache_entry* scache_add_item(pa_core *c, const char *name) { return e; } -int pa_scache_add_item(pa_core *c, const char *name, pa_sample_spec *ss, pa_memchunk *chunk, uint32_t *idx) { +int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, uint32_t *idx) { pa_scache_entry *e; assert(c && name); if (!(e = scache_add_item(c, name))) return -1; - if (ss) + if (ss) { e->sample_spec = *ss; + pa_channel_map_init_auto(&e->channel_map, ss->channels); + } + + if (map) + e->channel_map = *map; if (chunk) { e->memchunk = *chunk; @@ -161,7 +168,7 @@ int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint3 if (pa_sound_file_load(filename, &ss, &chunk, c->memblock_stat) < 0) return -1; - r = pa_scache_add_item(c, name, &ss, &chunk, idx); + r = pa_scache_add_item(c, name, &ss, NULL, &chunk, idx); pa_memblock_unref(chunk.memblock); return r; @@ -230,9 +237,10 @@ void pa_scache_free(pa_core *c) { c->mainloop->time_free(c->scache_auto_unload_event); } -int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, uint32_t volume) { +int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, const pa_cvolume *volume) { pa_scache_entry *e; char *t; + pa_cvolume r; assert(c && name && sink); if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 1))) @@ -249,7 +257,8 @@ int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, uint32_t vo return -1; t = pa_sprintf_malloc("sample:%s", name); - if (pa_play_memchunk(sink, t, &e->sample_spec, &e->memchunk, pa_volume_multiply(volume, e->volume)) < 0) { + + if (pa_play_memchunk(sink, t, &e->sample_spec, &e->channel_map, &e->memchunk, pa_sw_cvolume_multiply(&r, volume, &e->volume)) < 0) { free(t); return -1; } diff --git a/polyp/scache.h b/polyp/scache.h index c23e33de..d667ae60 100644 --- a/polyp/scache.h +++ b/polyp/scache.h @@ -31,8 +31,9 @@ typedef struct pa_scache_entry { uint32_t index; char *name; - uint32_t volume; + pa_cvolume volume; pa_sample_spec sample_spec; + pa_channel_map channel_map; pa_memchunk memchunk; char *filename; @@ -41,14 +42,14 @@ typedef struct pa_scache_entry { time_t last_used_time; } pa_scache_entry; -int pa_scache_add_item(pa_core *c, const char *name, pa_sample_spec *ss, pa_memchunk *chunk, uint32_t *idx); +int pa_scache_add_item(pa_core *c, const char *name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_memchunk *chunk, uint32_t *idx); int pa_scache_add_file(pa_core *c, const char *name, const char *filename, uint32_t *idx); int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename, uint32_t *idx); int pa_scache_add_directory_lazy(pa_core *c, const char *pathname); int pa_scache_remove_item(pa_core *c, const char *name); -int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, uint32_t volume); +int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, const pa_cvolume *cvolume); void pa_scache_free(pa_core *c); const char *pa_scache_get_name_by_id(pa_core *c, uint32_t id); diff --git a/polyp/sconv-s16be.c b/polyp/sconv-s16be.c index 3880b043..8b076f06 100644 --- a/polyp/sconv-s16be.c +++ b/polyp/sconv-s16be.c @@ -23,11 +23,19 @@ #include #endif +#include "endianmacros.h" + #define INT16_FROM INT16_FROM_BE #define INT16_TO INT16_TO_BE #define pa_sconv_s16le_to_float32ne pa_sconv_s16be_to_float32ne #define pa_sconv_s16le_from_float32ne pa_sconv_s16be_from_float32ne +#ifdef WORDS_BIGENDIAN +#define SWAP_WORDS 0 +#else +#define SWAP_WORDS 1 +#endif + #include "sconv-s16le.h" #include "sconv-s16le.c" diff --git a/polyp/sconv-s16be.h b/polyp/sconv-s16be.h index 86107fb5..b2b6a8c7 100644 --- a/polyp/sconv-s16be.h +++ b/polyp/sconv-s16be.h @@ -22,7 +22,7 @@ USA. ***/ -void pa_sconv_s16be_to_float32ne(unsigned n, const void *a, unsigned an, float *b); -void pa_sconv_s16be_from_float32ne(unsigned n, const float *a, void *b, unsigned bn); +void pa_sconv_s16be_to_float32ne(unsigned n, const void *a, float *b); +void pa_sconv_s16be_from_float32ne(unsigned n, const float *a, void *b); #endif diff --git a/polyp/sconv-s16le.c b/polyp/sconv-s16le.c index c9682fff..e47c5e8e 100644 --- a/polyp/sconv-s16le.c +++ b/polyp/sconv-s16le.c @@ -26,6 +26,8 @@ #include #include +#include + #include "endianmacros.h" #include "sconv.h" #include "sconv-s16le.h" @@ -39,49 +41,61 @@ #define INT16_TO INT16_TO_LE #endif -void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, unsigned an, float *b) { +#ifndef SWAP_WORDS +#ifdef WORDS_BIGENDIAN +#define SWAP_WORDS 1 +#else +#define SWAP_WORDS 0 +#endif +#endif + +void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, float *b) { const int16_t *ca = a; - assert(n && a && an && b); + assert(a); + assert(b); + +#if SWAP_WORDS == 1 + for (; n > 0; n--) { - unsigned i; - float sum = 0; - - for (i = 0; i < an; i++) { - int16_t s = *(ca++); - sum += ((float) INT16_FROM(s))/0x7FFF; - } - - if (sum > 1) - sum = 1; - if (sum < -1) - sum = -1; - - *(b++) = sum; + int16_t s = *(ca++); + *(b++) = ((float) INT16_FROM(s))/0x7FFF; } + +#else +{ + static const double add = 0, factor = 1.0/0x7FFF; + oil_scaleconv_f32_s16(b, ca, n, &add, &factor); +} +#endif } -void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b, unsigned bn) { +void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b) { int16_t *cb = b; - -/* pa_log("%u %p %p %u\n", n, a, b, bn); */ - assert(n && a && b && bn); + assert(a); + assert(b); + +#if SWAP_WORDS == 1 for (; n > 0; n--) { - unsigned i; int16_t s; float v = *(a++); if (v > 1) v = 1; + if (v < -1) v = -1; s = (int16_t) (v * 0x7FFF); - s = INT16_TO(s); - - for (i = 0; i < bn; i++) - *(cb++) = s; + *(cb++) = INT16_TO(s); } + +#else +{ + static const double add = 0, factor = 0x7FFF; + oil_scaleconv_s16_f32(cb, a, n, &add, &factor); +} +#endif } diff --git a/polyp/sconv-s16le.h b/polyp/sconv-s16le.h index caed826e..ef5e31e8 100644 --- a/polyp/sconv-s16le.h +++ b/polyp/sconv-s16le.h @@ -22,7 +22,7 @@ USA. ***/ -void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, unsigned an, float *b); -void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b, unsigned bn); +void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, float *b); +void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b); #endif diff --git a/polyp/sconv.c b/polyp/sconv.c index 223df5d9..1fcb5a0c 100644 --- a/polyp/sconv.c +++ b/polyp/sconv.c @@ -26,6 +26,10 @@ #include #include #include + +#include +#include + #include "endianmacros.h" #include "sconv.h" #include "g711.h" @@ -33,107 +37,58 @@ #include "sconv-s16le.h" #include "sconv-s16be.h" -static void u8_to_float32ne(unsigned n, const void *a, unsigned an, float *b) { - unsigned i; +static void u8_to_float32ne(unsigned n, const void *a, float *b) { const uint8_t *ca = a; - assert(n && a && an && b); - - for (; n > 0; n--) { - float sum = 0; + static const double add = -128.0/127.0, factor = 1.0/127.0; + + assert(a); + assert(b); - for (i = 0; i < an; i++) { - uint8_t v = *(ca++); - sum += (((float) v)-128)/127; - } - - if (sum > 1) - sum = 1; - if (sum < -1) - sum = -1; - - *(b++) = sum; - } + oil_scaleconv_f32_u8(b, ca, n, &add, &factor); } -static void u8_from_float32ne(unsigned n, const float *a, void *b, unsigned bn) { - unsigned i; +static void u8_from_float32ne(unsigned n, const float *a, void *b) { uint8_t *cb = b; + static const double add = 128.0, factor = 127.0; - assert(n && a && b && bn); - for (; n > 0; n--) { - float v = *(a++); - uint8_t u; - - if (v > 1) - v = 1; - - if (v < -1) - v = -1; + assert(a); + assert(b); - u = (uint8_t) (v*127+128); - - for (i = 0; i < bn; i++) - *(cb++) = u; - } + oil_scaleconv_u8_f32(cb, a, n, &add, &factor); } -static void float32ne_to_float32ne(unsigned n, const void *a, unsigned an, float *b) { - unsigned i; - const float *ca = a; - assert(n && a && an && b); - for (; n > 0; n--) { - float sum = 0; - - for (i = 0; i < an; i++) - sum += *(ca++); +static void float32ne_to_float32ne(unsigned n, const void *a, float *b) { + assert(a); + assert(b); - if (sum > 1) - sum = 1; - if (sum < -1) - sum = -1; - - *(b++) = sum; - } + oil_memcpy(b, a, sizeof(float) * n); } -static void float32ne_from_float32ne(unsigned n, const float *a, void *b, unsigned bn) { - unsigned i; - float *cb = b; - assert(n && a && b && bn); - for (; n > 0; n--) { - float v = *(a++); - for (i = 0; i < bn; i++) - *(cb++) = v; - } +static void float32ne_from_float32ne(unsigned n, const float *a, void *b) { + assert(a); + assert(b); + + oil_memcpy(b, a, sizeof(float) * n); } -static void ulaw_to_float32ne(unsigned n, const void *a, unsigned an, float *b) { - unsigned i; +static void ulaw_to_float32ne(unsigned n, const void *a, float *b) { const uint8_t *ca = a; - assert(n && a && an && b); - for (; n > 0; n--) { - float sum = 0; - - for (i = 0; i < an; i++) - sum += st_ulaw2linear16(*ca++) * 1.0F / 0x7FFF; - if (sum > 1) - sum = 1; - if (sum < -1) - sum = -1; - - *(b++) = sum; - } + assert(a); + assert(b); + + for (; n > 0; n--) + *(b++) = st_ulaw2linear16(*(ca++)) * 1.0F / 0x7FFF; } -static void ulaw_from_float32ne(unsigned n, const float *a, void *b, unsigned bn) { - unsigned i; +static void ulaw_from_float32ne(unsigned n, const float *a, void *b) { uint8_t *cb = b; - assert(n && a && b && bn); + assert(a); + assert(b); + for (; n > 0; n--) { float v = *(a++); - uint8_t u; if (v > 1) v = 1; @@ -141,40 +96,28 @@ static void ulaw_from_float32ne(unsigned n, const float *a, void *b, unsigned bn if (v < -1) v = -1; - u = st_14linear2ulaw((int16_t) (v * 0x1FFF)); - - for (i = 0; i < bn; i++) - *(cb++) = u; + *(cb++) = st_14linear2ulaw((int16_t) (v * 0x1FFF)); } } -static void alaw_to_float32ne(unsigned n, const void *a, unsigned an, float *b) { - unsigned i; +static void alaw_to_float32ne(unsigned n, const void *a, float *b) { const uint8_t *ca = a; - assert(n && a && an && b); - for (; n > 0; n--) { - float sum = 0; - - for (i = 0; i < an; i++) - sum += st_alaw2linear16(*ca++) * 1.0F / 0x7FFF; - if (sum > 1) - sum = 1; - if (sum < -1) - sum = -1; + assert(a); + assert(b); - *(b++) = sum; - } + for (; n > 0; n--) + *(b++) = st_alaw2linear16(*(ca++)) * 1.0F / 0x7FFF; } -static void alaw_from_float32ne(unsigned n, const float *a, void *b, unsigned bn) { - unsigned i; +static void alaw_from_float32ne(unsigned n, const float *a, void *b) { uint8_t *cb = b; - assert(n && a && b && bn); + assert(a); + assert(b); + for (; n > 0; n--) { float v = *(a++); - uint8_t u; if (v > 1) v = 1; @@ -182,15 +125,11 @@ static void alaw_from_float32ne(unsigned n, const float *a, void *b, unsigned bn if (v < -1) v = -1; - u = st_13linear2alaw((int16_t) (v * 0xFFF)); - - for (i = 0; i < bn; i++) - *(cb++) = u; + *(cb++) = st_13linear2alaw((int16_t) (v * 0xFFF)); } } - -pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format f) { +pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f) { switch(f) { case PA_SAMPLE_U8: return u8_to_float32ne; @@ -209,7 +148,7 @@ pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_fo } } -pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format f) { +pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f) { switch(f) { case PA_SAMPLE_U8: return u8_from_float32ne; diff --git a/polyp/sconv.h b/polyp/sconv.h index 2866fd41..2a005219 100644 --- a/polyp/sconv.h +++ b/polyp/sconv.h @@ -24,10 +24,10 @@ #include "sample.h" -typedef void (*pa_convert_to_float32ne_func_t)(unsigned n, const void *a, unsigned an, float *b); -typedef void (*pa_convert_from_float32ne_func_t)(unsigned n, const float *a, void *b, unsigned bn); +typedef void (*pa_convert_to_float32ne_func_t)(unsigned n, const void *a, float *b); +typedef void (*pa_convert_from_float32ne_func_t)(unsigned n, const float *a, void *b); -pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format f); -pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format f); +pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f); +pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f); #endif diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 682b3222..4a847e46 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -36,47 +36,66 @@ #define CONVERT_BUFFER_LENGTH 4096 -pa_sink_input* pa_sink_input_new(pa_sink *s, pa_typeid_t typeid, const char *name, const pa_sample_spec *spec, int variable_rate, int resample_method) { +pa_sink_input* pa_sink_input_new( + pa_sink *s, + const char *driver, + const char *name, + const pa_sample_spec *spec, + const pa_channel_map *map, + int variable_rate, + int resample_method) { + pa_sink_input *i; pa_resampler *resampler = NULL; int r; char st[256]; - assert(s && spec && s->state == PA_SINK_RUNNING); + pa_channel_map tmap; + + assert(s); + assert(spec); + assert(s->state == PA_SINK_RUNNING); if (pa_idxset_size(s->inputs) >= PA_MAX_INPUTS_PER_SINK) { - pa_log(__FILE__": Failed to create sink input: too many inputs per sink.\n"); + pa_log_warn(__FILE__": Failed to create sink input: too many inputs per sink.\n"); return NULL; } if (resample_method == PA_RESAMPLER_INVALID) resample_method = s->core->resample_method; - if (variable_rate || !pa_sample_spec_equal(spec, &s->sample_spec)) - if (!(resampler = pa_resampler_new(spec, &s->sample_spec, s->core->memblock_stat, resample_method))) + if (!map) { + pa_channel_map_init_auto(&tmap, spec->channels); + map = &tmap; + } + + if (variable_rate || !pa_sample_spec_equal(spec, &s->sample_spec) || !pa_channel_map_equal(map, &s->channel_map)) + if (!(resampler = pa_resampler_new(spec, map, &s->sample_spec, &s->channel_map, s->core->memblock_stat, resample_method))) return NULL; - i = pa_xmalloc(sizeof(pa_sink_input)); + i = pa_xnew(pa_sink_input, 1); i->ref = 1; i->state = PA_SINK_INPUT_RUNNING; i->name = pa_xstrdup(name); - i->typeid = typeid; - i->client = NULL; + i->driver = pa_xstrdup(driver); i->owner = NULL; i->sink = s; + i->client = NULL; + i->sample_spec = *spec; + i->channel_map = *map; + pa_cvolume_reset(&i->volume, spec->channels); + i->peek = NULL; i->drop = NULL; i->kill = NULL; i->get_latency = NULL; - i->userdata = NULL; i->underrun = NULL; + i->userdata = NULL; - i->volume = PA_VOLUME_NORM; i->playing = 0; - i->resampled_chunk.memblock = NULL; - i->resampled_chunk.index = i->resampled_chunk.length = 0; + pa_memchunk_reset(&i->resampled_chunk); i->resampler = resampler; assert(s->core); @@ -94,7 +113,10 @@ pa_sink_input* pa_sink_input_new(pa_sink *s, pa_typeid_t typeid, const char *nam } void pa_sink_input_disconnect(pa_sink_input *i) { - assert(i && i->state != PA_SINK_INPUT_DISCONNECTED && i->sink && i->sink->core); + assert(i); + assert(i->state != PA_SINK_INPUT_DISCONNECTED); + assert(i->sink); + assert(i->sink->core); pa_idxset_remove_by_data(i->sink->core->sink_inputs, i, NULL); pa_idxset_remove_by_data(i->sink->inputs, i, NULL); @@ -106,7 +128,9 @@ void pa_sink_input_disconnect(pa_sink_input *i) { i->drop = NULL; i->kill = NULL; i->get_latency = NULL; + i->underrun = NULL; + i->playing = 0; i->state = PA_SINK_INPUT_DISCONNECTED; } @@ -120,28 +144,34 @@ static void sink_input_free(pa_sink_input* i) { if (i->resampled_chunk.memblock) pa_memblock_unref(i->resampled_chunk.memblock); + if (i->resampler) pa_resampler_free(i->resampler); pa_xfree(i->name); + pa_xfree(i->driver); pa_xfree(i); } void pa_sink_input_unref(pa_sink_input *i) { - assert(i && i->ref >= 1); + assert(i); + assert(i->ref >= 1); if (!(--i->ref)) sink_input_free(i); } pa_sink_input* pa_sink_input_ref(pa_sink_input *i) { - assert(i && i->ref >= 1); + assert(i); + assert(i->ref >= 1); + i->ref++; return i; } void pa_sink_input_kill(pa_sink_input*i) { - assert(i && i->ref >= 1); + assert(i); + assert(i->ref >= 1); if (i->kill) i->kill(i); @@ -149,7 +179,9 @@ void pa_sink_input_kill(pa_sink_input*i) { pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) { pa_usec_t r = 0; - assert(i && i->ref >= 1); + + assert(i); + assert(i->ref >= 1); if (i->get_latency) r += i->get_latency(i); @@ -160,20 +192,28 @@ pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) { return r; } -int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { +int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume) { int ret = -1; - assert(i && chunk && i->ref >= 1); + int do_volume_adj_here; + + assert(i); + assert(i->ref >= 1); + assert(chunk); + assert(volume); pa_sink_input_ref(i); if (!i->peek || !i->drop || i->state == PA_SINK_INPUT_CORKED) goto finish; - + if (!i->resampler) { + do_volume_adj_here = 0; ret = i->peek(i, chunk); goto finish; } + do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map); + while (!i->resampled_chunk.memblock) { pa_memchunk tchunk; size_t l; @@ -182,6 +222,12 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { goto finish; assert(tchunk.length); + + /* It might be necessary to adjust the volume here */ + if (do_volume_adj_here) { + pa_memchunk_make_writable(&tchunk, i->sink->core->memblock_stat, 0); + pa_volume_memchunk(&tchunk, &i->sample_spec, &i->volume); + } l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH); @@ -195,7 +241,9 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { pa_memblock_unref(tchunk.memblock); } - assert(i->resampled_chunk.memblock && i->resampled_chunk.length); + assert(i->resampled_chunk.memblock); + assert(i->resampled_chunk.length); + *chunk = i->resampled_chunk; pa_memblock_ref(i->resampled_chunk.memblock); @@ -207,6 +255,19 @@ finish: i->underrun(i); i->playing = ret >= 0; + + if (ret >= 0) { + /* Let's see if we had to apply the volume adjustment + * ourselves, or if this can be done by the sink for us */ + + if (do_volume_adj_here) + /* We've both the same channel map, so let's have the sink do the adjustment for us*/ + + pa_cvolume_reset(volume, i->sample_spec.channels); + else + /* We had different channel maps, so we already did the adjustment */ + *volume = i->volume; + } pa_sink_input_unref(i); @@ -214,7 +275,9 @@ finish: } void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { - assert(i && length && i->ref >= 1); + assert(i); + assert(i->ref >= 1); + assert(length > 0); if (!i->resampler) { if (i->drop) @@ -222,35 +285,50 @@ void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t lengt return; } - assert(i->resampled_chunk.memblock && i->resampled_chunk.length >= length); + assert(i->resampled_chunk.memblock); + assert(i->resampled_chunk.length >= length); i->resampled_chunk.index += length; i->resampled_chunk.length -= length; - if (!i->resampled_chunk.length) { + if (i->resampled_chunk.length <= 0) { pa_memblock_unref(i->resampled_chunk.memblock); i->resampled_chunk.memblock = NULL; i->resampled_chunk.index = i->resampled_chunk.length = 0; } } -void pa_sink_input_set_volume(pa_sink_input *i, pa_volume_t volume) { - assert(i && i->sink && i->sink->core && i->ref >= 1); +void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume) { + assert(i); + assert(i->ref >= 1); + assert(i->sink); + assert(i->sink->core); - if (i->volume != volume) { - i->volume = volume; - pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); - } + if (pa_cvolume_equal(&i->volume, volume)) + return; + + i->volume = *volume; + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); +} + +const pa_cvolume * pa_sink_input_get_volume(pa_sink_input *i) { + assert(i); + assert(i->ref >= 1); + + return &i->volume; } void pa_sink_input_cork(pa_sink_input *i, int b) { int n; - assert(i && i->ref >= 1); + + assert(i); + assert(i->ref >= 1); if (i->state == PA_SINK_INPUT_DISCONNECTED) return; n = i->state == PA_SINK_INPUT_CORKED && !b; + i->state = b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING; if (n) @@ -258,7 +336,9 @@ void pa_sink_input_cork(pa_sink_input *i, int b) { } void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) { - assert(i && i->resampler && i->ref >= 1); + assert(i); + assert(i->resampler); + assert(i->ref >= 1); if (i->sample_spec.rate == rate) return; @@ -268,7 +348,8 @@ void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate) { } void pa_sink_input_set_name(pa_sink_input *i, const char *name) { - assert(i && i->ref >= 1); + assert(i); + assert(i->ref >= 1); pa_xfree(i->name); i->name = pa_xstrdup(name); @@ -276,8 +357,9 @@ void pa_sink_input_set_name(pa_sink_input *i, const char *name) { pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); } -pa_resample_method pa_sink_input_get_resample_method(pa_sink_input *i) { - assert(i && i->ref >= 1); +pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) { + assert(i); + assert(i->ref >= 1); if (!i->resampler) return PA_RESAMPLER_INVALID; diff --git a/polyp/sink-input.h b/polyp/sink-input.h index b4c3ec7f..1db993f5 100644 --- a/polyp/sink-input.h +++ b/polyp/sink-input.h @@ -33,25 +33,27 @@ typedef struct pa_sink_input pa_sink_input; #include "module.h" #include "client.h" -typedef enum { +typedef enum pa_sink_input_state { PA_SINK_INPUT_RUNNING, PA_SINK_INPUT_CORKED, PA_SINK_INPUT_DISCONNECTED -} pa_sink_input_state ; +} pa_sink_input_state_t; struct pa_sink_input { int ref; - pa_sink_input_state state; - uint32_t index; - pa_typeid_t typeid; - - char *name; + pa_sink_input_state_t state; + + char *name, *driver; pa_module *owner; - pa_client *client; + pa_sink *sink; + pa_client *client; + pa_sample_spec sample_spec; - uint32_t volume; + pa_channel_map channel_map; + + pa_cvolume volume; int (*peek) (pa_sink_input *i, pa_memchunk *chunk); void (*drop) (pa_sink_input *i, const pa_memchunk *chunk, size_t length); @@ -67,7 +69,15 @@ struct pa_sink_input { pa_resampler *resampler; }; -pa_sink_input* pa_sink_input_new(pa_sink *s, pa_typeid_t typeid, const char *name, const pa_sample_spec *spec, int variable_rate, int resample_method); +pa_sink_input* pa_sink_input_new( + pa_sink *s, + const char *driver, + const char *name, + const pa_sample_spec *spec, + const pa_channel_map *map, + int variable_rate, + int resample_method); + void pa_sink_input_unref(pa_sink_input* i); pa_sink_input* pa_sink_input_ref(pa_sink_input* i); @@ -79,10 +89,11 @@ void pa_sink_input_kill(pa_sink_input*i); pa_usec_t pa_sink_input_get_latency(pa_sink_input *i); -int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk); +int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk, pa_cvolume *volume); void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length); -void pa_sink_input_set_volume(pa_sink_input *i, pa_volume_t volume); +void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume); +const pa_cvolume * pa_sink_input_get_volume(pa_sink_input *i); void pa_sink_input_cork(pa_sink_input *i, int b); @@ -90,6 +101,6 @@ void pa_sink_input_set_rate(pa_sink_input *i, uint32_t rate); void pa_sink_input_set_name(pa_sink_input *i, const char *name); -pa_resample_method pa_sink_input_get_resample_method(pa_sink_input *i); +pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i); #endif diff --git a/polyp/sink.c b/polyp/sink.c index aac90c04..bb656649 100644 --- a/polyp/sink.c +++ b/polyp/sink.c @@ -40,43 +40,54 @@ #define MAX_MIX_CHANNELS 32 -pa_sink* pa_sink_new(pa_core *core, pa_typeid_t typeid, const char *name, int fail, const pa_sample_spec *spec) { +pa_sink* pa_sink_new( + pa_core *core, + const char *driver, + const char *name, + int fail, + const pa_sample_spec *spec, + const pa_channel_map *map) { + pa_sink *s; char *n = NULL; char st[256]; int r; - assert(core && name && *name && spec); - s = pa_xmalloc(sizeof(pa_sink)); + assert(core); + assert(name); + assert(*name); + assert(spec); + + s = pa_xnew(pa_sink, 1); if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SINK, s, fail))) { pa_xfree(s); return NULL; } - s->name = pa_xstrdup(name); - s->description = NULL; - s->typeid = typeid; - s->ref = 1; + s->core = core; s->state = PA_SINK_RUNNING; - + s->name = pa_xstrdup(name); + s->description = NULL; + s->driver = pa_xstrdup(driver); s->owner = NULL; - s->core = core; + s->sample_spec = *spec; + if (map) + s->channel_map = *map; + else + pa_channel_map_init_auto(&s->channel_map, spec->channels); + s->inputs = pa_idxset_new(NULL, NULL); - n = pa_sprintf_malloc("%s_monitor", name); - s->monitor_source = pa_source_new(core, typeid, n, 0, spec); - assert(s->monitor_source); - pa_xfree(n); - s->monitor_source->monitor_of = s; - s->monitor_source->description = pa_sprintf_malloc("Monitor source of sink '%s'", s->name); - - s->volume = PA_VOLUME_NORM; + pa_cvolume_reset(&s->sw_volume, spec->channels); + pa_cvolume_reset(&s->hw_volume, spec->channels); - s->notify = NULL; s->get_latency = NULL; + s->notify = NULL; + s->set_hw_volume = NULL; + s->get_hw_volume = NULL; s->userdata = NULL; r = pa_idxset_put(core->sinks, s, &s->index); @@ -85,6 +96,13 @@ pa_sink* pa_sink_new(pa_core *core, pa_typeid_t typeid, const char *name, int fa pa_sample_spec_snprint(st, sizeof(st), spec); pa_log_info(__FILE__": created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); + n = pa_sprintf_malloc("%s_monitor", name); + s->monitor_source = pa_source_new(core, driver, n, 0, spec, map); + assert(s->monitor_source); + pa_xfree(n); + s->monitor_source->monitor_of = s; + s->monitor_source->description = pa_sprintf_malloc("Monitor source of sink '%s'", s->name); + pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index); return s; @@ -92,7 +110,9 @@ pa_sink* pa_sink_new(pa_core *core, pa_typeid_t typeid, const char *name, int fa void pa_sink_disconnect(pa_sink* s) { pa_sink_input *i, *j = NULL; - assert(s && s->state == PA_SINK_RUNNING); + + assert(s); + assert(s->state == PA_SINK_RUNNING); pa_namereg_unregister(s->core, s->name); @@ -105,16 +125,19 @@ void pa_sink_disconnect(pa_sink* s) { pa_source_disconnect(s->monitor_source); pa_idxset_remove_by_data(s->core->sinks, s, NULL); - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); - s->notify = NULL; s->get_latency = NULL; + s->notify = NULL; + s->get_hw_volume = NULL; + s->set_hw_volume = NULL; s->state = PA_SINK_DISCONNECTED; + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); } static void sink_free(pa_sink *s) { - assert(s && s->ref == 0); + assert(s); + assert(!s->ref); if (s->state != PA_SINK_DISCONNECTED) pa_sink_disconnect(s); @@ -128,24 +151,29 @@ static void sink_free(pa_sink *s) { pa_xfree(s->name); pa_xfree(s->description); + pa_xfree(s->driver); pa_xfree(s); } void pa_sink_unref(pa_sink*s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); if (!(--s->ref)) sink_free(s); } pa_sink* pa_sink_ref(pa_sink *s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); + s->ref++; return s; } void pa_sink_notify(pa_sink*s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); if (s->notify) s->notify(s); @@ -156,20 +184,25 @@ static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) { pa_sink_input *i; unsigned n = 0; - assert(s && s->ref >= 1 && info); + assert(s); + assert(s->ref >= 1); + assert(info); for (i = pa_idxset_first(s->inputs, &idx); maxinfo > 0 && i; i = pa_idxset_next(s->inputs, &idx)) { + /* Increase ref counter, to make sure that this input doesn't + * vanish while we still need it */ pa_sink_input_ref(i); - if (pa_sink_input_peek(i, &info->chunk) < 0) { + if (pa_sink_input_peek(i, &info->chunk, &info->volume) < 0) { pa_sink_input_unref(i); continue; } - info->volume = i->volume; info->userdata = i; - assert(info->chunk.memblock && info->chunk.memblock->data && info->chunk.length); + assert(info->chunk.memblock); + assert(info->chunk.memblock->data); + assert(info->chunk.length); info++; maxinfo--; @@ -180,15 +213,21 @@ static unsigned fill_mix_info(pa_sink *s, pa_mix_info *info, unsigned maxinfo) { } static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned maxinfo, size_t length) { - assert(s && s->ref >= 1 && info); + assert(s); + assert(s->ref >= 1); + assert(info); for (; maxinfo > 0; maxinfo--, info++) { pa_sink_input *i = info->userdata; - assert(i && info->chunk.memblock); + assert(i); + assert(info->chunk.memblock); + + /* Drop read data */ pa_sink_input_drop(i, &info->chunk, length); pa_memblock_unref(info->chunk.memblock); + /* Decrease ref counter */ pa_sink_input_unref(i); info->userdata = NULL; } @@ -197,8 +236,8 @@ static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned maxinfo, size_t int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { pa_mix_info info[MAX_MIX_CHANNELS]; unsigned n; - size_t l; int r = -1; + assert(s); assert(s->ref >= 1); assert(length); @@ -212,37 +251,29 @@ int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) { goto finish; if (n == 1) { - uint32_t volume = PA_VOLUME_NORM; - pa_sink_input *i = info[0].userdata; - assert(i); + pa_cvolume volume; + *result = info[0].chunk; pa_memblock_ref(result->memblock); if (result->length > length) result->length = length; - l = result->length; - - if (s->volume != PA_VOLUME_NORM || info[0].volume != PA_VOLUME_NORM) - volume = pa_volume_multiply(s->volume, info[0].volume); + pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); - if (volume != PA_VOLUME_NORM) { + if (!pa_cvolume_is_norm(&volume)) { pa_memchunk_make_writable(result, s->core->memblock_stat, 0); - pa_volume_memchunk(result, &s->sample_spec, volume); + pa_volume_memchunk(result, &s->sample_spec, &volume); } } else { result->memblock = pa_memblock_new(length, s->core->memblock_stat); assert(result->memblock); - result->length = l = pa_mix(info, n, result->memblock->data, length, &s->sample_spec, s->volume); + result->length = pa_mix(info, n, result->memblock->data, length, &s->sample_spec, &s->sw_volume); result->index = 0; - - assert(l); } - inputs_drop(s, info, n, l); - - assert(s->monitor_source); + inputs_drop(s, info, n, result->length); pa_source_post(s->monitor_source, result); r = 0; @@ -256,9 +287,14 @@ finish: int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { pa_mix_info info[MAX_MIX_CHANNELS]; unsigned n; - size_t l; int r = -1; - assert(s && s->ref >= 1 && target && target->length && target->memblock && target->memblock->data); + + assert(s); + assert(s->ref >= 1); + assert(target); + assert(target->memblock); + assert(target->length); + assert(target->memblock->data); pa_sink_ref(s); @@ -268,27 +304,27 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { goto finish; if (n == 1) { - uint32_t volume = PA_VOLUME_NORM; + pa_cvolume volume; - l = target->length; - if (l > info[0].chunk.length) - l = info[0].chunk.length; + if (target->length > info[0].chunk.length) + target->length = info[0].chunk.length; - memcpy((uint8_t*) target->memblock->data+target->index, (uint8_t*) info[0].chunk.memblock->data + info[0].chunk.index, l); - target->length = l; - - if (s->volume != PA_VOLUME_NORM || info[0].volume != PA_VOLUME_NORM) - volume = pa_volume_multiply(s->volume, info[0].volume); + memcpy((uint8_t*) target->memblock->data + target->index, + (uint8_t*) info[0].chunk.memblock->data + info[0].chunk.index, + target->length); - if (volume != PA_VOLUME_NORM) - pa_volume_memchunk(target, &s->sample_spec, volume); + pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume); + + if (!pa_cvolume_is_norm(&volume)) + pa_volume_memchunk(target, &s->sample_spec, &volume); } else - target->length = l = pa_mix(info, n, (uint8_t*) target->memblock->data+target->index, target->length, &s->sample_spec, s->volume); + target->length = pa_mix(info, n, + (uint8_t*) target->memblock->data + target->index, + target->length, + &s->sample_spec, + &s->sw_volume); - assert(l); - inputs_drop(s, info, n, l); - - assert(s->monitor_source); + inputs_drop(s, info, n, target->length); pa_source_post(s->monitor_source, target); r = 0; @@ -302,7 +338,13 @@ finish: void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { pa_memchunk chunk; size_t l, d; - assert(s && s->ref >= 1 && target && target->memblock && target->length && target->memblock->data); + + assert(s); + assert(s->ref >= 1); + assert(target); + assert(target->memblock); + assert(target->length); + assert(target->memblock->data); pa_sink_ref(s); @@ -331,7 +373,10 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { } void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) { - assert(s && s->ref >= 1 && length && result); + assert(s); + assert(s->ref >= 1); + assert(length); + assert(result); /*** This needs optimization ***/ @@ -342,7 +387,8 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) { } pa_usec_t pa_sink_get_latency(pa_sink *s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); if (!s->get_latency) return 0; @@ -351,7 +397,8 @@ pa_usec_t pa_sink_get_latency(pa_sink *s) { } void pa_sink_set_owner(pa_sink *s, pa_module *m) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); s->owner = m; @@ -359,11 +406,40 @@ void pa_sink_set_owner(pa_sink *s, pa_module *m) { pa_source_set_owner(s->monitor_source, m); } -void pa_sink_set_volume(pa_sink *s, pa_volume_t volume) { - assert(s && s->ref >= 1); +void pa_sink_set_volume(pa_sink *s, pa_mixer_t m, const pa_cvolume *volume) { + pa_cvolume *v; - if (s->volume != volume) { - s->volume = volume; - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); - } + assert(s); + assert(s->ref >= 1); + assert(volume); + + if (m == PA_MIXER_HARDWARE && s->set_hw_volume) + v = &s->hw_volume; + else + v = &s->sw_volume; + + if (pa_cvolume_equal(v, volume)) + return; + + *v = *volume; + + if (v == &s->hw_volume) + if (s->set_hw_volume(s) < 0) + s->sw_volume = *volume; + + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); +} + +const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_mixer_t m) { + assert(s); + assert(s->ref >= 1); + + if (m == PA_MIXER_HARDWARE && s->set_hw_volume) { + + if (s->get_hw_volume) + s->get_hw_volume(s); + + return &s->hw_volume; + } else + return &s->sw_volume; } diff --git a/polyp/sink.h b/polyp/sink.h index 22d90858..33aba233 100644 --- a/polyp/sink.h +++ b/polyp/sink.h @@ -30,39 +30,55 @@ typedef struct pa_sink pa_sink; #include "sample.h" #include "idxset.h" #include "source.h" -#include "typeid.h" +#include "channelmap.h" #include "module.h" +#include "volume.h" #define PA_MAX_INPUTS_PER_SINK 6 typedef enum pa_sink_state { PA_SINK_RUNNING, PA_SINK_DISCONNECTED -} pa_sink_state; +} pa_sink_state_t; + +typedef enum pa_mixer { + PA_MIXER_SOFTWARE, + PA_MIXER_HARDWARE +} pa_mixer_t; struct pa_sink { int ref; - pa_sink_state state; - uint32_t index; - pa_typeid_t typeid; + pa_core *core; + pa_sink_state_t state; - char *name, *description; + char *name, *description, *driver; pa_module *owner; - pa_core *core; + pa_sample_spec sample_spec; - pa_idxset *inputs; + pa_channel_map channel_map; + pa_idxset *inputs; pa_source *monitor_source; - - pa_volume_t volume; + + pa_cvolume hw_volume, sw_volume; void (*notify)(pa_sink*sink); pa_usec_t (*get_latency)(pa_sink *s); + int (*set_hw_volume)(pa_sink *s); + int (*get_hw_volume)(pa_sink *s); + void *userdata; }; -pa_sink* pa_sink_new(pa_core *core, pa_typeid_t typeid, const char *name, int fail, const pa_sample_spec *spec); +pa_sink* pa_sink_new( + pa_core *core, + const char *driver, + const char *name, + int namereg_fail, + const pa_sample_spec *spec, + const pa_channel_map *map); + void pa_sink_disconnect(pa_sink* s); void pa_sink_unref(pa_sink*s); pa_sink* pa_sink_ref(pa_sink *s); @@ -78,6 +94,7 @@ void pa_sink_notify(pa_sink*s); void pa_sink_set_owner(pa_sink *sink, pa_module *m); -void pa_sink_set_volume(pa_sink *sink, pa_volume_t volume); +void pa_sink_set_volume(pa_sink *sink, pa_mixer_t m, const pa_cvolume *volume); +const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_mixer_t m); #endif diff --git a/polyp/socket-client.c b/polyp/socket-client.c index a884aa61..29c9775e 100644 --- a/polyp/socket-client.c +++ b/polyp/socket-client.c @@ -173,7 +173,7 @@ static void connect_fixed_cb(pa_mainloop_api *m, pa_defer_event *e, void *userda do_call(c); } -static void connect_io_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags f, void *userdata) { +static void connect_io_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { pa_socket_client *c = userdata; assert(m && c && c->io_event == e && fd >= 0); do_call(c); @@ -344,7 +344,7 @@ pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[ #ifdef HAVE_LIBASYNCNS -static void asyncns_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags f, void *userdata) { +static void asyncns_cb(pa_mainloop_api*m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { pa_socket_client *c = userdata; struct addrinfo *res = NULL; int ret; diff --git a/polyp/socket-server.c b/polyp/socket-server.c index 6f1794bc..262b32a7 100644 --- a/polyp/socket-server.c +++ b/polyp/socket-server.c @@ -78,7 +78,7 @@ struct pa_socket_server { enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX, SOCKET_SERVER_IPV6 } type; }; -static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags f, void *userdata) { +static void callback(pa_mainloop_api *mainloop, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { pa_socket_server *s = userdata; pa_iochannel *io; int nfd; diff --git a/polyp/sound-file-stream.c b/polyp/sound-file-stream.c index a277eb25..881e3077 100644 --- a/polyp/sound-file-stream.c +++ b/polyp/sound-file-stream.c @@ -36,7 +36,6 @@ #include "log.h" #define BUF_SIZE (1024*10) -#define PA_TYPEID_SOUND_FILE PA_TYPEID_MAKE('S', 'N', 'D', 'F') struct userdata { SNDFILE *sndfile; @@ -116,15 +115,12 @@ static void sink_input_drop(pa_sink_input *i, const pa_memchunk*chunk, size_t le } } -int pa_play_file(pa_sink *sink, const char *fname, pa_volume_t volume) { +int pa_play_file(pa_sink *sink, const char *fname, const pa_cvolume *volume) { struct userdata *u = NULL; SF_INFO sfinfo; pa_sample_spec ss; assert(sink && fname); - if (volume <= 0) - goto fail; - u = pa_xmalloc(sizeof(struct userdata)); u->sink_input = NULL; u->memchunk.memblock = NULL; @@ -161,10 +157,11 @@ int pa_play_file(pa_sink *sink, const char *fname, pa_volume_t volume) { goto fail; } - if (!(u->sink_input = pa_sink_input_new(sink, PA_TYPEID_SOUND_FILE, fname, &ss, 0, -1))) + if (!(u->sink_input = pa_sink_input_new(sink, __FILE__, fname, &ss, NULL, 0, -1))) goto fail; - u->sink_input->volume = volume; + if (volume) + u->sink_input->volume = *volume; u->sink_input->peek = sink_input_peek; u->sink_input->drop = sink_input_drop; u->sink_input->kill = sink_input_kill; diff --git a/polyp/sound-file-stream.h b/polyp/sound-file-stream.h index 0b383f96..2e56ef49 100644 --- a/polyp/sound-file-stream.h +++ b/polyp/sound-file-stream.h @@ -24,6 +24,6 @@ #include "sink.h" -int pa_play_file(pa_sink *sink, const char *fname, pa_volume_t volume); +int pa_play_file(pa_sink *sink, const char *fname, const pa_cvolume *volume); #endif diff --git a/polyp/source-output.c b/polyp/source-output.c index 7a540633..e1d8ccf7 100644 --- a/polyp/source-output.c +++ b/polyp/source-output.c @@ -33,13 +33,24 @@ #include "subscribe.h" #include "log.h" -pa_source_output* pa_source_output_new(pa_source *s, pa_typeid_t typeid, const char *name, const pa_sample_spec *spec, int resample_method) { +pa_source_output* pa_source_output_new( + pa_source *s, + const char *driver, + const char *name, + const pa_sample_spec *spec, + const pa_channel_map *map, + int resample_method) { + pa_source_output *o; pa_resampler *resampler = NULL; int r; char st[256]; - assert(s && spec); + pa_channel_map tmap; + assert(s); + assert(spec); + assert(s->state == PA_SOURCE_RUNNING); + if (pa_idxset_size(s->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) { pa_log(__FILE__": Failed to create source output: too many outputs per source.\n"); return NULL; @@ -48,25 +59,31 @@ pa_source_output* pa_source_output_new(pa_source *s, pa_typeid_t typeid, const c if (resample_method == PA_RESAMPLER_INVALID) resample_method = s->core->resample_method; - if (!pa_sample_spec_equal(&s->sample_spec, spec)) - if (!(resampler = pa_resampler_new(&s->sample_spec, spec, s->core->memblock_stat, resample_method))) + if (!map) { + pa_channel_map_init_auto(&tmap, spec->channels); + map = &tmap; + } + + if (!pa_sample_spec_equal(&s->sample_spec, spec) || !pa_channel_map_equal(&s->channel_map, map)) + if (!(resampler = pa_resampler_new(&s->sample_spec, &s->channel_map, spec, map, s->core->memblock_stat, resample_method))) return NULL; o = pa_xmalloc(sizeof(pa_source_output)); o->ref = 1; o->state = PA_SOURCE_OUTPUT_RUNNING; o->name = pa_xstrdup(name); - o->typeid = typeid; - - o->client = NULL; + o->driver = pa_xstrdup(driver); o->owner = NULL; o->source = s; + o->client = NULL; + o->sample_spec = *spec; + o->channel_map = *map; o->push = NULL; o->kill = NULL; - o->userdata = NULL; o->get_latency = NULL; + o->userdata = NULL; o->resampler = resampler; @@ -85,7 +102,10 @@ pa_source_output* pa_source_output_new(pa_source *s, pa_typeid_t typeid, const c } void pa_source_output_disconnect(pa_source_output*o) { - assert(o && o->state != PA_SOURCE_OUTPUT_DISCONNECTED && o->source && o->source->core); + assert(o); + assert(o->state != PA_SOURCE_OUTPUT_DISCONNECTED); + assert(o->source); + assert(o->source->core); pa_idxset_remove_by_data(o->source->core->source_outputs, o, NULL); pa_idxset_remove_by_data(o->source->outputs, o, NULL); @@ -95,7 +115,7 @@ void pa_source_output_disconnect(pa_source_output*o) { o->push = NULL; o->kill = NULL; - + o->get_latency = NULL; o->state = PA_SOURCE_OUTPUT_DISCONNECTED; } @@ -112,26 +132,31 @@ static void source_output_free(pa_source_output* o) { pa_resampler_free(o->resampler); pa_xfree(o->name); + pa_xfree(o->driver); pa_xfree(o); } void pa_source_output_unref(pa_source_output* o) { - assert(o && o->ref >= 1); + assert(o); + assert(o->ref >= 1); if (!(--o->ref)) source_output_free(o); } pa_source_output* pa_source_output_ref(pa_source_output *o) { - assert(o && o->ref >= 1); + assert(o); + assert(o->ref >= 1); + o->ref++; return o; } void pa_source_output_kill(pa_source_output*o) { - assert(o && o->ref >= 1); + assert(o); + assert(o->ref >= 1); if (o->kill) o->kill(o); @@ -139,7 +164,11 @@ void pa_source_output_kill(pa_source_output*o) { void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { pa_memchunk rchunk; - assert(o && chunk && chunk->length && o->push); + + assert(o); + assert(chunk); + assert(chunk->length); + assert(o->push); if (o->state == PA_SOURCE_OUTPUT_CORKED) return; @@ -159,7 +188,9 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) { } void pa_source_output_set_name(pa_source_output *o, const char *name) { - assert(o && o->ref >= 1); + assert(o); + assert(o->ref >= 1); + pa_xfree(o->name); o->name = pa_xstrdup(name); @@ -167,7 +198,8 @@ void pa_source_output_set_name(pa_source_output *o, const char *name) { } pa_usec_t pa_source_output_get_latency(pa_source_output *o) { - assert(o && o->ref >= 1); + assert(o); + assert(o->ref >= 1); if (o->get_latency) return o->get_latency(o); @@ -176,7 +208,8 @@ pa_usec_t pa_source_output_get_latency(pa_source_output *o) { } void pa_source_output_cork(pa_source_output *o, int b) { - assert(o && o->ref >= 1); + assert(o); + assert(o->ref >= 1); if (o->state == PA_SOURCE_OUTPUT_DISCONNECTED) return; @@ -184,9 +217,10 @@ void pa_source_output_cork(pa_source_output *o, int b) { o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING; } -pa_resample_method pa_source_output_get_resample_method(pa_source_output *o) { - assert(o && o->ref >= 1); - +pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o) { + assert(o); + assert(o->ref >= 1); + if (!o->resampler) return PA_RESAMPLER_INVALID; diff --git a/polyp/source-output.h b/polyp/source-output.h index ef8f9fa9..f8e4b152 100644 --- a/polyp/source-output.h +++ b/polyp/source-output.h @@ -37,20 +37,21 @@ typedef enum { PA_SOURCE_OUTPUT_RUNNING, PA_SOURCE_OUTPUT_CORKED, PA_SOURCE_OUTPUT_DISCONNECTED -} pa_source_output_state; +} pa_source_output_state_t; struct pa_source_output { int ref; - pa_source_output_state state; - uint32_t index; - pa_typeid_t typeid; - - char *name; + pa_source_output_state_t state; + + char *name, *driver; pa_module *owner; - pa_client *client; + pa_source *source; + pa_client *client; + pa_sample_spec sample_spec; + pa_channel_map channel_map; void (*push)(pa_source_output *o, const pa_memchunk *chunk); void (*kill)(pa_source_output* o); @@ -61,7 +62,14 @@ struct pa_source_output { void *userdata; }; -pa_source_output* pa_source_output_new(pa_source *s, pa_typeid_t typeid, const char *name, const pa_sample_spec *spec, int resample_method); +pa_source_output* pa_source_output_new( + pa_source *s, + const char *driver, + const char *name, + const pa_sample_spec *spec, + const pa_channel_map *map, + int resample_method); + void pa_source_output_unref(pa_source_output* o); pa_source_output* pa_source_output_ref(pa_source_output *o); @@ -79,6 +87,6 @@ pa_usec_t pa_source_output_get_latency(pa_source_output *i); void pa_source_output_cork(pa_source_output *i, int b); -pa_resample_method pa_source_output_get_resample_method(pa_source_output *o); +pa_resample_method_t pa_source_output_get_resample_method(pa_source_output *o); #endif diff --git a/polyp/source.c b/polyp/source.c index c287899e..6e377b20 100644 --- a/polyp/source.c +++ b/polyp/source.c @@ -35,13 +35,24 @@ #include "subscribe.h" #include "log.h" -pa_source* pa_source_new(pa_core *core, pa_typeid_t typeid, const char *name, int fail, const pa_sample_spec *spec) { +pa_source* pa_source_new( + pa_core *core, + const char *driver, + const char *name, + int fail, + const pa_sample_spec *spec, + const pa_channel_map *map) { + pa_source *s; char st[256]; int r; - assert(core && spec && name && *name); + + assert(core); + assert(name); + assert(*name); + assert(spec); - s = pa_xmalloc(sizeof(pa_source)); + s = pa_xnew(pa_source, 1); if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SOURCE, s, fail))) { pa_xfree(s); @@ -49,15 +60,19 @@ pa_source* pa_source_new(pa_core *core, pa_typeid_t typeid, const char *name, in } s->ref = 1; + s->core = core; s->state = PA_SOURCE_RUNNING; - s->name = pa_xstrdup(name); s->description = NULL; - s->typeid = typeid; - + s->driver = pa_xstrdup(driver); s->owner = NULL; - s->core = core; + s->sample_spec = *spec; + if (map) + s->channel_map = *map; + else + pa_channel_map_init_auto(&s->channel_map, spec->channels); + s->outputs = pa_idxset_new(NULL, NULL); s->monitor_of = NULL; @@ -78,7 +93,9 @@ pa_source* pa_source_new(pa_core *core, pa_typeid_t typeid, const char *name, in void pa_source_disconnect(pa_source *s) { pa_source_output *o, *j = NULL; - assert(s && s->state == PA_SOURCE_RUNNING); + + assert(s); + assert(s->state == PA_SOURCE_RUNNING); pa_namereg_unregister(s->core, s->name); @@ -89,15 +106,17 @@ void pa_source_disconnect(pa_source *s) { } pa_idxset_remove_by_data(s->core->sources, s, NULL); - pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); + s->get_latency = NULL; s->notify = NULL; s->state = PA_SOURCE_DISCONNECTED; + pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE | PA_SUBSCRIPTION_EVENT_REMOVE, s->index); } static void source_free(pa_source *s) { - assert(s && !s->ref); + assert(s); + assert(!s->ref); if (s->state != PA_SOURCE_DISCONNECTED) pa_source_disconnect(s); @@ -108,40 +127,49 @@ static void source_free(pa_source *s) { pa_xfree(s->name); pa_xfree(s->description); + pa_xfree(s->driver); pa_xfree(s); } void pa_source_unref(pa_source *s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); if (!(--s->ref)) source_free(s); } pa_source* pa_source_ref(pa_source *s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); + s->ref++; return s; } void pa_source_notify(pa_source*s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); if (s->notify) s->notify(s); } static int do_post(void *p, PA_GCC_UNUSED uint32_t idx, int *del, void*userdata) { - const pa_memchunk *chunk = userdata; pa_source_output *o = p; - assert(o && o->push && del && chunk); + const pa_memchunk *chunk = userdata; + + assert(o); + assert(chunk); pa_source_output_push(o, chunk); return 0; } void pa_source_post(pa_source*s, const pa_memchunk *chunk) { - assert(s && s->ref >= 1 && chunk); + assert(s); + assert(s->ref >= 1); + assert(chunk); pa_source_ref(s); pa_idxset_foreach(s->outputs, do_post, (void*) chunk); @@ -150,11 +178,14 @@ void pa_source_post(pa_source*s, const pa_memchunk *chunk) { void pa_source_set_owner(pa_source *s, pa_module *m) { assert(s); + assert(s->ref >= 1); + s->owner = m; } pa_usec_t pa_source_get_latency(pa_source *s) { - assert(s && s->ref >= 1); + assert(s); + assert(s->ref >= 1); if (!s->get_latency) return 0; diff --git a/polyp/source.h b/polyp/source.h index c7f8d059..823a9424 100644 --- a/polyp/source.h +++ b/polyp/source.h @@ -31,7 +31,7 @@ typedef struct pa_source pa_source; #include "memblock.h" #include "memchunk.h" #include "sink.h" -#include "typeid.h" +#include "channelmap.h" #include "module.h" #define PA_MAX_OUTPUTS_PER_SOURCE 16 @@ -39,28 +39,37 @@ typedef struct pa_source pa_source; typedef enum pa_source_state { PA_SOURCE_RUNNING, PA_SOURCE_DISCONNECTED -} pa_source_state; +} pa_source_state_t; struct pa_source { int ref; - pa_source_state state; - uint32_t index; - pa_typeid_t typeid; + pa_core *core; + pa_source_state_t state; - char *name, *description; + char *name, *description, *driver; pa_module *owner; - pa_core *core; + pa_sample_spec sample_spec; + pa_channel_map channel_map; + pa_idxset *outputs; pa_sink *monitor_of; - + void (*notify)(pa_source*source); pa_usec_t (*get_latency)(pa_source *s); + void *userdata; }; -pa_source* pa_source_new(pa_core *core, pa_typeid_t typeid, const char *name, int fail, const pa_sample_spec *spec); +pa_source* pa_source_new( + pa_core *core, + const char *driver, + const char *name, + int namereg_fail, + const pa_sample_spec *spec, + const pa_channel_map *map); + void pa_source_disconnect(pa_source *s); void pa_source_unref(pa_source *s); pa_source* pa_source_ref(pa_source *c); diff --git a/polyp/subscribe.c b/polyp/subscribe.c index d3db90f7..e8b3c841 100644 --- a/polyp/subscribe.c +++ b/polyp/subscribe.c @@ -41,22 +41,22 @@ struct pa_subscription { pa_core *core; int dead; - void (*callback)(pa_core *c, pa_subscription_event_type t, uint32_t index, void *userdata); + void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata); void *userdata; - pa_subscription_mask mask; + pa_subscription_mask_t mask; pa_subscription *prev, *next; }; struct pa_subscription_event { - pa_subscription_event_type type; + pa_subscription_event_type_t type; uint32_t index; }; static void sched_event(pa_core *c); /* Allocate a new subscription object for the given subscription mask. Use the specified callback function and user data */ -pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask m, void (*callback)(pa_core *c, pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata) { +pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata) { pa_subscription *s; assert(c); @@ -210,7 +210,7 @@ static void sched_event(pa_core *c) { } /* Append a new subscription event to the subscription event queue and schedule a main loop event */ -void pa_subscription_post(pa_core *c, pa_subscription_event_type t, uint32_t index) { +void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t index) { pa_subscription_event *e; assert(c); diff --git a/polyp/subscribe.h b/polyp/subscribe.h index 6980328f..625159e3 100644 --- a/polyp/subscribe.h +++ b/polyp/subscribe.h @@ -28,10 +28,10 @@ typedef struct pa_subscription_event pa_subscription_event; #include "core.h" #include "native-common.h" -pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask m, void (*callback)(pa_core *c, pa_subscription_event_type t, uint32_t index, void *userdata), void *userdata); +pa_subscription* pa_subscription_new(pa_core *c, pa_subscription_mask_t m, void (*callback)(pa_core *c, pa_subscription_event_type_t t, uint32_t index, void *userdata), void *userdata); void pa_subscription_free(pa_subscription*s); void pa_subscription_free_all(pa_core *c); -void pa_subscription_post(pa_core *c, pa_subscription_event_type t, uint32_t idx); +void pa_subscription_post(pa_core *c, pa_subscription_event_type_t t, uint32_t idx); #endif diff --git a/polyp/tagstruct.c b/polyp/tagstruct.c index 28b1afa6..d4980411 100644 --- a/polyp/tagstruct.c +++ b/polyp/tagstruct.c @@ -54,7 +54,9 @@ enum tags { TAG_BOOLEAN_TRUE = '1', TAG_BOOLEAN_FALSE = '0', TAG_TIMEVAL = 'T', - TAG_USEC = 'U' /* 64bit unsigned */ + TAG_USEC = 'U' /* 64bit unsigned */, + TAG_CHANNEL_MAP = 'm', + TAG_CVOLUME = 'v' }; struct pa_tagstruct { @@ -204,6 +206,34 @@ void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t u) { t->length += 9; } +void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map) { + unsigned i; + + assert(t); + extend(t, 2 + map->channels); + + t->data[t->length++] = TAG_CHANNEL_MAP; + t->data[t->length++] = map->channels; + + for (i = 0; i < map->channels; i ++) + t->data[t->length++] = (uint8_t) map->map[i]; +} + +void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume) { + unsigned i; + + assert(t); + extend(t, 2 + cvolume->channels * sizeof(pa_volume_t)); + + t->data[t->length++] = TAG_CVOLUME; + t->data[t->length++] = cvolume->channels; + + for (i = 0; i < cvolume->channels; i ++) { + *(pa_volume_t*) (t->data + t->length) = htonl(cvolume->values[i]); + t->length += sizeof(pa_volume_t); + } +} + int pa_tagstruct_gets(pa_tagstruct*t, const char **s) { int error = 0; size_t n; @@ -283,6 +313,9 @@ int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss) { ss->channels = t->data[t->rindex+2]; memcpy(&ss->rate, t->data+t->rindex+3, 4); ss->rate = ntohl(ss->rate); + + if (!pa_sample_spec_valid(ss)) + return -1; t->rindex += 7; return 0; @@ -387,3 +420,59 @@ int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *u) { t->rindex +=9; return 0; } + +int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map) { + unsigned i; + + assert(t); + assert(map); + + if (t->rindex+2 > t->length) + return -1; + + if (t->data[t->rindex] != TAG_CHANNEL_MAP) + return -1; + + if ((map->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX) + return -1; + + if (t->rindex+2+map->channels > t->length) + return -1; + + for (i = 0; i < map->channels; i ++) + map->map[i] = (int8_t) t->data[t->rindex + 2 + i]; + + if (!pa_channel_map_valid(map)) + return -1; + + t->rindex += 2 + map->channels; + return 0; +} + +int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *cvolume) { + unsigned i; + + assert(t); + assert(cvolume); + + if (t->rindex+2 > t->length) + return -1; + + if (t->data[t->rindex] != TAG_CVOLUME) + return -1; + + if ((cvolume->channels = t->data[t->rindex+1]) > PA_CHANNELS_MAX) + return -1; + + if (t->rindex+2+cvolume->channels*sizeof(pa_volume_t) > t->length) + return -1; + + for (i = 0; i < cvolume->channels; i ++) + cvolume->values[i] = (pa_volume_t) ntohl(*((pa_volume_t*) (t->data + t->rindex + 2)+i)); + + if (!pa_cvolume_valid(cvolume)) + return -1; + + t->rindex += 2 + cvolume->channels * sizeof(pa_volume_t); + return 0; +} diff --git a/polyp/tagstruct.h b/polyp/tagstruct.h index 85b324b7..cd6a8f99 100644 --- a/polyp/tagstruct.h +++ b/polyp/tagstruct.h @@ -28,6 +28,8 @@ #include #include "sample.h" +#include "channelmap.h" +#include "volume.h" typedef struct pa_tagstruct pa_tagstruct; @@ -44,6 +46,8 @@ void pa_tagstruct_put_arbitrary(pa_tagstruct*t, const void *p, size_t length); void pa_tagstruct_put_boolean(pa_tagstruct*t, int b); void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv); void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u); +void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map); +void pa_tagstruct_put_cvolume(pa_tagstruct *t, const pa_cvolume *cvolume); int pa_tagstruct_gets(pa_tagstruct*t, const char **s); int pa_tagstruct_getu8(pa_tagstruct*t, uint8_t *c); @@ -54,6 +58,8 @@ int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length); int pa_tagstruct_get_boolean(pa_tagstruct *t, int *b); int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv); int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u); +int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map); +int pa_tagstruct_get_cvolume(pa_tagstruct *t, pa_cvolume *v); int pa_tagstruct_eof(pa_tagstruct*t); const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l); diff --git a/polyp/typeid.c b/polyp/typeid.c deleted file mode 100644 index 70d3df33..00000000 --- a/polyp/typeid.c +++ /dev/null @@ -1,33 +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. -***/ - -#include - -#include "typeid.h" - -char *pa_typeid_to_string(pa_typeid_t id, char *ret_s, size_t length) { - if (id == PA_TYPEID_UNKNOWN) - snprintf(ret_s, length, "????"); - else - snprintf(ret_s, length, "%c%c%c%c", (char) (id >> 24), (char) (id >> 16), (char) (id >> 8), (char) (id)); - - return ret_s; -} diff --git a/polyp/typeid.h b/polyp/typeid.h deleted file mode 100644 index cc1676bc..00000000 --- a/polyp/typeid.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef footypeidhfoo -#define footypeidhfoo - -/* $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 -#include - -#include - -PA_C_DECL_BEGIN - -typedef uint32_t pa_typeid_t; - -#define PA_TYPEID_UNKNOWN ((pa_typeid_t) -1) - -char *pa_typeid_to_string(pa_typeid_t id, char *ret_s, size_t length); - -#define PA_TYPEID_MAKE(a,b,c,d) (\ - (((pa_typeid_t) a & 0xFF) << 24) | \ - (((pa_typeid_t) b & 0xFF) << 16) | \ - (((pa_typeid_t) c & 0xFF) << 8) | \ - (((pa_typeid_t) d & 0xFF))) - -PA_C_DECL_END - -#endif diff --git a/polyp/voltest.c b/polyp/voltest.c index 286334d0..917e04d3 100644 --- a/polyp/voltest.c +++ b/polyp/voltest.c @@ -2,14 +2,19 @@ #include -#include +#include #include "gccmacro.h" int main(PA_GCC_UNUSED int argc, PA_GCC_UNUSED char *argv[]) { - int p; - for (p = 0; p <= 200; p++) { - pa_volume_t v = pa_volume_from_user((double) p/100); - double dB = pa_volume_to_dB(v); - printf("%3i%% = %u = %0.2f dB = %u = %3i%%\n", p, v, dB, pa_volume_from_dB(dB), (int) (pa_volume_to_user(v)*100)); + pa_volume_t v; + + for (v = PA_VOLUME_MUTED; v <= PA_VOLUME_NORM*2; v += 256) { + + double dB = pa_sw_volume_to_dB(v); + double f = pa_sw_volume_to_linear(v); + + printf("Volume: %3i; percent: %i%%; decibel %0.2f; linear = %0.2f; volume(decibel): %3i; volume(linear): %3i\n", + v, (v*100)/PA_VOLUME_NORM, dB, f, pa_sw_volume_from_dB(dB), pa_sw_volume_from_linear(f)); + } } diff --git a/polyp/volume.c b/polyp/volume.c new file mode 100644 index 00000000..0f153141 --- /dev/null +++ b/polyp/volume.c @@ -0,0 +1,176 @@ +/* $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 +#endif + +#include +#include +#include + +#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/polyp/volume.h b/polyp/volume.h new file mode 100644 index 00000000..b2a48084 --- /dev/null +++ b/polyp/volume.h @@ -0,0 +1,107 @@ +#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 +#include +#include + +/** \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; + pa_volume_t values[PA_CHANNELS_MAX]; +} 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); + +/** Pretty print a volume structure */ +#define PA_CVOLUME_SNPRINT_MAX 64 +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); + +#define pa_cvolume_is_muted(a) pa_cvolume_channels_equal_to((a), PA_VOLUME_MUTED) +#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. */ +pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b); + +pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b); + +/** Convert a decibel value to a volume. \since 0.4 */ +pa_volume_t pa_sw_volume_from_dB(double f); + +/** Convert a volume to a decibel value. \since 0.4 */ +double pa_sw_volume_to_dB(pa_volume_t v); + +/** Convert a linear factor to a volume. \since 0.8 */ +pa_volume_t pa_sw_volume_from_linear(double v); + +/** Convert a volume to a linear factor. \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/polyp/x11prop.c b/polyp/x11prop.c index bbe3e32c..e57fc136 100644 --- a/polyp/x11prop.c +++ b/polyp/x11prop.c @@ -33,7 +33,7 @@ void pa_x11_set_prop(Display *d, const char *name, const char *data) { Atom a = XInternAtom(d, name, False); - XChangeProperty(d, RootWindow(d, 0), a, XA_STRING, 8, PropModeReplace, (unsigned char*) data, strlen(data)+1); + XChangeProperty(d, RootWindow(d, 0), a, XA_STRING, 8, PropModeReplace, (const unsigned char*) data, strlen(data)+1); } void pa_x11_del_prop(Display *d, const char *name) { diff --git a/polyp/x11wrap.c b/polyp/x11wrap.c index 64923320..e20a50a6 100644 --- a/polyp/x11wrap.c +++ b/polyp/x11wrap.c @@ -76,7 +76,7 @@ static void work(pa_x11_wrapper *w) { } /* IO notification event for the X11 display connection */ -static void display_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags f, void *userdata) { +static void display_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { pa_x11_wrapper *w = userdata; assert(m && e && fd >= 0 && w && w->ref >= 1); work(w); @@ -90,7 +90,7 @@ static void defer_event(pa_mainloop_api *m, pa_defer_event *e, void *userdata) { } /* IO notification event for X11 internal connections */ -static void internal_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags f, void *userdata) { +static void internal_io_event(pa_mainloop_api *m, pa_io_event *e, int fd, PA_GCC_UNUSED pa_io_event_flags_t f, void *userdata) { pa_x11_wrapper *w = userdata; assert(m && e && fd >= 0 && w && w->ref >= 1); -- cgit