From 964bf1d5f07a0c68672b642a66cd4eee4855b60f Mon Sep 17 00:00:00 2001 From: Sangchul Lee Date: Thu, 25 Jun 2020 16:05:26 +0900 Subject: [PATCH 01/16] Exclude ringbacktone stream from changing call active routing logic stream_is_call_family() is also renamed to is_stream_related_call_active_routing() [Version] 13.0.20 [Issue Type] Bug fix Change-Id: Iedee8a5c2e655d4bf4c9f0275c0ed8c0c5450621 Signed-off-by: Sangchul Lee --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/stream-manager-dbus.c | 2 +- src/stream-manager-priv.h | 2 +- src/stream-manager.c | 25 +++++++++++++------------ 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index fa7798e..3944878 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.19 +Version: 13.0.20 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/stream-manager-dbus.c b/src/stream-manager-dbus.c index 64adff1..a6e7506 100644 --- a/src/stream-manager-dbus.c +++ b/src/stream-manager-dbus.c @@ -512,7 +512,7 @@ static ret_msg_t update_devices_and_trigger_routing(pa_stream_manager *m, stream pa_log_debug(" -- cur_highest_priority_stream->index[%u] belongs to this stream_parent[%p], do notify for the route change", GET_STREAM_INDEX(cur_highest_priority_stream, type), sp); ret = do_notify(m, NOTIFY_COMMAND_CHANGE_ROUTE_START, type, false, cur_highest_priority_stream); - if (!ret && stream_is_call_family(PA_OBJECT(cur_highest_priority_stream)) && m->on_call) { + if (!ret && is_stream_related_call_active_routing(PA_OBJECT(cur_highest_priority_stream)) && m->on_call) { pa_log_info("set active device for new call route device"); change_active_route_for_call(m, PA_OBJECT(cur_highest_priority_stream), false); } diff --git a/src/stream-manager-priv.h b/src/stream-manager-priv.h index 6425e99..f78a063 100644 --- a/src/stream-manager-priv.h +++ b/src/stream-manager-priv.h @@ -284,7 +284,7 @@ struct _stream_manager { } comm; }; -bool stream_is_call_family(pa_object *stream); +bool is_stream_related_call_active_routing(pa_object *stream); bool is_active_device_of_stream(const void *stream, stream_type_t stream_type, const char *device_type); bool is_stream_ducked(stream_ducking *sd); int32_t get_route_type(void *stream, stream_type_t stream_type, bool is_new_data, stream_route_type_t *stream_route_type); diff --git a/src/stream-manager.c b/src/stream-manager.c index cb89244..981d4c6 100644 --- a/src/stream-manager.c +++ b/src/stream-manager.c @@ -137,7 +137,7 @@ static bool is_valid_process_command(process_command_type_t command) { return (command < sizeof(process_command_type_str) / sizeof(char *)); } -bool stream_is_call_family(pa_object *stream) { +bool is_stream_related_call_active_routing(pa_object *stream) { const char *stream_role; pa_proplist *prop; @@ -148,9 +148,15 @@ bool stream_is_call_family(pa_object *stream) { else prop = PA_SOURCE_OUTPUT(stream)->proplist; - stream_role = pa_proplist_gets(prop, PA_PROP_MEDIA_ROLE); - if (stream_role && IS_ROLE_COMMUNICATION(stream_role)) + if (!(stream_role = pa_proplist_gets(prop, PA_PROP_MEDIA_ROLE))) + return false; + + if (pa_safe_streq(stream_role, STREAM_ROLE_CALL_VOICE) || + pa_safe_streq(stream_role, STREAM_ROLE_CALL_VIDEO) || + pa_safe_streq(stream_role, STREAM_ROLE_VOIP)) { + pa_log_info("%s relates call active routing", stream_role); return true; + } return false; } @@ -522,11 +528,6 @@ int change_active_route_for_call(pa_stream_manager *m, pa_object *stream, bool s stream_role = pa_proplist_gets(prop, PA_PROP_MEDIA_ROLE); - if (stream_is_call_family(stream) == false) { - pa_log_error("Not call family stream"); - return -1; - } - avail_device_types = get_avail_device_types(m, stream_role, GET_DIRECTION(stream)); if (!avail_device_types) { pa_log_error("No avail device typs for [%s]", stream_role); @@ -2495,7 +2496,7 @@ static pa_hook_result_t sink_input_put_cb(pa_core *core, pa_sink_input *i, pa_st process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_ADD_PARENT_ID, false); process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_APPLY_FILTER, false); process_stream(m, i, STREAM_SINK_INPUT, PROCESS_COMMAND_UPDATE_VOLUME, false); - if (stream_is_call_family(PA_OBJECT(i))) { + if (is_stream_related_call_active_routing(PA_OBJECT(i))) { change_active_route_for_call(m, PA_OBJECT(i), true); m->on_call = true; } @@ -2511,7 +2512,7 @@ static pa_hook_result_t sink_input_unlink_cb(pa_core *core, pa_sink_input *i, pa pa_log_info("sink-input(%p, index:%u)", i, i->index); - if (stream_is_call_family(PA_OBJECT(i))) { + if (is_stream_related_call_active_routing(PA_OBJECT(i))) { m->on_call = false; set_media_active_device(m); } @@ -2652,7 +2653,7 @@ static pa_hook_result_t source_output_put_cb(pa_core *core, pa_source_output *o, update_mirroring_streams(m, o, true); process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_ADD_PARENT_ID, false); process_stream(m, o, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_UPDATE_VOLUME, false); - if (stream_is_call_family(PA_OBJECT(o))) { + if (is_stream_related_call_active_routing(PA_OBJECT(o))) { change_active_route_for_call(m, PA_OBJECT(o), true); m->on_call = true; } @@ -2666,7 +2667,7 @@ static pa_hook_result_t source_output_unlink_cb(pa_core *core, pa_source_output pa_log_info("source-output(%p, index:%u)", o, o->index); - if (stream_is_call_family(PA_OBJECT(o))) { + if (is_stream_related_call_active_routing(PA_OBJECT(o))) { m->on_call = false; set_media_active_device(m); } -- 2.7.4 From 2c1bdbb11d7fb3568f53c3f5996edde35a1ac5ed Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Mon, 23 Mar 2020 20:22:54 +0900 Subject: [PATCH 02/16] Add module-tizenaudio-discover / module-tizenaudio-publish for remote audio feature module-tizenaudio-discover : based on module-zeroconf-discover with mDNSResponder porting module-tizenaudio-publish : based on module-bonjour-publish with minor changes [Version] 13.0.21 [Issue Type] New feature Change-Id: Id47dad038bfae487bbe57a09aaece674b30f9008 --- Makefile.am | 12 + configure.ac | 4 + packaging/pulseaudio-modules-tizen.spec | 5 +- src/module-tizenaudio-discover.c | 733 ++++++++++++++++++++++++++++++++ src/module-tizenaudio-publish.c | 513 ++++++++++++++++++++++ 5 files changed, 1266 insertions(+), 1 deletion(-) create mode 100644 src/module-tizenaudio-discover.c create mode 100644 src/module-tizenaudio-publish.c diff --git a/Makefile.am b/Makefile.am index 9b59496..07985dc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -36,6 +36,8 @@ pulsemodlibexec_LTLIBRARIES = \ module-tizenaudio-sink.la \ module-tizenaudio-source.la \ module-tizenaudio-policy.la \ + module-tizenaudio-discover.la \ + module-tizenaudio-publish.la \ module-sound-player.la \ module-tone-player.la \ module-poweroff.la @@ -115,6 +117,16 @@ module_acm_sink_la_LIBADD = $(MODULE_LIBADD) module_acm_sink_la_CFLAGS = $(MODULE_CFLAGS) endif +module_tizenaudio_discover_la_SOURCES = src/module-tizenaudio-discover.c +module_tizenaudio_discover_la_LDFLAGS = $(MODULE_LDFLAGS) +module_tizenaudio_discover_la_LIBADD = $(MODULE_LIBADD) $(DNSSD_LIBS) +module_tizenaudio_discover_la_CFLAGS = $(MODULE_CFLAGS) $(DNSSD_CFLAGS) + +module_tizenaudio_publish_la_SOURCES = src/module-tizenaudio-publish.c +module_tizenaudio_publish_la_LDFLAGS = $(MODULE_LDFLAGS) +module_tizenaudio_publish_la_LIBADD = $(MODULE_LIBADD) $(DNSSD_LIBS) +module_tizenaudio_publish_la_CFLAGS = $(AM_CFLAGS) $(DNSSD_CFLAGS) + if ENABLE_VCONF_HELPER pulsemodlibexec_LTLIBRARIES += module-vconf.la diff --git a/configure.ac b/configure.ac index f38d675..8557992 100644 --- a/configure.ac +++ b/configure.ac @@ -361,6 +361,10 @@ PKG_CHECK_MODULES(VCONF, vconf) AC_SUBST(VCONF_CFLAGS) AC_SUBST(VCONF_LIBS) +PKG_CHECK_MODULES(DNSSD, dns_sd) +AC_SUBST(DNSSD_CFLAGS) +AC_SUBST(DNSSD_LIBS) + dnl use hal tc ------------------------------------------------------------ AC_ARG_ENABLE(haltc, AC_HELP_STRING([--enable-haltc], [using haltc]), [ diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 3944878..c3749d4 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.20 +Version: 13.0.21 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ @@ -20,6 +20,7 @@ BuildRequires: mm-hal-interface-devel BuildRequires: pkgconfig(libpulse) BuildRequires: pkgconfig(pulsecore) BuildRequires: pkgconfig(libsystemd) +BuildRequires: pkgconfig(dns_sd) BuildRequires: pulseaudio BuildRequires: m4 Requires(post): /sbin/ldconfig @@ -74,6 +75,8 @@ install -m 0644 %SOURCE1 %{buildroot}%{_tmpfilesdir}/pulseaudio.conf %{_libdir}/pulse-13.0/modules/module-tizenaudio-policy.so %{_libdir}/pulse-13.0/modules/module-tizenaudio-sink.so %{_libdir}/pulse-13.0/modules/module-tizenaudio-source.so +%{_libdir}/pulse-13.0/modules/module-tizenaudio-discover.so +%{_libdir}/pulse-13.0/modules/module-tizenaudio-publish.so %{_libdir}/pulse-13.0/modules/libhal-interface.so %{_libdir}/pulse-13.0/modules/libcommunicator.so %{_tmpfilesdir}/pulseaudio.conf diff --git a/src/module-tizenaudio-discover.c b/src/module-tizenaudio-discover.c new file mode 100644 index 0000000..ac88209 --- /dev/null +++ b/src/module-tizenaudio-discover.c @@ -0,0 +1,733 @@ +/*** + This file is part of PulseAudio. + + Copyright 2020 Seungbae Shin + based on module-zeroconf-discover.c + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio 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 + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, see . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +PA_MODULE_AUTHOR("Seungbae Shin"); +PA_MODULE_DESCRIPTION("mDNS/DNS-SD Service Discovery"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(true); + +#define SERVICE_TYPE_SINK "_pulse-sink._tcp" +#define SERVICE_TYPE_SOURCE "_pulse-source._tcp" +#define MAX_IP_ADDR 32 +#define MAX_RECORD_LEN 256 + +static const char * const valid_modargs[] = { + NULL +}; + +typedef struct dns_request_data { + DNSServiceRef sd_ref; + pa_io_event *io; +} dns_request_data_t; + +typedef struct service_data { + struct userdata *u; + + int protocol; + dns_request_data_t resolve; + dns_request_data_t addr; + + /* browse */ + int flags; + unsigned int interface; + char *service_name; + char *service_type; + char *domain; + + /* resolve */ + char *host_name; + unsigned short port; + + char *device; + pa_sample_spec ss; + pa_channel_map cm; + bool channel_map_set; + + /* address */ + char *ip_address; +} service_data_t; + +struct tunnel { + unsigned int interface; + int protocol; + char *name, *type, *domain; + uint32_t module_index; +}; + +struct userdata { + pa_core *core; + pa_module *module; + + dns_request_data_t browse_sink; + dns_request_data_t browse_source; + + pa_hashmap *tunnels; +}; + +static unsigned tunnel_hash(const void *p) { + const struct tunnel *t = p; + + return + (unsigned) t->interface + + (unsigned) t->protocol + + pa_idxset_string_hash_func(t->name) + + pa_idxset_string_hash_func(t->type) + + pa_idxset_string_hash_func(t->domain); +} + +static int tunnel_compare(const void *a, const void *b) { + const struct tunnel *ta = a, *tb = b; + int r; + + if (ta->interface != tb->interface) + return 1; + if (ta->protocol != tb->protocol) + return 1; + if ((r = strcmp(ta->name, tb->name))) + return r; + if ((r = strcmp(ta->type, tb->type))) + return r; + if ((r = strcmp(ta->domain, tb->domain))) + return r; + + return 0; +} + +static struct tunnel *tunnel_new( + unsigned int interface, int protocol, + const char *name, const char *type, const char *domain) { + struct tunnel *t; + t = pa_xnew0(struct tunnel, 1); + t->interface = interface; + t->protocol = protocol; + t->name = pa_xstrdup(name); + t->type = pa_xstrdup(type); + t->domain = pa_xstrdup(domain); + t->module_index = PA_IDXSET_INVALID; + return t; +} + +static void tunnel_free(struct tunnel *t) { + pa_assert(t); + pa_xfree(t->name); + pa_xfree(t->type); + pa_xfree(t->domain); + pa_xfree(t); +} + +static service_data_t *service_data_new() { + return pa_xnew0(service_data_t, 1); +} + +static void service_data_free(service_data_t *data) { + pa_assert(data); + + pa_xfree(data->service_name); + pa_xfree(data->service_type); + pa_xfree(data->domain); + pa_xfree(data->host_name); + pa_xfree(data->ip_address); + pa_xfree(data->device); + + pa_xfree(data); +} + + +static int request_set_io_callback(pa_mainloop_api *m_api, dns_request_data_t *request, pa_io_event_cb_t cb, void *user_data) { + int fd = -1; + + pa_assert(request); + pa_assert(request->sd_ref); + + fd = DNSServiceRefSockFD(request->sd_ref); + + if (fd < 0) { + pa_log_error("DNSServiceRefSockFD(%p) error", request->sd_ref); + return -1; + } + + request->io = m_api->io_new(m_api, fd, + PA_IO_EVENT_INPUT|PA_IO_EVENT_HANGUP, + cb, user_data); + + pa_log_info("io(%p) with cb(%p) added for fd(%d)", request->io, cb, fd); + + return 0; +} + +static void request_clear(pa_mainloop_api *m_api, dns_request_data_t *request) { + if (request->sd_ref) { + DNSServiceRefDeallocate(request->sd_ref); + request->sd_ref = NULL; + } + + if (request->io) { + m_api->io_free(request->io); + request->io = NULL; + } +} + +static char *get_ip_str(const struct sockaddr *sa) { + char addr_str[MAX_IP_ADDR] = { 0, }; + + switch(sa->sa_family) { + case AF_INET: + inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr), addr_str, MAX_IP_ADDR); + break; + + case AF_INET6: + inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr), addr_str, MAX_IP_ADDR); + break; + + default: + pa_strlcpy(addr_str, "Unknown AF", MAX_IP_ADDR); + break; + } + + return pa_xstrdup(addr_str); +} + +static void parse_txt_record(service_data_t *data, + const unsigned char *txt_record, + unsigned short txt_len) { + char record_str[MAX_RECORD_LEN] = { 0, }; + int record_len; + const char *key_str = NULL; + const char *val_str = NULL; + const char *state = NULL; + size_t val_len; + const char *delimiter = "="; + const unsigned char *cur = txt_record; + + pa_assert(data); + pa_assert(txt_record); + pa_assert(txt_len > 0); + + while (cur < txt_record + txt_len) { + record_len = *cur; + state = NULL; + + pa_snprintf(record_str, record_len + 1, "%s", ++cur); + + key_str = pa_split_in_place(record_str, delimiter, &val_len, &state); + if (pa_strneq(key_str, "device", val_len)) { + data->device = pa_split(record_str, delimiter, &state); + } else if (pa_strneq(key_str, "rate", val_len)) { + data->ss.rate = (uint32_t)atoi(pa_split_in_place(record_str, delimiter, &val_len, &state)); + } else if (pa_strneq(key_str, "channels", val_len)) { + data->ss.channels = (uint8_t)atoi(pa_split_in_place(record_str, delimiter, &val_len, &state)); + } else if (pa_strneq(key_str, "format", val_len)) { + val_str = pa_split_in_place(record_str, delimiter, &val_len, &state); + data->ss.format = pa_parse_sample_format(val_str); + } else if (pa_strneq(key_str, "channel_map", val_len)) { + val_str = pa_split_in_place(record_str, delimiter, &val_len, &state); + pa_channel_map_parse(&data->cm, val_str); + } + + cur += record_len; + } + pa_log_info("-----------------------------------"); + pa_log_info("device : [%s]", data->device); + pa_log_info("rate : [%d]", data->ss.rate); + pa_log_info("channels : [%d]", data->ss.channels); + pa_log_info("format : [%s]", pa_sample_format_to_string(data->ss.format)); + pa_log_info("channel_map : [%s]", pa_channel_map_to_pretty_name(&data->cm)); + pa_log_info("-----------------------------------"); +} + +static void tunnel_add(service_data_t *data) { + struct tunnel *tnl; + char *dname, *module_name, *args; + const char *t; + char cmt[PA_CHANNEL_MAP_SNPRINT_MAX]; + pa_module *m; + + pa_assert(data); + pa_assert(data->u); + + tnl = tunnel_new(data->interface, data->protocol, data->service_name, data->service_type, data->domain); + + data->ss = data->u->core->default_sample_spec; + data->cm = data->u->core->default_channel_map; + + if (!data->channel_map_set && data->cm.channels != data->ss.channels) + pa_channel_map_init_extend(&data->cm, data->ss.channels, PA_CHANNEL_MAP_DEFAULT); + + if (!pa_sample_spec_valid(&data->ss)) { + pa_log("Service '%s' contains an invalid sample specification.", data->service_name); + goto finish; + } + + if (!pa_channel_map_valid(&data->cm) || data->cm.channels != data->ss.channels) { + pa_log("Service '%s' contains an invalid channel map.", data->service_name); + goto finish; + } + + if (data->device) + dname = pa_sprintf_malloc("tunnel.%s.%s", data->host_name, data->device); + else + dname = pa_sprintf_malloc("tunnel.%s", data->host_name); + + if (!pa_namereg_is_valid_name(dname)) { + pa_log("Cannot construct valid device name from credentials of service '%s'.", dname); + pa_xfree(dname); + goto finish; + } + + t = strstr(data->service_type, "sink") ? "sink" : "source"; + + module_name = pa_sprintf_malloc("module-tunnel-%s", t); + args = pa_sprintf_malloc("server=[%s]:%u " + "%s=%s " + "format=%s " + "channels=%u " + "rate=%u " + "%s_name=%s " + "channel_map=%s", + data->ip_address, + data->port, + t, data->device, + pa_sample_format_to_string(data->ss.format), + data->ss.channels, + data->ss.rate, + t, dname, + pa_channel_map_snprint(cmt, sizeof(cmt), &data->cm)); + + pa_log_debug("Loading %s with arguments '%s'", module_name, args); + + if (pa_module_load(&m, data->u->core, module_name, args) >= 0) { + tnl->module_index = m->index; + pa_hashmap_put(data->u->tunnels, tnl, tnl); + pa_log_info("Module(%u) loaded, Tunnel(%p) added success", m->index, tnl); + tnl = NULL; + } else { + pa_log_error("Failed to load Module(%s)", module_name); + } + + pa_xfree(module_name); + pa_xfree(dname); + pa_xfree(args); + +finish: + + if (tnl) + tunnel_free(tnl); +} + + +static void dnssd_getaddrinfo_reply_cb(DNSServiceRef sd_ref, + unsigned int flags, unsigned int if_index, + DNSServiceErrorType error_code, const char *host_name, + const struct sockaddr *address, unsigned int ttl, + void *user_data) { + service_data_t *data = (service_data_t *)user_data; + + pa_assert(data); + pa_assert(data->u); + + if (flags & kDNSServiceFlagsMoreComing) { + pa_log_warn("More results are queued, No need to send callback to " + "application at this stage"); + return; + } + + if (data->interface != if_index) + pa_log_warn("diff interface %d <=> %d", data->interface, if_index); + if (!pa_safe_streq(data->host_name, host_name)) + pa_log_warn("diff host_name %s <=> %s", data->host_name, host_name); + + data->ip_address = get_ip_str(address); + + pa_log_info("-----------------------------------"); + pa_log_info("Address Reply : ref(%p), userdata(%p), error(%d), flags(0x%x)", + sd_ref, user_data, error_code, flags); + pa_log_info(" Interface Index : %d", if_index); + pa_log_info(" Host Name : %s", data->host_name); + pa_log_info(" IP Address : %s", data->ip_address); + pa_log_info(" TTL : %d", ttl); + + pa_log_info("-----------------------------------"); + + tunnel_add(data); + + /* cleanup addr */ + request_clear(data->u->module->core->mainloop, &data->addr); + + /* cleanup data */ + service_data_free(data); +} + +static void io_addr_event_callback(pa_mainloop_api *io, pa_io_event *e, + int fd, pa_io_event_flags_t events, + void *user_data) { + service_data_t *data = (service_data_t *)user_data; + DNSServiceErrorType err; + + pa_assert(io); + pa_assert(data); + pa_assert(data->u); + + if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { + pa_log_warn("Lost connection fd : %d", fd); + goto fail; + } + + if (events & PA_IO_EVENT_INPUT) { + err = DNSServiceProcessResult(data->addr.sd_ref); + if (err == 0) + pa_log_info("DNSServiceProcessResult(%p, fd:%d) success", data->addr.sd_ref, fd); + else + pa_log_info("DNSServiceProcessResult(%p, fd:%d) error(%d)", data->addr.sd_ref, fd, err); + } + + return; + +fail: + request_clear(data->u->module->core->mainloop, &data->addr); +} + +static int dnssd_getaddrinfo(service_data_t *data) { + int ret; + + ret = DNSServiceGetAddrInfo(&(data->addr.sd_ref), data->flags, data->interface, + data->protocol, data->host_name, + dnssd_getaddrinfo_reply_cb, data); + if (ret != kDNSServiceErr_NoError) { + pa_log_error("DNSServiceGetAddrInfo() error(%d)", ret); + return -1; + } + + pa_log_info("DNSServiceGetAddrInfo(%p) success", data->addr.sd_ref); + + return request_set_io_callback(data->u->module->core->mainloop, &data->addr, io_addr_event_callback, data); +} + +static void dnssd_resolve_reply_cb(DNSServiceRef sd_ref, unsigned int flags, + unsigned int if_index, DNSServiceErrorType error_code, + const char *fullname, const char *host_name, + unsigned short port, unsigned short txt_len, + const unsigned char *txt_record, void *user_data) { + int ret; + service_data_t *data = (service_data_t *)user_data; + + pa_assert(data); + pa_assert(data->u); + + if (flags & kDNSServiceFlagsMoreComing) { + pa_log_warn("More results are queued"); + return; + } + + if (data->interface != if_index) + pa_log_warn("diff interface %d <=> %d", data->interface, if_index); + + data->flags = flags; + data->host_name = pa_xstrdup(host_name); + data->port = ntohs(port); + + pa_log_info("-----------------------------------"); + pa_log_info("Resolve Reply : ref(%p), userdata(%p), error(%d), flags(0x%x)", + sd_ref, user_data, error_code, flags); + pa_log_info(" Interface Index : %d", if_index); + pa_log_info(" Full Name : %s", fullname); + pa_log_info(" Host Name : %s", data->host_name); + pa_log_info(" Port : %d", data->port); + pa_log_info(" Text Record : [%p][%d]", txt_record, txt_len); + pa_log_info("-----------------------------------"); + + parse_txt_record(data, txt_record, txt_len); + + /* cleanup resolve */ + request_clear(data->u->module->core->mainloop, &data->resolve); + + /* Get Address Info details and send browse callback */ + ret = dnssd_getaddrinfo(data); + if (ret < 0) { + pa_log_error("failed to get address info!"); + service_data_free(data); + } +} + + +static void io_resolve_event_callback(pa_mainloop_api *io, pa_io_event *e, int fd, + pa_io_event_flags_t events, void *user_data) { + service_data_t *data = (service_data_t *)user_data; + DNSServiceErrorType err; + + pa_assert(io); + pa_assert(data); + pa_assert(data->u); + + if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { + pa_log_warn("Lost connection fd : %d", fd); + goto fail; + } + + if (events & PA_IO_EVENT_INPUT) { + err = DNSServiceProcessResult(data->resolve.sd_ref); + if (err == 0) + pa_log_info("DNSServiceProcessResult(%p, fd:%d) success", data->resolve.sd_ref, fd); + else + pa_log_info("DNSServiceProcessResult(%p, fd:%d) error(%d)", data->resolve.sd_ref, fd, err); + } + + return; + +fail: + request_clear(data->u->module->core->mainloop, &data->resolve); +} + + +static int dnssd_resolve_dns_service(struct userdata *u, + unsigned int flags, unsigned int if_index, int protocol, + const char *service_name, const char *service_type, + const char *domain) { + int ret; + + service_data_t *data = service_data_new(); + data->u = u; + data->flags = flags; + data->interface = if_index; + data->protocol = protocol; + data->service_name = pa_xstrdup(service_name); + data->service_type = pa_xstrdup(service_type); + data->domain = pa_xstrdup(domain); + + ret = DNSServiceResolve(&(data->resolve.sd_ref), + flags, if_index, + service_name, service_type, + domain, + dnssd_resolve_reply_cb, + data); + if (ret != kDNSServiceErr_NoError) { + pa_log_error("DNSServiceResolve() error(%d)", ret); + goto fail; + } + + pa_log_info("DNSServiceResolve(%p) success", data->resolve.sd_ref); + + ret = request_set_io_callback(u->module->core->mainloop, &data->resolve, io_resolve_event_callback, data); + if (ret < 0) + goto fail; + + return 0; + +fail: + service_data_free(data); + return -1; +} + +static void dnssd_browse_reply_cb(DNSServiceRef sd_ref, unsigned int flags, + unsigned int if_index, DNSServiceErrorType error_code, + const char *service_name, const char *service_type, + const char *domain, void *user_data) { + struct userdata *u = user_data; + struct tunnel *t; + int protocol = kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6; + + pa_log_info("-----------------------------------"); + pa_log_info("Browse Reply : ref(%p), userdata(%p), error(%d), flags(0x%x)", + sd_ref, user_data, error_code, flags); + pa_log_info(" Interface Index : %d", if_index); + pa_log_info(" Service Name : %s", service_name); + pa_log_info(" Service Type : %s", service_type); + pa_log_info(" Domain : %s", domain); + pa_log_info("-----------------------------------"); + + t = tunnel_new(if_index, protocol, service_name, service_type, domain); + + if (flags & kDNSServiceFlagsAdd) { + if (!pa_hashmap_get(u->tunnels, t)) + dnssd_resolve_dns_service(u, flags, if_index, protocol, + service_name, service_type, domain); + else + pa_log_warn("already exists %p", t); + } else { + struct tunnel *t2; + + if ((t2 = pa_hashmap_get(u->tunnels, t))) { + pa_module_unload_request_by_index(u->core, t2->module_index, true); + pa_hashmap_remove(u->tunnels, t2); + pa_log_info("Module(%u) Unloaded, Tunnel(%p) removed success", t2->module_index, t2); + tunnel_free(t2); + } else { + pa_log_warn("Not found %p", t); + } + } +} + +static void io_browse_handle_event(pa_mainloop_api *io, pa_io_event *e, int fd, + pa_io_event_flags_t events, struct userdata *u, dns_request_data_t *request) { + DNSServiceErrorType err; + + pa_assert(io); + pa_assert(u); + + if (events & (PA_IO_EVENT_HANGUP|PA_IO_EVENT_ERROR)) { + pa_log_warn("Lost connection fd : %d", fd); + goto fail; + } + + if (events & PA_IO_EVENT_INPUT) { + err = DNSServiceProcessResult(request->sd_ref); + if (err == 0) + pa_log_info("DNSServiceProcessResult(%p, fd:%d) success", request->sd_ref, fd); + else + pa_log_info("DNSServiceProcessResult(%p, fd:%d) error(%d)", request->sd_ref, fd, err); + } + + return; + +fail: + request_clear(u->module->core->mainloop, request); + pa_module_unload_request(u->module, true); +} + +static void io_browse_sink_event_callback(pa_mainloop_api *io, pa_io_event *e, int fd, + pa_io_event_flags_t events, void *user_data) { + struct userdata *u = user_data; + + io_browse_handle_event(io, e, fd, events, u, &u->browse_sink); +} + +static void io_browse_source_event_callback(pa_mainloop_api *io, pa_io_event *e, int fd, + pa_io_event_flags_t events, void *user_data) { + struct userdata *u = user_data; + + io_browse_handle_event(io, e, fd, events, u, &u->browse_source); +} + +static int dnssd_browse_dns_service(struct userdata *u, const char *service_type) { + int ret; + dns_request_data_t *request; + pa_io_event_cb_t cb; + + if (pa_safe_streq(service_type, SERVICE_TYPE_SINK)) { + request = &u->browse_sink; + cb = io_browse_sink_event_callback; + } else if (pa_safe_streq(service_type, SERVICE_TYPE_SOURCE)) { + request = &u->browse_source; + cb = io_browse_source_event_callback; + } else { + pa_log_error("invalid service type %s", pa_strnull(service_type)); + return -1; + } + + ret = DNSServiceBrowse(&request->sd_ref, 0, + kDNSServiceInterfaceIndexAny, service_type, + NULL, dnssd_browse_reply_cb, + u); + if (ret != kDNSServiceErr_NoError) { + pa_log_error("DNSServiceBrowse() with %s error(%d)", service_type, ret); + return -1; + } + + pa_log_info("DNSServiceBrowse(%p) success", request->sd_ref); + + ret = request_set_io_callback(u->module->core->mainloop, request, cb, u); + if (ret < 0) { + request_clear(u->module->core->mainloop, request); + return -1; + } + + return 0; +} + +void pa__done(pa_module *m) { + struct userdata *u; + pa_assert(m); + + if (!(u = m->userdata)) + return; + + if (u->tunnels) { + struct tunnel *t; + + while ((t = pa_hashmap_steal_first(u->tunnels))) { + pa_module_unload_request_by_index(u->core, t->module_index, true); + tunnel_free(t); + } + + pa_hashmap_free(u->tunnels); + } + + request_clear(u->module->core->mainloop, &u->browse_sink); + request_clear(u->module->core->mainloop, &u->browse_source); + + pa_xfree(u); +} + +int pa__init(pa_module *m) { + + struct userdata *u; + pa_modargs *ma = NULL; + int ret; + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log("Failed to parse module arguments."); + goto fail; + } + + m->userdata = u = pa_xnew(struct userdata, 1); + u->core = m->core; + u->module = m; + u->tunnels = pa_hashmap_new(tunnel_hash, tunnel_compare); + + ret = dnssd_browse_dns_service(u, SERVICE_TYPE_SINK); + if (ret < 0) + goto fail; + + ret = dnssd_browse_dns_service(u, SERVICE_TYPE_SOURCE); + if (ret < 0) + goto fail; + + pa_modargs_free(ma); + + return 0; + +fail: + pa__done(m); + + if (ma) + pa_modargs_free(ma); + + return -1; +} diff --git a/src/module-tizenaudio-publish.c b/src/module-tizenaudio-publish.c new file mode 100644 index 0000000..480b98f --- /dev/null +++ b/src/module-tizenaudio-publish.c @@ -0,0 +1,513 @@ +/*** + This file is part of PulseAudio. + + Copyright 2020 Seungbae Shin + based on module-bonjour-publish.c + + PulseAudio is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + PulseAudio 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 + General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with PulseAudio; if not, see . +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +PA_MODULE_AUTHOR("Seungbae Shin"); +PA_MODULE_DESCRIPTION("mDNS/DNS-SD Service Publisher"); +PA_MODULE_VERSION(PACKAGE_VERSION); +PA_MODULE_LOAD_ONCE(true); + +#define SERVICE_TYPE_SINK "_pulse-sink._tcp" +#define SERVICE_TYPE_SOURCE "_pulse-source._tcp" +#define SERVICE_TYPE_SERVER "_pulse-server._tcp" + +static const char* const valid_modargs[] = { + NULL +}; + +enum service_subtype { + SUBTYPE_HARDWARE, + SUBTYPE_VIRTUAL, + SUBTYPE_MONITOR +}; + +struct service { + struct userdata *userdata; + DNSServiceRef service; + DNSRecordRef rec, rec2; + char *service_name; + pa_object *device; + enum service_subtype subtype; +}; + +struct userdata { + pa_core *core; + pa_module *module; + + pa_hashmap *services; + char *service_name; + + pa_hook_slot *sink_new_slot, *source_new_slot, *sink_unlink_slot, *source_unlink_slot, *sink_changed_slot, *source_changed_slot; + + pa_native_protocol *native; + DNSServiceRef main_service; +}; + +static void get_service_data(struct service *s, pa_sample_spec *ret_ss, pa_channel_map *ret_map, const char **ret_name, pa_proplist **ret_proplist, enum service_subtype *ret_subtype) { + pa_assert(s); + pa_assert(ret_ss); + pa_assert(ret_proplist); + pa_assert(ret_subtype); + + if (pa_sink_isinstance(s->device)) { + pa_sink *sink = PA_SINK(s->device); + + *ret_ss = sink->sample_spec; + *ret_map = sink->channel_map; + *ret_name = sink->name; + *ret_proplist = sink->proplist; + *ret_subtype = sink->flags & PA_SINK_HARDWARE ? SUBTYPE_HARDWARE : SUBTYPE_VIRTUAL; + + } else if (pa_source_isinstance(s->device)) { + pa_source *source = PA_SOURCE(s->device); + + *ret_ss = source->sample_spec; + *ret_map = source->channel_map; + *ret_name = source->name; + *ret_proplist = source->proplist; + *ret_subtype = source->monitor_of ? SUBTYPE_MONITOR : (source->flags & PA_SOURCE_HARDWARE ? SUBTYPE_HARDWARE : SUBTYPE_VIRTUAL); + + } else { + pa_assert_not_reached(); + } +} + +static void txt_record_server_data(pa_core *c, TXTRecordRef *txt) { + char s[128]; + char *t; + + pa_assert(c); + + TXTRecordSetValue(txt, "server-version", strlen(PACKAGE_NAME" "PACKAGE_VERSION), PACKAGE_NAME" "PACKAGE_VERSION); + + t = pa_get_user_name_malloc(); + TXTRecordSetValue(txt, "user-name", strlen(t), t); + pa_xfree(t); + + t = pa_machine_id(); + TXTRecordSetValue(txt, "machine-id", strlen(t), t); + pa_xfree(t); + + t = pa_uname_string(); + TXTRecordSetValue(txt, "uname", strlen(t), t); + pa_xfree(t); + + t = pa_get_fqdn(s, sizeof(s)); + TXTRecordSetValue(txt, "fqdn", strlen(t), t); + + snprintf(s, sizeof(s), "0x%08x", c->cookie); + TXTRecordSetValue(txt, "cookie", strlen(s), s); +} + +static void service_free(struct service *s); + +static void dns_service_register_reply(DNSServiceRef sdRef, + DNSServiceFlags flags, + DNSServiceErrorType errorCode, + const char *name, + const char *regtype, + const char *domain, + void *context) { + struct service *s = context; + + pa_assert(s); + + switch (errorCode) { + case kDNSServiceErr_NameConflict: + pa_log("DNS service reported kDNSServiceErr_NameConflict\n"); + service_free(s); + break; + + case kDNSServiceErr_NoError: + /* fall through */ + default: + break; + } +} + +static uint16_t compute_port(struct userdata *u) { + pa_strlist *i; + + pa_assert(u); + + for (i = pa_native_protocol_servers(u->native); i; i = pa_strlist_next(i)) { + pa_parsed_address a; + + if (pa_parse_address(pa_strlist_data(i), &a) >= 0 && + (a.type == PA_PARSED_ADDRESS_TCP4 || + a.type == PA_PARSED_ADDRESS_TCP6 || + a.type == PA_PARSED_ADDRESS_TCP_AUTO) && + a.port > 0) { + + pa_xfree(a.path_or_host); + return htons(a.port); + } + + pa_xfree(a.path_or_host); + } + + return htons(PA_NATIVE_DEFAULT_PORT); +} + +static int publish_service(struct service *s) { + int r = -1; + TXTRecordRef txt; + DNSServiceErrorType err; + const char *name = NULL, *t; + pa_proplist *proplist = NULL; + pa_sample_spec ss; + pa_channel_map map; + char cm[PA_CHANNEL_MAP_SNPRINT_MAX], tmp[64]; + enum service_subtype subtype; + + const char * const subtype_text[] = { + [SUBTYPE_HARDWARE] = "hardware", + [SUBTYPE_VIRTUAL] = "virtual", + [SUBTYPE_MONITOR] = "monitor" + }; + + pa_assert(s); + + if (s->service) { + DNSServiceRefDeallocate(s->service); + s->service = NULL; + } + + TXTRecordCreate(&txt, 0, NULL); + + txt_record_server_data(s->userdata->core, &txt); + + get_service_data(s, &ss, &map, &name, &proplist, &subtype); + TXTRecordSetValue(&txt, "device", strlen(name), name); + + snprintf(tmp, sizeof(tmp), "%u", ss.rate); + TXTRecordSetValue(&txt, "rate", strlen(tmp), tmp); + + snprintf(tmp, sizeof(tmp), "%u", ss.channels); + TXTRecordSetValue(&txt, "channels", strlen(tmp), tmp); + + t = pa_sample_format_to_string(ss.format); + TXTRecordSetValue(&txt, "format", strlen(t), t); + + t = pa_channel_map_snprint(cm, sizeof(cm), &map); + TXTRecordSetValue(&txt, "channel_map", strlen(t), t); + + t = subtype_text[subtype]; + TXTRecordSetValue(&txt, "subtype", strlen(t), t); + + if ((t = pa_proplist_gets(proplist, PA_PROP_DEVICE_DESCRIPTION))) + TXTRecordSetValue(&txt, "description", strlen(t), t); + if ((t = pa_proplist_gets(proplist, PA_PROP_DEVICE_ICON_NAME))) + TXTRecordSetValue(&txt, "icon-name", strlen(t), t); + if ((t = pa_proplist_gets(proplist, PA_PROP_DEVICE_VENDOR_NAME))) + TXTRecordSetValue(&txt, "vendor-name", strlen(t), t); + if ((t = pa_proplist_gets(proplist, PA_PROP_DEVICE_PRODUCT_NAME))) + TXTRecordSetValue(&txt, "product-name", strlen(t), t); + if ((t = pa_proplist_gets(proplist, PA_PROP_DEVICE_CLASS))) + TXTRecordSetValue(&txt, "class", strlen(t), t); + if ((t = pa_proplist_gets(proplist, PA_PROP_DEVICE_FORM_FACTOR))) + TXTRecordSetValue(&txt, "form-factor", strlen(t), t); + + err = DNSServiceRegister(&s->service, + 0, /* flags */ + kDNSServiceInterfaceIndexAny, + s->service_name, + pa_sink_isinstance(s->device) ? SERVICE_TYPE_SINK : SERVICE_TYPE_SOURCE, + NULL, /* domain */ + NULL, /* host */ + compute_port(s->userdata), + TXTRecordGetLength(&txt), + TXTRecordGetBytesPtr(&txt), + dns_service_register_reply, s); + + if (err != kDNSServiceErr_NoError) { + pa_log("DNSServiceRegister() returned err %d", err); + goto finish; + } + + pa_log_debug("Successfully registered mDNS services for >%s<.", s->service_name); + return 0; + +finish: + + /* Remove this service */ + if (r < 0) + service_free(s); + + TXTRecordDeallocate(&txt); + + return r; +} + +static struct service *get_service(struct userdata *u, pa_object *device) { + struct service *s; + char *hn, *un; + const char *n; + + pa_assert(u); + pa_object_assert_ref(device); + + if ((s = pa_hashmap_get(u->services, device))) + return s; + + s = pa_xnew0(struct service, 1); + s->userdata = u; + s->device = device; + + if (pa_sink_isinstance(device)) { + if (!(n = pa_proplist_gets(PA_SINK(device)->proplist, PA_PROP_DEVICE_DESCRIPTION))) + n = PA_SINK(device)->name; + } else { + if (!(n = pa_proplist_gets(PA_SOURCE(device)->proplist, PA_PROP_DEVICE_DESCRIPTION))) + n = PA_SOURCE(device)->name; + } + + hn = pa_get_host_name_malloc(); + un = pa_get_user_name_malloc(); + + s->service_name = pa_truncate_utf8(pa_sprintf_malloc("%s@%s: %s", un, hn, n), kDNSServiceMaxDomainName-1); + + pa_xfree(un); + pa_xfree(hn); + + pa_hashmap_put(u->services, s->device, s); + + return s; +} + +static void service_free(struct service *s) { + pa_assert(s); + + pa_hashmap_remove(s->userdata->services, s->device); + + if (s->service) + DNSServiceRefDeallocate(s->service); + + pa_xfree(s->service_name); + pa_xfree(s); +} + +static bool shall_ignore(pa_object *o) { + pa_object_assert_ref(o); + + if (pa_sink_isinstance(o)) + return !!(PA_SINK(o)->flags & PA_SINK_NETWORK); + + if (pa_source_isinstance(o)) + return PA_SOURCE(o)->monitor_of || (PA_SOURCE(o)->flags & PA_SOURCE_NETWORK); + + pa_assert_not_reached(); +} + +static pa_hook_result_t device_new_or_changed_cb(pa_core *c, pa_object *o, struct userdata *u) { + pa_assert(c); + pa_object_assert_ref(o); + + if (!shall_ignore(o)) + publish_service(get_service(u, o)); + + return PA_HOOK_OK; +} + +static pa_hook_result_t device_unlink_cb(pa_core *c, pa_object *o, struct userdata *u) { + struct service *s; + + pa_assert(c); + pa_object_assert_ref(o); + + if ((s = pa_hashmap_get(u->services, o))) + service_free(s); + + return PA_HOOK_OK; +} + +static int publish_main_service(struct userdata *u) { + DNSServiceErrorType err; + TXTRecordRef txt; + + pa_assert(u); + + if (u->main_service) { + DNSServiceRefDeallocate(u->main_service); + u->main_service = NULL; + } + + TXTRecordCreate(&txt, 0, NULL); + txt_record_server_data(u->core, &txt); + + err = DNSServiceRegister(&u->main_service, + 0, /* flags */ + kDNSServiceInterfaceIndexAny, + u->service_name, + SERVICE_TYPE_SERVER, + NULL, /* domain */ + NULL, /* host */ + compute_port(u), + TXTRecordGetLength(&txt), + TXTRecordGetBytesPtr(&txt), + NULL, NULL); + + if (err != kDNSServiceErr_NoError) { + pa_log("DNSServiceRegister() returned err %d", err); + return err; + } + + TXTRecordDeallocate(&txt); + + return 0; +} + +static int publish_all_services(struct userdata *u) { + pa_sink *sink; + pa_source *source; + uint32_t idx; + + pa_assert(u); + + pa_log_debug("Publishing services in mDNS"); + + for (sink = PA_SINK(pa_idxset_first(u->core->sinks, &idx)); sink; sink = PA_SINK(pa_idxset_next(u->core->sinks, &idx))) + if (!shall_ignore(PA_OBJECT(sink))) + publish_service(get_service(u, PA_OBJECT(sink))); + + for (source = PA_SOURCE(pa_idxset_first(u->core->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(u->core->sources, &idx))) + if (!shall_ignore(PA_OBJECT(source))) + publish_service(get_service(u, PA_OBJECT(source))); + + return publish_main_service(u); +} + +static void unpublish_all_services(struct userdata *u) { + void *state = NULL; + struct service *s; + + pa_assert(u); + + pa_log_debug("Unpublishing services in mDNS"); + + while ((s = pa_hashmap_iterate(u->services, &state, NULL))) + service_free(s); + + if (u->main_service) + DNSServiceRefDeallocate(u->main_service); +} + +void pa__done(pa_module *m) { + struct userdata *u; + pa_assert(m); + + if (!(u = m->userdata)) + return; + + unpublish_all_services(u); + + if (u->services) + pa_hashmap_free(u->services); + + if (u->sink_new_slot) + pa_hook_slot_free(u->sink_new_slot); + if (u->source_new_slot) + pa_hook_slot_free(u->source_new_slot); + if (u->sink_changed_slot) + pa_hook_slot_free(u->sink_changed_slot); + if (u->source_changed_slot) + pa_hook_slot_free(u->source_changed_slot); + if (u->sink_unlink_slot) + pa_hook_slot_free(u->sink_unlink_slot); + if (u->source_unlink_slot) + pa_hook_slot_free(u->source_unlink_slot); + + if (u->native) + pa_native_protocol_unref(u->native); + + pa_xfree(u->service_name); + pa_xfree(u); +} + +int pa__init(pa_module *m) { + struct userdata *u; + pa_modargs *ma = NULL; + char *hn, *un; + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + pa_log("Failed to parse module arguments."); + goto fail; + } + + m->userdata = u = pa_xnew0(struct userdata, 1); + u->core = m->core; + u->module = m; + u->native = pa_native_protocol_get(u->core); + + u->services = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); + + u->sink_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE, (pa_hook_cb_t) device_new_or_changed_cb, u); + u->sink_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], PA_HOOK_LATE, (pa_hook_cb_t) device_new_or_changed_cb, u); + u->sink_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) device_unlink_cb, u); + u->source_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE, (pa_hook_cb_t) device_new_or_changed_cb, u); + u->source_changed_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], PA_HOOK_LATE, (pa_hook_cb_t) device_new_or_changed_cb, u); + u->source_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_LATE, (pa_hook_cb_t) device_unlink_cb, u); + + un = pa_get_user_name_malloc(); + hn = pa_get_host_name_malloc(); + u->service_name = pa_truncate_utf8(pa_sprintf_malloc("%s@%s", un, hn), kDNSServiceMaxDomainName-1); + pa_xfree(un); + pa_xfree(hn); + + if (publish_all_services(u) != 0) + goto fail; + + pa_modargs_free(ma); + + return 0; + +fail: + pa__done(m); + + if (ma) + pa_modargs_free(ma); + + return -1; +} -- 2.7.4 From 8e05a49407271c3b185298a7634b99c0be1bfdac Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Mon, 13 Jul 2020 11:12:18 +0900 Subject: [PATCH 03/16] tizenaudio-discover: ignore local services [Version] 13.0.22 [Issue Type] Update Change-Id: I6e8f334e6a16f5f4367c002ea5bd5809dc6b561b --- Makefile.am | 4 ++-- packaging/pulseaudio-modules-tizen.spec | 2 +- src/module-tizenaudio-discover.c | 19 +++++++++++++++++-- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/Makefile.am b/Makefile.am index 07985dc..90d1260 100644 --- a/Makefile.am +++ b/Makefile.am @@ -119,8 +119,8 @@ endif module_tizenaudio_discover_la_SOURCES = src/module-tizenaudio-discover.c module_tizenaudio_discover_la_LDFLAGS = $(MODULE_LDFLAGS) -module_tizenaudio_discover_la_LIBADD = $(MODULE_LIBADD) $(DNSSD_LIBS) -module_tizenaudio_discover_la_CFLAGS = $(MODULE_CFLAGS) $(DNSSD_CFLAGS) +module_tizenaudio_discover_la_LIBADD = $(MODULE_LIBADD) $(DNSSD_LIBS) $(VCONF_LIBS) +module_tizenaudio_discover_la_CFLAGS = $(MODULE_CFLAGS) $(DNSSD_CFLAGS) $(VCONF_CFLAGS) module_tizenaudio_publish_la_SOURCES = src/module-tizenaudio-publish.c module_tizenaudio_publish_la_LDFLAGS = $(MODULE_LDFLAGS) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index c3749d4..541fad8 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.21 +Version: 13.0.22 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/module-tizenaudio-discover.c b/src/module-tizenaudio-discover.c index ac88209..8b3ec80 100644 --- a/src/module-tizenaudio-discover.c +++ b/src/module-tizenaudio-discover.c @@ -26,10 +26,13 @@ #include #include #include +#include #include #include #include +#include +#include #include @@ -352,6 +355,16 @@ finish: tunnel_free(tnl); } +static bool is_local_service(const char *ip_addr) { + char *ipv4_addr = NULL; + bool is_local = false; + + ipv4_addr = vconf_get_str(VCONFKEY_NETWORK_IP); + is_local = pa_safe_streq(ipv4_addr, ip_addr); + pa_xfree(ipv4_addr); + + return is_local; +} static void dnssd_getaddrinfo_reply_cb(DNSServiceRef sd_ref, unsigned int flags, unsigned int if_index, @@ -383,10 +396,12 @@ static void dnssd_getaddrinfo_reply_cb(DNSServiceRef sd_ref, pa_log_info(" Host Name : %s", data->host_name); pa_log_info(" IP Address : %s", data->ip_address); pa_log_info(" TTL : %d", ttl); - pa_log_info("-----------------------------------"); - tunnel_add(data); + if (is_local_service(data->ip_address)) + pa_log_info("Skip local service!!!"); + else + tunnel_add(data); /* cleanup addr */ request_clear(data->u->module->core->mainloop, &data->addr); -- 2.7.4 From c50510164267eed6d013f9c665fce7eda12c8dfb Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Tue, 14 Jul 2020 20:24:16 +0900 Subject: [PATCH 04/16] tizenaudio-discover: use new tunnel module [Version] 13.0.23 [Issue Type] Update Change-Id: I42946234489dffb5e936d49ce7a6eb46aec5dcaa --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/module-tizenaudio-discover.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 541fad8..78eccb1 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.22 +Version: 13.0.23 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/module-tizenaudio-discover.c b/src/module-tizenaudio-discover.c index 8b3ec80..798f006 100644 --- a/src/module-tizenaudio-discover.c +++ b/src/module-tizenaudio-discover.c @@ -317,7 +317,7 @@ static void tunnel_add(service_data_t *data) { t = strstr(data->service_type, "sink") ? "sink" : "source"; - module_name = pa_sprintf_malloc("module-tunnel-%s", t); + module_name = pa_sprintf_malloc("module-tunnel-%s-new", t); args = pa_sprintf_malloc("server=[%s]:%u " "%s=%s " "format=%s " -- 2.7.4 From 2e2db377b4dfd8293a393ca8a8cb7a0e303f9807 Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Mon, 13 Jul 2020 11:13:47 +0900 Subject: [PATCH 05/16] tizenaudio-publish: publish only built-in devices [Version] 13.0.24 [Issue Type] Update Change-Id: I69753da561c813c80c35df7690d4efc1efc48a43 --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/module-tizenaudio-publish.c | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 78eccb1..9324ca1 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.23 +Version: 13.0.24 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/module-tizenaudio-publish.c b/src/module-tizenaudio-publish.c index 480b98f..cdead84 100644 --- a/src/module-tizenaudio-publish.c +++ b/src/module-tizenaudio-publish.c @@ -329,14 +329,30 @@ static void service_free(struct service *s) { pa_xfree(s); } +static bool is_builtin_device(pa_proplist *pl) +{ + /* FIXME: Determining the built-in device should be retrieved from device-manager. */ + return pa_safe_streq(pa_proplist_gets(pl, PA_PROP_DEVICE_FORM_FACTOR), "internal"); +} + static bool shall_ignore(pa_object *o) { pa_object_assert_ref(o); - if (pa_sink_isinstance(o)) + if (pa_sink_isinstance(o)) { + if (!is_builtin_device(PA_SINK(o)->proplist)) { + pa_log_error("sink [%s] is not an internal, skip this", PA_SINK(o)->name); + return true; + } return !!(PA_SINK(o)->flags & PA_SINK_NETWORK); + } - if (pa_source_isinstance(o)) + if (pa_source_isinstance(o)) { + if (!is_builtin_device(PA_SOURCE(o)->proplist)) { + pa_log_error("source [%s] is not an internal, skip this", PA_SOURCE(o)->name); + return true; + } return PA_SOURCE(o)->monitor_of || (PA_SOURCE(o)->flags & PA_SOURCE_NETWORK); + } pa_assert_not_reached(); } -- 2.7.4 From c3a2c2f15263d3af53c3904da00631e6da68db89 Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Tue, 18 Aug 2020 19:36:53 +0900 Subject: [PATCH 06/16] device-manager: handle tunnel device tunnel device will be registered(unregistered) when the remote access permission is allowed(denied). tunnel device will be a network type device [Version] 13.0.25 [Issue Type] Update Change-Id: I897fcb5a74ee55c60112e5a9d956c909aae736d0 --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/device-manager-priv.h | 2 + src/device-manager.c | 109 ++++++++++++++++++++++++++++++++ src/tizen-device-def.h | 1 + 4 files changed, 113 insertions(+), 1 deletion(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 9324ca1..3d9e02b 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.24 +Version: 13.0.25 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/device-manager-priv.h b/src/device-manager-priv.h index faf4b1d..5e17f2c 100644 --- a/src/device-manager-priv.h +++ b/src/device-manager-priv.h @@ -53,6 +53,8 @@ struct _device_manager { pa_hook_slot *comm_hook_device_connection_changed_slot; pa_hook_slot *comm_hook_device_state_changed_slot; pa_hook_slot *comm_hook_device_running_changed_slot; + pa_hook_slot *source_proplist_changed_slot; + pa_hook_slot *sink_proplist_changed_slot; pa_communicator *comm; pa_hal_interface *hal_interface; diff --git a/src/device-manager.c b/src/device-manager.c index 6276308..7fc3435 100644 --- a/src/device-manager.c +++ b/src/device-manager.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -80,6 +81,7 @@ #define DEVICE_API_NULL "null" #define DEVICE_API_ACM "acm" #define DEVICE_API_RAOP "raop" +#define DEVICE_API_TUNNEL "tunnel" #define DEVICE_BUS_USB "usb" #define DEVICE_CLASS_SOUND "sound" #define DEVICE_CLASS_MONITOR "monitor" @@ -397,6 +399,14 @@ static bool pulse_device_is_raop(pa_object *pdevice) { return pa_safe_streq(pa_proplist_gets(prop, PA_PROP_DEVICE_API), DEVICE_API_RAOP); } +static bool pulse_device_is_tunnel(pa_object *pdevice) { + pa_proplist *prop = pulse_device_get_proplist(pdevice); + + if (!prop) + return false; + + return pa_safe_streq(pa_proplist_gets(prop, PA_PROP_DEVICE_API), DEVICE_API_TUNNEL); +} static bool pulse_device_is_tizenaudio(pa_object *pdevice) { if (!pdevice) @@ -1140,6 +1150,8 @@ static const char* pulse_device_get_system_id(pa_object *pdevice) { return pa_proplist_gets(prop, "bluez.path"); else if (pulse_device_is_raop(pdevice)) return pa_proplist_gets(prop, PA_PROP_DEVICE_STRING); + else if (pulse_device_is_tunnel(pdevice)) + return pa_proplist_gets(prop, PA_PROP_DEVICE_DESCRIPTION); else return NULL; } @@ -1469,6 +1481,43 @@ static void handle_raop_pulse_device(pa_object *pdevice, bool is_loaded, pa_devi } } +static void handle_tunnel_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *dm) { + dm_device_direction_t direction; + pa_tz_device *device; + const char *system_id; + + pa_assert(pdevice); + pa_assert(dm); + + pa_log_info("Handle TUNNEL pulse device"); + + direction = pulse_device_get_direction(pdevice); + system_id = pulse_device_get_system_id(pdevice); + + if (is_loaded) { + pa_tz_device_new_data data; + + pa_proplist *prop = pulse_device_get_proplist(pdevice); + const char *name = pa_proplist_gets(prop, PA_PROP_DEVICE_DESCRIPTION); + + pa_tz_device_new_data_init(&data, dm->device_list, dm->comm, dm->dbus_conn); + _fill_new_data_basic(&data, DEVICE_TYPE_NETWORK, direction, false, dm); + pa_tz_device_new_data_set_name(&data, name); + pa_tz_device_new_data_set_system_id(&data, system_id); + if (direction == DM_DEVICE_DIRECTION_OUT) + pa_tz_device_new_data_add_sink(&data, DEVICE_ROLE_TUNNEL, PA_SINK(pdevice)); + else + pa_tz_device_new_data_add_source(&data, DEVICE_ROLE_TUNNEL, PA_SOURCE(pdevice)); + pa_tz_device_new(&data); + pa_tz_device_new_data_done(&data); + } else { + if (!(device = device_list_get_device(dm, DEVICE_TYPE_NETWORK, NULL, system_id))) + pa_log_warn("Can't get REMOTE device for %s", system_id); + else + pa_tz_device_free(device); + } +} + static void handle_acm_pulse_device(pa_object *pdevice, bool is_loaded, pa_device_manager *dm) { pa_tz_device *device; @@ -1602,6 +1651,18 @@ static pa_hook_result_t sink_unlink_hook_callback(pa_core *c, pa_sink *sink, pa_ } else if (pulse_device_is_raop(PA_OBJECT(sink))) { handle_raop_pulse_device(PA_OBJECT(sink), false, dm); return PA_HOOK_OK; + } else if (pulse_device_is_tunnel(PA_OBJECT(sink))) { + if (pa_proplist_has_remote_name(sink->proplist)) { + if (pa_proplist_remote_is_allowed(sink->proplist)) { + pa_log_info("allowed sink is unlinked, update to deny now"); + pa_sink_update_proplist_remote_access_permission(sink, false); + } else { + pa_log_info("denied sink is unlinked, nothing to do"); + } + } else { + pa_log_warn("tunnel but not remote....ignore this"); + } + return PA_HOOK_OK; } else if (pulse_device_is_acm(PA_OBJECT(sink))) { handle_acm_pulse_device(PA_OBJECT(sink), false, dm); return PA_HOOK_OK; @@ -1660,6 +1721,18 @@ static pa_hook_result_t source_unlink_hook_callback(pa_core *c, pa_source *sourc } else if (pulse_device_is_bluez(PA_OBJECT(source))) { handle_bt_pulse_device(PA_OBJECT(source), false, dm); return PA_HOOK_OK; + } else if (pulse_device_is_tunnel(PA_OBJECT(source))) { + if (pa_proplist_has_remote_name(source->proplist)) { + if (pa_proplist_remote_is_allowed(source->proplist)) { + pa_log_info("allowed source is unlinked, update to deny now"); + pa_source_update_proplist_remote_access_permission(source, false); + } else { + pa_log_info("denied source is unlinked, nothing to do"); + } + } else { + pa_log_warn("tunnel but not remote....ignore this"); + } + return PA_HOOK_OK; } else if (pulse_device_is_alsa(PA_OBJECT(source)) || pulse_device_is_tizenaudio(PA_OBJECT(source))) { handle_internal_pulse_device(PA_OBJECT(source), false, dm); return PA_HOOK_OK; @@ -1698,6 +1771,32 @@ static pa_hook_result_t sink_source_state_changed_hook_cb(pa_core *c, pa_object return PA_HOOK_OK; } +static pa_hook_result_t source_proplist_changed(pa_core *core, pa_source *source, pa_device_manager *dm) { + pa_core_assert_ref(core); + pa_source_assert_ref(source); + + if (pulse_device_is_tunnel(PA_OBJECT(source)) && + pa_proplist_has_remote_name(source->proplist)) { + /* FIXME : skip if no changes */ + pulse_device_set_use_internal_codec(PA_OBJECT(source), false); + handle_tunnel_pulse_device(PA_OBJECT(source), pa_proplist_remote_is_allowed(source->proplist), dm); + } + return PA_HOOK_OK; +} + +static pa_hook_result_t sink_proplist_changed(pa_core *core, pa_sink *sink, pa_device_manager *dm) { + pa_core_assert_ref(core); + pa_sink_assert_ref(sink); + + if (pulse_device_is_tunnel(PA_OBJECT(sink)) && + pa_proplist_has_remote_name(sink->proplist)) { + /* FIXME : skip if no changes */ + pulse_device_set_use_internal_codec(PA_OBJECT(sink), false); + handle_tunnel_pulse_device(PA_OBJECT(sink), pa_proplist_remote_is_allowed(sink->proplist), dm); + } + return PA_HOOK_OK; +} + /* Build params for load sink or source, and load it. */ @@ -2776,9 +2875,13 @@ pa_device_manager* pa_device_manager_get(pa_core *c) { dm->sink_put_hook_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SINK_PUT], PA_HOOK_LATE+10, (pa_hook_cb_t) sink_put_hook_callback, dm); dm->sink_unlink_hook_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SINK_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) sink_unlink_hook_callback, dm); dm->sink_state_changed_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_source_state_changed_hook_cb, dm); + dm->sink_proplist_changed_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SINK_PROPLIST_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_proplist_changed, dm); + dm->source_put_hook_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SOURCE_PUT], PA_HOOK_LATE+10, (pa_hook_cb_t) source_put_hook_callback, dm); dm->source_unlink_hook_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SOURCE_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) source_unlink_hook_callback, dm); dm->source_state_changed_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SOURCE_STATE_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) sink_source_state_changed_hook_cb, dm); + dm->source_proplist_changed_slot = pa_hook_connect(&dm->core->hooks[PA_CORE_HOOK_SOURCE_PROPLIST_CHANGED], PA_HOOK_NORMAL, (pa_hook_cb_t) source_proplist_changed, dm); + dm->comm = pa_communicator_get(dm->core); dm->comm_hook_device_connection_changed_slot = pa_hook_connect(pa_communicator_hook(dm->comm, PA_COMMUNICATOR_HOOK_DEVICE_CONNECTION_CHANGED), PA_HOOK_EARLY, (pa_hook_cb_t)device_connection_changed_hook_cb, dm); @@ -2843,18 +2946,24 @@ void pa_device_manager_unref(pa_device_manager *dm) { pa_hook_slot_free(dm->comm_hook_device_state_changed_slot); if (dm->comm_hook_device_running_changed_slot) pa_hook_slot_free(dm->comm_hook_device_running_changed_slot); + if (dm->sink_put_hook_slot) pa_hook_slot_free(dm->sink_put_hook_slot); if (dm->sink_unlink_hook_slot) pa_hook_slot_free(dm->sink_unlink_hook_slot); if (dm->sink_state_changed_slot) pa_hook_slot_free(dm->sink_state_changed_slot); + if (dm->sink_proplist_changed_slot) + pa_hook_slot_free(dm->sink_proplist_changed_slot); + if (dm->source_put_hook_slot) pa_hook_slot_free(dm->source_put_hook_slot); if (dm->source_unlink_hook_slot) pa_hook_slot_free(dm->source_unlink_hook_slot); if (dm->source_state_changed_slot) pa_hook_slot_free(dm->source_state_changed_slot); + if (dm->source_proplist_changed_slot) + pa_hook_slot_free(dm->source_proplist_changed_slot); if (dm->hal_interface) pa_hal_interface_unref(dm->hal_interface); diff --git a/src/tizen-device-def.h b/src/tizen-device-def.h index ed91400..e4232da 100644 --- a/src/tizen-device-def.h +++ b/src/tizen-device-def.h @@ -27,6 +27,7 @@ #define DEVICE_ROLE_HIGH_LATENCY "high-latency" #define DEVICE_ROLE_UHQA "uhqa" #define DEVICE_ROLE_RAOP "raop" +#define DEVICE_ROLE_TUNNEL "tunnel" #define DEVICE_ROLE_ACM "acm" typedef enum dm_device_direction_type { -- 2.7.4 From ee06cef6ad7a087ddb440271f072c065cdee9b20 Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Tue, 18 Aug 2020 20:10:32 +0900 Subject: [PATCH 07/16] stream-manager: add restriction for accessing denied remote device includes minor code refactoring [Version] 13.0.26 [Issue Type] Update Change-Id: I1d77ff249192bde15b861c9a9d481e3564b791d6 --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/stream-manager-restriction-priv.h | 6 ++-- src/stream-manager-restriction.c | 62 +++++++++++++++++++++++---------- src/stream-manager.c | 5 ++- 4 files changed, 51 insertions(+), 24 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 3d9e02b..06d9cea 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.25 +Version: 13.0.26 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/stream-manager-restriction-priv.h b/src/stream-manager-restriction-priv.h index bc1906d..1e738e3 100644 --- a/src/stream-manager-restriction-priv.h +++ b/src/stream-manager-restriction-priv.h @@ -24,10 +24,8 @@ #include "stream-manager.h" -/* dbus method args */ -#define STREAM_MANAGER_METHOD_ARGS_BLOCK_RECORDING_MEDIA "block_recording_media" - int32_t handle_restrictions(pa_stream_manager *m, const char *name, uint32_t value); -bool check_restrictions(pa_stream_manager *m, void *stream, stream_type_t stream_type); +bool is_restricted(pa_stream_manager *m, void *stream, stream_type_t stream_type); +bool is_remote_restricted(void *stream, stream_type_t type); #endif diff --git a/src/stream-manager-restriction.c b/src/stream-manager-restriction.c index 818b6c5..27a91a6 100644 --- a/src/stream-manager-restriction.c +++ b/src/stream-manager-restriction.c @@ -23,9 +23,14 @@ #include #endif +#include + #include "stream-manager-priv.h" #include "stream-manager-restriction-priv.h" +/* dbus method args */ +#define STREAM_MANAGER_METHOD_ARGS_BLOCK_RECORDING_MEDIA "block_recording_media" + int32_t handle_restrictions(pa_stream_manager *m, const char *name, uint32_t value) { const char *role; void *s; @@ -33,33 +38,54 @@ int32_t handle_restrictions(pa_stream_manager *m, const char *name, uint32_t val pa_assert(m); - if (pa_safe_streq(name, STREAM_MANAGER_METHOD_ARGS_BLOCK_RECORDING_MEDIA) ) { - if (value == 1) { - pa_log_info("block MEDIA recording"); - m->restrictions.block_recording_media = true; - PA_IDXSET_FOREACH(s, m->core->source_outputs, idx) { - role = pa_proplist_gets(GET_STREAM_PROPLIST(s, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROLE); - if (pa_safe_streq(role, "media")) { - pa_log_info(" -- kill source-output(%p, %u)", s, ((pa_source_output*)s)->index); - pa_source_output_kill((pa_source_output*)s); - } + if (!pa_safe_streq(name, STREAM_MANAGER_METHOD_ARGS_BLOCK_RECORDING_MEDIA)) { + pa_log_error("unknown name : %s", pa_strnull(name)); + return -1; + } + + if (value == 1) { + pa_log_info("block MEDIA recording"); + m->restrictions.block_recording_media = true; + PA_IDXSET_FOREACH(s, m->core->source_outputs, idx) { + role = pa_proplist_gets(GET_STREAM_PROPLIST(s, STREAM_SOURCE_OUTPUT), PA_PROP_MEDIA_ROLE); + if (pa_safe_streq(role, "media")) { + pa_log_info(" -- kill source-output(%p, %u)", s, ((pa_source_output*)s)->index); + pa_source_output_kill((pa_source_output*)s); } - } else if (value == 0) { - pa_log_info("MEDIA recording is now available"); - m->restrictions.block_recording_media = false; - } else { - pa_log_error("unknown value"); - return -1; } + } else if (value == 0) { + pa_log_info("MEDIA recording is now available"); + m->restrictions.block_recording_media = false; } else { - pa_log_error("unknown name"); + pa_log_error("unknown value : %u", value); return -1; } return 0; } -bool check_restrictions(pa_stream_manager *m, void *stream, stream_type_t type) { +bool is_remote_restricted(void *stream, stream_type_t type) { + pa_proplist* p = NULL; + if (type == STREAM_SOURCE_OUTPUT) + p = ((pa_source_output_new_data *)stream)->source->proplist; + else + p = ((pa_sink_input_new_data *)stream)->sink->proplist; + + if (!pa_proplist_has_remote_name(p)) { + pa_log_debug("it is a local stream(%p)", stream); + return false; + } + + if (pa_proplist_remote_is_allowed(p)) { + pa_log_info("stream(%p) is currently allowed", stream); + return false; + } + + pa_log_warn("restricted due to denied remote access of stream(%p)!!!", stream); + return true; +} + +bool is_restricted(pa_stream_manager *m, void *stream, stream_type_t type) { const char *role; pa_assert(m); diff --git a/src/stream-manager.c b/src/stream-manager.c index 981d4c6..f75e8f7 100644 --- a/src/stream-manager.c +++ b/src/stream-manager.c @@ -2480,6 +2480,8 @@ static pa_hook_result_t sink_input_new_cb(pa_core *core, pa_sink_input_new_data pa_log_debug("sink-input-new-data(%p)", new_data); process_stream(m, new_data, STREAM_SINK_INPUT, PROCESS_COMMAND_PREPARE, true); + if (is_remote_restricted(new_data, STREAM_SINK_INPUT)) + return PA_HOOK_CANCEL; process_stream(m, new_data, STREAM_SINK_INPUT, PROCESS_COMMAND_UPDATE_BUFFER_ATTR, true); process_stream(m, new_data, STREAM_SINK_INPUT, PROCESS_COMMAND_UPDATE_VOLUME, true); process_stream(m, new_data, STREAM_SINK_INPUT, PROCESS_COMMAND_CHANGE_ROUTE_BY_STREAM_STARTED, true); @@ -2635,7 +2637,8 @@ static pa_hook_result_t source_output_new_cb(pa_core *core, pa_source_output_new pa_log_debug("source-output-new-data(%p)", new_data); process_stream(m, new_data, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_PREPARE, true); - if (check_restrictions(m, new_data, STREAM_SOURCE_OUTPUT)) + if (is_restricted(m, new_data, STREAM_SOURCE_OUTPUT) || + is_remote_restricted(new_data, STREAM_SOURCE_OUTPUT)) return PA_HOOK_CANCEL; process_stream(m, new_data, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_UPDATE_BUFFER_ATTR, true); process_stream(m, new_data, STREAM_SOURCE_OUTPUT, PROCESS_COMMAND_UPDATE_VOLUME, true); -- 2.7.4 From 3a83081231b354654b47e45b1b004ec7f898c866 Mon Sep 17 00:00:00 2001 From: Jaechul Lee Date: Wed, 19 Aug 2020 11:48:15 +0900 Subject: [PATCH 08/16] stream-manager: add publish/discover/set_permission interfaces method name : SetRemotePermission method argument : [in] string for type [in] unsigned for index [in] boolean for allowed return value : None method name : DiscoverRemoteDevice method argument : [in] boolean for enable return value : None method name : PublishLocalDevice method argument : [in] boolean for enable return value : None [Version] 13.0.27 [Issue Type] New feature Change-Id: I6ab4a388410dcf4d9480bdc1aaaaa7202a199a9f Signed-off-by: Jaechul Lee --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/stream-manager-dbus-priv.h | 29 +++- src/stream-manager-dbus.c | 226 +++++++++++++++++++++++++++++++- src/stream-manager-priv.h | 11 +- src/stream-manager.c | 61 +++++++++ 5 files changed, 325 insertions(+), 4 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 06d9cea..bb99b51 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.26 +Version: 13.0.27 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/stream-manager-dbus-priv.h b/src/stream-manager-dbus-priv.h index 166c3a3..940940a 100644 --- a/src/stream-manager-dbus-priv.h +++ b/src/stream-manager-dbus-priv.h @@ -54,10 +54,14 @@ #define STREAM_MANAGER_METHOD_NAME_GET_PID_OF_LATEST_STREAM "GetPidOfLatestStream" #define STREAM_MANAGER_METHOD_NAME_ACTIVATE_DUCKING "ActivateDucking" #define STREAM_MANAGER_METHOD_NAME_GET_DUCKING_STATE "GetDuckingState" +#define STREAM_MANAGER_METHOD_NAME_SET_REMOTE_PERMISSION "SetRemotePermission" +#define STREAM_MANAGER_METHOD_NAME_DISCOVER_REMOTE_DEVICE "DiscoverRemoteDevice" +#define STREAM_MANAGER_METHOD_NAME_PUBLISH_LOCAL_DEVICE "PublishLocalDevice" /* signal */ #define STREAM_MANAGER_SIGNAL_NAME_VOLUME_CHANGED "VolumeChanged" #define STREAM_MANAGER_SIGNAL_NAME_DUCKING_STATE_CHANGED "DuckingStateChanged" #define STREAM_MANAGER_SIGNAL_NAME_COMMAND "Command" +#define STREAM_MANAGER_SIGNAL_NAME_REMOTE_FOUND "RemoteFound" enum method_handler_index { METHOD_HANDLER_GET_STREAM_INFO, @@ -88,6 +92,9 @@ enum method_handler_index { METHOD_HANDLER_GET_PID_OF_LATEST_STREAM, METHOD_HANDLER_ACTIVATE_DUCKING, METHOD_HANDLER_GET_DUCKING_STATE, + METHOD_HANDLER_NAME_SET_REMOTE_PERMISSION, + METHOD_HANDLER_DISCOVER_REMOTE_DEVICE, + METHOD_HANDLER_PUBLISH_LOCAL_DEVICE, METHOD_HANDLER_MAX }; @@ -266,6 +273,17 @@ pa_dbus_interface_info stream_manager_interface_info = { " " \ " " \ " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ " " \ " " \ " " \ @@ -275,6 +293,13 @@ pa_dbus_interface_info stream_manager_interface_info = { " " \ " " \ " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ " " \ " " \ " " \ @@ -286,9 +311,11 @@ pa_dbus_interface_info stream_manager_interface_info = { void send_ducking_state_changed_signal(DBusConnection *conn, const int index, const int is_ducked); void send_command_signal(DBusConnection *conn, const char *name, int value); +void send_remote_found_signal(DBusConnection *conn, int type, bool connected, + unsigned int index, const char *name, const char *description); int32_t init_sm_dbus(pa_stream_manager *m); void deinit_sm_dbus(pa_stream_manager *m); #endif -#endif \ No newline at end of file +#endif diff --git a/src/stream-manager-dbus.c b/src/stream-manager-dbus.c index a6e7506..0367446 100644 --- a/src/stream-manager-dbus.c +++ b/src/stream-manager-dbus.c @@ -25,6 +25,7 @@ #ifdef HAVE_DBUS +#include #include "stream-manager-priv.h" #include "stream-manager-dbus-priv.h" #include "stream-manager-volume-priv.h" @@ -70,6 +71,9 @@ static void handle_check_stream_exist_by_pid(DBusConnection *conn, DBusMessage * static void handle_get_pid_of_latest_stream(DBusConnection *conn, DBusMessage *msg, void *userdata); static void handle_activate_ducking(DBusConnection *conn, DBusMessage *msg, void *userdata); static void handle_get_ducking_state(DBusConnection *conn, DBusMessage *msg, void *userdata); +static void handle_set_remote_permission(DBusConnection *conn, DBusMessage *msg, void *userdata); +static void handle_discover_remote_device(DBusConnection *conn, DBusMessage *msg, void *userdata); +static void handle_publish_local_device(DBusConnection *conn, DBusMessage *msg, void *userdata); static void send_volume_changed_signal(DBusConnection *conn, const char *direction, const char *volume_type, const uint32_t volume_level); static pa_dbus_arg_info get_stream_info_args[] = { { "stream_type", "s", "in" }, @@ -179,6 +183,11 @@ static pa_dbus_arg_info activate_ducking_args[] = { { "index", "u", "in" }, static pa_dbus_arg_info get_ducking_state_args[] = { { "index", "u", "in" }, { "is_ducked", "b", "out" }, { "ret_msg", "s", "out" } }; +static pa_dbus_arg_info set_remote_permission_args[] = { { "type", "s", "in" }, + { "index", "u", "in" }, + { "allowed", "b", "in" } }; +static pa_dbus_arg_info discover_remote_device_args[] = { { "enable", "b", "in" } }; +static pa_dbus_arg_info publish_local_device_args[] = { { "enable", "b", "in" } }; static const char* signature_args_for_in[] = { "s", /* METHOD_HANDLER_GET_STREAM_INFO */ @@ -208,7 +217,10 @@ static const char* signature_args_for_in[] = { "uss", /* METHOD_HANDLER_CHECK_STREAM_EXIST_BY_PID */ "sas", /* METHOD_HANDLER_GET_PID_OF_LATEST_STREAM */ "ubsud", /* METHOD_HANDLER_ACTIVATE_DUCKING */ - "u" /* METHOD_HANDLER_GET_DUCKING_STATE */ + "u", /* METHOD_HANDLER_GET_DUCKING_STATE */ + "sub", /* METHOD_HANDLER_SET_REMOTE_PERMISSION */ + "b", /* METHOD_HANDLER_DISCOVER_REMOTE_DEVICE */ + "b" /* METHOD_HANDLER_PUBLISH_LOCAL_DEVICE */ }; static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = { @@ -352,6 +364,21 @@ static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = { .arguments = get_ducking_state_args, .n_arguments = sizeof(get_ducking_state_args) / sizeof(pa_dbus_arg_info), .receive_cb = handle_get_ducking_state }, + [METHOD_HANDLER_NAME_SET_REMOTE_PERMISSION] = { + .method_name = STREAM_MANAGER_METHOD_NAME_SET_REMOTE_PERMISSION, + .arguments = set_remote_permission_args, + .n_arguments = sizeof(set_remote_permission_args) / sizeof(pa_dbus_arg_info), + .receive_cb = handle_set_remote_permission }, + [METHOD_HANDLER_DISCOVER_REMOTE_DEVICE] = { + .method_name = STREAM_MANAGER_METHOD_NAME_DISCOVER_REMOTE_DEVICE, + .arguments = discover_remote_device_args, + .n_arguments = sizeof(discover_remote_device_args) / sizeof(pa_dbus_arg_info), + .receive_cb = handle_discover_remote_device }, + [METHOD_HANDLER_PUBLISH_LOCAL_DEVICE] = { + .method_name = STREAM_MANAGER_METHOD_NAME_PUBLISH_LOCAL_DEVICE, + .arguments = publish_local_device_args, + .n_arguments = sizeof(publish_local_device_args) / sizeof(pa_dbus_arg_info), + .receive_cb = handle_publish_local_device }, }; static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata) { @@ -2322,6 +2349,175 @@ static void handle_get_ducking_state(DBusConnection *conn, DBusMessage *msg, voi dbus_message_unref(reply); } +static void handle_set_remote_permission(DBusConnection *conn, DBusMessage *msg, void *userdata) { + pa_stream_manager *m = (pa_stream_manager*)userdata; + dbus_uint32_t index; + dbus_bool_t allowed; + pa_proplist *p = NULL; + char *type = NULL; + + pa_assert(conn); + pa_assert(msg); + pa_assert(m); + + pa_assert_se(dbus_message_get_args(msg, NULL, + DBUS_TYPE_STRING, &type, + DBUS_TYPE_UINT32, &index, + DBUS_TYPE_BOOLEAN, &allowed, + DBUS_TYPE_INVALID)); + + if (!type) { + pa_log_error("invalid arguments"); + goto out; + } + + pa_log_info("type(%s), index(%d), allowed(%d)", type, index, allowed); + + p = pa_proplist_new(); + if (!p) { + pa_log_error("failed to create proplist"); + goto out; + } + + if (pa_proplist_set_remote_access_permission(p, allowed)) { + pa_log_error("set remote access permission error"); + goto out; + } + + if (pa_streq(type, "sink-input")) { + pa_sink_input *i; + + i = pa_idxset_get_by_index(m->core->sink_inputs, index); + if (!i) { + pa_log_error("not found sink-input"); + goto out; + } + + if (pa_proplist_remote_is_allowed(i->proplist) != allowed){ + pa_sink_input_update_proplist(i, PA_UPDATE_REPLACE, p); + pa_sink_input_send_event(i, PA_STREAM_EVENT_UPDATE_MEDIA_REMOTE_ACCESS, p); + } + + } else if (pa_streq(type, "source-output")) { + pa_source_output *o; + + o = pa_idxset_get_by_index(m->core->source_outputs, index); + if (!o) { + pa_log_error("not found source-output"); + goto out; + } + + if (pa_proplist_remote_is_allowed(o->proplist) != allowed){ + pa_source_output_update_proplist(o, PA_UPDATE_REPLACE, p); + pa_source_output_send_event(o, PA_STREAM_EVENT_UPDATE_MEDIA_REMOTE_ACCESS, p); + } + + } else { + pa_log_warn("unknown type"); + } + +out: + if (p) + pa_proplist_free(p); + + pa_dbus_send_empty_reply(conn, msg); +} + +static void handle_discover_remote_device(DBusConnection *conn, DBusMessage *msg, void *userdata) { + pa_stream_manager *m = (pa_stream_manager*)userdata; + pa_module *module; + dbus_bool_t enable; + + pa_assert(conn); + pa_assert(msg); + pa_assert(m); + + pa_assert_se(dbus_message_get_args(msg, NULL, + DBUS_TYPE_BOOLEAN, &enable, + DBUS_TYPE_INVALID)); + + pa_log_info("discover module enable(%d)", enable); + + if (enable) { + if (m->m_discover) { + pa_log_error("already loaded"); + goto error; + } + + if (pa_module_load(&module, m->core, "module-tizenaudio-discover", NULL)) { + pa_log_error("failed to load module"); + goto error; + } + m->m_discover = module->index; + } else { + if (m->m_discover) { + pa_module_unload_request_by_index(m->core, m->m_discover, true); + m->m_discover = 0; + } + } + + pa_dbus_send_empty_reply(conn, msg); + + return; + +error: + pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", + "org.tizen.multimedia.audio.Internal"); +} + +static void handle_publish_local_device(DBusConnection *conn, DBusMessage *msg, void *userdata) { + pa_stream_manager *m = (pa_stream_manager*)userdata; + pa_module *module; + dbus_bool_t enable; + + pa_assert(conn); + pa_assert(msg); + pa_assert(m); + + pa_assert_se(dbus_message_get_args(msg, NULL, + DBUS_TYPE_BOOLEAN, &enable, + DBUS_TYPE_INVALID)); + + pa_log_info("publish module enable(%d)", enable); + + if (enable) { + if (m->m_protocol_tcp || m->m_publish) { + pa_log_error("already loaded"); + goto error; + } + + if (pa_module_load(&module, m->core, "module-native-protocol-tcp", "auth-anonymous=1")) { + pa_log_error("failed to load module"); + goto error; + } + m->m_protocol_tcp = module->index; + + if (pa_module_load(&module, m->core, "module-tizenaudio-publish", NULL)) { + pa_module_unload_request_by_index(m->core, m->m_protocol_tcp, true); + pa_log_error("failed to load module"); + goto error; + } + m->m_publish = module->index; + } else { + if (m->m_protocol_tcp) { + pa_module_unload_request_by_index(m->core, m->m_protocol_tcp, true); + m->m_protocol_tcp = 0; + } + if (m->m_publish) { + pa_module_unload_request_by_index(m->core, m->m_publish, true); + m->m_publish = 0; + } + } + + pa_dbus_send_empty_reply(conn, msg); + + return; + +error: + pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", + "org.tizen.multimedia.audio.Internal"); +} + static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) { int idx = 0; pa_stream_manager *m = (pa_stream_manager*)userdata; @@ -2435,6 +2631,34 @@ void send_command_signal(DBusConnection *conn, const char *name, int value) { dbus_message_unref(signal_msg); } +void send_remote_found_signal(DBusConnection *conn, int type, bool connected, unsigned int index, + const char *name, const char *description) { + DBusMessage *signal_msg; + DBusMessageIter msg_iter; + dbus_bool_t c = (dbus_bool_t)connected; + + pa_assert(conn); + + if (!name || !description) { + pa_log_error("Unknown device"); + return; + } + + pa_log_info("type[%d], index[%d], connected[%d], name[%s] description[%s]", type, index, connected, name, description); + + pa_assert_se((signal_msg = dbus_message_new_signal(STREAM_MANAGER_OBJECT_PATH, STREAM_MANAGER_INTERFACE, STREAM_MANAGER_SIGNAL_NAME_REMOTE_FOUND))); + dbus_message_iter_init_append(signal_msg, &msg_iter); + + dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &type); + dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_UINT32, &index); + dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_BOOLEAN, &c); + dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name); + dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &description); + + pa_assert_se(dbus_connection_send(conn, signal_msg, NULL)); + dbus_message_unref(signal_msg); +} + int32_t init_sm_dbus(pa_stream_manager *m) { pa_assert(m); diff --git a/src/stream-manager-priv.h b/src/stream-manager-priv.h index f78a063..aeb0ac9 100644 --- a/src/stream-manager-priv.h +++ b/src/stream-manager-priv.h @@ -266,7 +266,16 @@ struct _stream_manager { *source_output_unlink_slot, *source_output_state_changed_slot, *source_output_move_start_slot, - *source_output_move_finish_slot; + *source_output_move_finish_slot, + + *remote_sink_input_put_slot, + *remote_sink_input_unlink_slot, + *remote_source_output_unlink_slot, + *remote_source_output_put_slot; + + uint32_t m_discover; + uint32_t m_protocol_tcp; + uint32_t m_publish; #ifdef HAVE_DBUS #ifdef USE_DBUS_PROTOCOL diff --git a/src/stream-manager.c b/src/stream-manager.c index f75e8f7..8073580 100644 --- a/src/stream-manager.c +++ b/src/stream-manager.c @@ -2731,6 +2731,53 @@ static pa_hook_result_t source_output_move_finish_cb(pa_core *core, pa_source_ou return PA_HOOK_OK; } +static void notify_remote_connection(pa_core *core, pa_object *obj, pa_stream_manager *m, bool connected) { + pa_proplist *p; + pa_sink_input *i; + pa_source_output *o; + unsigned int index; + + if (pa_source_output_isinstance(obj)) { + o = PA_SOURCE_OUTPUT(obj); + p = o->proplist; + index = o->index; + } else { + i = PA_SINK_INPUT(obj); + p = i->proplist; + index = i->index; + } + + if (!p) { + pa_log_error("unknown remote client"); + return; + } + + if (pa_proplist_has_remote_name(p)) { + send_remote_found_signal(pa_dbus_connection_get(m->dbus_conn), + pa_source_output_isinstance(obj) ? 1 : 0, connected, index, + pa_proplist_gets(p, PA_PROP_MEDIA_REMOTE_NAME), + pa_proplist_gets(p, "native-protocol.peer")); + } +} + +static pa_hook_result_t remote_client_put_cb(pa_core *core, pa_object *o, pa_stream_manager *m) { + pa_core_assert_ref(core); + pa_object_assert_ref(o); + + notify_remote_connection(core, o, m, true); + + return PA_HOOK_OK; +} + +static pa_hook_result_t remote_client_unlink_cb(pa_core *core, pa_object *o, pa_stream_manager *m) { + pa_core_assert_ref(core); + pa_object_assert_ref(o); + + notify_remote_connection(core, o, m, false); + + return PA_HOOK_OK; +} + static void find_next_device_for_auto_route(pa_stream_manager *m, stream_route_type_t route_type, const char *stream_role, stream_type_t stream_type, const char *cur_device_type, const char *preferred_device_role, pa_tz_device **next_device) { stream_info *si = NULL; @@ -3734,6 +3781,11 @@ pa_stream_manager* pa_stream_manager_get(pa_core *c) { m->source_output_move_start_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_START], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_move_start_cb, m); m->source_output_move_finish_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FINISH], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_move_finish_cb, m); + m->remote_sink_input_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_EARLY, (pa_hook_cb_t) remote_client_put_cb, m); + m->remote_sink_input_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) remote_client_unlink_cb, m); + m->remote_source_output_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], PA_HOOK_NORMAL, (pa_hook_cb_t) remote_client_put_cb, m); + m->remote_source_output_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], PA_HOOK_NORMAL, (pa_hook_cb_t) remote_client_unlink_cb, m); + m->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_CLIENT | PA_SUBSCRIPTION_MASK_SAMPLE_CACHE, (pa_subscription_cb_t)subscribe_cb, m); m->comm.comm = pa_communicator_get(c); @@ -3787,8 +3839,12 @@ static void free_hook_slots(pa_stream_manager *m) { pa_hook_slot_free(m->sink_input_new_slot); if (m->sink_input_put_slot) pa_hook_slot_free(m->sink_input_put_slot); + if (m->remote_sink_input_put_slot) + pa_hook_slot_free(m->remote_sink_input_put_slot); if (m->sink_input_unlink_slot) pa_hook_slot_free(m->sink_input_unlink_slot); + if (m->remote_sink_input_unlink_slot) + pa_hook_slot_free(m->remote_sink_input_unlink_slot); if (m->sink_input_state_changed_slot) pa_hook_slot_free(m->sink_input_state_changed_slot); if (m->sink_input_move_start_slot) @@ -3797,12 +3853,17 @@ static void free_hook_slots(pa_stream_manager *m) { pa_hook_slot_free(m->sink_input_move_finish_slot); if (m->sink_input_ramp_finish_slot) pa_hook_slot_free(m->sink_input_ramp_finish_slot); + if (m->source_output_new_slot) pa_hook_slot_free(m->source_output_new_slot); if (m->source_output_put_slot) pa_hook_slot_free(m->source_output_put_slot); + if (m->remote_source_output_put_slot) + pa_hook_slot_free(m->remote_source_output_put_slot); if (m->source_output_unlink_slot) pa_hook_slot_free(m->source_output_unlink_slot); + if (m->remote_source_output_unlink_slot) + pa_hook_slot_free(m->remote_source_output_unlink_slot); if (m->source_output_state_changed_slot) pa_hook_slot_free(m->source_output_state_changed_slot); if (m->source_output_move_start_slot) -- 2.7.4 From 4473003cc7c2986bacd2f951cc1ac3dab1ab6a15 Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Thu, 20 Aug 2020 15:17:38 +0900 Subject: [PATCH 09/16] stream-manager-dbus: launch mdnsd when remote publish/discover [Version] 13.0.28 [Issue Type] Update Change-Id: I0a63ba5c5636e249f640337b25bfd698c18311d9 --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/stream-manager-dbus.c | 42 +++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index bb99b51..441a781 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.27 +Version: 13.0.28 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/stream-manager-dbus.c b/src/stream-manager-dbus.c index 0367446..c365345 100644 --- a/src/stream-manager-dbus.c +++ b/src/stream-manager-dbus.c @@ -2349,6 +2349,38 @@ static void handle_get_ducking_state(DBusConnection *conn, DBusMessage *msg, voi dbus_message_unref(reply); } +static int dbus_launch_mdnsd(pa_stream_manager *m, DBusConnection *conn) { + DBusMessage *msg, *reply; + DBusError err; + const char *name = NULL; + + pa_log_info("launching mdnsd"); + + if (!(msg = dbus_message_new_method_call("net.netconfig", + "/net/netconfig/network", + "net.netconfig.network", + "LaunchMdns"))) { + pa_log_error("dbus method call failed"); + return -1; + } + + name = dbus_bus_get_unique_name(conn); + pa_assert_se(dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)); + + dbus_error_init(&err); + if (!(reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err))) { + pa_log_error("Failed to method call : %s", err.message); + dbus_error_free(&err); + return -1; + } + + dbus_message_unref(reply); + + pa_log_info("success"); + + return 0; +} + static void handle_set_remote_permission(DBusConnection *conn, DBusMessage *msg, void *userdata) { pa_stream_manager *m = (pa_stream_manager*)userdata; dbus_uint32_t index; @@ -2444,6 +2476,11 @@ static void handle_discover_remote_device(DBusConnection *conn, DBusMessage *msg goto error; } + if (dbus_launch_mdnsd(m, conn) == -1) { + pa_log_error("failed to launch mdnsd!!!"); + goto error; + } + if (pa_module_load(&module, m->core, "module-tizenaudio-discover", NULL)) { pa_log_error("failed to load module"); goto error; @@ -2486,6 +2523,11 @@ static void handle_publish_local_device(DBusConnection *conn, DBusMessage *msg, goto error; } + if (dbus_launch_mdnsd(m, conn) == -1) { + pa_log_error("failed to launch mdnsd!!!"); + goto error; + } + if (pa_module_load(&module, m->core, "module-native-protocol-tcp", "auth-anonymous=1")) { pa_log_error("failed to load module"); goto error; -- 2.7.4 From 26c98e7e2a8d03c153ac20af68d31812a406831e Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Thu, 20 Aug 2020 19:07:32 +0900 Subject: [PATCH 10/16] fixup! tizenaudio-discover: ignore local services skip discovered from localhost(127.0.0.1) [Version] 13.0.29 [Issue Type] Update Change-Id: I5faa7ae58b5ebfa8dae5a8c68ba64ff2309096f4 --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/module-tizenaudio-discover.c | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 441a781..04850b6 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.28 +Version: 13.0.29 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/module-tizenaudio-discover.c b/src/module-tizenaudio-discover.c index 798f006..e507e39 100644 --- a/src/module-tizenaudio-discover.c +++ b/src/module-tizenaudio-discover.c @@ -356,12 +356,14 @@ finish: } static bool is_local_service(const char *ip_addr) { - char *ipv4_addr = NULL; + static const char *localhost = "127.0.0.1"; + char *current_ip_addr = NULL; bool is_local = false; - ipv4_addr = vconf_get_str(VCONFKEY_NETWORK_IP); - is_local = pa_safe_streq(ipv4_addr, ip_addr); - pa_xfree(ipv4_addr); + current_ip_addr = vconf_get_str(VCONFKEY_NETWORK_IP); + is_local = (pa_safe_streq(ip_addr, current_ip_addr) || + pa_safe_streq(ip_addr, localhost)); + pa_xfree(current_ip_addr); return is_local; } -- 2.7.4 From d04fc67580a49ff132699a1dd85fff0a0a3a2384 Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Fri, 21 Aug 2020 16:31:03 +0900 Subject: [PATCH 11/16] fixup! tizenaudio-publish: publish only built-in devices adjust log level for ignoring publish [Version] 13.0.30 [Issue Type] Update Change-Id: I0476c340de9b4bffc13bf9734bd837fd5f169f92 --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/module-tizenaudio-publish.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 04850b6..bc64475 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.29 +Version: 13.0.30 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/module-tizenaudio-publish.c b/src/module-tizenaudio-publish.c index cdead84..0fb0602 100644 --- a/src/module-tizenaudio-publish.c +++ b/src/module-tizenaudio-publish.c @@ -340,7 +340,7 @@ static bool shall_ignore(pa_object *o) { if (pa_sink_isinstance(o)) { if (!is_builtin_device(PA_SINK(o)->proplist)) { - pa_log_error("sink [%s] is not an internal, skip this", PA_SINK(o)->name); + pa_log_info("ignore : sink [%s] is not an internal", PA_SINK(o)->name); return true; } return !!(PA_SINK(o)->flags & PA_SINK_NETWORK); @@ -348,7 +348,7 @@ static bool shall_ignore(pa_object *o) { if (pa_source_isinstance(o)) { if (!is_builtin_device(PA_SOURCE(o)->proplist)) { - pa_log_error("source [%s] is not an internal, skip this", PA_SOURCE(o)->name); + pa_log_info("ignore : source [%s] is not an internal", PA_SOURCE(o)->name); return true; } return PA_SOURCE(o)->monitor_of || (PA_SOURCE(o)->flags & PA_SOURCE_NETWORK); -- 2.7.4 From 480ec0b9bfc56f35a4462d58a674a22063e17537 Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Thu, 27 Aug 2020 19:28:52 +0900 Subject: [PATCH 12/16] Fix Coverity defects - Unchecked return value (CHECKED_RETURN) - String not null terminated (STRING_NULL) [Version] 13.0.31 [Issue Type] Vulnerability Change-Id: I0e4b8c824c0d6dd9efe71d34d3576aa81453aa83 --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/acm.c | 6 +++--- src/module-sound-player.c | 6 +++--- src/subscribe-observer.c | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index bc64475..2264698 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.30 +Version: 13.0.31 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/acm.c b/src/acm.c index a0d07a7..7f697c2 100644 --- a/src/acm.c +++ b/src/acm.c @@ -558,13 +558,13 @@ static void msg_thread_func(void *userdata) { } if ((recv_len = recv(u->msg_fd, recv_msg , IPC_MAX_MSG_LEN, 0)) > 0) { - if (!strcmp(recv_msg, MSG_DRAIN_COMPLETE)) { + if (!strncmp(recv_msg, MSG_DRAIN_COMPLETE, IPC_MAX_MSG_LEN)) { pa_log_debug("got drain complete signal [%s]", recv_msg); pa_cond_signal(u->msg_cond, false); - } else if (!strcmp(recv_msg, MSG_SEND_PAUSE)) { + } else if (!strncmp(recv_msg, MSG_SEND_PAUSE, IPC_MAX_MSG_LEN)) { pa_log_debug("got pause signal [%s]", recv_msg); u->need_pause = true; - } else if (!strcmp(recv_msg, MSG_SEND_RESUME) && u->need_pause) { + } else if (!strncmp(recv_msg, MSG_SEND_RESUME, IPC_MAX_MSG_LEN) && u->need_pause) { pa_log_debug("got resume signal [%s]", recv_msg); u->need_pause = false; pa_cond_signal(u->msg_cond, false); diff --git a/src/module-sound-player.c b/src/module-sound-player.c index 0322544..5e60af2 100644 --- a/src/module-sound-player.c +++ b/src/module-sound-player.c @@ -733,11 +733,11 @@ static void io_event_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io pa_log_info("name(%s), role(%s), volume_gain_type(%s), method(%s)", data.filename, data.role, data.volume_gain_type, data.method); - if (pa_streq(data.method, SOUND_PLAYER_METHOD_NAME_SIMPLE_PLAY)) + if (pa_strneq(data.method, SOUND_PLAYER_METHOD_NAME_SIMPLE_PLAY, METHOD_LEN)) _simple_play(u, data.filename, data.role, data.volume_gain_type); - else if (pa_streq(data.method, SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP)) + else if (pa_strneq(data.method, SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP, METHOD_LEN)) _simple_stop(u, data.filename); - else if (pa_streq(data.method, SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP_ALL)) + else if (pa_strneq(data.method, SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP_ALL, METHOD_LEN)) _simple_stop_all(u); else pa_log_error("Invalid method!!!"); diff --git a/src/subscribe-observer.c b/src/subscribe-observer.c index c565a36..a8ec66a 100644 --- a/src/subscribe-observer.c +++ b/src/subscribe-observer.c @@ -188,9 +188,9 @@ static int get_sender_pid(DBusConnection *c, DBusMessage *got_msg, uint32_t *_se return -1; } - dbus_message_append_args(msg, + pa_assert_se(dbus_message_append_args(msg, DBUS_TYPE_STRING, &sender, - DBUS_TYPE_INVALID); + DBUS_TYPE_INVALID)); dbus_error_init(&err); if (!(reply = dbus_connection_send_with_reply_and_block(c, msg, -1, &err))) { -- 2.7.4 From 49d1e63cff1bfbaa64d6b31efdd29c79e0231489 Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Fri, 28 Aug 2020 17:54:19 +0900 Subject: [PATCH 13/16] Fix SVACE defect(DEREF_OF_NULL.RET.STAT) [Version] 13.0.32 [Issue Type] Vulnerability Change-Id: Ideb267ce415c92c51702558cfdba9cb8cb0bc179 --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/stream-manager.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 2264698..a622af5 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.31 +Version: 13.0.32 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/stream-manager.c b/src/stream-manager.c index 8073580..e8f107d 100644 --- a/src/stream-manager.c +++ b/src/stream-manager.c @@ -2739,10 +2739,12 @@ static void notify_remote_connection(pa_core *core, pa_object *obj, pa_stream_ma if (pa_source_output_isinstance(obj)) { o = PA_SOURCE_OUTPUT(obj); + pa_assert(o); p = o->proplist; index = o->index; } else { i = PA_SINK_INPUT(obj); + pa_assert(i); p = i->proplist; index = i->index; } -- 2.7.4 From 5b1bfefac4bceed567a2d6c642f861e47aeca872 Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Wed, 2 Sep 2020 17:35:14 +0900 Subject: [PATCH 14/16] Fix build warnings [Version] 13.0.33 [Issue Type] Build Change-Id: Idf96facb42ef0260e96ac1d1af4e9ec131c999a7 --- Makefile.am | 22 ++++++------ packaging/pulseaudio-modules-tizen.spec | 2 +- src/module-tizenaudio-discover.c | 48 ++++++++++++------------- src/module-tizenaudio-publish.c | 64 ++++++++++++++++----------------- src/stream-manager.c | 2 +- 5 files changed, 69 insertions(+), 69 deletions(-) diff --git a/Makefile.am b/Makefile.am index 90d1260..e529cae 100644 --- a/Makefile.am +++ b/Makefile.am @@ -65,22 +65,22 @@ libcommunicator_la_CFLAGS = $(AM_CFLAGS) $(PACORE_CFLAGS) $(PA_CFLAGS) module_tizenaudio_sink_la_SOURCES = src/module-tizenaudio-sink.c module_tizenaudio_sink_la_LDFLAGS = $(MODULE_LDFLAGS) module_tizenaudio_sink_la_LIBADD = $(MODULE_LIBADD) libhal-interface.la -module_tizenaudio_sink_la_CFLAGS = $(MODULE_CFLAGS) +module_tizenaudio_sink_la_CFLAGS = $(MODULE_CFLAGS) -DPA_MODULE_NAME=module_tizenaudio_sink module_tizenaudio_source_la_SOURCES = src/module-tizenaudio-source.c module_tizenaudio_source_la_LDFLAGS = $(MODULE_LDFLAGS) module_tizenaudio_source_la_LIBADD = $(MODULE_LIBADD) libhal-interface.la -module_tizenaudio_source_la_CFLAGS = $(MODULE_CFLAGS) +module_tizenaudio_source_la_CFLAGS = $(MODULE_CFLAGS) -DPA_MODULE_NAME=module_tizenaudio_source module_sound_player_la_SOURCES = src/module-sound-player.c module_sound_player_la_LDFLAGS = $(MODULE_LDFLAGS) module_sound_player_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) -module_sound_player_la_CFLAGS = $(MODULE_CFLAGS) $(DBUS_CFLAGS) +module_sound_player_la_CFLAGS = $(MODULE_CFLAGS) $(DBUS_CFLAGS) -DPA_MODULE_NAME=module_sound_player module_tone_player_la_SOURCES = src/module-tone-player.c module_tone_player_la_LDFLAGS = $(MODULE_LDFLAGS) module_tone_player_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) -module_tone_player_la_CFLAGS = $(MODULE_CFLAGS) $(DBUS_CFLAGS) +module_tone_player_la_CFLAGS = $(MODULE_CFLAGS) $(DBUS_CFLAGS) -DPA_MODULE_NAME=module_tone_player module_tizenaudio_policy_la_SOURCES = \ src/module-tizenaudio-policy.c \ @@ -96,36 +96,36 @@ module_tizenaudio_policy_la_SOURCES = \ src/subscribe-observer.c src/subscribe-observer.h module_tizenaudio_policy_la_LDFLAGS = $(MODULE_LDFLAGS) -L$(pulsemodlibexecdir) module_tizenaudio_policy_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) $(VCONF_LIBS) $(INIPARSER_LIBS) $(LIBJSON_LIBS) libhal-interface.la libcommunicator.la -module_tizenaudio_policy_la_CFLAGS = $(MODULE_CFLAGS) $(DBUS_CFLAGS) $(VCONF_CFLAGS) $(INIPARSER_CFLAGS) $(LIBJSON_CFLAGS) +module_tizenaudio_policy_la_CFLAGS = $(MODULE_CFLAGS) $(DBUS_CFLAGS) $(VCONF_CFLAGS) $(INIPARSER_CFLAGS) $(LIBJSON_CFLAGS) -DPA_MODULE_NAME=module_tizenaudio_policy if ENABLE_HALTC module_tizenaudio_haltc_la_SOURCES = src/module-tizenaudio-haltc.c module_tizenaudio_haltc_la_LDFLAGS = $(MODULE_LDFLAGS) module_tizenaudio_haltc_la_LIBADD = $(MODULE_LIBADD) libhal-interface.la -module_tizenaudio_haltc_la_CFLAGS = $(MODULE_CFLAGS) +module_tizenaudio_haltc_la_CFLAGS = $(MODULE_CFLAGS) -DPA_MODULE_NAME=module_tizenaudio_haltc endif module_poweroff_la_SOURCES = src/module-poweroff.c module_poweroff_la_LDFLAGS = $(MODULE_LDFLAGS) module_poweroff_la_LIBADD = $(MODULE_LIBADD) $(DBUS_LIBS) libhal-interface.la -module_poweroff_la_CFLAGS = $(MODULE_CFLAGS) $(DBUS_CFLAGS) +module_poweroff_la_CFLAGS = $(MODULE_CFLAGS) $(DBUS_CFLAGS) -DPA_MODULE_NAME=module_poweroff if ENABLE_ACM module_acm_sink_la_SOURCES = src/module-acm-sink.c src/acm.c src/acm.h module_acm_sink_la_LDFLAGS = $(MODULE_LDFLAGS) module_acm_sink_la_LIBADD = $(MODULE_LIBADD) -module_acm_sink_la_CFLAGS = $(MODULE_CFLAGS) +module_acm_sink_la_CFLAGS = $(MODULE_CFLAGS) -DPA_MODULE_NAME=module_acm_sink endif module_tizenaudio_discover_la_SOURCES = src/module-tizenaudio-discover.c module_tizenaudio_discover_la_LDFLAGS = $(MODULE_LDFLAGS) module_tizenaudio_discover_la_LIBADD = $(MODULE_LIBADD) $(DNSSD_LIBS) $(VCONF_LIBS) -module_tizenaudio_discover_la_CFLAGS = $(MODULE_CFLAGS) $(DNSSD_CFLAGS) $(VCONF_CFLAGS) +module_tizenaudio_discover_la_CFLAGS = $(MODULE_CFLAGS) $(DNSSD_CFLAGS) $(VCONF_CFLAGS) -DPA_MODULE_NAME=module_tizenaudio_discover module_tizenaudio_publish_la_SOURCES = src/module-tizenaudio-publish.c module_tizenaudio_publish_la_LDFLAGS = $(MODULE_LDFLAGS) module_tizenaudio_publish_la_LIBADD = $(MODULE_LIBADD) $(DNSSD_LIBS) -module_tizenaudio_publish_la_CFLAGS = $(AM_CFLAGS) $(DNSSD_CFLAGS) +module_tizenaudio_publish_la_CFLAGS = $(AM_CFLAGS) $(DNSSD_CFLAGS) -DPA_MODULE_NAME=module_tizenaudio_publish if ENABLE_VCONF_HELPER pulsemodlibexec_LTLIBRARIES += module-vconf.la @@ -133,7 +133,7 @@ pulsemodlibexec_LTLIBRARIES += module-vconf.la module_vconf_la_SOURCES = src/vconf/module-vconf.c module_vconf_la_LDFLAGS = $(MODULE_LDFLAGS) module_vconf_la_LIBADD = $(MODULE_LIBADD) libcommunicator.la -module_vconf_la_CFLAGS = $(MODULE_CFLAGS) -DPA_VCONF_HELPER=\"$(pulselibexecdir)/vconf-helper\" +module_vconf_la_CFLAGS = $(MODULE_CFLAGS) -DPA_VCONF_HELPER=\"$(pulselibexecdir)/vconf-helper\" -DPA_MODULE_NAME=module_vconf pulselibexec_PROGRAMS = vconf-helper diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index a622af5..0a6f996 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.32 +Version: 13.0.33 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/module-tizenaudio-discover.c b/src/module-tizenaudio-discover.c index e507e39..e75e452 100644 --- a/src/module-tizenaudio-discover.c +++ b/src/module-tizenaudio-discover.c @@ -688,30 +688,6 @@ static int dnssd_browse_dns_service(struct userdata *u, const char *service_type return 0; } -void pa__done(pa_module *m) { - struct userdata *u; - pa_assert(m); - - if (!(u = m->userdata)) - return; - - if (u->tunnels) { - struct tunnel *t; - - while ((t = pa_hashmap_steal_first(u->tunnels))) { - pa_module_unload_request_by_index(u->core, t->module_index, true); - tunnel_free(t); - } - - pa_hashmap_free(u->tunnels); - } - - request_clear(u->module->core->mainloop, &u->browse_sink); - request_clear(u->module->core->mainloop, &u->browse_source); - - pa_xfree(u); -} - int pa__init(pa_module *m) { struct userdata *u; @@ -748,3 +724,27 @@ fail: return -1; } + +void pa__done(pa_module *m) { + struct userdata *u; + pa_assert(m); + + if (!(u = m->userdata)) + return; + + if (u->tunnels) { + struct tunnel *t; + + while ((t = pa_hashmap_steal_first(u->tunnels))) { + pa_module_unload_request_by_index(u->core, t->module_index, true); + tunnel_free(t); + } + + pa_hashmap_free(u->tunnels); + } + + request_clear(u->module->core->mainloop, &u->browse_sink); + request_clear(u->module->core->mainloop, &u->browse_source); + + pa_xfree(u); +} \ No newline at end of file diff --git a/src/module-tizenaudio-publish.c b/src/module-tizenaudio-publish.c index 0fb0602..1c502f2 100644 --- a/src/module-tizenaudio-publish.c +++ b/src/module-tizenaudio-publish.c @@ -450,38 +450,6 @@ static void unpublish_all_services(struct userdata *u) { DNSServiceRefDeallocate(u->main_service); } -void pa__done(pa_module *m) { - struct userdata *u; - pa_assert(m); - - if (!(u = m->userdata)) - return; - - unpublish_all_services(u); - - if (u->services) - pa_hashmap_free(u->services); - - if (u->sink_new_slot) - pa_hook_slot_free(u->sink_new_slot); - if (u->source_new_slot) - pa_hook_slot_free(u->source_new_slot); - if (u->sink_changed_slot) - pa_hook_slot_free(u->sink_changed_slot); - if (u->source_changed_slot) - pa_hook_slot_free(u->source_changed_slot); - if (u->sink_unlink_slot) - pa_hook_slot_free(u->sink_unlink_slot); - if (u->source_unlink_slot) - pa_hook_slot_free(u->source_unlink_slot); - - if (u->native) - pa_native_protocol_unref(u->native); - - pa_xfree(u->service_name); - pa_xfree(u); -} - int pa__init(pa_module *m) { struct userdata *u; pa_modargs *ma = NULL; @@ -527,3 +495,35 @@ fail: return -1; } + +void pa__done(pa_module *m) { + struct userdata *u; + pa_assert(m); + + if (!(u = m->userdata)) + return; + + unpublish_all_services(u); + + if (u->services) + pa_hashmap_free(u->services); + + if (u->sink_new_slot) + pa_hook_slot_free(u->sink_new_slot); + if (u->source_new_slot) + pa_hook_slot_free(u->source_new_slot); + if (u->sink_changed_slot) + pa_hook_slot_free(u->sink_changed_slot); + if (u->source_changed_slot) + pa_hook_slot_free(u->source_changed_slot); + if (u->sink_unlink_slot) + pa_hook_slot_free(u->sink_unlink_slot); + if (u->source_unlink_slot) + pa_hook_slot_free(u->source_unlink_slot); + + if (u->native) + pa_native_protocol_unref(u->native); + + pa_xfree(u->service_name); + pa_xfree(u); +} \ No newline at end of file diff --git a/src/stream-manager.c b/src/stream-manager.c index e8f107d..4507a71 100644 --- a/src/stream-manager.c +++ b/src/stream-manager.c @@ -44,7 +44,7 @@ #include #include #include - +#include #include #include "stream-manager.h" -- 2.7.4 From ff392108d7d644aaa7166259c52f6798ede1cc51 Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Tue, 27 Oct 2020 20:08:46 +0900 Subject: [PATCH 15/16] device-manager-dbus: fix crash of getting empty supported samplerates/formats [Version] 13.0.34 [Issue Type] Bug Change-Id: I8faab3479f9bf2daa87d0f818b50f1a95e96caeb --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/device-manager-dbus.c | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 0a6f996..638827d 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.33 +Version: 13.0.34 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/device-manager-dbus.c b/src/device-manager-dbus.c index b9ab071..7190965 100644 --- a/src/device-manager-dbus.c +++ b/src/device-manager-dbus.c @@ -1095,6 +1095,12 @@ static void handle_get_supported_sample_formats(DBusConnection *conn, DBusMessag return; } + if (!sink->supported_sample_formats) { + pa_log_error("supported sample formats is not set on this sink"); + pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation"); + return; + } + dbus_message_iter_init_append(reply, &msg_iter); pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "s", &array_iter)); for (i = 0; sink->supported_sample_formats[i] != PA_SAMPLE_MAX; i++) { @@ -1268,6 +1274,12 @@ static void handle_get_supported_sample_rates(DBusConnection *conn, DBusMessage return; } + if (!sink->supported_sample_rates) { + pa_log_error("supported sample rates is not set on this sink"); + pa_dbus_send_error(conn, msg, DBUS_ERROR_NOT_SUPPORTED, "%s", "org.tizen.multimedia.audio.InvalidOperation"); + return; + } + dbus_message_iter_init_append(reply, &msg_iter); pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "u", &array_iter)); for (i = 0; sink->supported_sample_rates[i]; i++) { -- 2.7.4 From d07b2271b0453d63ac22c9970313412140b90953 Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Wed, 28 Oct 2020 20:17:32 +0900 Subject: [PATCH 16/16] device-manager-dbus: use pa dbus wrapper function if possible [Version] 13.0.35 [Issue Type] Revise Change-Id: I926a1860bc43b789ae5cf5490973f92b9ddd6cbd --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/device-manager-dbus.c | 306 +++++++++++--------------------- 2 files changed, 108 insertions(+), 200 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 638827d..e6f794d 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -1,6 +1,6 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 13.0.34 +Version: 13.0.35 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/device-manager-dbus.c b/src/device-manager-dbus.c index 7190965..52e87e1 100644 --- a/src/device-manager-dbus.c +++ b/src/device-manager-dbus.c @@ -507,10 +507,10 @@ static int handle_bluez_headset_property_changed(DBusConnection *c, DBusMessage static DBusHandlerResult dbus_filter_device_detect_handler(DBusConnection *c, DBusMessage *s, void *userdata) { DBusError error; int status = 0; - pa_device_manager *dm = (pa_device_manager *) userdata; + pa_device_manager *dm = (pa_device_manager *)userdata; device_detected_type_t detected; - pa_assert(userdata); + pa_assert(dm); if (dbus_message_get_type(s) != DBUS_MESSAGE_TYPE_SIGNAL) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -678,7 +678,7 @@ static int method_call_bt_get_name(DBusConnection *conn, const char *device_path } static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_device_manager *dm; + pa_device_manager *dm = (pa_device_manager *)userdata; DBusMessage *reply = NULL; DBusMessageIter msg_iter, array_iter, device_iter; pa_tz_device *device; @@ -692,10 +692,7 @@ static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage * pa_assert(conn); pa_assert(msg); - pa_assert(userdata); - - - dm = (pa_device_manager*) userdata; + pa_assert(dm); pa_assert_se((reply = dbus_message_new_method_return(msg))); @@ -742,7 +739,7 @@ static void handle_get_connected_device_list(DBusConnection *conn, DBusMessage * } static void handle_get_device_by_id(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_device_manager *manager; + pa_device_manager *dm = (pa_device_manager *)userdata; DBusMessage *reply; DBusMessageIter msg_iter; pa_tz_device *device; @@ -753,9 +750,7 @@ static void handle_get_device_by_id(DBusConnection *conn, DBusMessage *msg, void pa_assert(conn); pa_assert(msg); - pa_assert(userdata); - - manager = (pa_device_manager*) userdata; + pa_assert(dm); pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &device_id, @@ -763,7 +758,7 @@ static void handle_get_device_by_id(DBusConnection *conn, DBusMessage *msg, void pa_log_info("Get device by id(%d)", device_id); - if ((device = device_list_get_device_by_id(manager, device_id))) { + if ((device = device_list_get_device_by_id(dm, device_id))) { pa_assert_se((reply = dbus_message_new_method_return(msg))); dbus_message_iter_init_append(reply, &msg_iter); @@ -792,19 +787,15 @@ static void handle_get_device_by_id(DBusConnection *conn, DBusMessage *msg, void } } -static void handle_is_device_running_by_id(DBusConnection *conn, DBusMessage *msg, void *userdata) -{ - pa_device_manager *manager; - DBusMessage *reply; +static void handle_is_device_running_by_id(DBusConnection *conn, DBusMessage *msg, void *userdata) { + pa_device_manager *dm = (pa_device_manager *)userdata; pa_tz_device *device; dbus_int32_t device_id; dbus_bool_t is_running; pa_assert(conn); pa_assert(msg); - pa_assert(userdata); - - manager = (pa_device_manager *)userdata; + pa_assert(dm); pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &device_id, @@ -812,28 +803,21 @@ static void handle_is_device_running_by_id(DBusConnection *conn, DBusMessage *ms pa_log_info("Is device running by id(%d)", device_id); - if ((device = device_list_get_device_by_id(manager, device_id))) { - pa_assert_se((reply = dbus_message_new_method_return(msg))); - + if ((device = device_list_get_device_by_id(dm, device_id))) { is_running = pa_tz_device_is_running(device); pa_log_info("device(id:%d) is %s", device_id, is_running ? "Running" : "Not Running"); - pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &is_running, - DBUS_TYPE_INVALID)); - - pa_assert_se(dbus_connection_send(conn, reply, NULL)); - dbus_message_unref(reply); + pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_BOOLEAN, &is_running); } else { pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal"); } } static void handle_is_stream_on_device(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_device_manager *manager; - DBusMessage *reply; + pa_device_manager *dm = (pa_device_manager *)userdata; pa_tz_device *device; - dbus_bool_t is_on = false; + dbus_bool_t is_on = FALSE; dbus_int32_t stream_id, device_id; pa_intset *stream_id_set; int32_t stream_id_val; @@ -842,27 +826,22 @@ static void handle_is_stream_on_device(DBusConnection *conn, DBusMessage *msg, v pa_assert(conn); pa_assert(msg); - pa_assert(userdata); + pa_assert(dm); pa_log_info("Is stream on device"); - manager = (pa_device_manager*) userdata; - - pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &stream_id, DBUS_TYPE_INT32, &device_id, DBUS_TYPE_INVALID)); - if ((device = device_list_get_device_by_id(manager, device_id))) { - pa_assert_se((reply = dbus_message_new_method_return(msg))); - + if ((device = device_list_get_device_by_id(dm, device_id))) { state = pa_tz_device_get_state(device); if (state == DM_DEVICE_STATE_ACTIVATED) { stream_id_set = pa_tz_device_get_stream_list(device); PA_INTSET_FOREACH(stream_id_val, stream_id_set, ret) { if (stream_id_val == stream_id) { - is_on = true; + is_on = TRUE; pa_log_info("stream(%d) is on device(%d)", stream_id, device_id); break; } @@ -870,113 +849,106 @@ static void handle_is_stream_on_device(DBusConnection *conn, DBusMessage *msg, v pa_intset_free(stream_id_set); } else { pa_log_info("device(%d) is not activated, regard as no stream on it", device_id); - is_on = false; + is_on = FALSE; } - - pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &is_on, - DBUS_TYPE_INVALID)); - - pa_assert_se(dbus_connection_send(conn, reply, NULL)); - dbus_message_unref(reply); + pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_BOOLEAN, &is_on); } else { pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", "org.tizen.multimedia.audio.Internal"); } } static void handle_get_bt_a2dp_status(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_device_manager *dm; + pa_device_manager *dm = (pa_device_manager *)userdata; DBusMessage *reply = NULL; pa_tz_device *device; - dbus_bool_t is_bt_on = false; + dbus_bool_t is_bt_on = FALSE; const char *bt_name = "none"; pa_assert(conn); pa_assert(msg); - pa_assert(userdata); + pa_assert(dm); pa_log_info("Get BT A2DP list"); - dm = (pa_device_manager*) userdata; - - pa_assert_se((reply = dbus_message_new_method_return(msg))); - /* FIXME : Give system_id for multi device */ if ((device = device_list_get_device(dm, DEVICE_TYPE_BT_A2DP, NULL, NULL)) != NULL) { - is_bt_on = true; + is_bt_on = TRUE; bt_name = pa_tz_device_get_name(device); } + pa_assert_se((reply = dbus_message_new_method_return(msg))); pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &is_bt_on, DBUS_TYPE_STRING, &bt_name, DBUS_TYPE_INVALID)); - pa_assert_se(dbus_connection_send(conn, reply, NULL)); dbus_message_unref(reply); } static void handle_load_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_device_manager *dm; + pa_device_manager *dm = (pa_device_manager *)userdata; char *type, *role; pa_sink *sink; - DBusMessage *reply = NULL; - dm = (pa_device_manager *) userdata; + pa_assert(conn); + pa_assert(msg); + pa_assert(dm); + pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &type, DBUS_TYPE_STRING, &role, DBUS_TYPE_INVALID)); - if (!(sink = pa_device_manager_load_sink(dm, type, role))) { + if (!(sink = pa_device_manager_load_sink(dm, type, role))) pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s", "org.tizen.multimedia.audio.Internal"); - return; - } - - pa_assert_se((reply = dbus_message_new_method_return(msg))); - pa_assert_se(dbus_connection_send(conn, reply, NULL)); - dbus_message_unref(reply); + else + pa_dbus_send_empty_reply(conn, msg); } static void handle_unload_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_device_manager *dm; + pa_device_manager *dm = (pa_device_manager *)userdata; char *type, *role; - DBusMessage *reply = NULL; - pa_assert_se((reply = dbus_message_new_method_return(msg))); - dm = (pa_device_manager *) userdata; + pa_assert(conn); + pa_assert(msg); + pa_assert(dm); + pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &type, DBUS_TYPE_STRING, &role, DBUS_TYPE_INVALID)); pa_device_manager_unload_sink(dm, type, role); - pa_assert_se(dbus_connection_send(conn, reply, NULL)); - dbus_message_unref(reply); + + pa_dbus_send_empty_reply(conn, msg); } static void handle_unload_sink_with_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_device_manager *dm; + pa_device_manager *dm = (pa_device_manager *)userdata; char *device_string; - DBusMessage *reply = NULL; - pa_assert_se((reply = dbus_message_new_method_return(msg))); - dm = (pa_device_manager *) userdata; + pa_assert(conn); + pa_assert(msg); + pa_assert(dm); + pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &device_string, DBUS_TYPE_INVALID)); pa_device_manager_unload_sink_with_device_string(dm, device_string); - pa_assert_se(dbus_connection_send(conn, reply, NULL)); - dbus_message_unref(reply); + + pa_dbus_send_empty_reply(conn, msg); } static void handle_get_device_string(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_device_manager *dm; + pa_device_manager *dm = (pa_device_manager *)userdata; char *type, *role; const char *device_string; dbus_bool_t is_playback; - DBusMessage *reply; - dm = (pa_device_manager *) userdata; + pa_assert(conn); + pa_assert(msg); + pa_assert(dm); + pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &is_playback, DBUS_TYPE_STRING, &type, @@ -990,27 +962,24 @@ static void handle_get_device_string(DBusConnection *conn, DBusMessage *msg, voi } pa_log_info("device string : %s", device_string); - pa_assert_se((reply = dbus_message_new_method_return(msg))); - pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &device_string, - DBUS_TYPE_INVALID)); - pa_assert_se(dbus_connection_send(conn, reply, NULL)); - dbus_message_unref(reply); + + pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &device_string); } static void handle_dump_device_list(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_device_manager *dm; + pa_device_manager *dm = (pa_device_manager *)userdata; pa_tz_device *device; uint32_t device_idx; - DBusMessage *reply = NULL; - pa_assert_se((reply = dbus_message_new_method_return(msg))); - dm = (pa_device_manager *) userdata; + pa_assert(conn); + pa_assert(msg); + pa_assert(dm); PA_IDXSET_FOREACH(device, dm->device_list, device_idx) { pa_tz_device_dump_info(device, PA_LOG_INFO); } - pa_assert_se(dbus_connection_send(conn, reply, NULL)); - dbus_message_unref(reply); + + pa_dbus_send_empty_reply(conn, msg); } static bool is_usb_output_device(pa_tz_device *device) { @@ -1057,7 +1026,7 @@ static bool is_supported_sample_format(pa_sample_format_t *supported_sample_form } static void handle_get_supported_sample_formats(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_device_manager *dm; + pa_device_manager *dm = (pa_device_manager *)userdata; DBusMessage *reply = NULL; DBusMessageIter msg_iter, array_iter; dbus_int32_t device_id; @@ -1068,9 +1037,7 @@ static void handle_get_supported_sample_formats(DBusConnection *conn, DBusMessag pa_assert(conn); pa_assert(msg); - pa_assert(userdata); - - dm = (pa_device_manager *)userdata; + pa_assert(dm); pa_assert_se((reply = dbus_message_new_method_return(msg))); @@ -1114,8 +1081,7 @@ static void handle_get_supported_sample_formats(DBusConnection *conn, DBusMessag } static void handle_set_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_device_manager *dm; - DBusMessage *reply = NULL; + pa_device_manager *dm = (pa_device_manager *)userdata; dbus_int32_t device_id; char *sample_format; pa_sample_format_t prev_selected_sample_format; @@ -1125,10 +1091,8 @@ static void handle_set_sample_format(DBusConnection *conn, DBusMessage *msg, voi pa_assert(conn); pa_assert(msg); - pa_assert(userdata); + pa_assert(dm); - pa_assert_se((reply = dbus_message_new_method_return(msg))); - dm = (pa_device_manager *)userdata; pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &device_id, DBUS_TYPE_STRING, &sample_format, @@ -1172,13 +1136,12 @@ static void handle_set_sample_format(DBusConnection *conn, DBusMessage *msg, voi } pa_log_info("Set sample format(%s) of the device(id:%d) successfully", sample_format, device_id); - pa_assert_se(dbus_connection_send(conn, reply, NULL)); - dbus_message_unref(reply); + + pa_dbus_send_empty_reply(conn, msg); } static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_device_manager *dm; - DBusMessage *reply = NULL; + pa_device_manager *dm = (pa_device_manager *)userdata; dbus_int32_t device_id; pa_tz_device *device; pa_sink *sink; @@ -1186,11 +1149,7 @@ static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, voi pa_assert(conn); pa_assert(msg); - pa_assert(userdata); - - dm = (pa_device_manager *)userdata; - - pa_assert_se((reply = dbus_message_new_method_return(msg))); + pa_assert(dm); pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &device_id, @@ -1215,10 +1174,8 @@ static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, voi format = pa_sample_format_to_string(sink->selected_sample_format); pa_log_info("Get sample format(%s) of the device(id:%d) successfully", format, device_id); - pa_assert_se((reply = dbus_message_new_method_return(msg))); - pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &format, DBUS_TYPE_INVALID)); - pa_assert_se(dbus_connection_send(conn, reply, NULL)); - dbus_message_unref(reply); + + pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &format); } static bool is_supported_sample_rate(uint32_t *supported_sample_rates, uint32_t sample_rate) { @@ -1237,7 +1194,7 @@ static bool is_supported_sample_rate(uint32_t *supported_sample_rates, uint32_t } static void handle_get_supported_sample_rates(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_device_manager *dm; + pa_device_manager *dm = (pa_device_manager *)userdata; DBusMessage *reply = NULL; DBusMessageIter msg_iter, array_iter; dbus_int32_t device_id; @@ -1247,9 +1204,7 @@ static void handle_get_supported_sample_rates(DBusConnection *conn, DBusMessage pa_assert(conn); pa_assert(msg); - pa_assert(userdata); - - dm = (pa_device_manager *)userdata; + pa_assert(dm); pa_assert_se((reply = dbus_message_new_method_return(msg))); @@ -1292,8 +1247,7 @@ static void handle_get_supported_sample_rates(DBusConnection *conn, DBusMessage } static void handle_set_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_device_manager *dm; - DBusMessage *reply = NULL; + pa_device_manager *dm = (pa_device_manager *)userdata; dbus_int32_t device_id; dbus_uint32_t sample_rate; uint32_t prev_selected_sample_rate; @@ -1303,10 +1257,8 @@ static void handle_set_sample_rate(DBusConnection *conn, DBusMessage *msg, void pa_assert(conn); pa_assert(msg); - pa_assert(userdata); + pa_assert(dm); - pa_assert_se((reply = dbus_message_new_method_return(msg))); - dm = (pa_device_manager *)userdata; pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &device_id, DBUS_TYPE_UINT32, &sample_rate, @@ -1350,24 +1302,19 @@ static void handle_set_sample_rate(DBusConnection *conn, DBusMessage *msg, void } pa_log_info("Set sample rate(%u) of the device(id:%d) successfully", sample_rate, device_id); - pa_assert_se(dbus_connection_send(conn, reply, NULL)); - dbus_message_unref(reply); + + pa_dbus_send_empty_reply(conn, msg); } static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_device_manager *dm; - DBusMessage *reply = NULL; + pa_device_manager *dm = (pa_device_manager *)userdata; dbus_int32_t device_id; pa_tz_device *device; pa_sink *sink; pa_assert(conn); pa_assert(msg); - pa_assert(userdata); - - dm = (pa_device_manager *)userdata; - - pa_assert_se((reply = dbus_message_new_method_return(msg))); + pa_assert(dm); pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &device_id, @@ -1391,25 +1338,20 @@ static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void } pa_log_info("Get sample rate(%u) of the device(id:%d) successfully", sink->selected_sample_rate, device_id); - pa_assert_se((reply = dbus_message_new_method_return(msg))); - pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_UINT32, &sink->selected_sample_rate, DBUS_TYPE_INVALID)); - pa_assert_se(dbus_connection_send(conn, reply, NULL)); - dbus_message_unref(reply); + + pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_UINT32, &sink->selected_sample_rate); } static void handle_set_specific_stream_only(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_device_manager *dm; - DBusMessage *reply = NULL; + pa_device_manager *dm = (pa_device_manager *)userdata; dbus_int32_t device_id; char *stream_role; pa_tz_device *device; pa_assert(conn); pa_assert(msg); - pa_assert(userdata); + pa_assert(dm); - pa_assert_se((reply = dbus_message_new_method_return(msg))); - dm = (pa_device_manager *)userdata; pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &device_id, DBUS_TYPE_STRING, &stream_role, @@ -1434,24 +1376,18 @@ static void handle_set_specific_stream_only(DBusConnection *conn, DBusMessage *m pa_xfree(device->specified_stream_role); device->specified_stream_role = pa_xstrdup(stream_role); - pa_assert_se(dbus_connection_send(conn, reply, NULL)); - dbus_message_unref(reply); + pa_dbus_send_empty_reply(conn, msg); } static void handle_get_specified_stream(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_device_manager *dm; - DBusMessage *reply = NULL; + pa_device_manager *dm = (pa_device_manager *)userdata; dbus_int32_t device_id; char *specified_stream_role; pa_tz_device *device; pa_assert(conn); pa_assert(msg); - pa_assert(userdata); - - dm = (pa_device_manager *)userdata; - - pa_assert_se((reply = dbus_message_new_method_return(msg))); + pa_assert(dm); pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &device_id, @@ -1472,15 +1408,12 @@ static void handle_get_specified_stream(DBusConnection *conn, DBusMessage *msg, specified_stream_role = device->specified_stream_role; pa_log_info("stream role(%s) is specified for the device(id:%d)", device->specified_stream_role, device_id); - pa_assert_se((reply = dbus_message_new_method_return(msg))); - pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_STRING, &specified_stream_role, DBUS_TYPE_INVALID)); - pa_assert_se(dbus_connection_send(conn, reply, NULL)); - dbus_message_unref(reply); + + pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_STRING, &specified_stream_role); } static void handle_set_avoid_resampling(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_device_manager *dm; - DBusMessage *reply = NULL; + pa_device_manager *dm = (pa_device_manager *)userdata; dbus_int32_t device_id; dbus_bool_t avoid_resampling; pa_tz_device *device; @@ -1488,10 +1421,8 @@ static void handle_set_avoid_resampling(DBusConnection *conn, DBusMessage *msg, pa_assert(conn); pa_assert(msg); - pa_assert(userdata); + pa_assert(dm); - pa_assert_se((reply = dbus_message_new_method_return(msg))); - dm = (pa_device_manager *)userdata; pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &device_id, DBUS_TYPE_BOOLEAN, &avoid_resampling, @@ -1515,24 +1446,17 @@ static void handle_set_avoid_resampling(DBusConnection *conn, DBusMessage *msg, } if (sink->avoid_resampling == avoid_resampling) { pa_log_info("already set to %d", avoid_resampling); - pa_assert_se(dbus_connection_send(conn, reply, NULL)); - dbus_message_unref(reply); - return; + } else { + sink->avoid_resampling = avoid_resampling; + save_preference(dm, sink); + pa_log_info("Set avoid-resampling(%d) to the device(id:%d)", avoid_resampling, device_id); } - sink->avoid_resampling = avoid_resampling; - - save_preference(dm, sink); - - pa_log_info("Set avoid-resampling(%d) to the device(id:%d)", avoid_resampling, device_id); - - pa_assert_se(dbus_connection_send(conn, reply, NULL)); - dbus_message_unref(reply); + pa_dbus_send_empty_reply(conn, msg); } static void handle_get_avoid_resampling(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_device_manager *dm; - DBusMessage *reply = NULL; + pa_device_manager *dm = (pa_device_manager *)userdata; dbus_int32_t device_id; dbus_bool_t avoid_resampling; pa_tz_device *device; @@ -1540,11 +1464,7 @@ static void handle_get_avoid_resampling(DBusConnection *conn, DBusMessage *msg, pa_assert(conn); pa_assert(msg); - pa_assert(userdata); - - dm = (pa_device_manager *)userdata; - - pa_assert_se((reply = dbus_message_new_method_return(msg))); + pa_assert(dm); pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &device_id, @@ -1570,48 +1490,38 @@ static void handle_get_avoid_resampling(DBusConnection *conn, DBusMessage *msg, avoid_resampling = sink->avoid_resampling; pa_log_info("got avoid-resampling(%d) of the device(id:%d)", avoid_resampling, device_id); - pa_assert_se((reply = dbus_message_new_method_return(msg))); - pa_assert_se(dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &avoid_resampling, DBUS_TYPE_INVALID)); - pa_assert_se(dbus_connection_send(conn, reply, NULL)); - dbus_message_unref(reply); + pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_BOOLEAN, &avoid_resampling); } static void handle_test_device_status_change(DBusConnection *conn, DBusMessage *msg, void *userdata) { pa_device_manager *dm = (pa_device_manager *)userdata; char *type; dbus_int32_t status; - DBusMessage *reply = NULL; - DBusError error; - pa_assert_se((reply = dbus_message_new_method_return(msg))); + pa_assert(conn); + pa_assert(msg); + pa_assert(dm); - dbus_error_init(&error); - if (!dbus_message_get_args(msg, NULL, + pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &type, DBUS_TYPE_INT32, &status, - DBUS_TYPE_INVALID)) { - pa_log_error("failed to get dbus args : %s", error.message); - pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message); - dbus_error_free(&error); - } + DBUS_TYPE_INVALID)); pa_log_debug("handle_test_device_status_change, type:%s, status:%d", type, status); - handle_device_status_changed(dm, type, NULL, NULL, status); - pa_assert_se(dbus_connection_send(conn, reply, NULL)); - dbus_message_unref(reply); + handle_device_status_changed(dm, type, NULL, NULL, status); + + pa_dbus_send_empty_reply(conn, msg); } static void handle_set_acm_mode(DBusConnection *conn, DBusMessage *msg, void *userdata) { - pa_device_manager *dm; - DBusMessage *reply = NULL; + pa_device_manager *dm = (pa_device_manager *)userdata; uint32_t mode = 0; pa_assert(conn); pa_assert(msg); - pa_assert(userdata); + pa_assert(dm); - dm = (pa_device_manager *)userdata; pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &mode, DBUS_TYPE_INVALID)); @@ -1629,9 +1539,7 @@ static void handle_set_acm_mode(DBusConnection *conn, DBusMessage *msg, void *us } } - pa_assert_se((reply = dbus_message_new_method_return(msg))); - pa_assert_se(dbus_connection_send(conn, reply, NULL)); - dbus_message_unref(reply); + pa_dbus_send_empty_reply(conn, msg); } static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata) { -- 2.7.4