libpulseaudio: add module-aaudio-sink
Add a sink module that makes use of the AAudio API, which is available in Oreo or later. The sink will have its sample rate and latency configured based on the info we got with the API. They will also be updated accordingly when the output device is changed.
This commit is contained in:
parent
19709225bd
commit
6b1d24adf0
17
packages/libpulseaudio/aaudio.patch
Normal file
17
packages/libpulseaudio/aaudio.patch
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
diff --git a/src/Makefile.am~ b/src/Makefile.am
|
||||||
|
index f4464d2..eebcf02 100644
|
||||||
|
--- a/src/Makefile.am~
|
||||||
|
+++ b/src/Makefile.am
|
||||||
|
@@ -1495,6 +1495,12 @@ bin_SCRIPTS += utils/qpaeq
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
+modlibexec_LTLIBRARIES += module-aaudio-sink.la
|
||||||
|
+module_aaudio_sink_la_SOURCES = modules/aaudio/module-aaudio-sink.c
|
||||||
|
+module_aaudio_sink_la_LDFLAGS = $(MODULE_LDFLAGS) -laaudio
|
||||||
|
+module_aaudio_sink_la_LIBADD = $(MODULE_LIBADD)
|
||||||
|
+module_aaudio_sink_la_CFLAGS = $(AM_CFLAGS) -DPA_MODULE_NAME=module_aaudio_sink
|
||||||
|
+
|
||||||
|
# Simple protocol
|
||||||
|
|
||||||
|
module_simple_protocol_tcp_la_SOURCES = modules/module-protocol-stub.c
|
@ -1,7 +1,7 @@
|
|||||||
TERMUX_PKG_HOMEPAGE=https://www.freedesktop.org/wiki/Software/PulseAudio
|
TERMUX_PKG_HOMEPAGE=https://www.freedesktop.org/wiki/Software/PulseAudio
|
||||||
TERMUX_PKG_DESCRIPTION="A featureful, general-purpose sound server - shared libraries"
|
TERMUX_PKG_DESCRIPTION="A featureful, general-purpose sound server - shared libraries"
|
||||||
TERMUX_PKG_VERSION=12.2
|
TERMUX_PKG_VERSION=12.2
|
||||||
TERMUX_PKG_REVISION=4
|
TERMUX_PKG_REVISION=5
|
||||||
TERMUX_PKG_SHA256=809668ffc296043779c984f53461c2b3987a45b7a25eb2f0a1d11d9f23ba4055
|
TERMUX_PKG_SHA256=809668ffc296043779c984f53461c2b3987a45b7a25eb2f0a1d11d9f23ba4055
|
||||||
TERMUX_PKG_SRCURL=https://www.freedesktop.org/software/pulseaudio/releases/pulseaudio-${TERMUX_PKG_VERSION}.tar.xz
|
TERMUX_PKG_SRCURL=https://www.freedesktop.org/software/pulseaudio/releases/pulseaudio-${TERMUX_PKG_VERSION}.tar.xz
|
||||||
TERMUX_PKG_DEPENDS="libltdl, libsndfile, libandroid-glob, libsoxr"
|
TERMUX_PKG_DEPENDS="libltdl, libsndfile, libandroid-glob, libsoxr"
|
||||||
@ -23,6 +23,8 @@ TERMUX_PKG_CONFFILES="etc/pulse/client.conf etc/pulse/daemon.conf etc/pulse/defa
|
|||||||
termux_step_pre_configure () {
|
termux_step_pre_configure () {
|
||||||
mkdir $TERMUX_PKG_SRCDIR/src/modules/sles
|
mkdir $TERMUX_PKG_SRCDIR/src/modules/sles
|
||||||
cp $TERMUX_PKG_BUILDER_DIR/module-sles-sink.c $TERMUX_PKG_SRCDIR/src/modules/sles
|
cp $TERMUX_PKG_BUILDER_DIR/module-sles-sink.c $TERMUX_PKG_SRCDIR/src/modules/sles
|
||||||
|
mkdir $TERMUX_PKG_SRCDIR/src/modules/aaudio
|
||||||
|
cp $TERMUX_PKG_BUILDER_DIR/module-aaudio-sink.c $TERMUX_PKG_SRCDIR/src/modules/aaudio
|
||||||
intltoolize --automake --copy --force
|
intltoolize --automake --copy --force
|
||||||
LDFLAGS+=" -llog -landroid-glob"
|
LDFLAGS+=" -llog -landroid-glob"
|
||||||
}
|
}
|
||||||
@ -39,6 +41,7 @@ termux_step_post_make_install () {
|
|||||||
sed -i $TERMUX_PREFIX/etc/pulse/default.pa \
|
sed -i $TERMUX_PREFIX/etc/pulse/default.pa \
|
||||||
-e '/^load-module module-detect$/s/^/#/'
|
-e '/^load-module module-detect$/s/^/#/'
|
||||||
echo "load-module module-sles-sink" >> $TERMUX_PREFIX/etc/pulse/default.pa
|
echo "load-module module-sles-sink" >> $TERMUX_PREFIX/etc/pulse/default.pa
|
||||||
|
echo "#load-module module-aaudio-sink" >> $TERMUX_PREFIX/etc/pulse/default.pa
|
||||||
|
|
||||||
if [ "$TERMUX_ARCH_BITS" = 32 ]; then
|
if [ "$TERMUX_ARCH_BITS" = 32 ]; then
|
||||||
SYSTEM_LIB=lib
|
SYSTEM_LIB=lib
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
--- ../cache/pulseaudio-11.1/src/Makefile.am 2017-09-18 10:41:02.000000000 +0000
|
|
||||||
+++ ./src/Makefile.am 2017-12-22 22:51:30.628573929 +0000
|
|
||||||
@@ -1594,6 +1595,11 @@
|
|
||||||
module_simple_protocol_unix_la_LIBADD = $(MODULE_LIBADD) libprotocol-simple.la
|
|
||||||
|
|
||||||
# CLI protocol
|
|
||||||
+modlibexec_LTLIBRARIES += module-sles-sink.la
|
|
||||||
+module_sles_sink_la_SOURCES = modules/sles/module-sles-sink.c
|
|
||||||
+module_sles_sink_la_LDFLAGS = $(MODULE_LDFLAGS) -lOpenSLES
|
|
||||||
+module_sles_sink_la_LIBADD = $(MODULE_LIBADD)
|
|
||||||
+module_sles_sink_la_CFLAGS = $(AM_CFLAGS) -DPA_MODULE_NAME=module_sles_sink
|
|
||||||
|
|
||||||
module_cli_la_SOURCES = modules/module-cli.c
|
|
||||||
module_cli_la_LDFLAGS = $(MODULE_LDFLAGS)
|
|
401
packages/libpulseaudio/module-aaudio-sink.c
Normal file
401
packages/libpulseaudio/module-aaudio-sink.c
Normal file
@ -0,0 +1,401 @@
|
|||||||
|
/***
|
||||||
|
This file is part of PulseAudio.
|
||||||
|
|
||||||
|
Copyright 2004-2008 Lennart Poettering
|
||||||
|
|
||||||
|
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.1 of the License,
|
||||||
|
or (at your option) any later version.
|
||||||
|
|
||||||
|
PulseAudio is distributed in the hope that it will be useful, but
|
||||||
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
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 Lesser General Public License
|
||||||
|
along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
|
||||||
|
***/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.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/modargs.h>
|
||||||
|
#include <pulsecore/log.h>
|
||||||
|
#include <pulsecore/thread.h>
|
||||||
|
#include <pulsecore/thread-mq.h>
|
||||||
|
#include <pulsecore/rtpoll.h>
|
||||||
|
|
||||||
|
#include <aaudio/AAudio.h>
|
||||||
|
|
||||||
|
PA_MODULE_AUTHOR("Tom Yan");
|
||||||
|
PA_MODULE_DESCRIPTION("Android AAudio sink");
|
||||||
|
PA_MODULE_VERSION(PACKAGE_VERSION);
|
||||||
|
PA_MODULE_LOAD_ONCE(false);
|
||||||
|
PA_MODULE_USAGE(
|
||||||
|
"sink_name=<name for the sink> "
|
||||||
|
"sink_properties=<properties for the sink> "
|
||||||
|
"rate=<sampling rate> "
|
||||||
|
"latency=<buffer length> "
|
||||||
|
"no_close_hack=<avoid segfault caused by AAudioStream_close()> "
|
||||||
|
);
|
||||||
|
|
||||||
|
#define DEFAULT_SINK_NAME "AAudio sink"
|
||||||
|
|
||||||
|
struct userdata {
|
||||||
|
pa_core *core;
|
||||||
|
pa_module *module;
|
||||||
|
pa_sink *sink;
|
||||||
|
|
||||||
|
pa_thread *thread;
|
||||||
|
pa_thread_mq thread_mq;
|
||||||
|
pa_rtpoll *rtpoll;
|
||||||
|
|
||||||
|
uint32_t latency;
|
||||||
|
uint32_t rate;
|
||||||
|
bool no_close;
|
||||||
|
|
||||||
|
pa_memchunk memchunk;
|
||||||
|
size_t frame_size;
|
||||||
|
|
||||||
|
AAudioStreamBuilder *builder;
|
||||||
|
AAudioStream *stream;
|
||||||
|
pa_sample_spec ss;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char* const valid_modargs[] = {
|
||||||
|
"sink_name",
|
||||||
|
"sink_properties",
|
||||||
|
"rate",
|
||||||
|
"latency",
|
||||||
|
"no_close_hack",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static void update_latency(struct userdata *u) {
|
||||||
|
pa_usec_t block_usec;
|
||||||
|
|
||||||
|
if(!u->latency) {
|
||||||
|
block_usec = PA_USEC_PER_SEC * AAudioStream_getBufferSizeInFrames(u->stream) / u->sink->sample_spec.rate / 2;
|
||||||
|
if(!pa_thread_mq_get())
|
||||||
|
pa_sink_set_fixed_latency(u->sink, block_usec);
|
||||||
|
else
|
||||||
|
pa_sink_set_fixed_latency_within_thread(u->sink, block_usec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static aaudio_data_callback_result_t buffer_callback(AAudioStream *stream, void *userdata, void *audioData, int32_t numFrames) {
|
||||||
|
struct userdata* u = userdata;
|
||||||
|
|
||||||
|
pa_assert(u);
|
||||||
|
|
||||||
|
if (!pa_thread_mq_get()) {
|
||||||
|
pa_log_debug("Thread starting up");
|
||||||
|
pa_thread_mq_install(&u->thread_mq);
|
||||||
|
}
|
||||||
|
|
||||||
|
u->memchunk.memblock = pa_memblock_new_fixed(u->core->mempool, audioData, numFrames * u->frame_size, false);
|
||||||
|
u->memchunk.length = numFrames * u->frame_size;
|
||||||
|
pa_sink_render_into_full(u->sink, &u->memchunk);
|
||||||
|
pa_memblock_unref_fixed(u->memchunk.memblock);
|
||||||
|
|
||||||
|
return AAUDIO_CALLBACK_RESULT_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void error_callback(AAudioStream *stream, void *userdata, aaudio_result_t error) {
|
||||||
|
struct userdata* u = userdata;
|
||||||
|
|
||||||
|
pa_assert(u);
|
||||||
|
|
||||||
|
if (error == AAUDIO_ERROR_DISCONNECTED) {
|
||||||
|
if (!pa_thread_mq_get()) {
|
||||||
|
pa_sink_suspend(u->sink, true, PA_SUSPEND_UNAVAILABLE);
|
||||||
|
pa_sink_suspend(u->sink, false, PA_SUSPEND_UNAVAILABLE);
|
||||||
|
} else {
|
||||||
|
AAudioStream_requestStop(u->stream);
|
||||||
|
AAudioStream_requestStart(u->stream);
|
||||||
|
update_latency(u);
|
||||||
|
pa_log("Failed to reconfigure sink for new device.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CHK(stmt) { \
|
||||||
|
aaudio_result_t res = stmt; \
|
||||||
|
if (res != AAUDIO_OK) { \
|
||||||
|
fprintf(stderr, "error %d at %s:%d\n", res, __FILE__, __LINE__); \
|
||||||
|
goto fail; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pa_open_aaudio_stream(struct userdata *u)
|
||||||
|
{
|
||||||
|
bool want_float;
|
||||||
|
aaudio_format_t format;
|
||||||
|
pa_sample_spec *ss = &u->ss;
|
||||||
|
|
||||||
|
CHK(AAudio_createStreamBuilder(&u->builder));
|
||||||
|
AAudioStreamBuilder_setPerformanceMode(u->builder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
|
||||||
|
AAudioStreamBuilder_setDataCallback(u->builder, buffer_callback, u);
|
||||||
|
AAudioStreamBuilder_setErrorCallback(u->builder, error_callback, u);
|
||||||
|
|
||||||
|
want_float = ss->format > PA_SAMPLE_S16BE;
|
||||||
|
ss->format = want_float ? PA_SAMPLE_FLOAT32LE : PA_SAMPLE_S16LE;
|
||||||
|
format = want_float ? AAUDIO_FORMAT_PCM_FLOAT : AAUDIO_FORMAT_PCM_I16;
|
||||||
|
AAudioStreamBuilder_setFormat(u->builder, format);
|
||||||
|
|
||||||
|
if (u->rate)
|
||||||
|
AAudioStreamBuilder_setSampleRate(u->builder, u->rate);
|
||||||
|
|
||||||
|
AAudioStreamBuilder_setChannelCount(u->builder, ss->channels);
|
||||||
|
|
||||||
|
CHK(AAudioStreamBuilder_openStream(u->builder, &u->stream));
|
||||||
|
CHK(AAudioStreamBuilder_delete(u->builder));
|
||||||
|
|
||||||
|
ss->rate = AAudioStream_getSampleRate(u->stream);
|
||||||
|
u->frame_size = pa_frame_size(ss);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef CHK
|
||||||
|
|
||||||
|
static void thread_func(void *userdata) {
|
||||||
|
struct userdata *u = userdata;
|
||||||
|
|
||||||
|
pa_assert(u);
|
||||||
|
|
||||||
|
pa_log_debug("Thread starting up");
|
||||||
|
pa_thread_mq_install(&u->thread_mq);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (PA_SINK_IS_LINKED(u->sink->thread_info.state)) {
|
||||||
|
AAudioStream_requestStart(u->stream);
|
||||||
|
update_latency(u);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hmm, nothing to do. Let's sleep */
|
||||||
|
if ((ret = pa_rtpoll_run(u->rtpoll)) < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Hmm, nothing to do. Let's sleep */
|
||||||
|
if ((ret = pa_rtpoll_run(u->rtpoll)) < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
/* If this was no regular exit from the loop we have to continue
|
||||||
|
* processing messages until we received PA_MESSAGE_SHUTDOWN */
|
||||||
|
pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
|
||||||
|
pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
|
||||||
|
|
||||||
|
finish:
|
||||||
|
pa_log_debug("Thread shutting down");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int state_func(pa_sink *s, pa_sink_state_t state, pa_suspend_cause_t suspend_cause) {
|
||||||
|
struct userdata *u = s->userdata;
|
||||||
|
int r = 0;
|
||||||
|
uint32_t idx;
|
||||||
|
pa_sink_input *i;
|
||||||
|
pa_idxset *inputs;
|
||||||
|
|
||||||
|
if ((PA_SINK_IS_OPENED(s->state) && state == PA_SINK_SUSPENDED) ||
|
||||||
|
(PA_SINK_IS_LINKED(s->state) && state == PA_SINK_UNLINKED)) {
|
||||||
|
if (u->no_close) {
|
||||||
|
AAudioStream_requestStop(u->stream);
|
||||||
|
} else {
|
||||||
|
AAudioStream_close(u->stream);
|
||||||
|
}
|
||||||
|
} else if (s->state == PA_SINK_SUSPENDED && PA_SINK_IS_OPENED(state)) {
|
||||||
|
pa_open_aaudio_stream(u);
|
||||||
|
|
||||||
|
inputs = pa_idxset_copy(s->inputs, NULL);
|
||||||
|
PA_IDXSET_FOREACH(i, inputs, idx) {
|
||||||
|
if (i->state == PA_SINK_INPUT_RUNNING) {
|
||||||
|
pa_sink_input_cork(i, true);
|
||||||
|
} else {
|
||||||
|
pa_idxset_remove_by_index(inputs, idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s->alternate_sample_rate = u->ss.rate;
|
||||||
|
pa_sink_reconfigure(s, &u->ss, false);
|
||||||
|
s->default_sample_rate = u->ss.rate;
|
||||||
|
|
||||||
|
/* Avoid infinite loop triggered if uncork in this case */
|
||||||
|
if (s->suspend_cause == PA_SUSPEND_IDLE)
|
||||||
|
pa_sink_suspend(u->sink, true, PA_SUSPEND_UNAVAILABLE);
|
||||||
|
|
||||||
|
PA_IDXSET_FOREACH(i, inputs, idx) pa_sink_input_cork(i, false);
|
||||||
|
pa_idxset_free(inputs, NULL);
|
||||||
|
|
||||||
|
AAudioStream_requestStart(u->stream);
|
||||||
|
update_latency(u);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int reconfigure_func(pa_sink *s, pa_sample_spec *ss, bool passthrough) {
|
||||||
|
s->sample_spec.rate = ss->rate;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void process_rewind(pa_sink *s) {
|
||||||
|
pa_sink_process_rewind(s, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pa__init(pa_module*m) {
|
||||||
|
struct userdata *u = NULL;
|
||||||
|
pa_channel_map map;
|
||||||
|
pa_modargs *ma = NULL;
|
||||||
|
pa_sink_new_data data;
|
||||||
|
pa_usec_t block_usec;
|
||||||
|
|
||||||
|
pa_assert(m);
|
||||||
|
|
||||||
|
m->userdata = u = pa_xnew0(struct userdata, 1);
|
||||||
|
|
||||||
|
u->core = m->core;
|
||||||
|
u->module = m;
|
||||||
|
u->rtpoll = pa_rtpoll_new();
|
||||||
|
pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll);
|
||||||
|
|
||||||
|
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
|
||||||
|
pa_log("Failed to parse module arguments.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
u->ss = m->core->default_sample_spec;
|
||||||
|
map = m->core->default_channel_map;
|
||||||
|
pa_modargs_get_sample_rate(ma, &u->rate);
|
||||||
|
|
||||||
|
pa_modargs_get_value_boolean(ma, "no_close_hack", &u->no_close);
|
||||||
|
|
||||||
|
if (pa_open_aaudio_stream(u) < 0)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
pa_sink_new_data_init(&data);
|
||||||
|
data.driver = __FILE__;
|
||||||
|
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_sample_spec(&data, &u->ss);
|
||||||
|
pa_sink_new_data_set_channel_map(&data, &map);
|
||||||
|
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, _("AAudio Output"));
|
||||||
|
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_CLASS, "abstract");
|
||||||
|
|
||||||
|
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, 0);
|
||||||
|
pa_sink_new_data_done(&data);
|
||||||
|
|
||||||
|
if (!u->sink) {
|
||||||
|
pa_log("Failed to create sink object.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
u->sink->parent.process_msg = pa_sink_process_msg;
|
||||||
|
u->sink->set_state_in_main_thread = state_func;
|
||||||
|
u->sink->reconfigure = reconfigure_func;
|
||||||
|
u->sink->request_rewind = process_rewind;
|
||||||
|
u->sink->userdata = u;
|
||||||
|
|
||||||
|
pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
|
||||||
|
pa_sink_set_rtpoll(u->sink, u->rtpoll);
|
||||||
|
|
||||||
|
pa_modargs_get_value_u32(ma, "latency", &u->latency);
|
||||||
|
if (u->latency) {
|
||||||
|
block_usec = PA_USEC_PER_MSEC * u->latency;
|
||||||
|
pa_sink_set_fixed_latency(u->sink, block_usec);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(u->thread = pa_thread_new("aaudio-sink", thread_func, u))) {
|
||||||
|
pa_log("Failed to create thread.");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_sink_put(u->sink);
|
||||||
|
|
||||||
|
pa_modargs_free(ma);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (ma)
|
||||||
|
pa_modargs_free(ma);
|
||||||
|
|
||||||
|
pa__done(m);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
pa_assert(m);
|
||||||
|
|
||||||
|
if (!(u = m->userdata))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (u->sink)
|
||||||
|
pa_sink_unlink(u->sink);
|
||||||
|
|
||||||
|
if (u->thread) {
|
||||||
|
pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
|
||||||
|
pa_thread_free(u->thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
pa_thread_mq_done(&u->thread_mq);
|
||||||
|
|
||||||
|
if (u->sink)
|
||||||
|
pa_sink_unref(u->sink);
|
||||||
|
|
||||||
|
if (u->rtpoll)
|
||||||
|
pa_rtpoll_free(u->rtpoll);
|
||||||
|
|
||||||
|
pa_xfree(u);
|
||||||
|
}
|
17
packages/libpulseaudio/sles.patch
Normal file
17
packages/libpulseaudio/sles.patch
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
diff --git a/src/Makefile.am~ b/src/Makefile.am
|
||||||
|
index f4464d2..a2c201d 100644
|
||||||
|
--- a/src/Makefile.am~
|
||||||
|
+++ b/src/Makefile.am
|
||||||
|
@@ -1495,6 +1495,12 @@ bin_SCRIPTS += utils/qpaeq
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
+modlibexec_LTLIBRARIES += module-sles-sink.la
|
||||||
|
+module_sles_sink_la_SOURCES = modules/sles/module-sles-sink.c
|
||||||
|
+module_sles_sink_la_LDFLAGS = $(MODULE_LDFLAGS) -lOpenSLES
|
||||||
|
+module_sles_sink_la_LIBADD = $(MODULE_LIBADD)
|
||||||
|
+module_sles_sink_la_CFLAGS = $(AM_CFLAGS) -DPA_MODULE_NAME=module_sles_sink
|
||||||
|
+
|
||||||
|
# Simple protocol
|
||||||
|
|
||||||
|
module_simple_protocol_tcp_la_SOURCES = modules/module-protocol-stub.c
|
Loading…
Reference in New Issue
Block a user