From d0fe0c7cc316dcb6f7150e84c657f100c4a22ad0 Mon Sep 17 00:00:00 2001 From: Mart Raudsepp Date: Fri, 21 Feb 2020 22:41:37 +0200 Subject: net-libs/dleyna-renderer: bump to 0.6.0 and use gupnp-1.2 Package-Manager: Portage-2.3.84, Repoman-2.3.20 Signed-off-by: Mart Raudsepp --- net-libs/dleyna-renderer/Manifest | 1 + .../dleyna-renderer/dleyna-renderer-0.6.0.ebuild | 45 + .../dleyna-renderer/files/0.6.0-gupnp-1.2.patch | 944 +++++++++++++++++++++ 3 files changed, 990 insertions(+) create mode 100644 net-libs/dleyna-renderer/dleyna-renderer-0.6.0.ebuild create mode 100644 net-libs/dleyna-renderer/files/0.6.0-gupnp-1.2.patch (limited to 'net-libs') diff --git a/net-libs/dleyna-renderer/Manifest b/net-libs/dleyna-renderer/Manifest index bfde6702fbc3..96110f36ad4e 100644 --- a/net-libs/dleyna-renderer/Manifest +++ b/net-libs/dleyna-renderer/Manifest @@ -1 +1,2 @@ DIST dleyna-renderer-0.5.0.tar.gz 378208 BLAKE2B 4a1b9e28310c2dd13baa9dccc1f35b2190b6af852da5a3a7ee77766affd7c52312e68b34a881652f3dbf6f71f0e25a69988ed2ff6ce897dc4f74c60793e06359 SHA512 28802057d6e0b7da24fd8abb11748faeb78ea6ef15ce85d83907497ff252c86cec1072a919e64bab6df0a375e0092c1281569802515fb87d9dc083098f1d4820 +DIST dleyna-renderer-0.6.0.tar.gz 65566 BLAKE2B cfd2b5a08b2e5c6e15006e722c4878281bf7f4b6d8a9bd317ec5b27fc1568a2ca891af2ac2fc3c230f65e9920bd524b4fbaf43631192b079b2aea051783d2b8a SHA512 f4cb6c658bfaf620962eb6b84ab6b41be1bb8455ac1ff358db7fcf3db7f5c4e2130bb7b0e5201005c738e892aabf25b3cf2a3e1cc1f4a9ef9d834789b87c0183 diff --git a/net-libs/dleyna-renderer/dleyna-renderer-0.6.0.ebuild b/net-libs/dleyna-renderer/dleyna-renderer-0.6.0.ebuild new file mode 100644 index 000000000000..d8d20888cdb8 --- /dev/null +++ b/net-libs/dleyna-renderer/dleyna-renderer-0.6.0.ebuild @@ -0,0 +1,45 @@ +# Copyright 1999-2020 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=7 + +inherit autotools + +DESCRIPTION="library implementing services that allow clients to discover and manipulate DLNA renderers" +HOMEPAGE="https://01.org/dleyna/" +SRC_URI="https://01.org/sites/default/files/downloads/dleyna/${P}.tar_2.gz -> ${P}.tar.gz" + +LICENSE="LGPL-2.1" +SLOT="0" +KEYWORDS="~amd64" +IUSE="" + +DEPEND=" + >=dev-libs/glib-2.28:2 + >=media-libs/gupnp-dlna-0.9.4:2.0 + >=net-libs/dleyna-core-0.6.0 + >=net-libs/gssdp-1.2.0:0= + >=net-libs/gupnp-1.2.0:0= + >=net-libs/gupnp-av-0.11.5 + >=net-libs/libsoup-2.28.2:2.4 +" +RDEPEND="${DEPEND} + net-libs/dleyna-connector-dbus +" +BDEPEND=" + virtual/pkgconfig +" + +PATCHES=( + "${FILESDIR}"/${PV}-gupnp-1.2.patch +) + +src_prepare() { + default + eautoreconf +} + +src_install() { + default + find "${ED}" -name "*.la" -delete || die +} diff --git a/net-libs/dleyna-renderer/files/0.6.0-gupnp-1.2.patch b/net-libs/dleyna-renderer/files/0.6.0-gupnp-1.2.patch new file mode 100644 index 000000000000..2fddca199444 --- /dev/null +++ b/net-libs/dleyna-renderer/files/0.6.0-gupnp-1.2.patch @@ -0,0 +1,944 @@ +https://github.com/intel/dleyna-renderer/pull/167 + +From 594015eac2757f629a32d043c9a9b10ff6c5f95f Mon Sep 17 00:00:00 2001 +From: Jens Georg +Date: Mon, 5 Nov 2018 22:07:09 +0100 +Subject: [PATCH 1/4] Use english for logging + +--- + libdleyna/renderer/device.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/libdleyna/renderer/device.c b/libdleyna/renderer/device.c +index 7acef89..032d394 100644 +--- a/libdleyna/renderer/device.c ++++ b/libdleyna/renderer/device.c +@@ -1201,7 +1201,7 @@ static void prv_add_actions(dlr_device_t *device, + continue; + } + +- DLEYNA_LOG_DEBUG("DLNA version ≥ 1.50 pour %s", ++ DLEYNA_LOG_DEBUG("DLNA version ≥ 1.50 for %s", + device->path); + timeseek_missing = TRUE; + g_free(dlna_device_class); + +From a588dd11e4c6d2ff6a7c1789fad913ab9c2519b5 Mon Sep 17 00:00:00 2001 +From: Jens Georg +Date: Sat, 21 Sep 2019 20:36:04 +0200 +Subject: [PATCH 2/4] Do service introspection on device creation + +Fixes #104 +Fixes #164 +--- + libdleyna/renderer/Makefile.am | 2 + + libdleyna/renderer/device.c | 411 ++++++++++++++++--------------- + libdleyna/renderer/gasync-task.c | 135 ++++++++++ + libdleyna/renderer/gasync-task.h | 57 +++++ + libdleyna/renderer/manager.c | 1 - + libdleyna/renderer/upnp.c | 14 +- + 6 files changed, 419 insertions(+), 201 deletions(-) + create mode 100644 libdleyna/renderer/gasync-task.c + create mode 100644 libdleyna/renderer/gasync-task.h + +diff --git a/libdleyna/renderer/Makefile.am b/libdleyna/renderer/Makefile.am +index ca601c7..ce4dc41 100644 +--- a/libdleyna/renderer/Makefile.am ++++ b/libdleyna/renderer/Makefile.am +@@ -22,6 +22,7 @@ libdleyna_renderer_1_0_la_LDFLAGS = -version-info $(DLEYNA_RENDERER_VERSION) \ + libdleyna_renderer_1_0_la_SOURCES = $(libdleyna_rendererinc_HEADERS) \ + async.c \ + device.c \ ++ gasync-task.c \ + host-service.c \ + manager.c \ + server.c \ +@@ -53,6 +54,7 @@ sysconf_DATA = dleyna-renderer-service.conf + EXTRA_DIST = $(sysconf_DATA) \ + async.h \ + device.h \ ++ gasync-task.h \ + host-service.h \ + prop-defs.h \ + manager.h \ +diff --git a/libdleyna/renderer/device.c b/libdleyna/renderer/device.c +index 032d394..73b3dd3 100644 +--- a/libdleyna/renderer/device.c ++++ b/libdleyna/renderer/device.c +@@ -26,15 +26,16 @@ + + #include + #include ++#include + #include + + #include + #include + #include +-#include + + #include "async.h" + #include "device.h" ++#include "gasync-task.h" + #include "prop-defs.h" + #include "server.h" + +@@ -675,21 +676,30 @@ static void prv_process_protocol_info(dlr_device_t *device, + DLEYNA_LOG_DEBUG("Exit"); + } + +-static void prv_get_protocol_info_cb(GUPnPServiceProxy *proxy, +- GUPnPServiceProxyAction *action, ++static void prv_get_protocol_info_cb(GObject *target, ++ GAsyncResult *res, + gpointer user_data) + { + gchar *result = NULL; + gboolean end; + GError *error = NULL; + prv_new_device_ct_t *priv_t = (prv_new_device_ct_t *)user_data; ++ GUPnPServiceProxyAction *action; + + DLEYNA_LOG_DEBUG("Enter"); + + priv_t->dev->construct_step++; + +- end = gupnp_service_proxy_end_action(proxy, action, &error, "Sink", +- G_TYPE_STRING, &result, NULL); ++ action = gupnp_service_proxy_call_action_finish(GUPNP_SERVICE_PROXY(target), res, &error); ++ ++ if (action == NULL || (error != NULL)) { ++ DLEYNA_LOG_WARNING("GetProtocolInfo operation failed: %s", ++ ((error != NULL) ? error->message ++ : "Invalid result")); ++ goto on_error; ++ } ++ ++ end = gupnp_service_proxy_action_get_result (action, &error, "Sink", G_TYPE_STRING, &result, NULL); + if (!end || (result == NULL)) { + DLEYNA_LOG_WARNING("GetProtocolInfo operation failed: %s", + ((error != NULL) ? error->message +@@ -701,6 +711,10 @@ static void prv_get_protocol_info_cb(GUPnPServiceProxy *proxy, + + on_error: + ++ if (action) { ++ gupnp_service_proxy_action_unref(action); ++ } ++ + if (error) + g_error_free(error); + +@@ -709,53 +723,193 @@ static void prv_get_protocol_info_cb(GUPnPServiceProxy *proxy, + DLEYNA_LOG_DEBUG("Exit"); + } + +-static GUPnPServiceProxyAction *prv_get_protocol_info( +- dleyna_service_task_t *task, +- GUPnPServiceProxy *proxy, +- gboolean *failed) ++static void prv_introspection_wrap_cb (GUPnPServiceInfo *info, ++ GUPnPServiceIntrospection *introspection, ++ const GError *error, ++ gpointer user_data) ++{ ++ if (error != NULL) { ++ g_task_return_error (G_TASK (user_data), ++ g_error_copy (error)); ++ } else { ++ g_task_return_pointer (G_TASK (user_data), ++ introspection, ++ g_object_unref); ++ } ++ ++ g_object_unref (G_OBJECT (user_data)); ++} ++ ++void prv_introspect_async (GUPnPServiceInfo *info, ++ GCancellable *cancellable, ++ GAsyncReadyCallback callback, ++ gpointer user_data) ++{ ++ GTask *task = g_task_new (info, cancellable, callback, user_data); ++ ++ gupnp_service_info_get_introspection_async_full (info, ++ prv_introspection_wrap_cb, ++ cancellable, ++ task); ++} ++ ++static GUPnPServiceIntrospection *prv_introspect_finish ++ (GUPnPServiceInfo *info, ++ GAsyncResult *res, ++ GError **error) ++{ ++ g_return_val_if_fail (g_task_is_valid (res, info), NULL); ++ ++ return g_task_propagate_pointer (G_TASK (res), error); ++} ++ ++static gint compare_speeds(gconstpointer a, gconstpointer b); ++ ++static void prv_introspect_av_cb (GObject *target, ++ GAsyncResult *res, ++ gpointer user_data) ++{ ++ prv_new_device_ct_t *priv_t = (prv_new_device_ct_t *)user_data; ++ GError *error = NULL; ++ GUPnPServiceIntrospection *introspection; ++ const GUPnPServiceStateVariableInfo *svi; ++ GList *allowed_values; ++ GVariant *speeds = NULL; ++ const GUPnPServiceActionInfo *sai; ++ ++ DLEYNA_LOG_DEBUG("Enter"); ++ ++ priv_t->dev->construct_step++; ++ ++ introspection = prv_introspect_finish (GUPNP_SERVICE_INFO (target), res, &error); ++ ++ if (introspection == NULL || (error != NULL)) { ++ DLEYNA_LOG_WARNING("GetProtocolInfo operation failed: %s", ++ ((error != NULL) ? error->message ++ : "Invalid result")); ++ goto on_error; ++ } ++ ++ svi = gupnp_service_introspection_get_state_variable( ++ introspection, ++ "TransportPlaySpeed"); ++ ++ if (svi && svi->allowed_values) { ++ allowed_values = svi->allowed_values; ++ ++ allowed_values = g_list_sort(allowed_values, compare_speeds); ++ ++ prv_get_rates_values(allowed_values, &speeds, ++ &priv_t->dev->transport_play_speeds, ++ &priv_t->dev->min_rate, ++ &priv_t->dev->max_rate); ++ ++ priv_t->dev->mpris_transport_play_speeds = g_variant_ref_sink(speeds); ++ } ++ ++ sai = gupnp_service_introspection_get_action( ++ introspection, ++ "X_DLNA_GetBytePositionInfo"); ++ ++ priv_t->dev->can_get_byte_position = (sai != NULL); ++ ++on_error: ++ g_clear_object(&introspection); ++ ++ g_clear_error(&error); ++ ++ DLEYNA_LOG_DEBUG("Exit"); ++} ++ ++static void prv_introspect_rc_cb (GObject *target, ++ GAsyncResult *res, ++ gpointer user_data) ++{ ++ prv_new_device_ct_t *priv_t = (prv_new_device_ct_t *)user_data; ++ GError *error = NULL; ++ GUPnPServiceIntrospection *introspection; ++ const GUPnPServiceStateVariableInfo *svi; ++ ++ DLEYNA_LOG_DEBUG("Enter"); ++ ++ priv_t->dev->construct_step++; ++ ++ introspection = prv_introspect_finish (GUPNP_SERVICE_INFO (target), res, &error); ++ ++ if (introspection == NULL || (error != NULL)) { ++ DLEYNA_LOG_WARNING("GetProtocolInfo operation failed: %s", ++ ((error != NULL) ? error->message ++ : "Invalid result")); ++ goto on_error; ++ } ++ ++ svi = gupnp_service_introspection_get_state_variable(introspection, ++ "Volume"); ++ if (svi != NULL) ++ priv_t->dev->max_volume = g_value_get_uint(&svi->maximum); ++ ++on_error: ++ g_clear_object(&introspection); ++ ++ g_clear_error(&error); ++ ++ DLEYNA_LOG_DEBUG("Exit"); ++} ++ ++static gboolean prv_get_protocol_info( ++ dleyna_gasync_task_t *task, ++ GObject *target) + { +- *failed = FALSE; ++ GUPnPServiceProxyAction *action; + +- return gupnp_service_proxy_begin_action( +- proxy, "GetProtocolInfo", +- dleyna_service_task_begin_action_cb, +- task, NULL); ++ action = gupnp_service_proxy_action_new("GetProtocolInfo", NULL); ++ ++ gupnp_service_proxy_call_action_async(GUPNP_SERVICE_PROXY (target), action, ++ dleyna_gasync_task_get_cancellable (task), ++ dleyna_gasync_task_ready_cb, ++ task); ++ ++ return FALSE; ++} ++ ++static gboolean prv_introspect(dleyna_gasync_task_t *task, GObject *target) ++{ ++ prv_introspect_async (GUPNP_SERVICE_INFO (target), ++ dleyna_gasync_task_get_cancellable (task), ++ dleyna_gasync_task_ready_cb, ++ task); ++ ++ return FALSE; + } + +-static GUPnPServiceProxyAction *prv_subscribe(dleyna_service_task_t *task, +- GUPnPServiceProxy *proxy, +- gboolean *failed) ++static gboolean prv_subscribe(dleyna_gasync_task_t *task, GObject *target) + { + dlr_device_t *device; + + DLEYNA_LOG_DEBUG("Enter"); + +- device = (dlr_device_t *)dleyna_service_task_get_user_data(task); ++ device = (dlr_device_t *)dleyna_gasync_task_get_user_data(task); + + device->construct_step++; + prv_device_subscribe_context(device); + +- *failed = FALSE; +- + DLEYNA_LOG_DEBUG("Exit"); + +- return NULL; ++ return FALSE; + } + +-static GUPnPServiceProxyAction *prv_declare(dleyna_service_task_t *task, +- GUPnPServiceProxy *proxy, +- gboolean *failed) ++static gboolean prv_declare(dleyna_gasync_task_t *task, ++ GObject *target) + { + unsigned int i; + dlr_device_t *device; + prv_new_device_ct_t *priv_t; + const dleyna_connector_dispatch_cb_t *table; ++ gboolean result = FALSE; + + DLEYNA_LOG_DEBUG("Enter"); + +- *failed = FALSE; +- +- priv_t = (prv_new_device_ct_t *)dleyna_service_task_get_user_data(task); ++ priv_t = (prv_new_device_ct_t *)dleyna_gasync_task_get_user_data(task); + device = priv_t->dev; + device->construct_step++; + +@@ -770,16 +924,16 @@ static GUPnPServiceProxyAction *prv_declare(dleyna_service_task_t *task, + table + i); + + if (!device->ids[i]) { +- *failed = TRUE; ++ result = TRUE; + goto on_error; + } + } + + on_error: + +-DLEYNA_LOG_DEBUG("Exit"); ++ DLEYNA_LOG_DEBUG("Exit"); + +- return NULL; ++ return result; + } + + static void prv_free_rc_event(gpointer user_data) +@@ -800,6 +954,9 @@ void dlr_device_construct( + { + prv_new_device_ct_t *priv_t; + GUPnPServiceProxy *s_proxy; ++ GUPnPServiceProxy *av_proxy; ++ GUPnPServiceProxy *rc_proxy; ++ GCancellable *cancellable; + + DLEYNA_LOG_DEBUG("Current step: %d", dev->construct_step); + +@@ -809,19 +966,42 @@ void dlr_device_construct( + priv_t->dispatch_table = dispatch_table; + + s_proxy = context->service_proxies.cm_proxy; ++ cancellable = g_cancellable_new (); + + if (dev->construct_step < 1) +- dleyna_service_task_add(queue_id, prv_get_protocol_info, +- s_proxy, prv_get_protocol_info_cb, +- NULL, priv_t); ++ dleyna_gasync_task_add(queue_id, ++ prv_get_protocol_info, ++ G_OBJECT(s_proxy), ++ prv_get_protocol_info_cb, ++ cancellable, ++ NULL, priv_t); ++ ++ av_proxy = context->service_proxies.av_proxy; ++ if (dev->construct_step < 2) ++ dleyna_gasync_task_add(queue_id, ++ prv_introspect, ++ G_OBJECT(av_proxy), ++ prv_introspect_av_cb, ++ cancellable, ++ NULL, priv_t); ++ ++ rc_proxy = context->service_proxies.rc_proxy; ++ if (dev->construct_step < 3) ++ dleyna_gasync_task_add(queue_id, ++ prv_introspect, ++ G_OBJECT(rc_proxy), ++ prv_introspect_rc_cb, ++ cancellable, ++ NULL, priv_t); ++ + + /* The following task should always be completed */ +- dleyna_service_task_add(queue_id, prv_subscribe, s_proxy, +- NULL, NULL, dev); ++ dleyna_gasync_task_add(queue_id, prv_subscribe, G_OBJECT(s_proxy), ++ NULL, NULL, NULL, dev); + +- if (dev->construct_step < 3) +- dleyna_service_task_add(queue_id, prv_declare, s_proxy, +- NULL, g_free, priv_t); ++ if (dev->construct_step < 5) ++ dleyna_gasync_task_add(queue_id, prv_declare, G_OBJECT(s_proxy), ++ NULL, NULL, g_free, priv_t); + + dleyna_task_queue_start(queue_id); + +@@ -2121,133 +2301,6 @@ static void prv_get_rates_values(GList *allowed_tp_speeds, + return; + } + +-static gboolean prv_get_av_service_states_values(GUPnPServiceProxy *av_proxy, +- GVariant **mpris_tp_speeds, +- GPtrArray **upnp_tp_speeds, +- double *min_rate, +- double *max_rate, +- gboolean *can_get_byte_pos) +-{ +- const GUPnPServiceStateVariableInfo *svi; +- const GUPnPServiceActionInfo *sai; +- GUPnPServiceIntrospection *introspection; +- GError *error = NULL; +- GVariant *speeds = NULL; +- GList *allowed_values; +- gpointer weak_ref = NULL; +- gboolean device_alive = TRUE; +- +- /* TODO: this weak_ref hack is needed as +- gupnp_service_info_get_introspection iterates the main loop. +- This can result in our device getting deleted before this +- function returns. Ultimately, this code needs to be re-written +- to use gupnp_service_info_get_introspection_async but this cannot +- really be done until GUPnP provides a way to cancel this function. */ +- +- weak_ref = av_proxy; +- g_object_add_weak_pointer(G_OBJECT(av_proxy), &weak_ref); +- +- introspection = gupnp_service_info_get_introspection( +- GUPNP_SERVICE_INFO(av_proxy), +- &error); +- +- if (!weak_ref) { +- DLEYNA_LOG_WARNING("Lost device during introspection call"); +- device_alive = FALSE; +- goto exit; +- } +- +- g_object_remove_weak_pointer(G_OBJECT(av_proxy), &weak_ref); +- +- if (error != NULL) { +- DLEYNA_LOG_DEBUG( +- "failed to fetch AV service introspection file"); +- +- g_error_free(error); +- +- goto exit; +- } +- +- svi = gupnp_service_introspection_get_state_variable( +- introspection, +- "TransportPlaySpeed"); +- +- if (svi && svi->allowed_values) { +- allowed_values = svi->allowed_values; +- +- allowed_values = g_list_sort(allowed_values, compare_speeds); +- +- prv_get_rates_values(allowed_values, &speeds, upnp_tp_speeds, +- min_rate, max_rate); +- +- *mpris_tp_speeds = g_variant_ref_sink(speeds); +- } +- +- sai = gupnp_service_introspection_get_action( +- introspection, +- "X_DLNA_GetBytePositionInfo"); +- +- *can_get_byte_pos = (sai != NULL); +- +- g_object_unref(introspection); +- +-exit: +- +- return device_alive; +-} +- +-static gboolean prv_get_rc_service_states_values(GUPnPServiceProxy *rc_proxy, +- guint *max_volume) +-{ +- const GUPnPServiceStateVariableInfo *svi; +- GUPnPServiceIntrospection *introspection; +- GError *error = NULL; +- gpointer weak_ref = NULL; +- gboolean device_alive = TRUE; +- +- /* TODO: this weak_ref hack is needed as +- gupnp_service_info_get_introspection iterates the main loop. +- This can result in our device getting deleted before this +- function returns. Ultimately, this code needs to be re-written +- to use gupnp_service_info_get_introspection_async but this cannot +- really be done until GUPnP provides a way to cancel this function. */ +- +- weak_ref = rc_proxy; +- g_object_add_weak_pointer(G_OBJECT(rc_proxy), &weak_ref); +- +- introspection = gupnp_service_info_get_introspection( +- GUPNP_SERVICE_INFO(rc_proxy), +- &error); +- +- if (!weak_ref) { +- DLEYNA_LOG_WARNING("Lost device during introspection call"); +- device_alive = FALSE; +- goto exit; +- } +- +- g_object_remove_weak_pointer(G_OBJECT(rc_proxy), &weak_ref); +- +- if (error != NULL) { +- DLEYNA_LOG_DEBUG( +- "failed to fetch RC service introspection file"); +- +- g_error_free(error); +- +- goto exit; +- } +- +- svi = gupnp_service_introspection_get_state_variable(introspection, +- "Volume"); +- if (svi != NULL) +- *max_volume = g_value_get_uint(&svi->maximum); +- +- g_object_unref(introspection); +- +-exit: +- +- return device_alive; +-} +- + static void prv_update_device_props(GUPnPDeviceInfo *proxy, GHashTable *props) + { + GVariant *val; +@@ -2378,34 +2431,6 @@ static gboolean prv_props_update(dlr_device_t *device, dlr_task_t *task) + + service_proxies = &context->service_proxies; + +- /* TODO: We should not retrieve these values here. They should be +- retrieved during device construction. */ +- +- if (service_proxies->av_proxy) +- if (!prv_get_av_service_states_values( +- service_proxies->av_proxy, +- &device->mpris_transport_play_speeds, +- &device->transport_play_speeds, +- &device->min_rate, +- &device->max_rate, +- &device->can_get_byte_position)) { +- DLEYNA_LOG_DEBUG("Lost Device AV"); +- +- device_alive = FALSE; +- goto on_lost_device; +- } +- +- /* TODO: We should not retrieve these values here. They should be +- retrieved during device construction. */ +- +- if (service_proxies->rc_proxy) +- if (!prv_get_rc_service_states_values(service_proxies->rc_proxy, +- &device->max_volume)) { +- DLEYNA_LOG_DEBUG("Lost Device RC"); +- device_alive = FALSE; +- goto on_lost_device; +- } +- + changed_props_vb = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); + + prv_add_player_speed_props(device->props.player_props, +diff --git a/libdleyna/renderer/gasync-task.c b/libdleyna/renderer/gasync-task.c +new file mode 100644 +index 0000000..47a0ad5 +--- /dev/null ++++ b/libdleyna/renderer/gasync-task.c +@@ -0,0 +1,135 @@ ++/* ++ * dLeyna ++ * ++ * Copyright (c) 2019 Jens Georg ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU Lesser General Public License, ++ * version 2.1, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ */ ++ ++#include "gasync-task.h" ++#include ++ ++struct dleyna_gasync_task_t_ { ++ dleyna_task_atom_t base; ++ dleyna_gasync_task_action action; ++ GObject *target; ++ GAsyncReadyCallback callback; ++ GCancellable *cancellable; ++ GDestroyNotify free_func; ++ gpointer cb_user_data; ++}; ++ ++const char *dleyna_gasync_task_create_source(void) ++{ ++ static unsigned int cpt = 1; ++ static char source[27]; ++ ++ g_snprintf(source, 27, "gasync-source-%d", cpt); ++ cpt++; ++ ++ return source; ++} ++ ++void dleyna_gasync_task_add(const dleyna_task_queue_key_t *queue_id, ++ dleyna_gasync_task_action action, ++ GObject *target, ++ GAsyncReadyCallback callback, ++ GCancellable *cancellable, ++ GDestroyNotify free_func, ++ gpointer cb_user_data) ++{ ++ dleyna_gasync_task_t *task; ++ ++ task = g_new0(dleyna_gasync_task_t, 1); ++ ++ task->action = action; ++ task->callback = callback; ++ task->cancellable = cancellable; ++ task->free_func = free_func; ++ task->cb_user_data = cb_user_data; ++ task->target = target; ++ ++ if (target != NULL) { ++ g_object_add_weak_pointer (target, (gpointer *)(&task->target)); ++ } ++ ++ dleyna_task_queue_add_task(queue_id, &task->base); ++} ++ ++void dleyna_gasync_task_ready_cb(GObject *source, GAsyncResult *res, gpointer user_data) ++{ ++ dleyna_gasync_task_t *task = (dleyna_gasync_task_t *)user_data; ++ ++ task->callback(source, res, task->cb_user_data); ++ ++ dleyna_task_queue_task_completed(task->base.queue_id); ++} ++ ++void dleyna_gasync_task_process_cb(dleyna_task_atom_t *atom, ++ gpointer user_data) ++{ ++ gboolean failed = FALSE; ++ ++ dleyna_gasync_task_t *task = (dleyna_gasync_task_t *)atom; ++ ++ failed = task->action(task, task->target); ++ ++ if (failed) { ++ dleyna_task_processor_cancel_queue(task->base.queue_id); ++ dleyna_task_queue_task_completed(task->base.queue_id); ++ } ++ ++ if (task->callback == NULL) { ++ dleyna_task_queue_task_completed(task->base.queue_id); ++ } ++} ++ ++void dleyna_gasync_task_cancel_cb(dleyna_task_atom_t *atom, ++ gpointer user_data) ++{ ++ dleyna_gasync_task_t *task = (dleyna_gasync_task_t *)atom; ++ ++ if (task->cancellable) { ++ g_cancellable_cancel (task->cancellable); ++ task->cancellable = NULL; ++ ++ dleyna_task_queue_task_completed(task->base.queue_id); ++ } ++} ++ ++void dleyna_gasync_task_delete_cb(dleyna_task_atom_t *atom, ++ gpointer user_data) ++{ ++ dleyna_gasync_task_t *task = (dleyna_gasync_task_t *)atom; ++ ++ if (task->free_func != NULL) ++ task->free_func(task->cb_user_data); ++ ++ if (task->target != NULL) { ++ g_object_remove_weak_pointer(task->target, (gpointer *)&task->target); ++ } ++ ++ g_free(task); ++} ++ ++gpointer dleyna_gasync_task_get_user_data(dleyna_gasync_task_t *task) ++{ ++ return task->cb_user_data; ++} ++ ++GCancellable *dleyna_gasync_task_get_cancellable(dleyna_gasync_task_t *task) ++{ ++ return task->cancellable; ++} +diff --git a/libdleyna/renderer/gasync-task.h b/libdleyna/renderer/gasync-task.h +new file mode 100644 +index 0000000..629e48c +--- /dev/null ++++ b/libdleyna/renderer/gasync-task.h +@@ -0,0 +1,57 @@ ++/* ++ * dLeyna ++ * ++ * Copyright (c) 2019 Jens Georg ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms and conditions of the GNU Lesser General Public License, ++ * version 2.1, as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License ++ * for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public License ++ * along with this program; if not, write to the Free Software Foundation, Inc., ++ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ */ ++ ++#pragma once ++ ++#include ++ ++#include ++#include ++ ++typedef struct dleyna_gasync_task_t_ dleyna_gasync_task_t; ++ ++typedef gboolean (*dleyna_gasync_task_action) ++ (dleyna_gasync_task_t *task, ++ GObject *target); ++ ++const char *dleyna_gasync_task_create_source(void); ++ ++void dleyna_gasync_task_add(const dleyna_task_queue_key_t *queue_id, ++ dleyna_gasync_task_action action, ++ GObject *target, ++ GAsyncReadyCallback callback, ++ GCancellable *cancellable, ++ GDestroyNotify free_func, ++ gpointer cb_user_data); ++ ++void dleyna_gasync_task_ready_cb(GObject *source, GAsyncResult *res, gpointer user_data); ++ ++void dleyna_gasync_task_process_cb(dleyna_task_atom_t *atom, ++ gpointer user_data); ++ ++void dleyna_gasync_task_cancel_cb(dleyna_task_atom_t *atom, ++ gpointer user_data); ++ ++void dleyna_gasync_task_delete_cb(dleyna_task_atom_t *atom, ++ gpointer user_data); ++ ++gpointer dleyna_gasync_task_get_user_data(dleyna_gasync_task_t *task); ++ ++GCancellable *dleyna_gasync_task_get_cancellable(dleyna_gasync_task_t *task); +diff --git a/libdleyna/renderer/manager.c b/libdleyna/renderer/manager.c +index 74052f5..bea9935 100644 +--- a/libdleyna/renderer/manager.c ++++ b/libdleyna/renderer/manager.c +@@ -25,7 +25,6 @@ + + #include + #include +-#include + #include + + #include "async.h" +diff --git a/libdleyna/renderer/upnp.c b/libdleyna/renderer/upnp.c +index 17cbda7..0e9d483 100644 +--- a/libdleyna/renderer/upnp.c ++++ b/libdleyna/renderer/upnp.c +@@ -28,10 +28,10 @@ + + #include + #include +-#include + + #include "async.h" + #include "device.h" ++#include "gasync-task.h" + #include "host-service.h" + #include "prop-defs.h" + #include "upnp.h" +@@ -116,12 +116,12 @@ static const dleyna_task_queue_key_t *prv_create_device_queue( + + queue_id = dleyna_task_processor_add_queue( + dlr_renderer_service_get_task_processor(), +- dleyna_service_task_create_source(), ++ dleyna_gasync_task_create_source(), + DLR_RENDERER_SINK, + DLEYNA_TASK_QUEUE_FLAG_AUTO_REMOVE, +- dleyna_service_task_process_cb, +- dleyna_service_task_cancel_cb, +- dleyna_service_task_delete_cb); ++ dleyna_gasync_task_process_cb, ++ dleyna_gasync_task_cancel_cb, ++ dleyna_gasync_task_delete_cb); + dleyna_task_queue_set_finally(queue_id, prv_device_chain_end); + dleyna_task_queue_set_user_data(queue_id, *priv_t); + +@@ -243,8 +243,8 @@ static void prv_server_unavailable_cb(GUPnPControlPoint *cp, + + udn = gupnp_device_info_get_udn((GUPnPDeviceInfo *)proxy); + +- ip_address = gupnp_context_get_host_ip( +- gupnp_control_point_get_context(cp)); ++ ip_address = gssdp_client_get_host_ip( ++ GSSDP_CLIENT(gupnp_control_point_get_context(cp))); + + if (!udn || !ip_address) + goto on_error; + +From 79593067cf40ed58a3bd95311c7fa108feafcb46 Mon Sep 17 00:00:00 2001 +From: Jens Georg +Date: Sat, 21 Sep 2019 20:37:33 +0200 +Subject: [PATCH 3/4] Move to GUPnP 1.2 + +Fixes #166 +--- + configure.ac | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 271ee92..364659d 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -38,8 +38,8 @@ LT_LANG([C]) + PKG_PROG_PKG_CONFIG(0.16) + PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.28]) + PKG_CHECK_MODULES([GIO], [gio-2.0 >= 2.28]) +-PKG_CHECK_MODULES([GSSDP], [gssdp-1.0 >= 0.13.2]) +-PKG_CHECK_MODULES([GUPNP], [gupnp-1.0 >= 0.20.5]) ++PKG_CHECK_MODULES([GSSDP], [gssdp-1.2 >= 1.2.0]) ++PKG_CHECK_MODULES([GUPNP], [gupnp-1.2 >= 1.2.0]) + PKG_CHECK_MODULES([GUPNPAV], [gupnp-av-1.0 >= 0.11.5]) + PKG_CHECK_MODULES([GUPNPDLNA], [gupnp-dlna-2.0 >= 0.9.4]) + PKG_CHECK_MODULES([SOUP], [libsoup-2.4 >= 2.28.2]) + +From 66e755a89cdcd7f10a535131a340c3f3ab371194 Mon Sep 17 00:00:00 2001 +From: Jens Georg +Date: Mon, 23 Sep 2019 00:08:38 +0200 +Subject: [PATCH 4/4] Protect introspection calls against missing proxies + +--- + libdleyna/renderer/device.c | 38 +++++++++++++++++++++++-------------- + 1 file changed, 24 insertions(+), 14 deletions(-) + +diff --git a/libdleyna/renderer/device.c b/libdleyna/renderer/device.c +index 73b3dd3..525a23d 100644 +--- a/libdleyna/renderer/device.c ++++ b/libdleyna/renderer/device.c +@@ -977,22 +977,32 @@ void dlr_device_construct( + NULL, priv_t); + + av_proxy = context->service_proxies.av_proxy; +- if (dev->construct_step < 2) +- dleyna_gasync_task_add(queue_id, +- prv_introspect, +- G_OBJECT(av_proxy), +- prv_introspect_av_cb, +- cancellable, +- NULL, priv_t); ++ if (dev->construct_step < 2) { ++ if (av_proxy == NULL) { ++ dev->construct_step++; ++ } else { ++ dleyna_gasync_task_add(queue_id, ++ prv_introspect, ++ G_OBJECT(av_proxy), ++ prv_introspect_av_cb, ++ cancellable, ++ NULL, priv_t); ++ } ++ } + + rc_proxy = context->service_proxies.rc_proxy; +- if (dev->construct_step < 3) +- dleyna_gasync_task_add(queue_id, +- prv_introspect, +- G_OBJECT(rc_proxy), +- prv_introspect_rc_cb, +- cancellable, +- NULL, priv_t); ++ if (dev->construct_step < 3) { ++ if (rc_proxy == NULL) { ++ dev->construct_step++; ++ } else { ++ dleyna_gasync_task_add(queue_id, ++ prv_introspect, ++ G_OBJECT(rc_proxy), ++ prv_introspect_rc_cb, ++ cancellable, ++ NULL, priv_t); ++ } ++ } + + + /* The following task should always be completed */ -- cgit v1.2.3-65-gdbad