messenger-gtk

Gtk+3 graphical user interfaces for GNUnet Messenger
Log | Files | Refs | Submodules | README | LICENSE

commit 1a1a706288ecf41c84877fffb0de000abacfe765
parent 749a1e990d4f0b54e58ed08d5a09a4e5b2e05994
Author: Jacki <jacki@thejackimonster.de>
Date:   Sat, 27 Jul 2024 01:40:34 +0200

Add dummy video recording pipeline

Signed-off-by: Jacki <jacki@thejackimonster.de>

Diffstat:
Msrc/discourse.c | 228+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Msrc/discourse.h | 36++++++++++++++++++++++++++----------
Msrc/ui/discourse.c | 55+++++++++++++++++++++----------------------------------
3 files changed, 206 insertions(+), 113 deletions(-)

diff --git a/src/discourse.c b/src/discourse.c @@ -31,6 +31,36 @@ #include <pthread.h> #include <stdlib.h> +const struct GNUNET_ShortHashCode* +get_voice_discourse_id() +{ + static enum GNUNET_GenericReturnValue init = GNUNET_NO; + static struct GNUNET_ShortHashCode id; + + if (GNUNET_YES != init) + { + memset(&id, 0, sizeof(id)); + init = GNUNET_YES; + } + + return &id; +} + +const struct GNUNET_ShortHashCode* +get_video_discourse_id() +{ + static enum GNUNET_GenericReturnValue init = GNUNET_NO; + static struct GNUNET_ShortHashCode id; + + if (GNUNET_YES != init) + { + memset(&id, 1, sizeof(id)); + init = GNUNET_YES; + } + + return &id; +} + static void error_cb(GstBus *bus, GstMessage *msg, @@ -51,19 +81,19 @@ _setup_gst_pipelines_of_subscription(MESSENGER_DiscourseSubscriptionInfo *info) { g_assert(info); - info->stream_source = gst_element_factory_make("appsrc", NULL); - info->converter = gst_element_factory_make("audioconvert", NULL); + info->audio_stream_source = gst_element_factory_make("appsrc", NULL); + info->audio_converter = gst_element_factory_make("audioconvert", NULL); gst_bin_add_many( - GST_BIN(info->discourse->mix_pipeline), - info->stream_source, - info->converter, + GST_BIN(info->discourse->audio_mix_pipeline), + info->audio_stream_source, + info->audio_converter, NULL ); gst_element_link_many( - info->stream_source, - info->converter, + info->audio_stream_source, + info->audio_converter, NULL ); @@ -78,7 +108,7 @@ _setup_gst_pipelines_of_subscription(MESSENGER_DiscourseSubscriptionInfo *info) ); g_object_set( - info->stream_source, + info->audio_stream_source, "format", GST_FORMAT_TIME, "caps", caps, "is-live", TRUE, @@ -88,21 +118,21 @@ _setup_gst_pipelines_of_subscription(MESSENGER_DiscourseSubscriptionInfo *info) gst_caps_unref(caps); } - info->mix_pad = gst_element_request_pad_simple( - info->discourse->mix_element, "sink_%u" + info->audio_mix_pad = gst_element_request_pad_simple( + info->discourse->audio_mix_element, "sink_%u" ); { GstPad *pad = gst_element_get_static_pad( - info->converter, "src" + info->audio_converter, "src" ); - g_object_set(info->mix_pad, "mute", FALSE, "volume", 1.0, NULL); - gst_pad_link(pad, info->mix_pad); + g_object_set(info->audio_mix_pad, "mute", FALSE, "volume", 1.0, NULL); + gst_pad_link(pad, info->audio_mix_pad); } - gst_element_sync_state_with_parent(info->stream_source); - gst_element_sync_state_with_parent(info->converter); + gst_element_sync_state_with_parent(info->audio_stream_source); + gst_element_sync_state_with_parent(info->audio_converter); } static MESSENGER_DiscourseSubscriptionInfo* @@ -121,10 +151,10 @@ discourse_subscription_create_info(MESSENGER_DiscourseInfo *discourse, info->discourse = discourse; info->contact = contact; - info->stream_source = NULL; - info->converter = NULL; + info->audio_stream_source = NULL; + info->audio_converter = NULL; - info->mix_pad = NULL; + info->audio_mix_pad = NULL; info->position = 0; @@ -137,31 +167,31 @@ discourse_subscription_destroy_info(MESSENGER_DiscourseSubscriptionInfo *info) { g_assert(info); - gst_element_set_state(info->stream_source, GST_STATE_NULL); - gst_element_set_state(info->converter, GST_STATE_NULL); + gst_element_set_state(info->audio_stream_source, GST_STATE_NULL); + gst_element_set_state(info->audio_converter, GST_STATE_NULL); - if (info->mix_pad) + if (info->audio_mix_pad) { GstPad *pad = gst_element_get_static_pad( - info->converter, "src" + info->audio_converter, "src" ); - gst_pad_unlink(pad, info->mix_pad); + gst_pad_unlink(pad, info->audio_mix_pad); - gst_element_release_request_pad(info->discourse->mix_element, info->mix_pad); - gst_object_unref(GST_OBJECT(info->mix_pad)); + gst_element_release_request_pad(info->discourse->audio_mix_element, info->audio_mix_pad); + gst_object_unref(GST_OBJECT(info->audio_mix_pad)); } gst_element_unlink_many( - info->stream_source, - info->converter, + info->audio_stream_source, + info->audio_converter, NULL ); gst_bin_remove_many( - GST_BIN(info->discourse->mix_pipeline), - info->stream_source, - info->converter, + GST_BIN(info->discourse->audio_mix_pipeline), + info->audio_stream_source, + info->audio_converter, NULL ); @@ -204,7 +234,7 @@ discourse_subscription_stream_message(MESSENGER_DiscourseSubscriptionInfo *info, else goto skip_buffer; - g_signal_emit_by_name(info->stream_source, "push-buffer", buffer, &ret); + g_signal_emit_by_name(info->audio_stream_source, "push-buffer", buffer, &ret); info->position += samples; skip_buffer: @@ -215,25 +245,25 @@ skip_buffer: } static void -_setup_gst_pipelines(MESSENGER_DiscourseInfo *info) +_setup_audio_gst_pipelines(MESSENGER_DiscourseInfo *info) { g_assert(info); - info->record_audio_pipeline = gst_parse_launch( + info->audio_record_pipeline = gst_parse_launch( "autoaudiosrc ! audioconvert ! capsfilter name=filter ! fdsink name=sink", NULL ); - info->record_audio_sink = gst_bin_get_by_name( - GST_BIN(info->record_audio_pipeline), "sink" + info->audio_record_sink = gst_bin_get_by_name( + GST_BIN(info->audio_record_pipeline), "sink" ); GstElement *filter = gst_bin_get_by_name( - GST_BIN(info->record_audio_pipeline), "filter" + GST_BIN(info->audio_record_pipeline), "filter" ); { - GstBus *bus = gst_element_get_bus(info->record_audio_pipeline); + GstBus *bus = gst_element_get_bus(info->audio_record_pipeline); gst_bus_add_signal_watch(bus); g_signal_connect(G_OBJECT(bus), "message::error", (GCallback)error_cb, info); gst_object_unref(bus); @@ -252,31 +282,75 @@ _setup_gst_pipelines(MESSENGER_DiscourseInfo *info) const int fd = GNUNET_CHAT_discourse_get_fd(info->discourse); if (-1 != fd) - g_object_set(info->record_audio_sink, "fd", fd, NULL); + g_object_set(info->audio_record_sink, "fd", fd, NULL); - gst_element_set_state(info->record_audio_pipeline, GST_STATE_PLAYING); + gst_element_set_state(info->audio_record_pipeline, GST_STATE_PLAYING); } - info->mix_pipeline = gst_parse_launch( + info->audio_mix_pipeline = gst_parse_launch( "audiomixer name=mixer ! volume name=control ! autoaudiosink", NULL ); - info->mix_element = gst_bin_get_by_name( - GST_BIN(info->mix_pipeline), "mixer" + info->audio_mix_element = gst_bin_get_by_name( + GST_BIN(info->audio_mix_pipeline), "mixer" ); - info->volume_element = gst_bin_get_by_name( - GST_BIN(info->mix_pipeline), "control" + info->audio_volume_element = gst_bin_get_by_name( + GST_BIN(info->audio_mix_pipeline), "control" ); { - GstBus *bus = gst_element_get_bus(info->mix_pipeline); + GstBus *bus = gst_element_get_bus(info->audio_mix_pipeline); gst_bus_add_signal_watch(bus); g_signal_connect(G_OBJECT(bus), "message::error", (GCallback)error_cb, info); gst_object_unref(bus); - gst_element_set_state(info->mix_pipeline, GST_STATE_PLAYING); + gst_element_set_state(info->audio_mix_pipeline, GST_STATE_PLAYING); + } +} + +static void +_setup_video_gst_pipelines(MESSENGER_DiscourseInfo *info) +{ + g_assert(info); + + info->video_record_pipeline = gst_parse_launch( + "videotestsrc ! videoconvert ! x264enc tune=zerolatency ! rtph264pay ! capsfilter name=filter ! fdsink name=sink", + NULL + ); + + info->video_record_sink = gst_bin_get_by_name( + GST_BIN(info->video_record_pipeline), "sink" + ); + + GstElement *filter = gst_bin_get_by_name( + GST_BIN(info->video_record_pipeline), "filter" + ); + + { + GstBus *bus = gst_element_get_bus(info->video_record_pipeline); + gst_bus_add_signal_watch(bus); + g_signal_connect(G_OBJECT(bus), "message::error", (GCallback)error_cb, info); + gst_object_unref(bus); + + GstCaps *caps = gst_caps_new_simple ( + "application/x-rtp", + "media", G_TYPE_STRING, "video", + "payload", G_TYPE_INT, 96, + "clock-rate", G_TYPE_INT, 90000, + "encoding-name", G_TYPE_STRING, "H264", + NULL + ); + + g_object_set(filter, "caps", caps, NULL); + gst_caps_unref(caps); + + const int fd = GNUNET_CHAT_discourse_get_fd(info->discourse); + if (-1 != fd) + g_object_set(info->video_record_sink, "fd", fd, NULL); + + gst_element_set_state(info->video_record_pipeline, GST_STATE_NULL); } } @@ -293,12 +367,15 @@ discourse_create_info(struct GNUNET_CHAT_Discourse *discourse) info->discourse = discourse; - info->record_audio_pipeline = NULL; - info->record_audio_sink = NULL; + info->audio_record_pipeline = NULL; + info->audio_record_sink = NULL; + + info->video_record_pipeline = NULL; + info->video_record_sink = NULL; - info->mix_pipeline = NULL; - info->mix_element = NULL; - info->volume_element = NULL; + info->audio_mix_pipeline = NULL; + info->audio_mix_element = NULL; + info->audio_volume_element = NULL; info->sending_task = 0; pthread_mutex_init(&(info->mutex), NULL); @@ -306,7 +383,14 @@ discourse_create_info(struct GNUNET_CHAT_Discourse *discourse) info->samples = NULL; info->subscriptions = NULL; - _setup_gst_pipelines(info); + const struct GNUNET_ShortHashCode *id = GNUNET_CHAT_discourse_get_id( + info->discourse + ); + + if (0 == GNUNET_memcmp(id, get_voice_discourse_id())) + _setup_audio_gst_pipelines(info); + else if (0 == GNUNET_memcmp(id, get_video_discourse_id())) + _setup_video_gst_pipelines(info); GNUNET_CHAT_discourse_set_user_pointer(discourse, info); return GNUNET_YES; @@ -336,16 +420,22 @@ discourse_destroy_info(struct GNUNET_CHAT_Discourse *discourse) g_list_free(info->subscriptions); } - if (info->mix_pipeline) + if (info->video_record_pipeline) + { + gst_element_set_state(info->video_record_pipeline, GST_STATE_NULL); + gst_object_unref(GST_OBJECT(info->video_record_pipeline)); + } + + if (info->audio_mix_pipeline) { - gst_element_set_state(info->mix_pipeline, GST_STATE_NULL); - gst_object_unref(GST_OBJECT(info->mix_pipeline)); + gst_element_set_state(info->audio_mix_pipeline, GST_STATE_NULL); + gst_object_unref(GST_OBJECT(info->audio_mix_pipeline)); } - if (info->record_audio_pipeline) + if (info->audio_record_pipeline) { - gst_element_set_state(info->record_audio_pipeline, GST_STATE_NULL); - gst_object_unref(GST_OBJECT(info->record_audio_pipeline)); + gst_element_set_state(info->audio_record_pipeline, GST_STATE_NULL); + gst_object_unref(GST_OBJECT(info->audio_record_pipeline)); } pthread_mutex_lock(&(info->mutex)); @@ -505,11 +595,11 @@ discourse_has_controls(struct GNUNET_CHAT_Discourse *discourse, switch (control) { case MESSENGER_DISCOURSE_CTRL_MICROPHONE: - return (info->record_audio_pipeline? TRUE : FALSE); + return (info->audio_record_pipeline? TRUE : FALSE); case MESSENGER_DISCOURSE_CTRL_SPEAKERS: - return (info->mix_pipeline? TRUE : FALSE); + return (info->audio_mix_pipeline? TRUE : FALSE); case MESSENGER_DISCOURSE_CTRL_WEBCAM: - return FALSE; + return (info->video_record_pipeline? TRUE : FALSE); case MESSENGER_DISCOURSE_CTRL_SCREEN_CAPTURE: return FALSE; default: @@ -523,10 +613,10 @@ discourse_set_volume(struct GNUNET_CHAT_Discourse *discourse, { MESSENGER_DiscourseInfo* info = GNUNET_CHAT_discourse_get_user_pointer(discourse); - if ((!info) || (!(info->mix_pipeline)) || (!(info->volume_element))) + if ((!info) || (!(info->audio_mix_pipeline)) || (!(info->audio_volume_element))) return; - g_object_set(info->volume_element, "volume", volume, NULL); + g_object_set(info->audio_volume_element, "volume", volume, NULL); } double @@ -534,11 +624,11 @@ discourse_get_volume(struct GNUNET_CHAT_Discourse *discourse) { MESSENGER_DiscourseInfo* info = GNUNET_CHAT_discourse_get_user_pointer(discourse); - if ((!info) || (!(info->mix_pipeline)) || (!(info->volume_element))) + if ((!info) || (!(info->audio_mix_pipeline)) || (!(info->audio_volume_element))) return 0.0; gdouble volume; - g_object_get(info->volume_element, "volume", &volume, NULL); + g_object_get(info->audio_volume_element, "volume", &volume, NULL); return volume; } @@ -549,11 +639,11 @@ discourse_set_mute(struct GNUNET_CHAT_Discourse *discourse, { MESSENGER_DiscourseInfo* info = GNUNET_CHAT_discourse_get_user_pointer(discourse); - if ((!info) || (!(info->record_audio_pipeline))) + if ((!info) || (!(info->audio_record_pipeline))) return; gst_element_set_state( - info->record_audio_pipeline, + info->audio_record_pipeline, mute? GST_STATE_NULL : GST_STATE_PLAYING ); } @@ -563,12 +653,12 @@ discourse_is_mute(struct GNUNET_CHAT_Discourse *discourse) { MESSENGER_DiscourseInfo* info = GNUNET_CHAT_discourse_get_user_pointer(discourse); - if ((!info) || (!(info->record_audio_pipeline))) + if ((!info) || (!(info->audio_record_pipeline))) return TRUE; GstState state; gst_element_get_state( - info->record_audio_pipeline, + info->audio_record_pipeline, &state, NULL, GST_CLOCK_TIME_NONE diff --git a/src/discourse.h b/src/discourse.h @@ -31,6 +31,22 @@ #include <gnunet/gnunet_chat_lib.h> #include <pthread.h> +/** + * Returns the discourse id for a typical voice chat. + * + * @return Voice chat discourse id + */ +const struct GNUNET_ShortHashCode* +get_voice_discourse_id(); + +/** + * Returns the discourse id for a typical video chat. + * + * @return Video chat discourse id + */ +const struct GNUNET_ShortHashCode* +get_video_discourse_id(); + typedef enum MESSENGER_DiscourseControl { MESSENGER_DISCOURSE_CTRL_MICROPHONE = 1, MESSENGER_DISCOURSE_CTRL_SPEAKERS = 2, @@ -44,15 +60,15 @@ typedef struct MESSENGER_DiscourseInfo { struct GNUNET_CHAT_Discourse *discourse; - GstElement *record_audio_pipeline; - GstElement *record_audio_sink; + GstElement *audio_record_pipeline; + GstElement *audio_record_sink; - GstElement *record_video_pipeline; - GstElement *record_video_sink; + GstElement *video_record_pipeline; + GstElement *video_record_sink; - GstElement *mix_pipeline; - GstElement *mix_element; - GstElement *volume_element; + GstElement *audio_mix_pipeline; + GstElement *audio_mix_element; + GstElement *audio_volume_element; guint sending_task; pthread_mutex_t mutex; @@ -66,10 +82,10 @@ typedef struct MESSENGER_DiscourseSubscriptionInfo MESSENGER_DiscourseInfo *discourse; struct GNUNET_CHAT_Contact *contact; - GstElement *stream_source; - GstElement *converter; + GstElement *audio_stream_source; + GstElement *audio_converter; - GstPad *mix_pad; + GstPad *audio_mix_pad; uint64_t position; } MESSENGER_DiscourseSubscriptionInfo; diff --git a/src/ui/discourse.c b/src/ui/discourse.c @@ -38,36 +38,6 @@ #include <string.h> -static const struct GNUNET_ShortHashCode* -get_voice_discourse_id() -{ - static enum GNUNET_GenericReturnValue init = GNUNET_NO; - static struct GNUNET_ShortHashCode id; - - if (GNUNET_YES != init) - { - memset(&id, 0, sizeof(id)); - init = GNUNET_YES; - } - - return &id; -} - -static const struct GNUNET_ShortHashCode* -get_video_discourse_id() -{ - static enum GNUNET_GenericReturnValue init = GNUNET_NO; - static struct GNUNET_ShortHashCode id; - - if (GNUNET_YES != init) - { - memset(&id, 1, sizeof(id)); - init = GNUNET_YES; - } - - return &id; -} - static void handle_back_button_click(UNUSED GtkButton *button, gpointer user_data) @@ -151,8 +121,10 @@ _update_call_button(UI_DISCOURSE_Handle *handle) { g_assert(handle); - if ((handle->voice_discourse) && - (GNUNET_YES ==GNUNET_CHAT_discourse_is_open(handle->voice_discourse))) + if (((handle->voice_discourse) && + (GNUNET_YES == GNUNET_CHAT_discourse_is_open(handle->voice_discourse))) || + ((handle->video_discourse) && + (GNUNET_YES == GNUNET_CHAT_discourse_is_open(handle->video_discourse)))) gtk_stack_set_visible_child(handle->call_stack, handle->call_stop_button); else gtk_stack_set_visible_child(handle->call_stack, handle->call_start_button); @@ -170,10 +142,15 @@ handle_call_start_button_click(UNUSED GtkButton *button, return; application_chat_lock(handle->app); + handle->voice_discourse = GNUNET_CHAT_context_open_discourse( handle->context, get_voice_discourse_id() ); + handle->video_discourse = GNUNET_CHAT_context_open_discourse( + handle->context, get_video_discourse_id() + ); + _update_call_button(handle); application_chat_unlock(handle->app); } @@ -190,8 +167,18 @@ handle_call_stop_button_click(UNUSED GtkButton *button, return; application_chat_lock(handle->app); - GNUNET_CHAT_discourse_close(handle->voice_discourse); - handle->voice_discourse = NULL; + + if (handle->voice_discourse) + { + GNUNET_CHAT_discourse_close(handle->voice_discourse); + handle->voice_discourse = NULL; + } + + if (handle->video_discourse) + { + GNUNET_CHAT_discourse_close(handle->video_discourse); + handle->video_discourse = NULL; + } _update_call_button(handle); application_chat_unlock(handle->app);