diff options
Diffstat (limited to 'src/cmumble.c')
-rw-r--r-- | src/cmumble.c | 193 |
1 files changed, 5 insertions, 188 deletions
diff --git a/src/cmumble.c b/src/cmumble.c index 3a40e21..3d060ce 100644 --- a/src/cmumble.c +++ b/src/cmumble.c @@ -23,55 +23,6 @@ find_user(struct context *ctx, uint32_t session) } static void -appsrc_push(GstAppSrc *src, const void *mem, size_t size) -{ - GstBuffer *gstbuf; - - gstbuf = gst_app_buffer_new(g_memdup(mem, size), size, g_free, NULL); - gst_app_src_push_buffer(src, gstbuf); -} - -static GstFlowReturn -pull_buffer(GstAppSink *sink, gpointer user_data) -{ - struct context *ctx = user_data; - GstBuffer *buf; - uint8_t data[1024]; - uint32_t write = 0, pos = 0; - MumbleProto__UDPTunnel tunnel; - static int seq = 0; - - buf = gst_app_sink_pull_buffer(ctx->sink); - - if (++seq <= 2) { - gst_buffer_unref(buf); - return GST_FLOW_OK; - } - if (GST_BUFFER_SIZE(buf) > 127) { - g_printerr("GOT TOO BIG BUFFER\n"); - return GST_FLOW_ERROR; - } - - data[pos++] = (udp_voice_celt_alpha) | (0 << 4); - - encode_varint(&data[pos], &write, ++ctx->sequence, 1024-pos); - pos += write; - - data[pos++] = 0x00 /*: 0x80 */ | (GST_BUFFER_SIZE(buf) & 0x7F); - memcpy(&data[pos], GST_BUFFER_DATA(buf), GST_BUFFER_SIZE(buf)); - pos += GST_BUFFER_SIZE(buf); - - gst_buffer_unref(buf); - - mumble_proto__udptunnel__init(&tunnel); - tunnel.packet.data = data; - tunnel.packet.len = pos; - cmumble_send_msg(ctx, &tunnel.base); - - return GST_FLOW_OK; -} - -static void recv_udp_tunnel(MumbleProto__UDPTunnel *tunnel, struct context *ctx) { int64_t session, sequence; @@ -100,7 +51,7 @@ recv_udp_tunnel(MumbleProto__UDPTunnel *tunnel, struct context *ctx) if (frame_len == 0 || frame_len > len-pos) break; - appsrc_push(user->src, &data[pos], frame_len); + cmumble_audio_push(ctx, user, &data[pos], frame_len); pos += frame_len; sequence++; @@ -177,9 +128,6 @@ recv_user_remove(MumbleProto__UserRemove *remove, struct context *ctx) } } -static int -user_create_playback_pipeline(struct context *ctx, struct user *user); - static void recv_user_state(MumbleProto__UserState *state, struct context *ctx) { @@ -200,7 +148,8 @@ recv_user_state(MumbleProto__UserState *state, struct context *ctx) user->name = g_strdup(state->name); user->user_id = state->user_id; - user_create_playback_pipeline(ctx, user); + + cmumble_audio_create_playback_pipeline(ctx, user); g_print("receive user: %s\n", user->name); ctx->users = g_list_prepend(ctx->users, user); } @@ -239,135 +188,6 @@ static const struct { .SuggestConfig = NULL, }; -static void -set_pulse_states(gpointer data, gpointer user_data) -{ - GstElement *elm = data; - struct user *user = user_data; - GstStructure *props; - gchar *name; - - if (g_strcmp0(G_OBJECT_TYPE_NAME(elm), "GstPulseSink") != 0 || - g_object_class_find_property(G_OBJECT_GET_CLASS(elm), - "stream-properties") == NULL) - goto out; - - /* configure pulseaudio to use: - * load-module module-device-manager "do_routing=1" - * or new users may join to default output which is not headset? - * Also consider setting device.intended_roles = "phone" for your - * wanted default output (if you dont have a usb headset dev). */ - - name = g_strdup_printf("cmumble [%s]", user->name); - - props = gst_structure_new("props", - "application.name", G_TYPE_STRING, name, - "media.role", G_TYPE_STRING, "phone", - NULL); - - g_object_set(elm, "stream-properties", props, NULL); - gst_structure_free(props); - g_free(name); - -out: - g_object_unref(G_OBJECT(elm)); -} - -static int -user_create_playback_pipeline(struct context *ctx, struct user *user) -{ - GstElement *pipeline, *sink_bin; - GError *error = NULL; - char *desc = "appsrc name=src ! celtdec ! audioconvert ! autoaudiosink name=sink"; - - pipeline = gst_parse_launch(desc, &error); - if (error) { - g_printerr("Failed to create pipeline: %s\n", error->message); - return -1; - } - - user->pipeline = pipeline; - user->src = GST_APP_SRC(gst_bin_get_by_name(GST_BIN(pipeline), "src")); - - /* Important! */ - gst_base_src_set_live(GST_BASE_SRC(user->src), TRUE); - gst_base_src_set_do_timestamp(GST_BASE_SRC(user->src), TRUE); - gst_base_src_set_format(GST_BASE_SRC(user->src), GST_FORMAT_TIME); - - gst_app_src_set_stream_type(user->src, GST_APP_STREAM_TYPE_STREAM); - - gst_element_set_state(pipeline, GST_STATE_PLAYING); - - sink_bin = gst_bin_get_by_name(GST_BIN(pipeline), "sink"); - GstIterator *iter = gst_bin_iterate_sinks(GST_BIN(sink_bin)); - gst_iterator_foreach(iter, set_pulse_states, user); - gst_iterator_free(iter); - - /* Setup Celt Decoder */ - appsrc_push(user->src, ctx->celt_header_packet, sizeof(CELTHeader)); - /* fake vorbiscomment buffer */ - appsrc_push(user->src, NULL, 0); - - return 0; -} - -static int -setup_playback_gst_pipeline(struct context *ctx) -{ -#define SAMPLERATE 48000 -#define CHANNELS 1 - ctx->celt_mode = celt_mode_create(SAMPLERATE, - SAMPLERATE / 100, NULL); - celt_header_init(&ctx->celt_header, ctx->celt_mode, CHANNELS); - celt_header_to_packet(&ctx->celt_header, - ctx->celt_header_packet, sizeof(CELTHeader)); - - return 0; -} - -static int -setup_recording_gst_pipeline(struct context *ctx) -{ - GstElement *pipeline, *cutter, *sink; - GError *error = NULL; - GstCaps *caps; - - char *desc = "autoaudiosrc ! cutter name=cutter ! audioresample ! audioconvert ! " - "audio/x-raw-int,channels=1,depth=16,rate=48000,signed=TRUE,width=16 ! " - "celtenc ! appsink name=sink"; - - pipeline = gst_parse_launch(desc, &error); - if (error) { - g_printerr("Failed to create pipeline: %s\n", error->message); - return -1; - } - sink = gst_bin_get_by_name(GST_BIN(pipeline), "sink"); - ctx->sink = GST_APP_SINK(sink); - ctx->record_pipeline = pipeline; - - cutter = gst_bin_get_by_name(GST_BIN(pipeline), "cutter"); - g_object_set(G_OBJECT(cutter), - "threshold_dB", -45.0, "leaky", TRUE, NULL); - - gst_app_sink_set_emit_signals(ctx->sink, TRUE); - gst_app_sink_set_drop(ctx->sink, FALSE);; - g_signal_connect(sink, "new-buffer", G_CALLBACK(pull_buffer), ctx); - - caps = gst_caps_new_simple("audio/x-celt", - "rate", G_TYPE_INT, SAMPLERATE, - "channels", G_TYPE_INT, 1, - "frame-size", G_TYPE_INT, SAMPLERATE/100, - NULL); - gst_app_sink_set_caps(ctx->sink, caps); - gst_caps_unref(caps); - - gst_element_set_state(pipeline, GST_STATE_PLAYING); - - ctx->sequence = 0; - - return 0; -} - int main(int argc, char **argv) { char *host = "localhost"; @@ -411,12 +231,8 @@ int main(int argc, char **argv) gst_init(&argc, &argv); - if (setup_playback_gst_pipeline(&ctx) < 0) + if (cmumble_audio_init(&ctx) < 0) return 1; - - if (setup_recording_gst_pipeline(&ctx) < 0) - return 1; - cmumble_io_init(&ctx); g_main_loop_run(ctx.loop); @@ -424,6 +240,7 @@ int main(int argc, char **argv) g_main_loop_unref(ctx.loop); cmumble_io_fini(&ctx); + cmumble_audio_init(&ctx); cmumble_connection_fini(&ctx); return 0; |