summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--uca-net-camera.c58
-rw-r--r--uca-net-protocol.h33
-rw-r--r--ucad.c61
3 files changed, 152 insertions, 0 deletions
diff --git a/uca-net-camera.c b/uca-net-camera.c
index f2d5638..849d446 100644
--- a/uca-net-camera.c
+++ b/uca-net-camera.c
@@ -455,6 +455,59 @@ ufo_net_camera_initable_init (GInitable *initable,
return TRUE;
}
+static GParamSpec *
+deserialize_param_spec (UcaNetMessageProperty *prop)
+{
+#define CASE_NUMERIC(type, storage) \
+ case type: \
+ return g_param_spec_##storage (prop->name, prop->nick, prop->blurb, \
+ prop->spec.g##storage.minimum, prop->spec.g##storage.maximum, \
+ prop->spec.g##storage.default_value, \
+ prop->flags);
+ switch (prop->value_type) {
+ case G_TYPE_BOOLEAN:
+ return g_param_spec_boolean (prop->name, prop->nick, prop->blurb,
+ prop->spec.gboolean.default_value,
+ prop->flags);
+ CASE_NUMERIC (G_TYPE_INT, int)
+ CASE_NUMERIC (G_TYPE_UINT, uint)
+ CASE_NUMERIC (G_TYPE_FLOAT, float)
+ CASE_NUMERIC (G_TYPE_DOUBLE, double)
+ default:
+ return NULL;
+ }
+
+#undef CASE_NUMERIC
+}
+
+static void
+read_property_reply (GObject *object, GInputStream *input, guint index, GError **error)
+{
+ UcaNetMessageProperty property;
+
+ if (g_input_stream_read_all (input, &property, sizeof (property), NULL, NULL, error)) {
+ GParamSpec *pspec;
+
+ pspec = deserialize_param_spec (&property);
+
+ if (pspec != NULL)
+ g_object_class_install_property (G_OBJECT_GET_CLASS (object), N_PROPERTIES + index + 1, pspec);
+ }
+}
+
+static void
+read_get_properties_reply (GObject *object, GInputStream *input, GError **error)
+{
+ UcaNetMessageGetPropertiesReply reply;
+
+ if (g_input_stream_read_all (input, &reply, sizeof (reply), NULL, NULL, error)) {
+ g_assert (reply.type == UCA_NET_MESSAGE_GET_PROPERTIES);
+
+ for (guint i = 0; i < reply.num_properties; i++)
+ read_property_reply (object, input, i, error);
+ }
+}
+
static void
uca_net_camera_constructed (GObject *object)
{
@@ -466,6 +519,11 @@ uca_net_camera_constructed (GObject *object)
priv->host = g_strdup ("localhost");
priv->connection = g_socket_client_connect_to_host (priv->client, priv->host, UCA_NET_DEFAULT_PORT, NULL, &priv->construct_error);
+
+ /* ask for additional camera properties */
+ if (send_default_message (priv->connection, UCA_NET_MESSAGE_GET_PROPERTIES, &priv->construct_error))
+ read_get_properties_reply (object, g_io_stream_get_input_stream (G_IO_STREAM (priv->connection)),
+ &priv->construct_error);
}
static void
diff --git a/uca-net-protocol.h b/uca-net-protocol.h
index 653a26d..d8e07e6 100644
--- a/uca-net-protocol.h
+++ b/uca-net-protocol.h
@@ -5,6 +5,7 @@
typedef enum {
UCA_NET_MESSAGE_INVALID = 0,
+ UCA_NET_MESSAGE_GET_PROPERTIES,
UCA_NET_MESSAGE_GET_PROPERTY,
UCA_NET_MESSAGE_SET_PROPERTY,
UCA_NET_MESSAGE_START_RECORDING,
@@ -60,4 +61,36 @@ typedef struct {
gchar name[128];
} UcaNetMessageWriteRequest;
+typedef struct {
+ UcaNetMessageType type;
+ guint num_properties;
+} UcaNetMessageGetPropertiesReply;
+
+#define NUMERIC_STRUCT(type) \
+ struct { \
+ type minimum; \
+ type maximum; \
+ type default_value; \
+ } type;
+
+typedef struct {
+ GType value_type;
+ GParamFlags flags;
+ gchar name[128];
+ gchar nick[128];
+ gchar blurb[128];
+
+ union {
+ struct {
+ gboolean default_value;
+ } gboolean;
+ NUMERIC_STRUCT (gint)
+ NUMERIC_STRUCT (guint)
+ NUMERIC_STRUCT (gfloat)
+ NUMERIC_STRUCT (gdouble)
+ } spec;
+} UcaNetMessageProperty;
+
+#undef NUMERIC_STRUCT
+
#endif
diff --git a/ucad.c b/ucad.c
index 649ef28..490964a 100644
--- a/ucad.c
+++ b/ucad.c
@@ -104,6 +104,66 @@ prepare_error_reply (GError *error, UcaNetErrorReply *reply)
}
}
+static gboolean
+serialize_param_spec (GParamSpec *pspec, UcaNetMessageProperty *prop)
+{
+ strncpy (prop->name, g_param_spec_get_name (pspec), sizeof (prop->name));
+ strncpy (prop->nick, g_param_spec_get_nick (pspec), sizeof (prop->nick));
+ strncpy (prop->blurb, g_param_spec_get_blurb (pspec), sizeof (prop->blurb));
+
+ prop->value_type = pspec->value_type;
+ prop->flags = pspec->flags;
+
+#define CASE_NUMERIC(type, storage, typeclass) \
+ case type: \
+ prop->spec.storage.minimum = ((typeclass *) pspec)->minimum; \
+ prop->spec.storage.maximum = ((typeclass *) pspec)->maximum; \
+ prop->spec.storage.default_value = ((typeclass *) pspec)->default_value;
+
+ switch (pspec->value_type) {
+ case G_TYPE_BOOLEAN:
+ prop->spec.gboolean.default_value = ((GParamSpecBoolean *) pspec)->default_value;
+ break;
+ CASE_NUMERIC (G_TYPE_INT, gint, GParamSpecInt)
+ break;
+ CASE_NUMERIC (G_TYPE_UINT, guint, GParamSpecUInt)
+ break;
+ CASE_NUMERIC (G_TYPE_FLOAT, gfloat, GParamSpecFloat)
+ break;
+ CASE_NUMERIC (G_TYPE_DOUBLE, gdouble, GParamSpecDouble)
+ break;
+ default:
+ g_warning ("Unsupported property type");
+ return FALSE;
+ }
+
+#undef CASE_NUMERIC
+
+ return TRUE;
+}
+
+static void
+handle_get_properties_request (GSocketConnection *connection, UcaCamera *camera, gpointer message, GError **error)
+{
+ UcaNetMessageGetPropertiesReply reply = { .type = UCA_NET_MESSAGE_GET_PROPERTIES };
+ GParamSpec **pspecs;
+ guint num_properties;
+
+ pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (camera), &num_properties);
+ reply.num_properties = num_properties - N_BASE_PROPERTIES + 1;
+
+ send_reply (connection, &reply, sizeof (reply), error);
+
+ for (guint i = N_BASE_PROPERTIES - 1; i < num_properties; i++) {
+ UcaNetMessageProperty property;
+
+ if (serialize_param_spec (pspecs[i], &property))
+ send_reply (connection, &property, sizeof (property), error);
+ }
+
+ g_free (pspecs);
+}
+
static void
handle_get_property_request (GSocketConnection *connection, UcaCamera *camera, gpointer message, GError **error)
{
@@ -277,6 +337,7 @@ serve_connection (GSocketConnection *connection, UcaCamera *camera)
gboolean active;
HandlerTable table[] = {
+ { UCA_NET_MESSAGE_GET_PROPERTIES, handle_get_properties_request },
{ UCA_NET_MESSAGE_GET_PROPERTY, handle_get_property_request },
{ UCA_NET_MESSAGE_SET_PROPERTY, handle_set_property_request },
{ UCA_NET_MESSAGE_START_RECORDING, handle_start_recording_request },