messenger-gtk

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

commit 6c8633fb2c677030d84df89587def575c74ee960
parent da44d0ba556cb7d8df9954fdd95eb23ea903dd2c
Author: Jacki <jacki@thejackimonster.de>
Date:   Tue, 25 Jun 2024 16:59:59 +0200

Implement discourse audio controls via UI

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

Diffstat:
Mresources/css/style.css | 5+++++
Mresources/ui/discourse.ui | 4++++
Msrc/discourse.c | 81++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/discourse.h | 18++++++++++++++++++
Msrc/ui/discourse.c | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Msrc/ui/discourse.h | 1+
6 files changed, 185 insertions(+), 5 deletions(-)

diff --git a/resources/css/style.css b/resources/css/style.css @@ -57,6 +57,11 @@ color: @theme_selected_fg_color; } +.discourse-action:disabled { + background-color: mix(@theme_bg_color, @theme_selected_bg_color, 0.2); + color: mix(black, @theme_selected_fg_color, 0.8); +} + .success-action { background-color: @success_color; } diff --git a/resources/ui/discourse.ui b/resources/ui/discourse.ui @@ -189,6 +189,7 @@ Author: Tobias Frisch <child> <object class="GtkButton" id="microphone_button"> <property name="visible">True</property> + <property name="sensitive">False</property> <property name="can-focus">True</property> <property name="receives-default">True</property> <property name="relief">none</property> @@ -232,6 +233,7 @@ Author: Tobias Frisch <child> <object class="GtkButton" id="camera_button"> <property name="visible">True</property> + <property name="sensitive">False</property> <property name="can-focus">True</property> <property name="receives-default">True</property> <property name="relief">none</property> @@ -255,6 +257,7 @@ Author: Tobias Frisch <child> <object class="GtkButton" id="screen_button"> <property name="visible">True</property> + <property name="sensitive">False</property> <property name="can-focus">True</property> <property name="receives-default">True</property> <property name="relief">none</property> @@ -278,6 +281,7 @@ Author: Tobias Frisch <child> <object class="GtkVolumeButton" id="speakers_button"> <property name="visible">True</property> + <property name="sensitive">False</property> <property name="can-focus">True</property> <property name="focus-on-click">False</property> <property name="receives-default">True</property> diff --git a/src/discourse.c b/src/discourse.c @@ -265,7 +265,7 @@ _setup_gst_pipelines(MESSENGER_DiscourseInfo *info) } info->mix_pipeline = gst_parse_launch( - "audiomixer name=mixer ! autoaudiosink", + "audiomixer name=mixer ! volume name=control ! autoaudiosink", NULL ); @@ -273,6 +273,10 @@ _setup_gst_pipelines(MESSENGER_DiscourseInfo *info) GST_BIN(info->mix_pipeline), "mixer" ); + info->volume_element = gst_bin_get_by_name( + GST_BIN(info->mix_pipeline), "control" + ); + { GstBus *bus = gst_element_get_bus(info->mix_pipeline); gst_bus_add_signal_watch(bus); @@ -301,6 +305,7 @@ discourse_create_info(struct GNUNET_CHAT_Discourse *discourse) info->mix_pipeline = NULL; info->mix_element = NULL; + info->volume_element = NULL; info->subscriptions = NULL; @@ -468,3 +473,77 @@ discourse_stream_message(struct GNUNET_CHAT_Discourse *discourse, discourse_subscription_stream_message(sub_info, message); } + +bool +discourse_has_controls(struct GNUNET_CHAT_Discourse *discourse) +{ + MESSENGER_DiscourseInfo* info = GNUNET_CHAT_discourse_get_user_pointer(discourse); + + if (!info) + return FALSE; + + if ((!(info->record_pipeline)) && (!(info->mix_pipeline))) + return FALSE; + + return TRUE; +} + +void +discourse_set_volume(struct GNUNET_CHAT_Discourse *discourse, + double volume) +{ + MESSENGER_DiscourseInfo* info = GNUNET_CHAT_discourse_get_user_pointer(discourse); + + if ((!info) || (!(info->mix_pipeline)) || (!(info->volume_element))) + return; + + g_object_set(info->volume_element, "volume", volume, NULL); +} + +double +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))) + return 0.0; + + gdouble volume; + g_object_get(info->volume_element, "volume", &volume, NULL); + + return volume; +} + +void +discourse_set_mute(struct GNUNET_CHAT_Discourse *discourse, + bool mute) +{ + MESSENGER_DiscourseInfo* info = GNUNET_CHAT_discourse_get_user_pointer(discourse); + + if ((!info) || (!(info->record_pipeline))) + return; + + gst_element_set_state( + info->record_pipeline, + mute? GST_STATE_NULL : GST_STATE_PLAYING + ); +} + +bool +discourse_is_mute(struct GNUNET_CHAT_Discourse *discourse) +{ + MESSENGER_DiscourseInfo* info = GNUNET_CHAT_discourse_get_user_pointer(discourse); + + if ((!info) || (!(info->record_pipeline))) + return TRUE; + + GstState state; + gst_element_get_state( + info->record_pipeline, + &state, + NULL, + GST_CLOCK_TIME_NONE + ); + + return (GST_STATE_PLAYING != state); +} diff --git a/src/discourse.h b/src/discourse.h @@ -39,6 +39,7 @@ typedef struct MESSENGER_DiscourseInfo GstElement *mix_pipeline; GstElement *mix_element; + GstElement *volume_element; GList *subscriptions; } MESSENGER_DiscourseInfo; @@ -70,4 +71,21 @@ void discourse_stream_message(struct GNUNET_CHAT_Discourse *discourse, const struct GNUNET_CHAT_Message *message); +bool +discourse_has_controls(struct GNUNET_CHAT_Discourse *discourse); + +void +discourse_set_volume(struct GNUNET_CHAT_Discourse *discourse, + double volume); + +double +discourse_get_volume(struct GNUNET_CHAT_Discourse *discourse); + +void +discourse_set_mute(struct GNUNET_CHAT_Discourse *discourse, + bool mute); + +bool +discourse_is_mute(struct GNUNET_CHAT_Discourse *discourse); + #endif /* DISCOURSE_H_ */ diff --git a/src/ui/discourse.c b/src/ui/discourse.c @@ -32,6 +32,7 @@ #include "discourse_panel.h" #include "../application.h" +#include "../discourse.h" #include "../ui.h" #include "../util.h" @@ -52,6 +53,21 @@ get_voice_discourse_id() 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) @@ -111,10 +127,26 @@ handle_microphone_button_click(UNUSED GtkButton *button, UI_DISCOURSE_Handle *handle = (UI_DISCOURSE_Handle*) user_data; handle->muted = !(handle->muted); + if (handle->voice_discourse) + discourse_set_mute(handle->voice_discourse, handle->muted); + _update_microphone_icon(handle); } static void +handle_speakers_button_value_changed(UNUSED GtkScaleButton *button, + gdouble value, + gpointer user_data) +{ + g_assert(user_data); + + UI_DISCOURSE_Handle *handle = (UI_DISCOURSE_Handle*) user_data; + + if (handle->voice_discourse) + discourse_set_volume(handle->voice_discourse, value); +} + +static void _update_call_button(UI_DISCOURSE_Handle *handle) { g_assert(handle); @@ -278,6 +310,13 @@ ui_discourse_window_init(MESSENGER_Application *app, gtk_builder_get_object(handle->builder, "speakers_button") ); + g_signal_connect( + handle->speakers_button, + "value-changed", + G_CALLBACK(handle_speakers_button_value_changed), + handle + ); + handle->microphone_stack = GTK_STACK( gtk_builder_get_object(handle->builder, "microphone_stack") ); @@ -559,10 +598,14 @@ iterate_ui_discourse_search_context_discourses(void *cls, { g_assert((cls) && (context) && (discourse)); - UI_DISCOURSE_Handle *handle = (UI_DISCOURSE_Handle*) cls; + struct GNUNET_CHAT_Discourse **discourses = (struct GNUNET_CHAT_Discourse**) cls; + + const struct GNUNET_ShortHashCode *id = GNUNET_CHAT_discourse_get_id(discourse); - if (0 == GNUNET_memcmp(GNUNET_CHAT_discourse_get_id(discourse), get_voice_discourse_id())) - handle->voice_discourse = discourse; + if (0 == GNUNET_memcmp(id, get_voice_discourse_id())) + discourses[0] = discourse; + else if (0 == GNUNET_memcmp(id, get_video_discourse_id())) + discourses[1] = discourse; return GNUNET_YES; } @@ -573,15 +616,45 @@ _update_discourse_via_context(UI_DISCOURSE_Handle *handle) g_assert(handle); handle->voice_discourse = NULL; + handle->video_discourse = NULL; if (!(handle->context)) return; + struct GNUNET_CHAT_Discourse *discourses [2]; + memset(discourses, 0, sizeof(struct GNUNET_CHAT_Discourse*) * 2); + GNUNET_CHAT_context_iterate_discourses( handle->context, iterate_ui_discourse_search_context_discourses, - handle + discourses + ); + + const gboolean has_voice_controls = discourse_has_controls( + discourses[0] + ); + + const gboolean has_video_controls = discourse_has_controls( + discourses[1] ); + + gtk_widget_set_sensitive(GTK_WIDGET(handle->microphone_button), has_voice_controls); + gtk_widget_set_sensitive(GTK_WIDGET(handle->camera_button), has_video_controls); + gtk_widget_set_sensitive(GTK_WIDGET(handle->screen_button), has_video_controls); + gtk_widget_set_sensitive(GTK_WIDGET(handle->speakers_button), has_voice_controls); + + if (discourses[0]) + { + handle->muted = discourse_is_mute(discourses[0]); + + gtk_scale_button_set_value( + GTK_SCALE_BUTTON(handle->speakers_button), + discourse_get_volume(discourses[0]) + ); + } + + handle->voice_discourse = discourses[0]; + handle->video_discourse = discourses[1]; } void diff --git a/src/ui/discourse.h b/src/ui/discourse.h @@ -39,6 +39,7 @@ typedef struct UI_DISCOURSE_Handle struct GNUNET_CHAT_Context *context; struct GNUNET_CHAT_Discourse *voice_discourse; + struct GNUNET_CHAT_Discourse *video_discourse; gboolean muted;