X-Git-Url: https://code.delx.au/pulseaudio/blobdiff_plain/bb0b105b83c0f4ee56b4c7e9a179606aee296aa9..fa499dad06ba6558111cdef64c18f2401e803cff:/polyp/module-alsa-sink.c diff --git a/polyp/module-alsa-sink.c b/polyp/module-alsa-sink.c index c250d1cf..a708329d 100644 --- a/polyp/module-alsa-sink.c +++ b/polyp/module-alsa-sink.c @@ -4,7 +4,7 @@ This file is part of polypaudio. polypaudio is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published + 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. @@ -13,7 +13,7 @@ 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 General Public License + 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. @@ -37,15 +37,24 @@ #include "util.h" #include "sample-util.h" #include "alsa-util.h" +#include "xmalloc.h" +#include "log.h" +#include "module-alsa-sink-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("ALSA Sink") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("sink_name= device= format= channels= rate= fragments= fragment_size=") struct userdata { snd_pcm_t *pcm_handle; struct pa_sink *sink; - void **io_sources; - unsigned n_io_sources; + struct pa_io_event **io_events; + unsigned n_io_events; size_t frame_size, fragment_size; struct pa_memchunk memchunk, silence; + struct pa_module *module; }; static const char* const valid_modargs[] = { @@ -62,18 +71,26 @@ static const char* const valid_modargs[] = { #define DEFAULT_SINK_NAME "alsa_output" #define DEFAULT_DEVICE "plughw:0,0" +static void update_usage(struct userdata *u) { + pa_module_set_used(u->module, + (u->sink ? pa_idxset_ncontents(u->sink->inputs) : 0) + + (u->sink ? pa_idxset_ncontents(u->sink->monitor_source->outputs) : 0)); +} + static void xrun_recovery(struct userdata *u) { assert(u); - fprintf(stderr, "*** ALSA-XRUN (playback) ***\n"); + pa_log(__FILE__": *** ALSA-XRUN (playback) ***\n"); if (snd_pcm_prepare(u->pcm_handle) < 0) - fprintf(stderr, "snd_pcm_prepare() failed\n"); + pa_log(__FILE__": snd_pcm_prepare() failed\n"); } static void do_write(struct userdata *u) { assert(u); + update_usage(u); + for (;;) { struct pa_memchunk *memchunk = NULL; snd_pcm_sframes_t frames; @@ -89,7 +106,7 @@ static void do_write(struct userdata *u) { assert(memchunk->memblock && memchunk->memblock->data && memchunk->length && memchunk->memblock->length && (memchunk->length % u->frame_size) == 0); - if ((frames = snd_pcm_writei(u->pcm_handle, memchunk->memblock->data + memchunk->index, memchunk->length / u->frame_size)) < 0) { + if ((frames = snd_pcm_writei(u->pcm_handle, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length / u->frame_size)) < 0) { if (frames == -EAGAIN) return; @@ -98,7 +115,7 @@ static void do_write(struct userdata *u) { continue; } - fprintf(stderr, "snd_pcm_writei() failed\n"); + pa_log(__FILE__": snd_pcm_writei() failed\n"); return; } @@ -118,9 +135,9 @@ static void do_write(struct userdata *u) { } } -static void io_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { +static void io_callback(struct pa_mainloop_api*a, struct pa_io_event *e, int fd, enum pa_io_event_flags f, void *userdata) { struct userdata *u = userdata; - assert(u && a && id); + assert(u && a && e); if (snd_pcm_state(u->pcm_handle) == SND_PCM_STATE_XRUN) xrun_recovery(u); @@ -128,13 +145,14 @@ static void io_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_main do_write(u); } -static uint32_t sink_get_latency_cb(struct pa_sink *s) { +static pa_usec_t sink_get_latency_cb(struct pa_sink *s) { + pa_usec_t r = 0; struct userdata *u = s->userdata; snd_pcm_sframes_t frames; assert(s && u && u->sink); if (snd_pcm_delay(u->pcm_handle, &frames) < 0) { - fprintf(stderr, __FILE__": failed to get delay\n"); + pa_log(__FILE__": failed to get delay\n"); s->get_latency = NULL; return 0; } @@ -142,10 +160,15 @@ static uint32_t sink_get_latency_cb(struct pa_sink *s) { if (frames < 0) frames = 0; - return pa_samples_usec(frames * u->frame_size, &s->sample_spec); + r += pa_bytes_to_usec(frames * u->frame_size, &s->sample_spec); + + if (u->memchunk.memblock) + r += pa_bytes_to_usec(u->memchunk.length, &s->sample_spec); + + return r; } -int pa_module_init(struct pa_core *c, struct pa_module*m) { +int pa__init(struct pa_core *c, struct pa_module*m) { struct pa_modargs *ma = NULL; int ret = -1; struct userdata *u = NULL; @@ -156,37 +179,36 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { size_t frame_size; if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { - fprintf(stderr, __FILE__": failed to parse module arguments\n"); + pa_log(__FILE__": failed to parse module arguments\n"); goto fail; } ss = c->default_sample_spec; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { - fprintf(stderr, __FILE__": failed to parse sample specification\n"); + pa_log(__FILE__": failed to parse sample specification\n"); goto fail; } - frame_size = pa_sample_size(&ss); + frame_size = pa_frame_size(&ss); periods = 12; fragsize = 1024; if (pa_modargs_get_value_u32(ma, "fragments", &periods) < 0 || pa_modargs_get_value_u32(ma, "fragment_size", &fragsize) < 0) { - fprintf(stderr, __FILE__": failed to parse buffer metrics\n"); + pa_log(__FILE__": failed to parse buffer metrics\n"); goto fail; } buffer_size = fragsize/frame_size*periods; - u = malloc(sizeof(struct userdata)); - assert(u); - memset(u, 0, sizeof(struct userdata)); + u = pa_xmalloc0(sizeof(struct userdata)); m->userdata = u; + u->module = m; if (snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) { - fprintf(stderr, __FILE__": Error opening PCM device %s\n", dev); + pa_log(__FILE__": Error opening PCM device %s\n", dev); goto fail; } if (pa_alsa_set_hw_params(u->pcm_handle, &ss, &periods, &buffer_size) < 0) { - fprintf(stderr, __FILE__": Failed to set hardware parameters\n"); + pa_log(__FILE__": Failed to set hardware parameters\n"); goto fail; } @@ -198,17 +220,17 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { pa_sink_set_owner(u->sink, m); u->sink->description = pa_sprintf_malloc("Advanced Linux Sound Architecture PCM on '%s'", dev); - if (pa_create_io_sources(u->pcm_handle, c->mainloop, &u->io_sources, &u->n_io_sources, io_callback, u) < 0) { - fprintf(stderr, __FILE__": failed to obtain file descriptors\n"); + if (pa_create_io_events(u->pcm_handle, c->mainloop, &u->io_events, &u->n_io_events, io_callback, u) < 0) { + pa_log(__FILE__": failed to obtain file descriptors\n"); goto fail; } u->frame_size = frame_size; u->fragment_size = buffer_size*u->frame_size/periods; - fprintf(stderr, __FILE__": using %u fragments of size %u bytes.\n", periods, u->fragment_size); + pa_log(__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); + u->silence.memblock = pa_memblock_new(u->silence.length = u->fragment_size, c->memblock_stat); assert(u->silence.memblock); pa_silence_memblock(u->silence.memblock, &ss); u->silence.index = 0; @@ -227,33 +249,36 @@ finish: fail: if (u) - pa_module_done(c, m); + pa__done(c, m); goto finish; } -void pa_module_done(struct pa_core *c, struct pa_module*m) { +void pa__done(struct pa_core *c, struct pa_module*m) { struct userdata *u; assert(c && m); - if ((u = m->userdata)) { - if (u->sink) - pa_sink_free(u->sink); - - if (u->io_sources) - pa_free_io_sources(c->mainloop, u->io_sources, u->n_io_sources); - - if (u->pcm_handle) { - snd_pcm_drop(u->pcm_handle); - snd_pcm_close(u->pcm_handle); - } - - if (u->memchunk.memblock) - pa_memblock_unref(u->memchunk.memblock); - if (u->silence.memblock) - pa_memblock_unref(u->silence.memblock); - - free(u); + if (!(u = m->userdata)) + return; + + if (u->sink) { + pa_sink_disconnect(u->sink); + pa_sink_unref(u->sink); } + + if (u->io_events) + pa_free_io_events(c->mainloop, u->io_events, u->n_io_events); + + if (u->pcm_handle) { + snd_pcm_drop(u->pcm_handle); + snd_pcm_close(u->pcm_handle); + } + + if (u->memchunk.memblock) + pa_memblock_unref(u->memchunk.memblock); + if (u->silence.memblock) + pa_memblock_unref(u->silence.memblock); + + pa_xfree(u); }