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:
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;