From 594015eac2757f629a32d043c9a9b10ff6c5f95f Mon Sep 17 00:00:00 2001 From: Jens Georg Date: Mon, 5 Nov 2018 22:07:09 +0100 Subject: [PATCH 1/5] 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/5] 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/5] 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/5] 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 */ From 3c8e85a522516437151bc2c441ddc3eb406593ea Mon Sep 17 00:00:00 2001 From: Debarshi Ray Date: Mon, 22 Jun 2020 17:02:42 +0200 Subject: [PATCH 5/5] Add a manual https://github.com/phako/dleyna-renderer/pull/1 --- Makefile.am | 2 +- configure.ac | 6 + doc/Makefile.am | 18 +++ doc/dleyna-renderer-service.conf.xml | 182 +++++++++++++++++++++++++++ 4 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 doc/Makefile.am create mode 100644 doc/dleyna-renderer-service.conf.xml diff --git a/Makefile.am b/Makefile.am index 200e196..35bd628 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = libdleyna/renderer +SUBDIRS = doc libdleyna/renderer if BUILD_SERVER SUBDIRS += server diff --git a/configure.ac b/configure.ac index 364659d..b224ac7 100644 --- a/configure.ac +++ b/configure.ac @@ -34,6 +34,11 @@ LT_PREREQ([2.2.6]) LT_INIT([dlopen disable-static]) LT_LANG([C]) +AC_PATH_PROG([XSLTPROC], [xsltproc]) +if test -z "$XSLTPROC"; then + AC_MSG_ERROR([xsltproc not found]) +fi + # Checks for libraries. PKG_PROG_PKG_CONFIG(0.16) PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.28]) @@ -231,6 +236,7 @@ AC_SUBST([with_log_level]) AC_SUBST([with_log_type]) AC_CONFIG_FILES([Makefile \ + doc/Makefile \ libdleyna/renderer/Makefile \ libdleyna/renderer/dleyna-renderer-service.conf \ server/dleyna-renderer-service-1.0.pc \ diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..80069b1 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,18 @@ +XSLTPROC_FLAGS = \ + --nonet \ + --stringparam man.output.quietly 1 \ + --stringparam funcsynopsis.style ansi \ + --stringparam man.authors.section.enabled 0 \ + --stringparam man.copyright.section.enabled 0 + +.xml.5: + $(AM_V_GEN) $(XSLTPROC) $(XSLTPROC_FLAGS) http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $< + +man_MANS = \ + dleyna-renderer-service.conf.5 + +xml_files = $(man_MANS:.5=.xml) + +EXTRA_DIST = $(xml_files) + +CLEANFILES = $(man_MANS) diff --git a/doc/dleyna-renderer-service.conf.xml b/doc/dleyna-renderer-service.conf.xml new file mode 100644 index 0000000..e6be274 --- /dev/null +++ b/doc/dleyna-renderer-service.conf.xml @@ -0,0 +1,182 @@ + + + + dleyna-renderer-service.conf + June 2020 + dLeyna + + + + dleyna-renderer-service.conf + 5 + Linux Programmer's Manual + + + + dleyna-renderer-service.conf + Configuration file for dleyna-renderer + + + + + /etc/dleyna-renderer-service.conf + + + + + + DESCRIPTION + + The dleyna-renderer-service program provides the + com.intel.dleyna-renderer name on the session + message bus. It is a service for discovering and manipulating DLNA + Digital Media Renderers (or DMRs). + + + Users or administrators should never need to start this daemon as it will + be automatically started by + dbus-daemon1 + whenever a process sends a D-Bus message to the + com.intel.dleyna-renderer name on the session bus. + + + This file can be used to configure the behaviour of the + dleyna-renderer-service program. + + + + + FILE FORMAT + + The configuration file format is the so-called key file (sort of + ini-style) format. It consists of sections (or groups) of key-value + Lines beginning with a '#' and blank lines are considered comments. + Sections are started by a header line containing the section enclosed + in '[' and ']', and ended implicitly by the start of the next section + or the end of the file. Each key-value pair must be contained in a + section. + + + + + GENERAL SECTION + + + + + + The name of the inter-process communication method to be used. + The only supported value is dbus. + + + + + + + + Whether the process should stay alive forever or quit when the + last client disconnects. The default value is + false. + + + + + + + + Source port for Simple Service Discovery Protocol (or SSDP) + messages. The default value is 0 which + means that a random available port will be used. + + + + + + + + Port for push host file server. The default value is + 0 which means that a random available + port will be used. + + + + + + + + LOG SECTION + + + + + + The logging method to be used. Three technologies are supported. + 0 for syslog, 1 for GLib, and 2 for file. The default value is + 0. + + + + + + + + Comma-separated list of logging levels. The levels are 1 for + critical, 2 for error, 3 for warning, 4 for message, 5 for info + and 6 for debug. 0 excludes all levels, 7 is a combination of + critical, error and info, and 8 includes all levels. + + + The default value is 7. + + + + + + + + NETF SECTION + + + + + + Whether network filtering should be enabled or not. The default + values is false. + + + + + + + + Comma-separated list of interface names, service set identifiers + (or SSIDs), and Internet Protocol (or IP) addresses. If network + filtering is requested but the list is empty, then filtering + remains disabled. + + + The list is empty by default. + + + + + + + + BUGS + + Please send bug reports to either the distribution bug tracker + or the upstream bug tracker at + . + + + + + SEE ALSO + + + dbus-daemon1 + + + +