mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-02 09:01:46 -05:00
add input latency measurement
add GETOSPACE support to module-oss git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@205 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
parent
f5d47a293a
commit
f9e2058820
20 changed files with 293 additions and 69 deletions
|
|
@ -59,6 +59,7 @@ struct userdata {
|
|||
struct pa_memchunk memchunk, silence;
|
||||
|
||||
uint32_t in_fragment_size, out_fragment_size, sample_size;
|
||||
int use_getospace, use_getispace;
|
||||
|
||||
int fd;
|
||||
struct pa_module *module;
|
||||
|
|
@ -92,6 +93,9 @@ static void update_usage(struct userdata *u) {
|
|||
static void do_write(struct userdata *u) {
|
||||
struct pa_memchunk *memchunk;
|
||||
ssize_t r;
|
||||
size_t l;
|
||||
int loop = 0;
|
||||
|
||||
assert(u);
|
||||
|
||||
if (!u->sink || !pa_iochannel_is_writable(u->io))
|
||||
|
|
@ -99,37 +103,58 @@ static void do_write(struct userdata *u) {
|
|||
|
||||
update_usage(u);
|
||||
|
||||
memchunk = &u->memchunk;
|
||||
l = u->out_fragment_size;
|
||||
|
||||
if (!memchunk->length)
|
||||
if (pa_sink_render(u->sink, u->out_fragment_size, memchunk) < 0)
|
||||
memchunk = &u->silence;
|
||||
|
||||
assert(memchunk->memblock);
|
||||
assert(memchunk->memblock->data);
|
||||
assert(memchunk->length);
|
||||
|
||||
if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) {
|
||||
pa_log(__FILE__": write() failed: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (u->use_getospace) {
|
||||
audio_buf_info info;
|
||||
|
||||
if (memchunk == &u->silence)
|
||||
assert(r % u->sample_size == 0);
|
||||
else {
|
||||
u->memchunk.index += r;
|
||||
u->memchunk.length -= r;
|
||||
|
||||
if (u->memchunk.length <= 0) {
|
||||
pa_memblock_unref(u->memchunk.memblock);
|
||||
u->memchunk.memblock = NULL;
|
||||
if (ioctl(u->fd, SNDCTL_DSP_GETOSPACE, &info) < 0)
|
||||
u->use_getospace = 0;
|
||||
else {
|
||||
if (info.bytes/l > 0) {
|
||||
l = (info.bytes/l)*l;
|
||||
loop = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
memchunk = &u->memchunk;
|
||||
|
||||
if (!memchunk->length)
|
||||
if (pa_sink_render(u->sink, l, memchunk) < 0)
|
||||
memchunk = &u->silence;
|
||||
|
||||
assert(memchunk->memblock);
|
||||
assert(memchunk->memblock->data);
|
||||
assert(memchunk->length);
|
||||
|
||||
if ((r = pa_iochannel_write(u->io, (uint8_t*) memchunk->memblock->data + memchunk->index, memchunk->length)) < 0) {
|
||||
pa_log(__FILE__": write() failed: %s\n", strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
if (memchunk == &u->silence)
|
||||
assert(r % u->sample_size == 0);
|
||||
else {
|
||||
u->memchunk.index += r;
|
||||
u->memchunk.length -= r;
|
||||
|
||||
if (u->memchunk.length <= 0) {
|
||||
pa_memblock_unref(u->memchunk.memblock);
|
||||
u->memchunk.memblock = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
l = l > (size_t) r ? l - r : 0;
|
||||
} while (loop && l > 0);
|
||||
}
|
||||
|
||||
static void do_read(struct userdata *u) {
|
||||
struct pa_memchunk memchunk;
|
||||
ssize_t r;
|
||||
size_t l;
|
||||
int loop = 0;
|
||||
assert(u);
|
||||
|
||||
if (!u->source || !pa_iochannel_is_readable(u->io))
|
||||
|
|
@ -137,21 +162,40 @@ static void do_read(struct userdata *u) {
|
|||
|
||||
update_usage(u);
|
||||
|
||||
memchunk.memblock = pa_memblock_new(u->in_fragment_size, u->core->memblock_stat);
|
||||
assert(memchunk.memblock);
|
||||
if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) {
|
||||
pa_memblock_unref(memchunk.memblock);
|
||||
if (errno != EAGAIN)
|
||||
pa_log(__FILE__": read() failed: %s\n", strerror(errno));
|
||||
return;
|
||||
l = u->in_fragment_size;
|
||||
|
||||
if (u->use_getispace) {
|
||||
audio_buf_info info;
|
||||
|
||||
if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0)
|
||||
u->use_getispace = 0;
|
||||
else {
|
||||
if (info.bytes/l > 0) {
|
||||
l = (info.bytes/l)*l;
|
||||
loop = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
memchunk.memblock = pa_memblock_new(l, u->core->memblock_stat);
|
||||
assert(memchunk.memblock);
|
||||
if ((r = pa_iochannel_read(u->io, memchunk.memblock->data, memchunk.memblock->length)) < 0) {
|
||||
pa_memblock_unref(memchunk.memblock);
|
||||
if (errno != EAGAIN)
|
||||
pa_log(__FILE__": read() failed: %s\n", strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
assert(r <= (ssize_t) memchunk.memblock->length);
|
||||
memchunk.length = memchunk.memblock->length = r;
|
||||
memchunk.index = 0;
|
||||
|
||||
pa_source_post(u->source, &memchunk);
|
||||
pa_memblock_unref(memchunk.memblock);
|
||||
|
||||
assert(r <= (ssize_t) memchunk.memblock->length);
|
||||
memchunk.length = memchunk.memblock->length = r;
|
||||
memchunk.index = 0;
|
||||
|
||||
pa_source_post(u->source, &memchunk);
|
||||
pa_memblock_unref(memchunk.memblock);
|
||||
l = l > (size_t) r ? l - r : 0;
|
||||
} while (loop && l > 0);
|
||||
}
|
||||
|
||||
static void io_callback(struct pa_iochannel *io, void*userdata) {
|
||||
|
|
@ -181,6 +225,25 @@ static pa_usec_t sink_get_latency_cb(struct pa_sink *s) {
|
|||
return r;
|
||||
}
|
||||
|
||||
static pa_usec_t source_get_latency_cb(struct pa_source *s) {
|
||||
struct userdata *u = s->userdata;
|
||||
audio_buf_info info;
|
||||
assert(s && u && u->sink);
|
||||
|
||||
if (!u->use_getispace)
|
||||
return 0;
|
||||
|
||||
if (ioctl(u->fd, SNDCTL_DSP_GETISPACE, &info) < 0) {
|
||||
u->use_getispace = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (info.bytes <= 0)
|
||||
return 0;
|
||||
|
||||
return pa_bytes_to_usec(info.bytes, &s->sample_spec);
|
||||
}
|
||||
|
||||
int pa__init(struct pa_core *c, struct pa_module*m) {
|
||||
struct audio_buf_info info;
|
||||
struct userdata *u = NULL;
|
||||
|
|
@ -243,23 +306,27 @@ int pa__init(struct pa_core *c, struct pa_module*m) {
|
|||
assert(frag_size);
|
||||
in_frag_size = out_frag_size = frag_size;
|
||||
|
||||
u = pa_xmalloc(sizeof(struct userdata));
|
||||
u->core = c;
|
||||
u->use_getospace = u->use_getispace = 0;
|
||||
|
||||
if (ioctl(fd, SNDCTL_DSP_GETISPACE, &info) >= 0) {
|
||||
pa_log(__FILE__": input -- %u fragments of size %u.\n", info.fragstotal, info.fragsize);
|
||||
in_frag_size = info.fragsize;
|
||||
u->use_getispace = 1;
|
||||
}
|
||||
|
||||
if (ioctl(fd, SNDCTL_DSP_GETOSPACE, &info) >= 0) {
|
||||
pa_log(__FILE__": output -- %u fragments of size %u.\n", info.fragstotal, info.fragsize);
|
||||
out_frag_size = info.fragsize;
|
||||
u->use_getospace = 1;
|
||||
}
|
||||
|
||||
u = pa_xmalloc(sizeof(struct userdata));
|
||||
u->core = c;
|
||||
|
||||
if (mode != O_WRONLY) {
|
||||
u->source = pa_source_new(c, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME), 0, &ss);
|
||||
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("Open Sound System PCM on '%s'", p);
|
||||
} else
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue