Commit f434d30c authored by Jens Georg's avatar Jens Georg

service-proxy: Add new API for calling actions

parent 45d56850
<?xml version="1.0"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
<?xml version='1.0' encoding='UTF-8'?>
<!-- This document was created with Syntext Serna Free. -->
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" []>
<chapter id="client-tutorial">
<title>Writing a UPnP Client</title>
<title>Writing an UPnP Client</title>
<simplesect>
<title>Introduction</title>
<para>
......@@ -12,15 +11,13 @@
<glossterm>Control Point</glossterm> is created, which searches for
services of the type
<literal>urn:schemas-upnp-org:service:WANIPConnection:1</literal> (part of
the <ulink url="http://upnp.org/standardizeddcps/igd.asp">Internet Gateway
Device</ulink> specification). As services are discovered
the <ulink url="http://upnp.org/standardizeddcps/igd.asp">Internet Gateway Device</ulink> specification). As services are discovered
<firstterm>Service Proxy</firstterm> objects are created by GUPnP to allow
interaction with the service, on which we can invoke the action
<function>GetExternalIPAddress</function> to fetch the external IP
address.
</para>
</simplesect>
<simplesect>
<title>Finding Services</title>
<para>
......@@ -45,27 +42,22 @@ main (int argc, char **argv)
{
GUPnPContext *context;
GUPnPControlPoint *cp;
/* Required initialisation */
#if !GLIB_CHECK_VERSION(2,35,0)
g_type_init ();
#endif
/* Create a new GUPnP Context. By here we are using the default GLib main
context, and connecting to the current machine's default IP on an
context, and connecting to the current machine&apos;s default IP on an
automatically generated port. */
context = gupnp_context_new (NULL, NULL, 0, NULL);
context = gupnp_context_new (NULL, 0, NULL);
/* Create a Control Point targeting WAN IP Connection services */
cp = gupnp_control_point_new
(context, "urn:schemas-upnp-org:service:WANIPConnection:1");
(context, &quot;urn:schemas-upnp-org:service:WANIPConnection:1&quot;);
/* The service-proxy-available signal is emitted when any services which match
our target are found, so connect to it */
g_signal_connect (cp,
"service-proxy-available",
G_CALLBACK (service_proxy_available_cb),
NULL);
&quot;service-proxy-available&quot;,
G_CALLBACK (service_proxy_available_cb),
NULL);
/* Tell the Control Point to start searching */
gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (cp), TRUE);
......@@ -83,7 +75,6 @@ main (int argc, char **argv)
return 0;
}</programlisting>
</simplesect>
<simplesect>
<title>Invoking Actions</title>
<para>
......@@ -91,7 +82,7 @@ main (int argc, char **argv)
calls <function>service_proxy_available_cb</function> for each one it
found. To get the external IP address we need to invoke the
<literal>GetExternalIPAddress</literal> action. This action takes no in
arguments, and has a single out argument called "NewExternalIPAddress".
arguments, and has a single out argument called &quot;NewExternalIPAddress&quot;.
GUPnP has a set of methods to invoke actions (which will be very familiar
to anyone who has used <literal>dbus-glib</literal>) where you pass a
<constant>NULL</constant>-terminated varargs list of (name, GType, value)
......@@ -106,39 +97,54 @@ service_proxy_available_cb (GUPnPControlPoint *cp,
{
GError *error = NULL;
char *ip = NULL;
GUPnPServiceProxyAction *action = NULL;
gupnp_service_proxy_send_action (proxy,
/* Action name and error location */
"GetExternalIPAddress", &amp;error,
/* IN args */
NULL,
/* OUT args */
"NewExternalIPAddress",
G_TYPE_STRING, &amp;ip,
NULL);
action = gupnp_service_proxy_action_new (
/* Action name */
&quot;GetExternalIPAddress&quot;,
/* IN args */
NULL);
gupnp_service_proxy_call_action (proxy,
action,
NULL,
&amp;error);
if (error != NULL) {
goto out;
}
gupnp_service_proxy_action_get_result (action,
/* Error location */
&amp;error,
/* OUT args */
&quot;NewExternalIPAddress&quot;,
G_TYPE_STRING, &amp;ip,
NULL);
if (error == NULL) {
g_print ("External IP address is %s\n", ip);
g_print (&quot;External IP address is %s\n&quot;, ip);
g_free (ip);
} else {
g_printerr ("Error: %s\n", error-&gt;message);
}
out:
if (error != NULL) {
g_printerr (&quot;Error: %s\n&quot;, error-&gt;message);
g_error_free (error);
}
gupnp_service_proxy_action_unref (action);
g_main_loop_quit (main_loop);
}</programlisting>
<para>
Note that gupnp_service_proxy_send_action() blocks until the service has
<para>Note that gupnp_service_proxy_call_action() blocks until the service has
replied. If you need to make non-blocking calls then use
gupnp_service_proxy_begin_action(), which takes a callback that will be
gupnp_service_proxy_call_action_async(), which takes a callback that will be
called from the mainloop when the reply is received.
</para>
</simplesect>
<simplesect>
<title>Subscribing to state variable change notifications</title>
<para>
It is possible to get change notifications for the service state variables
that have attribute <literal>sendEvents="yes"</literal>. We'll demonstrate
that have attribute <literal>sendEvents=&quot;yes&quot;</literal>. We&apos;ll demonstrate
this by modifying <function>service_proxy_available_cb</function> and using
gupnp_service_proxy_add_notify() to setup a notification callback:
</para>
......@@ -148,7 +154,7 @@ external_ip_address_changed (GUPnPServiceProxy *proxy,
GValue *value,
gpointer userdata)
{
g_print ("External IP address changed: %s\n", g_value_get_string (value));
g_print (&quot;External IP address changed: %s\n&quot;, g_value_get_string (value));
}
static void
......@@ -156,29 +162,28 @@ service_proxy_available_cb (GUPnPControlPoint *cp,
GUPnPServiceProxy *proxy,
gpointer userdata)
{
g_print ("Found a WAN IP Connection service\n");
g_print (&quot;Found a WAN IP Connection service\n&quot;);
gupnp_service_proxy_set_subscribed (proxy, TRUE);
if (!gupnp_service_proxy_add_notify (proxy,
"ExternalIPAddress",
&quot;ExternalIPAddress&quot;,
G_TYPE_STRING,
external_ip_address_changed,
NULL)) {
g_printerr ("Failed to add notify");
g_printerr (&quot;Failed to add notify&quot;);
}
}</programlisting>
</simplesect>
<simplesect>
<title>Generating Wrappers</title>
<para>
Using gupnp_service_proxy_send_action() and gupnp_service_proxy_add_notify ()
Using gupnp_service_proxy_call_action() and gupnp_service_proxy_add_notify ()
can become tedious, because of the requirement to specify the types and deal
with GValues. An
alternative is to use <xref linkend="gupnp-binding-tool"/>, which
generates wrappers that hide the boilerplate code from you. Using a
wrapper generated with prefix 'ipconn' would replace
gupnp_service_proxy_send_action() with this code:
wrapper generated with prefix &apos;ipconn&apos; would replace
gupnp_service_proxy_call_action() with this code:
</para>
<programlisting>ipconn_get_external_ip_address (proxy, &amp;ip, &amp;error);</programlisting>
<para>
......@@ -189,7 +194,7 @@ external_ip_address_changed (GUPnPServiceProxy *proxy,
const gchar *external_ip_address,
gpointer userdata)
{
g_print ("External IP address changed: '%s'\n", external_ip_address);
g_print (&quot;External IP address changed: &apos;%s&apos;\n&quot;, external_ip_address);
}
static void
......@@ -197,13 +202,13 @@ service_proxy_available_cb (GUPnPControlPoint *cp,
GUPnPServiceProxy *proxy
gpointer userdata)
{
g_print ("Found a WAN IP Connection service\n");
g_print (&quot;Found a WAN IP Connection service\n&quot;);
gupnp_service_proxy_set_subscribed (proxy, TRUE);
if (!ipconn_external_ip_address_add_notify (proxy,
external_ip_address_changed,
NULL)) {
g_printerr ("Failed to add notify");
g_printerr (&quot;Failed to add notify&quot;);
}
}</programlisting>
</simplesect>
......
......@@ -71,6 +71,9 @@ GUPnPServiceProxy
GUPnPServiceProxyAction
GUPnPServiceProxyActionCallback
GUPnPServiceProxyNotifyCallback
gupnp_service_proxy_call_action
gupnp_service_proxy_call_action_async
gupnp_service_proxy_call_action_finish
gupnp_service_proxy_send_action
gupnp_service_proxy_send_action_valist
gupnp_service_proxy_send_action_list
......@@ -89,6 +92,14 @@ gupnp_service_proxy_remove_notify
gupnp_service_proxy_remove_raw_notify
gupnp_service_proxy_set_subscribed
gupnp_service_proxy_get_subscribed
gupnp_service_proxy_action_get_result
gupnp_service_proxy_action_get_result_hash
gupnp_service_proxy_action_get_result_list
gupnp_service_proxy_action_get_type
gupnp_service_proxy_action_new
gupnp_service_proxy_action_new_from_list
gupnp_service_proxy_action_ref
gupnp_service_proxy_action_unref
<SUBSECTION Standard>
GUPnPServiceProxyClass
GUPNP_SERVICE_PROXY
......
......@@ -39,16 +39,28 @@ send_cmd (GUPnPServiceProxy *proxy)
GError *error = NULL;
gboolean target;
GUPnPServiceProxyAction *action;
if (mode == TOGGLE) {
/* We're toggling, so first fetch the current status */
if (!gupnp_service_proxy_send_action
(proxy, "GetStatus", &error,
/* IN args */ NULL,
/* OUT args */ "ResultStatus", G_TYPE_BOOLEAN, &target, NULL)) {
action = gupnp_service_proxy_action_new ("GetStatus", NULL);
gupnp_service_proxy_call_action (proxy, action, NULL, &error);
if (error != NULL)
goto error;
}
gupnp_service_proxy_action_get_result (action,
&error,
"ResultStatus", G_TYPE_BOOLEAN, &target, NULL);
g_clear_pointer (&action, gupnp_service_proxy_action_unref);
if (error != NULL)
goto error;
/* And then toggle it */
target = ! target;
} else {
/* Mode is a boolean, so the target is the mode thanks to our well chosen
enumeration values. */
......@@ -56,12 +68,13 @@ send_cmd (GUPnPServiceProxy *proxy)
}
/* Set the target */
if (!gupnp_service_proxy_send_action (proxy, "SetTarget", &error,
/* IN args */
"newTargetValue", G_TYPE_BOOLEAN, target, NULL,
/* OUT args */
NULL)) {
goto error;
action = gupnp_service_proxy_action_new ("SetTarget",
"newTargetValue", G_TYPE_BOOLEAN, target, NULL);
gupnp_service_proxy_call_action (proxy, action, NULL, &error);
g_clear_pointer (&action, gupnp_service_proxy_action_unref);
if (error != NULL) {
goto error;
} else {
if (!quiet) {
g_print ("Set switch to %s.\n", target ? "on" : "off");
......@@ -76,6 +89,7 @@ send_cmd (GUPnPServiceProxy *proxy)
return;
error:
g_clear_pointer (&action, gupnp_service_proxy_action_unref);
g_printerr ("Cannot set switch: %s\n", error->message);
g_error_free (error);
goto done;
......
/*
* Copyright (C) 2018,2019 The GUPnP maintainers.
*
* Author: Jens Georg <mail@jensge.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef GUPNP_SERVICE_PROXY_ACTION_H
#define GUPNP_SERVICE_PROXY_ACTION_H
#include <gobject/gvaluecollector.h>
G_BEGIN_DECLS
/* Initializes hash table to hold arg names as keys and GValues of
* given type and value.
*/
#define VAR_ARGS_TO_IN_LIST(var_args, names, values) \
G_STMT_START { \
const gchar *arg_name = va_arg (var_args, const gchar *); \
\
while (arg_name != NULL) { \
GValue *value = g_new0 (GValue, 1); \
gchar *__error = NULL; \
GType type = va_arg (var_args, GType); \
\
G_VALUE_COLLECT_INIT (value, \
type, \
var_args, \
G_VALUE_NOCOPY_CONTENTS, \
&__error); \
if (__error == NULL) { \
names = g_list_prepend (names, g_strdup (arg_name)); \
values = g_list_prepend (values, value); \
} else { \
g_warning ("Failed to collect value of type %s for %s: %s", \
g_type_name (type), \
arg_name, \
__error); \
g_free (__error); \
} \
arg_name = va_arg (var_args, const gchar *); \
} \
names = g_list_reverse (names); \
values = g_list_reverse (values); \
} G_STMT_END
/* This is a skip variant of G_VALUE_LCOPY, same as there is
* G_VALUE_COLLECT_SKIP for G_VALUE_COLLECT.
*/
#define VALUE_LCOPY_SKIP(value_type, var_args) \
G_STMT_START { \
GTypeValueTable *_vtable = g_type_value_table_peek (value_type); \
const gchar *_lcopy_format = _vtable->lcopy_format; \
\
while (*_lcopy_format) { \
switch (*_lcopy_format++) { \
case G_VALUE_COLLECT_INT: \
va_arg ((var_args), gint); \
break; \
case G_VALUE_COLLECT_LONG: \
va_arg ((var_args), glong); \
break; \
case G_VALUE_COLLECT_INT64: \
va_arg ((var_args), gint64); \
break; \
case G_VALUE_COLLECT_DOUBLE: \
va_arg ((var_args), gdouble); \
break; \
case G_VALUE_COLLECT_POINTER: \
va_arg ((var_args), gpointer); \
break; \
default: \
g_assert_not_reached (); \
} \
} \
} G_STMT_END
/* Initializes hash table to hold arg names as keys and GValues of
* given type, but without any specific value. Note that if you are
* going to use OUT_HASH_TABLE_TO_VAR_ARGS then you have to store a
* copy of var_args with G_VA_COPY before using this macro.
*/
#define VAR_ARGS_TO_OUT_HASH_TABLE(var_args, hash) \
G_STMT_START { \
const gchar *arg_name = va_arg (var_args, const gchar *); \
\
while (arg_name != NULL) { \
GValue *value = g_new0 (GValue, 1); \
GType type = va_arg (var_args, GType); \
\
VALUE_LCOPY_SKIP (type, var_args); \
g_value_init (value, type); \
g_hash_table_insert (hash, g_strdup (arg_name), value); \
arg_name = va_arg (var_args, const gchar *); \
} \
} G_STMT_END
/* Puts values stored in hash table with GValues into var args.
*/
#define OUT_HASH_TABLE_TO_VAR_ARGS(hash, var_args) \
G_STMT_START { \
const gchar *arg_name = va_arg (var_args, const gchar *); \
\
while (arg_name != NULL) { \
GValue *value = g_hash_table_lookup (hash, arg_name); \
GType type = va_arg (var_args, GType); \
\
if (value == NULL) { \
g_warning ("No value for %s", arg_name); \
G_VALUE_COLLECT_SKIP (type, var_args); \
} else if (G_VALUE_TYPE (value) != type) { \
g_warning ("Different GType in value (%s) and in var args (%s) for %s.", \
G_VALUE_TYPE_NAME (value), \
g_type_name (type), \
arg_name); \
} else { \
gchar *__error = NULL; \
\
G_VALUE_LCOPY (value, var_args, 0, &__error); \
if (__error != NULL) { \
g_warning ("Failed to lcopy the value of type %s for %s: %s", \
g_type_name (type), \
arg_name, \
__error); \
g_free (__error); \
} \
} \
arg_name = va_arg (var_args, const gchar *); \
} \
} G_STMT_END
struct _GUPnPServiceProxyAction {
GUPnPServiceProxy *proxy;
char *name;
gint header_pos;
SoupMessage *msg;
GString *msg_str;
GCancellable *cancellable;
gulong cancellable_connection_id;
GUPnPServiceProxyActionCallback callback;
gpointer user_data;
GError *error; /* If non-NULL, description of error that
occurred when preparing message */
};
G_GNUC_INTERNAL GUPnPServiceProxyAction *
gupnp_service_proxy_action_new_internal (const char *action);
G_GNUC_INTERNAL gboolean
gupnp_service_proxy_action_get_result_valist (GUPnPServiceProxyAction *action,
GError **error,
va_list var_args);
G_END_DECLS
#endif /* GUPNP_SERVICE_PROXY_ACTION_H */
This diff is collapsed.
#ifndef GUPNP_SERVICE_PROXY_PRIVATE_H
#define GUPNP_SERVICE_PROXY_PRIVATE_H
#include "gupnp-service-proxy.h"
G_BEGIN_DECLS
G_GNUC_INTERNAL void
gupnp_service_proxy_remove_action (GUPnPServiceProxy *proxy,
GUPnPServiceProxyAction *action);
G_END_DECLS
#endif /* GUPNP_SERVICE_PROXY_ACTION_H */
This diff is collapsed.
......@@ -89,20 +89,20 @@ typedef void (* GUPnPServiceProxyNotifyCallback) (GUPnPServiceProxy *proxy,
GValue *value,
gpointer user_data);
gboolean
G_GNUC_DEPRECATED gboolean
gupnp_service_proxy_send_action (GUPnPServiceProxy *proxy,
const char *action,
GError **error,
...) G_GNUC_NULL_TERMINATED;
gboolean
G_GNUC_DEPRECATED gboolean
gupnp_service_proxy_send_action_valist
(GUPnPServiceProxy *proxy,
const char *action,
GError **error,
va_list var_args);
gboolean
G_GNUC_DEPRECATED gboolean
gupnp_service_proxy_send_action_list (GUPnPServiceProxy *proxy,
const char *action,
GList *in_names,
......@@ -111,14 +111,14 @@ gupnp_service_proxy_send_action_list (GUPnPServiceProxy *proxy,
GList *out_types,
GList **out_values,
GError **error);
GUPnPServiceProxyAction *
G_GNUC_DEPRECATED GUPnPServiceProxyAction *
gupnp_service_proxy_begin_action (GUPnPServiceProxy *proxy,
const char *action,
GUPnPServiceProxyActionCallback callback,
gpointer user_data,
...) G_GNUC_NULL_TERMINATED;
GUPnPServiceProxyAction *
G_GNUC_DEPRECATED GUPnPServiceProxyAction *
gupnp_service_proxy_begin_action_valist
(GUPnPServiceProxy *proxy,
const char *action,
......@@ -126,7 +126,7 @@ gupnp_service_proxy_begin_action_valist
gpointer user_data,
va_list var_args);
GUPnPServiceProxyAction *
G_GNUC_DEPRECATED GUPnPServiceProxyAction *
gupnp_service_proxy_begin_action_list
(GUPnPServiceProxy *proxy,
const char *action,
......@@ -135,20 +135,20 @@ gupnp_service_proxy_begin_action_list
GUPnPServiceProxyActionCallback callback,
gpointer user_data);
gboolean
G_GNUC_DEPRECATED gboolean
gupnp_service_proxy_end_action (GUPnPServiceProxy *proxy,
GUPnPServiceProxyAction *action,
GError **error,
...) G_GNUC_NULL_TERMINATED;
gboolean
G_GNUC_DEPRECATED gboolean
gupnp_service_proxy_end_action_valist
(GUPnPServiceProxy *proxy,
GUPnPServiceProxyAction *action,
GError **error,
va_list var_args);
gboolean
G_GNUC_DEPRECATED gboolean
gupnp_service_proxy_end_action_list
(GUPnPServiceProxy *proxy,
GUPnPServiceProxyAction *action,
......@@ -157,14 +157,14 @@ gupnp_service_proxy_end_action_list
GList **out_values,
GError **error);
gboolean
G_GNUC_DEPRECATED gboolean
gupnp_service_proxy_end_action_hash
(GUPnPServiceProxy *proxy,
GUPnPServiceProxyAction *action,
GHashTable *hash,
GError **error);
void
G_GNUC_DEPRECATED void
gupnp_service_proxy_cancel_action (GUPnPServiceProxy *proxy,
GUPnPServiceProxyAction *action);
......@@ -208,6 +208,58 @@ gupnp_service_proxy_set_subscribed (GUPnPServiceProxy *proxy,
gboolean
gupnp_service_proxy_get_subscribed (GUPnPServiceProxy *proxy);
/* New action API */
GUPnPServiceProxyAction *
gupnp_service_proxy_action_new (const char *action,
...) G_GNUC_NULL_TERMINATED;
GUPnPServiceProxyAction *
gupnp_service_proxy_action_new_from_list (const char *action,
GList *in_names,
GList *in_values);
GUPnPServiceProxyAction *
gupnp_service_proxy_action_ref (GUPnPServiceProxyAction *action);
void
gupnp_service_proxy_action_unref (GUPnPServiceProxyAction *action);
gboolean
gupnp_service_proxy_action_get_result (GUPnPServiceProxyAction *action,
GError **error,
...) G_GNUC_NULL_TERMINATED;
gboolean
gupnp_service_proxy_action_get_result_list (GUPnPServiceProxyAction *action,
GList *out_names,
GList *out_types,
GList **out_values,
GError **error);
gboolean
gupnp_service_proxy_action_get_result_hash (GUPnPServiceProxyAction *action,
GHashTable *out_hash,
GError **error);
GUPnPServiceProxyAction *
gupnp_service_proxy_call_action_async (GUPnPServiceProxy *proxy,
GUPnPServiceProxyAction *action,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GUPnPServiceProxyAction *
gupnp_service_proxy_call_action_finish (GUPnPServiceProxy *proxy,
GAsyncResult *result,
GError **error);
GUPnPServiceProxyAction *
gupnp_service_proxy_call_action (GUPnPServiceProxy *proxy,
GUPnPServiceProxyAction *action,
GCancellable *cancellable,
GError **error);
G_END_DECLS
......
......@@ -264,3 +264,14 @@ gvalue_util_value_append_to_xml_string (const GValue *value,
}
}
}
/* GDestroyNotify for GHashTable holding GValues.
*/
void
gvalue_free (gpointer data)
{
GValue *value = (GValue *) data;
g_value_unset (value);
g_free (value);
}
......@@ -37,4 +37,7 @@ G_GNUC_INTERNAL gboolean
gvalue_util_value_append_to_xml_string (const GValue *value,
GString *str);
G_GNUC_INTERNAL void
gvalue_free (gpointer data);
#endif /* GUPNP_GVALUE_UTIL_H */
......@@ -80,6 +80,7 @@ sources = files(
'gupnp-service-info.c',
'gupnp-service-introspection.c',
'gupnp-service-proxy.c',
'gupnp-service-proxy-action.c',
'gupnp-simple-context-manager.c',
'gupnp-types.c',
'gupnp-white-list.c',
......
......@@ -243,6 +243,7 @@ test_bgo_696762 (void)
test_run_loop (data.loop);
g_assert (data.proxy != NULL);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
gupnp_service_proxy_begin_action (data.proxy,
"Browse",
test_bgo_696762_on_browse,
......@@ -254,6 +255,7 @@ test_bgo_696762 (void)
"RequestedCount", G_TYPE_UINT, 0,
"SortCriteria", G_TYPE_STRING, "",
NULL);
G_GNUC_END_IGNORE_DEPRECATIONS
test_run_loop (data.loop);
......
......@@ -61,6 +61,7 @@ service_proxy_available_cb (G_GNUC_UNUSED GUPnPControlPoint *cp,
char *result = NULL;
guint count, total;
GError *error = NULL;
GUPnPServiceProxyAction *action = NULL;
location = gupnp_service_info_get_location (GUPNP_SERVICE_INFO (proxy));
......@@ -84,9 +85,8 @@ service_proxy_available_cb (G_GNUC_UNUSED GUPnPControlPoint *cp,
gupnp_service_proxy_set_subscribed (proxy, TRUE);
/* And test action IO */
gupnp_service_proxy_send_action (proxy,
action = gupnp_service_proxy_action_new (
"Browse",
&error,
/* IN args */
"ObjectID",
G_TYPE_STRING,
......@@ -106,7 +106,19 @@ service_proxy_available_cb (G_GNUC_UNUSED GUPnPControlPoint *cp,
"SortCriteria",
G_TYPE_STRING,
"",
NULL,
NULL);
gupnp_service_proxy_call_action (proxy, action, NULL, &error);
if (error) {
g_printerr ("Error: %s\n", error->message);
g_error_free (error);
gupnp_service_proxy_action_unref (action);
return;
}
gupnp_service_proxy_action_get_result (action,
&error,
/* OUT args */
"Result",
G_TYPE_STRING,
......@@ -122,6 +134,7 @@ service_proxy_available_cb (G_GNUC_UNUSED GUPnPControlPoint *cp,
if (error) {
g_printerr ("Error: %s\n", error->message);
g_error_free (error);
gupnp_service_proxy_action_unref (action);
return;
}
......@@ -131,6 +144,7 @@ service_proxy_available_cb (G_GNUC_UNUSED GUPnPControlPoint *cp,
g_print ("\tNumberReturned: %u\n", count);
g_print ("\tTotalMatches: %u\n", total);
gupnp_service_proxy_action_unref (action);
g_free (result);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment