summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRegis Merlino <regis.merlino@intel.com>2013-09-02 15:21:17 +0200
committerMark Ryan <mark.d.ryan@intel.com>2013-09-06 12:17:40 +0200
commit4d959b08882574b605b8dce48a1fb4d9bf2f7cee (patch)
treed3c0388d03926c1f114d6b1815beaa78e41e6187
parent8c460ff2e476eeb2b7e35471e97308652a0197f2 (diff)
downloaddleyna-server-4d959b08882574b605b8dce48a1fb4d9bf2f7cee.tar.gz
[Device] Deprecate LastChange in favor of Changed signal
Fix issue #109 * Remove LastChange signal * Add Changed signal * A Changed signal is emitted along with a ContainerUpdateID signal when LastChange is not managed by the DLNA server. Signed-off-by: Regis Merlino <regis.merlino@intel.com>
-rw-r--r--doc/server/dbus/API.txt82
-rw-r--r--libdleyna/server/device.c154
-rw-r--r--libdleyna/server/device.h1
-rw-r--r--libdleyna/server/interface.h9
-rw-r--r--libdleyna/server/server.c5
-rwxr-xr-xtest/dbus/monitor_changed.py (renamed from test/dbus/monitor_last_change.py)12
6 files changed, 187 insertions, 76 deletions
diff --git a/doc/server/dbus/API.txt b/doc/server/dbus/API.txt
index 9664ed9..378daf9 100644
--- a/doc/server/dbus/API.txt
+++ b/doc/server/dbus/API.txt
@@ -391,73 +391,47 @@ Signals:
The com.intel.dLeynaServer.MediaDevice interface also exposes three signals.
-LastChange (a(sv) StateEvent)
+Changed (aa{sv} ChangedObjects)
-The LastChange signal is generated by servers to provide precise information
-of changes that have taken place to their content. LastChange is useful for
+The Changed signal is generated by servers to provide precise information
+of changes that have taken place to their content. Changed is useful for
synchronisation controllers. It allows them to dynamically update their local
-cache of the server's content. This signal contains an array of zero or more
-elements, each of which represents a change to a specific object.
-The value of each dictionary entry depends on the key value.
+cache of the server's content. This signal contains an array of zero or more
+dictionary elements, each of which represents a change to a specific object.
+The dictionary is composed of the following keys:
|------------------------------------------------------------------------------|
-| Key values | R/O | Description |
+| Key | Type | m/o | Description |
|------------------------------------------------------------------------------|
-| "ADD" | O | Indicates that an object has been added. |
+| ChangeType | u | m | Contains the Type of the notification: |
+| | | | 1 (ADD) an object has been added |
+| | | | 2 (MOD) an object has been modified |
+| | | | 3 (DEL) an object has been deleted |
+| | | | 4 (DONE) an update to a sub-tree has |
+| | | | completed |
+| | | | 5 (CONTAINER) a container has been updated |
|------------------------------------------------------------------------------|
-| "MOD" | O | Indicates that an object has been modified. |
+| Path | o | m | Contains the Object Path property of the |
+| | | | object that was changed. |
|------------------------------------------------------------------------------|
-| "DEL" | O | Indicates that an object has been deleted |
+| UpdateID | u | m | ContainerUpdateID or SystemUpdateID when the |
+| | | | object was changed. |
|------------------------------------------------------------------------------|
-| "DONE" | O | Indicates that an update to a sub-tree has completed. |
+| SubTreeUpdate | b | o | True if the object was added as part of a |
+| | | | subtree update. |
|------------------------------------------------------------------------------|
-
-
-|------------------------------------------------------------------------------|
-| Dictionary value for key "ADD": Format (oubos) |
-|------------------------------------------------------------------------------|
-| o | M | Contains the Object Path property of the object that was added. |
-|------------------------------------------------------------------------------|
-| u | M | Contains the value of the SystemUpdateID when the object was added. |
-|------------------------------------------------------------------------------|
-| b | M | True if the object was added as part of a subtree update |
-|------------------------------------------------------------------------------|
-| o | M | Contains the Object Path property of the parent container to which |
-| | | this object was added. |
-|------------------------------------------------------------------------------|
-| s | M | Contains the value of the TypeEx (converted upnp:class property) |
-| | | of the object that was added. |
-|------------------------------------------------------------------------------|
-
-|------------------------------------------------------------------------------|
-| Dictionary value for key "MOD": Format (oub) |
-|------------------------------------------------------------------------------|
-| o | M | Contains the Object Path property of the object that was modified. |
+| Parent | o | o | Contains the Object Path property of the |
+| | | | parent container of the changed object. |
|------------------------------------------------------------------------------|
-| u | M | Contains the value of the SystemUpdateID when the object was added. |
+| TypeEx | s | o | Contains the value of the TypeEx property |
+| | | | (converted upnp:class property) of the |
+| | | | object that was changed. |
|------------------------------------------------------------------------------|
-| b | M | True if the object was modified as part of a subtree update |
+| Type | s | o | Contains the value of the Type property |
+| | | | (converted upnp:class property) of the object |
+| | | | that was changed. |
|------------------------------------------------------------------------------|
-|------------------------------------------------------------------------------|
-| Dictionary value for key "DEL": Format (oub) |
-|------------------------------------------------------------------------------|
-| o | M | Contains the Object Path property of the object that was deleted. |
-|------------------------------------------------------------------------------|
-| u | M | Contains the value of the SystemUpdateID when the object was added. |
-|------------------------------------------------------------------------------|
-| b | M | True if the object was deleted as part of a subtree update |
-|------------------------------------------------------------------------------|
-
-|------------------------------------------------------------------------------|
-| Dictionary value for key "DONE": Format (ou) |
-|------------------------------------------------------------------------------|
-| o | M | Contains the Object Path of the updated sub-tree |
-|------------------------------------------------------------------------------|
-| u | M | Contains the value of the SystemUpdateID when the object was added. |
-|------------------------------------------------------------------------------|
-
-
ContainerUpdateIDs(a(ou) ContainerPathsIDs)
Is generated when the contents of one or more folders maintained by the
diff --git a/libdleyna/server/device.c b/libdleyna/server/device.c
index 4864f43..612a85d 100644
--- a/libdleyna/server/device.c
+++ b/libdleyna/server/device.c
@@ -98,6 +98,15 @@ struct prv_new_device_ct_t_ {
GHashTable *property_map;
};
+enum prv_changed_event_type_t_ {
+ PRV_CHANGED_EVENT_ADD = 1,
+ PRV_CHANGED_EVENT_MOD,
+ PRV_CHANGED_EVENT_DEL,
+ PRV_CHANGED_EVENT_DONE,
+ PRV_CHANGED_EVENT_CONTAINER
+};
+typedef enum prv_changed_event_type_t_ prv_changed_event_type_t;
+
static void prv_get_child_count(dls_async_task_t *cb_data,
dls_device_count_cb_t cb, const gchar *id);
static void prv_retrieve_child_count_for_list(dls_async_task_t *cb_data);
@@ -265,16 +274,19 @@ static void prv_last_change_decode(GUPnPCDSLastChangeEntry *entry,
const char *root_path)
{
GUPnPCDSLastChangeEvent event;
- GVariant *state;
const char *object_id;
const char *parent_id;
const char *mclass;
const char *media_class;
- char *key[] = {"ADD", "DEL", "MOD", "DONE"};
+ const char *media_class_ex;
char *parent_path;
char *path = NULL;
gboolean sub_update;
guint32 update_id;
+ GVariantBuilder *dict;
+ gboolean mod;
+
+ dict = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
object_id = gupnp_cds_last_change_entry_get_object_id(entry);
if (!object_id)
@@ -295,21 +307,79 @@ static void prv_last_change_decode(GUPnPCDSLastChangeEntry *entry,
if (!mclass)
goto on_error;
- media_class = dls_props_upnp_class_to_media_spec_ex(mclass);
+ media_class = dls_props_upnp_class_to_media_spec(mclass);
if (!media_class)
goto on_error;
+ media_class_ex = dls_props_upnp_class_to_media_spec_ex(mclass);
+
parent_path = dls_path_from_id(root_path, parent_id);
- state = g_variant_new("(oubos)", path, update_id, sub_update,
- parent_path, media_class);
+
+ g_variant_builder_add(
+ dict, "{sv}",
+ DLS_INTERFACE_PROP_CHANGE_TYPE,
+ g_variant_new_uint32(PRV_CHANGED_EVENT_ADD));
+ g_variant_builder_add(
+ dict, "{sv}",
+ DLS_INTERFACE_PROP_PATH,
+ g_variant_new_string(path));
+ g_variant_builder_add(
+ dict, "{sv}",
+ DLS_INTERFACE_PROP_UPDATE_ID,
+ g_variant_new_uint32(update_id));
+ g_variant_builder_add(
+ dict, "{sv}",
+ DLS_INTERFACE_PROP_SUBTREE_UPDATE,
+ g_variant_new_boolean(sub_update));
+ g_variant_builder_add(
+ dict, "{sv}",
+ DLS_INTERFACE_PROP_PARENT,
+ g_variant_new_string(parent_path));
+ g_variant_builder_add(
+ dict, "{sv}",
+ DLS_INTERFACE_PROP_TYPE,
+ g_variant_new_string(media_class));
+ g_variant_builder_add(
+ dict, "{sv}",
+ DLS_INTERFACE_PROP_TYPE_EX,
+ g_variant_new_string(media_class_ex));
+
g_free(parent_path);
break;
case GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_REMOVED:
case GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_MODIFIED:
- state = g_variant_new("(oub)", path, update_id, sub_update);
+ mod = (event == GUPNP_CDS_LAST_CHANGE_EVENT_OBJECT_MODIFIED);
+ g_variant_builder_add(
+ dict, "{sv}",
+ DLS_INTERFACE_PROP_CHANGE_TYPE,
+ g_variant_new_uint32(mod ? PRV_CHANGED_EVENT_MOD :
+ PRV_CHANGED_EVENT_DEL));
+ g_variant_builder_add(
+ dict, "{sv}",
+ DLS_INTERFACE_PROP_PATH,
+ g_variant_new_string(path));
+ g_variant_builder_add(
+ dict, "{sv}",
+ DLS_INTERFACE_PROP_UPDATE_ID,
+ g_variant_new_uint32(update_id));
+ g_variant_builder_add(
+ dict, "{sv}",
+ DLS_INTERFACE_PROP_SUBTREE_UPDATE,
+ g_variant_new_boolean(sub_update));
break;
case GUPNP_CDS_LAST_CHANGE_EVENT_ST_DONE:
- state = g_variant_new("(ou)", path, update_id);
+ g_variant_builder_add(
+ dict, "{sv}",
+ DLS_INTERFACE_PROP_CHANGE_TYPE,
+ g_variant_new_uint32(PRV_CHANGED_EVENT_DONE));
+ g_variant_builder_add(
+ dict, "{sv}",
+ DLS_INTERFACE_PROP_PATH,
+ g_variant_new_string(path));
+ g_variant_builder_add(
+ dict, "{sv}",
+ DLS_INTERFACE_PROP_UPDATE_ID,
+ g_variant_new_uint32(update_id));
break;
case GUPNP_CDS_LAST_CHANGE_EVENT_INVALID:
default:
@@ -317,10 +387,12 @@ static void prv_last_change_decode(GUPnPCDSLastChangeEntry *entry,
break;
}
- g_variant_builder_add(array, "(sv)", key[event - 1], state);
+ g_variant_builder_add(array, "@a{sv}", g_variant_builder_end(dict));
+
on_error:
+ g_variant_builder_unref(dict);
g_free(path);
}
@@ -354,7 +426,7 @@ static void prv_last_change_cb(GUPnPServiceProxy *proxy,
goto on_error;
}
- g_variant_builder_init(&array, G_VARIANT_TYPE("a(sv)"));
+ g_variant_builder_init(&array, G_VARIANT_TYPE("aa{sv}"));
next = list;
while (next) {
prv_last_change_decode(next->data, &array, device->path);
@@ -362,12 +434,12 @@ static void prv_last_change_cb(GUPnPServiceProxy *proxy,
next = g_list_next(next);
}
- val = g_variant_new("(@a(sv))", g_variant_builder_end(&array));
+ val = g_variant_new("(@aa{sv})", g_variant_builder_end(&array));
(void) dls_server_get_connector()->notify(device->connection,
device->path,
DLEYNA_SERVER_INTERFACE_MEDIA_DEVICE,
- DLS_INTERFACE_ESV_LAST_CHANGE,
+ DLS_INTERFACE_CHANGED_EVENT,
val,
NULL);
@@ -407,6 +479,44 @@ static void prv_build_container_update_array(const gchar *root_path,
g_strfreev(str_array);
}
+static void prv_build_container_update_changed_array(const gchar *root_path,
+ const gchar *value,
+ GVariantBuilder *builder)
+{
+ gchar **str_array;
+ int pos = 0;
+ gchar *path;
+ guint id;
+ GVariantBuilder dict;
+
+ str_array = g_strsplit(value, ",", 0);
+
+ while (str_array[pos] && str_array[pos + 1]) {
+ g_variant_builder_init(&dict, G_VARIANT_TYPE("a{sv}"));
+
+ path = dls_path_from_id(root_path, str_array[pos++]);
+ id = atoi(str_array[pos++]);
+
+ g_variant_builder_add(
+ &dict, "{sv}",
+ DLS_INTERFACE_PROP_CHANGE_TYPE,
+ g_variant_new_uint32(PRV_CHANGED_EVENT_CONTAINER));
+ g_variant_builder_add(&dict, "{sv}",
+ DLS_INTERFACE_PROP_PATH,
+ g_variant_new_string(path));
+ g_variant_builder_add(&dict, "{sv}",
+ DLS_INTERFACE_PROP_UPDATE_ID,
+ g_variant_new_uint32(id));
+
+ g_variant_builder_add(builder, "@a{sv}",
+ g_variant_builder_end(&dict));
+
+ g_free(path);
+ }
+
+ g_strfreev(str_array);
+}
+
static void prv_container_update_cb(GUPnPServiceProxy *proxy,
const char *variable,
GValue *value,
@@ -429,6 +539,25 @@ static void prv_container_update_cb(GUPnPServiceProxy *proxy,
g_variant_new("(@a(ou))",
g_variant_builder_end(&array)),
NULL);
+
+ if (!device->has_last_change) {
+ g_variant_builder_init(&array, G_VARIANT_TYPE("aa{sv}"));
+
+ prv_build_container_update_changed_array(
+ device->path,
+ g_value_get_string(value),
+ &array);
+
+ (void) dls_server_get_connector()->notify(
+ device->connection,
+ device->path,
+ DLEYNA_SERVER_INTERFACE_MEDIA_DEVICE,
+ DLS_INTERFACE_CHANGED_EVENT,
+ g_variant_new("(@aa{sv})",
+ g_variant_builder_end(
+ &array)),
+ NULL);
+ }
}
static void prv_system_update_cb(GUPnPServiceProxy *proxy,
@@ -870,6 +999,9 @@ static void prv_get_search_capabilities_cb(GUPnPServiceProxy *proxy,
prv_get_capabilities_analyze(priv_t->property_map, result,
&priv_t->dev->search_caps);
+ if (g_hash_table_lookup(priv_t->property_map, "upnp:objectUpdateID"))
+ priv_t->dev->has_last_change = TRUE;
+
on_error:
if (error)
diff --git a/libdleyna/server/device.h b/libdleyna/server/device.h
index 530f976..6771464 100644
--- a/libdleyna/server/device.h
+++ b/libdleyna/server/device.h
@@ -63,6 +63,7 @@ struct dls_device_t_ {
GVariant *sort_ext_caps;
GVariant *feature_list;
gboolean shutting_down;
+ gboolean has_last_change;
guint construct_step;
dls_device_icon_t icon;
};
diff --git a/libdleyna/server/interface.h b/libdleyna/server/interface.h
index 57f6dea..f8cb6c6 100644
--- a/libdleyna/server/interface.h
+++ b/libdleyna/server/interface.h
@@ -123,6 +123,11 @@ enum dls_interface_type_ {
/* Evented State Variable Properties */
#define DLS_INTERFACE_PROP_ESV_SYSTEM_UPDATE_ID "SystemUpdateID"
+/* Changed event properties */
+#define DLS_INTERFACE_PROP_CHANGE_TYPE "ChangeType"
+#define DLS_INTERFACE_PROP_UPDATE_ID "UpdateID"
+#define DLS_INTERFACE_PROP_SUBTREE_UPDATE "SubTreeUpdate"
+
#define DLS_INTERFACE_GET_VERSION "GetVersion"
#define DLS_INTERFACE_GET_SERVERS "GetServers"
#define DLS_INTERFACE_RESCAN "Rescan"
@@ -180,8 +185,8 @@ enum dls_interface_type_ {
#define DLS_INTERFACE_INVALIDATED_PROPERTIES "InvalidatedProperties"
#define DLS_INTERFACE_ESV_CONTAINER_UPDATE_IDS "ContainerUpdateIDs"
#define DLS_INTERFACE_CONTAINER_PATHS_ID "ContainerPathsIDs"
-#define DLS_INTERFACE_ESV_LAST_CHANGE "LastChange"
-#define DLS_INTERFACE_LAST_CHANGE_STATE_EVENT "StateEvent"
+#define DLS_INTERFACE_CHANGED_EVENT "Changed"
+#define DLS_INTERFACE_CHANGED_OBJECTS "ChangedObjects"
#define DLS_INTERFACE_DELETE "Delete"
diff --git a/libdleyna/server/server.c b/libdleyna/server/server.c
index 10e01c0..20c5704 100644
--- a/libdleyna/server/server.c
+++ b/libdleyna/server/server.c
@@ -513,9 +513,8 @@ static const gchar g_server_introspection[] =
" <signal name='"DLS_INTERFACE_ESV_CONTAINER_UPDATE_IDS"'>"
" <arg type='a(ou)' name='"DLS_INTERFACE_CONTAINER_PATHS_ID"'/>"
" </signal>"
- " <signal name='"DLS_INTERFACE_ESV_LAST_CHANGE"'>"
- " <arg type='a(sv)' name='"
- DLS_INTERFACE_LAST_CHANGE_STATE_EVENT"'/>"
+ " <signal name='"DLS_INTERFACE_CHANGED_EVENT"'>"
+ " <arg type='aa{sv}' name='"DLS_INTERFACE_CHANGED_OBJECTS"'/>"
" </signal>"
" <signal name='"DLS_INTERFACE_UPLOAD_UPDATE"'>"
" <arg type='u' name='"DLS_INTERFACE_UPLOAD_ID"'/>"
diff --git a/test/dbus/monitor_last_change.py b/test/dbus/monitor_changed.py
index d831ff2..ff32138 100755
--- a/test/dbus/monitor_last_change.py
+++ b/test/dbus/monitor_changed.py
@@ -29,19 +29,19 @@ import json
def print_properties(props):
print json.dumps(props, indent=4, sort_keys=True)
-def last_change(state_event, path):
- print "LastChange signal from [%s]" % path
- print "State Event:"
- print_properties(state_event)
+def changed(objects, path):
+ print "Changed signal from [%s]" % path
+ print "Objects:"
+ print_properties(objects)
if __name__ == '__main__':
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
bus = dbus.SessionBus()
- bus.add_signal_receiver(last_change,
+ bus.add_signal_receiver(changed,
bus_name="com.intel.dleyna-server",
- signal_name = "LastChange",
+ signal_name = "Changed",
path_keyword="path")
mainloop = gobject.MainLoop()