Mega patch:

* implement inner loops using liboil
* drop "typeid" stuff
* add support for channel maps
* add support for seperate volumes per channel
* add support for hardware mixer settings (only module-oss implements this for now)
* fix a lot of types for _t suffix


git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@463 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2006-01-27 16:25:31 +00:00
parent 759721cbbc
commit dd10c98241
114 changed files with 2584 additions and 1329 deletions

View file

@ -330,6 +330,11 @@ AC_SUBST(HOWL_LIBS)
AC_SUBST(HAVE_HOWL) AC_SUBST(HAVE_HOWL)
AM_CONDITIONAL([HAVE_HOWL], [test "x$HAVE_HOWL" = x1]) 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) #### #### Async DNS support (optional) ####
PKG_CHECK_MODULES(LIBASYNCNS, [ libasyncns >= 0.1 ], HAVE_LIBASYNCNS=1, HAVE_LIBASYNCNS=0) PKG_CHECK_MODULES(LIBASYNCNS, [ libasyncns >= 0.1 ], HAVE_LIBASYNCNS=1, HAVE_LIBASYNCNS=0)

View file

@ -47,6 +47,7 @@ AM_CFLAGS += $(PTHREAD_CFLAGS) -D_POSIX_PTHREAD_SEMANTICS
AM_CFLAGS += $(LTDLINCL) AM_CFLAGS += $(LTDLINCL)
AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS) AM_CFLAGS += $(LIBSAMPLERATE_CFLAGS) $(LIBSNDFILE_CFLAGS)
AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\" AM_CFLAGS += -DDLSEARCHPATH=\"$(modlibdir)\"
#AM_CFLAGS += -DDLSEARCHPATH=\"$(shell pwd)\"
AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(DEFAULT_CONFIG_DIR)\" AM_CFLAGS += -DDEFAULT_CONFIG_DIR=\"$(DEFAULT_CONFIG_DIR)\"
AM_CFLAGS += -DPOLYPAUDIO_BINARY=\"$(POLYPAUDIO_BINARY)\" AM_CFLAGS += -DPOLYPAUDIO_BINARY=\"$(POLYPAUDIO_BINARY)\"
@ -101,10 +102,10 @@ polypaudio_SOURCES = \
main.c \ main.c \
pid.c pid.h pid.c pid.h
polypaudio_CFLAGS = $(AM_CFLAGS) polypaudio_CFLAGS = $(AM_CFLAGS) $(LIBOIL_CFLAGS)
polypaudio_CPPFLAGS = $(AM_CPPFLAGS) polypaudio_CPPFLAGS = $(AM_CPPFLAGS)
polypaudio_LDADD = $(AM_LDADD) libpolypcore.la $(LIBLTDL) \ 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)) polypaudio_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) -dlopen force $(foreach f,$(PREOPEN_LIBS),-dlopen $(f))
if PREOPEN_MODS if PREOPEN_MODS
@ -219,7 +220,7 @@ strlist_test_CFLAGS = $(AM_CFLAGS)
strlist_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS) strlist_test_LDADD = $(AM_LDADD) $(WINSOCK_LIBS)
strlist_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) 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_CFLAGS = $(AM_CFLAGS)
voltest_LDADD = $(AM_LDADD) voltest_LDADD = $(AM_LDADD)
voltest_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS) voltest_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
@ -265,8 +266,7 @@ polypinclude_HEADERS = \
polyplib-stream.h \ polyplib-stream.h \
polyplib-subscribe.h \ polyplib-subscribe.h \
polyplib-version.h \ polyplib-version.h \
sample.h \ sample.h
typeid.h
if HAVE_HOWL if HAVE_HOWL
polypinclude_HEADERS += \ polypinclude_HEADERS += \
@ -333,10 +333,11 @@ libpolyp_@PA_MAJORMINOR@_la_SOURCES = \
strbuf.c strbuf.h \ strbuf.c strbuf.h \
strlist.c strlist.h \ strlist.c strlist.h \
tagstruct.c tagstruct.h \ tagstruct.c tagstruct.h \
typeid.c typeid.h \
util.c util.h \ util.c util.h \
winsock.h \ winsock.h \
xmalloc.c xmalloc.h xmalloc.c xmalloc.h \
channelmap.c channelmap.h \
volume.c volume.h
if HAVE_X11 if HAVE_X11
libpolyp_@PA_MAJORMINOR@_la_SOURCES += \ libpolyp_@PA_MAJORMINOR@_la_SOURCES += \
@ -475,14 +476,15 @@ libpolypcore_la_SOURCES = \
strbuf.c strbuf.h \ strbuf.c strbuf.h \
subscribe.c subscripe.h \ subscribe.c subscripe.h \
tokenizer.c tokenizer.h \ tokenizer.c tokenizer.h \
typeid.c typeid.h \
util.c util.h \ util.c util.h \
winsock.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_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 # # Plug-in support libraries #

View file

@ -85,7 +85,7 @@ finish:
* *io_events. Store the length of that array in *n_io_events. Use the * *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 * specified callback function and userdata. The array has to be freed
* with pa_free_io_events(). */ * 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; unsigned i;
struct pollfd *pfds, *ppfd; struct pollfd *pfds, *ppfd;
pa_io_event **ios; pa_io_event **ios;

View file

@ -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_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); void pa_free_io_events(pa_mainloop_api* m, pa_io_event **io_sources, unsigned n_io_sources);
#endif #endif

View file

@ -81,7 +81,7 @@ static pa_autoload_entry* entry_new(pa_core *c, const char *name) {
return e; 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; pa_autoload_entry *e = NULL;
assert(c && name && module && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); 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; 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; pa_autoload_entry *e;
assert(c && name && type); assert(c && name && type);
@ -120,7 +120,7 @@ int pa_autoload_remove_by_index(pa_core *c, uint32_t idx) {
return 0; 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_autoload_entry *e;
pa_module *m; pa_module *m;
assert(c && name); 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; pa_autoload_entry *e;
assert(c && name); assert(c && name);

View file

@ -34,7 +34,7 @@ typedef struct pa_autoload_entry {
pa_core *core; pa_core *core;
uint32_t index; uint32_t index;
char *name; 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 */ int in_action; /* Currently loaded */
char *module, *argument; char *module, *argument;
} pa_autoload_entry; } pa_autoload_entry;
@ -42,17 +42,17 @@ typedef struct pa_autoload_entry {
/* Add a new autoload entry of the given time, with the speicified /* Add a new autoload entry of the given time, with the speicified
* sink/source name, module name and argument. Return the entry's * sink/source name, module name and argument. Return the entry's
* index in *index */ * 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 */ /* Free all autoload entries */
void pa_autoload_free(pa_core *c); 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); 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 */ /* 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); const pa_autoload_entry* pa_autoload_get_by_index(pa_core *c, uint32_t idx);
#endif #endif

202
polyp/channelmap.c Normal file
View file

@ -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;
}

94
polyp/channelmap.h Normal file
View file

@ -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

View file

@ -311,6 +311,7 @@ static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *bu
const char *n, *v; const char *n, *v;
pa_sink *sink; pa_sink *sink;
uint32_t volume; uint32_t volume;
pa_cvolume cvolume;
if (!(n = pa_tokenizer_get(t, 1))) { 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"); 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; 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; return 0;
} }
static int pa_cli_command_sink_input_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_GCC_UNUSED int *fail) { 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; const char *n, *v;
pa_sink_input *si; pa_sink_input *si;
uint32_t volume; pa_volume_t volume;
pa_cvolume cvolume;
uint32_t idx; uint32_t idx;
if (!(n = pa_tokenizer_get(t, 1))) { 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; 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; return 0;
} }
@ -497,7 +501,7 @@ static int pa_cli_command_scache_play(pa_core *c, pa_tokenizer *t, pa_strbuf *bu
return -1; 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"); pa_strbuf_puts(buf, "Failed to play sample.\n");
return -1; 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) { 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; nl = 0;
for (s = pa_idxset_first(c->sinks, &idx); s; s = pa_idxset_next(c->sinks, &idx)) { 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) if (s->owner && s->owner->auto_unload)
continue; continue;
@ -674,7 +675,7 @@ static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, PA_G
nl = 1; 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)));
} }

View file

@ -38,6 +38,7 @@
#include "scache.h" #include "scache.h"
#include "autoload.h" #include "autoload.h"
#include "xmalloc.h" #include "xmalloc.h"
#include "volume.h"
char *pa_module_list_to_string(pa_core *c) { char *pa_module_list_to_string(pa_core *c) {
pa_strbuf *s; pa_strbuf *s;
@ -60,7 +61,6 @@ char *pa_client_list_to_string(pa_core *c) {
pa_strbuf *s; pa_strbuf *s;
pa_client *client; pa_client *client;
uint32_t idx = PA_IDXSET_INVALID; uint32_t idx = PA_IDXSET_INVALID;
char tid[5];
assert(c); assert(c);
s = pa_strbuf_new(); 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)); 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)) { 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) if (client->owner)
pa_strbuf_printf(s, "\towner module: <%u>\n", client->owner->index); 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_strbuf *s;
pa_sink *sink; pa_sink *sink;
uint32_t idx = PA_IDXSET_INVALID; uint32_t idx = PA_IDXSET_INVALID;
char tid[5];
assert(c); assert(c);
s = pa_strbuf_new(); 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)); 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)) { for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) {
char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; 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), &sink->sample_spec);
assert(sink->monitor_source);
pa_strbuf_printf( pa_strbuf_printf(
s, 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) ? '*' : ' ', c->default_sink_name && !strcmp(sink->name, c->default_sink_name) ? '*' : ' ',
sink->index, sink->name, sink->index, sink->name,
pa_typeid_to_string(sink->typeid, tid, sizeof(tid)), sink->driver,
(unsigned) sink->volume, pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, PA_MIXER_HARDWARE)),
pa_volume_to_dB(sink->volume),
(double) pa_sink_get_latency(sink), (double) pa_sink_get_latency(sink),
sink->monitor_source->index, 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) if (sink->owner)
pa_strbuf_printf(s, "\towner module: <%u>\n", sink->owner->index); 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_strbuf *s;
pa_source *source; pa_source *source;
uint32_t idx = PA_IDXSET_INVALID; uint32_t idx = PA_IDXSET_INVALID;
char tid[5];
assert(c); assert(c);
s = pa_strbuf_new(); 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)); 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)) { for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) {
char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_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) ? '*' : ' ', pa_strbuf_printf(
source->index, s,
source->name, " %c index: %u\n"
pa_typeid_to_string(source->typeid, tid, sizeof(tid)), "\tname: <%s>\n"
(double) pa_source_get_latency(source), "\tdriver: <%s>\n"
ss); "\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) if (source->monitor_of)
pa_strbuf_printf(s, "\tmonitor_of: <%u>\n", source->monitor_of->index); 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_strbuf *s;
pa_source_output *o; pa_source_output *o;
uint32_t idx = PA_IDXSET_INVALID; uint32_t idx = PA_IDXSET_INVALID;
char tid[5];
static const char* const state_table[] = { static const char* const state_table[] = {
"RUNNING", "RUNNING",
"CORKED", "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)); 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)) { 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]; char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
const char *rm;
pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec);
assert(o->source); assert(o->source);
if (!(rm = pa_resample_method_to_string(pa_source_output_get_resample_method(o))))
rm = "invalid";
pa_strbuf_printf( 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->index,
o->name, o->name,
pa_typeid_to_string(o->typeid, tid, sizeof(tid)), o->driver,
state_table[o->state], state_table[o->state],
o->source->index, o->source->name, o->source->index, o->source->name,
ss, pa_sample_spec_snprint(ss, sizeof(ss), &o->sample_spec),
rm); 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) if (o->owner)
pa_strbuf_printf(s, "\towner module: <%u>\n", o->owner->index); pa_strbuf_printf(s, "\towner module: <%u>\n", o->owner->index);
if (o->client) if (o->client)
@ -198,7 +215,6 @@ char *pa_sink_input_list_to_string(pa_core *c) {
pa_strbuf *s; pa_strbuf *s;
pa_sink_input *i; pa_sink_input *i;
uint32_t idx = PA_IDXSET_INVALID; uint32_t idx = PA_IDXSET_INVALID;
char tid[5];
static const char* const state_table[] = { static const char* const state_table[] = {
"RUNNING", "RUNNING",
"CORKED", "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)); 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)) { 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]; char ss[PA_SAMPLE_SPEC_SNPRINT_MAX], cv[PA_CVOLUME_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
const char *rm;
if (!(rm = pa_resample_method_to_string(pa_sink_input_get_resample_method(i))))
rm = "invalid";
pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec);
assert(i->sink); assert(i->sink);
pa_strbuf_printf( 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->index,
i->name, i->name,
pa_typeid_to_string(i->typeid, tid, sizeof(tid)), i->driver,
state_table[i->state], state_table[i->state],
i->sink->index, i->sink->name, i->sink->index, i->sink->name,
(unsigned) i->volume, pa_cvolume_snprint(cv, sizeof(cv), pa_sink_input_get_volume(i)),
pa_volume_to_dB(i->volume),
(double) pa_sink_input_get_latency(i), (double) pa_sink_input_get_latency(i),
ss, pa_sample_spec_snprint(ss, sizeof(ss), &i->sample_spec),
rm); 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) if (i->owner)
pa_strbuf_printf(s, "\towner module: <%u>\n", i->owner->index); 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)) { for (e = pa_idxset_first(c->scache, &idx); e; e = pa_idxset_next(c->scache, &idx)) {
double l = 0; 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) { if (e->memchunk.memblock) {
pa_sample_spec_snprint(ss, sizeof(ss), &e->sample_spec); 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); l = (double) e->memchunk.length / pa_bytes_per_second(&e->sample_spec);
} }
pa_strbuf_printf( 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->name,
e->index, e->index,
ss, ss,
cm,
e->memchunk.memblock ? e->memchunk.length : 0, e->memchunk.memblock ? e->memchunk.length : 0,
l, l,
e->volume, pa_cvolume_snprint(cv, sizeof(cv), &e->volume),
e->lazy ? "yes" : "no", e->lazy ? "yes" : "no",
e->filename ? e->filename : "n/a"); e->filename ? e->filename : "n/a");
} }

View file

@ -45,7 +45,6 @@
#include "log.h" #include "log.h"
#define PROMPT ">>> " #define PROMPT ">>> "
#define PA_TYPEID_CLI PA_TYPEID_MAKE('C', 'L', 'I', '_')
struct pa_cli { struct pa_cli {
pa_core *core; 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; c->eof_callback = NULL;
pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); 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); assert(c->client);
c->client->kill = client_kill; c->client->kill = client_kill;
c->client->userdata = c; c->client->userdata = c;

View file

@ -33,16 +33,16 @@
#include "subscribe.h" #include "subscribe.h"
#include "log.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; pa_client *c;
int r; int r;
assert(core); assert(core);
c = pa_xmalloc(sizeof(pa_client)); c = pa_xmalloc(sizeof(pa_client));
c->name = pa_xstrdup(name); c->name = pa_xstrdup(name);
c->driver = pa_xstrdup(driver);
c->owner = NULL; c->owner = NULL;
c->core = core; c->core = core;
c->typeid = typeid;
c->kill = NULL; c->kill = NULL;
c->userdata = 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_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_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_REMOVE, c->index);
pa_xfree(c->name); pa_xfree(c->name);
pa_xfree(c->driver);
pa_xfree(c); pa_xfree(c);
} }
void pa_client_kill(pa_client *c) { void pa_client_kill(pa_client *c) {

View file

@ -24,7 +24,6 @@
#include "core.h" #include "core.h"
#include "module.h" #include "module.h"
#include "typeid.h"
/* Every connection to the server should have a pa_client /* Every connection to the server should have a pa_client
* attached. That way the user may generate a listing of all connected * 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 { struct pa_client {
uint32_t index; uint32_t index;
pa_typeid_t typeid;
pa_module *owner; pa_module *owner;
char *name; char *name, *driver;
pa_core *core; pa_core *core;
void (*kill)(pa_client *c); void (*kill)(pa_client *c);
void *userdata; 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 */ /* This function should be called only by the code that created the client */
void pa_client_free(pa_client *c); void pa_client_free(pa_client *c);

View file

@ -70,7 +70,7 @@ struct pa_core {
pa_time_event *scache_auto_unload_event; 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); pa_core* pa_core_new(pa_mainloop_api *m);

View file

@ -126,7 +126,7 @@ int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string) {
if (u >= PA_LOG_LEVEL_MAX) if (u >= PA_LOG_LEVEL_MAX)
return -1; return -1;
c->log_level = (pa_log_level) u; c->log_level = (pa_log_level_t) u;
} else if (pa_startswith(string, "debug")) } else if (pa_startswith(string, "debug"))
c->log_level = PA_LOG_DEBUG; c->log_level = PA_LOG_DEBUG;
else if (pa_startswith(string, "info")) else if (pa_startswith(string, "info"))

View file

@ -33,11 +33,11 @@ typedef enum pa_daemon_conf_cmd {
PA_CMD_DUMP_MODULES, PA_CMD_DUMP_MODULES,
PA_CMD_KILL, PA_CMD_KILL,
PA_CMD_CHECK PA_CMD_CHECK
} pa_daemon_conf_cmd; } pa_daemon_conf_cmd_t;
/* A structure containing configuration data for the Polypaudio server . */ /* A structure containing configuration data for the Polypaudio server . */
typedef struct pa_daemon_conf { typedef struct pa_daemon_conf {
pa_daemon_conf_cmd cmd; pa_daemon_conf_cmd_t cmd;
int daemonize, int daemonize,
fail, fail,
high_priority, high_priority,
@ -48,8 +48,8 @@ typedef struct pa_daemon_conf {
auto_log_target, auto_log_target,
use_pid_file; use_pid_file;
char *script_commands, *dl_search_path, *default_script_file; char *script_commands, *dl_search_path, *default_script_file;
pa_log_target log_target; pa_log_target_t log_target;
pa_log_level log_level; pa_log_level_t log_level;
int resample_method; int resample_method;
char *config_file; char *config_file;
} pa_daemon_conf; } pa_daemon_conf;

View file

@ -1,4 +1,4 @@
/* $Id: dllmain.c 317 2004-12-11 00:10:41Z lennart $ */ /* $Id$ */
/*** /***
This file is part of polypaudio. This file is part of polypaudio.

View file

@ -38,9 +38,9 @@ struct pa_io_event {
GSource *source; GSource *source;
GIOCondition io_condition; GIOCondition io_condition;
int fd; 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 *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; 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 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_io_event *e;
pa_glib_mainloop *g; 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 */ /* The callback GLIB calls whenever an IO condition is met */
static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) { static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) {
pa_io_event *e = data; pa_io_event *e = data;
pa_io_event_flags f; pa_io_event_flags_t f;
assert(source && e && e->io_channel == source); assert(source && e && e->io_channel == source);
f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | 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; 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; GIOCondition c;
assert(e && !e->dead); assert(e && !e->dead);

View file

@ -39,7 +39,7 @@ struct pa_io_event {
guint source; guint source;
GIOCondition io_condition; GIOCondition io_condition;
int fd; 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 *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; 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 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_io_event *e;
pa_glib_mainloop *g; 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) { static gboolean io_cb(GIOChannel *source, GIOCondition condition, gpointer data) {
pa_io_event *e = data; pa_io_event *e = data;
pa_io_event_flags f; pa_io_event_flags_t f;
assert(source && e && e->io_channel == source); assert(source && e && e->io_channel == source);
f = (condition & G_IO_IN ? PA_IO_EVENT_INPUT : 0) | 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; 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; GIOCondition c;
assert(e && !e->dead); assert(e && !e->dead);

View file

@ -1,4 +1,4 @@
/* $Id: inet_ntop.c 428 2006-01-09 16:50:39Z ossman $ */ /* $Id$ */
/*** /***
This file is part of polypaudio. This file is part of polypaudio.

View file

@ -55,7 +55,7 @@ static void enable_mainloop_sources(pa_iochannel *io) {
assert(io); assert(io);
if (io->input_event == io->output_event && io->input_event) { 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); assert(io->input_event);
if (!io->readable) 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; pa_iochannel *io = userdata;
int changed = 0; int changed = 0;

View file

@ -38,9 +38,9 @@
#define ENV_LOGLEVEL "POLYP_LOG" #define ENV_LOGLEVEL "POLYP_LOG"
static char *log_ident = NULL; static char *log_ident = NULL;
static pa_log_target log_target = PA_LOG_STDERR; static pa_log_target_t log_target = PA_LOG_STDERR;
static void (*user_log_func)(pa_log_level l, const char *s) = NULL; static void (*user_log_func)(pa_log_level_t l, const char *s) = NULL;
static pa_log_level maximal_level = PA_LOG_NOTICE; static pa_log_level_t maximal_level = PA_LOG_NOTICE;
#ifdef HAVE_SYSLOG_H #ifdef HAVE_SYSLOG_H
static const int level_to_syslog[] = { static const int level_to_syslog[] = {
@ -59,18 +59,18 @@ void pa_log_set_ident(const char *p) {
log_ident = pa_xstrdup(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); assert(l < PA_LOG_LEVEL_MAX);
maximal_level = l; 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); assert(t == PA_LOG_USER || !func);
log_target = t; log_target = t;
user_log_func = func; 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; const char *e;
assert(level < PA_LOG_LEVEL_MAX); 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_list ap;
va_start(ap, format); va_start(ap, format);
pa_log_with_levelv(level, format, ap); pa_log_levelv(level, format, ap);
va_end(ap); va_end(ap);
} }
void pa_log_debug(const char *format, ...) { void pa_log_debug(const char *format, ...) {
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
pa_log_with_levelv(PA_LOG_DEBUG, format, ap); pa_log_levelv(PA_LOG_DEBUG, format, ap);
va_end(ap); va_end(ap);
} }
void pa_log_info(const char *format, ...) { void pa_log_info(const char *format, ...) {
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
pa_log_with_levelv(PA_LOG_INFO, format, ap); pa_log_levelv(PA_LOG_INFO, format, ap);
va_end(ap); va_end(ap);
} }
void pa_log_notice(const char *format, ...) { void pa_log_notice(const char *format, ...) {
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
pa_log_with_levelv(PA_LOG_INFO, format, ap); pa_log_levelv(PA_LOG_INFO, format, ap);
va_end(ap); va_end(ap);
} }
void pa_log_warn(const char *format, ...) { void pa_log_warn(const char *format, ...) {
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
pa_log_with_levelv(PA_LOG_WARN, format, ap); pa_log_levelv(PA_LOG_WARN, format, ap);
va_end(ap); va_end(ap);
} }
void pa_log_error(const char *format, ...) { void pa_log_error(const char *format, ...) {
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
pa_log_with_levelv(PA_LOG_ERROR, format, ap); pa_log_levelv(PA_LOG_ERROR, format, ap);
va_end(ap); va_end(ap);
} }

View file

@ -33,7 +33,7 @@ typedef enum pa_log_target {
PA_LOG_SYSLOG, PA_LOG_SYSLOG,
PA_LOG_USER, /* to user specified function */ PA_LOG_USER, /* to user specified function */
PA_LOG_NULL /* to /dev/null */ PA_LOG_NULL /* to /dev/null */
} pa_log_target; } pa_log_target_t;
typedef enum pa_log_level { typedef enum pa_log_level {
PA_LOG_ERROR = 0, /* Error messages */ PA_LOG_ERROR = 0, /* Error messages */
@ -42,16 +42,16 @@ typedef enum pa_log_level {
PA_LOG_INFO = 3, /* Info messages */ PA_LOG_INFO = 3, /* Info messages */
PA_LOG_DEBUG = 4, /* debug message */ PA_LOG_DEBUG = 4, /* debug message */
PA_LOG_LEVEL_MAX PA_LOG_LEVEL_MAX
} pa_log_level; } pa_log_level_t;
/* Set an identification for the current daemon. Used when logging to syslog. */ /* Set an identification for the current daemon. Used when logging to syslog. */
void pa_log_set_ident(const char *p); 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 */ /* 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 */ /* 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 */ /* Do a log line */
void pa_log_debug(const char *format, ...) PA_GCC_PRINTF_ATTR(1,2); 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_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_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 #define pa_log pa_log_error

View file

@ -37,6 +37,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <sys/types.h> #include <sys/types.h>
#include <liboil/liboil.h>
#ifdef HAVE_SYS_IOCTL_H #ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h> #include <sys/ioctl.h>
@ -386,6 +387,8 @@ int main(int argc, char *argv[]) {
pa_signal_new(SIGHUP, signal_callback, c); pa_signal_new(SIGHUP, signal_callback, c);
#endif #endif
oil_init();
r = pa_cpu_limit_init(pa_mainloop_get_api(mainloop)); r = pa_cpu_limit_init(pa_mainloop_get_api(mainloop));
assert(r == 0); assert(r == 0);

View file

@ -51,7 +51,7 @@ typedef enum pa_io_event_flags {
PA_IO_EVENT_OUTPUT = 2, /**< Output event */ PA_IO_EVENT_OUTPUT = 2, /**< Output event */
PA_IO_EVENT_HANGUP = 4, /**< Hangup event */ PA_IO_EVENT_HANGUP = 4, /**< Hangup event */
PA_IO_EVENT_ERROR = 8 /**< Error event */ PA_IO_EVENT_ERROR = 8 /**< Error event */
} pa_io_event_flags; } pa_io_event_flags_t;
/** \pa_io_event /** \pa_io_event
* An opaque IO event source object */ * An opaque IO event source object */
@ -73,10 +73,10 @@ struct pa_mainloop_api {
void *userdata; void *userdata;
/** Create a new IO event source object */ /** 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 */ /** 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 */ /** Free a IO event source object */
void (*io_free)(pa_io_event* e); void (*io_free)(pa_io_event* e);

View file

@ -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; ssize_t r;
int sig; int sig;
assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]); assert(a && e && f == PA_IO_EVENT_INPUT && e == io_event && fd == signal_pipe[0]);

View file

@ -51,7 +51,7 @@ static GMainLoop* glib_main_loop = NULL;
static pa_defer_event *de; 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; unsigned char c;
read(fd, &c, sizeof(c)); read(fd, &c, sizeof(c));
fprintf(stderr, "IO EVENT: %c\n", c < 32 ? '.' : c); fprintf(stderr, "IO EVENT: %c\n", c < 32 ? '.' : c);

View file

@ -50,8 +50,8 @@ struct pa_io_event {
pa_mainloop *mainloop; pa_mainloop *mainloop;
int dead; int dead;
int fd; int fd;
pa_io_event_flags events; pa_io_event_flags_t events;
void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags f, void *userdata); void (*callback) (pa_mainloop_api*a, pa_io_event *e, int fd, pa_io_event_flags_t f, void *userdata);
struct pollfd *pollfd; struct pollfd *pollfd;
void *userdata; void *userdata;
void (*destroy_callback) (pa_mainloop_api*a, pa_io_event *e, void *userdata); void (*destroy_callback) (pa_mainloop_api*a, pa_io_event *e, void *userdata);
@ -91,7 +91,13 @@ struct pa_mainloop {
}; };
/* IO events */ /* 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_mainloop *m;
pa_io_event *e; 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; 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); assert(e && e->mainloop);
e->events = events; e->events = events;

View file

@ -31,12 +31,12 @@
* memory blocks. */ * memory blocks. */
/* The type of memory this block points to */ /* 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_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_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_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_USER /* User supplied memory, to be freed with free_cb */
} pa_memblock_type ; } pa_memblock_type_t;
/* A structure of keeping memory block statistics */ /* A structure of keeping memory block statistics */
/* Maintains statistics about memory blocks */ /* Maintains statistics about memory blocks */
@ -49,7 +49,7 @@ typedef struct pa_memblock_stat {
} pa_memblock_stat; } pa_memblock_stat;
typedef struct pa_memblock { typedef struct pa_memblock {
pa_memblock_type type; pa_memblock_type_t type;
unsigned ref; /* the reference counter */ unsigned ref; /* the reference counter */
int read_only; /* boolean */ int read_only; /* boolean */
size_t length; size_t length;

View file

@ -51,8 +51,6 @@ PA_MODULE_DESCRIPTION("ALSA Sink")
PA_MODULE_VERSION(PACKAGE_VERSION) 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>") 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 { struct userdata {
snd_pcm_t *pcm_handle; snd_pcm_t *pcm_handle;
pa_sink *sink; 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; struct userdata *u = userdata;
assert(u && a && e); assert(u && a && e);
@ -220,7 +218,7 @@ int pa__init(pa_core *c, pa_module*m) {
goto fail; 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); assert(u->sink);
u->sink->get_latency = sink_get_latency_cb; 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->frame_size = frame_size;
u->fragment_size = period_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); u->silence.memblock = pa_memblock_new(u->silence.length = u->fragment_size, c->memblock_stat);
assert(u->silence.memblock); assert(u->silence.memblock);

View file

@ -51,8 +51,6 @@ PA_MODULE_DESCRIPTION("ALSA Source")
PA_MODULE_VERSION(PACKAGE_VERSION) 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>") 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 { struct userdata {
snd_pcm_t *pcm_handle; snd_pcm_t *pcm_handle;
pa_source *source; 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; struct userdata *u = userdata;
assert(u && a && e); assert(u && a && e);
@ -211,7 +209,7 @@ int pa__init(pa_core *c, pa_module*m) {
goto fail; 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); assert(u->source);
u->source->userdata = u; u->source->userdata = u;

View file

@ -43,8 +43,6 @@ PA_MODULE_DESCRIPTION("Combine multiple sinks to one")
PA_MODULE_VERSION(PACKAGE_VERSION) 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>") 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 DEFAULT_SINK_NAME "combined"
#define MEMBLOCKQ_MAXLENGTH (1024*170) #define MEMBLOCKQ_MAXLENGTH (1024*170)
#define RENDER_SIZE (1024*10) #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); 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); 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; goto fail;
o->sink_input->get_latency = sink_input_get_latency_cb; 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; 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"); pa_log(__FILE__": failed to create sink\n");
goto fail; goto fail;
} }

View file

@ -46,14 +46,12 @@
#include "authkey.h" #include "authkey.h"
PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_AUTHOR("Lennart Poettering")
PA_MODULE_DESCRIPTION("Esound ") PA_MODULE_DESCRIPTION("ESOUND Sink")
PA_MODULE_VERSION(PACKAGE_VERSION) 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>") 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 DEFAULT_SINK_NAME "esound_output"
#define PA_TYPEID_ESOUND_SINK PA_TYPEID_MAKE('E', 'S', 'D', 'S')
struct userdata { struct userdata {
pa_core *core; pa_core *core;
@ -354,7 +352,7 @@ int pa__init(pa_core *c, pa_module*m) {
u->state = STATE_AUTH; u->state = STATE_AUTH;
u->latency = 0; 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"); pa_log(__FILE__": failed to create sink.\n");
goto fail; goto fail;
} }

View file

@ -61,7 +61,7 @@ struct userdata {
static int lirc_in_use = 0; 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; struct userdata *u = userdata;
char *name = NULL, *code = NULL; char *name = NULL, *code = NULL;
assert(io); assert(io);
@ -109,18 +109,36 @@ 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))) 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); pa_log(__FILE__": failed to get sink '%s'\n", u->sink_name);
else { 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) { switch (volchange) {
case UP: v += .05; break; case UP:
case DOWN: v -= .05; break; v += PA_VOLUME_NORM/20;
case MUTE: v = 0; break; break;
case RESET: v = 1; 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: { case MUTE_TOGGLE: {
if (v > 0) { if (v > 0) {
u->mute_toggle_save = v; u->mute_toggle_save = v;
v = 0; v = PA_VOLUME_MUTED;
} else } else
v = u->mute_toggle_save; v = u->mute_toggle_save;
} }
@ -128,7 +146,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);
} }
} }
} }

View file

@ -154,7 +154,7 @@ finish:
return ret; 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; struct userdata *u = userdata;
pa_sink_input *si; pa_sink_input *si;
struct rule *r; 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) { for (r = u->rules; r; r = r->next) {
if (!regexec(&r->regex, si->name, 0, NULL, 0)) { 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_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);
} }
} }
} }

View file

@ -74,7 +74,7 @@ struct userdata {
float mute_toggle_save; 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; struct userdata *u = userdata;
assert(io); assert(io);
assert(u); 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))) 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); pa_log(__FILE__": failed to get sink '%s'\n", u->sink_name);
else { 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) { switch (volchange) {
case UP: v += .05; break; case UP:
case DOWN: v -= .05; break; v += DELTA;
break;
case DOWN:
if (v > DELTA)
v -= DELTA;
else
v = PA_VOLUME_MUTED;
break;
case MUTE_TOGGLE: { case MUTE_TOGGLE: {
if (v > 0) { if (v > 0) {
u->mute_toggle_save = v; u->mute_toggle_save = v;
v = 0; v = PA_VOLUME_MUTED;
} else } else
v = u->mute_toggle_save; 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);
} }
} }
} }

View file

@ -49,8 +49,6 @@ PA_MODULE_USAGE("format=<sample format> channels=<number of channels> rate=<samp
#define DEFAULT_SINK_NAME "null" #define DEFAULT_SINK_NAME "null"
#define PA_TYPEID_NULL PA_TYPEID_MAKE('N', 'U', 'L', 'L')
struct userdata { struct userdata {
pa_core *core; pa_core *core;
pa_module *module; pa_module *module;
@ -108,7 +106,7 @@ int pa__init(pa_core *c, pa_module*m) {
u->module = m; u->module = m;
m->userdata = u; 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"); pa_log(__FILE__": failed to create sink.\n");
goto fail; goto fail;
} }

View file

@ -53,8 +53,6 @@ PA_MODULE_DESCRIPTION("OSS Sink/Source (mmap)")
PA_MODULE_VERSION(PACKAGE_VERSION) 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>") 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 { struct userdata {
pa_sink *sink; pa_sink *sink;
pa_source *source; pa_source *source;
@ -204,7 +202,7 @@ static void do_read(struct userdata *u) {
in_clear_memblocks(u, u->in_fragments/2); 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; struct userdata *u = userdata;
assert (u && u->core->mainloop == m && u->io_event == e); assert (u && u->core->mainloop == m && u->io_event == e);
@ -304,7 +302,7 @@ int pa__init(pa_core *c, pa_module*m) {
} }
} else { } 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); assert(u->source);
u->source->userdata = u; u->source->userdata = u;
pa_source_set_owner(u->source, m); pa_source_set_owner(u->source, m);
@ -336,7 +334,7 @@ int pa__init(pa_core *c, pa_module*m) {
} else { } else {
pa_silence_memory(u->out_mmap, u->out_mmap_length, &u->sample_spec); 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); assert(u->sink);
u->sink->get_latency = sink_get_latency_cb; u->sink->get_latency = sink_get_latency_cb;
u->sink->userdata = u; u->sink->userdata = u;

View file

@ -52,8 +52,6 @@ PA_MODULE_DESCRIPTION("OSS Sink/Source")
PA_MODULE_VERSION(PACKAGE_VERSION) 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>") 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 { struct userdata {
pa_sink *sink; pa_sink *sink;
pa_source *source; pa_source *source;
@ -222,7 +220,7 @@ static pa_usec_t sink_get_latency_cb(pa_sink *s) {
assert(s && u && u->sink); assert(s && u && u->sink);
if (ioctl(u->fd, SNDCTL_DSP_GETODELAY, &arg) < 0) { 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; s->get_latency = NULL;
return 0; 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); 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) { int pa__init(pa_core *c, pa_module*m) {
struct audio_buf_info info; struct audio_buf_info info;
struct userdata *u = NULL; struct userdata *u = NULL;
@ -332,7 +370,7 @@ int pa__init(pa_core *c, pa_module*m) {
} }
if (mode != O_WRONLY) { 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); assert(u->source);
u->source->userdata = u; u->source->userdata = u;
u->source->notify = source_notify_cb; u->source->notify = source_notify_cb;
@ -343,9 +381,11 @@ int pa__init(pa_core *c, pa_module*m) {
u->source = NULL; u->source = NULL;
if (mode != O_RDONLY) { 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); assert(u->sink);
u->sink->get_latency = sink_get_latency_cb; 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; u->sink->userdata = u;
pa_sink_set_owner(u->sink, m); pa_sink_set_owner(u->sink, m);
u->sink->description = pa_sprintf_malloc("Open Sound System PCM on '%s'", p); 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(u->fd, buf, u->sample_size);
} }
/* Read mixer settings */
if (u->sink)
sink_get_hw_volume(u->sink);
return 0; return 0;
fail: fail:

View file

@ -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_FIFO_NAME "/tmp/music.output"
#define DEFAULT_SINK_NAME "fifo_output" #define DEFAULT_SINK_NAME "fifo_output"
#define PA_TYPEID_PIPE PA_TYPEID_MAKE('P', 'I', 'P', 'E')
struct userdata { struct userdata {
pa_core *core; pa_core *core;
@ -177,7 +175,7 @@ int pa__init(pa_core *c, pa_module*m) {
u->module = m; u->module = m;
m->userdata = u; 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"); pa_log(__FILE__": failed to create sink.\n");
goto fail; goto fail;
} }

View file

@ -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_FIFO_NAME "/tmp/music.input"
#define DEFAULT_SOURCE_NAME "fifo_input" #define DEFAULT_SOURCE_NAME "fifo_input"
#define PA_TYPEID_PIPE PA_TYPEID_MAKE('P', 'I', 'P', 'E')
struct userdata { struct userdata {
pa_core *core; pa_core *core;
@ -154,7 +152,7 @@ int pa__init(pa_core *c, pa_module*m) {
u->filename = pa_xstrdup(p); u->filename = pa_xstrdup(p);
u->core = c; 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"); pa_log(__FILE__": failed to create source.\n");
goto fail; goto fail;
} }

View file

@ -146,7 +146,7 @@
#else #else
#include "module-esound-protocol-unix-symdef.h" #include "module-esound-protocol-unix-symdef.h"
#endif #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) 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 #else
#error "Broken build system" #error "Broken build system"

View file

@ -40,8 +40,6 @@ PA_MODULE_DESCRIPTION("Sine wave generator")
PA_MODULE_USAGE("sink=<sink to connect to> frequency=<frequency in Hz>") PA_MODULE_USAGE("sink=<sink to connect to> frequency=<frequency in Hz>")
PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_VERSION(PACKAGE_VERSION)
#define PA_TYPEID_SINE PA_TYPEID_MAKE('S', 'I', 'N', 'E')
struct userdata { struct userdata {
pa_core *core; pa_core *core;
pa_module *module; 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); calc_sine(u->memblock->data, u->memblock->length, frequency);
snprintf(t, sizeof(t), "Sine Generator at %u Hz", 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; goto fail;
u->sink_input->peek = sink_input_peek; u->sink_input->peek = sink_input_peek;

View file

@ -1,4 +1,4 @@
/* $Id: module-oss.c 333 2005-01-08 21:36:53Z lennart $ */ /* $Id$ */
/*** /***
This file is part of polypaudio. This file is part of polypaudio.

View file

@ -59,8 +59,6 @@ PA_MODULE_USAGE("server=<address> source=<remote source name> cookie=<filename>
PA_MODULE_AUTHOR("Lennart Poettering") PA_MODULE_AUTHOR("Lennart Poettering")
PA_MODULE_VERSION(PACKAGE_VERSION) PA_MODULE_VERSION(PACKAGE_VERSION)
#define PA_TYPEID_TUNNEL PA_TYPEID_MAKE('T', 'U', 'N', 'L')
#define DEFAULT_SINK_NAME "tunnel" #define DEFAULT_SINK_NAME "tunnel"
#define DEFAULT_SOURCE_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); pa_socket_client_set_callback(u->client, on_connection, u);
#ifdef TUNNEL_SINK #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"); pa_log(__FILE__": failed to create sink.\n");
goto fail; goto fail;
} }
@ -637,7 +635,7 @@ int pa__init(pa_core *c, pa_module*m) {
pa_sink_set_owner(u->sink, m); pa_sink_set_owner(u->sink, m);
#else #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"); pa_log(__FILE__": failed to create source.\n");
goto fail; goto fail;
} }

View file

@ -1,4 +1,4 @@
/* $Id: module-waveout.c 333 2005-01-08 21:36:53Z lennart $ */ /* $Id$ */
/*** /***
This file is part of polypaudio. This file is part of polypaudio.

View file

@ -66,6 +66,7 @@ static const char* const valid_modargs[] = {
static int ring_bell(struct userdata *u, int percent) { static int ring_bell(struct userdata *u, int percent) {
pa_sink *s; pa_sink *s;
pa_cvolume cv;
assert(u); assert(u);
if (!(s = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) { 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; 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; return 0;
} }

View file

@ -38,7 +38,7 @@
#include "util.h" #include "util.h"
struct namereg_entry { struct namereg_entry {
pa_namereg_type type; pa_namereg_type_t type;
char *name; char *name;
void *data; void *data;
}; };
@ -51,7 +51,7 @@ void pa_namereg_free(pa_core *c) {
pa_hashmap_free(c->namereg, NULL, NULL); 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; struct namereg_entry *e;
char *n = NULL; char *n = NULL;
int r; int r;
@ -110,7 +110,7 @@ void pa_namereg_unregister(pa_core *c, const char *name) {
pa_xfree(e); 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; struct namereg_entry *e;
uint32_t idx; uint32_t idx;
assert(c); assert(c);
@ -152,7 +152,7 @@ void* pa_namereg_get(pa_core *c, const char *name, pa_namereg_type type, int aut
return NULL; 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; char **s;
assert(c && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE)); assert(c && (type == PA_NAMEREG_SINK || type == PA_NAMEREG_SOURCE));

View file

@ -28,14 +28,14 @@ typedef enum pa_namereg_type {
PA_NAMEREG_SINK, PA_NAMEREG_SINK,
PA_NAMEREG_SOURCE, PA_NAMEREG_SOURCE,
PA_NAMEREG_SAMPLE PA_NAMEREG_SAMPLE
} pa_namereg_type ; } pa_namereg_type_t;
void pa_namereg_free(pa_core *c); 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_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_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 type); 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_sink_name(pa_core *c);
const char *pa_namereg_get_default_source_name(pa_core *c); const char *pa_namereg_get_default_source_name(pa_core *c);

View file

@ -51,6 +51,7 @@ enum {
PA_COMMAND_FINISH_UPLOAD_STREAM, PA_COMMAND_FINISH_UPLOAD_STREAM,
PA_COMMAND_PLAY_SAMPLE, PA_COMMAND_PLAY_SAMPLE,
PA_COMMAND_REMOVE_SAMPLE, PA_COMMAND_REMOVE_SAMPLE,
PA_COMMAND_GET_SERVER_INFO, PA_COMMAND_GET_SERVER_INFO,
PA_COMMAND_GET_SINK_INFO, PA_COMMAND_GET_SINK_INFO,
PA_COMMAND_GET_SINK_INFO_LIST, PA_COMMAND_GET_SINK_INFO_LIST,
@ -68,15 +69,19 @@ enum {
PA_COMMAND_GET_SAMPLE_INFO_LIST, PA_COMMAND_GET_SAMPLE_INFO_LIST,
PA_COMMAND_SUBSCRIBE, PA_COMMAND_SUBSCRIBE,
PA_COMMAND_SUBSCRIBE_EVENT, PA_COMMAND_SUBSCRIBE_EVENT,
PA_COMMAND_SET_SINK_VOLUME, PA_COMMAND_SET_SINK_VOLUME,
PA_COMMAND_SET_SINK_INPUT_VOLUME, PA_COMMAND_SET_SINK_INPUT_VOLUME,
PA_COMMAND_CORK_PLAYBACK_STREAM, PA_COMMAND_CORK_PLAYBACK_STREAM,
PA_COMMAND_FLUSH_PLAYBACK_STREAM, PA_COMMAND_FLUSH_PLAYBACK_STREAM,
PA_COMMAND_TRIGGER_PLAYBACK_STREAM, PA_COMMAND_TRIGGER_PLAYBACK_STREAM,
PA_COMMAND_SET_DEFAULT_SINK, PA_COMMAND_SET_DEFAULT_SINK,
PA_COMMAND_SET_DEFAULT_SOURCE, PA_COMMAND_SET_DEFAULT_SOURCE,
PA_COMMAND_SET_PLAYBACK_STREAM_NAME, PA_COMMAND_SET_PLAYBACK_STREAM_NAME,
PA_COMMAND_SET_RECORD_STREAM_NAME, PA_COMMAND_SET_RECORD_STREAM_NAME,
PA_COMMAND_KILL_CLIENT, PA_COMMAND_KILL_CLIENT,
PA_COMMAND_KILL_SINK_INPUT, PA_COMMAND_KILL_SINK_INPUT,
PA_COMMAND_KILL_SOURCE_OUTPUT, PA_COMMAND_KILL_SOURCE_OUTPUT,

View file

@ -48,7 +48,7 @@ int main(PA_GCC_UNUSED int argc, char*argv[]) {
int error; int error;
/* Create a new playback stream */ /* 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)); fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
goto finish; goto finish;
} }

View file

@ -162,16 +162,17 @@ static void context_state_callback(pa_context *c, void *userdata) {
if (verbose) if (verbose)
fprintf(stderr, "Connection established.\n"); 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); assert(stream);
pa_stream_set_state_callback(stream, stream_state_callback, NULL); pa_stream_set_state_callback(stream, stream_state_callback, NULL);
pa_stream_set_write_callback(stream, stream_write_callback, NULL); pa_stream_set_write_callback(stream, stream_write_callback, NULL);
pa_stream_set_read_callback(stream, stream_read_callback, NULL); pa_stream_set_read_callback(stream, stream_read_callback, NULL);
if (mode == PLAYBACK) if (mode == PLAYBACK) {
pa_stream_connect_playback(stream, device, NULL, 0, volume); pa_cvolume cv;
else 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); pa_stream_connect_record(stream, device, NULL, 0);
break; break;
@ -219,7 +220,7 @@ static void stream_drain_complete(pa_stream*s, int success, void *userdata) {
} }
/* New data on STDIN **/ /* 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; size_t l, w = 0;
ssize_t r; ssize_t r;
assert(a == mainloop_api && e && stdio_event == e); 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 */ /* 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; ssize_t r;
assert(a == mainloop_api && e && stdio_event == e); assert(a == mainloop_api && e && stdio_event == e);

View file

@ -149,7 +149,7 @@ 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) { 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) { if (is_last < 0) {
fprintf(stderr, "Failed to get sink information: %s\n", pa_strerror(pa_context_errno(c))); fprintf(stderr, "Failed to get sink information: %s\n", pa_strerror(pa_context_errno(c)));
@ -168,31 +168,31 @@ static void get_sink_info_callback(pa_context *c, const pa_sink_info *i, int is_
printf("\n"); printf("\n");
nl = 1; nl = 1;
pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec);
printf("*** Sink #%u ***\n" printf("*** Sink #%u ***\n"
"Name: %s\n" "Name: %s\n"
"Type: %s\n" "Driver: %s\n"
"Description: %s\n" "Description: %s\n"
"Sample Specification: %s\n" "Sample Specification: %s\n"
"Channel Map: %s\n"
"Owner Module: %u\n" "Owner Module: %u\n"
"Volume: 0x%03x (%0.2f dB)\n" "Volume: %s\n"
"Monitor Source: %u\n" "Monitor Source: %u\n"
"Latency: %0.0f usec\n", "Latency: %0.0f usec\n",
i->index, i->index,
i->name, i->name,
pa_typeid_to_string(i->_typeid, tid, sizeof(tid)), i->driver,
i->description, 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->owner_module,
i->volume, pa_volume_to_dB(i->volume), pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
i->monitor_source, i->monitor_source,
(double) i->latency); (double) i->latency);
} }
static void get_source_info_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) { 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) { if (is_last < 0) {
fprintf(stderr, "Failed to get source information: %s\n", pa_strerror(pa_context_errno(c))); 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); snprintf(t, sizeof(t), "%u", i->monitor_of_sink);
pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec);
printf("*** Source #%u ***\n" printf("*** Source #%u ***\n"
"Name: %s\n" "Name: %s\n"
"Type: %s\n" "Driver: %s\n"
"Description: %s\n" "Description: %s\n"
"Sample Specification: %s\n" "Sample Specification: %s\n"
"Channel Map: %s\n"
"Owner Module: %u\n" "Owner Module: %u\n"
"Monitor of Sink: %s\n" "Monitor of Sink: %s\n"
"Latency: %0.0f usec\n", "Latency: %0.0f usec\n",
i->index, i->index,
pa_typeid_to_string(i->_typeid, tid, sizeof(tid)), i->driver,
i->name, i->name,
i->description, 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->owner_module,
i->monitor_of_sink != PA_INVALID_INDEX ? t : "no", i->monitor_of_sink != PA_INVALID_INDEX ? t : "no",
(double) i->latency); (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) { 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) { if (is_last < 0) {
fprintf(stderr, "Failed to get client information: %s\n", pa_strerror(pa_context_errno(c))); 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" printf("*** Client #%u ***\n"
"Name: %s\n" "Name: %s\n"
"Type: %s\n" "Driver: %s\n"
"Owner Module: %s\n", "Owner Module: %s\n",
i->index, i->index,
i->name, i->name,
pa_typeid_to_string(i->_typeid, tid, sizeof(tid)), i->driver,
i->owner_module != PA_INVALID_INDEX ? t : "n/a"); 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) { 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) { if (is_last < 0) {
fprintf(stderr, "Failed to get sink input information: %s\n", pa_strerror(pa_context_errno(c))); 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"); printf("\n");
nl = 1; nl = 1;
pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec);
snprintf(t, sizeof(t), "%u", i->owner_module); snprintf(t, sizeof(t), "%u", i->owner_module);
snprintf(k, sizeof(k), "%u", i->client); snprintf(k, sizeof(k), "%u", i->client);
printf("*** Sink Input #%u ***\n" printf("*** Sink Input #%u ***\n"
"Name: %s\n" "Name: %s\n"
"Type: %s\n" "Driver: %s\n"
"Owner Module: %s\n" "Owner Module: %s\n"
"Client: %s\n" "Client: %s\n"
"Sink: %u\n" "Sink: %u\n"
"Sample Specification: %s\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" "Buffer Latency: %0.0f usec\n"
"Sink Latency: %0.0f usec\n" "Sink Latency: %0.0f usec\n"
"Resample method: %s\n", "Resample method: %s\n",
i->index, i->index,
i->name, i->name,
pa_typeid_to_string(i->_typeid, tid, sizeof(tid)), i->driver,
i->owner_module != PA_INVALID_INDEX ? t : "n/a", i->owner_module != PA_INVALID_INDEX ? t : "n/a",
i->client != PA_INVALID_INDEX ? k : "n/a", i->client != PA_INVALID_INDEX ? k : "n/a",
i->sink, i->sink,
s, pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec),
i->volume, pa_volume_to_dB(i->volume), pa_channel_map_snprint(cm, sizeof(cm), &i->channel_map),
pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
(double) i->buffer_usec, (double) i->buffer_usec,
(double) i->sink_usec, (double) i->sink_usec,
i->resample_method ? i->resample_method : "n/a"); 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) { 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) { if (is_last < 0) {
fprintf(stderr, "Failed to get source output information: %s\n", pa_strerror(pa_context_errno(c))); 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"); printf("\n");
nl = 1; nl = 1;
pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec);
snprintf(t, sizeof(t), "%u", i->owner_module); snprintf(t, sizeof(t), "%u", i->owner_module);
snprintf(k, sizeof(k), "%u", i->client); snprintf(k, sizeof(k), "%u", i->client);
printf("*** Source Output #%u ***\n" printf("*** Source Output #%u ***\n"
"Name: %s\n" "Name: %s\n"
"Type: %s\n" "Driver: %s\n"
"Owner Module: %s\n" "Owner Module: %s\n"
"Client: %s\n" "Client: %s\n"
"Source: %u\n" "Source: %u\n"
"Sample Specification: %s\n" "Sample Specification: %s\n"
"Channel Map: %s\n"
"Buffer Latency: %0.0f usec\n" "Buffer Latency: %0.0f usec\n"
"Source Latency: %0.0f usec\n" "Source Latency: %0.0f usec\n"
"Resample method: %s\n", "Resample method: %s\n",
i->index, i->index,
i->name, i->name,
pa_typeid_to_string(i->_typeid, tid, sizeof(tid)), i->driver,
i->owner_module != PA_INVALID_INDEX ? t : "n/a", i->owner_module != PA_INVALID_INDEX ? t : "n/a",
i->client != PA_INVALID_INDEX ? k : "n/a", i->client != PA_INVALID_INDEX ? k : "n/a",
i->source, 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->buffer_usec,
(double) i->source_usec, (double) i->source_usec,
i->resample_method ? i->resample_method : "n/a"); 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) { 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) { if (is_last < 0) {
fprintf(stderr, "Failed to get sample information: %s\n", pa_strerror(pa_context_errno(c))); 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"); printf("\n");
nl = 1; nl = 1;
pa_sample_spec_snprint(s, sizeof(s), &i->sample_spec);
pa_bytes_snprint(t, sizeof(t), i->bytes); pa_bytes_snprint(t, sizeof(t), i->bytes);
printf("*** Sample #%u ***\n" printf("*** Sample #%u ***\n"
"Name: %s\n" "Name: %s\n"
"Volume: 0x%03x (%0.2f dB)\n" "Volume: %s\n"
"Sample Specification: %s\n" "Sample Specification: %s\n"
"Channel Map: %s\n"
"Duration: %0.1fs\n" "Duration: %0.1fs\n"
"Size: %s\n" "Size: %s\n"
"Lazy: %s\n" "Lazy: %s\n"
"Filename: %s\n", "Filename: %s\n",
i->index, i->index,
i->name, i->name,
i->volume, pa_volume_to_dB(i->volume), pa_cvolume_snprint(cv, sizeof(cv), &i->volume),
pa_sample_spec_valid(&i->sample_spec) ? s : "n/a", 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, (double) i->duration/1000000,
t, t,
i->lazy ? "yes" : "no", i->lazy ? "yes" : "no",
@ -547,7 +552,7 @@ static void context_state_callback(pa_context *c, void *userdata) {
break; break;
case UPLOAD_SAMPLE: 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); assert(sample_stream);
pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL); pa_stream_set_state_callback(sample_stream, stream_state_callback, NULL);

View file

@ -155,21 +155,23 @@ static void context_state_callback(pa_context *c, void *userdata) {
case PA_CONTEXT_SETTING_NAME: case PA_CONTEXT_SETTING_NAME:
break; break;
case PA_CONTEXT_READY: case PA_CONTEXT_READY: {
pa_cvolume cv;
assert(c && !stream); assert(c && !stream);
if (verbose) if (verbose)
fprintf(stderr, "Connection established.\n"); 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); assert(stream);
pa_stream_set_state_callback(stream, stream_state_callback, NULL); pa_stream_set_state_callback(stream, stream_state_callback, NULL);
pa_stream_set_write_callback(stream, stream_write_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; break;
}
case PA_CONTEXT_TERMINATED: case PA_CONTEXT_TERMINATED:
quit(0); quit(0);

View file

@ -67,7 +67,7 @@ int main(PA_GCC_UNUSED int argc, char*argv[]) {
int error; int error;
/* Create the recording stream */ /* 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)); fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
goto finish; goto finish;
} }

View file

@ -29,10 +29,10 @@ typedef enum pa_parsed_address_type {
PA_PARSED_ADDRESS_TCP4, PA_PARSED_ADDRESS_TCP4,
PA_PARSED_ADDRESS_TCP6, PA_PARSED_ADDRESS_TCP6,
PA_PARSED_ADDRESS_TCP_AUTO PA_PARSED_ADDRESS_TCP_AUTO
} pa_parsed_address_type; } pa_parsed_address_type_t;
typedef struct pa_parsed_address { typedef struct pa_parsed_address {
pa_parsed_address_type type; pa_parsed_address_type_t type;
char *path_or_host; char *path_or_host;
uint16_t port; uint16_t port;
} pa_parsed_address; } pa_parsed_address;

View file

@ -33,8 +33,6 @@
#include "xmalloc.h" #include "xmalloc.h"
#include "gccmacro.h" #include "gccmacro.h"
#define PA_TYPEID_MEMCHUNK PA_TYPEID_MAKE('M', 'C', 'N', 'K')
static void sink_input_kill(pa_sink_input *i) { static void sink_input_kill(pa_sink_input *i) {
pa_memchunk *c; pa_memchunk *c;
assert(i && i->userdata); assert(i && i->userdata);
@ -45,7 +43,6 @@ static void sink_input_kill(pa_sink_input *i) {
pa_memblock_unref(c->memblock); pa_memblock_unref(c->memblock);
pa_xfree(c); pa_xfree(c);
} }
static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) { 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); 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_sink_input *si;
pa_memchunk *nchunk; pa_memchunk *nchunk;
assert(sink && chunk); assert(sink);
assert(ss);
assert(chunk);
if (volume <= 0) if (cvolume && pa_cvolume_is_muted(cvolume))
return 0; 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; return -1;
si->volume = volume; if (cvolume)
si->volume = *cvolume;
si->peek = sink_input_peek; si->peek = sink_input_peek;
si->drop = sink_input_drop; si->drop = sink_input_drop;
si->kill = sink_input_kill; si->kill = sink_input_kill;
si->userdata = nchunk = pa_xmalloc(sizeof(pa_memchunk)); si->userdata = nchunk = pa_xnew(pa_memchunk, 1);
*nchunk = *chunk; *nchunk = *chunk;
pa_memblock_ref(chunk->memblock); pa_memblock_ref(chunk->memblock);

View file

@ -25,6 +25,12 @@
#include "sink.h" #include "sink.h"
#include "memchunk.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 #endif

View file

@ -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. Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc.

View file

@ -1,4 +1,4 @@
/* $Id: mainloop.c 302 2004-11-21 17:02:25Z lennart $ */ /* $Id$ */
/*** /***
Compatibility definitions for System V `poll' interface. Compatibility definitions for System V `poll' interface.

View file

@ -187,7 +187,7 @@ void pa_context_unref(pa_context *c) {
context_free(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); assert(c);
if (c->state == st) 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_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); assert(c && c->ref >= 1);
return c->state; return c->state;
} }

View file

@ -75,7 +75,7 @@ int pa_context_errno(pa_context *c);
int pa_context_is_pending(pa_context *c); int pa_context_is_pending(pa_context *c);
/** Return the current context status */ /** 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 the context to the specified server. If server is NULL,
connect to the default server. This routine may but will not always connect to the default server. This routine may but will not always

View file

@ -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_READY, /**< The connection is established, the context is ready to execute operations */
PA_CONTEXT_FAILED, /**< The connection failed or was disconnected */ PA_CONTEXT_FAILED, /**< The connection failed or was disconnected */
PA_CONTEXT_TERMINATED /**< The connection was terminated cleanly */ PA_CONTEXT_TERMINATED /**< The connection was terminated cleanly */
} pa_context_state; } pa_context_state_t;
/** The state of a stream */ /** The state of a stream */
typedef enum pa_stream_state { 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_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_FAILED, /**< An error occured that made the stream invalid */
PA_STREAM_TERMINATED /**< The stream has been terminated cleanly */ PA_STREAM_TERMINATED /**< The stream has been terminated cleanly */
} pa_stream_state; } pa_stream_state_t;
/** The state of an operation */ /** The state of an operation */
typedef enum pa_operation_state { typedef enum pa_operation_state {
PA_OPERATION_RUNNING, /**< The operation is still running */ PA_OPERATION_RUNNING, /**< The operation is still running */
PA_OPERATION_DONE, /**< The operation has been completed */ PA_OPERATION_DONE, /**< The operation has been completed */
PA_OPERATION_CANCELED /**< The operation has been canceled */ PA_OPERATION_CANCELED /**< The operation has been canceled */
} pa_operation_state; } pa_operation_state_t;
/** An invalid index */ /** An invalid index */
#define PA_INVALID_INDEX ((uint32_t) -1) #define PA_INVALID_INDEX ((uint32_t) -1)
@ -70,7 +70,7 @@ typedef enum pa_stream_direction {
PA_STREAM_PLAYBACK, /**< Playback stream */ PA_STREAM_PLAYBACK, /**< Playback stream */
PA_STREAM_RECORD, /**< Record stream */ PA_STREAM_RECORD, /**< Record stream */
PA_STREAM_UPLOAD /**< Sample upload stream */ PA_STREAM_UPLOAD /**< Sample upload stream */
} pa_stream_direction; } pa_stream_direction_t;
/** Some special flags for stream connections. \since 0.6 */ /** Some special flags for stream connections. \since 0.6 */
typedef enum pa_stream_flags { typedef enum pa_stream_flags {
@ -90,7 +90,7 @@ typedef enum pa_stream_flags {
* information. This is * information. This is
* especially useful on long latency * especially useful on long latency
* network connections. */ * network connections. */
} pa_stream_flags; } pa_stream_flags_t;
/** Playback and record buffer metrics */ /** Playback and record buffer metrics */
typedef struct pa_buffer_attr { 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_SAMPLE_CACHE = 64, /**< Sample cache events */
PA_SUBSCRIPTION_MASK_SERVER = 128, /**< Other global server changes. \since 0.4 */ 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_AUTOLOAD = 256 /**< Autoload table events. \since 0.5 */
} pa_subscription_mask; } pa_subscription_mask_t;
/** Subscription event types, as used by pa_context_subscribe() */ /** Subscription event types, as used by pa_context_subscribe() */
typedef enum pa_subscription_event_type { 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_CHANGE = 16, /**< A property of the object was modified */
PA_SUBSCRIPTION_EVENT_REMOVE = 32, /**< An object was removed */ 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_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 */ /** 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)))) #define pa_subscription_match_flags(m, t) (!!((m) & (1 << ((t) & PA_SUBSCRIPTION_EVENT_FACILITY_MASK))))

View file

@ -55,12 +55,12 @@ struct pa_context {
uint32_t ctag; uint32_t ctag;
uint32_t error; uint32_t error;
pa_context_state state; pa_context_state_t state;
void (*state_callback)(pa_context*c, void *userdata); void (*state_callback)(pa_context*c, void *userdata);
void *state_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; void *subscribe_userdata;
pa_memblock_stat *memblock_stat; pa_memblock_stat *memblock_stat;
@ -86,15 +86,16 @@ struct pa_stream {
char *name; char *name;
pa_buffer_attr buffer_attr; pa_buffer_attr buffer_attr;
pa_sample_spec sample_spec; pa_sample_spec sample_spec;
pa_channel_map channel_map;
uint32_t channel; uint32_t channel;
int channel_valid; int channel_valid;
uint32_t device_index; uint32_t device_index;
pa_stream_direction direction; pa_stream_direction_t direction;
uint32_t requested_bytes; uint32_t requested_bytes;
uint64_t counter; uint64_t counter;
pa_usec_t previous_time; pa_usec_t previous_time;
pa_usec_t previous_ipol_time; pa_usec_t previous_ipol_time;
pa_stream_state state; pa_stream_state_t state;
pa_mcalign *mcalign; pa_mcalign *mcalign;
int interpolate; int interpolate;
@ -123,7 +124,7 @@ struct pa_operation {
pa_stream *stream; pa_stream *stream;
PA_LLIST_FIELDS(pa_operation); PA_LLIST_FIELDS(pa_operation);
pa_operation_state state; pa_operation_state_t state;
void *userdata; void *userdata;
pa_operation_callback callback; 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_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_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); 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); 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); void pa_stream_trash_ipol(pa_stream *s);

View file

@ -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.name) < 0 ||
pa_tagstruct_gets(t, &i.description) < 0 || pa_tagstruct_gets(t, &i.description) < 0 ||
pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 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.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_getu32(t, &i.monitor_source) < 0 ||
pa_tagstruct_gets(t, &i.monitor_source_name) < 0 || pa_tagstruct_gets(t, &i.monitor_source_name) < 0 ||
pa_tagstruct_get_usec(t, &i.latency) < 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); pa_context_fail(o->context, PA_ERROR_PROTOCOL);
goto finish; 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.name) < 0 ||
pa_tagstruct_gets(t, &i.description) < 0 || pa_tagstruct_gets(t, &i.description) < 0 ||
pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 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.owner_module) < 0 ||
pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 || pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 ||
pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 || pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 ||
pa_tagstruct_get_usec(t, &i.latency) < 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); pa_context_fail(o->context, PA_ERROR_PROTOCOL);
goto finish; 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 || if (pa_tagstruct_getu32(t, &i.index) < 0 ||
pa_tagstruct_gets(t, &i.name) < 0 || pa_tagstruct_gets(t, &i.name) < 0 ||
pa_tagstruct_getu32(t, &i.owner_module) < 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); pa_context_fail(o->context, PA_ERROR_PROTOCOL);
goto finish; 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.client) < 0 ||
pa_tagstruct_getu32(t, &i.sink) < 0 || pa_tagstruct_getu32(t, &i.sink) < 0 ||
pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 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.buffer_usec) < 0 ||
pa_tagstruct_get_usec(t, &i.sink_usec) < 0 || pa_tagstruct_get_usec(t, &i.sink_usec) < 0 ||
pa_tagstruct_gets(t, &i.resample_method) < 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); pa_context_fail(o->context, PA_ERROR_PROTOCOL);
goto finish; 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.client) < 0 ||
pa_tagstruct_getu32(t, &i.source) < 0 || pa_tagstruct_getu32(t, &i.source) < 0 ||
pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 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.buffer_usec) < 0 ||
pa_tagstruct_get_usec(t, &i.source_usec) < 0 || pa_tagstruct_get_usec(t, &i.source_usec) < 0 ||
pa_tagstruct_gets(t, &i.resample_method) < 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); pa_context_fail(o->context, PA_ERROR_PROTOCOL);
goto finish; 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 || if (pa_tagstruct_getu32(t, &i.index) < 0 ||
pa_tagstruct_gets(t, &i.name) < 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_usec(t, &i.duration) < 0 ||
pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 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_getu32(t, &i.bytes) < 0 ||
pa_tagstruct_get_boolean(t, &i.lazy) < 0 || pa_tagstruct_get_boolean(t, &i.lazy) < 0 ||
pa_tagstruct_gets(t, &i.filename) < 0) { pa_tagstruct_gets(t, &i.filename) < 0) {
@ -861,7 +866,7 @@ finish:
pa_operation_unref(o); 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_tagstruct *t;
pa_operation *o; pa_operation *o;
uint32_t tag; uint32_t tag;
@ -933,8 +938,7 @@ finish:
pa_operation_unref(o); pa_operation_unref(o);
} }
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* 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 *o; pa_operation *o;
pa_tagstruct *t; pa_tagstruct *t;
uint32_t tag; 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); 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_operation *o;
pa_tagstruct *t; pa_tagstruct *t;
uint32_t tag; uint32_t tag;

View file

@ -27,7 +27,8 @@
#include <polyp/polyplib-operation.h> #include <polyp/polyplib-operation.h>
#include <polyp/polyplib-context.h> #include <polyp/polyplib-context.h>
#include <polyp/cdecl.h> #include <polyp/cdecl.h>
#include <polyp/typeid.h> #include <polyp/channelmap.h>
#include <polyp/volume.h>
/** \file /** \file
* *
@ -52,13 +53,14 @@ typedef struct pa_sink_info {
const char *name; /**< Name of the sink */ const char *name; /**< Name of the sink */
uint32_t index; /**< Index of the sink */ uint32_t index; /**< Index of the sink */
const char *description; /**< Description of this 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 */ 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 */ uint32_t monitor_source; /**< Index of the monitor source connected to this sink */
const char *monitor_source_name; /**< The name of the monitor source */ const char *monitor_source_name; /**< The name of the monitor source */
pa_usec_t latency; /**< Length of filled playback buffer of this sink */ 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; } pa_sink_info;
/** Get information about a sink by its name */ /** Get information about a sink by its name */
@ -75,12 +77,13 @@ typedef struct pa_source_info {
const char *name ; /**< Name of the source */ const char *name ; /**< Name of the source */
uint32_t index; /**< Index of the source */ uint32_t index; /**< Index of the source */
const char *description; /**< Description of this 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 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 */ 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 */ 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_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; } pa_source_info;
/** Get information about a source by its name */ /** 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 *host_name; /**< Host name the daemon is running on */
const char *server_version; /**< Version string of the daemon */ const char *server_version; /**< Version string of the daemon */
const char *server_name; /**< Server package name (usually "polypaudio") */ 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_sink_name; /**< Name of default sink. \since 0.4 */
const char *default_source_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 */ 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 */ uint32_t index; /**< Index of this client */
const char *name; /**< Name of this client */ const char *name; /**< Name of this client */
uint32_t owner_module; /**< Index of the owning module, or PA_INVALID_INDEX */ 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; } pa_client_info;
/** Get information about a client by its index */ /** 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 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 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 */ uint32_t sink; /**< Index of the connected sink */
pa_sample_spec sample_spec; /**< The sample specification of the sink input */ pa_sample_spec sample_spec; /**< The sample specification of the sink input */
pa_volume_t volume; /**< The volume of this 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 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 */ pa_usec_t sink_usec; /**< Latency of the sink device, see pa_latency_info for details */
const char *resample_method; /**< Thre resampling method used by this sink input. \since 0.7 */ const char *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; } pa_sink_input_info;
/** Get some information about a sink input by its index */ /** 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 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 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 */ 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 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 */ pa_usec_t source_usec; /**< Latency of the source device, see pa_latency_info for details. \since 0.5 */
const char *resample_method; /**< Thre resampling method used by this source output. \since 0.7 */ const char *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; } pa_source_output_info;
/** Get information about a source output by its index */ /** 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 { typedef struct pa_sample_info {
uint32_t index; /**< Index of this entry */ uint32_t index; /**< Index of this entry */
const char *name; /**< Name of this entry */ const char *name; /**< Name of this entry */
pa_volume_t volume; /**< Default volume of this entry */ pa_cvolume volume; /**< Default volume of this entry */
pa_sample_spec sample_spec; /**< Sample specification of the sampel */ 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 */ pa_usec_t duration; /**< Duration of this entry */
uint32_t bytes; /**< Length of this sample in bytes. \since 0.4 */ 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 */ 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 { typedef enum pa_autoload_type {
PA_AUTOLOAD_SINK = 0, PA_AUTOLOAD_SINK = 0,
PA_AUTOLOAD_SOURCE = 1 PA_AUTOLOAD_SOURCE = 1
} pa_autoload_type; } pa_autoload_type_t;
/** Stores information about autoload entries. \since 0.5 */ /** Stores information about autoload entries. \since 0.5 */
typedef struct pa_autoload_info { typedef struct pa_autoload_info {
uint32_t index; /**< Index of this autoload entry */ uint32_t index; /**< Index of this autoload entry */
const char *name; /**< Name of the sink or source */ 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 *module; /**< Module name to load */
const char *argument; /**< Argument string for module */ const char *argument; /**< Argument string for module */
} pa_autoload_info; } pa_autoload_info;
/** Get info about a specific autoload entry. \since 0.6 */ /** 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 */ /** 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); 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); 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 */ /** 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 */ /** 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 */ /** 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); 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);

View file

@ -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); assert(o && o->ref >= 1);
if (st == o->state) if (st == o->state)
@ -97,7 +97,7 @@ void pa_operation_done(pa_operation *o) {
operation_set_state(o, PA_OPERATION_DONE); 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); assert(o && o->ref >= 1);
return o->state; return o->state;
} }

View file

@ -44,7 +44,7 @@ void pa_operation_unref(pa_operation *o);
void pa_operation_cancel(pa_operation *o); void pa_operation_cancel(pa_operation *o);
/** Return the current status of the operation */ /** 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 PA_C_DECL_END

View file

@ -39,7 +39,7 @@ struct pa_simple {
pa_mainloop *mainloop; pa_mainloop *mainloop;
pa_context *context; pa_context *context;
pa_stream *stream; pa_stream *stream;
pa_stream_direction direction; pa_stream_direction_t direction;
int dead; 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 void read_callback(pa_stream *s, const void*data, size_t length, void *userdata);
static int check_error(pa_simple *p, int *rerror) { static int check_error(pa_simple *p, int *rerror) {
pa_context_state cst; pa_context_state_t cst;
pa_stream_state sst; pa_stream_state_t sst;
assert(p); assert(p);
if ((cst = pa_context_get_state(p->context)) == PA_CONTEXT_FAILED) 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( pa_simple* pa_simple_new(
const char *server, const char *server,
const char *name, const char *name,
pa_stream_direction dir, pa_stream_direction_t dir,
const char *dev, const char *dev,
const char *stream_name, const char *stream_name,
const pa_sample_spec *ss, const pa_sample_spec *ss,
const pa_buffer_attr *attr, const pa_buffer_attr *attr,
pa_volume_t volume,
int *rerror) { int *rerror) {
pa_simple *p; pa_simple *p;
@ -152,11 +151,11 @@ pa_simple* pa_simple_new(
goto fail; 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; goto fail;
if (dir == PA_STREAM_PLAYBACK) 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 else
pa_stream_connect_record(p->stream, dev, attr, 0); pa_stream_connect_record(p->stream, dev, attr, 0);

View file

@ -49,12 +49,11 @@ typedef struct pa_simple pa_simple;
pa_simple* pa_simple_new( pa_simple* pa_simple_new(
const char *server, /**< Server name, or NULL for default */ const char *server, /**< Server name, or NULL for default */
const char *name, /**< A descriptive name for this client (application name, ...) */ 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 *dev, /**< Sink (resp. source) name, or NULL for default */
const char *stream_name, /**< A descriptive name for this client (application name, song title, ...) */ 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_sample_spec *ss, /**< The sample type to use */
const pa_buffer_attr *attr, /**< Buffering attributes, or NULL for default */ 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. */ int *error /**< A pointer where the error code is stored when the routine returns NULL. It is OK to pass NULL here. */
); );

View file

@ -36,11 +36,18 @@
#define LATENCY_IPOL_INTERVAL_USEC (10000L) #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; 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->ref = 1;
s->context = c; s->context = c;
s->mainloop = c->mainloop; 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->direction = PA_STREAM_NODIRECTION;
s->name = pa_xstrdup(name); s->name = pa_xstrdup(name);
s->sample_spec = *ss; 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 = 0;
s->channel_valid = 0; s->channel_valid = 0;
s->device_index = PA_INVALID_INDEX; s->device_index = PA_INVALID_INDEX;
@ -108,7 +121,7 @@ pa_stream* pa_stream_ref(pa_stream *s) {
return 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); assert(s && s->ref >= 1);
return s->state; return s->state;
} }
@ -123,7 +136,7 @@ uint32_t pa_stream_get_index(pa_stream *s) {
return s->device_index; 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); assert(s && s->ref >= 1);
if (s->state == st) if (s->state == st)
@ -271,7 +284,7 @@ finish:
pa_stream_unref(s); 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; pa_tagstruct *t;
uint32_t tag; uint32_t tag;
assert(s && s->ref >= 1 && s->state == PA_STREAM_DISCONNECTED); 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_putu32(t, tag = s->context->ctag++);
pa_tagstruct_puts(t, s->name); pa_tagstruct_puts(t, s->name);
pa_tagstruct_put_sample_spec(t, &s->sample_spec); 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_putu32(t, PA_INVALID_INDEX);
pa_tagstruct_puts(t, dev); pa_tagstruct_puts(t, dev);
pa_tagstruct_putu32(t, s->buffer_attr.maxlength); pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
pa_tagstruct_put_boolean(t, !!(flags & PA_STREAM_START_CORKED)); pa_tagstruct_put_boolean(t, !!(flags & PA_STREAM_START_CORKED));
if (s->direction == PA_STREAM_PLAYBACK) { if (s->direction == PA_STREAM_PLAYBACK) {
pa_cvolume cv;
pa_tagstruct_putu32(t, s->buffer_attr.tlength); pa_tagstruct_putu32(t, s->buffer_attr.tlength);
pa_tagstruct_putu32(t, s->buffer_attr.prebuf); pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
pa_tagstruct_putu32(t, s->buffer_attr.minreq); 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 } else
pa_tagstruct_putu32(t, s->buffer_attr.fragsize); 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); 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); assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1);
s->direction = PA_STREAM_PLAYBACK; s->direction = PA_STREAM_PLAYBACK;
create_stream(s, dev, attr, flags, volume); 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); assert(s && s->context->state == PA_CONTEXT_READY && s->ref >= 1);
s->direction = PA_STREAM_RECORD; s->direction = PA_STREAM_RECORD;
create_stream(s, dev, attr, flags, 0); create_stream(s, dev, attr, flags, 0);

View file

@ -25,6 +25,8 @@
#include <sys/types.h> #include <sys/types.h>
#include <polyp/sample.h> #include <polyp/sample.h>
#include <polyp/channelmap.h>
#include <polyp/volume.h>
#include <polyp/polyplib-def.h> #include <polyp/polyplib-def.h>
#include <polyp/cdecl.h> #include <polyp/cdecl.h>
#include <polyp/polyplib-operation.h> #include <polyp/polyplib-operation.h>
@ -39,7 +41,7 @@ PA_C_DECL_BEGIN
typedef struct pa_stream pa_stream; typedef struct pa_stream pa_stream;
/** Create a new, unconnected stream with the specified name and sample type */ /** 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 */ /** Decrease the reference counter by one */
void pa_stream_unref(pa_stream *s); 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); pa_stream *pa_stream_ref(pa_stream *s);
/** Return the current state of the stream */ /** 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 */ /** Return the context this stream is attached to */
pa_context* pa_stream_get_context(pa_stream *p); 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); uint32_t pa_stream_get_index(pa_stream *s);
/** Connect the stream to a sink */ /** 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 */ /** 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 */ /** Disconnect a stream from a source/sink */
void pa_stream_disconnect(pa_stream *s); void pa_stream_disconnect(pa_stream *s);

View file

@ -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) { 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_context *c = userdata;
pa_subscription_event_type e; pa_subscription_event_type_t e;
uint32_t index; uint32_t index;
assert(pd && command == PA_COMMAND_SUBSCRIBE_EVENT && t && c); 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_operation *o;
pa_tagstruct *t; pa_tagstruct *t;
uint32_t tag; 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); 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); assert(c);
c->subscribe_callback = cb; c->subscribe_callback = cb;
c->subscribe_userdata = userdata; c->subscribe_userdata = userdata;

View file

@ -37,10 +37,10 @@
PA_C_DECL_BEGIN PA_C_DECL_BEGIN
/** Enable event notification */ /** 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 */ /** 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 PA_C_DECL_END

View file

@ -64,8 +64,6 @@
#define SCACHE_PREFIX "esound." #define SCACHE_PREFIX "esound."
#define PA_TYPEID_ESOUND PA_TYPEID_MAKE('E', 'S', 'D', 'P')
/* This is heavily based on esound's code */ /* This is heavily based on esound's code */
struct connection { 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); 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"); pa_log(__FILE__": failed to create sink input.\n");
return -1; 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); 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"); pa_log(__FILE__": failed to create source output\n");
return -1; return -1;
} }
@ -476,7 +474,7 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v
assert(k); assert(k);
for (conn = pa_idxset_first(c->protocol->connections, &idx); conn; conn = pa_idxset_next(c->protocol->connections, &idx)) { 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) if (conn->state != ESD_STREAMING_DATA)
continue; continue;
@ -485,7 +483,8 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v
if (conn->sink_input) { if (conn->sink_input) {
rate = conn->sink_input->sample_spec.rate; 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); 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); response += sizeof(int);
/* left */ /* 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); response += sizeof(int);
/*right*/ /*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); response += sizeof(int);
/*format*/ /*format*/
@ -545,11 +544,11 @@ static int esd_proto_all_info(struct connection *c, esd_proto_t request, const v
response += sizeof(int); response += sizeof(int);
/* left */ /* 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); response += sizeof(int);
/*right*/ /*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); response += sizeof(int);
/*format*/ /*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) { static int esd_proto_stream_pan(struct connection *c, PA_GCC_UNUSED esd_proto_t request, const void *data, size_t length) {
int *ok; int *ok;
uint32_t idx, volume; uint32_t idx;
pa_volume_t lvolume, rvolume;
struct connection *conn; struct connection *conn;
assert(c && data && length == sizeof(int)*3); assert(c && data && length == sizeof(int)*3);
idx = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *(const int*)data)-1; 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)); lvolume = (uint32_t) maybe_swap_endian_32(c->swap_byte_order, *((const int*)data + 1));
volume = (volume*0x100)/0xFF; 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)); ok = connection_write(c, sizeof(int));
assert(ok); assert(ok);
if ((conn = pa_idxset_get_by_index(c->protocol->connections, idx))) { if ((conn = pa_idxset_get_by_index(c->protocol->connections, idx))) {
assert(conn->sink_input); 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; *ok = 1;
} else } else
*ok = 0; *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; 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)); ok = connection_write(c, sizeof(int));
assert(ok); assert(ok);
@ -676,7 +680,7 @@ static int esd_proto_sample_free_or_play(struct connection *c, esd_proto_t reque
pa_sink *sink; pa_sink *sink;
if ((sink = pa_namereg_get(c->protocol->core, c->protocol->sink_name, PA_NAMEREG_SINK, 1))) 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; *ok = (int) idx+1;
} else { } else {
assert(request == ESD_PROTO_SAMPLE_FREE); assert(request == ESD_PROTO_SAMPLE_FREE);
@ -801,7 +805,7 @@ static int do_read(struct connection *c) {
int *ok; int *ok;
c->scache.memchunk.index = 0; 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); pa_memblock_unref(c->scache.memchunk.memblock);
c->scache.memchunk.memblock = NULL; 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)); pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname));
assert(p->core); 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); assert(c->client);
c->client->owner = p->module; c->client->owner = p->module;
c->client->kill = client_kill_cb; c->client->kill = client_kill_cb;

View file

@ -56,8 +56,6 @@
/* Don't accept more connection than this */ /* Don't accept more connection than this */
#define MAX_CONNECTIONS 10 #define MAX_CONNECTIONS 10
#define PA_TYPEID_NATIVE PA_TYPEID_MAKE('N', 'A', 'T', 'V')
struct connection; struct connection;
struct pa_protocol_native; struct pa_protocol_native;
@ -88,6 +86,7 @@ struct upload_stream {
size_t length; size_t length;
char *name; char *name;
pa_sample_spec sample_spec; pa_sample_spec sample_spec;
pa_channel_map channel_map;
}; };
struct output_stream { struct output_stream {
@ -235,7 +234,12 @@ static const pa_pdispatch_callback command_table[PA_COMMAND_MAX] = {
/* structure management */ /* 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; struct upload_stream *s;
assert(c && ss && name && length); 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->type = UPLOAD_STREAM;
s->connection = c; s->connection = c;
s->sample_spec = *ss; s->sample_spec = *ss;
s->channel_map = *map;
s->name = pa_xstrdup(name); s->name = pa_xstrdup(name);
s->memchunk.memblock = NULL; s->memchunk.memblock = NULL;
@ -268,13 +273,21 @@ static void upload_stream_free(struct upload_stream *o) {
pa_xfree(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; struct record_stream *s;
pa_source_output *source_output; pa_source_output *source_output;
size_t base; size_t base;
assert(c && source && ss && name && maxlength); 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; return NULL;
s = pa_xmalloc(sizeof(struct record_stream)); s = pa_xmalloc(sizeof(struct record_stream));
@ -308,17 +321,23 @@ static void record_stream_free(struct record_stream* r) {
pa_xfree(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, static struct playback_stream* playback_stream_new(
size_t maxlength, struct connection *c,
size_t tlength, pa_sink *sink,
size_t prebuf, const pa_sample_spec *ss,
size_t minreq, const pa_channel_map *map,
pa_volume_t volume) { const char *name,
size_t maxlength,
size_t tlength,
size_t prebuf,
size_t minreq,
pa_cvolume *volume) {
struct playback_stream *s; struct playback_stream *s;
pa_sink_input *sink_input; pa_sink_input *sink_input;
assert(c && sink && ss && name && maxlength); 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; return NULL;
s = pa_xmalloc(sizeof(struct playback_stream)); 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->requested_bytes = 0;
s->drain_request = 0; s->drain_request = 0;
s->sink_input->volume = volume; s->sink_input->volume = *volume;
pa_idxset_put(c->output_streams, s, &s->index); pa_idxset_put(c->output_streams, s, &s->index);
return s; return s;
@ -561,14 +580,17 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC
uint32_t sink_index; uint32_t sink_index;
const char *name, *sink_name; const char *name, *sink_name;
pa_sample_spec ss; pa_sample_spec ss;
pa_channel_map map;
pa_tagstruct *reply; pa_tagstruct *reply;
pa_sink *sink; pa_sink *sink;
pa_volume_t volume; pa_cvolume volume;
int corked; int corked;
assert(c && t && c->protocol && c->protocol->core); assert(c && t && c->protocol && c->protocol->core);
if (pa_tagstruct_gets(t, &name) < 0 || !name || if (pa_tagstruct_gets(t, &name) < 0 || !name ||
pa_tagstruct_get_sample_spec(t, &ss) < 0 || 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_getu32(t, &sink_index) < 0 ||
pa_tagstruct_gets(t, &sink_name) < 0 || pa_tagstruct_gets(t, &sink_name) < 0 ||
pa_tagstruct_getu32(t, &maxlength) < 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, &tlength) < 0 ||
pa_tagstruct_getu32(t, &prebuf) < 0 || pa_tagstruct_getu32(t, &prebuf) < 0 ||
pa_tagstruct_getu32(t, &minreq) < 0 || pa_tagstruct_getu32(t, &minreq) < 0 ||
pa_tagstruct_getu32(t, &volume) < 0 || pa_tagstruct_get_cvolume(t, &volume) < 0 ||
!pa_tagstruct_eof(t)) { !pa_tagstruct_eof(t)) {
protocol_error(c); protocol_error(c);
return; return;
} }
if (!c->authorized) { if (!c->authorized) {
pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS); pa_pstream_send_error(c->pstream, tag, PA_ERROR_ACCESS);
return; return;
@ -599,7 +620,7 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC
return; 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); pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID);
return; return;
} }
@ -671,6 +692,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_
uint32_t source_index; uint32_t source_index;
const char *name, *source_name; const char *name, *source_name;
pa_sample_spec ss; pa_sample_spec ss;
pa_channel_map map;
pa_tagstruct *reply; pa_tagstruct *reply;
pa_source *source; pa_source *source;
int corked; 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 || if (pa_tagstruct_gets(t, &name) < 0 || !name ||
pa_tagstruct_get_sample_spec(t, &ss) < 0 || 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_getu32(t, &source_index) < 0 ||
pa_tagstruct_gets(t, &source_name) < 0 || pa_tagstruct_gets(t, &source_name) < 0 ||
pa_tagstruct_getu32(t, &maxlength) < 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; 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); pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID);
return; return;
} }
@ -984,11 +1007,13 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_
size_t length; size_t length;
const char *name; const char *name;
pa_sample_spec ss; pa_sample_spec ss;
pa_channel_map map;
pa_tagstruct *reply; pa_tagstruct *reply;
assert(c && t && c->protocol && c->protocol->core); assert(c && t && c->protocol && c->protocol->core);
if (pa_tagstruct_gets(t, &name) < 0 || !name || if (pa_tagstruct_gets(t, &name) < 0 || !name ||
pa_tagstruct_get_sample_spec(t, &ss) < 0 || pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
pa_tagstruct_get_channel_map(t, &map) < 0 ||
pa_tagstruct_getu32(t, &length) < 0 || pa_tagstruct_getu32(t, &length) < 0 ||
!pa_tagstruct_eof(t)) { !pa_tagstruct_eof(t)) {
protocol_error(c); protocol_error(c);
@ -1005,7 +1030,7 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_
return; 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); pa_pstream_send_error(c->pstream, tag, PA_ERROR_INVALID);
return; return;
} }
@ -1042,21 +1067,22 @@ static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_
return; 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); pa_pstream_send_simple_ack(c->pstream, tag);
upload_stream_free(s); 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) { 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; struct connection *c = userdata;
uint32_t sink_index, volume; uint32_t sink_index;
pa_cvolume volume;
pa_sink *sink; pa_sink *sink;
const char *name, *sink_name; const char *name, *sink_name;
assert(c && t); assert(c && t);
if (pa_tagstruct_getu32(t, &sink_index) < 0 || if (pa_tagstruct_getu32(t, &sink_index) < 0 ||
pa_tagstruct_gets(t, &sink_name) < 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_gets(t, &name) < 0 || !name ||
!pa_tagstruct_eof(t)) { !pa_tagstruct_eof(t)) {
protocol_error(c); protocol_error(c);
@ -1078,7 +1104,7 @@ static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui
return; 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); pa_pstream_send_error(c->pstream, tag, PA_ERROR_NOENTITY);
return; 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->name);
pa_tagstruct_puts(t, sink->description); pa_tagstruct_puts(t, sink->description);
pa_tagstruct_put_sample_spec(t, &sink->sample_spec); 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->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_putu32(t, sink->monitor_source->index);
pa_tagstruct_puts(t, sink->monitor_source->name); pa_tagstruct_puts(t, sink->monitor_source->name);
pa_tagstruct_put_usec(t, pa_sink_get_latency(sink)); 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) { 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->name);
pa_tagstruct_puts(t, source->description); pa_tagstruct_puts(t, source->description);
pa_tagstruct_put_sample_spec(t, &source->sample_spec); 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->owner ? source->owner->index : (uint32_t) -1);
pa_tagstruct_putu32(t, source->monitor_of ? source->monitor_of->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_puts(t, source->monitor_of ? source->monitor_of->name : NULL);
pa_tagstruct_put_usec(t, pa_source_get_latency(source)); 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) { 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_putu32(t, client->index);
pa_tagstruct_puts(t, client->name); pa_tagstruct_puts(t, client->name);
pa_tagstruct_putu32(t, client->owner ? client->owner->index : (uint32_t) -1); 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) { 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->client ? s->client->index : (uint32_t) -1);
pa_tagstruct_putu32(t, s->sink->index); pa_tagstruct_putu32(t, s->sink->index);
pa_tagstruct_put_sample_spec(t, &s->sample_spec); 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_input_get_latency(s));
pa_tagstruct_put_usec(t, pa_sink_get_latency(s->sink)); 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_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) { 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->client ? s->client->index : (uint32_t) -1);
pa_tagstruct_putu32(t, s->source->index); pa_tagstruct_putu32(t, s->source->index);
pa_tagstruct_put_sample_spec(t, &s->sample_spec); 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_output_get_latency(s));
pa_tagstruct_put_usec(t, pa_source_get_latency(s->source)); 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_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) { static void scache_fill_tagstruct(pa_tagstruct *t, pa_scache_entry *e) {
assert(t && e); assert(t && e);
pa_tagstruct_putu32(t, e->index); pa_tagstruct_putu32(t, e->index);
pa_tagstruct_puts(t, e->name); 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_usec(t, pa_bytes_to_usec(e->memchunk.length, &e->sample_spec));
pa_tagstruct_put_sample_spec(t, &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_putu32(t, e->memchunk.length);
pa_tagstruct_put_boolean(t, e->lazy); pa_tagstruct_put_boolean(t, e->lazy);
pa_tagstruct_puts(t, e->filename); 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); 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; pa_tagstruct *t;
struct connection *c = userdata; struct connection *c = userdata;
assert(c && core); 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) { 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; struct connection *c = userdata;
pa_subscription_mask m; pa_subscription_mask_t m;
assert(c && t); assert(c && t);
if (pa_tagstruct_getu32(t, &m) < 0 || 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) { 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; struct connection *c = userdata;
uint32_t idx, volume; uint32_t idx;
pa_cvolume volume;
pa_sink *sink = NULL; pa_sink *sink = NULL;
pa_sink_input *si = NULL; pa_sink_input *si = NULL;
const char *name = 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 || if (pa_tagstruct_getu32(t, &idx) < 0 ||
(command == PA_COMMAND_SET_SINK_VOLUME && pa_tagstruct_gets(t, &name) < 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)) { !pa_tagstruct_eof(t)) {
protocol_error(c); protocol_error(c);
return; return;
@ -1458,9 +1490,9 @@ static void command_set_volume(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command,
} }
if (sink) if (sink)
pa_sink_set_volume(sink, volume); pa_sink_set_volume(sink, PA_MIXER_HARDWARE, &volume);
else if (si) 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); 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; c->protocol = p;
assert(p->core); 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); assert(c->client);
c->client->kill = client_kill_cb; c->client->kill = client_kill_cb;
c->client->userdata = c; c->client->userdata = c;

View file

@ -42,8 +42,6 @@
/* Don't allow more than this many concurrent connections */ /* Don't allow more than this many concurrent connections */
#define MAX_CONNECTIONS 10 #define MAX_CONNECTIONS 10
#define PA_TYPEID_SIMPLE PA_TYPEID_MAKE('S', 'M', 'P', 'L')
struct connection { struct connection {
pa_protocol_simple *protocol; pa_protocol_simple *protocol;
pa_iochannel *io; 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; c->playback.fragment_size = 0;
pa_iochannel_socket_peer_to_string(io, cname, sizeof(cname)); 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); assert(c->client);
c->client->owner = p->module; c->client->owner = p->module;
c->client->kill = client_kill_cb; 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; 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"); pa_log(__FILE__": Failed to create sink input.\n");
goto fail; goto fail;
} }
@ -355,7 +353,7 @@ static void on_connection(pa_socket_server*s, pa_iochannel *io, void *userdata)
goto fail; 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) { if (!c->source_output) {
pa_log(__FILE__": Failed to create source output.\n"); pa_log(__FILE__": Failed to create source output.\n");
goto fail; goto fail;

View file

@ -27,6 +27,8 @@
#include <string.h> #include <string.h>
#include <samplerate.h> #include <samplerate.h>
#include <liboil/liboilfuncs.h>
#include <liboil/liboil.h>
#include "resampler.h" #include "resampler.h"
#include "sconv.h" #include "sconv.h"
@ -34,24 +36,28 @@
#include "log.h" #include "log.h"
struct pa_resampler { struct pa_resampler {
pa_resample_method_t resample_method;
pa_sample_spec i_ss, o_ss; pa_sample_spec i_ss, o_ss;
pa_channel_map i_cm, o_cm;
size_t i_fz, o_fz; size_t i_fz, o_fz;
pa_memblock_stat *memblock_stat; pa_memblock_stat *memblock_stat;
void *impl_data;
int channels;
pa_resample_method resample_method;
void (*impl_free)(pa_resampler *r); 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_run)(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out);
void *impl_data;
}; };
struct impl_libsamplerate { struct impl_libsamplerate {
float* i_buf, *o_buf; float* buf1, *buf2, *buf3, *buf4;
unsigned i_alloc, o_alloc; unsigned buf1_samples, buf2_samples, buf3_samples, buf4_samples;
pa_convert_to_float32ne_func_t to_float32ne_func; pa_convert_to_float32ne_func_t to_float32ne_func;
pa_convert_from_float32ne_func_t from_float32ne_func; pa_convert_from_float32ne_func_t from_float32ne_func;
SRC_STATE *src_state; SRC_STATE *src_state;
int map_table[PA_CHANNELS_MAX][PA_CHANNELS_MAX];
int map_required;
}; };
struct impl_trivial { struct impl_trivial {
@ -62,35 +68,54 @@ struct impl_trivial {
static int libsamplerate_init(pa_resampler*r); static int libsamplerate_init(pa_resampler*r);
static int trivial_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; 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) assert(a);
goto fail; 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->impl_data = NULL;
r->memblock_stat = s; r->memblock_stat = s;
r->resample_method = resample_method; r->resample_method = resample_method;
r->impl_free = NULL; r->impl_free = NULL;
r->impl_set_input_rate = NULL; r->impl_update_input_rate = NULL;
r->impl_run = NULL; r->impl_run = NULL;
/* Fill sample specs */ /* Fill sample specs */
r->i_ss = *a; r->i_ss = *a;
r->o_ss = *b; 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->i_fz = pa_frame_size(a);
r->o_fz = pa_frame_size(b); r->o_fz = pa_frame_size(b);
r->channels = a->channels;
if (b->channels < r->channels)
r->channels = b->channels;
/* Choose implementation */ /* 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 */ /* Use the libsamplerate based resampler for the complicated cases */
if (resample_method == PA_RESAMPLER_TRIVIAL) if (resample_method == PA_RESAMPLER_TRIVIAL)
r->resample_method = PA_RESAMPLER_SRC_ZERO_ORDER_HOLD; 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) { 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; 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) { 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; 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); assert(r);
return r->resample_method; return r->resample_method;
} }
/* Parse a libsamplrate compatible resampling implementation */ static const char * const resample_methods[] = {
pa_resample_method pa_parse_resample_method(const char *string) { "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); assert(string);
if (!strcmp(string, "src-sinc-best-quality")) for (m = 0; m < PA_RESAMPLER_MAX; m++)
return PA_RESAMPLER_SRC_SINC_BEST_QUALITY; if (!strcmp(string, resample_methods[m]))
else if (!strcmp(string, "src-sinc-medium-quality")) return m;
return PA_RESAMPLER_SRC_SINC_MEDIUM_QUALITY;
else if (!strcmp(string, "src-sinc-fastest")) return PA_RESAMPLER_INVALID;
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;
} }
/*** libsamplerate based implementation ***/ /*** libsamplerate based implementation ***/
static void libsamplerate_free(pa_resampler *r) { static void libsamplerate_free(pa_resampler *r) {
struct impl_libsamplerate *i; struct impl_libsamplerate *u;
assert(r && r->impl_data);
i = r->impl_data;
if (i->src_state) assert(r);
src_delete(i->src_state); assert(r->impl_data);
pa_xfree(i->i_buf); u = r->impl_data;
pa_xfree(i->o_buf);
pa_xfree(i); 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);
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 float * convert_to_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 incoming sample into floats and place them in buf1 */
if (!u->to_float32ne_func)
return input;
n_samples = n_frames * r->i_ss.channels;
if (u->buf1_samples < n_samples)
u->buf1 = pa_xrealloc(u->buf1, sizeof(float) * (u->buf1_samples = n_samples));
u->to_float32ne_func(n_samples, input, u->buf1);
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 */
if (!u->map_required)
return input;
n_samples = n_frames * r->o_ss.channels;
if (u->buf2_samples < n_samples)
u->buf2 = pa_xrealloc(u->buf2, sizeof(float) * (u->buf2_samples = n_samples));
memset(u->buf2, 0, n_samples * sizeof(float));
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);
}
return u->buf2;
}
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;
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;
data.src_ratio = (double) r->o_ss.rate / r->i_ss.rate;
data.end_of_input = 0;
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) { 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; struct impl_libsamplerate *u;
float *cbuf; float *buf, *input;
struct impl_libsamplerate *i; unsigned n_frames;
assert(r && in && out && in->length && in->memblock && (in->length % r->i_fz) == 0 && r->impl_data);
i = r->impl_data;
/* How many input samples? */ assert(r);
ins = in->length/r->i_fz; assert(in);
assert(out);
assert(in->length);
assert(in->memblock);
assert(in->length % r->i_fz == 0);
assert(r->impl_data);
/* pa_log("%u / %u = %u\n", in->length, r->i_fz, ins); */ u = r->impl_data;
/* How much space for output samples? */ buf = input = (float*) ((uint8_t*) in->memblock->data + in->index);
if (i->src_state) n_frames = in->length / r->i_fz;
ons = (ins*r->o_ss.rate/r->i_ss.rate)+1024; assert(n_frames > 0);
else
ons = ins;
/* How many channels? */ buf = convert_to_float(r, buf, n_frames);
if (r->i_ss.channels == r->o_ss.channels) { buf = remap_channels(r, buf, n_frames);
i_nchannels = o_nchannels = 1; buf = resample(r, buf, &n_frames);
eff_ins = ins*r->i_ss.channels; /* effective samples */
eff_ons = ons*r->o_ss.channels; 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 { } else {
i_nchannels = r->i_ss.channels;
o_nchannels = r->o_ss.channels;
eff_ins = ins;
eff_ons = ons;
}
/* pa_log("eff_ins = %u \n", eff_ins); */
out->memblock = pa_memblock_new(out->length = (ons*r->o_fz), r->memblock_stat);
out->index = 0;
assert(out->memblock);
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);
/* pa_log("eff_ins = %u \n", eff_ins); */
i->to_float32ne_func(eff_ins, (uint8_t*) in->memblock->data+in->index, i_nchannels, i->i_buf);
if (i->src_state) {
int ret;
SRC_DATA data;
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);
data.data_in = i->i_buf;
data.input_frames = ins;
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;
ret = src_process(i->src_state, &data);
assert(ret == 0);
assert((unsigned) data.input_frames_used == ins);
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);
out->memblock = NULL; out->memblock = NULL;
out->index = out->length = 0;
} }
} }
static void libsamplerate_set_input_rate(pa_resampler *r, uint32_t rate) { static void libsamplerate_update_input_rate(pa_resampler *r, uint32_t rate) {
int ret; struct impl_libsamplerate *u;
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(r);
assert(ret == 0); 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) { static int libsamplerate_init(pa_resampler *r) {
struct impl_libsamplerate *i = NULL; struct impl_libsamplerate *u = NULL;
int err; int err;
r->impl_data = i = pa_xmalloc(sizeof(struct impl_libsamplerate)); r->impl_data = u = pa_xnew(struct impl_libsamplerate, 1);
i->to_float32ne_func = pa_get_convert_to_float32ne_function(r->i_ss.format); u->buf1 = u->buf2 = u->buf3 = u->buf4 = NULL;
i->from_float32ne_func = pa_get_convert_from_float32ne_function(r->o_ss.format); 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; 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; goto fail;
i->i_buf = i->o_buf = NULL; if (r->o_ss.rate == r->i_ss.rate)
i->i_alloc = i->o_alloc = 0; 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_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; r->impl_run = libsamplerate_run;
calc_map_table(r);
return 0; return 0;
fail: fail:
pa_xfree(i); pa_xfree(u);
return -1; return -1;
} }
@ -310,15 +514,20 @@ fail:
static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) { static void trivial_run(pa_resampler *r, const pa_memchunk *in, pa_memchunk *out) {
size_t fz; size_t fz;
unsigned nframes; unsigned n_frames;
struct impl_trivial *i; struct impl_trivial *u;
assert(r && in && out && r->impl_data);
i = r->impl_data; assert(r);
assert(in);
assert(out);
assert(r->impl_data);
u = r->impl_data;
fz = r->i_fz; fz = r->i_fz;
assert(fz == r->o_fz); assert(fz == r->o_fz);
nframes = in->length/fz; n_frames = in->length/fz;
if (r->i_ss.rate == r->o_ss.rate) { 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; *out = *in;
pa_memblock_ref(out->memblock); pa_memblock_ref(out->memblock);
i->o_counter += nframes; u->o_counter += n_frames;
} else { } else {
/* Do real resampling */ /* Do real resampling */
size_t l; size_t l;
unsigned o_index; unsigned o_index;
/* The length of the new memory block rounded up */ /* 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->index = 0;
out->memblock = pa_memblock_new(l, r->memblock_stat); 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; unsigned j;
j = (i->o_counter * r->i_ss.rate / r->o_ss.rate); j = (u->o_counter * r->i_ss.rate / r->o_ss.rate);
j = j > i->i_counter ? j - i->i_counter : 0; j = j > u->i_counter ? j - u->i_counter : 0;
if (j >= nframes) if (j >= n_frames)
break; break;
assert(o_index*fz < out->memblock->length); 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; out->length = o_index*fz;
} }
i->i_counter += nframes; u->i_counter += n_frames;
/* Normalize counters */ /* Normalize counters */
while (i->i_counter >= r->i_ss.rate) { while (u->i_counter >= r->i_ss.rate) {
i->i_counter -= r->i_ss.rate; u->i_counter -= r->i_ss.rate;
assert(i->o_counter >= r->o_ss.rate); assert(u->o_counter >= r->o_ss.rate);
i->o_counter -= r->o_ss.rate; u->o_counter -= r->o_ss.rate;
} }
} }
static void trivial_free(pa_resampler *r) { static void trivial_free(pa_resampler *r) {
assert(r); assert(r);
pa_xfree(r->impl_data); pa_xfree(r->impl_data);
} }
static void trivial_set_input_rate(pa_resampler *r, uint32_t rate) { static void trivial_update_input_rate(pa_resampler *r, uint32_t rate) {
struct impl_trivial *i; struct impl_trivial *u;
assert(r && rate > 0 && r->impl_data);
i = r->impl_data;
i->i_counter = 0; assert(r);
i->o_counter = 0; assert(rate > 0);
assert(r->impl_data);
u = r->impl_data;
u->i_counter = 0;
u->o_counter = 0;
} }
static int trivial_init(pa_resampler*r) { static int trivial_init(pa_resampler*r) {
struct impl_trivial *i; struct impl_trivial *u;
assert(r && r->i_ss.format == r->o_ss.format && r->i_ss.channels == r->o_ss.channels);
r->impl_data = i = pa_xmalloc(sizeof(struct impl_trivial)); assert(r);
i->o_counter = i->i_counter = 0; assert(r->i_ss.format == r->o_ss.format);
assert(r->i_ss.channels == r->o_ss.channels);
r->impl_data = u = pa_xnew(struct impl_trivial, 1);
u->o_counter = u->i_counter = 0;
r->impl_run = trivial_run; r->impl_run = trivial_run;
r->impl_free = trivial_free; 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; 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];
}

View file

@ -27,6 +27,7 @@
#include "sample.h" #include "sample.h"
#include "memblock.h" #include "memblock.h"
#include "memchunk.h" #include "memchunk.h"
#include "channelmap.h"
typedef struct pa_resampler pa_resampler; typedef struct pa_resampler pa_resampler;
@ -39,9 +40,16 @@ typedef enum pa_resample_method {
PA_RESAMPLER_SRC_LINEAR = SRC_LINEAR, PA_RESAMPLER_SRC_LINEAR = SRC_LINEAR,
PA_RESAMPLER_TRIVIAL, PA_RESAMPLER_TRIVIAL,
PA_RESAMPLER_MAX 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); 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 */ /* 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); void pa_resampler_set_input_rate(pa_resampler *r, uint32_t rate);
/* Return the resampling method of the resampler object */ /* 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 */ /* 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() */ /* 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 #endif

View file

@ -28,6 +28,8 @@
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <liboil/liboilfuncs.h>
#include "sample-util.h" #include "sample-util.h"
pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec) { 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) { void pa_silence_memchunk(pa_memchunk *c, const pa_sample_spec *spec) {
assert(c && c->memblock && c->memblock->data && spec && c->length); assert(c && c->memblock && c->memblock->data && spec && c->length);
pa_silence_memory((uint8_t*) c->memblock->data+c->index, c->length, spec); 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); 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) { size_t pa_mix(
assert(channels && data && length && spec); 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) { assert(streams && data && length && spec);
size_t d;
for (d = 0;; d += sizeof(int16_t)) { switch (spec->format) {
unsigned c; case PA_SAMPLE_S16NE:{
int32_t sum = 0; size_t d;
unsigned channel = 0;
if (d >= length) for (d = 0;; d += sizeof(int16_t)) {
return d; int32_t sum = 0;
for (c = 0; c < nchannels; c++) { if (d >= length)
int32_t v;
pa_volume_t cvolume = channels[c].volume;
if (d >= channels[c].chunk.length)
return d; return d;
if (cvolume == PA_VOLUME_MUTED) if (volume->values[channel] != PA_VOLUME_MUTED) {
v = 0; unsigned i;
else {
v = *((int16_t*) ((uint8_t*) channels[c].chunk.memblock->data + channels[c].chunk.index + d));
if (cvolume != PA_VOLUME_NORM) { for (i = 0; i < nstreams; i++) {
v *= cvolume; int32_t v;
v /= PA_VOLUME_NORM; 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;
}
*((int16_t*) data) = sum;
data = (uint8_t*) data + sizeof(int16_t);
if (++channel >= spec->channels)
channel = 0;
}
}
case PA_SAMPLE_U8: {
size_t d;
unsigned channel = 0;
for (d = 0;; d ++) {
int32_t sum = 0;
if (d >= length)
return d;
if (volume->values[channel] != PA_VOLUME_MUTED) {
unsigned i;
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;
}
*((uint8_t*) data) = (uint8_t) (sum + 0x80);
data = (uint8_t*) data + 1;
if (++channel >= spec->channels)
channel = 0;
}
}
case PA_SAMPLE_FLOAT32NE: {
size_t d;
unsigned channel = 0;
for (d = 0;; d += sizeof(float)) {
float sum = 0;
if (d >= length)
return d;
if (volume->values[channel] != PA_VOLUME_MUTED) {
unsigned i;
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 (volume->values[channel] != PA_VOLUME_NORM) {
sum *= volume->values[channel];
sum /= PA_VOLUME_NORM;
} }
} }
sum += v; *((float*) data) = sum;
data = (uint8_t*) data + sizeof(float);
if (++channel >= spec->channels)
channel = 0;
} }
if (volume == PA_VOLUME_MUTED)
sum = 0;
else if (volume != PA_VOLUME_NORM) {
sum *= volume;
sum /= PA_VOLUME_NORM;
}
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;
for (c = 0; c < nchannels; c++) {
int32_t v;
pa_volume_t cvolume = channels[c].volume;
if (d >= channels[c].chunk.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 (cvolume != PA_VOLUME_NORM) {
v *= cvolume;
v /= PA_VOLUME_NORM;
}
}
sum += v;
}
if (volume == PA_VOLUME_MUTED)
sum = 0;
else if (volume != PA_VOLUME_NORM) {
sum *= volume;
sum /= PA_VOLUME_NORM;
}
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) { default:
size_t d; abort();
for (d = 0;; d += sizeof(float)) {
float sum = 0;
unsigned c;
if (d >= length)
return d;
for (c = 0; c < nchannels; c++) {
float v;
pa_volume_t cvolume = channels[c].volume;
if (d >= channels[c].chunk.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 (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;
if (sum < -1) sum = -1;
if (sum > 1) sum = 1;
*((float*) data) = sum;
data = (uint8_t*) data + sizeof(float);
}
} else {
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(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; return;
if (volume == PA_VOLUME_MUTED) { if (pa_cvolume_channels_equal_to(volume, PA_VOLUME_MUTED)) {
pa_silence_memchunk(c, spec); pa_silence_memchunk(c, spec);
return; return;
} }
if (spec->format == PA_SAMPLE_S16NE) { switch (spec->format) {
int16_t *d; case PA_SAMPLE_S16NE: {
size_t n; int16_t *d;
size_t n;
unsigned channel = 0;
for (d = (int16_t*) ((uint8_t*) c->memblock->data+c->index), n = c->length/sizeof(int16_t); n > 0; d++, 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); int32_t t = (int32_t)(*d);
t *= volume; t *= volume->values[channel];
t /= PA_VOLUME_NORM; t /= PA_VOLUME_NORM;
if (t < -0x8000) t = -0x8000; if (t < -0x8000) t = -0x8000;
if (t > 0x7FFF) t = 0x7FFF; if (t > 0x7FFF) t = 0x7FFF;
*d = (int16_t) t; *d = (int16_t) t;
}
} 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--) { if (++channel >= spec->channels)
int32_t t = (int32_t) *d - 0x80; channel = 0;
}
t *= volume;
t /= PA_VOLUME_NORM;
if (t < -0x80) t = -0x80;
if (t > 0x7F) t = 0x7F;
*d = (uint8_t) (t + 0x80);
}
} 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 { case PA_SAMPLE_U8: {
abort(); uint8_t *d;
size_t n;
unsigned channel = 0;
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;
}
}
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);
}
}
default:
abort();
} }
} }

View file

@ -25,7 +25,7 @@
#include "sample.h" #include "sample.h"
#include "memblock.h" #include "memblock.h"
#include "memchunk.h" #include "memchunk.h"
#include "volume.h"
pa_memblock *pa_silence_memblock(pa_memblock* b, const pa_sample_spec *spec); 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); 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 { typedef struct pa_mix_info {
pa_memchunk chunk; pa_memchunk chunk;
pa_volume_t volume; pa_cvolume volume;
void *userdata; void *userdata;
} pa_mix_info ; } 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); 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, pa_volume_t volume); void pa_volume_memchunk(
pa_memchunk*c,
const pa_sample_spec *spec,
const pa_cvolume *volume);
#endif #endif

View file

@ -30,29 +30,29 @@
#include "sample.h" #include "sample.h"
size_t pa_frame_size(const pa_sample_spec *spec) { size_t pa_sample_size(const pa_sample_spec *spec) {
size_t b = 1;
assert(spec); assert(spec);
switch (spec->format) { switch (spec->format) {
case PA_SAMPLE_U8: case PA_SAMPLE_U8:
case PA_SAMPLE_ULAW: case PA_SAMPLE_ULAW:
case PA_SAMPLE_ALAW: case PA_SAMPLE_ALAW:
b = 1; return 1;
break;
case PA_SAMPLE_S16LE: case PA_SAMPLE_S16LE:
case PA_SAMPLE_S16BE: case PA_SAMPLE_S16BE:
b = 2; return 2;
break;
case PA_SAMPLE_FLOAT32LE: case PA_SAMPLE_FLOAT32LE:
case PA_SAMPLE_FLOAT32BE: case PA_SAMPLE_FLOAT32BE:
b = 4; return 4;
break;
default: default:
assert(0); assert(0);
} }
}
return b * spec->channels; size_t pa_frame_size(const pa_sample_spec *spec) {
assert(spec);
return pa_sample_size(spec) * spec->channels;
} }
size_t pa_bytes_per_second(const pa_sample_spec *spec) { 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) { int pa_sample_spec_valid(const pa_sample_spec *spec) {
assert(spec); assert(spec);
if (spec->rate <= 0 || spec->channels <= 0) if (spec->rate <= 0 ||
return 0; spec->channels <= 0 ||
spec->channels > PA_CHANNELS_MAX ||
if (spec->format >= PA_SAMPLE_MAX || spec->format < 0) spec->format >= PA_SAMPLE_MAX ||
spec->format < 0)
return 0; return 0;
return 1; 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); 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[]= { static const char* const table[]= {
[PA_SAMPLE_U8] = "U8", [PA_SAMPLE_U8] = "u8",
[PA_SAMPLE_ALAW] = "ALAW", [PA_SAMPLE_ALAW] = "aLaw",
[PA_SAMPLE_ULAW] = "ULAW", [PA_SAMPLE_ULAW] = "uLaw",
[PA_SAMPLE_S16LE] = "S16LE", [PA_SAMPLE_S16LE] = "s16le",
[PA_SAMPLE_S16BE] = "S16BE", [PA_SAMPLE_S16BE] = "s16be",
[PA_SAMPLE_FLOAT32LE] = "FLOAT32LE", [PA_SAMPLE_FLOAT32LE] = "float32le",
[PA_SAMPLE_FLOAT32BE] = "FLOAT32BE", [PA_SAMPLE_FLOAT32BE] = "float32be",
}; };
if (f >= PA_SAMPLE_MAX) 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; 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) { void pa_bytes_snprint(char *s, size_t l, unsigned v) {
if (v >= ((unsigned) 1024)*1024*1024) if (v >= ((unsigned) 1024)*1024*1024)
snprintf(s, l, "%0.1f GB", ((double) v)/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); 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) if (strcasecmp(format, "s16le") == 0)
return PA_SAMPLE_S16LE; return PA_SAMPLE_S16LE;

View file

@ -33,6 +33,9 @@
PA_C_DECL_BEGIN PA_C_DECL_BEGIN
/* Maximum allowed channels */
#define PA_CHANNELS_MAX 16
/** Sample format */ /** Sample format */
typedef enum pa_sample_format { typedef enum pa_sample_format {
PA_SAMPLE_U8, /**< Unsigned 8 Bit PCM */ 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_FLOAT32BE, /**< 32 Bit IEEE floating point, big endian, range -1..1 */
PA_SAMPLE_MAX, /**< Upper limit of valid sample types */ PA_SAMPLE_MAX, /**< Upper limit of valid sample types */
PA_SAMPLE_INVALID = -1 /**< An invalid value */ PA_SAMPLE_INVALID = -1 /**< An invalid value */
} pa_sample_format; } pa_sample_format_t;
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
/** Signed 16 Bit PCM, native endian */ /** Signed 16 Bit PCM, native endian */
@ -71,7 +74,7 @@ typedef enum pa_sample_format {
/** A sample format and attribute specification */ /** A sample format and attribute specification */
typedef struct pa_sample_spec { 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) */ uint32_t rate; /**< The sample rate. (e.g. 44100) */
uint8_t channels; /**< Audio channels. (1 for mono, 2 for stereo, ...) */ uint8_t channels; /**< Audio channels. (1 for mono, 2 for stereo, ...) */
} pa_sample_spec; } 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 */ /** Return the size of a frame with the specific sample type */
size_t pa_frame_size(const pa_sample_spec *spec); 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 */ /** 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); 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); 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 */ /* 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() */ /** Maximum required string length for pa_sample_spec_snprint() */
#define PA_SAMPLE_SPEC_SNPRINT_MAX 32 #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 */ /** Pretty print a sample type specification to a string */
char* pa_sample_spec_snprint(char *s, size_t l, const pa_sample_spec *spec); 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") */ /** Pretty print a byte size value. (i.e. "2.5 MB") */
void pa_bytes_snprint(char *s, size_t l, unsigned v); 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 PA_C_DECL_END
#endif #endif

View file

@ -52,6 +52,8 @@
#include "sound-file.h" #include "sound-file.h"
#include "util.h" #include "util.h"
#include "log.h" #include "log.h"
#include "channelmap.h"
#include "volume.h"
#define UNLOAD_POLL_TIME 2 #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); 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->last_used_time = 0;
e->memchunk.memblock = NULL; e->memchunk.memblock = NULL;
e->memchunk.index = e->memchunk.length = 0; 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; 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; pa_scache_entry *e;
assert(c && name); assert(c && name);
if (!(e = scache_add_item(c, name))) if (!(e = scache_add_item(c, name)))
return -1; return -1;
if (ss) if (ss) {
e->sample_spec = *ss; e->sample_spec = *ss;
pa_channel_map_init_auto(&e->channel_map, ss->channels);
}
if (map)
e->channel_map = *map;
if (chunk) { if (chunk) {
e->memchunk = *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) if (pa_sound_file_load(filename, &ss, &chunk, c->memblock_stat) < 0)
return -1; 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); pa_memblock_unref(chunk.memblock);
return r; return r;
@ -230,9 +237,10 @@ void pa_scache_free(pa_core *c) {
c->mainloop->time_free(c->scache_auto_unload_event); 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; pa_scache_entry *e;
char *t; char *t;
pa_cvolume r;
assert(c && name && sink); assert(c && name && sink);
if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE, 1))) 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; return -1;
t = pa_sprintf_malloc("sample:%s", name); 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); free(t);
return -1; return -1;
} }

View file

@ -31,8 +31,9 @@ typedef struct pa_scache_entry {
uint32_t index; uint32_t index;
char *name; char *name;
uint32_t volume; pa_cvolume volume;
pa_sample_spec sample_spec; pa_sample_spec sample_spec;
pa_channel_map channel_map;
pa_memchunk memchunk; pa_memchunk memchunk;
char *filename; char *filename;
@ -41,14 +42,14 @@ typedef struct pa_scache_entry {
time_t last_used_time; time_t last_used_time;
} pa_scache_entry; } 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(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_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_add_directory_lazy(pa_core *c, const char *pathname);
int pa_scache_remove_item(pa_core *c, const char *name); 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); void pa_scache_free(pa_core *c);
const char *pa_scache_get_name_by_id(pa_core *c, uint32_t id); const char *pa_scache_get_name_by_id(pa_core *c, uint32_t id);

View file

@ -23,11 +23,19 @@
#include <config.h> #include <config.h>
#endif #endif
#include "endianmacros.h"
#define INT16_FROM INT16_FROM_BE #define INT16_FROM INT16_FROM_BE
#define INT16_TO INT16_TO_BE #define INT16_TO INT16_TO_BE
#define pa_sconv_s16le_to_float32ne pa_sconv_s16be_to_float32ne #define pa_sconv_s16le_to_float32ne pa_sconv_s16be_to_float32ne
#define pa_sconv_s16le_from_float32ne pa_sconv_s16be_from_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.h"
#include "sconv-s16le.c" #include "sconv-s16le.c"

View file

@ -22,7 +22,7 @@
USA. USA.
***/ ***/
void pa_sconv_s16be_to_float32ne(unsigned n, const void *a, unsigned an, float *b); 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, unsigned bn); void pa_sconv_s16be_from_float32ne(unsigned n, const float *a, void *b);
#endif #endif

View file

@ -26,6 +26,8 @@
#include <assert.h> #include <assert.h>
#include <inttypes.h> #include <inttypes.h>
#include <liboil/liboilfuncs.h>
#include "endianmacros.h" #include "endianmacros.h"
#include "sconv.h" #include "sconv.h"
#include "sconv-s16le.h" #include "sconv-s16le.h"
@ -39,49 +41,61 @@
#define INT16_TO INT16_TO_LE #define INT16_TO INT16_TO_LE
#endif #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; const int16_t *ca = a;
assert(n && a && an && b);
assert(a);
assert(b);
#if SWAP_WORDS == 1
for (; n > 0; n--) { for (; n > 0; n--) {
unsigned i; int16_t s = *(ca++);
float sum = 0; *(b++) = ((float) INT16_FROM(s))/0x7FFF;
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;
} }
#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; int16_t *cb = b;
/* pa_log("%u %p %p %u\n", n, a, b, bn); */ assert(a);
assert(b);
assert(n && a && b && bn); #if SWAP_WORDS == 1
for (; n > 0; n--) { for (; n > 0; n--) {
unsigned i;
int16_t s; int16_t s;
float v = *(a++); float v = *(a++);
if (v > 1) if (v > 1)
v = 1; v = 1;
if (v < -1) if (v < -1)
v = -1; v = -1;
s = (int16_t) (v * 0x7FFF); s = (int16_t) (v * 0x7FFF);
s = INT16_TO(s); *(cb++) = INT16_TO(s);
for (i = 0; i < bn; i++)
*(cb++) = s;
} }
#else
{
static const double add = 0, factor = 0x7FFF;
oil_scaleconv_s16_f32(cb, a, n, &add, &factor);
}
#endif
} }

View file

@ -22,7 +22,7 @@
USA. USA.
***/ ***/
void pa_sconv_s16le_to_float32ne(unsigned n, const void *a, unsigned an, float *b); 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, unsigned bn); void pa_sconv_s16le_from_float32ne(unsigned n, const float *a, void *b);
#endif #endif

View file

@ -26,6 +26,10 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#include <liboil/liboilfuncs.h>
#include <liboil/liboil.h>
#include "endianmacros.h" #include "endianmacros.h"
#include "sconv.h" #include "sconv.h"
#include "g711.h" #include "g711.h"
@ -33,36 +37,58 @@
#include "sconv-s16le.h" #include "sconv-s16le.h"
#include "sconv-s16be.h" #include "sconv-s16be.h"
static void u8_to_float32ne(unsigned n, const void *a, unsigned an, float *b) { static void u8_to_float32ne(unsigned n, const void *a, float *b) {
unsigned i;
const uint8_t *ca = a; const uint8_t *ca = a;
assert(n && a && an && b); static const double add = -128.0/127.0, factor = 1.0/127.0;
for (; n > 0; n--) { assert(a);
float sum = 0; assert(b);
for (i = 0; i < an; i++) { oil_scaleconv_f32_u8(b, ca, n, &add, &factor);
uint8_t v = *(ca++);
sum += (((float) v)-128)/127;
}
if (sum > 1)
sum = 1;
if (sum < -1)
sum = -1;
*(b++) = sum;
}
} }
static void u8_from_float32ne(unsigned n, const float *a, void *b, unsigned bn) { static void u8_from_float32ne(unsigned n, const float *a, void *b) {
unsigned i; uint8_t *cb = b;
static const double add = 128.0, factor = 127.0;
assert(a);
assert(b);
oil_scaleconv_u8_f32(cb, a, n, &add, &factor);
}
static void float32ne_to_float32ne(unsigned n, const void *a, float *b) {
assert(a);
assert(b);
oil_memcpy(b, a, sizeof(float) * n);
}
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, float *b) {
const uint8_t *ca = a;
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) {
uint8_t *cb = b; uint8_t *cb = b;
assert(n && a && b && bn); assert(a);
assert(b);
for (; n > 0; n--) { for (; n > 0; n--) {
float v = *(a++); float v = *(a++);
uint8_t u;
if (v > 1) if (v > 1)
v = 1; v = 1;
@ -70,70 +96,28 @@ static void u8_from_float32ne(unsigned n, const float *a, void *b, unsigned bn)
if (v < -1) if (v < -1)
v = -1; v = -1;
u = (uint8_t) (v*127+128); *(cb++) = st_14linear2ulaw((int16_t) (v * 0x1FFF));
for (i = 0; i < bn; i++)
*(cb++) = u;
} }
} }
static void float32ne_to_float32ne(unsigned n, const void *a, unsigned an, float *b) { static void alaw_to_float32ne(unsigned n, const void *a, 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++);
if (sum > 1)
sum = 1;
if (sum < -1)
sum = -1;
*(b++) = sum;
}
}
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 ulaw_to_float32ne(unsigned n, const void *a, unsigned an, float *b) {
unsigned i;
const uint8_t *ca = a; const uint8_t *ca = a;
assert(n && a && an && b);
for (; n > 0; n--) {
float sum = 0;
for (i = 0; i < an; i++) assert(a);
sum += st_ulaw2linear16(*ca++) * 1.0F / 0x7FFF; assert(b);
if (sum > 1) for (; n > 0; n--)
sum = 1; *(b++) = st_alaw2linear16(*(ca++)) * 1.0F / 0x7FFF;
if (sum < -1)
sum = -1;
*(b++) = sum;
}
} }
static void ulaw_from_float32ne(unsigned n, const float *a, void *b, unsigned bn) { static void alaw_from_float32ne(unsigned n, const float *a, void *b) {
unsigned i;
uint8_t *cb = b; uint8_t *cb = b;
assert(n && a && b && bn); assert(a);
assert(b);
for (; n > 0; n--) { for (; n > 0; n--) {
float v = *(a++); float v = *(a++);
uint8_t u;
if (v > 1) if (v > 1)
v = 1; v = 1;
@ -141,56 +125,11 @@ static void ulaw_from_float32ne(unsigned n, const float *a, void *b, unsigned bn
if (v < -1) if (v < -1)
v = -1; v = -1;
u = st_14linear2ulaw((int16_t) (v * 0x1FFF)); *(cb++) = st_13linear2alaw((int16_t) (v * 0xFFF));
for (i = 0; i < bn; i++)
*(cb++) = u;
} }
} }
static void alaw_to_float32ne(unsigned n, const void *a, unsigned an, float *b) { pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format_t f) {
unsigned i;
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;
*(b++) = sum;
}
}
static void alaw_from_float32ne(unsigned n, const float *a, void *b, unsigned bn) {
unsigned i;
uint8_t *cb = b;
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;
u = st_13linear2alaw((int16_t) (v * 0xFFF));
for (i = 0; i < bn; i++)
*(cb++) = u;
}
}
pa_convert_to_float32ne_func_t pa_get_convert_to_float32ne_function(pa_sample_format f) {
switch(f) { switch(f) {
case PA_SAMPLE_U8: case PA_SAMPLE_U8:
return u8_to_float32ne; 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) { switch(f) {
case PA_SAMPLE_U8: case PA_SAMPLE_U8:
return u8_from_float32ne; return u8_from_float32ne;

View file

@ -24,10 +24,10 @@
#include "sample.h" #include "sample.h"
typedef void (*pa_convert_to_float32ne_func_t)(unsigned n, const void *a, unsigned an, float *b); 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, unsigned bn); 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_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 f); pa_convert_from_float32ne_func_t pa_get_convert_from_float32ne_function(pa_sample_format_t f);
#endif #endif

View file

@ -36,47 +36,66 @@
#define CONVERT_BUFFER_LENGTH 4096 #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_sink_input *i;
pa_resampler *resampler = NULL; pa_resampler *resampler = NULL;
int r; int r;
char st[256]; 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) { 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; return NULL;
} }
if (resample_method == PA_RESAMPLER_INVALID) if (resample_method == PA_RESAMPLER_INVALID)
resample_method = s->core->resample_method; resample_method = s->core->resample_method;
if (variable_rate || !pa_sample_spec_equal(spec, &s->sample_spec)) if (!map) {
if (!(resampler = pa_resampler_new(spec, &s->sample_spec, s->core->memblock_stat, resample_method))) 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; return NULL;
i = pa_xmalloc(sizeof(pa_sink_input)); i = pa_xnew(pa_sink_input, 1);
i->ref = 1; i->ref = 1;
i->state = PA_SINK_INPUT_RUNNING; i->state = PA_SINK_INPUT_RUNNING;
i->name = pa_xstrdup(name); i->name = pa_xstrdup(name);
i->typeid = typeid; i->driver = pa_xstrdup(driver);
i->client = NULL;
i->owner = NULL; i->owner = NULL;
i->sink = s; i->sink = s;
i->client = NULL;
i->sample_spec = *spec; i->sample_spec = *spec;
i->channel_map = *map;
pa_cvolume_reset(&i->volume, spec->channels);
i->peek = NULL; i->peek = NULL;
i->drop = NULL; i->drop = NULL;
i->kill = NULL; i->kill = NULL;
i->get_latency = NULL; i->get_latency = NULL;
i->userdata = NULL;
i->underrun = NULL; i->underrun = NULL;
i->userdata = NULL;
i->volume = PA_VOLUME_NORM;
i->playing = 0; i->playing = 0;
i->resampled_chunk.memblock = NULL; pa_memchunk_reset(&i->resampled_chunk);
i->resampled_chunk.index = i->resampled_chunk.length = 0;
i->resampler = resampler; i->resampler = resampler;
assert(s->core); 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) { 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->core->sink_inputs, i, NULL);
pa_idxset_remove_by_data(i->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->drop = NULL;
i->kill = NULL; i->kill = NULL;
i->get_latency = NULL; i->get_latency = NULL;
i->underrun = NULL;
i->playing = 0;
i->state = PA_SINK_INPUT_DISCONNECTED; i->state = PA_SINK_INPUT_DISCONNECTED;
} }
@ -120,28 +144,34 @@ static void sink_input_free(pa_sink_input* i) {
if (i->resampled_chunk.memblock) if (i->resampled_chunk.memblock)
pa_memblock_unref(i->resampled_chunk.memblock); pa_memblock_unref(i->resampled_chunk.memblock);
if (i->resampler) if (i->resampler)
pa_resampler_free(i->resampler); pa_resampler_free(i->resampler);
pa_xfree(i->name); pa_xfree(i->name);
pa_xfree(i->driver);
pa_xfree(i); pa_xfree(i);
} }
void pa_sink_input_unref(pa_sink_input *i) { void pa_sink_input_unref(pa_sink_input *i) {
assert(i && i->ref >= 1); assert(i);
assert(i->ref >= 1);
if (!(--i->ref)) if (!(--i->ref))
sink_input_free(i); sink_input_free(i);
} }
pa_sink_input* pa_sink_input_ref(pa_sink_input *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++; i->ref++;
return i; return i;
} }
void pa_sink_input_kill(pa_sink_input*i) { void pa_sink_input_kill(pa_sink_input*i) {
assert(i && i->ref >= 1); assert(i);
assert(i->ref >= 1);
if (i->kill) if (i->kill)
i->kill(i); 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 pa_sink_input_get_latency(pa_sink_input *i) {
pa_usec_t r = 0; pa_usec_t r = 0;
assert(i && i->ref >= 1);
assert(i);
assert(i->ref >= 1);
if (i->get_latency) if (i->get_latency)
r += i->get_latency(i); r += i->get_latency(i);
@ -160,9 +192,14 @@ pa_usec_t pa_sink_input_get_latency(pa_sink_input *i) {
return r; 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; 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); pa_sink_input_ref(i);
@ -170,10 +207,13 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) {
goto finish; goto finish;
if (!i->resampler) { if (!i->resampler) {
do_volume_adj_here = 0;
ret = i->peek(i, chunk); ret = i->peek(i, chunk);
goto finish; goto finish;
} }
do_volume_adj_here = !pa_channel_map_equal(&i->channel_map, &i->sink->channel_map);
while (!i->resampled_chunk.memblock) { while (!i->resampled_chunk.memblock) {
pa_memchunk tchunk; pa_memchunk tchunk;
size_t l; size_t l;
@ -183,6 +223,12 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) {
assert(tchunk.length); 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); l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH);
if (l > tchunk.length) if (l > tchunk.length)
@ -195,7 +241,9 @@ int pa_sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) {
pa_memblock_unref(tchunk.memblock); 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; *chunk = i->resampled_chunk;
pa_memblock_ref(i->resampled_chunk.memblock); pa_memblock_ref(i->resampled_chunk.memblock);
@ -208,13 +256,28 @@ finish:
i->playing = ret >= 0; 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); pa_sink_input_unref(i);
return ret; return ret;
} }
void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length) { 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->resampler) {
if (i->drop) if (i->drop)
@ -222,35 +285,50 @@ void pa_sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t lengt
return; 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.index += length;
i->resampled_chunk.length -= length; i->resampled_chunk.length -= length;
if (!i->resampled_chunk.length) { if (i->resampled_chunk.length <= 0) {
pa_memblock_unref(i->resampled_chunk.memblock); pa_memblock_unref(i->resampled_chunk.memblock);
i->resampled_chunk.memblock = NULL; i->resampled_chunk.memblock = NULL;
i->resampled_chunk.index = i->resampled_chunk.length = 0; i->resampled_chunk.index = i->resampled_chunk.length = 0;
} }
} }
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) {
assert(i && i->sink && i->sink->core && i->ref >= 1); assert(i);
assert(i->ref >= 1);
assert(i->sink);
assert(i->sink->core);
if (i->volume != volume) { if (pa_cvolume_equal(&i->volume, volume))
i->volume = volume; return;
pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
} 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) { void pa_sink_input_cork(pa_sink_input *i, int b) {
int n; int n;
assert(i && i->ref >= 1);
assert(i);
assert(i->ref >= 1);
if (i->state == PA_SINK_INPUT_DISCONNECTED) if (i->state == PA_SINK_INPUT_DISCONNECTED)
return; return;
n = i->state == PA_SINK_INPUT_CORKED && !b; n = i->state == PA_SINK_INPUT_CORKED && !b;
i->state = b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING; i->state = b ? PA_SINK_INPUT_CORKED : PA_SINK_INPUT_RUNNING;
if (n) 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) { 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) if (i->sample_spec.rate == rate)
return; 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) { 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); pa_xfree(i->name);
i->name = pa_xstrdup(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_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) { pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) {
assert(i && i->ref >= 1); assert(i);
assert(i->ref >= 1);
if (!i->resampler) if (!i->resampler)
return PA_RESAMPLER_INVALID; return PA_RESAMPLER_INVALID;

View file

@ -33,25 +33,27 @@ typedef struct pa_sink_input pa_sink_input;
#include "module.h" #include "module.h"
#include "client.h" #include "client.h"
typedef enum { typedef enum pa_sink_input_state {
PA_SINK_INPUT_RUNNING, PA_SINK_INPUT_RUNNING,
PA_SINK_INPUT_CORKED, PA_SINK_INPUT_CORKED,
PA_SINK_INPUT_DISCONNECTED PA_SINK_INPUT_DISCONNECTED
} pa_sink_input_state ; } pa_sink_input_state_t;
struct pa_sink_input { struct pa_sink_input {
int ref; int ref;
pa_sink_input_state state;
uint32_t index; uint32_t index;
pa_typeid_t typeid; pa_sink_input_state_t state;
char *name; char *name, *driver;
pa_module *owner; pa_module *owner;
pa_client *client;
pa_sink *sink; pa_sink *sink;
pa_client *client;
pa_sample_spec sample_spec; 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); int (*peek) (pa_sink_input *i, pa_memchunk *chunk);
void (*drop) (pa_sink_input *i, const pa_memchunk *chunk, size_t length); 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_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); void pa_sink_input_unref(pa_sink_input* i);
pa_sink_input* pa_sink_input_ref(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); 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_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); 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); 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 #endif

View file

@ -40,43 +40,54 @@
#define MAX_MIX_CHANNELS 32 #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; pa_sink *s;
char *n = NULL; char *n = NULL;
char st[256]; char st[256];
int r; 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))) { if (!(name = pa_namereg_register(core, name, PA_NAMEREG_SINK, s, fail))) {
pa_xfree(s); pa_xfree(s);
return NULL; return NULL;
} }
s->ref = 1;
s->core = core;
s->state = PA_SINK_RUNNING;
s->name = pa_xstrdup(name); s->name = pa_xstrdup(name);
s->description = NULL; s->description = NULL;
s->typeid = typeid; s->driver = pa_xstrdup(driver);
s->ref = 1;
s->state = PA_SINK_RUNNING;
s->owner = NULL; s->owner = NULL;
s->core = core;
s->sample_spec = *spec; 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); s->inputs = pa_idxset_new(NULL, NULL);
n = pa_sprintf_malloc("%s_monitor", name); pa_cvolume_reset(&s->sw_volume, spec->channels);
s->monitor_source = pa_source_new(core, typeid, n, 0, spec); pa_cvolume_reset(&s->hw_volume, spec->channels);
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;
s->notify = NULL;
s->get_latency = NULL; s->get_latency = NULL;
s->notify = NULL;
s->set_hw_volume = NULL;
s->get_hw_volume = NULL;
s->userdata = NULL; s->userdata = NULL;
r = pa_idxset_put(core->sinks, s, &s->index); 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_sample_spec_snprint(st, sizeof(st), spec);
pa_log_info(__FILE__": created %u \"%s\" with sample spec \"%s\"\n", s->index, s->name, st); 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); pa_subscription_post(core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_NEW, s->index);
return s; 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) { void pa_sink_disconnect(pa_sink* s) {
pa_sink_input *i, *j = NULL; 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); 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_source_disconnect(s->monitor_source);
pa_idxset_remove_by_data(s->core->sinks, s, NULL); 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->get_latency = NULL;
s->notify = NULL;
s->get_hw_volume = NULL;
s->set_hw_volume = NULL;
s->state = PA_SINK_DISCONNECTED; 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) { static void sink_free(pa_sink *s) {
assert(s && s->ref == 0); assert(s);
assert(!s->ref);
if (s->state != PA_SINK_DISCONNECTED) if (s->state != PA_SINK_DISCONNECTED)
pa_sink_disconnect(s); pa_sink_disconnect(s);
@ -128,24 +151,29 @@ static void sink_free(pa_sink *s) {
pa_xfree(s->name); pa_xfree(s->name);
pa_xfree(s->description); pa_xfree(s->description);
pa_xfree(s->driver);
pa_xfree(s); pa_xfree(s);
} }
void pa_sink_unref(pa_sink*s) { void pa_sink_unref(pa_sink*s) {
assert(s && s->ref >= 1); assert(s);
assert(s->ref >= 1);
if (!(--s->ref)) if (!(--s->ref))
sink_free(s); sink_free(s);
} }
pa_sink* pa_sink_ref(pa_sink *s) { pa_sink* pa_sink_ref(pa_sink *s) {
assert(s && s->ref >= 1); assert(s);
assert(s->ref >= 1);
s->ref++; s->ref++;
return s; return s;
} }
void pa_sink_notify(pa_sink*s) { void pa_sink_notify(pa_sink*s) {
assert(s && s->ref >= 1); assert(s);
assert(s->ref >= 1);
if (s->notify) if (s->notify)
s->notify(s); 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; pa_sink_input *i;
unsigned n = 0; 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)) { 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); 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); pa_sink_input_unref(i);
continue; continue;
} }
info->volume = i->volume;
info->userdata = i; 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++; info++;
maxinfo--; 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) { 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++) { for (; maxinfo > 0; maxinfo--, info++) {
pa_sink_input *i = info->userdata; 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_sink_input_drop(i, &info->chunk, length);
pa_memblock_unref(info->chunk.memblock); pa_memblock_unref(info->chunk.memblock);
/* Decrease ref counter */
pa_sink_input_unref(i); pa_sink_input_unref(i);
info->userdata = NULL; 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) { int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
pa_mix_info info[MAX_MIX_CHANNELS]; pa_mix_info info[MAX_MIX_CHANNELS];
unsigned n; unsigned n;
size_t l;
int r = -1; int r = -1;
assert(s); assert(s);
assert(s->ref >= 1); assert(s->ref >= 1);
assert(length); assert(length);
@ -212,37 +251,29 @@ int pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
goto finish; goto finish;
if (n == 1) { if (n == 1) {
uint32_t volume = PA_VOLUME_NORM; pa_cvolume volume;
pa_sink_input *i = info[0].userdata;
assert(i);
*result = info[0].chunk; *result = info[0].chunk;
pa_memblock_ref(result->memblock); pa_memblock_ref(result->memblock);
if (result->length > length) if (result->length > length)
result->length = length; result->length = length;
l = result->length; pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume);
if (s->volume != PA_VOLUME_NORM || info[0].volume != PA_VOLUME_NORM) if (!pa_cvolume_is_norm(&volume)) {
volume = pa_volume_multiply(s->volume, info[0].volume);
if (volume != PA_VOLUME_NORM) {
pa_memchunk_make_writable(result, s->core->memblock_stat, 0); 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 { } else {
result->memblock = pa_memblock_new(length, s->core->memblock_stat); result->memblock = pa_memblock_new(length, s->core->memblock_stat);
assert(result->memblock); 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; result->index = 0;
assert(l);
} }
inputs_drop(s, info, n, l); inputs_drop(s, info, n, result->length);
assert(s->monitor_source);
pa_source_post(s->monitor_source, result); pa_source_post(s->monitor_source, result);
r = 0; r = 0;
@ -256,9 +287,14 @@ finish:
int pa_sink_render_into(pa_sink*s, pa_memchunk *target) { int pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
pa_mix_info info[MAX_MIX_CHANNELS]; pa_mix_info info[MAX_MIX_CHANNELS];
unsigned n; unsigned n;
size_t l;
int r = -1; 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); pa_sink_ref(s);
@ -268,27 +304,27 @@ int pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
goto finish; goto finish;
if (n == 1) { if (n == 1) {
uint32_t volume = PA_VOLUME_NORM; pa_cvolume volume;
l = target->length; if (target->length > info[0].chunk.length)
if (l > info[0].chunk.length) target->length = info[0].chunk.length;
l = info[0].chunk.length;
memcpy((uint8_t*) target->memblock->data+target->index, (uint8_t*) info[0].chunk.memblock->data + info[0].chunk.index, l); memcpy((uint8_t*) target->memblock->data + target->index,
target->length = l; (uint8_t*) info[0].chunk.memblock->data + info[0].chunk.index,
target->length);
if (s->volume != PA_VOLUME_NORM || info[0].volume != PA_VOLUME_NORM) pa_sw_cvolume_multiply(&volume, &s->sw_volume, &info[0].volume);
volume = pa_volume_multiply(s->volume, info[0].volume);
if (volume != PA_VOLUME_NORM) if (!pa_cvolume_is_norm(&volume))
pa_volume_memchunk(target, &s->sample_spec, volume); pa_volume_memchunk(target, &s->sample_spec, &volume);
} else } 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, target->length);
inputs_drop(s, info, n, l);
assert(s->monitor_source);
pa_source_post(s->monitor_source, target); pa_source_post(s->monitor_source, target);
r = 0; r = 0;
@ -302,7 +338,13 @@ finish:
void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) { void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
pa_memchunk chunk; pa_memchunk chunk;
size_t l, d; 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); 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) { 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 ***/ /*** 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) { 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) if (!s->get_latency)
return 0; 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) { 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; 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); pa_source_set_owner(s->monitor_source, m);
} }
void pa_sink_set_volume(pa_sink *s, pa_volume_t volume) { void pa_sink_set_volume(pa_sink *s, pa_mixer_t m, const pa_cvolume *volume) {
assert(s && s->ref >= 1); pa_cvolume *v;
if (s->volume != volume) { assert(s);
s->volume = volume; assert(s->ref >= 1);
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index); 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;
} }

View file

@ -30,39 +30,55 @@ typedef struct pa_sink pa_sink;
#include "sample.h" #include "sample.h"
#include "idxset.h" #include "idxset.h"
#include "source.h" #include "source.h"
#include "typeid.h" #include "channelmap.h"
#include "module.h" #include "module.h"
#include "volume.h"
#define PA_MAX_INPUTS_PER_SINK 6 #define PA_MAX_INPUTS_PER_SINK 6
typedef enum pa_sink_state { typedef enum pa_sink_state {
PA_SINK_RUNNING, PA_SINK_RUNNING,
PA_SINK_DISCONNECTED 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 { struct pa_sink {
int ref; int ref;
pa_sink_state state;
uint32_t index; uint32_t index;
pa_typeid_t typeid;
char *name, *description;
pa_module *owner;
pa_core *core; pa_core *core;
pa_sample_spec sample_spec; pa_sink_state_t state;
pa_idxset *inputs;
char *name, *description, *driver;
pa_module *owner;
pa_sample_spec sample_spec;
pa_channel_map channel_map;
pa_idxset *inputs;
pa_source *monitor_source; pa_source *monitor_source;
pa_volume_t volume; pa_cvolume hw_volume, sw_volume;
void (*notify)(pa_sink*sink); void (*notify)(pa_sink*sink);
pa_usec_t (*get_latency)(pa_sink *s); pa_usec_t (*get_latency)(pa_sink *s);
int (*set_hw_volume)(pa_sink *s);
int (*get_hw_volume)(pa_sink *s);
void *userdata; 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_disconnect(pa_sink* s);
void pa_sink_unref(pa_sink*s); void pa_sink_unref(pa_sink*s);
pa_sink* pa_sink_ref(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_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 #endif

View file

@ -173,7 +173,7 @@ static void connect_fixed_cb(pa_mainloop_api *m, pa_defer_event *e, void *userda
do_call(c); 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; pa_socket_client *c = userdata;
assert(m && c && c->io_event == e && fd >= 0); assert(m && c && c->io_event == e && fd >= 0);
do_call(c); 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 #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; pa_socket_client *c = userdata;
struct addrinfo *res = NULL; struct addrinfo *res = NULL;
int ret; int ret;

View file

@ -78,7 +78,7 @@ struct pa_socket_server {
enum { SOCKET_SERVER_GENERIC, SOCKET_SERVER_IPV4, SOCKET_SERVER_UNIX, SOCKET_SERVER_IPV6 } type; 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_socket_server *s = userdata;
pa_iochannel *io; pa_iochannel *io;
int nfd; int nfd;

View file

@ -36,7 +36,6 @@
#include "log.h" #include "log.h"
#define BUF_SIZE (1024*10) #define BUF_SIZE (1024*10)
#define PA_TYPEID_SOUND_FILE PA_TYPEID_MAKE('S', 'N', 'D', 'F')
struct userdata { struct userdata {
SNDFILE *sndfile; 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; struct userdata *u = NULL;
SF_INFO sfinfo; SF_INFO sfinfo;
pa_sample_spec ss; pa_sample_spec ss;
assert(sink && fname); assert(sink && fname);
if (volume <= 0)
goto fail;
u = pa_xmalloc(sizeof(struct userdata)); u = pa_xmalloc(sizeof(struct userdata));
u->sink_input = NULL; u->sink_input = NULL;
u->memchunk.memblock = 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; 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; goto fail;
u->sink_input->volume = volume; if (volume)
u->sink_input->volume = *volume;
u->sink_input->peek = sink_input_peek; u->sink_input->peek = sink_input_peek;
u->sink_input->drop = sink_input_drop; u->sink_input->drop = sink_input_drop;
u->sink_input->kill = sink_input_kill; u->sink_input->kill = sink_input_kill;

View file

@ -24,6 +24,6 @@
#include "sink.h" #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 #endif

View file

@ -33,12 +33,23 @@
#include "subscribe.h" #include "subscribe.h"
#include "log.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_source_output *o;
pa_resampler *resampler = NULL; pa_resampler *resampler = NULL;
int r; int r;
char st[256]; 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) { 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"); pa_log(__FILE__": Failed to create source output: too many outputs per source.\n");
@ -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) if (resample_method == PA_RESAMPLER_INVALID)
resample_method = s->core->resample_method; resample_method = s->core->resample_method;
if (!pa_sample_spec_equal(&s->sample_spec, spec)) if (!map) {
if (!(resampler = pa_resampler_new(&s->sample_spec, spec, s->core->memblock_stat, resample_method))) 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; return NULL;
o = pa_xmalloc(sizeof(pa_source_output)); o = pa_xmalloc(sizeof(pa_source_output));
o->ref = 1; o->ref = 1;
o->state = PA_SOURCE_OUTPUT_RUNNING; o->state = PA_SOURCE_OUTPUT_RUNNING;
o->name = pa_xstrdup(name); o->name = pa_xstrdup(name);
o->typeid = typeid; o->driver = pa_xstrdup(driver);
o->client = NULL;
o->owner = NULL; o->owner = NULL;
o->source = s; o->source = s;
o->client = NULL;
o->sample_spec = *spec; o->sample_spec = *spec;
o->channel_map = *map;
o->push = NULL; o->push = NULL;
o->kill = NULL; o->kill = NULL;
o->userdata = NULL;
o->get_latency = NULL; o->get_latency = NULL;
o->userdata = NULL;
o->resampler = resampler; 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) { 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->core->source_outputs, o, NULL);
pa_idxset_remove_by_data(o->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->push = NULL;
o->kill = NULL; o->kill = NULL;
o->get_latency = NULL;
o->state = PA_SOURCE_OUTPUT_DISCONNECTED; 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_resampler_free(o->resampler);
pa_xfree(o->name); pa_xfree(o->name);
pa_xfree(o->driver);
pa_xfree(o); pa_xfree(o);
} }
void pa_source_output_unref(pa_source_output* o) { void pa_source_output_unref(pa_source_output* o) {
assert(o && o->ref >= 1); assert(o);
assert(o->ref >= 1);
if (!(--o->ref)) if (!(--o->ref))
source_output_free(o); source_output_free(o);
} }
pa_source_output* pa_source_output_ref(pa_source_output *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++; o->ref++;
return o; return o;
} }
void pa_source_output_kill(pa_source_output*o) { void pa_source_output_kill(pa_source_output*o) {
assert(o && o->ref >= 1); assert(o);
assert(o->ref >= 1);
if (o->kill) if (o->kill)
o->kill(o); 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) { void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
pa_memchunk rchunk; 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) if (o->state == PA_SOURCE_OUTPUT_CORKED)
return; 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) { 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); pa_xfree(o->name);
o->name = pa_xstrdup(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) { 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) if (o->get_latency)
return o->get_latency(o); 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) { 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) if (o->state == PA_SOURCE_OUTPUT_DISCONNECTED)
return; return;
@ -184,8 +217,9 @@ void pa_source_output_cork(pa_source_output *o, int b) {
o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING; o->state = b ? PA_SOURCE_OUTPUT_CORKED : PA_SOURCE_OUTPUT_RUNNING;
} }
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) {
assert(o && o->ref >= 1); assert(o);
assert(o->ref >= 1);
if (!o->resampler) if (!o->resampler)
return PA_RESAMPLER_INVALID; return PA_RESAMPLER_INVALID;

Some files were not shown because too many files have changed in this diff Show more