PulseAudio 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,
+ by the Free Software Foundation; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
#endif
#include <stdlib.h>
-#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
-#include <string.h>
-#include <fcntl.h>
#include <unistd.h>
-#include <limits.h>
+#include <pulse/rtclock.h>
#include <pulse/timeval.h>
#include <pulse/xmalloc.h>
+#include <pulsecore/i18n.h>
#include <pulsecore/macro.h>
#include <pulsecore/sink.h>
#include <pulsecore/module.h>
#include <pulsecore/core-util.h>
-#include <pulsecore/core-error.h>
#include <pulsecore/modargs.h>
#include <pulsecore/log.h>
#include <pulsecore/thread.h>
#include <pulsecore/thread-mq.h>
#include <pulsecore/rtpoll.h>
-#include <pulsecore/rtclock.h>
#include "module-null-sink-symdef.h"
PA_MODULE_AUTHOR("Lennart Poettering");
-PA_MODULE_DESCRIPTION("Clocked NULL sink");
+PA_MODULE_DESCRIPTION(_("Clocked NULL sink"));
PA_MODULE_VERSION(PACKAGE_VERSION);
PA_MODULE_LOAD_ONCE(FALSE);
PA_MODULE_USAGE(
+ "sink_name=<name of sink> "
+ "sink_properties=<properties for the sink> "
"format=<sample format> "
- "channels=<number of channels> "
"rate=<sample rate> "
- "sink_name=<name of sink> "
- "channel_map=<channel map> "
- "description=<description for the sink>");
+ "channels=<number of channels> "
+ "channel_map=<channel map>");
#define DEFAULT_SINK_NAME "null"
-#define MAX_LATENCY_USEC (PA_USEC_PER_SEC * 2)
+#define BLOCK_USEC (PA_USEC_PER_SEC * 2)
struct userdata {
pa_core *core;
};
static const char* const valid_modargs[] = {
- "rate",
+ "sink_name",
+ "sink_properties",
"format",
+ "rate",
"channels",
- "sink_name",
"channel_map",
- "description",
NULL
};
case PA_SINK_MESSAGE_SET_STATE:
if (PA_PTR_TO_UINT(data) == PA_SINK_RUNNING)
- u->timestamp = pa_rtclock_usec();
+ u->timestamp = pa_rtclock_now();
break;
case PA_SINK_MESSAGE_GET_LATENCY: {
pa_usec_t now;
- now = pa_rtclock_usec();
+ now = pa_rtclock_now();
*((pa_usec_t*) data) = u->timestamp > now ? u->timestamp - now : 0ULL;
return 0;
static void sink_update_requested_latency_cb(pa_sink *s) {
struct userdata *u;
+ size_t nbytes;
pa_sink_assert_ref(s);
pa_assert_se(u = s->userdata);
if (u->block_usec == (pa_usec_t) -1)
u->block_usec = s->thread_info.max_latency;
+
+ nbytes = pa_usec_to_bytes(u->block_usec, &s->sample_spec);
+ pa_sink_set_max_rewind_within_thread(s, nbytes);
+ pa_sink_set_max_request_within_thread(s, nbytes);
}
static void process_rewind(struct userdata *u, pa_usec_t now) {
/* This is the configured latency. Sink inputs connected to us
might not have a single frame more than the maxrequest value
- queed. Hence: at maximum read this many bytes from the sink
+ queued. Hence: at maximum read this many bytes from the sink
inputs. */
- /* Fill the buffer up the the latency size */
+ /* Fill the buffer up the latency size */
while (u->timestamp < now + u->block_usec) {
pa_memchunk chunk;
pa_log_debug("Thread starting up");
pa_thread_mq_install(&u->thread_mq);
- pa_rtpoll_install(u->rtpoll);
- u->timestamp = pa_rtclock_usec();
+ u->timestamp = pa_rtclock_now();
for (;;) {
int ret;
if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) {
pa_usec_t now;
- now = pa_rtclock_usec();
+ now = pa_rtclock_now();
if (u->sink->thread_info.rewind_requested) {
if (u->sink->thread_info.rewind_nbytes > 0)
pa_channel_map map;
pa_modargs *ma = NULL;
pa_sink_new_data data;
+ size_t nbytes;
pa_assert(m);
}
ss = m->core->default_sample_spec;
+ map = m->core->default_channel_map;
if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
pa_log("Invalid sample format specification or channel map");
goto fail;
pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME));
pa_sink_new_data_set_sample_spec(&data, &ss);
pa_sink_new_data_set_channel_map(&data, &map);
- pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, pa_modargs_get_value(ma, "description", "Null Output"));
+ pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, _("Null Output"));
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract");
- u->sink = pa_sink_new(m->core, &data, PA_SINK_LATENCY);
+ if (pa_modargs_get_proplist(ma, "sink_properties", data.proplist, PA_UPDATE_REPLACE) < 0) {
+ pa_log("Invalid properties");
+ pa_sink_new_data_done(&data);
+ goto fail;
+ }
+
+ u->sink = pa_sink_new(m->core, &data, PA_SINK_LATENCY|PA_SINK_DYNAMIC_LATENCY);
pa_sink_new_data_done(&data);
if (!u->sink) {
pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
pa_sink_set_rtpoll(u->sink, u->rtpoll);
- pa_sink_set_latency_range(u->sink, (pa_usec_t) -1, MAX_LATENCY_USEC);
- u->block_usec = u->sink->thread_info.max_latency;
-
- u->sink->thread_info.max_rewind =
- u->sink->thread_info.max_request =
- pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
+ u->block_usec = BLOCK_USEC;
+ nbytes = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
+ pa_sink_set_max_rewind(u->sink, nbytes);
+ pa_sink_set_max_request(u->sink, nbytes);
- if (!(u->thread = pa_thread_new(thread_func, u))) {
+ if (!(u->thread = pa_thread_new("null-sink", thread_func, u))) {
pa_log("Failed to create thread.");
goto fail;
}
+ pa_sink_set_latency_range(u->sink, 0, BLOCK_USEC);
+
pa_sink_put(u->sink);
pa_modargs_free(ma);
return -1;
}
+int pa__get_n_used(pa_module *m) {
+ struct userdata *u;
+
+ pa_assert(m);
+ pa_assert_se(u = m->userdata);
+
+ return pa_sink_linked_by(u->sink);
+}
+
void pa__done(pa_module*m) {
struct userdata *u;