mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-02 09:01:46 -05:00
fix pipe sink for glitch-free
git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/glitch-free@2417 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
parent
dd29f67703
commit
8baa1a46e3
2 changed files with 63 additions and 36 deletions
|
|
@ -160,6 +160,8 @@ static void process_render(struct userdata *u, pa_usec_t now) {
|
||||||
size_t nbytes;
|
size_t nbytes;
|
||||||
size_t ate = 0;
|
size_t ate = 0;
|
||||||
|
|
||||||
|
pa_assert(u);
|
||||||
|
|
||||||
/* This is the configured latency. Sink inputs connected to us
|
/* This is the configured latency. Sink inputs connected to us
|
||||||
might not have a single frame more than this value queued. Hence:
|
might not have a single frame more than this value queued. Hence:
|
||||||
at maximum read this many bytes from the sink inputs. */
|
at maximum read this many bytes from the sink inputs. */
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ PA_MODULE_USAGE(
|
||||||
"rate=<sample rate>"
|
"rate=<sample rate>"
|
||||||
"channel_map=<channel map>");
|
"channel_map=<channel map>");
|
||||||
|
|
||||||
#define DEFAULT_FILE_NAME "/tmp/music.output"
|
#define DEFAULT_FILE_NAME "fifo_output"
|
||||||
#define DEFAULT_SINK_NAME "fifo_output"
|
#define DEFAULT_SINK_NAME "fifo_output"
|
||||||
|
|
||||||
struct userdata {
|
struct userdata {
|
||||||
|
|
@ -80,6 +80,8 @@ struct userdata {
|
||||||
pa_memchunk memchunk;
|
pa_memchunk memchunk;
|
||||||
|
|
||||||
pa_rtpoll_item *rtpoll_item;
|
pa_rtpoll_item *rtpoll_item;
|
||||||
|
|
||||||
|
int write_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char* const valid_modargs[] = {
|
static const char* const valid_modargs[] = {
|
||||||
|
|
@ -109,16 +111,64 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
|
||||||
n += u->memchunk.length;
|
n += u->memchunk.length;
|
||||||
|
|
||||||
*((pa_usec_t*) data) = pa_bytes_to_usec(n, &u->sink->sample_spec);
|
*((pa_usec_t*) data) = pa_bytes_to_usec(n, &u->sink->sample_spec);
|
||||||
break;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pa_sink_process_msg(o, code, data, offset, chunk);
|
return pa_sink_process_msg(o, code, data, offset, chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void process_rewind(struct userdata *u) {
|
||||||
|
pa_assert(u);
|
||||||
|
|
||||||
|
pa_log_debug("Rewind requested but not supported by pipe sink. Ignoring.");
|
||||||
|
u->sink->thread_info.rewind_nbytes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int process_render(struct userdata *u) {
|
||||||
|
pa_assert(u);
|
||||||
|
|
||||||
|
if (u->memchunk.length <= 0)
|
||||||
|
pa_sink_render(u->sink, PIPE_BUF, &u->memchunk);
|
||||||
|
|
||||||
|
pa_assert(u->memchunk.length > 0);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
ssize_t l;
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
p = pa_memblock_acquire(u->memchunk.memblock);
|
||||||
|
l = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, &u->write_type);
|
||||||
|
pa_memblock_release(u->memchunk.memblock);
|
||||||
|
|
||||||
|
pa_assert(l != 0);
|
||||||
|
|
||||||
|
if (l < 0) {
|
||||||
|
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
else if (errno != EAGAIN) {
|
||||||
|
pa_log("Failed to write data to FIFO: %s", pa_cstrerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
u->memchunk.index += l;
|
||||||
|
u->memchunk.length -= l;
|
||||||
|
|
||||||
|
if (u->memchunk.length <= 0) {
|
||||||
|
pa_memblock_unref(u->memchunk.memblock);
|
||||||
|
pa_memchunk_reset(&u->memchunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void thread_func(void *userdata) {
|
static void thread_func(void *userdata) {
|
||||||
struct userdata *u = userdata;
|
struct userdata *u = userdata;
|
||||||
int write_type = 0;
|
|
||||||
|
|
||||||
pa_assert(u);
|
pa_assert(u);
|
||||||
|
|
||||||
|
|
@ -134,39 +184,14 @@ static void thread_func(void *userdata) {
|
||||||
pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
|
pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
|
||||||
|
|
||||||
/* Render some data and write it to the fifo */
|
/* Render some data and write it to the fifo */
|
||||||
if (u->sink->thread_info.state == PA_SINK_RUNNING && pollfd->revents) {
|
if (u->sink->thread_info.state == PA_SINK_RUNNING) {
|
||||||
ssize_t l;
|
|
||||||
void *p;
|
|
||||||
|
|
||||||
if (u->memchunk.length <= 0)
|
if (u->sink->thread_info.rewind_nbytes > 0)
|
||||||
pa_sink_render(u->sink, PIPE_BUF, &u->memchunk);
|
process_rewind(u);
|
||||||
|
|
||||||
pa_assert(u->memchunk.length > 0);
|
if (pollfd->revents) {
|
||||||
|
if (process_render(u) < 0)
|
||||||
p = pa_memblock_acquire(u->memchunk.memblock);
|
|
||||||
l = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, &write_type);
|
|
||||||
pa_memblock_release(u->memchunk.memblock);
|
|
||||||
|
|
||||||
pa_assert(l != 0);
|
|
||||||
|
|
||||||
if (l < 0) {
|
|
||||||
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
else if (errno != EAGAIN) {
|
|
||||||
pa_log("Failed to write data to FIFO: %s", pa_cstrerror(errno));
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
u->memchunk.index += l;
|
|
||||||
u->memchunk.length -= l;
|
|
||||||
|
|
||||||
if (u->memchunk.length <= 0) {
|
|
||||||
pa_memblock_unref(u->memchunk.memblock);
|
|
||||||
pa_memchunk_reset(&u->memchunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
pollfd->revents = 0;
|
pollfd->revents = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -229,8 +254,9 @@ int pa__init(pa_module*m) {
|
||||||
pa_memchunk_reset(&u->memchunk);
|
pa_memchunk_reset(&u->memchunk);
|
||||||
u->rtpoll = pa_rtpoll_new();
|
u->rtpoll = pa_rtpoll_new();
|
||||||
pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
|
pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
|
||||||
|
u->write_type = 0;
|
||||||
|
|
||||||
u->filename = pa_xstrdup(pa_modargs_get_value(ma, "file", DEFAULT_FILE_NAME));
|
u->filename = pa_runtime_path(pa_modargs_get_value(ma, "file", DEFAULT_FILE_NAME));
|
||||||
|
|
||||||
mkfifo(u->filename, 0666);
|
mkfifo(u->filename, 0666);
|
||||||
if ((u->fd = open(u->filename, O_RDWR|O_NOCTTY)) < 0) {
|
if ((u->fd = open(u->filename, O_RDWR|O_NOCTTY)) < 0) {
|
||||||
|
|
@ -256,8 +282,7 @@ int pa__init(pa_module*m) {
|
||||||
data.module = m;
|
data.module = m;
|
||||||
pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME));
|
pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME));
|
||||||
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->filename);
|
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->filename);
|
||||||
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, t = pa_sprintf_malloc("Unix FIFO sink %s", u->filename));
|
pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Unix FIFO sink %s", u->filename);
|
||||||
pa_xfree(t);
|
|
||||||
pa_sink_new_data_set_sample_spec(&data, &ss);
|
pa_sink_new_data_set_sample_spec(&data, &ss);
|
||||||
pa_sink_new_data_set_channel_map(&data, &map);
|
pa_sink_new_data_set_channel_map(&data, &map);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue