diff options
114 files changed, 2549 insertions, 1294 deletions
diff --git a/configure.ac b/configure.ac index f2de1653..710f205b 100644 --- a/configure.ac +++ b/configure.ac @@ -330,6 +330,11 @@ AC_SUBST(HOWL_LIBS)  AC_SUBST(HAVE_HOWL)  AM_CONDITIONAL([HAVE_HOWL], [test "x$HAVE_HOWL" = x1]) + +PKG_CHECK_MODULES(LIBOIL, [ liboil-0.3 >= 0.3.0 ]) +AC_SUBST(LIBOIL_CFLAGS) +AC_SUBST(LIBOIL_LIBS) +  #### Async DNS support (optional) ####  PKG_CHECK_MODULES(LIBASYNCNS, [ libasyncns >= 0.1 ], HAVE_LIBASYNCNS=1, HAVE_LIBASYNCNS=0) 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 <config.h> +#endif + +#include <stdlib.h> +#include <assert.h> +#include <stdio.h> +#include <string.h> + +#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 <polyp/sample.h> +#include <polyp/cdecl.h> + +/** \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 <fcntl.h>  #include <unistd.h>  #include <sys/types.h> +#include <liboil/liboil.h>  #ifdef HAVE_SYS_IOCTL_H  #include <sys/ioctl.h> @@ -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=<name for the sink> device=<ALSA device> format=<sample format> channels=<number of channels> rate=<sample rate> fragments=<number of fragments> fragment_size=<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=<name for the source> device=<ALSA device> format=<sample format> channels=<number of channels> rate=<sample rate> fragments=<number of fragments> fragment_size=<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=<name for the sink> master=<master sink> slaves=<slave sinks> adjust_time=<seconds> resample_method=<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=<name for the sink> server=<address> cookie=<filename>  format=<sample format> channels=<number of channels> rate=<sample 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=<sample format> channels=<number of channels> rate=<samp  #define DEFAULT_SINK_NAME "null" -#define PA_TYPEID_NULL PA_TYPEID_MAKE('N', 'U', 'L', 'L') -  struct userdata {      pa_core *core;      pa_module *module; @@ -108,7 +106,7 @@ int pa__init(pa_core *c, pa_module*m) {      u->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=<name for the sink> source_name=<name for the source> device=<OSS device> record=<enable source?> playback=<enable sink?> format=<sample format> channels=<number of channels> rate=<sample rate> fragments=<number of fragments> fragment_size=<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=<name for the sink> source_name=<name for the source> device=<OSS device> record=<enable source?> playback=<enable sink?> format=<sample format> channels=<number of channels> rate=<sample rate> fragments=<number of fragments> fragment_size=<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=<name for the sink> file=<path of the FIFO> format=<s  #define DEFAULT_FIFO_NAME "/tmp/music.output"  #define DEFAULT_SINK_NAME "fifo_output" -#define PA_TYPEID_PIPE PA_TYPEID_MAKE('P', 'I', 'P', 'E') -  struct userdata {      pa_core *core; @@ -177,7 +175,7 @@ int pa__init(pa_core *c, pa_module*m) {      u->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=<name for the source> file=<path of the FIFO> 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=<sink to connect to> source=<source to connect to> public=<don't check for cookies?> cookie=<path to cookie file> "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=<sink to connect to> frequency=<frequency in Hz>")  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=<address> source=<remote source name> cookie=<filename>  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 <polyp/polyplib-operation.h>  #include <polyp/polyplib-context.h>  #include <polyp/cdecl.h> -#include <polyp/typeid.h> +#include <polyp/channelmap.h> +#include <polyp/volume.h>  /** \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 <sys/types.h>  #include <polyp/sample.h> +#include <polyp/channelmap.h> +#include <polyp/volume.h>  #include <polyp/polyplib-def.h>  #include <polyp/cdecl.h>  #include <polyp/polyplib-operation.h> @@ -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 <string.h>  #include <samplerate.h> +#include <liboil/liboilfuncs.h> +#include <liboil/liboil.h>  #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 <assert.h>  #include <stdlib.h> +#include <liboil/liboilfuncs.h> +  #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 <config.h>  #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 <assert.h>  #include <inttypes.h> +#include <liboil/liboilfuncs.h> +  #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 <stdio.h>  #include <stdlib.h>  #include <assert.h> + +#include <liboil/liboilfuncs.h> +#include <liboil/liboil.h> +  #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 <time.h>  #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 <stdio.h> - -#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 <inttypes.h> -#include <sys/types.h> - -#include <polyp/cdecl.h> - -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 <stdio.h> -#include <polyp/sample.h> +#include <polyp/volume.h>  #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 <config.h> +#endif + +#include <assert.h> +#include <stdio.h> +#include <string.h> + +#include "volume.h" + +int pa_cvolume_equal(const pa_cvolume *a, const pa_cvolume *b) { +    int i; +    assert(a); +    assert(b); + +    if (a->channels != b->channels) +        return 0; +     +    for (i = 0; i < a->channels; i++) +        if (a->values[i] != b->values[i]) +            return 0; + +    return 1; +} + +pa_cvolume* pa_cvolume_set(pa_cvolume *a, unsigned channels, pa_volume_t v) { +    int i; +     +    assert(a); +    assert(channels > 0); +    assert(channels <= PA_CHANNELS_MAX); + +    a->channels = channels; + +    for (i = 0; i < a->channels; i++) +        a->values[i] = v; + +    return a; +} + +pa_volume_t pa_cvolume_avg(const pa_cvolume *a) { +    uint64_t sum = 0; +    int i; +    assert(a); + +    for (i = 0; i < a->channels; i++) +        sum += a->values[i]; + +    sum /= a->channels; + +    return (pa_volume_t) sum; +} + +pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) { +    return pa_sw_volume_from_linear(pa_sw_volume_to_linear(a)* pa_sw_volume_to_linear(b)); +} + +#define USER_DECIBEL_RANGE 30 + +pa_volume_t pa_sw_volume_from_dB(double dB) { +    if (dB <= -USER_DECIBEL_RANGE) +        return PA_VOLUME_MUTED; + +    return (pa_volume_t) ((dB/USER_DECIBEL_RANGE+1)*PA_VOLUME_NORM); +} + +double pa_sw_volume_to_dB(pa_volume_t v) { +    if (v == PA_VOLUME_MUTED) +        return PA_DECIBEL_MININFTY; + +    return ((double) v/PA_VOLUME_NORM-1)*USER_DECIBEL_RANGE; +} + +pa_volume_t pa_sw_volume_from_linear(double v) { + +    if (v <= 0) +        return PA_VOLUME_MUTED; + +    if (v > .999 && v < 1.001) +        return PA_VOLUME_NORM; + +    return pa_sw_volume_from_dB(20*log10(v)); +} + +double pa_sw_volume_to_linear(pa_volume_t v) { + +    if (v == PA_VOLUME_MUTED) +        return 0; + +    return pow(10, pa_sw_volume_to_dB(v)/20); +} + +char *pa_cvolume_snprint(char *s, size_t l, const pa_cvolume *c) { +    unsigned channel; +    int first = 1; +    char *e; +     +    assert(s); +    assert(l > 0); +    assert(c); + +    *(e = s) = 0; + +    for (channel = 0; channel < c->channels && l > 1; channel++) { +        l -= snprintf(e, l, "%s%u: %3u%%", +                      first ? "" : " ", +                      channel, +                      (c->values[channel]*100)/PA_VOLUME_NORM); + +        e = strchr(e, 0); +        first = 0; +    } + +    return s; +} + +/** Return non-zero if the volume of all channels is equal to the specified value */ +int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) { +    unsigned c; +    assert(a); + +    for (c = 0; c < a->channels; c++) +        if (a->values[c] != v) +            return 0; + +    return 1; +} + +pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) { +    unsigned i; +     +    assert(dest); +    assert(a); +    assert(b); + +    for (i = 0; i < a->channels || i < b->channels || i < PA_CHANNELS_MAX; i++) { + +        dest->values[i] = pa_sw_volume_multiply( +            i < a->channels ? a->values[i] : PA_VOLUME_NORM, +            i < b->channels ? b->values[i] : PA_VOLUME_NORM); +    } + +    dest->channels = i; + +    return dest; +} + +int pa_cvolume_valid(const pa_cvolume *v) { +    assert(v); + +    if (v->channels <= 0 || v->channels > PA_CHANNELS_MAX) +        return 0; + +    return 1; +} diff --git a/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 <inttypes.h> +#include <polyp/cdecl.h> +#include <polyp/sample.h> + +/** \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);  | 
