messenger-gtk

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

commit b2dbe8c64805cace6f4b9366b6370ce443805bf4
parent ba7c65188a8adcaa8d809c81517108ad62f1b245
Author: Jacki <jacki@thejackimonster.de>
Date:   Tue, 13 Aug 2024 18:14:55 +0200

Wire up logic to set target of pipewiresrc dynamically

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

Diffstat:
Msrc/discourse.c | 25++++++++++++++++++++++++-
Msrc/discourse.h | 11+++++++++++
Msrc/ui/discourse.c | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Msrc/ui/discourse.h | 2+-
4 files changed, 127 insertions(+), 32 deletions(-)

diff --git a/src/discourse.c b/src/discourse.c @@ -588,10 +588,14 @@ _setup_video_gst_pipelines(MESSENGER_DiscourseInfo *info) g_assert(info); info->video_record_pipeline = gst_parse_launch( - "autovideosrc ! video/x-raw,framerate={ [ 0/1, 30/1 ] } ! videoscale ! video/x-raw,width=1280,height=720 ! videoconvert ! video/x-raw,format=I420 ! x264enc bitrate=1000 speed-preset=fast bframes=0 key-int-max=30 tune=zerolatency byte-stream=true ! video/x-h264,profile=baseline ! rtph264pay aggregate-mode=zero-latency mtu=45000 ! capsfilter name=filter ! fdsink name=sink", + "pipewiresrc name=source ! video/x-raw,framerate={ [ 0/1, 30/1 ] } ! videoscale ! video/x-raw,width=1280,height=720 ! videoconvert ! video/x-raw,format=I420 ! x264enc bitrate=1000 speed-preset=fast bframes=0 key-int-max=30 tune=zerolatency byte-stream=true ! video/x-h264,profile=baseline ! rtph264pay aggregate-mode=zero-latency mtu=45000 ! capsfilter name=filter ! fdsink name=sink", NULL ); + info->video_record_source = gst_bin_get_by_name( + GST_BIN(info->video_record_pipeline), "source" + ); + info->video_record_sink = gst_bin_get_by_name( GST_BIN(info->video_record_pipeline), "sink" ); @@ -643,6 +647,7 @@ discourse_create_info(struct GNUNET_CHAT_Discourse *discourse) info->audio_record_sink = NULL; info->video_record_pipeline = NULL; + info->video_record_source = NULL; info->video_record_sink = NULL; info->audio_mix_pipeline = NULL; @@ -940,6 +945,24 @@ discourse_is_mute(const struct GNUNET_CHAT_Discourse *discourse) return (GST_STATE_PLAYING != state); } +void +discourse_set_target(struct GNUNET_CHAT_Discourse *discourse, + const char *name) +{ + MESSENGER_DiscourseInfo* info = GNUNET_CHAT_discourse_get_user_pointer(discourse); + + if (!info) + return; + + if (info->video_record_source) + g_object_set( + G_OBJECT(info->video_record_source), + "target-object", + name, + NULL + ); +} + gboolean discourse_link_widget(const struct GNUNET_CHAT_Discourse *discourse, const struct GNUNET_CHAT_Contact *contact, diff --git a/src/discourse.h b/src/discourse.h @@ -65,6 +65,7 @@ typedef struct MESSENGER_DiscourseInfo GstElement *audio_record_sink; GstElement *video_record_pipeline; + GstElement *video_record_source; GstElement *video_record_sink; GstElement *audio_mix_pipeline; @@ -193,6 +194,16 @@ bool discourse_is_mute(const struct GNUNET_CHAT_Discourse *discourse); /** + * Sets the capture target of a given discourse by name. + * + * @param discourse Chat discourse + * @param name Target name + */ +void +discourse_set_target(struct GNUNET_CHAT_Discourse *discourse, + const char *name); + +/** * Links/Unlinks a widget from the video pipeline of a discourse * for a given chat contact to a selected container as * child. diff --git a/src/ui/discourse.c b/src/ui/discourse.c @@ -109,6 +109,65 @@ static void _discourse_update_members(UI_DISCOURSE_Handle *handle); static void +_update_streaming_state(UI_DISCOURSE_Handle *handle, + gboolean streaming) +{ + handle->streaming = streaming; + + if (handle->video_discourse) + discourse_set_mute(handle->video_discourse, !(handle->streaming)); + + if ((handle->app) && (!(handle->streaming))) + application_set_active_session(handle->app, NULL); + + _discourse_update_members(handle); +} + +static void +iterate_cameras(void *cls, + const char *name, + const char *description, + const char *media_class, + const char *media_role) +{ + g_assert(cls); + + UI_DISCOURSE_Handle *handle = (UI_DISCOURSE_Handle*) cls; + + if ((!name) || (!description) || (!media_class) || (!media_role)) + return; + + if (0 != g_strcmp0(media_class, "Video/Source")) + return; + if (0 != g_strcmp0(media_role, "Camera")) + return; + + if (handle->video_discourse) + discourse_set_target(handle->video_discourse, name); +} + +static void +_request_camera_callback(MESSENGER_Application *app, + gboolean success, + gboolean error, + gpointer user_data) +{ + g_assert((app) && (user_data)); + + UI_DISCOURSE_Handle *handle = (UI_DISCOURSE_Handle*) user_data; + + if ((!success) || (error)) + return; + + media_init_camera_capturing(&(app->media.camera), app); + media_pw_main_loop_run(&(app->media.camera)); + + media_pw_iterate_nodes(&(app->media.camera), iterate_cameras, handle); + + _update_streaming_state(handle, true); +} + +static void handle_camera_button_click(UNUSED GtkButton *button, gpointer user_data) { @@ -116,11 +175,15 @@ handle_camera_button_click(UNUSED GtkButton *button, UI_DISCOURSE_Handle *handle = (UI_DISCOURSE_Handle*) user_data; - handle->stream_camera = !(handle->stream_camera); - if (handle->video_discourse) - discourse_set_mute(handle->video_discourse, !(handle->stream_camera)); - - _discourse_update_members(handle); + if (handle->streaming) + _update_streaming_state(handle, false); + else + request_new_camera( + handle->app, + XDP_CAMERA_FLAG_NONE, + _request_camera_callback, + handle + ); } static void @@ -140,7 +203,8 @@ iterate_streams(void *cls, if (0 != g_strcmp0(media_class, "Stream/Output/Video")) return; - // TODO + if (handle->video_discourse) + discourse_set_target(handle->video_discourse, name); } static void @@ -153,19 +217,15 @@ _request_screen_callback(MESSENGER_Application *app, UI_DISCOURSE_Handle *handle = (UI_DISCOURSE_Handle*) user_data; -#ifndef MESSENGER_APPLICATION_NO_PORTAL - if ((app->portal) && (success)) -#else - if (success) -#endif - { - media_init_screen_sharing(&(app->media.screen), app); - media_pw_main_loop_run(&(app->media.screen)); + if ((!success) || (error)) + return; - media_pw_iterate_nodes(&(app->media.screen), iterate_streams, handle); + media_init_screen_sharing(&(app->media.screen), app); + media_pw_main_loop_run(&(app->media.screen)); - // TODO - } + media_pw_iterate_nodes(&(app->media.screen), iterate_streams, handle); + + _update_streaming_state(handle, true); } static void @@ -176,17 +236,18 @@ handle_screen_button_click(UNUSED GtkButton *button, UI_DISCOURSE_Handle *handle = (UI_DISCOURSE_Handle*) user_data; - // TODO - - request_new_screencast( - handle->app, - XDP_OUTPUT_MONITOR | XDP_OUTPUT_WINDOW, - XDP_SCREENCAST_FLAG_NONE, - XDP_CURSOR_MODE_EMBEDDED, - XDP_PERSIST_MODE_TRANSIENT, - _request_screen_callback, - handle - ); + if (handle->streaming) + _update_streaming_state(handle, false); + else + request_new_screencast( + handle->app, + XDP_OUTPUT_MONITOR | XDP_OUTPUT_WINDOW, + XDP_SCREENCAST_FLAG_NONE, + XDP_CURSOR_MODE_EMBEDDED, + XDP_PERSIST_MODE_TRANSIENT, + _request_screen_callback, + handle + ); } static void @@ -267,7 +328,7 @@ handle_call_stop_button_click(UNUSED GtkButton *button, } handle->muted = TRUE; - handle->stream_camera = FALSE; + handle->streaming = FALSE; _update_call_button(handle); application_chat_unlock(handle->app); @@ -295,7 +356,7 @@ ui_discourse_window_init(MESSENGER_Application *app, handle->video_discourse = NULL; handle->muted = TRUE; - handle->stream_camera = FALSE; + handle->streaming = FALSE; handle->parent = GTK_WINDOW(app->ui.messenger.main_window); diff --git a/src/ui/discourse.h b/src/ui/discourse.h @@ -42,7 +42,7 @@ typedef struct UI_DISCOURSE_Handle struct GNUNET_CHAT_Discourse *video_discourse; gboolean muted; - gboolean stream_camera; + gboolean streaming; GtkWindow *parent;