summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Franzke <benjaminfranzke@googlemail.com>2014-01-24 13:37:22 +0100
committerBenjamin Franzke <benjaminfranzke@googlemail.com>2014-01-24 13:37:22 +0100
commite810950547b4c55abdec977a002db522ccab0ad1 (patch)
treec1c2dd56fe97042af37e187c8185b051b15a5012
parentc25bbd8b8cc9aeae31ee689518ebfc6487197102 (diff)
downloadcmumble-audio-2-opuswip.tar.gz
cmumble-audio-2-opuswip.tar.bz2
cmumble-audio-2-opuswip.zip
-rw-r--r--configure.ac2
-rw-r--r--src/audio.c22
-rw-r--r--src/cmumble.c11
-rw-r--r--src/cmumble.h1
-rw-r--r--src/util.c73
-rw-r--r--src/util.h5
6 files changed, 110 insertions, 4 deletions
diff --git a/configure.ac b/configure.ac
index b65d62e..7b82130 100644
--- a/configure.ac
+++ b/configure.ac
@@ -41,7 +41,7 @@ PKG_CHECK_MODULES(GIO, [gio-2.0])
PKG_CHECK_MODULES(GSTREAMER, [gstreamer-1.0 gstreamer-app-1.0 gstreamer-tag-1.0])
PKG_CHECK_MODULES(CELT, [celt])
-GST_ELEMENTS="appsrc appsink celtdec celtenc capsfilter
+GST_ELEMENTS="appsrc appsink celtdec celtenc opusdec opusenc capsfilter
audioconvert audioresample autoaudiosrc autoaudiosink"
for element in $GST_ELEMENTS
diff --git a/src/audio.c b/src/audio.c
index 37e746b..b1bba35 100644
--- a/src/audio.c
+++ b/src/audio.c
@@ -11,6 +11,7 @@
#define BUFFER_TIME (gst_util_uint64_scale_int(1, GST_SECOND, 100))
#define CELT_CAPS "audio/x-celt,channels=" G_STRINGIFY(CHANNELS) "," \
"rate=" G_STRINGIFY(SAMPLERATE) ",frame-size=" G_STRINGIFY(FRAMESIZE)
+#define OPUS_CAPS "audio/x-opus"
#define AUDIO_CAPS "audio/x-raw,format=S16LE,channels=" \
G_STRINGIFY(CHANNELS) ",rate=" G_STRINGIFY(SAMPLERATE)
@@ -243,7 +244,7 @@ pull_buffer(GstAppSink *sink, gpointer user_data)
GstSample *sample;
GstBuffer *buf;
GstClockTime *silence;
-
+ GstCaps *caps;
sample = gst_app_sink_pull_sample(cm->audio.sink);
if (sample == NULL)
@@ -264,6 +265,15 @@ pull_buffer(GstAppSink *sink, gpointer user_data)
return GST_FLOW_OK;
}
+ caps = gst_sample_get_caps(sample);
+ /* FIXME: Find a better method to match the caps */
+ char *caps_s = gst_caps_to_string(caps);
+ if (strcmp(caps_s, "audio/x-opus") == 0) {
+ pull_opus_buffer(sink, cm);
+ } else if (strncmp(caps_s, "audio/x-celt", strlen("audio/x-celt")) == 0) {
+ pull_celt_buffer(sink, cm);
+ }
+
if (gst_buffer_get_size(buf) > 127) {
g_printerr("error: unexpected buffer size\n");
gst_sample_unref(sample);
@@ -386,8 +396,14 @@ setup_recording_gst_pipeline(struct cmumble *cm)
GstBus *bus;
char *desc = "autoaudiosrc name=src ! cutter name=cutter ! "
"audioresample ! audioconvert ! "AUDIO_CAPS" ! "
- "celtenc name=enc " /*perfect-timestamp=true hard-resync=true" */" ! "
- "appsink name=sink caps="CELT_CAPS;
+ "output-selector name=os ! "
+ "os.src0 "
+ "celtenc name=celt-enc " /*perfect-timestamp=true hard-resync=true" */" ! "
+ CELT_CAPS" ! "
+ "os.src1 "
+ "opusenc name=opus-enc ! " OPUS_CAPS " ! "
+ "funnel ! "
+ "appsink name=sink"
pipeline = gst_parse_launch(desc, &error);
if (error) {
diff --git a/src/cmumble.c b/src/cmumble.c
index 8267834..0350b97 100644
--- a/src/cmumble.c
+++ b/src/cmumble.c
@@ -145,6 +145,12 @@ recv_codec_version(mumble_codec_version_t *codec, struct cmumble *cm)
"Opus: %d\n",
codec->alpha, codec->beta, codec->prefer_alpha,
codec->opus);
+
+ if (codec->has_opus && !!codec->opus != !!cm->use_opus) {
+ cm->use_opus = !!codec->opus;
+ cmumble_audio_fini(cm);
+ cmumble_audio_init(cm);
+ }
}
static void
@@ -302,6 +308,10 @@ cmumble_protocol_init(struct cmumble *cm)
authenticate.password = "";
authenticate.n_celt_versions = 1;
authenticate.celt_versions = &cm->audio.celt_bitstream_version;
+#if 0
+ authenticate.opus = TRUE;
+ authenticate.has_opus = TRUE;
+#endif
cmumble_send_authenticate(cm, &authenticate);
source = g_timeout_source_new_seconds(5);
@@ -354,6 +364,7 @@ int main(int argc, char **argv)
cm.user_name = user ? user : g_get_user_name();
cm.users = NULL;
+ cm.use_opus = FALSE;
cm.verbose = verbose;
g_type_init();
diff --git a/src/cmumble.h b/src/cmumble.h
index 3997c8a..6dd16b3 100644
--- a/src/cmumble.h
+++ b/src/cmumble.h
@@ -37,6 +37,7 @@ struct cmumble {
struct cmumble_user *user;
gboolean verbose;
+ gboolean use_opus;
};
struct cmumble_user {
diff --git a/src/util.c b/src/util.c
index 1f6fd41..186251e 100644
--- a/src/util.c
+++ b/src/util.c
@@ -4,6 +4,8 @@
#include <stdlib.h>
#include <glib.h>
+#include <gst/base/gstbytewriter.h>
+
gpointer
cmumble_find_by_id(GList *list, gsize member_offset, guint id)
{
@@ -62,3 +64,74 @@ out:
fclose(f);
return os;
}
+
+/* This code is taken from gst-plugins-bad/ext/opus/gstopusheader.c */
+GstBuffer *
+_gst_opus_enc_create_id_buffer(gint nchannels, gint n_stereo_streams,
+ gint sample_rate, guint8 channel_mapping_family,
+ const guint8 *channel_mapping)
+{
+ GstBuffer *buffer;
+ GstByteWriter bw;
+ gboolean hdl = TRUE;
+
+ g_return_val_if_fail (nchannels > 0 && nchannels < 256, NULL);
+ g_return_val_if_fail (n_stereo_streams >= 0, NULL);
+ g_return_val_if_fail (n_stereo_streams <= nchannels - n_stereo_streams, NULL);
+
+ gst_byte_writer_init (&bw);
+
+ /* See http://wiki.xiph.org/OggOpus */
+ hdl &= gst_byte_writer_put_data (&bw, (const guint8 *) "OpusHead", 8);
+ hdl &= gst_byte_writer_put_uint8 (&bw, 0x01); /* version number */
+ hdl &= gst_byte_writer_put_uint8 (&bw, nchannels);
+ hdl &= gst_byte_writer_put_uint16_le (&bw, 0); /* pre-skip */
+ hdl &= gst_byte_writer_put_uint32_le (&bw, sample_rate);
+ hdl &= gst_byte_writer_put_uint16_le (&bw, 0); /* output gain */
+ hdl &= gst_byte_writer_put_uint8 (&bw, channel_mapping_family);
+ if (channel_mapping_family > 0) {
+ hdl &= gst_byte_writer_put_uint8 (&bw, nchannels - n_stereo_streams);
+ hdl &= gst_byte_writer_put_uint8 (&bw, n_stereo_streams);
+ hdl &= gst_byte_writer_put_data (&bw, channel_mapping, nchannels);
+ }
+
+ if (!hdl)
+ GST_WARNING ("Error creating header");
+
+ buffer = gst_byte_writer_reset_and_get_buffer (&bw);
+
+ GST_BUFFER_OFFSET (buffer) = 0;
+ GST_BUFFER_OFFSET_END (buffer) = 0;
+
+ return buffer;
+}
+
+static int
+create_gst_buffer_array (GValue *array, GstBuffer * buf, ...)
+{
+ va_list va;
+ GValue value = { 0 };
+
+ g_value_init (array, GST_TYPE_ARRAY);
+
+ va_start (va, buf);
+ /* put buffers in a fixed list */
+ while (buf) {
+ g_assert (gst_buffer_is_writable (buf));
+
+ /* mark buffer */
+ GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
+
+ g_value_init (&value, GST_TYPE_BUFFER);
+ buf = gst_buffer_copy (buf);
+ GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_HEADER);
+ gst_value_set_buffer (&value, buf);
+ gst_buffer_unref (buf);
+ gst_value_array_append_value (&array, &value);
+ g_value_unset (&value);
+
+ buf = va_arg (va, GstBuffer *);
+ }
+
+ return 0;
+
diff --git a/src/util.h b/src/util.h
index e2d58c6..afbf555 100644
--- a/src/util.h
+++ b/src/util.h
@@ -26,4 +26,9 @@ find_channel(struct cmumble *cm, guint channel_id)
channel_id);
}
+GstBuffer *
+_gst_opus_enc_create_id_buffer(gint nchannels, gint n_stereo_streams,
+ gint sample_rate, guint8 channel_mapping_family,
+ const guint8 * channel_mapping);
+
#endif /* _UTIL_H_ */