X-Git-Url: https://code.delx.au/pulseaudio/blobdiff_plain/46091a9237f17f4295dca7140d8d70b4fce8b357..fa499dad06ba6558111cdef64c18f2401e803cff:/polyp/module-alsa-source.c diff --git a/polyp/module-alsa-source.c b/polyp/module-alsa-source.c index 8207d462..ba09d319 100644 --- a/polyp/module-alsa-source.c +++ b/polyp/module-alsa-source.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. @@ -38,12 +38,19 @@ #include "sample-util.h" #include "alsa-util.h" #include "xmalloc.h" +#include "log.h" +#include "module-alsa-source-symdef.h" + +PA_MODULE_AUTHOR("Lennart Poettering") +PA_MODULE_DESCRIPTION("ALSA Source") +PA_MODULE_VERSION(PACKAGE_VERSION) +PA_MODULE_USAGE("source_name= device= format= channels= rate= fragments= fragment_size=") struct userdata { snd_pcm_t *pcm_handle; struct pa_source *source; - 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; @@ -53,9 +60,9 @@ struct userdata { static const char* const valid_modargs[] = { "device", "source_name", - "format", "channels", "rate", + "format", "fragments", "fragment_size", NULL @@ -72,10 +79,10 @@ static void update_usage(struct userdata *u) { static void xrun_recovery(struct userdata *u) { assert(u); - fprintf(stderr, "*** ALSA-XRUN (capture) ***\n"); + pa_log(__FILE__": *** ALSA-XRUN (capture) ***\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_read(struct userdata *u) { @@ -89,13 +96,13 @@ static void do_read(struct userdata *u) { size_t l; if (!u->memchunk.memblock) { - u->memchunk.memblock = pa_memblock_new(u->memchunk.length = u->fragment_size); + u->memchunk.memblock = pa_memblock_new(u->memchunk.length = u->fragment_size, u->source->core->memblock_stat); u->memchunk.index = 0; } assert(u->memchunk.memblock && u->memchunk.memblock->data && u->memchunk.length && u->memchunk.memblock->length && (u->memchunk.length % u->frame_size) == 0); - if ((frames = snd_pcm_readi(u->pcm_handle, u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { + if ((frames = snd_pcm_readi(u->pcm_handle, (uint8_t*) u->memchunk.memblock->data + u->memchunk.index, u->memchunk.length / u->frame_size)) < 0) { if (frames == -EAGAIN) return; @@ -104,7 +111,7 @@ static void do_read(struct userdata *u) { continue; } - fprintf(stderr, "snd_pcm_readi() failed: %s\n", strerror(-frames)); + pa_log(__FILE__": snd_pcm_readi() failed: %s\n", strerror(-frames)); return; } @@ -128,9 +135,9 @@ static void do_read(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); @@ -138,7 +145,21 @@ static void io_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_main do_read(u); } -int pa_module_init(struct pa_core *c, struct pa_module*m) { +static pa_usec_t source_get_latency_cb(struct pa_source *s) { + struct userdata *u = s->userdata; + snd_pcm_sframes_t frames; + assert(s && u && u->source); + + if (snd_pcm_delay(u->pcm_handle, &frames) < 0) { + pa_log(__FILE__": failed to get delay\n"); + s->get_latency = NULL; + return 0; + } + + return pa_bytes_to_usec(frames * u->frame_size, &s->sample_spec); +} + +int pa__init(struct pa_core *c, struct pa_module*m) { struct pa_modargs *ma = NULL; int ret = -1; struct userdata *u = NULL; @@ -149,13 +170,13 @@ 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_frame_size(&ss); @@ -163,7 +184,7 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { 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; @@ -173,12 +194,12 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { u->module = m; if (snd_pcm_open(&u->pcm_handle, dev = pa_modargs_get_value(ma, "device", DEFAULT_DEVICE), SND_PCM_STREAM_CAPTURE, 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; } @@ -186,18 +207,19 @@ int pa_module_init(struct pa_core *c, struct pa_module*m) { assert(u->source); u->source->userdata = u; + u->source->get_latency = source_get_latency_cb; pa_source_set_owner(u->source, m); u->source->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->memchunk.memblock = NULL; u->memchunk.index = u->memchunk.length = 0; @@ -215,23 +237,25 @@ 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)) return; - if (u->source) - pa_source_free(u->source); + if (u->source) { + pa_source_disconnect(u->source); + pa_source_unref(u->source); + } - if (u->io_sources) - pa_free_io_sources(c->mainloop, u->io_sources, u->n_io_sources); + 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);