[pulseaudio-commits] 3 commits - configure.ac src/Makefile.am src/modules src/pulsecore
Arun Raghavan
arun at kemper.freedesktop.org
Mon Oct 17 04:33:52 PDT 2011
configure.ac | 19 ++
src/Makefile.am | 8
src/modules/echo-cancel/echo-cancel.h | 21 ++
src/modules/echo-cancel/module-echo-cancel.c | 39 ++--
src/modules/echo-cancel/webrtc.cc | 234 +++++++++++++++++++++++++++
src/pulsecore/macro.h | 3
6 files changed, 308 insertions(+), 16 deletions(-)
New commits:
commit 6df6eb959edbce481329bb9e45bbfa32fc8257f1
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date: Mon Sep 19 13:41:13 2011 +0530
echo-cancel: Add the WebRTC echo canceller
This adds the WebRTC echo canceller as another module-echo-cancel
backend. We're exposing both the full echo canceller as well as the
mobile echo control version as modargs.
Pending items:
1. The mobile canceller doesn't seem to work at the moment.
2. We still need to add bits to hook in drift compensation (to support
sink and source from different devices).
The most controversial part of this patch would probably be the
mandatory build-time dependency on a C++ compiler. If the optional
--enable-webrtc-aec is set, then there's also a dependency on libstdc++.
diff --git a/configure.ac b/configure.ac
index 0bf40a8..feeae75 100644
--- a/configure.ac
+++ b/configure.ac
@@ -78,6 +78,9 @@ AC_PROG_MKDIR_P
AC_PROG_CC
AC_PROG_CC_C99
AM_PROG_CC_C_O
+# Only required if you want the WebRTC canceller -- no runtime dep on
+# libstdc++ otherwise
+AC_PROG_CXX
AC_PROG_GCC_TRADITIONAL
AC_USE_SYSTEM_EXTENSIONS
@@ -1139,6 +1142,20 @@ if test "x$os_is_darwin" = "x1" ; then
fi
fi
+AC_ARG_ENABLE([webrtc-aec],
+ AS_HELP_STRING([--enable-webrtc-aec], [Enable the optional WebRTC-based echo canceller]))
+
+AS_IF([test "x$enable_webrtc_aec" != "xno"],
+ [PKG_CHECK_MODULES(WEBRTC, [ webrtc-audio-processing ], [HAVE_WEBRTC=1], [HAVE_WEBRTC=0])],
+ [HAVE_WEBRTC=0])
+
+AS_IF([test "x$enable_webrtc_aec" = "xyes" && test "x$HAVE_WEBRTC" = "x0"],
+ [AC_MSG_ERROR([*** webrtc-audio-processing library not found])])
+
+AC_SUBST(WEBRTC_CFLAGS)
+AC_SUBST(WEBRTC_LIBS)
+AM_CONDITIONAL([HAVE_WEBRTC], [test "x$HAVE_WEBRTC" = "x1"])
+
###################################
# Output #
@@ -1275,6 +1292,7 @@ AS_IF([test "x$HAVE_IPV6" = "x1"], ENABLE_IPV6=yes, ENABLE_IPV6=no)
AS_IF([test "x$HAVE_OPENSSL" = "x1"], ENABLE_OPENSSL=yes, ENABLE_OPENSSL=no)
AS_IF([test "x$HAVE_FFTW" = "x1"], ENABLE_FFTW=yes, ENABLE_FFTW=no)
AS_IF([test "x$HAVE_ORC" = "xyes"], ENABLE_ORC=yes, ENABLE_ORC=no)
+AS_IF([test "x$HAVE_WEBRTC" = "x1"], ENABLE_WEBRTC=yes, ENABLE_WEBRTC=no)
AS_IF([test "x$HAVE_TDB" = "x1"], ENABLE_TDB=yes, ENABLE_TDB=no)
AS_IF([test "x$HAVE_GDBM" = "x1"], ENABLE_GDBM=yes, ENABLE_GDBM=no)
AS_IF([test "x$HAVE_SIMPLEDB" = "x1"], ENABLE_SIMPLEDB=yes, ENABLE_SIMPLEDB=no)
@@ -1321,6 +1339,7 @@ echo "
Enable OpenSSL (for Airtunes): ${ENABLE_OPENSSL}
Enable fftw: ${ENABLE_FFTW}
Enable orc: ${ENABLE_ORC}
+ Enable WebRTC echo canceller: ${ENABLE_WEBRTC}
Database
tdb: ${ENABLE_TDB}
gdbm: ${ENABLE_GDBM}
diff --git a/src/Makefile.am b/src/Makefile.am
index d3fe1c3..5f8a9bb 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -48,6 +48,7 @@ AM_CFLAGS = \
$(PTHREAD_CFLAGS) \
-DPA_ALSA_PATHS_DIR=\"$(alsapathsdir)\" \
-DPA_ALSA_PROFILE_SETS_DIR=\"$(alsaprofilesetsdir)\"
+AM_CXXFLAGS = $(AM_CFLAGS)
SERVER_CFLAGS = -D__INCLUDED_FROM_PULSE_AUDIO
AM_LIBADD = $(PTHREAD_LIBS) $(INTLLIBS)
@@ -523,6 +524,7 @@ echo_cancel_test_SOURCES = $(module_echo_cancel_la_SOURCES)
nodist_echo_cancel_test_SOURCES = $(nodist_module_echo_cancel_la_SOURCES)
echo_cancel_test_LDADD = $(module_echo_cancel_la_LIBADD)
echo_cancel_test_CFLAGS = $(module_echo_cancel_la_CFLAGS) -DECHO_CANCEL_TEST=1
+echo_cancel_test_CXXFLAGS = $(module_echo_cancel_la_CXXFLAGS) -DECHO_CANCEL_TEST=1
echo_cancel_test_LDFLAGS = $(AM_LDFLAGS) $(BINLDFLAGS)
###################################
@@ -1753,6 +1755,12 @@ nodist_module_echo_cancel_la_SOURCES = \
module_echo_cancel_la_LIBADD += $(ORC_LIBS)
module_echo_cancel_la_CFLAGS += $(ORC_CFLAGS) -I$(top_builddir)/src/modules/echo-cancel
endif
+if HAVE_WEBRTC
+module_echo_cancel_la_SOURCES += modules/echo-cancel/webrtc.cc
+module_echo_cancel_la_CFLAGS += -DHAVE_WEBRTC=1
+module_echo_cancel_la_CXXFLAGS = $(AM_CXXFLAGS) $(SERVER_CFLAGS) $(WEBRTC_CFLAGS) -DHAVE_WEBRTC=1
+module_echo_cancel_la_LIBADD += $(WEBRTC_LIBS)
+endif
# RTP modules
module_rtp_send_la_SOURCES = modules/rtp/module-rtp-send.c
diff --git a/src/modules/echo-cancel/echo-cancel.h b/src/modules/echo-cancel/echo-cancel.h
index 9f67980..19e1350 100644
--- a/src/modules/echo-cancel/echo-cancel.h
+++ b/src/modules/echo-cancel/echo-cancel.h
@@ -49,6 +49,15 @@ struct pa_echo_canceller_params {
uint32_t blocksize;
AEC *aec;
} adrian;
+#ifdef HAVE_WEBRTC
+ struct {
+ /* This is a void* so that we don't have to convert this whole file
+ * to C++ linkage. apm is a pointer to an AudioProcessing object */
+ void *apm;
+ uint32_t blocksize;
+ pa_sample_spec sample_spec;
+ } webrtc;
+#endif
/* each canceller-specific structure goes here */
} priv;
};
@@ -86,4 +95,16 @@ pa_bool_t pa_adrian_ec_init(pa_core *c, pa_echo_canceller *ec,
void pa_adrian_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out);
void pa_adrian_ec_done(pa_echo_canceller *ec);
+#ifdef HAVE_WEBRTC
+/* WebRTC canceller functions */
+PA_C_DECL_BEGIN
+pa_bool_t pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
+ pa_sample_spec *source_ss, pa_channel_map *source_map,
+ pa_sample_spec *sink_ss, pa_channel_map *sink_map,
+ uint32_t *blocksize, const char *args);
+void pa_webrtc_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out);
+void pa_webrtc_ec_done(pa_echo_canceller *ec);
+PA_C_DECL_END
+#endif
+
#endif /* fooechocancelhfoo */
diff --git a/src/modules/echo-cancel/module-echo-cancel.c b/src/modules/echo-cancel/module-echo-cancel.c
index 20541f4..7360b27 100644
--- a/src/modules/echo-cancel/module-echo-cancel.c
+++ b/src/modules/echo-cancel/module-echo-cancel.c
@@ -83,6 +83,9 @@ typedef enum {
PA_ECHO_CANCELLER_INVALID = -1,
PA_ECHO_CANCELLER_SPEEX = 0,
PA_ECHO_CANCELLER_ADRIAN,
+#ifdef HAVE_WEBRTC
+ PA_ECHO_CANCELLER_WEBRTC,
+#endif
} pa_echo_canceller_method_t;
#define DEFAULT_ECHO_CANCELLER "speex"
@@ -100,6 +103,14 @@ static const pa_echo_canceller ec_table[] = {
.run = pa_adrian_ec_run,
.done = pa_adrian_ec_done,
},
+#ifdef HAVE_WEBRTC
+ {
+ /* WebRTC's audio processing engine */
+ .init = pa_webrtc_ec_init,
+ .run = pa_webrtc_ec_run,
+ .done = pa_webrtc_ec_done,
+ },
+#endif
};
#define DEFAULT_RATE 32000
@@ -1340,6 +1351,10 @@ static pa_echo_canceller_method_t get_ec_method_from_string(const char *method)
return PA_ECHO_CANCELLER_SPEEX;
else if (pa_streq(method, "adrian"))
return PA_ECHO_CANCELLER_ADRIAN;
+#ifdef HAVE_WEBRTC
+ else if (pa_streq(method, "webrtc"))
+ return PA_ECHO_CANCELLER_WEBRTC;
+#endif
else
return PA_ECHO_CANCELLER_INVALID;
}
diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
new file mode 100644
index 0000000..c53e963
--- /dev/null
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -0,0 +1,234 @@
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2011 Collabora Ltd.
+
+ Contributor: Arun Raghavan <arun.raghavan at collabora.co.uk>
+
+ 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ USA.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pulse/cdecl.h>
+
+PA_C_DECL_BEGIN
+#include <pulsecore/core-util.h>
+#include <pulsecore/modargs.h>
+
+#include <pulse/timeval.h>
+#include "echo-cancel.h"
+PA_C_DECL_END
+
+#include <audio_processing.h>
+#include <module_common_types.h>
+
+#define BLOCK_SIZE_US 10000
+
+#define DEFAULT_HIGH_PASS_FILTER TRUE
+#define DEFAULT_NOISE_SUPPRESSION TRUE
+#define DEFAULT_ANALOG_GAIN_CONTROL FALSE
+#define DEFAULT_DIGITAL_GAIN_CONTROL TRUE
+#define DEFAULT_MOBILE FALSE
+#define DEFAULT_ROUTING_MODE "speakerphone"
+#define DEFAULT_COMFORT_NOISE TRUE
+
+static const char* const valid_modargs[] = {
+ "high_pass_filter",
+ "noise_suppression",
+ "analog_gain_control",
+ "digital_gain_control",
+ "mobile",
+ "routing_mode",
+ "comfort_noise",
+ NULL
+};
+
+static int routing_mode_from_string(const char *rmode) {
+ if (pa_streq(rmode, "quiet-earpiece-or-headset"))
+ return webrtc::EchoControlMobile::kQuietEarpieceOrHeadset;
+ else if (pa_streq(rmode, "earpiece"))
+ return webrtc::EchoControlMobile::kEarpiece;
+ else if (pa_streq(rmode, "loud-earpiece"))
+ return webrtc::EchoControlMobile::kLoudEarpiece;
+ else if (pa_streq(rmode, "speakerphone"))
+ return webrtc::EchoControlMobile::kSpeakerphone;
+ else if (pa_streq(rmode, "loud-speakerphone"))
+ return webrtc::EchoControlMobile::kLoudSpeakerphone;
+ else
+ return -1;
+}
+
+pa_bool_t pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
+ pa_sample_spec *source_ss, pa_channel_map *source_map,
+ pa_sample_spec *sink_ss, pa_channel_map *sink_map,
+ uint32_t *blocksize, const char *args)
+{
+ webrtc::AudioProcessing *apm = NULL;
+ pa_bool_t hpf, ns, agc, dgc, mobile, cn;
+ int rm;
+ pa_modargs *ma;
+
+ if (!(ma = pa_modargs_new(args, valid_modargs))) {
+ pa_log("Failed to parse submodule arguments.");
+ goto fail;
+ }
+
+
+ hpf = DEFAULT_HIGH_PASS_FILTER;
+ if (pa_modargs_get_value_boolean(ma, "high_pass_filter", &hpf) < 0) {
+ pa_log("Failed to parse high_pass_filter value");
+ goto fail;
+ }
+
+ ns = DEFAULT_NOISE_SUPPRESSION;
+ if (pa_modargs_get_value_boolean(ma, "noise_suppression", &ns) < 0) {
+ pa_log("Failed to parse noise_suppression value");
+ goto fail;
+ }
+
+ agc = DEFAULT_ANALOG_GAIN_CONTROL;
+ if (pa_modargs_get_value_boolean(ma, "analog_gain_control", &agc) < 0) {
+ pa_log("Failed to parse analog_gain_control value");
+ goto fail;
+ }
+
+ dgc = DEFAULT_DIGITAL_GAIN_CONTROL;
+ if (pa_modargs_get_value_boolean(ma, "analog_gain_control", &dgc) < 0) {
+ pa_log("Failed to parse digital_gain_control value");
+ goto fail;
+ }
+
+ if (agc && dgc) {
+ pa_log("You must pick only one between analog and digital gain control");
+ goto fail;
+ }
+
+ mobile = DEFAULT_MOBILE;
+ if (pa_modargs_get_value_boolean(ma, "mobile", &mobile) < 0) {
+ pa_log("Failed to parse mobile value");
+ goto fail;
+ }
+
+ if (mobile) {
+ if ((rm = routing_mode_from_string(pa_modargs_get_value(ma, "routing_mode", DEFAULT_ROUTING_MODE))) < 0) {
+ pa_log("Failed to parse routing_mode value");
+ goto fail;
+ }
+
+ cn = DEFAULT_COMFORT_NOISE;
+ if (pa_modargs_get_value_boolean(ma, "comfort_noise", &cn) < 0) {
+ pa_log("Failed to parse cn value");
+ goto fail;
+ }
+ } else {
+ if (pa_modargs_get_value(ma, "comfort_noise", NULL) || pa_modargs_get_value(ma, "routing_mode", NULL)) {
+ pa_log("The routing_mode and comfort_noise options are only valid with mobile=true");
+ goto fail;
+ }
+ }
+
+ apm = webrtc::AudioProcessing::Create(0);
+
+ source_ss->format = PA_SAMPLE_S16NE;
+ *sink_ss = *source_ss;
+ /* FIXME: the implementation actually allows a different number of
+ * source/sink channels. Do we want to support that? */
+ *sink_map = *source_map;
+
+ apm->set_sample_rate_hz(source_ss->rate);
+
+ apm->set_num_channels(source_ss->channels, source_ss->channels);
+ apm->set_num_reverse_channels(sink_ss->channels);
+
+ if (hpf)
+ apm->high_pass_filter()->Enable(true);
+
+ if (!mobile) {
+ apm->echo_cancellation()->enable_drift_compensation(false);
+ apm->echo_cancellation()->Enable(true);
+ } else {
+ apm->echo_control_mobile()->set_routing_mode(static_cast<webrtc::EchoControlMobile::RoutingMode>(rm));
+ apm->echo_control_mobile()->enable_comfort_noise(cn);
+ apm->echo_control_mobile()->Enable(true);
+ }
+
+ if (ns) {
+ apm->noise_suppression()->set_level(webrtc::NoiseSuppression::kHigh);
+ apm->noise_suppression()->Enable(true);
+ }
+
+ if (agc || dgc) {
+ if (mobile && rm <= webrtc::EchoControlMobile::kEarpiece)
+ /* Maybe this should be a knob, but we've got a lot of knobs already */
+ apm->gain_control()->set_mode(webrtc::GainControl::kFixedDigital);
+ else if (dgc)
+ apm->gain_control()->set_mode(webrtc::GainControl::kAdaptiveDigital);
+ else {
+ /* FIXME: Hook up for analog AGC */
+ pa_log("Analog gain control isn't implemented yet -- using ditital gain control.");
+ apm->gain_control()->set_mode(webrtc::GainControl::kAdaptiveDigital);
+ }
+ }
+
+ apm->voice_detection()->Enable(true);
+
+ ec->params.priv.webrtc.apm = apm;
+ ec->params.priv.webrtc.sample_spec = *source_ss;
+ ec->params.priv.webrtc.blocksize = *blocksize = (uint64_t)pa_bytes_per_second(source_ss) * BLOCK_SIZE_US / PA_USEC_PER_SEC;
+
+ pa_modargs_free(ma);
+ return TRUE;
+
+fail:
+ if (ma)
+ pa_modargs_free(ma);
+ if (apm)
+ webrtc::AudioProcessing::Destroy(apm);
+
+ return FALSE;
+}
+
+void pa_webrtc_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out) {
+ webrtc::AudioProcessing *apm = (webrtc::AudioProcessing*)ec->params.priv.webrtc.apm;
+ webrtc::AudioFrame play_frame, out_frame;
+ const pa_sample_spec *ss = &ec->params.priv.webrtc.sample_spec;
+
+ play_frame._audioChannel = ss->channels;
+ play_frame._frequencyInHz = ss->rate;
+ play_frame._payloadDataLengthInSamples = ec->params.priv.webrtc.blocksize / pa_frame_size(ss);
+ memcpy(play_frame._payloadData, play, ec->params.priv.webrtc.blocksize);
+
+ out_frame._audioChannel = ss->channels;
+ out_frame._frequencyInHz = ss->rate;
+ out_frame._payloadDataLengthInSamples = ec->params.priv.webrtc.blocksize / pa_frame_size(ss);
+ memcpy(out_frame._payloadData, rec, ec->params.priv.webrtc.blocksize);
+
+ apm->AnalyzeReverseStream(&play_frame);
+ apm->set_stream_delay_ms(0);
+ apm->ProcessStream(&out_frame);
+
+ memcpy(out, out_frame._payloadData, ec->params.priv.webrtc.blocksize);
+}
+
+void pa_webrtc_ec_done(pa_echo_canceller *ec) {
+ if (ec->params.priv.webrtc.apm) {
+ webrtc::AudioProcessing::Destroy((webrtc::AudioProcessing*)ec->params.priv.webrtc.apm);
+ ec->params.priv.webrtc.apm = NULL;
+ }
+}
commit dbe8f2e595d63ce3286679059952c17d2eeb8225
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date: Mon Sep 19 13:38:03 2011 +0530
macro: typedef pa_bool_t to bool instead of _Bool
They're functionally equivalent, and the former lets the header be
included in C++ as well.
diff --git a/src/pulsecore/macro.h b/src/pulsecore/macro.h
index 7459e6f..c6d7d56 100644
--- a/src/pulsecore/macro.h
+++ b/src/pulsecore/macro.h
@@ -30,6 +30,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <stdbool.h>
#ifndef PACKAGE
#error "Please include config.h before including this file!"
@@ -178,7 +179,7 @@ static inline size_t PA_PAGE_ALIGN(size_t l) {
/* This type is not intended to be used in exported APIs! Use classic "int" there! */
#ifdef HAVE_STD_BOOL
-typedef _Bool pa_bool_t;
+typedef bool pa_bool_t;
#else
typedef int pa_bool_t;
#endif
commit e40bddc94609cf14b3509e9a4cba8981592d582c
Author: Arun Raghavan <arun.raghavan at collabora.co.uk>
Date: Mon Oct 17 15:55:51 2011 +0530
echo-cancel: Simplify checking if AEC is active
This removes the active_mask bits and just check source and sink states
directly.
diff --git a/src/modules/echo-cancel/module-echo-cancel.c b/src/modules/echo-cancel/module-echo-cancel.c
index a96ef37..20541f4 100644
--- a/src/modules/echo-cancel/module-echo-cancel.c
+++ b/src/modules/echo-cancel/module-echo-cancel.c
@@ -111,6 +111,10 @@ static const pa_echo_canceller ec_table[] = {
#define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
+/* Can only be used in main context */
+#define IS_ACTIVE(u) ((pa_source_get_state((u)->source) == PA_SOURCE_RUNNING) && \
+ (pa_sink_get_state((u)->sink) == PA_SINK_RUNNING))
+
/* This module creates a new (virtual) source and sink.
*
* The data sent to the new sink is kept in a memblockq before being
@@ -187,7 +191,6 @@ struct userdata {
pa_atomic_t request_resync;
- int active_mask;
pa_time_event *time_event;
pa_usec_t adjust_time;
int adjust_threshold;
@@ -278,7 +281,7 @@ static void time_callback(pa_mainloop_api *a, pa_time_event *e, const struct tim
pa_assert(u->time_event == e);
pa_assert_ctl_context();
- if (u->active_mask != 3)
+ if (!IS_ACTIVE(u))
return;
/* update our snapshots */
@@ -403,20 +406,17 @@ static int source_set_state_cb(pa_source *s, pa_source_state_t state) {
!PA_SOURCE_OUTPUT_IS_LINKED(pa_source_output_get_state(u->source_output)))
return 0;
- pa_log_debug("Source state %d %d", state, u->active_mask);
-
if (state == PA_SOURCE_RUNNING) {
/* restart timer when both sink and source are active */
- u->active_mask |= 1;
- if (u->active_mask == 3 && u->adjust_time)
+ if (IS_ACTIVE(u) && u->adjust_time)
pa_core_rttime_restart(u->core, u->time_event, pa_rtclock_now() + u->adjust_time);
pa_atomic_store(&u->request_resync, 1);
pa_source_output_cork(u->source_output, FALSE);
} else if (state == PA_SOURCE_SUSPENDED) {
- u->active_mask &= ~1;
pa_source_output_cork(u->source_output, TRUE);
}
+
return 0;
}
@@ -431,20 +431,17 @@ static int sink_set_state_cb(pa_sink *s, pa_sink_state_t state) {
!PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
return 0;
- pa_log_debug("Sink state %d %d", state, u->active_mask);
-
if (state == PA_SINK_RUNNING) {
/* restart timer when both sink and source are active */
- u->active_mask |= 2;
- if (u->active_mask == 3 && u->adjust_time)
+ if (IS_ACTIVE(u) && u->adjust_time)
pa_core_rttime_restart(u->core, u->time_event, pa_rtclock_now() + u->adjust_time);
pa_atomic_store(&u->request_resync, 1);
pa_sink_input_cork(u->sink_input, FALSE);
} else if (state == PA_SINK_SUSPENDED) {
- u->active_mask &= ~2;
pa_sink_input_cork(u->sink_input, TRUE);
}
+
return 0;
}
@@ -1676,9 +1673,6 @@ int pa__init(pa_module*m) {
goto fail;
}
- /* our source and sink are not suspended when we create them */
- u->active_mask = 3;
-
if (u->adjust_time > 0)
u->time_event = pa_core_rttime_new(m->core, pa_rtclock_now() + u->adjust_time, time_callback, u);
More information about the pulseaudio-commits
mailing list