diff options
-rw-r--r-- | uca-net-camera.c | 58 | ||||
-rw-r--r-- | uca-net-protocol.h | 33 | ||||
-rw-r--r-- | ucad.c | 61 |
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 @@ -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 }, |