summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac10
-rw-r--r--src/Makefile.am4
-rw-r--r--src/audio.c113
-rw-r--r--src/audio.h10
-rw-r--r--src/cmumble.h3
-rw-r--r--src/io.c3
6 files changed, 124 insertions, 19 deletions
diff --git a/configure.ac b/configure.ac
index 864792c..4bc248d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -48,15 +48,7 @@ if test "x$have_celt" = xno; then
AC_DEFINE([HAVE_CELT071], [1], [Defined if we're using celt071])
fi
-
-GST_ELEMENTS="appsrc appsink celtdec celtenc capsfilter
- audioconvert audioresample autoaudiosrc autoaudiosink"
-
-for element in $GST_ELEMENTS
-do
- AM_GST_ELEMENT_CHECK([$element], [],
- AC_MSG_ERROR([gstreamer element $element not found]))
-done
+PKG_CHECK_MODULES(SPEEX, [speex speexdsp])
if test "x$GCC" = "xyes"; then
GCC_CFLAGS="-Wall -g -Wstrict-prototypes -Wmissing-prototypes -fvisibility=hidden"
diff --git a/src/Makefile.am b/src/Makefile.am
index 18979d0..948c7bf 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -9,9 +9,9 @@ cmumble_SOURCES = cmumble.c message.c varint.c io.c \
nodist_cmumble_SOURCES = mumble.pb-c.c
cmumble_LDADD = $(PROTOBUF_LIBS) $(GLIB_LIBS) $(GIO_LIBS) \
- $(GSTREAMER_LIBS) $(CELT_LIBS)
+ $(GSTREAMER_LIBS) $(CELT_LIBS) $(SPEEX_LIBS)
AM_CPPFLAGS = $(PROTOBUF_CFLAGS) $(GLIB_CFLAGS) $(GIO_CFLAGS) \
- $(GSTREAMER_CFLAGS) $(CELT_CFLAGS)
+ $(GSTREAMER_CFLAGS) $(CELT_CFLAGS) $(SPEEX_LIBS)
AM_CFLAGS = $(GCC_CFLAGS)
diff --git a/src/audio.c b/src/audio.c
index cf18c78..0b2b17e 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -3,6 +3,8 @@
#include "cmumble.h"
#include <string.h>
+#include <speex/speex_jitter.h>
+
#define SAMPLERATE 48000
#define CHANNELS 1
@@ -85,6 +87,12 @@ new_buffer(GstAppSink *sink, gpointer user_data)
return GST_FLOW_OK;
}
+/* TODO pulseaudio with echo cancellation/webrtc audio processing?
+ *
+ * https://www.freedesktop.org/software/pulseaudio/webrtc-audio-processing/
+ *
+ */
+
static int
setup_recording_gst_pipeline(struct cmumble *cm)
{
@@ -163,10 +171,114 @@ out:
g_object_unref(G_OBJECT(elm));
}
+
+/* This is called whenever the context status changes */
+static void context_state_callback(pa_context *c, void *userdata) {
+ struct cmumble_user *user = userdata;
+ assert(c);
+
+ switch (pa_context_get_state(c)) {
+ case PA_CONTEXT_CONNECTING:
+ case PA_CONTEXT_AUTHORIZING:
+ case PA_CONTEXT_SETTING_NAME:
+ break;
+
+ case PA_CONTEXT_READY: {
+ int r;
+ pa_stream *stream = NULL;
+
+ static const pa_sample_spec ss = {
+ .format = PA_SAMPLE_S16LE,
+ .rate = SAMPLERATE,
+ .channels = CHANNELS
+ };
+
+
+ gchar *name;
+ stream_name = g_strdup_printf("cmumble [%s]", user->name);
+ /* TODO: use pa_stream_new_with_proplist and set filter.want=echo-cancel */
+ if (!(stream = pa_stream_new(c, stream_name, &ss, NULL))) {
+ fprintf(stderr, "pa_stream_new() failed: %s\n", pa_strerror(pa_context_errno(c)));
+ g_free(name);
+ goto fail;
+ }
+ g_free(stream_name);
+ user->stream = stream;
+
+ pa_stream_set_state_callback(stream, stream_state_callback, NULL);
+ pa_stream_set_write_callback(stream, stream_write_callback, NULL);
+ pa_stream_set_read_callback(stream, stream_read_callback, NULL);
+ pa_stream_set_suspended_callback(stream, stream_suspended_callback, NULL);
+ pa_stream_set_moved_callback(stream, stream_moved_callback, NULL);
+ pa_stream_set_underflow_callback(stream, stream_underflow_callback, NULL);
+ pa_stream_set_overflow_callback(stream, stream_overflow_callback, NULL);
+ pa_stream_set_started_callback(stream, stream_started_callback, NULL);
+ pa_stream_set_event_callback(stream, stream_event_callback, NULL);
+ pa_stream_set_buffer_attr_callback(stream, stream_buffer_attr_callback, NULL);
+
+ if ((r = pa_stream_connect_playback(stream, NULL, NULL, 0, NULL, NULL)) < 0) {
+ g_printerr("pa_stream_connect_playback() failed: %s\n", pa_strerror(pa_context_errno(c)));
+ goto fail;
+ }
+
+ break;
+ }
+
+ case PA_CONTEXT_TERMINATED:
+ //quit(0);
+ //TODO: destroy user pipeline
+ break;
+
+ case PA_CONTEXT_FAILED:
+ default:
+ fprintf(stderr, _("Connection failure: %s\n"), pa_strerror(pa_context_errno(c)));
+ goto fail;
+ }
+
+ return;
+
+fail:
+ quit(1);
+
+}
+
int
cmumble_audio_create_playback_pipeline(struct cmumble *cm,
struct cmumble_user *user)
{
+ pa_mainloop_api *mainloop_api = NULL;
+ pa_glib_mainloop *m = NULL;
+ int r;
+
+ if (!(m = pa_glib_mainloop_new(NULL))) {
+ g_printerr("pa_glib_mainloop_new failed\n");
+ return -1;
+ }
+ cm->mainloop_api = pa_glib_mainloop_get_api(m);
+
+ if (!(user->context = pa_context_new(mainloop_api, "cmumble"))) {
+ return -1;
+ /*
+ interface_set_status(&ctx.interface,
+ "pa_context_new failed: %s\n",
+ pa_strerror(pa_context_errno(ctx.context)));
+ */
+ }
+
+ // define callback for connection init
+ pa_context_set_state_callback(user->context,
+ context_state_callback, &user);
+ if (pa_context_connect(user->context, NULL,
+ PA_CONTEXT_NOAUTOSPAWN, NULL)) {
+ return -1;
+ /*
+ interface_set_status(&ctx.interface,
+ "pa_context_connect failed: %s\n",
+ pa_strerror(pa_context_errno(ctx.context)));
+ */
+ }
+
+
GstElement *pipeline, *sink_bin;
GError *error = NULL;
char *desc = "appsrc name=src ! celtdec ! audioconvert ! autoaudiosink name=sink";
@@ -211,7 +323,6 @@ setup_playback_gst_pipeline(struct cmumble *cm)
{
cm->audio.celt_mode = celt_mode_create(SAMPLERATE,
SAMPLERATE / 100, NULL);
-
#ifdef HAVE_CELT_071
celt_header_init(&cm->audio.celt_header, cm->audio.celt_mode, CHANNELS);
#else
diff --git a/src/audio.h b/src/audio.h
index 0f7aaa2..2671647 100644
--- a/src/audio.h
+++ b/src/audio.h
@@ -3,10 +3,8 @@
#include <glib.h>
-#include <gst/gst.h>
-#include <gst/app/gstappsrc.h>
-#include <gst/app/gstappsink.h>
-#include <gst/app/gstappbuffer.h>
+#include <pulse/pulseaudio.h>
+#include <pulse/glib-mainloop.h>
#ifdef HAVE_CELT071
#include <celt071/celt.h>
@@ -17,8 +15,8 @@
#endif
struct cmumble_audio {
- GstElement *record_pipeline;
- GstAppSink *sink;
+ //GstElement *record_pipeline;
+ //GstAppSink *sink;
guint8 celt_header_packet[sizeof(CELTHeader)];
CELTHeader celt_header;
diff --git a/src/cmumble.h b/src/cmumble.h
index b796d50..9036bdc 100644
--- a/src/cmumble.h
+++ b/src/cmumble.h
@@ -63,7 +63,8 @@ enum udp_message_type {
udp_voice_celt_alpha,
udp_ping,
udp_voice_speex,
- udp_voice_celt_beta
+ udp_voice_celt_beta,
+ udp_voice_opus
};
enum udp_message_target {
diff --git a/src/io.c b/src/io.c
index d722f16..fc41893 100644
--- a/src/io.c
+++ b/src/io.c
@@ -201,6 +201,9 @@ cmumble_io_init(struct cmumble *cm)
return -1;
}
+ /* TODO: Maybe add comments why tcsetattr is needed?
+ (as in readline/examples/excallback.c)
+ Rename io.term to io.term_backup? */
cm->io.term = term;
term.c_lflag &= ~ICANON;
term.c_cc[VTIME] = 1;