mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-11-03 09:01:50 -05:00 
			
		
		
		
	Merge remote branch 'tanuk/dbus-work'
This commit is contained in:
		
						commit
						692ce73899
					
				
					 49 changed files with 11609 additions and 49 deletions
				
			
		| 
						 | 
				
			
			@ -22,8 +22,7 @@
 | 
			
		|||
 | 
			
		||||
AC_PREREQ(2.63)
 | 
			
		||||
 | 
			
		||||
AC_INIT([pulseaudio], m4_esyscmd([./git-version-gen .tarball-version]),
 | 
			
		||||
	[mzchyfrnhqvb (at) 0pointer (dot) net])
 | 
			
		||||
AC_INIT([pulseaudio],[m4_esyscmd(./git-version-gen .tarball-version)],[mzchyfrnhqvb (at) 0pointer (dot) net])
 | 
			
		||||
AC_CONFIG_SRCDIR([src/daemon/main.c])
 | 
			
		||||
AC_CONFIG_MACRO_DIR([m4])
 | 
			
		||||
AC_CONFIG_HEADERS([config.h])
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -169,13 +169,14 @@ BUILT_SOURCES = \
 | 
			
		|||
bin_PROGRAMS = pulseaudio
 | 
			
		||||
 | 
			
		||||
pulseaudio_SOURCES = \
 | 
			
		||||
		daemon/caps.h daemon/caps.c \
 | 
			
		||||
		daemon/caps.c daemon/caps.h \
 | 
			
		||||
		daemon/cmdline.c daemon/cmdline.h \
 | 
			
		||||
		daemon/cpulimit.c daemon/cpulimit.h \
 | 
			
		||||
		daemon/daemon-conf.c daemon/daemon-conf.h \
 | 
			
		||||
		daemon/dumpmodules.c daemon/dumpmodules.h \
 | 
			
		||||
		daemon/ltdl-bind-now.c daemon/ltdl-bind-now.h \
 | 
			
		||||
		daemon/main.c
 | 
			
		||||
		daemon/main.c \
 | 
			
		||||
		daemon/server-lookup.c daemon/server-lookup.h
 | 
			
		||||
 | 
			
		||||
pulseaudio_CFLAGS = $(AM_CFLAGS) $(LIBSAMPLERATE_CFLAGS) $(LIBSPEEX_CFLAGS) $(LIBSNDFILE_CFLAGS) $(CAP_CFLAGS) $(DBUS_CFLAGS)
 | 
			
		||||
pulseaudio_LDADD = $(AM_LDADD) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la $(LIBLTDL) $(LIBSAMPLERATE_LIBS) $(LIBSPEEX_LIBS) $(LIBSNDFILE_LIBS) $(CAP_LIBS) $(DBUS_LIBS)
 | 
			
		||||
| 
						 | 
				
			
			@ -869,7 +870,9 @@ libpulsecore_@PA_MAJORMINORMICRO@_la_LDFLAGS += $(X11_LIBS)
 | 
			
		|||
endif
 | 
			
		||||
 | 
			
		||||
if HAVE_DBUS
 | 
			
		||||
libpulsecore_@PA_MAJORMINORMICRO@_la_SOURCES += pulsecore/dbus-shared.c pulsecore/dbus-shared.h
 | 
			
		||||
libpulsecore_@PA_MAJORMINORMICRO@_la_SOURCES += \
 | 
			
		||||
		pulsecore/dbus-shared.c pulsecore/dbus-shared.h \
 | 
			
		||||
		pulsecore/protocol-dbus.c pulsecore/protocol-dbus.h
 | 
			
		||||
libpulsecore_@PA_MAJORMINORMICRO@_la_CFLAGS += $(DBUS_CFLAGS)
 | 
			
		||||
libpulsecore_@PA_MAJORMINORMICRO@_la_LIBADD += $(DBUS_LIBS)
 | 
			
		||||
endif
 | 
			
		||||
| 
						 | 
				
			
			@ -1156,7 +1159,8 @@ endif
 | 
			
		|||
 | 
			
		||||
if HAVE_DBUS
 | 
			
		||||
modlibexec_LTLIBRARIES += \
 | 
			
		||||
		module-rygel-media-server.la
 | 
			
		||||
		module-rygel-media-server.la \
 | 
			
		||||
		module-dbus-protocol.la
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
if HAVE_BLUEZ
 | 
			
		||||
| 
						 | 
				
			
			@ -1251,6 +1255,7 @@ SYMDEF_FILES = \
 | 
			
		|||
		modules/module-augment-properties-symdef.h \
 | 
			
		||||
		modules/module-cork-music-on-phone-symdef.h \
 | 
			
		||||
		modules/module-console-kit-symdef.h \
 | 
			
		||||
		modules/dbus/module-dbus-protocol-symdef.h \
 | 
			
		||||
		modules/module-loopback-symdef.h
 | 
			
		||||
 | 
			
		||||
EXTRA_DIST += $(SYMDEF_FILES)
 | 
			
		||||
| 
						 | 
				
			
			@ -1300,6 +1305,24 @@ module_http_protocol_unix_la_CFLAGS = -DUSE_UNIX_SOCKETS -DUSE_PROTOCOL_HTTP $(A
 | 
			
		|||
module_http_protocol_unix_la_LDFLAGS = $(MODULE_LDFLAGS)
 | 
			
		||||
module_http_protocol_unix_la_LIBADD = $(AM_LIBADD) libpulsecore-@PA_MAJORMINORMICRO@.la libprotocol-http.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la
 | 
			
		||||
 | 
			
		||||
# D-Bus protocol
 | 
			
		||||
 | 
			
		||||
module_dbus_protocol_la_SOURCES = \
 | 
			
		||||
		modules/dbus/iface-card.c modules/dbus/iface-card.h \
 | 
			
		||||
		modules/dbus/iface-card-profile.c modules/dbus/iface-card-profile.h \
 | 
			
		||||
		modules/dbus/iface-client.c modules/dbus/iface-client.h \
 | 
			
		||||
		modules/dbus/iface-core.c modules/dbus/iface-core.h \
 | 
			
		||||
		modules/dbus/iface-device.c modules/dbus/iface-device.h \
 | 
			
		||||
		modules/dbus/iface-device-port.c modules/dbus/iface-device-port.h \
 | 
			
		||||
		modules/dbus/iface-memstats.c modules/dbus/iface-memstats.h \
 | 
			
		||||
		modules/dbus/iface-module.c modules/dbus/iface-module.h \
 | 
			
		||||
		modules/dbus/iface-sample.c modules/dbus/iface-sample.h \
 | 
			
		||||
		modules/dbus/iface-stream.c modules/dbus/iface-stream.h \
 | 
			
		||||
		modules/dbus/module-dbus-protocol.c
 | 
			
		||||
module_dbus_protocol_la_CFLAGS = $(AM_CFLAGS) $(DBUS_CFLAGS)
 | 
			
		||||
module_dbus_protocol_la_LDFLAGS = $(MODULE_LDFLAGS)
 | 
			
		||||
module_dbus_protocol_la_LIBADD = $(AM_LIBADD) $(DBUS_LIBS) libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la
 | 
			
		||||
 | 
			
		||||
# Native protocol
 | 
			
		||||
 | 
			
		||||
module_native_protocol_tcp_la_SOURCES = modules/module-protocol-stub.c
 | 
			
		||||
| 
						 | 
				
			
			@ -1551,6 +1574,11 @@ module_stream_restore_la_LDFLAGS = $(MODULE_LDFLAGS)
 | 
			
		|||
module_stream_restore_la_LIBADD = $(AM_LIBADD) libprotocol-native.la libpulsecore-@PA_MAJORMINORMICRO@.la libpulsecommon-@PA_MAJORMINORMICRO@.la libpulse.la
 | 
			
		||||
module_stream_restore_la_CFLAGS = $(AM_CFLAGS)
 | 
			
		||||
 | 
			
		||||
if HAVE_DBUS
 | 
			
		||||
module_stream_restore_la_LIBADD += $(DBUS_LIBS)
 | 
			
		||||
module_stream_restore_la_CFLAGS += $(DBUS_CFLAGS)
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
# Card profile restore module
 | 
			
		||||
module_card_restore_la_SOURCES = modules/module-card-restore.c
 | 
			
		||||
module_card_restore_la_LDFLAGS = $(MODULE_LDFLAGS)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -83,6 +83,9 @@ static const pa_daemon_conf default_conf = {
 | 
			
		|||
    .config_file = NULL,
 | 
			
		||||
    .use_pid_file = TRUE,
 | 
			
		||||
    .system_instance = FALSE,
 | 
			
		||||
#ifdef HAVE_DBUS
 | 
			
		||||
    .local_server_type = PA_SERVER_TYPE_UNSET, /* The actual default is _USER, but we have to detect when the user doesn't specify this option. */
 | 
			
		||||
#endif
 | 
			
		||||
    .no_cpu_limit = TRUE,
 | 
			
		||||
    .disable_shm = FALSE,
 | 
			
		||||
    .lock_memory = FALSE,
 | 
			
		||||
| 
						 | 
				
			
			@ -220,6 +223,22 @@ int pa_daemon_conf_set_resample_method(pa_daemon_conf *c, const char *string) {
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int pa_daemon_conf_set_local_server_type(pa_daemon_conf *c, const char *string) {
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
    pa_assert(string);
 | 
			
		||||
 | 
			
		||||
    if (!strcmp(string, "user"))
 | 
			
		||||
        c->local_server_type = PA_SERVER_TYPE_USER;
 | 
			
		||||
    else if (!strcmp(string, "system")) {
 | 
			
		||||
        c->local_server_type = PA_SERVER_TYPE_SYSTEM;
 | 
			
		||||
    } else if (!strcmp(string, "none")) {
 | 
			
		||||
        c->local_server_type = PA_SERVER_TYPE_NONE;
 | 
			
		||||
    } else
 | 
			
		||||
        return -1;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int parse_log_target(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
 | 
			
		||||
    pa_daemon_conf *c = data;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -447,6 +466,22 @@ static int parse_rtprio(const char *filename, unsigned line, const char *section
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int parse_server_type(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata) {
 | 
			
		||||
    pa_daemon_conf *c = data;
 | 
			
		||||
 | 
			
		||||
    pa_assert(filename);
 | 
			
		||||
    pa_assert(lvalue);
 | 
			
		||||
    pa_assert(rvalue);
 | 
			
		||||
    pa_assert(data);
 | 
			
		||||
 | 
			
		||||
    if (pa_daemon_conf_set_local_server_type(c, rvalue) < 0) {
 | 
			
		||||
        pa_log(_("[%s:%u] Invalid server type '%s'."), filename, line, rvalue);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
 | 
			
		||||
    int r = -1;
 | 
			
		||||
    FILE *f = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -462,6 +497,9 @@ int pa_daemon_conf_load(pa_daemon_conf *c, const char *filename) {
 | 
			
		|||
        { "allow-exit",                 pa_config_parse_not_bool, &c->disallow_exit, NULL },
 | 
			
		||||
        { "use-pid-file",               pa_config_parse_bool,     &c->use_pid_file, NULL },
 | 
			
		||||
        { "system-instance",            pa_config_parse_bool,     &c->system_instance, NULL },
 | 
			
		||||
#ifdef HAVE_DBUS
 | 
			
		||||
        { "local-server-type",          parse_server_type,        c, NULL },
 | 
			
		||||
#endif
 | 
			
		||||
        { "no-cpu-limit",               pa_config_parse_bool,     &c->no_cpu_limit, NULL },
 | 
			
		||||
        { "cpu-limit",                  pa_config_parse_not_bool, &c->no_cpu_limit, NULL },
 | 
			
		||||
        { "disable-shm",                pa_config_parse_bool,     &c->disable_shm, NULL },
 | 
			
		||||
| 
						 | 
				
			
			@ -627,6 +665,14 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) {
 | 
			
		|||
        [PA_LOG_WARN] = "warning",
 | 
			
		||||
        [PA_LOG_ERROR] = "error"
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    static const char* const server_type_to_string[] = {
 | 
			
		||||
        [PA_SERVER_TYPE_UNSET] = "!!UNSET!!",
 | 
			
		||||
        [PA_SERVER_TYPE_USER] = "user",
 | 
			
		||||
        [PA_SERVER_TYPE_SYSTEM] = "system",
 | 
			
		||||
        [PA_SERVER_TYPE_NONE] = "none"
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    pa_strbuf *s;
 | 
			
		||||
    char cm[PA_CHANNEL_MAP_SNPRINT_MAX];
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -649,6 +695,9 @@ char *pa_daemon_conf_dump(pa_daemon_conf *c) {
 | 
			
		|||
    pa_strbuf_printf(s, "allow-exit = %s\n", pa_yes_no(!c->disallow_exit));
 | 
			
		||||
    pa_strbuf_printf(s, "use-pid-file = %s\n", pa_yes_no(c->use_pid_file));
 | 
			
		||||
    pa_strbuf_printf(s, "system-instance = %s\n", pa_yes_no(c->system_instance));
 | 
			
		||||
#ifdef HAVE_DBUS
 | 
			
		||||
    pa_strbuf_printf(s, "local-server-type = %s\n", server_type_to_string[c->local_server_type]);
 | 
			
		||||
#endif
 | 
			
		||||
    pa_strbuf_printf(s, "cpu-limit = %s\n", pa_yes_no(!c->no_cpu_limit));
 | 
			
		||||
    pa_strbuf_printf(s, "enable-shm = %s\n", pa_yes_no(!c->disable_shm));
 | 
			
		||||
    pa_strbuf_printf(s, "flat-volumes = %s\n", pa_yes_no(c->flat_volumes));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,7 @@
 | 
			
		|||
 | 
			
		||||
#include <pulsecore/log.h>
 | 
			
		||||
#include <pulsecore/macro.h>
 | 
			
		||||
#include <pulsecore/core.h>
 | 
			
		||||
#include <pulsecore/core-util.h>
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_SYS_RESOURCE_H
 | 
			
		||||
| 
						 | 
				
			
			@ -75,6 +76,7 @@ typedef struct pa_daemon_conf {
 | 
			
		|||
        log_time,
 | 
			
		||||
        flat_volumes,
 | 
			
		||||
        lock_memory;
 | 
			
		||||
    pa_server_type_t local_server_type;
 | 
			
		||||
    int exit_idle_time,
 | 
			
		||||
        scache_idle_time,
 | 
			
		||||
        auto_log_target,
 | 
			
		||||
| 
						 | 
				
			
			@ -152,6 +154,7 @@ int pa_daemon_conf_env(pa_daemon_conf *c);
 | 
			
		|||
int pa_daemon_conf_set_log_target(pa_daemon_conf *c, const char *string);
 | 
			
		||||
int pa_daemon_conf_set_log_level(pa_daemon_conf *c, const char *string);
 | 
			
		||||
int pa_daemon_conf_set_resample_method(pa_daemon_conf *c, const char *string);
 | 
			
		||||
int pa_daemon_conf_set_local_server_type(pa_daemon_conf *c, const char *string);
 | 
			
		||||
 | 
			
		||||
const char *pa_daemon_conf_get_default_script_file(pa_daemon_conf *c);
 | 
			
		||||
FILE *pa_daemon_conf_open_default_script_file(pa_daemon_conf *c);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,6 +25,7 @@
 | 
			
		|||
; allow-exit = yes
 | 
			
		||||
; use-pid-file = yes
 | 
			
		||||
; system-instance = no
 | 
			
		||||
; local-server-type = user
 | 
			
		||||
; enable-shm = yes
 | 
			
		||||
; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB
 | 
			
		||||
; lock-memory = no
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,6 +66,9 @@ load-module module-bluetooth-discover
 | 
			
		|||
.ifexists module-esound-protocol-unix@PA_SOEXT@
 | 
			
		||||
load-module module-esound-protocol-unix
 | 
			
		||||
.endif
 | 
			
		||||
.ifexists module-dbus-protocol@PA_SOEXT@
 | 
			
		||||
load-module module-dbus-protocol
 | 
			
		||||
.endif
 | 
			
		||||
load-module module-native-protocol-unix
 | 
			
		||||
 | 
			
		||||
### Network access (may be configured with paprefs, so leave this commented
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -102,6 +102,7 @@
 | 
			
		|||
#include "dumpmodules.h"
 | 
			
		||||
#include "caps.h"
 | 
			
		||||
#include "ltdl-bind-now.h"
 | 
			
		||||
#include "server-lookup.h"
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_LIBWRAP
 | 
			
		||||
/* Only one instance of these variables */
 | 
			
		||||
| 
						 | 
				
			
			@ -343,33 +344,31 @@ static void set_all_rlimits(const pa_daemon_conf *conf) {
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DBUS
 | 
			
		||||
static pa_dbus_connection *register_dbus(pa_core *c) {
 | 
			
		||||
static pa_dbus_connection *register_dbus_name(pa_core *c, DBusBusType bus, const char* name) {
 | 
			
		||||
    DBusError error;
 | 
			
		||||
    pa_dbus_connection *conn;
 | 
			
		||||
 | 
			
		||||
    dbus_error_init(&error);
 | 
			
		||||
 | 
			
		||||
    if (!(conn = pa_dbus_bus_get(c, pa_in_system_mode() ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) {
 | 
			
		||||
    if (!(conn = pa_dbus_bus_get(c, bus, &error)) || dbus_error_is_set(&error)) {
 | 
			
		||||
        pa_log_warn("Unable to contact D-Bus: %s: %s", error.name, error.message);
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (dbus_bus_request_name(pa_dbus_connection_get(conn), "org.pulseaudio.Server", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
 | 
			
		||||
        pa_log_debug("Got org.pulseaudio.Server!");
 | 
			
		||||
    if (dbus_bus_request_name(pa_dbus_connection_get(conn), name, DBUS_NAME_FLAG_DO_NOT_QUEUE, &error) == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
 | 
			
		||||
        pa_log_debug("Got %s!", name);
 | 
			
		||||
        return conn;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (dbus_error_is_set(&error))
 | 
			
		||||
        pa_log_warn("Failed to acquire org.pulseaudio.Server: %s: %s", error.name, error.message);
 | 
			
		||||
        pa_log_error("Failed to acquire %s: %s: %s", name, error.name, error.message);
 | 
			
		||||
    else
 | 
			
		||||
        pa_log_warn("D-Bus name org.pulseaudio.Server already taken. Weird shit!");
 | 
			
		||||
        pa_log_error("D-Bus name %s already taken. Weird shit!", name);
 | 
			
		||||
 | 
			
		||||
    /* PA cannot be started twice by the same user and hence we can
 | 
			
		||||
     * ignore mostly the case that org.pulseaudio.Server is already
 | 
			
		||||
     * taken. */
 | 
			
		||||
     * ignore mostly the case that a name is already taken. */
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
 | 
			
		||||
    if (conn)
 | 
			
		||||
        pa_dbus_connection_unref(conn);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -399,7 +398,10 @@ int main(int argc, char *argv[]) {
 | 
			
		|||
    int autospawn_fd = -1;
 | 
			
		||||
    pa_bool_t autospawn_locked = FALSE;
 | 
			
		||||
#ifdef HAVE_DBUS
 | 
			
		||||
    pa_dbus_connection *dbus = NULL;
 | 
			
		||||
    pa_dbusobj_server_lookup *server_lookup = NULL; /* /org/pulseaudio/server_lookup */
 | 
			
		||||
    pa_dbus_connection *lookup_service_bus = NULL; /* Always the user bus. */
 | 
			
		||||
    pa_dbus_connection *server_bus = NULL; /* The bus where we reserve org.pulseaudio.Server, either the user or the system bus. */
 | 
			
		||||
    pa_bool_t start_server;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    pa_log_set_ident("pulseaudio");
 | 
			
		||||
| 
						 | 
				
			
			@ -483,6 +485,32 @@ int main(int argc, char *argv[]) {
 | 
			
		|||
        pa_log_set_flags(PA_LOG_PRINT_TIME, PA_LOG_SET);
 | 
			
		||||
    pa_log_set_show_backtrace(conf->log_backtrace);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DBUS
 | 
			
		||||
    /* conf->system_instance and conf->local_server_type control almost the
 | 
			
		||||
     * same thing; make them agree about what is requested. */
 | 
			
		||||
    switch (conf->local_server_type) {
 | 
			
		||||
        case PA_SERVER_TYPE_UNSET:
 | 
			
		||||
            conf->local_server_type = conf->system_instance ? PA_SERVER_TYPE_SYSTEM : PA_SERVER_TYPE_USER;
 | 
			
		||||
            break;
 | 
			
		||||
        case PA_SERVER_TYPE_USER:
 | 
			
		||||
        case PA_SERVER_TYPE_NONE:
 | 
			
		||||
            conf->system_instance = FALSE;
 | 
			
		||||
            break;
 | 
			
		||||
        case PA_SERVER_TYPE_SYSTEM:
 | 
			
		||||
            conf->system_instance = TRUE;
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            pa_assert_not_reached();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    start_server = conf->local_server_type == PA_SERVER_TYPE_USER || (getuid() == 0 && conf->local_server_type == PA_SERVER_TYPE_SYSTEM);
 | 
			
		||||
 | 
			
		||||
    if (!start_server && conf->local_server_type == PA_SERVER_TYPE_SYSTEM) {
 | 
			
		||||
        pa_log_notice(_("System mode refused for non-root user. Only starting the D-Bus server lookup service."));
 | 
			
		||||
        conf->system_instance = FALSE;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    LTDL_SET_PRELOADED_SYMBOLS();
 | 
			
		||||
    pa_ltdl_init();
 | 
			
		||||
    ltdl_init = TRUE;
 | 
			
		||||
| 
						 | 
				
			
			@ -569,10 +597,12 @@ int main(int argc, char *argv[]) {
 | 
			
		|||
 | 
			
		||||
    if (getuid() == 0 && !conf->system_instance)
 | 
			
		||||
        pa_log_warn(_("This program is not intended to be run as root (unless --system is specified)."));
 | 
			
		||||
#ifndef HAVE_DBUS /* A similar, only a notice worthy check was done earlier, if D-Bus is enabled. */
 | 
			
		||||
    else if (getuid() != 0 && conf->system_instance) {
 | 
			
		||||
        pa_log(_("Root privileges required."));
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    if (conf->cmd == PA_CMD_START && conf->system_instance) {
 | 
			
		||||
        pa_log(_("--start not supported for system instances."));
 | 
			
		||||
| 
						 | 
				
			
			@ -859,6 +889,9 @@ int main(int argc, char *argv[]) {
 | 
			
		|||
    c->running_as_daemon = !!conf->daemonize;
 | 
			
		||||
    c->disallow_exit = conf->disallow_exit;
 | 
			
		||||
    c->flat_volumes = conf->flat_volumes;
 | 
			
		||||
#ifdef HAVE_DBUS
 | 
			
		||||
    c->server_type = conf->local_server_type;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(pa_signal_init(pa_mainloop_get_api(mainloop)) == 0);
 | 
			
		||||
    pa_signal_new(SIGINT, signal_callback, c);
 | 
			
		||||
| 
						 | 
				
			
			@ -881,6 +914,10 @@ int main(int argc, char *argv[]) {
 | 
			
		|||
        pa_assert_se(pa_cpu_limit_init(pa_mainloop_get_api(mainloop)) == 0);
 | 
			
		||||
 | 
			
		||||
    buf = pa_strbuf_new();
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DBUS
 | 
			
		||||
    if (start_server) {
 | 
			
		||||
#endif
 | 
			
		||||
        if (conf->load_default_script_file) {
 | 
			
		||||
            FILE *f;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -896,10 +933,6 @@ int main(int argc, char *argv[]) {
 | 
			
		|||
        pa_log_error("%s", s = pa_strbuf_tostring_free(buf));
 | 
			
		||||
        pa_xfree(s);
 | 
			
		||||
 | 
			
		||||
    /* We completed the initial module loading, so let's disable it
 | 
			
		||||
     * from now on, if requested */
 | 
			
		||||
    c->disallow_module_loading = !!conf->disallow_module_loading;
 | 
			
		||||
 | 
			
		||||
        if (r < 0 && conf->fail) {
 | 
			
		||||
            pa_log(_("Failed to initialize daemon."));
 | 
			
		||||
            goto finish;
 | 
			
		||||
| 
						 | 
				
			
			@ -909,6 +942,19 @@ int main(int argc, char *argv[]) {
 | 
			
		|||
            pa_log(_("Daemon startup without any loaded modules, refusing to work."));
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
#ifdef HAVE_DBUS
 | 
			
		||||
    } else {
 | 
			
		||||
        /* When we just provide the D-Bus server lookup service, we don't want
 | 
			
		||||
         * any modules to be loaded. We haven't loaded any so far, so one might
 | 
			
		||||
         * think there's no way to contact the server, but receiving certain
 | 
			
		||||
         * signals could still cause modules to load. */
 | 
			
		||||
        conf->disallow_module_loading = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    /* We completed the initial module loading, so let's disable it
 | 
			
		||||
     * from now on, if requested */
 | 
			
		||||
    c->disallow_module_loading = !!conf->disallow_module_loading;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_FORK
 | 
			
		||||
    if (daemon_pipe[1] >= 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -920,7 +966,15 @@ int main(int argc, char *argv[]) {
 | 
			
		|||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_DBUS
 | 
			
		||||
    dbus = register_dbus(c);
 | 
			
		||||
    if (!conf->system_instance) {
 | 
			
		||||
        if (!(server_lookup = pa_dbusobj_server_lookup_new(c)))
 | 
			
		||||
            goto finish;
 | 
			
		||||
        if (!(lookup_service_bus = register_dbus_name(c, DBUS_BUS_SESSION, "org.PulseAudio1")))
 | 
			
		||||
            goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (start_server && !(server_bus = register_dbus_name(c, conf->system_instance ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, "org.pulseaudio.Server")))
 | 
			
		||||
        goto finish;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    pa_log_info(_("Daemon startup complete."));
 | 
			
		||||
| 
						 | 
				
			
			@ -933,8 +987,12 @@ int main(int argc, char *argv[]) {
 | 
			
		|||
 | 
			
		||||
finish:
 | 
			
		||||
#ifdef HAVE_DBUS
 | 
			
		||||
    if (dbus)
 | 
			
		||||
        pa_dbus_connection_unref(dbus);
 | 
			
		||||
    if (server_bus)
 | 
			
		||||
        pa_dbus_connection_unref(server_bus);
 | 
			
		||||
    if (lookup_service_bus)
 | 
			
		||||
        pa_dbus_connection_unref(lookup_service_bus);
 | 
			
		||||
    if (server_lookup)
 | 
			
		||||
        pa_dbusobj_server_lookup_free(server_lookup);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    if (autospawn_fd >= 0) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										522
									
								
								src/daemon/server-lookup.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										522
									
								
								src/daemon/server-lookup.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,522 @@
 | 
			
		|||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#include <config.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <dbus/dbus.h>
 | 
			
		||||
 | 
			
		||||
#include <pulse/client-conf.h>
 | 
			
		||||
#include <pulse/xmalloc.h>
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/core.h>
 | 
			
		||||
#include <pulsecore/core-util.h>
 | 
			
		||||
#include <pulsecore/dbus-shared.h>
 | 
			
		||||
#include <pulsecore/macro.h>
 | 
			
		||||
#include <pulsecore/protocol-dbus.h>
 | 
			
		||||
 | 
			
		||||
#include "server-lookup.h"
 | 
			
		||||
 | 
			
		||||
#define OBJECT_PATH "/org/pulseaudio/server_lookup1"
 | 
			
		||||
#define INTERFACE "org.PulseAudio.ServerLookup1"
 | 
			
		||||
 | 
			
		||||
struct pa_dbusobj_server_lookup {
 | 
			
		||||
    pa_core *core;
 | 
			
		||||
    pa_dbus_connection *conn;
 | 
			
		||||
    pa_bool_t path_registered;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const char introspection[] =
 | 
			
		||||
    DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
 | 
			
		||||
    "<node>"
 | 
			
		||||
    " <!-- If you are looking for documentation make sure to check out\n"
 | 
			
		||||
    "      http://pulseaudio.org/wiki/DBusInterface -->\n"
 | 
			
		||||
    " <interface name=\"" INTERFACE "\">\n"
 | 
			
		||||
    "  <property name=\"Address\" type=\"s\" access=\"read\"/>\n"
 | 
			
		||||
    " </interface>\n"
 | 
			
		||||
    " <interface name=\"" DBUS_INTERFACE_INTROSPECTABLE "\">\n"
 | 
			
		||||
    "  <method name=\"Introspect\">\n"
 | 
			
		||||
    "   <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
 | 
			
		||||
    "  </method>\n"
 | 
			
		||||
    " </interface>\n"
 | 
			
		||||
    " <interface name=\"" DBUS_INTERFACE_PROPERTIES "\">\n"
 | 
			
		||||
    "  <method name=\"Get\">\n"
 | 
			
		||||
    "   <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"value\" type=\"v\" direction=\"out\"/>\n"
 | 
			
		||||
    "  </method>\n"
 | 
			
		||||
    "  <method name=\"Set\">\n"
 | 
			
		||||
    "   <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"value\" type=\"v\" direction=\"in\"/>\n"
 | 
			
		||||
    "  </method>\n"
 | 
			
		||||
    "  <method name=\"GetAll\">\n"
 | 
			
		||||
    "   <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"props\" type=\"a{sv}\" direction=\"out\"/>\n"
 | 
			
		||||
    "  </method>\n"
 | 
			
		||||
    " </interface>\n"
 | 
			
		||||
    "</node>\n";
 | 
			
		||||
 | 
			
		||||
static void unregister_cb(DBusConnection *conn, void *user_data) {
 | 
			
		||||
    pa_dbusobj_server_lookup *sl = user_data;
 | 
			
		||||
 | 
			
		||||
    pa_assert(sl);
 | 
			
		||||
    pa_assert(sl->path_registered);
 | 
			
		||||
 | 
			
		||||
    sl->path_registered = FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_server_lookup *sl) {
 | 
			
		||||
    DBusHandlerResult r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
    const char *i = introspection;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
 | 
			
		||||
    if (!(reply = dbus_message_new_method_return(msg))) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &i, DBUS_TYPE_INVALID)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
finish:
 | 
			
		||||
    if (reply)
 | 
			
		||||
        dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum get_address_result_t {
 | 
			
		||||
    SUCCESS,
 | 
			
		||||
    FAILED_TO_LOAD_CLIENT_CONF,
 | 
			
		||||
    SERVER_FROM_TYPE_FAILED
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Caller frees the returned address. */
 | 
			
		||||
static enum get_address_result_t get_address(pa_server_type_t server_type, char **address) {
 | 
			
		||||
    enum get_address_result_t r = SUCCESS;
 | 
			
		||||
    pa_client_conf *conf = pa_client_conf_new();
 | 
			
		||||
 | 
			
		||||
    *address = NULL;
 | 
			
		||||
 | 
			
		||||
    if (pa_client_conf_load(conf, NULL) < 0) {
 | 
			
		||||
        r = FAILED_TO_LOAD_CLIENT_CONF;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (conf->default_dbus_server)
 | 
			
		||||
        *address = pa_xstrdup(conf->default_dbus_server);
 | 
			
		||||
    else if (!(*address = pa_get_dbus_address_from_server_type(server_type))) {
 | 
			
		||||
        r = SERVER_FROM_TYPE_FAILED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
finish:
 | 
			
		||||
    pa_client_conf_free(conf);
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DBusHandlerResult handle_get_address(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_server_lookup *sl) {
 | 
			
		||||
    DBusHandlerResult r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
    char *address = NULL;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
    DBusMessageIter variant_iter;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(sl);
 | 
			
		||||
 | 
			
		||||
    switch (get_address(sl->core->server_type, &address)) {
 | 
			
		||||
        case SUCCESS:
 | 
			
		||||
            if (!(reply = dbus_message_new_method_return(msg))) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            dbus_message_iter_init_append(reply, &msg_iter);
 | 
			
		||||
            if (!dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_VARIANT, "s", &variant_iter)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_message_iter_append_basic(&variant_iter, DBUS_TYPE_STRING, &address)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_message_iter_close_container(&msg_iter, &variant_iter)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
 | 
			
		||||
        case FAILED_TO_LOAD_CLIENT_CONF:
 | 
			
		||||
            if (!(reply = dbus_message_new_error(msg, "org.pulseaudio.ClientConfLoadError", "Failed to load client.conf."))) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
 | 
			
		||||
        case SERVER_FROM_TYPE_FAILED:
 | 
			
		||||
            if (!(reply = dbus_message_new_error(msg, DBUS_ERROR_FAILED, "PulseAudio internal error: get_dbus_server_from_type() failed."))) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            pa_assert_not_reached();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
finish:
 | 
			
		||||
    pa_xfree(address);
 | 
			
		||||
    if (reply)
 | 
			
		||||
        dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DBusHandlerResult handle_get(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_server_lookup *sl) {
 | 
			
		||||
    DBusHandlerResult r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
    const char* interface;
 | 
			
		||||
    const char* property;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(sl);
 | 
			
		||||
 | 
			
		||||
    if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID)) {
 | 
			
		||||
        if (!(reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, "Invalid arguments"))) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (*interface && !pa_streq(interface, INTERFACE)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!pa_streq(property, "Address")) {
 | 
			
		||||
        if (!(reply = dbus_message_new_error_printf(msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s: No such property", property))) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    r = handle_get_address(conn, msg, sl);
 | 
			
		||||
 | 
			
		||||
finish:
 | 
			
		||||
    if (reply)
 | 
			
		||||
        dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DBusHandlerResult handle_set(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_server_lookup *sl) {
 | 
			
		||||
    DBusHandlerResult r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
    const char* interface;
 | 
			
		||||
    const char* property;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(sl);
 | 
			
		||||
 | 
			
		||||
    if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID)) {
 | 
			
		||||
        if (!(reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, "Invalid arguments"))) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (*interface && !pa_streq(interface, INTERFACE)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!pa_streq(property, "Address")) {
 | 
			
		||||
        if (!(reply = dbus_message_new_error_printf(msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s: No such property", property))) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!(reply = dbus_message_new_error_printf(msg, DBUS_ERROR_ACCESS_DENIED, "%s: Property not settable", property))) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
 | 
			
		||||
finish:
 | 
			
		||||
    if (reply)
 | 
			
		||||
        dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DBusHandlerResult handle_get_all(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_server_lookup *sl) {
 | 
			
		||||
    DBusHandlerResult r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
    const char *property = "Address";
 | 
			
		||||
    char *interface = NULL;
 | 
			
		||||
    char *address = NULL;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
    DBusMessageIter dict_iter;
 | 
			
		||||
    DBusMessageIter dict_entry_iter;
 | 
			
		||||
    DBusMessageIter variant_iter;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(sl);
 | 
			
		||||
 | 
			
		||||
    if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID)) {
 | 
			
		||||
        if (!(reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, "Invalid arguments"))) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (get_address(sl->core->server_type, &address)) {
 | 
			
		||||
        case SUCCESS:
 | 
			
		||||
            if (!(reply = dbus_message_new_method_return(msg))) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            dbus_message_iter_init_append(reply, &msg_iter);
 | 
			
		||||
            if (!dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &property)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_message_iter_open_container(&dict_entry_iter, DBUS_TYPE_VARIANT, "s", &variant_iter)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_message_iter_append_basic(&variant_iter, DBUS_TYPE_STRING, &address)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_message_iter_close_container(&dict_entry_iter, &variant_iter)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_message_iter_close_container(&dict_iter, &dict_entry_iter)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_message_iter_close_container(&msg_iter, &dict_iter)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
 | 
			
		||||
        case FAILED_TO_LOAD_CLIENT_CONF:
 | 
			
		||||
            if (!(reply = dbus_message_new_error(msg, "org.pulseaudio.ClientConfLoadError", "Failed to load client.conf."))) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
 | 
			
		||||
        case SERVER_FROM_TYPE_FAILED:
 | 
			
		||||
            if (!(reply = dbus_message_new_error(msg, DBUS_ERROR_FAILED, "PulseAudio internal error: get_dbus_server_from_type() failed."))) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            pa_assert_not_reached();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
finish:
 | 
			
		||||
    pa_xfree(address);
 | 
			
		||||
    if (reply)
 | 
			
		||||
        dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DBusHandlerResult message_cb(DBusConnection *conn, DBusMessage *msg, void *user_data) {
 | 
			
		||||
    pa_dbusobj_server_lookup *sl = user_data;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(sl);
 | 
			
		||||
 | 
			
		||||
    /* pa_log("Got message! type = %s   path = %s   iface = %s   member = %s   dest = %s", dbus_message_type_to_string(dbus_message_get_type(msg)), dbus_message_get_path(msg), dbus_message_get_interface(msg), dbus_message_get_member(msg), dbus_message_get_destination(msg)); */
 | 
			
		||||
 | 
			
		||||
    if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_METHOD_CALL)
 | 
			
		||||
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
 | 
			
		||||
    if (dbus_message_is_method_call(msg, DBUS_INTERFACE_INTROSPECTABLE, "Introspect") ||
 | 
			
		||||
        (!dbus_message_get_interface(msg) && dbus_message_has_member(msg, "Introspect")))
 | 
			
		||||
        return handle_introspect(conn, msg, sl);
 | 
			
		||||
 | 
			
		||||
    if (dbus_message_is_method_call(msg, DBUS_INTERFACE_PROPERTIES, "Get") ||
 | 
			
		||||
        (!dbus_message_get_interface(msg) && dbus_message_has_member(msg, "Get")))
 | 
			
		||||
        return handle_get(conn, msg, sl);
 | 
			
		||||
 | 
			
		||||
    if (dbus_message_is_method_call(msg, DBUS_INTERFACE_PROPERTIES, "Set") ||
 | 
			
		||||
        (!dbus_message_get_interface(msg) && dbus_message_has_member(msg, "Set")))
 | 
			
		||||
        return handle_set(conn, msg, sl);
 | 
			
		||||
 | 
			
		||||
    if (dbus_message_is_method_call(msg, DBUS_INTERFACE_PROPERTIES, "GetAll") ||
 | 
			
		||||
        (!dbus_message_get_interface(msg) && dbus_message_has_member(msg, "GetAll")))
 | 
			
		||||
        return handle_get_all(conn, msg, sl);
 | 
			
		||||
 | 
			
		||||
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DBusObjectPathVTable vtable = {
 | 
			
		||||
    .unregister_function = unregister_cb,
 | 
			
		||||
    .message_function = message_cb,
 | 
			
		||||
    .dbus_internal_pad1 = NULL,
 | 
			
		||||
    .dbus_internal_pad2 = NULL,
 | 
			
		||||
    .dbus_internal_pad3 = NULL,
 | 
			
		||||
    .dbus_internal_pad4 = NULL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pa_dbusobj_server_lookup *pa_dbusobj_server_lookup_new(pa_core *c) {
 | 
			
		||||
    pa_dbusobj_server_lookup *sl;
 | 
			
		||||
    DBusError error;
 | 
			
		||||
 | 
			
		||||
    dbus_error_init(&error);
 | 
			
		||||
 | 
			
		||||
    sl = pa_xnew(pa_dbusobj_server_lookup, 1);
 | 
			
		||||
    sl->core = c;
 | 
			
		||||
    sl->path_registered = FALSE;
 | 
			
		||||
 | 
			
		||||
    if (!(sl->conn = pa_dbus_bus_get(c, DBUS_BUS_SESSION, &error)) || dbus_error_is_set(&error)) {
 | 
			
		||||
        pa_log("Unable to contact D-Bus: %s: %s", error.name, error.message);
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!dbus_connection_register_object_path(pa_dbus_connection_get(sl->conn), OBJECT_PATH, &vtable, sl)) {
 | 
			
		||||
        pa_log("dbus_connection_register_object_path() failed for " OBJECT_PATH ".");
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sl->path_registered = TRUE;
 | 
			
		||||
 | 
			
		||||
    return sl;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
    dbus_error_free(&error);
 | 
			
		||||
 | 
			
		||||
    pa_dbusobj_server_lookup_free(sl);
 | 
			
		||||
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbusobj_server_lookup_free(pa_dbusobj_server_lookup *sl) {
 | 
			
		||||
    pa_assert(sl);
 | 
			
		||||
 | 
			
		||||
    if (sl->path_registered) {
 | 
			
		||||
        pa_assert(sl->conn);
 | 
			
		||||
        if (!dbus_connection_unregister_object_path(pa_dbus_connection_get(sl->conn), OBJECT_PATH))
 | 
			
		||||
            pa_log_debug("dbus_connection_unregister_object_path() failed for " OBJECT_PATH ".");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (sl->conn)
 | 
			
		||||
        pa_dbus_connection_unref(sl->conn);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(sl);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								src/daemon/server-lookup.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/daemon/server-lookup.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,40 @@
 | 
			
		|||
#ifndef fooserverlookuphfoo
 | 
			
		||||
#define fooserverlookuphfoo
 | 
			
		||||
 | 
			
		||||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
/* This object implements the D-Bus object at path
 | 
			
		||||
 * /org/pulseaudio/server_lookup. Implemented interfaces
 | 
			
		||||
 * are org.pulseaudio.ServerLookup and org.freedesktop.DBus.Introspectable.
 | 
			
		||||
 *
 | 
			
		||||
 * See http://pulseaudio.org/wiki/DBusInterface for the ServerLookup interface
 | 
			
		||||
 * documentation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/core.h>
 | 
			
		||||
 | 
			
		||||
typedef struct pa_dbusobj_server_lookup pa_dbusobj_server_lookup;
 | 
			
		||||
 | 
			
		||||
pa_dbusobj_server_lookup *pa_dbusobj_server_lookup_new(pa_core *c);
 | 
			
		||||
void pa_dbusobj_server_lookup_free(pa_dbusobj_server_lookup *sl);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -32,6 +32,10 @@ load-module module-detect
 | 
			
		|||
.ifexists module-esound-protocol-unix@PA_SOEXT@
 | 
			
		||||
load-module module-esound-protocol-unix
 | 
			
		||||
.endif
 | 
			
		||||
.ifexists module-dbus-protocol@PA_SOEXT@
 | 
			
		||||
### If you want to allow TCP connections, set access to "remote" or "local,remote".
 | 
			
		||||
load-module module-dbus-protocol access=local
 | 
			
		||||
.endif
 | 
			
		||||
load-module module-native-protocol-unix
 | 
			
		||||
 | 
			
		||||
### Automatically restore the volume of streams and devices
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -185,6 +185,7 @@ pa_path_get_filename;
 | 
			
		|||
pa_proplist_clear;
 | 
			
		||||
pa_proplist_contains;
 | 
			
		||||
pa_proplist_copy;
 | 
			
		||||
pa_proplist_equal;
 | 
			
		||||
pa_proplist_free;
 | 
			
		||||
pa_proplist_from_string;
 | 
			
		||||
pa_proplist_get;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										228
									
								
								src/modules/dbus/iface-card-profile.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								src/modules/dbus/iface-card-profile.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,228 @@
 | 
			
		|||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#include <config.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <dbus/dbus.h>
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/core-util.h>
 | 
			
		||||
#include <pulsecore/dbus-util.h>
 | 
			
		||||
 | 
			
		||||
#include "iface-card-profile.h"
 | 
			
		||||
 | 
			
		||||
#define OBJECT_NAME "profile"
 | 
			
		||||
 | 
			
		||||
static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_description(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_sinks(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_sources(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_priority(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
struct pa_dbusiface_card_profile {
 | 
			
		||||
    uint32_t index;
 | 
			
		||||
    pa_card_profile *profile;
 | 
			
		||||
    char *path;
 | 
			
		||||
    pa_dbus_protocol *dbus_protocol;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum property_handler_index {
 | 
			
		||||
    PROPERTY_HANDLER_INDEX,
 | 
			
		||||
    PROPERTY_HANDLER_NAME,
 | 
			
		||||
    PROPERTY_HANDLER_DESCRIPTION,
 | 
			
		||||
    PROPERTY_HANDLER_SINKS,
 | 
			
		||||
    PROPERTY_HANDLER_SOURCES,
 | 
			
		||||
    PROPERTY_HANDLER_PRIORITY,
 | 
			
		||||
    PROPERTY_HANDLER_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = {
 | 
			
		||||
    [PROPERTY_HANDLER_INDEX]       = { .property_name = "Index",       .type = "u", .get_cb = handle_get_index,       .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_NAME]        = { .property_name = "Name",        .type = "s", .get_cb = handle_get_name,        .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_DESCRIPTION] = { .property_name = "Description", .type = "s", .get_cb = handle_get_description, .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_SINKS]       = { .property_name = "Sinks",       .type = "u", .get_cb = handle_get_sinks,       .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_SOURCES]     = { .property_name = "Sources",     .type = "u", .get_cb = handle_get_sources,     .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_PRIORITY]    = { .property_name = "Priority",    .type = "u", .get_cb = handle_get_priority,    .set_cb = NULL },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_interface_info profile_interface_info = {
 | 
			
		||||
    .name = PA_DBUSIFACE_CARD_PROFILE_INTERFACE,
 | 
			
		||||
    .method_handlers = NULL,
 | 
			
		||||
    .n_method_handlers = 0,
 | 
			
		||||
    .property_handlers = property_handlers,
 | 
			
		||||
    .n_property_handlers = PROPERTY_HANDLER_MAX,
 | 
			
		||||
    .get_all_properties_cb = handle_get_all,
 | 
			
		||||
    .signals = NULL,
 | 
			
		||||
    .n_signals = 0
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_card_profile *p = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(p);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &p->index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_card_profile *p = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(p);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &p->profile->name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_description(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_card_profile *p = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(p);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &p->profile->description);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_sinks(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_card_profile *p = userdata;
 | 
			
		||||
    dbus_uint32_t sinks = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(p);
 | 
			
		||||
 | 
			
		||||
    sinks = p->profile->n_sinks;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &sinks);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_sources(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_card_profile *p = userdata;
 | 
			
		||||
    dbus_uint32_t sources = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(p);
 | 
			
		||||
 | 
			
		||||
    sources = p->profile->n_sources;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &sources);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_priority(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_card_profile *p = userdata;
 | 
			
		||||
    dbus_uint32_t priority = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(p);
 | 
			
		||||
 | 
			
		||||
    priority = p->profile->priority;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &priority);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_card_profile *p = userdata;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
    DBusMessageIter dict_iter;
 | 
			
		||||
    dbus_uint32_t sinks = 0;
 | 
			
		||||
    dbus_uint32_t sources = 0;
 | 
			
		||||
    dbus_uint32_t priority = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(p);
 | 
			
		||||
 | 
			
		||||
    sinks = p->profile->n_sinks;
 | 
			
		||||
    sources = p->profile->n_sources;
 | 
			
		||||
    priority = p->profile->priority;
 | 
			
		||||
 | 
			
		||||
    pa_assert_se((reply = dbus_message_new_method_return(msg)));
 | 
			
		||||
 | 
			
		||||
    dbus_message_iter_init_append(reply, &msg_iter);
 | 
			
		||||
    pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
 | 
			
		||||
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &p->index);
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_NAME].property_name, DBUS_TYPE_STRING, &p->profile->name);
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DESCRIPTION].property_name, DBUS_TYPE_STRING, &p->profile->description);
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SINKS].property_name, DBUS_TYPE_UINT32, &sinks);
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SOURCES].property_name, DBUS_TYPE_UINT32, &sources);
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PRIORITY].property_name, DBUS_TYPE_UINT32, &priority);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_connection_send(conn, reply, NULL));
 | 
			
		||||
    dbus_message_unref(reply);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pa_dbusiface_card_profile *pa_dbusiface_card_profile_new(
 | 
			
		||||
        pa_dbusiface_card *card,
 | 
			
		||||
        pa_core *core,
 | 
			
		||||
        pa_card_profile *profile,
 | 
			
		||||
        uint32_t idx) {
 | 
			
		||||
    pa_dbusiface_card_profile *p = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(card);
 | 
			
		||||
    pa_assert(core);
 | 
			
		||||
    pa_assert(profile);
 | 
			
		||||
 | 
			
		||||
    p = pa_xnew(pa_dbusiface_card_profile, 1);
 | 
			
		||||
    p->index = idx;
 | 
			
		||||
    p->profile = profile;
 | 
			
		||||
    p->path = pa_sprintf_malloc("%s/%s%u", pa_dbusiface_card_get_path(card), OBJECT_NAME, idx);
 | 
			
		||||
    p->dbus_protocol = pa_dbus_protocol_get(core);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(pa_dbus_protocol_add_interface(p->dbus_protocol, p->path, &profile_interface_info, p) >= 0);
 | 
			
		||||
 | 
			
		||||
    return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbusiface_card_profile_free(pa_dbusiface_card_profile *p) {
 | 
			
		||||
    pa_assert(p);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(pa_dbus_protocol_remove_interface(p->dbus_protocol, p->path, profile_interface_info.name) >= 0);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_protocol_unref(p->dbus_protocol);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(p->path);
 | 
			
		||||
    pa_xfree(p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *pa_dbusiface_card_profile_get_path(pa_dbusiface_card_profile *p) {
 | 
			
		||||
    pa_assert(p);
 | 
			
		||||
 | 
			
		||||
    return p->path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *pa_dbusiface_card_profile_get_name(pa_dbusiface_card_profile *p) {
 | 
			
		||||
    pa_assert(p);
 | 
			
		||||
 | 
			
		||||
    return p->profile->name;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								src/modules/dbus/iface-card-profile.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/modules/dbus/iface-card-profile.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
#ifndef foodbusifacecardprofilehfoo
 | 
			
		||||
#define foodbusifacecardprofilehfoo
 | 
			
		||||
 | 
			
		||||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
/* This object implements the D-Bus interface org.PulseAudio.Core1.CardProfile.
 | 
			
		||||
 *
 | 
			
		||||
 * See http://pulseaudio.org/wiki/DBusInterface for the CardProfile interface
 | 
			
		||||
 * documentation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/core-scache.h>
 | 
			
		||||
#include <pulsecore/protocol-dbus.h>
 | 
			
		||||
 | 
			
		||||
#include "iface-card.h"
 | 
			
		||||
 | 
			
		||||
#define PA_DBUSIFACE_CARD_PROFILE_INTERFACE PA_DBUS_CORE_INTERFACE ".CardProfile"
 | 
			
		||||
 | 
			
		||||
typedef struct pa_dbusiface_card_profile pa_dbusiface_card_profile;
 | 
			
		||||
 | 
			
		||||
pa_dbusiface_card_profile *pa_dbusiface_card_profile_new(
 | 
			
		||||
        pa_dbusiface_card *card,
 | 
			
		||||
        pa_core *core,
 | 
			
		||||
        pa_card_profile *profile,
 | 
			
		||||
        uint32_t idx);
 | 
			
		||||
void pa_dbusiface_card_profile_free(pa_dbusiface_card_profile *p);
 | 
			
		||||
 | 
			
		||||
const char *pa_dbusiface_card_profile_get_path(pa_dbusiface_card_profile *p);
 | 
			
		||||
const char *pa_dbusiface_card_profile_get_name(pa_dbusiface_card_profile *p);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										561
									
								
								src/modules/dbus/iface-card.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										561
									
								
								src/modules/dbus/iface-card.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,561 @@
 | 
			
		|||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#include <config.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <dbus/dbus.h>
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/core-util.h>
 | 
			
		||||
#include <pulsecore/dbus-util.h>
 | 
			
		||||
#include <pulsecore/protocol-dbus.h>
 | 
			
		||||
 | 
			
		||||
#include "iface-card-profile.h"
 | 
			
		||||
 | 
			
		||||
#include "iface-card.h"
 | 
			
		||||
 | 
			
		||||
#define OBJECT_NAME "card"
 | 
			
		||||
 | 
			
		||||
static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_sinks(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_sources(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_profiles(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_active_profile(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_set_active_profile(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
 | 
			
		||||
static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
static void handle_get_profile_by_name(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
struct pa_dbusiface_card {
 | 
			
		||||
    pa_dbusiface_core *core;
 | 
			
		||||
 | 
			
		||||
    pa_card *card;
 | 
			
		||||
    char *path;
 | 
			
		||||
    pa_hashmap *profiles;
 | 
			
		||||
    uint32_t next_profile_index;
 | 
			
		||||
    pa_card_profile *active_profile;
 | 
			
		||||
    pa_proplist *proplist;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_protocol *dbus_protocol;
 | 
			
		||||
    pa_subscription *subscription;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum property_handler_index {
 | 
			
		||||
    PROPERTY_HANDLER_INDEX,
 | 
			
		||||
    PROPERTY_HANDLER_NAME,
 | 
			
		||||
    PROPERTY_HANDLER_DRIVER,
 | 
			
		||||
    PROPERTY_HANDLER_OWNER_MODULE,
 | 
			
		||||
    PROPERTY_HANDLER_SINKS,
 | 
			
		||||
    PROPERTY_HANDLER_SOURCES,
 | 
			
		||||
    PROPERTY_HANDLER_PROFILES,
 | 
			
		||||
    PROPERTY_HANDLER_ACTIVE_PROFILE,
 | 
			
		||||
    PROPERTY_HANDLER_PROPERTY_LIST,
 | 
			
		||||
    PROPERTY_HANDLER_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = {
 | 
			
		||||
    [PROPERTY_HANDLER_INDEX]          = { .property_name = "Index",         .type = "u",      .get_cb = handle_get_index,          .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_NAME]           = { .property_name = "Name",          .type = "s",      .get_cb = handle_get_name,           .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_DRIVER]         = { .property_name = "Driver",        .type = "s",      .get_cb = handle_get_driver,         .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_OWNER_MODULE]   = { .property_name = "OwnerModule",   .type = "o",      .get_cb = handle_get_owner_module,   .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_SINKS]          = { .property_name = "Sinks",         .type = "ao",     .get_cb = handle_get_sinks,          .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_SOURCES]        = { .property_name = "Sources",       .type = "ao",     .get_cb = handle_get_sources,        .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_PROFILES]       = { .property_name = "Profiles",      .type = "ao",     .get_cb = handle_get_profiles,       .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_ACTIVE_PROFILE] = { .property_name = "ActiveProfile", .type = "o",      .get_cb = handle_get_active_profile, .set_cb = handle_set_active_profile },
 | 
			
		||||
    [PROPERTY_HANDLER_PROPERTY_LIST]  = { .property_name = "PropertyList",  .type = "a{say}", .get_cb = handle_get_property_list,  .set_cb = NULL }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum method_handler_index {
 | 
			
		||||
    METHOD_HANDLER_GET_PROFILE_BY_NAME,
 | 
			
		||||
    METHOD_HANDLER_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_arg_info get_profile_by_name_args[] = { { "name", "s", "in" }, { "profile", "o", "out" } };
 | 
			
		||||
 | 
			
		||||
static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
 | 
			
		||||
    [METHOD_HANDLER_GET_PROFILE_BY_NAME] = {
 | 
			
		||||
        .method_name = "GetProfileByName",
 | 
			
		||||
        .arguments = get_profile_by_name_args,
 | 
			
		||||
        .n_arguments = sizeof(get_profile_by_name_args) / sizeof(pa_dbus_arg_info),
 | 
			
		||||
        .receive_cb = handle_get_profile_by_name }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum signal_index {
 | 
			
		||||
    SIGNAL_ACTIVE_PROFILE_UPDATED,
 | 
			
		||||
    SIGNAL_PROPERTY_LIST_UPDATED,
 | 
			
		||||
    SIGNAL_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_arg_info active_profile_updated_args[] = { { "profile",       "o",      NULL } };
 | 
			
		||||
static pa_dbus_arg_info property_list_updated_args[] =  { { "property_list", "a{say}", NULL } };
 | 
			
		||||
 | 
			
		||||
static pa_dbus_signal_info signals[SIGNAL_MAX] = {
 | 
			
		||||
    [SIGNAL_ACTIVE_PROFILE_UPDATED] = { .name = "ActiveProfileUpdated", .arguments = active_profile_updated_args, .n_arguments = 1 },
 | 
			
		||||
    [SIGNAL_PROPERTY_LIST_UPDATED]  = { .name = "PropertyListUpdated",  .arguments = property_list_updated_args,  .n_arguments = 1 }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_interface_info card_interface_info = {
 | 
			
		||||
    .name = PA_DBUSIFACE_CARD_INTERFACE,
 | 
			
		||||
    .method_handlers = method_handlers,
 | 
			
		||||
    .n_method_handlers = METHOD_HANDLER_MAX,
 | 
			
		||||
    .property_handlers = property_handlers,
 | 
			
		||||
    .n_property_handlers = PROPERTY_HANDLER_MAX,
 | 
			
		||||
    .get_all_properties_cb = handle_get_all,
 | 
			
		||||
    .signals = signals,
 | 
			
		||||
    .n_signals = SIGNAL_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_card *c = userdata;
 | 
			
		||||
    dbus_uint32_t idx;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    idx = c->card->index;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &idx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_card *c = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &c->card->name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_card *c = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &c->card->driver);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_card *c = userdata;
 | 
			
		||||
    const char *owner_module;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    if (!c->card->module) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Card %s doesn't have an owner module.", c->card->name);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    owner_module = pa_dbusiface_core_get_module_path(c->core, c->card->module);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &owner_module);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* The caller frees the array, but not the strings. */
 | 
			
		||||
static const char **get_sinks(pa_dbusiface_card *c, unsigned *n) {
 | 
			
		||||
    const char **sinks = NULL;
 | 
			
		||||
    unsigned i = 0;
 | 
			
		||||
    uint32_t idx = 0;
 | 
			
		||||
    pa_sink *sink = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
    pa_assert(n);
 | 
			
		||||
 | 
			
		||||
    *n = pa_idxset_size(c->card->sinks);
 | 
			
		||||
 | 
			
		||||
    if (*n == 0)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    sinks = pa_xnew(const char *, *n);
 | 
			
		||||
 | 
			
		||||
    PA_IDXSET_FOREACH(sink, c->card->sinks, idx) {
 | 
			
		||||
        sinks[i] = pa_dbusiface_core_get_sink_path(c->core, sink);
 | 
			
		||||
        ++i;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return sinks;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_sinks(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_card *c = userdata;
 | 
			
		||||
    const char **sinks;
 | 
			
		||||
    unsigned n_sinks;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    sinks = get_sinks(c, &n_sinks);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, sinks, n_sinks);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(sinks);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* The caller frees the array, but not the strings. */
 | 
			
		||||
static const char **get_sources(pa_dbusiface_card *c, unsigned *n) {
 | 
			
		||||
    const char **sources = NULL;
 | 
			
		||||
    unsigned i = 0;
 | 
			
		||||
    uint32_t idx = 0;
 | 
			
		||||
    pa_source *source = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
    pa_assert(n);
 | 
			
		||||
 | 
			
		||||
    *n = pa_idxset_size(c->card->sources);
 | 
			
		||||
 | 
			
		||||
    if (*n == 0)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    sources = pa_xnew(const char *, *n);
 | 
			
		||||
 | 
			
		||||
    PA_IDXSET_FOREACH(source, c->card->sinks, idx) {
 | 
			
		||||
        sources[i] = pa_dbusiface_core_get_source_path(c->core, source);
 | 
			
		||||
        ++i;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return sources;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_sources(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_card *c = userdata;
 | 
			
		||||
    const char **sources;
 | 
			
		||||
    unsigned n_sources;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    sources = get_sources(c, &n_sources);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, sources, n_sources);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(sources);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* The caller frees the array, but not the strings. */
 | 
			
		||||
static const char **get_profiles(pa_dbusiface_card *c, unsigned *n) {
 | 
			
		||||
    const char **profiles;
 | 
			
		||||
    unsigned i = 0;
 | 
			
		||||
    void *state = NULL;
 | 
			
		||||
    pa_dbusiface_card_profile *profile;
 | 
			
		||||
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
    pa_assert(n);
 | 
			
		||||
 | 
			
		||||
    *n = pa_hashmap_size(c->profiles);
 | 
			
		||||
 | 
			
		||||
    if (*n == 0)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    profiles = pa_xnew(const char *, *n);
 | 
			
		||||
 | 
			
		||||
    PA_HASHMAP_FOREACH(profile, c->profiles, state)
 | 
			
		||||
        profiles[i++] = pa_dbusiface_card_profile_get_path(profile);
 | 
			
		||||
 | 
			
		||||
    return profiles;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_profiles(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_card *c = userdata;
 | 
			
		||||
    const char **profiles;
 | 
			
		||||
    unsigned n_profiles;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    profiles = get_profiles(c, &n_profiles);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, profiles, n_profiles);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(profiles);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_active_profile(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_card *c = userdata;
 | 
			
		||||
    const char *active_profile;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    if (!c->active_profile) {
 | 
			
		||||
        pa_assert(pa_hashmap_isempty(c->profiles));
 | 
			
		||||
 | 
			
		||||
        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
 | 
			
		||||
                           "The card %s has no profiles, and therefore there's no active profile either.", c->card->name);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    active_profile = pa_dbusiface_card_profile_get_path(pa_hashmap_get(c->profiles, c->active_profile->name));
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &active_profile);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_set_active_profile(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
 | 
			
		||||
    pa_dbusiface_card *c = userdata;
 | 
			
		||||
    const char *new_active_path;
 | 
			
		||||
    pa_dbusiface_card_profile *new_active;
 | 
			
		||||
    int r;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(iter);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    if (!c->active_profile) {
 | 
			
		||||
        pa_assert(pa_hashmap_isempty(c->profiles));
 | 
			
		||||
 | 
			
		||||
        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
 | 
			
		||||
                           "The card %s has no profiles, and therefore there's no active profile either.",
 | 
			
		||||
                           c->card->name);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    dbus_message_iter_get_basic(iter, &new_active_path);
 | 
			
		||||
 | 
			
		||||
    if (!(new_active = pa_hashmap_get(c->profiles, new_active_path))) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such profile.", new_active_path);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((r = pa_card_set_profile(c->card, pa_dbusiface_card_profile_get_name(new_active), TRUE)) < 0) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED,
 | 
			
		||||
                           "Internal error in PulseAudio: pa_card_set_profile() failed with error code %i.", r);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_empty_reply(conn, msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_card *c = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_proplist_variant_reply(conn, msg, c->proplist);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_card *c = userdata;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
    DBusMessageIter dict_iter;
 | 
			
		||||
    dbus_uint32_t idx;
 | 
			
		||||
    const char *owner_module = NULL;
 | 
			
		||||
    const char **sinks = NULL;
 | 
			
		||||
    unsigned n_sinks = 0;
 | 
			
		||||
    const char **sources = NULL;
 | 
			
		||||
    unsigned n_sources = 0;
 | 
			
		||||
    const char **profiles = NULL;
 | 
			
		||||
    unsigned n_profiles = 0;
 | 
			
		||||
    const char *active_profile = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    idx = c->card->index;
 | 
			
		||||
    if (c->card->module)
 | 
			
		||||
        owner_module = pa_dbusiface_core_get_module_path(c->core, c->card->module);
 | 
			
		||||
    sinks = get_sinks(c, &n_sinks);
 | 
			
		||||
    sources = get_sources(c, &n_sources);
 | 
			
		||||
    profiles = get_profiles(c, &n_profiles);
 | 
			
		||||
    if (c->active_profile)
 | 
			
		||||
        active_profile = pa_dbusiface_card_profile_get_path(pa_hashmap_get(c->profiles, c->active_profile->name));
 | 
			
		||||
 | 
			
		||||
    pa_assert_se((reply = dbus_message_new_method_return(msg)));
 | 
			
		||||
 | 
			
		||||
    dbus_message_iter_init_append(reply, &msg_iter);
 | 
			
		||||
    pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
 | 
			
		||||
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &idx);
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_NAME].property_name, DBUS_TYPE_STRING, &c->card->name);
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DRIVER].property_name, DBUS_TYPE_STRING, &c->card->driver);
 | 
			
		||||
 | 
			
		||||
    if (owner_module)
 | 
			
		||||
        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_OWNER_MODULE].property_name, DBUS_TYPE_OBJECT_PATH, &owner_module);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SINKS].property_name, DBUS_TYPE_OBJECT_PATH, sinks, n_sinks);
 | 
			
		||||
    pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SOURCES].property_name, DBUS_TYPE_OBJECT_PATH, sources, n_sources);
 | 
			
		||||
    pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PROFILES].property_name, DBUS_TYPE_OBJECT_PATH, profiles, n_profiles);
 | 
			
		||||
 | 
			
		||||
    if (active_profile)
 | 
			
		||||
        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_ACTIVE_PROFILE].property_name, DBUS_TYPE_OBJECT_PATH, &active_profile);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_append_proplist_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PROPERTY_LIST].property_name, c->proplist);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_connection_send(conn, reply, NULL));
 | 
			
		||||
 | 
			
		||||
    dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(sinks);
 | 
			
		||||
    pa_xfree(sources);
 | 
			
		||||
    pa_xfree(profiles);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_profile_by_name(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_card *c = userdata;
 | 
			
		||||
    const char *profile_name = NULL;
 | 
			
		||||
    pa_dbusiface_card_profile *profile = NULL;
 | 
			
		||||
    const char *profile_path = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &profile_name, DBUS_TYPE_INVALID));
 | 
			
		||||
 | 
			
		||||
    if (!(profile = pa_hashmap_get(c->profiles, profile_name))) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such profile on card %s.", profile_name, c->card->name);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    profile_path = pa_dbusiface_card_profile_get_path(profile);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &profile_path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
 | 
			
		||||
    pa_dbusiface_card *c = userdata;
 | 
			
		||||
    DBusMessage *signal = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(core);
 | 
			
		||||
    pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_CARD);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    /* We can't use idx != c->card->index, because the c->card pointer may
 | 
			
		||||
     * be stale at this point. */
 | 
			
		||||
    if (pa_idxset_get_by_index(core->cards, idx) != c->card)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (c->active_profile != c->card->active_profile) {
 | 
			
		||||
        const char *object_path;
 | 
			
		||||
 | 
			
		||||
        c->active_profile = c->card->active_profile;
 | 
			
		||||
        object_path = pa_dbusiface_card_profile_get_path(pa_hashmap_get(c->profiles, c->active_profile->name));
 | 
			
		||||
 | 
			
		||||
        pa_assert_se(signal = dbus_message_new_signal(c->path,
 | 
			
		||||
                                                      PA_DBUSIFACE_CARD_INTERFACE,
 | 
			
		||||
                                                      signals[SIGNAL_ACTIVE_PROFILE_UPDATED].name));
 | 
			
		||||
        pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID));
 | 
			
		||||
 | 
			
		||||
        pa_dbus_protocol_send_signal(c->dbus_protocol, signal);
 | 
			
		||||
        dbus_message_unref(signal);
 | 
			
		||||
        signal = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!pa_proplist_equal(c->proplist, c->card->proplist)) {
 | 
			
		||||
        DBusMessageIter msg_iter;
 | 
			
		||||
 | 
			
		||||
        pa_proplist_update(c->proplist, PA_UPDATE_SET, c->card->proplist);
 | 
			
		||||
 | 
			
		||||
        pa_assert_se(signal = dbus_message_new_signal(c->path,
 | 
			
		||||
                                                      PA_DBUSIFACE_CARD_INTERFACE,
 | 
			
		||||
                                                      signals[SIGNAL_PROPERTY_LIST_UPDATED].name));
 | 
			
		||||
        dbus_message_iter_init_append(signal, &msg_iter);
 | 
			
		||||
        pa_dbus_append_proplist(&msg_iter, c->proplist);
 | 
			
		||||
 | 
			
		||||
        pa_dbus_protocol_send_signal(c->dbus_protocol, signal);
 | 
			
		||||
        dbus_message_unref(signal);
 | 
			
		||||
        signal = NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pa_dbusiface_card *pa_dbusiface_card_new(pa_dbusiface_core *core, pa_card *card) {
 | 
			
		||||
    pa_dbusiface_card *c = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(core);
 | 
			
		||||
    pa_assert(card);
 | 
			
		||||
 | 
			
		||||
    c = pa_xnew0(pa_dbusiface_card, 1);
 | 
			
		||||
    c->core = core;
 | 
			
		||||
    c->card = card;
 | 
			
		||||
    c->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, OBJECT_NAME, card->index);
 | 
			
		||||
    c->profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
 | 
			
		||||
    c->next_profile_index = 0;
 | 
			
		||||
    c->active_profile = NULL;
 | 
			
		||||
    c->proplist = pa_proplist_copy(card->proplist);
 | 
			
		||||
    c->dbus_protocol = pa_dbus_protocol_get(card->core);
 | 
			
		||||
    c->subscription = pa_subscription_new(card->core, PA_SUBSCRIPTION_MASK_CARD, subscription_cb, c);
 | 
			
		||||
 | 
			
		||||
    if (card->profiles) {
 | 
			
		||||
        pa_card_profile *profile;
 | 
			
		||||
        void *state = NULL;
 | 
			
		||||
 | 
			
		||||
        PA_HASHMAP_FOREACH(profile, card->profiles, state) {
 | 
			
		||||
            pa_dbusiface_card_profile *p = pa_dbusiface_card_profile_new(c, card->core, profile, c->next_profile_index++);
 | 
			
		||||
            pa_hashmap_put(c->profiles, pa_dbusiface_card_profile_get_name(p), p);
 | 
			
		||||
        }
 | 
			
		||||
        pa_assert_se(c->active_profile = card->active_profile);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(pa_dbus_protocol_add_interface(c->dbus_protocol, c->path, &card_interface_info, c) >= 0);
 | 
			
		||||
 | 
			
		||||
    return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void profile_free_cb(void *p, void *userdata) {
 | 
			
		||||
    pa_dbusiface_card_profile *profile = p;
 | 
			
		||||
 | 
			
		||||
    pa_assert(profile);
 | 
			
		||||
 | 
			
		||||
    pa_dbusiface_card_profile_free(profile);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbusiface_card_free(pa_dbusiface_card *c) {
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(pa_dbus_protocol_remove_interface(c->dbus_protocol, c->path, card_interface_info.name) >= 0);
 | 
			
		||||
 | 
			
		||||
    pa_hashmap_free(c->profiles, profile_free_cb, NULL);
 | 
			
		||||
    pa_proplist_free(c->proplist);
 | 
			
		||||
    pa_dbus_protocol_unref(c->dbus_protocol);
 | 
			
		||||
    pa_subscription_free(c->subscription);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(c->path);
 | 
			
		||||
    pa_xfree(c);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *pa_dbusiface_card_get_path(pa_dbusiface_card *c) {
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    return c->path;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								src/modules/dbus/iface-card.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/modules/dbus/iface-card.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
#ifndef foodbusifacecardhfoo
 | 
			
		||||
#define foodbusifacecardhfoo
 | 
			
		||||
 | 
			
		||||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
/* This object implements the D-Bus interface org.PulseAudio.Core1.Card.
 | 
			
		||||
 *
 | 
			
		||||
 * See http://pulseaudio.org/wiki/DBusInterface for the Card interface
 | 
			
		||||
 * documentation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/card.h>
 | 
			
		||||
#include <pulsecore/protocol-dbus.h>
 | 
			
		||||
 | 
			
		||||
#include "iface-core.h"
 | 
			
		||||
 | 
			
		||||
#define PA_DBUSIFACE_CARD_INTERFACE PA_DBUS_CORE_INTERFACE ".Card"
 | 
			
		||||
 | 
			
		||||
typedef struct pa_dbusiface_card pa_dbusiface_card;
 | 
			
		||||
 | 
			
		||||
pa_dbusiface_card *pa_dbusiface_card_new(pa_dbusiface_core *core, pa_card *card);
 | 
			
		||||
void pa_dbusiface_card_free(pa_dbusiface_card *c);
 | 
			
		||||
 | 
			
		||||
const char *pa_dbusiface_card_get_path(pa_dbusiface_card *c);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										459
									
								
								src/modules/dbus/iface-client.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										459
									
								
								src/modules/dbus/iface-client.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,459 @@
 | 
			
		|||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
  Copyright 2009 Vincent Filali-Ansary <filali.v@azurdigitalnetworks.net>
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#include <config.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <dbus/dbus.h>
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/core-util.h>
 | 
			
		||||
#include <pulsecore/dbus-util.h>
 | 
			
		||||
#include <pulsecore/protocol-dbus.h>
 | 
			
		||||
 | 
			
		||||
#include "iface-client.h"
 | 
			
		||||
 | 
			
		||||
#define OBJECT_NAME "client"
 | 
			
		||||
 | 
			
		||||
struct pa_dbusiface_client {
 | 
			
		||||
    pa_dbusiface_core *core;
 | 
			
		||||
 | 
			
		||||
    pa_client *client;
 | 
			
		||||
    char *path;
 | 
			
		||||
    pa_proplist *proplist;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_protocol *dbus_protocol;
 | 
			
		||||
    pa_subscription *subscription;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_playback_streams(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_record_streams(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
static void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_update_properties(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_remove_properties(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
enum property_handler_index {
 | 
			
		||||
    PROPERTY_HANDLER_INDEX,
 | 
			
		||||
    PROPERTY_HANDLER_DRIVER,
 | 
			
		||||
    PROPERTY_HANDLER_OWNER_MODULE,
 | 
			
		||||
    PROPERTY_HANDLER_PLAYBACK_STREAMS,
 | 
			
		||||
    PROPERTY_HANDLER_RECORD_STREAMS,
 | 
			
		||||
    PROPERTY_HANDLER_PROPERTY_LIST,
 | 
			
		||||
    PROPERTY_HANDLER_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = {
 | 
			
		||||
    [PROPERTY_HANDLER_INDEX]            = { .property_name = "Index",           .type = "u",      .get_cb = handle_get_index,            .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_DRIVER]           = { .property_name = "Driver",          .type = "s",      .get_cb = handle_get_driver,           .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_OWNER_MODULE]     = { .property_name = "OwnerModule",     .type = "o",      .get_cb = handle_get_owner_module,     .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_PLAYBACK_STREAMS] = { .property_name = "PlaybackStreams", .type = "ao",     .get_cb = handle_get_playback_streams, .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_RECORD_STREAMS]   = { .property_name = "RecordStreams",   .type = "ao",     .get_cb = handle_get_record_streams,   .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_PROPERTY_LIST]    = { .property_name = "PropertyList",    .type = "a{say}", .get_cb = handle_get_property_list,    .set_cb = NULL }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum method_handler_index {
 | 
			
		||||
    METHOD_HANDLER_KILL,
 | 
			
		||||
    METHOD_HANDLER_UPDATE_PROPERTIES,
 | 
			
		||||
    METHOD_HANDLER_REMOVE_PROPERTIES,
 | 
			
		||||
    METHOD_HANDLER_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_arg_info update_properties_args[] = { { "property_list", "a{say}", "in" }, { "update_mode", "u", "in" } };
 | 
			
		||||
static pa_dbus_arg_info remove_properties_args[] = { { "keys", "as", "in" } };
 | 
			
		||||
 | 
			
		||||
static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
 | 
			
		||||
    [METHOD_HANDLER_KILL] = {
 | 
			
		||||
        .method_name = "Kill",
 | 
			
		||||
        .arguments = NULL,
 | 
			
		||||
        .n_arguments = 0,
 | 
			
		||||
        .receive_cb = handle_kill },
 | 
			
		||||
    [METHOD_HANDLER_UPDATE_PROPERTIES] = {
 | 
			
		||||
        .method_name = "UpdateProperties",
 | 
			
		||||
        .arguments = update_properties_args,
 | 
			
		||||
        .n_arguments = sizeof(update_properties_args) / sizeof(pa_dbus_arg_info),
 | 
			
		||||
        .receive_cb = handle_update_properties },
 | 
			
		||||
    [METHOD_HANDLER_REMOVE_PROPERTIES] = {
 | 
			
		||||
        .method_name = "RemoveProperties",
 | 
			
		||||
        .arguments = remove_properties_args,
 | 
			
		||||
        .n_arguments = sizeof(remove_properties_args) / sizeof(pa_dbus_arg_info),
 | 
			
		||||
        .receive_cb = handle_remove_properties }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum signal_index {
 | 
			
		||||
    SIGNAL_PROPERTY_LIST_UPDATED,
 | 
			
		||||
    SIGNAL_CLIENT_EVENT,
 | 
			
		||||
    SIGNAL_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_arg_info property_list_updated_args[] = { { "property_list", "a{say}", NULL } };
 | 
			
		||||
static pa_dbus_arg_info client_event_args[]          = { { "name",          "s",      NULL },
 | 
			
		||||
                                                         { "property_list", "a{say}", NULL } };
 | 
			
		||||
 | 
			
		||||
static pa_dbus_signal_info signals[SIGNAL_MAX] = {
 | 
			
		||||
    [SIGNAL_PROPERTY_LIST_UPDATED] = { .name = "PropertyListUpdated", .arguments = property_list_updated_args, .n_arguments = 1 },
 | 
			
		||||
    /* ClientEvent is sent from module-dbus-protocol.c. */
 | 
			
		||||
    [SIGNAL_CLIENT_EVENT]          = { .name = "ClientEvent",         .arguments = client_event_args,          .n_arguments = 1 }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_interface_info client_interface_info = {
 | 
			
		||||
    .name = PA_DBUSIFACE_CLIENT_INTERFACE,
 | 
			
		||||
    .method_handlers = method_handlers,
 | 
			
		||||
    .n_method_handlers = METHOD_HANDLER_MAX,
 | 
			
		||||
    .property_handlers = property_handlers,
 | 
			
		||||
    .n_property_handlers = PROPERTY_HANDLER_MAX,
 | 
			
		||||
    .get_all_properties_cb = handle_get_all,
 | 
			
		||||
    .signals = signals,
 | 
			
		||||
    .n_signals = SIGNAL_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_client *c = userdata;
 | 
			
		||||
    dbus_uint32_t idx = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    idx = c->client->index;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &idx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_client *c = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &c->client->driver);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_client *c = userdata;
 | 
			
		||||
    const char *owner_module = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    if (!c->client->module) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Client %d doesn't have an owner module.", c->client->index);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    owner_module = pa_dbusiface_core_get_module_path(c->core, c->client->module);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &owner_module);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* The caller frees the array, but not the strings. */
 | 
			
		||||
static const char **get_playback_streams(pa_dbusiface_client *c, unsigned *n) {
 | 
			
		||||
    const char **playback_streams = NULL;
 | 
			
		||||
    unsigned i = 0;
 | 
			
		||||
    uint32_t idx = 0;
 | 
			
		||||
    pa_sink_input *sink_input = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
    pa_assert(n);
 | 
			
		||||
 | 
			
		||||
    *n = pa_idxset_size(c->client->sink_inputs);
 | 
			
		||||
 | 
			
		||||
    if (*n == 0)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    playback_streams = pa_xnew(const char *, *n);
 | 
			
		||||
 | 
			
		||||
    PA_IDXSET_FOREACH(sink_input, c->client->sink_inputs, idx)
 | 
			
		||||
        playback_streams[i++] = pa_dbusiface_core_get_playback_stream_path(c->core, sink_input);
 | 
			
		||||
 | 
			
		||||
    return playback_streams;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_playback_streams(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_client *c = userdata;
 | 
			
		||||
    const char **playback_streams = NULL;
 | 
			
		||||
    unsigned n_playback_streams = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    playback_streams = get_playback_streams(c, &n_playback_streams);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, playback_streams, n_playback_streams);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(playback_streams);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* The caller frees the array, but not the strings. */
 | 
			
		||||
static const char **get_record_streams(pa_dbusiface_client *c, unsigned *n) {
 | 
			
		||||
    const char **record_streams = NULL;
 | 
			
		||||
    unsigned i = 0;
 | 
			
		||||
    uint32_t idx = 0;
 | 
			
		||||
    pa_source_output *source_output = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
    pa_assert(n);
 | 
			
		||||
 | 
			
		||||
    *n = pa_idxset_size(c->client->source_outputs);
 | 
			
		||||
 | 
			
		||||
    if (*n == 0)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    record_streams = pa_xnew(const char *, *n);
 | 
			
		||||
 | 
			
		||||
    PA_IDXSET_FOREACH(source_output, c->client->source_outputs, idx)
 | 
			
		||||
        record_streams[i++] = pa_dbusiface_core_get_record_stream_path(c->core, source_output);
 | 
			
		||||
 | 
			
		||||
    return record_streams;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_record_streams(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_client *c = userdata;
 | 
			
		||||
    const char **record_streams = NULL;
 | 
			
		||||
    unsigned n_record_streams = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    record_streams = get_record_streams(c, &n_record_streams);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, record_streams, n_record_streams);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(record_streams);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_client *c = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_proplist_variant_reply(conn, msg, c->client->proplist);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_client *c = userdata;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
    DBusMessageIter dict_iter;
 | 
			
		||||
    dbus_uint32_t idx = 0;
 | 
			
		||||
    const char *owner_module = NULL;
 | 
			
		||||
    const char **playback_streams = NULL;
 | 
			
		||||
    unsigned n_playback_streams = 0;
 | 
			
		||||
    const char **record_streams = NULL;
 | 
			
		||||
    unsigned n_record_streams = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    idx = c->client->index;
 | 
			
		||||
    if (c->client->module)
 | 
			
		||||
        owner_module = pa_dbusiface_core_get_module_path(c->core, c->client->module);
 | 
			
		||||
    playback_streams = get_playback_streams(c, &n_playback_streams);
 | 
			
		||||
    record_streams = get_record_streams(c, &n_record_streams);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se((reply = dbus_message_new_method_return(msg)));
 | 
			
		||||
 | 
			
		||||
    dbus_message_iter_init_append(reply, &msg_iter);
 | 
			
		||||
    pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
 | 
			
		||||
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &idx);
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DRIVER].property_name, DBUS_TYPE_STRING, &c->client->driver);
 | 
			
		||||
 | 
			
		||||
    if (owner_module)
 | 
			
		||||
        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_OWNER_MODULE].property_name, DBUS_TYPE_OBJECT_PATH, &owner_module);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PLAYBACK_STREAMS].property_name, DBUS_TYPE_OBJECT_PATH, playback_streams, n_playback_streams);
 | 
			
		||||
    pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_RECORD_STREAMS].property_name, DBUS_TYPE_OBJECT_PATH, record_streams, n_record_streams);
 | 
			
		||||
    pa_dbus_append_proplist_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PROPERTY_LIST].property_name, c->client->proplist);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_connection_send(conn, reply, NULL));
 | 
			
		||||
 | 
			
		||||
    dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(playback_streams);
 | 
			
		||||
    pa_xfree(record_streams);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_client *c = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    dbus_connection_ref(conn);
 | 
			
		||||
 | 
			
		||||
    pa_client_kill(c->client);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_empty_reply(conn, msg);
 | 
			
		||||
 | 
			
		||||
    dbus_connection_unref(conn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_update_properties(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_client *c = userdata;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
    pa_proplist *property_list = NULL;
 | 
			
		||||
    dbus_uint32_t update_mode = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    if (pa_dbus_protocol_get_client(c->dbus_protocol, conn) != c->client) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, DBUS_ERROR_ACCESS_DENIED, "Client tried to modify the property list of another client.");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_init(msg, &msg_iter));
 | 
			
		||||
 | 
			
		||||
    if (!(property_list = pa_dbus_get_proplist_arg(conn, msg, &msg_iter)))
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    dbus_message_iter_get_basic(&msg_iter, &update_mode);
 | 
			
		||||
 | 
			
		||||
    if (!(update_mode == PA_UPDATE_SET || update_mode == PA_UPDATE_MERGE || update_mode == PA_UPDATE_REPLACE)) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid update mode: %u", update_mode);
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_client_update_proplist(c->client, update_mode, property_list);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_empty_reply(conn, msg);
 | 
			
		||||
 | 
			
		||||
finish:
 | 
			
		||||
    if (property_list)
 | 
			
		||||
        pa_proplist_free(property_list);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_remove_properties(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_client *c = userdata;
 | 
			
		||||
    char **keys = NULL;
 | 
			
		||||
    int n_keys = 0;
 | 
			
		||||
    pa_bool_t changed = FALSE;
 | 
			
		||||
    int i = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    if (pa_dbus_protocol_get_client(c->dbus_protocol, conn) != c->client) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, DBUS_ERROR_ACCESS_DENIED, "Client tried to modify the property list of another client.");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &keys, &n_keys, DBUS_TYPE_INVALID));
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < n_keys; ++i)
 | 
			
		||||
        changed |= pa_proplist_unset(c->client->proplist, keys[i]) >= 0;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_empty_reply(conn, msg);
 | 
			
		||||
 | 
			
		||||
    if (changed)
 | 
			
		||||
        pa_subscription_post(c->client->core, PA_SUBSCRIPTION_EVENT_CLIENT|PA_SUBSCRIPTION_EVENT_CHANGE, c->client->index);
 | 
			
		||||
 | 
			
		||||
    dbus_free_string_array(keys);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
 | 
			
		||||
    pa_dbusiface_client *c = userdata;
 | 
			
		||||
    DBusMessage *signal = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(core);
 | 
			
		||||
    pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_CLIENT);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    /* We can't use idx != c->client->index, because the c->client pointer may
 | 
			
		||||
     * be stale at this point. */
 | 
			
		||||
    if (pa_idxset_get_by_index(core->clients, idx) != c->client)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (!pa_proplist_equal(c->proplist, c->client->proplist)) {
 | 
			
		||||
        DBusMessageIter msg_iter;
 | 
			
		||||
 | 
			
		||||
        pa_proplist_update(c->proplist, PA_UPDATE_SET, c->client->proplist);
 | 
			
		||||
 | 
			
		||||
        pa_assert_se(signal = dbus_message_new_signal(c->path,
 | 
			
		||||
                                                      PA_DBUSIFACE_CLIENT_INTERFACE,
 | 
			
		||||
                                                      signals[SIGNAL_PROPERTY_LIST_UPDATED].name));
 | 
			
		||||
        dbus_message_iter_init_append(signal, &msg_iter);
 | 
			
		||||
        pa_dbus_append_proplist(&msg_iter, c->proplist);
 | 
			
		||||
 | 
			
		||||
        pa_dbus_protocol_send_signal(c->dbus_protocol, signal);
 | 
			
		||||
        dbus_message_unref(signal);
 | 
			
		||||
        signal = NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pa_dbusiface_client *pa_dbusiface_client_new(pa_dbusiface_core *core, pa_client *client) {
 | 
			
		||||
    pa_dbusiface_client *c = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(core);
 | 
			
		||||
    pa_assert(client);
 | 
			
		||||
 | 
			
		||||
    c = pa_xnew(pa_dbusiface_client, 1);
 | 
			
		||||
    c->core = core;
 | 
			
		||||
    c->client = client;
 | 
			
		||||
    c->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, OBJECT_NAME, client->index);
 | 
			
		||||
    c->proplist = pa_proplist_copy(client->proplist);
 | 
			
		||||
    c->dbus_protocol = pa_dbus_protocol_get(client->core);
 | 
			
		||||
    c->subscription = pa_subscription_new(client->core, PA_SUBSCRIPTION_MASK_CLIENT, subscription_cb, c);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(pa_dbus_protocol_add_interface(c->dbus_protocol, c->path, &client_interface_info, c) >= 0);
 | 
			
		||||
 | 
			
		||||
    return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbusiface_client_free(pa_dbusiface_client *c) {
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(pa_dbus_protocol_remove_interface(c->dbus_protocol, c->path, client_interface_info.name) >= 0);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_protocol_unref(c->dbus_protocol);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(c->path);
 | 
			
		||||
    pa_xfree(c);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *pa_dbusiface_client_get_path(pa_dbusiface_client *c) {
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    return c->path;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								src/modules/dbus/iface-client.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/modules/dbus/iface-client.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
#ifndef foodbusifaceclienthfoo
 | 
			
		||||
#define foodbusifaceclienthfoo
 | 
			
		||||
 | 
			
		||||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
/* This object implements the D-Bus interface org.PulseAudio.Core1.Client.
 | 
			
		||||
 *
 | 
			
		||||
 * See http://pulseaudio.org/wiki/DBusInterface for the Client interface
 | 
			
		||||
 * documentation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/client.h>
 | 
			
		||||
#include <pulsecore/protocol-dbus.h>
 | 
			
		||||
 | 
			
		||||
#include "iface-core.h"
 | 
			
		||||
 | 
			
		||||
#define PA_DBUSIFACE_CLIENT_INTERFACE PA_DBUS_CORE_INTERFACE ".Client"
 | 
			
		||||
 | 
			
		||||
typedef struct pa_dbusiface_client pa_dbusiface_client;
 | 
			
		||||
 | 
			
		||||
pa_dbusiface_client *pa_dbusiface_client_new(pa_dbusiface_core *core, pa_client *client);
 | 
			
		||||
void pa_dbusiface_client_free(pa_dbusiface_client *c);
 | 
			
		||||
 | 
			
		||||
const char *pa_dbusiface_client_get_path(pa_dbusiface_client *c);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										2197
									
								
								src/modules/dbus/iface-core.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2197
									
								
								src/modules/dbus/iface-core.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										52
									
								
								src/modules/dbus/iface-core.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/modules/dbus/iface-core.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,52 @@
 | 
			
		|||
#ifndef foodbusifacecorehfoo
 | 
			
		||||
#define foodbusifacecorehfoo
 | 
			
		||||
 | 
			
		||||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
/* This object implements the D-Bus interface org.PulseAudio.Core1.
 | 
			
		||||
 *
 | 
			
		||||
 * See http://pulseaudio.org/wiki/DBusInterface for the Core interface
 | 
			
		||||
 * documentation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/core.h>
 | 
			
		||||
 | 
			
		||||
typedef struct pa_dbusiface_core pa_dbusiface_core;
 | 
			
		||||
 | 
			
		||||
pa_dbusiface_core *pa_dbusiface_core_new(pa_core *core);
 | 
			
		||||
void pa_dbusiface_core_free(pa_dbusiface_core *c);
 | 
			
		||||
 | 
			
		||||
const char *pa_dbusiface_core_get_card_path(pa_dbusiface_core *c, const pa_card *card);
 | 
			
		||||
const char *pa_dbusiface_core_get_sink_path(pa_dbusiface_core *c, const pa_sink *sink);
 | 
			
		||||
const char *pa_dbusiface_core_get_source_path(pa_dbusiface_core *c, const pa_source *source);
 | 
			
		||||
const char *pa_dbusiface_core_get_playback_stream_path(pa_dbusiface_core *c, const pa_sink_input *sink_input);
 | 
			
		||||
const char *pa_dbusiface_core_get_record_stream_path(pa_dbusiface_core *c, const pa_source_output *source_output);
 | 
			
		||||
const char *pa_dbusiface_core_get_module_path(pa_dbusiface_core *c, const pa_module *module);
 | 
			
		||||
const char *pa_dbusiface_core_get_client_path(pa_dbusiface_core *c, const pa_client *client);
 | 
			
		||||
 | 
			
		||||
/* Returns NULL if there's no sink with the given path. */
 | 
			
		||||
pa_sink *pa_dbusiface_core_get_sink(pa_dbusiface_core *c, const char *object_path);
 | 
			
		||||
 | 
			
		||||
/* Returns NULL if there's no source with the given path. */
 | 
			
		||||
pa_source *pa_dbusiface_core_get_source(pa_dbusiface_core *c, const char *object_path);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										190
									
								
								src/modules/dbus/iface-device-port.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								src/modules/dbus/iface-device-port.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,190 @@
 | 
			
		|||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#include <config.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <dbus/dbus.h>
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/core-util.h>
 | 
			
		||||
#include <pulsecore/dbus-util.h>
 | 
			
		||||
 | 
			
		||||
#include "iface-device-port.h"
 | 
			
		||||
 | 
			
		||||
#define OBJECT_NAME "port"
 | 
			
		||||
 | 
			
		||||
static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_description(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_priority(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
struct pa_dbusiface_device_port {
 | 
			
		||||
    uint32_t index;
 | 
			
		||||
    pa_device_port *port;
 | 
			
		||||
    char *path;
 | 
			
		||||
    pa_dbus_protocol *dbus_protocol;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum property_handler_index {
 | 
			
		||||
    PROPERTY_HANDLER_INDEX,
 | 
			
		||||
    PROPERTY_HANDLER_NAME,
 | 
			
		||||
    PROPERTY_HANDLER_DESCRIPTION,
 | 
			
		||||
    PROPERTY_HANDLER_PRIORITY,
 | 
			
		||||
    PROPERTY_HANDLER_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = {
 | 
			
		||||
    [PROPERTY_HANDLER_INDEX]       = { .property_name = "Index",       .type = "u", .get_cb = handle_get_index,       .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_NAME]        = { .property_name = "Name",        .type = "s", .get_cb = handle_get_name,        .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_DESCRIPTION] = { .property_name = "Description", .type = "s", .get_cb = handle_get_description, .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_PRIORITY]    = { .property_name = "Priority",    .type = "u", .get_cb = handle_get_priority,    .set_cb = NULL },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_interface_info port_interface_info = {
 | 
			
		||||
    .name = PA_DBUSIFACE_DEVICE_PORT_INTERFACE,
 | 
			
		||||
    .method_handlers = NULL,
 | 
			
		||||
    .n_method_handlers = 0,
 | 
			
		||||
    .property_handlers = property_handlers,
 | 
			
		||||
    .n_property_handlers = PROPERTY_HANDLER_MAX,
 | 
			
		||||
    .get_all_properties_cb = handle_get_all,
 | 
			
		||||
    .signals = NULL,
 | 
			
		||||
    .n_signals = 0
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_device_port *p = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(p);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &p->index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_device_port *p = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(p);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &p->port->name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_description(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_device_port *p = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(p);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &p->port->description);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_priority(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_device_port *p = userdata;
 | 
			
		||||
    dbus_uint32_t priority = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(p);
 | 
			
		||||
 | 
			
		||||
    priority = p->port->priority;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &priority);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_device_port *p = userdata;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
    DBusMessageIter dict_iter;
 | 
			
		||||
    dbus_uint32_t priority = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(p);
 | 
			
		||||
 | 
			
		||||
    priority = p->port->priority;
 | 
			
		||||
 | 
			
		||||
    pa_assert_se((reply = dbus_message_new_method_return(msg)));
 | 
			
		||||
 | 
			
		||||
    dbus_message_iter_init_append(reply, &msg_iter);
 | 
			
		||||
    pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
 | 
			
		||||
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &p->index);
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_NAME].property_name, DBUS_TYPE_STRING, &p->port->name);
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DESCRIPTION].property_name, DBUS_TYPE_STRING, &p->port->description);
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PRIORITY].property_name, DBUS_TYPE_UINT32, &priority);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_connection_send(conn, reply, NULL));
 | 
			
		||||
    dbus_message_unref(reply);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pa_dbusiface_device_port *pa_dbusiface_device_port_new(
 | 
			
		||||
        pa_dbusiface_device *device,
 | 
			
		||||
        pa_core *core,
 | 
			
		||||
        pa_device_port *port,
 | 
			
		||||
        uint32_t idx) {
 | 
			
		||||
    pa_dbusiface_device_port *p = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(device);
 | 
			
		||||
    pa_assert(core);
 | 
			
		||||
    pa_assert(port);
 | 
			
		||||
 | 
			
		||||
    p = pa_xnew(pa_dbusiface_device_port, 1);
 | 
			
		||||
    p->index = idx;
 | 
			
		||||
    p->port = port;
 | 
			
		||||
    p->path = pa_sprintf_malloc("%s/%s%u", pa_dbusiface_device_get_path(device), OBJECT_NAME, idx);
 | 
			
		||||
    p->dbus_protocol = pa_dbus_protocol_get(core);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(pa_dbus_protocol_add_interface(p->dbus_protocol, p->path, &port_interface_info, p) >= 0);
 | 
			
		||||
 | 
			
		||||
    return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbusiface_device_port_free(pa_dbusiface_device_port *p) {
 | 
			
		||||
    pa_assert(p);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(pa_dbus_protocol_remove_interface(p->dbus_protocol, p->path, port_interface_info.name) >= 0);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_protocol_unref(p->dbus_protocol);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(p->path);
 | 
			
		||||
    pa_xfree(p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *pa_dbusiface_device_port_get_path(pa_dbusiface_device_port *p) {
 | 
			
		||||
    pa_assert(p);
 | 
			
		||||
 | 
			
		||||
    return p->path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *pa_dbusiface_device_port_get_name(pa_dbusiface_device_port *p) {
 | 
			
		||||
    pa_assert(p);
 | 
			
		||||
 | 
			
		||||
    return p->port->name;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										50
									
								
								src/modules/dbus/iface-device-port.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/modules/dbus/iface-device-port.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
#ifndef foodbusifacedeviceporthfoo
 | 
			
		||||
#define foodbusifacedeviceporthfoo
 | 
			
		||||
 | 
			
		||||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
/* This object implements the D-Bus interface org.PulseAudio.Core1.DevicePort.
 | 
			
		||||
 *
 | 
			
		||||
 * See http://pulseaudio.org/wiki/DBusInterface for the DevicePort interface
 | 
			
		||||
 * documentation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/protocol-dbus.h>
 | 
			
		||||
#include <pulsecore/sink.h>
 | 
			
		||||
 | 
			
		||||
#include "iface-device.h"
 | 
			
		||||
 | 
			
		||||
#define PA_DBUSIFACE_DEVICE_PORT_INTERFACE PA_DBUS_CORE_INTERFACE ".DevicePort"
 | 
			
		||||
 | 
			
		||||
typedef struct pa_dbusiface_device_port pa_dbusiface_device_port;
 | 
			
		||||
 | 
			
		||||
pa_dbusiface_device_port *pa_dbusiface_device_port_new(
 | 
			
		||||
        pa_dbusiface_device *device,
 | 
			
		||||
        pa_core *core,
 | 
			
		||||
        pa_device_port *port,
 | 
			
		||||
        uint32_t idx);
 | 
			
		||||
void pa_dbusiface_device_port_free(pa_dbusiface_device_port *p);
 | 
			
		||||
 | 
			
		||||
const char *pa_dbusiface_device_port_get_path(pa_dbusiface_device_port *p);
 | 
			
		||||
const char *pa_dbusiface_device_port_get_name(pa_dbusiface_device_port *p);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										1316
									
								
								src/modules/dbus/iface-device.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1316
									
								
								src/modules/dbus/iface-device.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										53
									
								
								src/modules/dbus/iface-device.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/modules/dbus/iface-device.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,53 @@
 | 
			
		|||
#ifndef foodbusifacedevicehfoo
 | 
			
		||||
#define foodbusifacedevicehfoo
 | 
			
		||||
 | 
			
		||||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
/* This object implements the D-Bus interfaces org.PulseAudio.Core1.Device,
 | 
			
		||||
 * org.PulseAudio.Core1.Sink and org.PulseAudio.Core1.Source.
 | 
			
		||||
 *
 | 
			
		||||
 * See http://pulseaudio.org/wiki/DBusInterface for the interface
 | 
			
		||||
 * documentation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/protocol-dbus.h>
 | 
			
		||||
#include <pulsecore/sink.h>
 | 
			
		||||
#include <pulsecore/source.h>
 | 
			
		||||
 | 
			
		||||
#include "iface-core.h"
 | 
			
		||||
 | 
			
		||||
#define PA_DBUSIFACE_DEVICE_INTERFACE PA_DBUS_CORE_INTERFACE ".Device"
 | 
			
		||||
#define PA_DBUSIFACE_SINK_INTERFACE PA_DBUS_CORE_INTERFACE ".Sink"
 | 
			
		||||
#define PA_DBUSIFACE_SOURCE_INTERFACE PA_DBUS_CORE_INTERFACE ".Source"
 | 
			
		||||
 | 
			
		||||
typedef struct pa_dbusiface_device pa_dbusiface_device;
 | 
			
		||||
 | 
			
		||||
pa_dbusiface_device *pa_dbusiface_device_new_sink(pa_dbusiface_core *core, pa_sink *sink);
 | 
			
		||||
pa_dbusiface_device *pa_dbusiface_device_new_source(pa_dbusiface_core *core, pa_source *source);
 | 
			
		||||
void pa_dbusiface_device_free(pa_dbusiface_device *d);
 | 
			
		||||
 | 
			
		||||
const char *pa_dbusiface_device_get_path(pa_dbusiface_device *d);
 | 
			
		||||
 | 
			
		||||
pa_sink *pa_dbusiface_device_get_sink(pa_dbusiface_device *d);
 | 
			
		||||
pa_source *pa_dbusiface_device_get_source(pa_dbusiface_device *d);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										231
									
								
								src/modules/dbus/iface-memstats.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										231
									
								
								src/modules/dbus/iface-memstats.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,231 @@
 | 
			
		|||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#include <config.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <dbus/dbus.h>
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/core-scache.h>
 | 
			
		||||
#include <pulsecore/core-util.h>
 | 
			
		||||
#include <pulsecore/dbus-util.h>
 | 
			
		||||
#include <pulsecore/protocol-dbus.h>
 | 
			
		||||
 | 
			
		||||
#include "iface-memstats.h"
 | 
			
		||||
 | 
			
		||||
#define OBJECT_NAME "memstats"
 | 
			
		||||
 | 
			
		||||
static void handle_get_current_memblocks(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_current_memblocks_size(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_accumulated_memblocks(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_accumulated_memblocks_size(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_sample_cache_size(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
struct pa_dbusiface_memstats {
 | 
			
		||||
    pa_core *core;
 | 
			
		||||
    char *path;
 | 
			
		||||
    pa_dbus_protocol *dbus_protocol;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum property_handler_index {
 | 
			
		||||
    PROPERTY_HANDLER_CURRENT_MEMBLOCKS,
 | 
			
		||||
    PROPERTY_HANDLER_CURRENT_MEMBLOCKS_SIZE,
 | 
			
		||||
    PROPERTY_HANDLER_ACCUMULATED_MEMBLOCKS,
 | 
			
		||||
    PROPERTY_HANDLER_ACCUMULATED_MEMBLOCKS_SIZE,
 | 
			
		||||
    PROPERTY_HANDLER_SAMPLE_CACHE_SIZE,
 | 
			
		||||
    PROPERTY_HANDLER_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = {
 | 
			
		||||
    [PROPERTY_HANDLER_CURRENT_MEMBLOCKS]          = { .property_name = "CurrentMemblocks",         .type = "u", .get_cb = handle_get_current_memblocks,          .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_CURRENT_MEMBLOCKS_SIZE]     = { .property_name = "CurrentMemblocksSize",     .type = "u", .get_cb = handle_get_current_memblocks_size,     .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_ACCUMULATED_MEMBLOCKS]      = { .property_name = "AccumulatedMemblocks",     .type = "u", .get_cb = handle_get_accumulated_memblocks,      .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_ACCUMULATED_MEMBLOCKS_SIZE] = { .property_name = "AccumulatedMemblocksSize", .type = "u", .get_cb = handle_get_accumulated_memblocks_size, .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_SAMPLE_CACHE_SIZE]          = { .property_name = "SampleCacheSize",          .type = "u", .get_cb = handle_get_sample_cache_size,          .set_cb = NULL }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_interface_info memstats_interface_info = {
 | 
			
		||||
    .name = PA_DBUSIFACE_MEMSTATS_INTERFACE,
 | 
			
		||||
    .method_handlers = NULL,
 | 
			
		||||
    .n_method_handlers = 0,
 | 
			
		||||
    .property_handlers = property_handlers,
 | 
			
		||||
    .n_property_handlers = PROPERTY_HANDLER_MAX,
 | 
			
		||||
    .get_all_properties_cb = handle_get_all,
 | 
			
		||||
    .signals = NULL,
 | 
			
		||||
    .n_signals = 0
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void handle_get_current_memblocks(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_memstats *m = userdata;
 | 
			
		||||
    const pa_mempool_stat *stat;
 | 
			
		||||
    dbus_uint32_t current_memblocks;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    stat = pa_mempool_get_stat(m->core->mempool);
 | 
			
		||||
 | 
			
		||||
    current_memblocks = pa_atomic_load(&stat->n_allocated);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, ¤t_memblocks);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_current_memblocks_size(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_memstats *m = userdata;
 | 
			
		||||
    const pa_mempool_stat *stat;
 | 
			
		||||
    dbus_uint32_t current_memblocks_size;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    stat = pa_mempool_get_stat(m->core->mempool);
 | 
			
		||||
 | 
			
		||||
    current_memblocks_size = pa_atomic_load(&stat->allocated_size);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, ¤t_memblocks_size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_accumulated_memblocks(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_memstats *m = userdata;
 | 
			
		||||
    const pa_mempool_stat *stat;
 | 
			
		||||
    dbus_uint32_t accumulated_memblocks;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    stat = pa_mempool_get_stat(m->core->mempool);
 | 
			
		||||
 | 
			
		||||
    accumulated_memblocks = pa_atomic_load(&stat->n_accumulated);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &accumulated_memblocks);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_accumulated_memblocks_size(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_memstats *m = userdata;
 | 
			
		||||
    const pa_mempool_stat *stat;
 | 
			
		||||
    dbus_uint32_t accumulated_memblocks_size;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    stat = pa_mempool_get_stat(m->core->mempool);
 | 
			
		||||
 | 
			
		||||
    accumulated_memblocks_size = pa_atomic_load(&stat->accumulated_size);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &accumulated_memblocks_size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_sample_cache_size(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_memstats *m = userdata;
 | 
			
		||||
    dbus_uint32_t sample_cache_size;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    sample_cache_size = pa_scache_total_size(m->core);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &sample_cache_size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_memstats *m = userdata;
 | 
			
		||||
    const pa_mempool_stat *stat;
 | 
			
		||||
    dbus_uint32_t current_memblocks;
 | 
			
		||||
    dbus_uint32_t current_memblocks_size;
 | 
			
		||||
    dbus_uint32_t accumulated_memblocks;
 | 
			
		||||
    dbus_uint32_t accumulated_memblocks_size;
 | 
			
		||||
    dbus_uint32_t sample_cache_size;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
    DBusMessageIter dict_iter;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    stat = pa_mempool_get_stat(m->core->mempool);
 | 
			
		||||
 | 
			
		||||
    current_memblocks = pa_atomic_load(&stat->n_allocated);
 | 
			
		||||
    current_memblocks_size = pa_atomic_load(&stat->allocated_size);
 | 
			
		||||
    accumulated_memblocks = pa_atomic_load(&stat->n_accumulated);
 | 
			
		||||
    accumulated_memblocks_size = pa_atomic_load(&stat->accumulated_size);
 | 
			
		||||
    sample_cache_size = pa_scache_total_size(m->core);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se((reply = dbus_message_new_method_return(msg)));
 | 
			
		||||
 | 
			
		||||
    dbus_message_iter_init_append(reply, &msg_iter);
 | 
			
		||||
    pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
 | 
			
		||||
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CURRENT_MEMBLOCKS].property_name, DBUS_TYPE_UINT32, ¤t_memblocks);
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CURRENT_MEMBLOCKS_SIZE].property_name, DBUS_TYPE_UINT32, ¤t_memblocks_size);
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_ACCUMULATED_MEMBLOCKS].property_name, DBUS_TYPE_UINT32, &accumulated_memblocks);
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_ACCUMULATED_MEMBLOCKS_SIZE].property_name, DBUS_TYPE_UINT32, &accumulated_memblocks_size);
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_CACHE_SIZE].property_name, DBUS_TYPE_UINT32, &sample_cache_size);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_connection_send(conn, reply, NULL));
 | 
			
		||||
 | 
			
		||||
    dbus_message_unref(reply);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pa_dbusiface_memstats *pa_dbusiface_memstats_new(pa_dbusiface_core *dbus_core, pa_core *core) {
 | 
			
		||||
    pa_dbusiface_memstats *m;
 | 
			
		||||
 | 
			
		||||
    pa_assert(dbus_core);
 | 
			
		||||
    pa_assert(core);
 | 
			
		||||
 | 
			
		||||
    m = pa_xnew(pa_dbusiface_memstats, 1);
 | 
			
		||||
    m->core = pa_core_ref(core);
 | 
			
		||||
    m->path = pa_sprintf_malloc("%s/%s", PA_DBUS_CORE_OBJECT_PATH, OBJECT_NAME);
 | 
			
		||||
    m->dbus_protocol = pa_dbus_protocol_get(core);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(pa_dbus_protocol_add_interface(m->dbus_protocol, m->path, &memstats_interface_info, m) >= 0);
 | 
			
		||||
 | 
			
		||||
    return m;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbusiface_memstats_free(pa_dbusiface_memstats *m) {
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(pa_dbus_protocol_remove_interface(m->dbus_protocol, m->path, memstats_interface_info.name) >= 0);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(m->path);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_protocol_unref(m->dbus_protocol);
 | 
			
		||||
    pa_core_unref(m->core);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(m);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *pa_dbusiface_memstats_get_path(pa_dbusiface_memstats *m) {
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    return m->path;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								src/modules/dbus/iface-memstats.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/modules/dbus/iface-memstats.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
#ifndef foodbusifacememstatshfoo
 | 
			
		||||
#define foodbusifacememstatshfoo
 | 
			
		||||
 | 
			
		||||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
/* This object implements the D-Bus interface org.PulseAudio.Core1.Memstats.
 | 
			
		||||
 *
 | 
			
		||||
 * See http://pulseaudio.org/wiki/DBusInterface for the Memstats interface
 | 
			
		||||
 * documentation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/core.h>
 | 
			
		||||
#include <pulsecore/protocol-dbus.h>
 | 
			
		||||
 | 
			
		||||
#include "iface-core.h"
 | 
			
		||||
 | 
			
		||||
#define PA_DBUSIFACE_MEMSTATS_INTERFACE PA_DBUS_CORE_INTERFACE ".Memstats"
 | 
			
		||||
 | 
			
		||||
typedef struct pa_dbusiface_memstats pa_dbusiface_memstats;
 | 
			
		||||
 | 
			
		||||
pa_dbusiface_memstats *pa_dbusiface_memstats_new(pa_dbusiface_core *dbus_core, pa_core *core);
 | 
			
		||||
void pa_dbusiface_memstats_free(pa_dbusiface_memstats *m);
 | 
			
		||||
 | 
			
		||||
const char *pa_dbusiface_memstats_get_path(pa_dbusiface_memstats *m);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										336
									
								
								src/modules/dbus/iface-module.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										336
									
								
								src/modules/dbus/iface-module.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,336 @@
 | 
			
		|||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#include <config.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/core-util.h>
 | 
			
		||||
#include <pulsecore/dbus-util.h>
 | 
			
		||||
#include <pulsecore/modargs.h>
 | 
			
		||||
#include <pulsecore/protocol-dbus.h>
 | 
			
		||||
 | 
			
		||||
#include "iface-module.h"
 | 
			
		||||
 | 
			
		||||
#define OBJECT_NAME "module"
 | 
			
		||||
 | 
			
		||||
struct pa_dbusiface_module {
 | 
			
		||||
    pa_module *module;
 | 
			
		||||
    char *path;
 | 
			
		||||
    pa_proplist *proplist;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_protocol *dbus_protocol;
 | 
			
		||||
    pa_subscription *subscription;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_arguments(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_usage_counter(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
static void handle_unload(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
enum property_handler_index {
 | 
			
		||||
    PROPERTY_HANDLER_INDEX,
 | 
			
		||||
    PROPERTY_HANDLER_NAME,
 | 
			
		||||
    PROPERTY_HANDLER_ARGUMENTS,
 | 
			
		||||
    PROPERTY_HANDLER_USAGE_COUNTER,
 | 
			
		||||
    PROPERTY_HANDLER_PROPERTY_LIST,
 | 
			
		||||
    PROPERTY_HANDLER_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = {
 | 
			
		||||
    [PROPERTY_HANDLER_INDEX]         = { .property_name = "Index",        .type = "u",      .get_cb = handle_get_index,         .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_NAME]          = { .property_name = "Name",         .type = "s",      .get_cb = handle_get_name,          .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_ARGUMENTS]     = { .property_name = "Arguments",    .type = "a{ss}",  .get_cb = handle_get_arguments,     .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_USAGE_COUNTER] = { .property_name = "UsageCounter", .type = "u",      .get_cb = handle_get_usage_counter, .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_PROPERTY_LIST] = { .property_name = "PropertyList", .type = "a{say}", .get_cb = handle_get_property_list, .set_cb = NULL }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum method_handler_index {
 | 
			
		||||
    METHOD_HANDLER_UNLOAD,
 | 
			
		||||
    METHOD_HANDLER_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
 | 
			
		||||
    [METHOD_HANDLER_UNLOAD] = {
 | 
			
		||||
        .method_name = "Unload",
 | 
			
		||||
        .arguments = NULL,
 | 
			
		||||
        .n_arguments = 0,
 | 
			
		||||
        .receive_cb = handle_unload }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum signal_index {
 | 
			
		||||
    SIGNAL_PROPERTY_LIST_UPDATED,
 | 
			
		||||
    SIGNAL_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_arg_info property_list_updated_args[] =  { { "property_list", "a{say}", NULL } };
 | 
			
		||||
 | 
			
		||||
static pa_dbus_signal_info signals[SIGNAL_MAX] = {
 | 
			
		||||
    [SIGNAL_PROPERTY_LIST_UPDATED] = { .name = "PropertyListUpdated", .arguments = property_list_updated_args, .n_arguments = 1 }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_interface_info module_interface_info = {
 | 
			
		||||
    .name = PA_DBUSIFACE_MODULE_INTERFACE,
 | 
			
		||||
    .method_handlers = method_handlers,
 | 
			
		||||
    .n_method_handlers = METHOD_HANDLER_MAX,
 | 
			
		||||
    .property_handlers = property_handlers,
 | 
			
		||||
    .n_property_handlers = PROPERTY_HANDLER_MAX,
 | 
			
		||||
    .get_all_properties_cb = handle_get_all,
 | 
			
		||||
    .signals = signals,
 | 
			
		||||
    .n_signals = SIGNAL_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_module *m = userdata;
 | 
			
		||||
    dbus_uint32_t idx = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    idx = m->module->index;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &idx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_module *m = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &m->module->name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void append_modargs_variant(DBusMessageIter *iter, pa_dbusiface_module *m) {
 | 
			
		||||
    pa_modargs *ma = NULL;
 | 
			
		||||
    DBusMessageIter variant_iter;
 | 
			
		||||
    DBusMessageIter dict_iter;
 | 
			
		||||
    DBusMessageIter dict_entry_iter;
 | 
			
		||||
    void *state = NULL;
 | 
			
		||||
    const char *key = NULL;
 | 
			
		||||
    const char *value = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(iter);
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(ma = pa_modargs_new(m->module->argument, NULL));
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{ss}", &variant_iter));
 | 
			
		||||
    pa_assert_se(dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY, "{ss}", &dict_iter));
 | 
			
		||||
 | 
			
		||||
    for (state = NULL, key = pa_modargs_iterate(ma, &state); key; key = pa_modargs_iterate(ma, &state)) {
 | 
			
		||||
        pa_assert_se(value = pa_modargs_get_value(ma, key, NULL));
 | 
			
		||||
 | 
			
		||||
        pa_assert_se(dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
 | 
			
		||||
 | 
			
		||||
        pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
 | 
			
		||||
        pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &value));
 | 
			
		||||
 | 
			
		||||
        pa_assert_se(dbus_message_iter_close_container(&dict_iter, &dict_entry_iter));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_close_container(&variant_iter, &dict_iter));
 | 
			
		||||
    pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
 | 
			
		||||
 | 
			
		||||
    pa_modargs_free(ma);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_arguments(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_module *m = userdata;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(reply = dbus_message_new_method_return(msg));
 | 
			
		||||
    dbus_message_iter_init_append(reply, &msg_iter);
 | 
			
		||||
    append_modargs_variant(&msg_iter, m);
 | 
			
		||||
    pa_assert_se(dbus_connection_send(conn, reply, NULL));
 | 
			
		||||
    dbus_message_unref(reply);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_usage_counter(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_module *m = userdata;
 | 
			
		||||
    int real_counter_value = -1;
 | 
			
		||||
    dbus_uint32_t usage_counter = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    if (!m->module->get_n_used || (real_counter_value = m->module->get_n_used(m->module)) < 0) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
 | 
			
		||||
                           "Module %u (%s) doesn't have a usage counter.", m->module->index, m->module->name);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    usage_counter = real_counter_value;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &usage_counter);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_module *m = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_proplist_variant_reply(conn, msg, m->proplist);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_module *m = userdata;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
    DBusMessageIter dict_iter;
 | 
			
		||||
    DBusMessageIter dict_entry_iter;
 | 
			
		||||
    dbus_uint32_t idx = 0;
 | 
			
		||||
    int real_counter_value = -1;
 | 
			
		||||
    dbus_uint32_t usage_counter = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    idx = m->module->index;
 | 
			
		||||
    if (m->module->get_n_used && (real_counter_value = m->module->get_n_used(m->module)) >= 0)
 | 
			
		||||
        usage_counter = real_counter_value;
 | 
			
		||||
 | 
			
		||||
    pa_assert_se((reply = dbus_message_new_method_return(msg)));
 | 
			
		||||
 | 
			
		||||
    dbus_message_iter_init_append(reply, &msg_iter);
 | 
			
		||||
    pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
 | 
			
		||||
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &idx);
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_NAME].property_name, DBUS_TYPE_STRING, &m->module->name);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
 | 
			
		||||
    pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &property_handlers[PROPERTY_HANDLER_ARGUMENTS].property_name));
 | 
			
		||||
    append_modargs_variant(&dict_entry_iter, m);
 | 
			
		||||
    pa_assert_se(dbus_message_iter_close_container(&dict_iter, &dict_entry_iter));
 | 
			
		||||
 | 
			
		||||
    if (real_counter_value >= 0)
 | 
			
		||||
        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_ARGUMENTS].property_name, DBUS_TYPE_UINT32, &usage_counter);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_append_proplist_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PROPERTY_LIST].property_name, m->proplist);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_connection_send(conn, reply, NULL));
 | 
			
		||||
 | 
			
		||||
    dbus_message_unref(reply);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_unload(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_module *m = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    if (m->module->core->disallow_module_loading) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, DBUS_ERROR_ACCESS_DENIED, "The server is configured to disallow module unloading.");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_module_unload_request(m->module, FALSE);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_empty_reply(conn, msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void subscription_cb(pa_core *core, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
 | 
			
		||||
    pa_dbusiface_module *m = userdata;
 | 
			
		||||
    DBusMessage *signal = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(core);
 | 
			
		||||
    pa_assert((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_MODULE);
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    /* We can't use idx != m->module->index, because the m->module pointer may
 | 
			
		||||
     * be stale at this point. */
 | 
			
		||||
    if (pa_idxset_get_by_index(core->modules, idx) != m->module)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (!pa_proplist_equal(m->proplist, m->module->proplist)) {
 | 
			
		||||
        DBusMessageIter msg_iter;
 | 
			
		||||
 | 
			
		||||
        pa_proplist_update(m->proplist, PA_UPDATE_SET, m->module->proplist);
 | 
			
		||||
 | 
			
		||||
        pa_assert_se(signal = dbus_message_new_signal(m->path,
 | 
			
		||||
                                                      PA_DBUSIFACE_MODULE_INTERFACE,
 | 
			
		||||
                                                      signals[SIGNAL_PROPERTY_LIST_UPDATED].name));
 | 
			
		||||
        dbus_message_iter_init_append(signal, &msg_iter);
 | 
			
		||||
        pa_dbus_append_proplist(&msg_iter, m->proplist);
 | 
			
		||||
 | 
			
		||||
        pa_dbus_protocol_send_signal(m->dbus_protocol, signal);
 | 
			
		||||
        dbus_message_unref(signal);
 | 
			
		||||
        signal = NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pa_dbusiface_module *pa_dbusiface_module_new(pa_module *module) {
 | 
			
		||||
    pa_dbusiface_module *m;
 | 
			
		||||
 | 
			
		||||
    pa_assert(module);
 | 
			
		||||
 | 
			
		||||
    m = pa_xnew0(pa_dbusiface_module, 1);
 | 
			
		||||
    m->module = module;
 | 
			
		||||
    m->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, OBJECT_NAME, module->index);
 | 
			
		||||
    m->proplist = pa_proplist_copy(module->proplist);
 | 
			
		||||
    m->dbus_protocol = pa_dbus_protocol_get(module->core);
 | 
			
		||||
    m->subscription = pa_subscription_new(module->core, PA_SUBSCRIPTION_MASK_MODULE, subscription_cb, m);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(pa_dbus_protocol_add_interface(m->dbus_protocol, m->path, &module_interface_info, m) >= 0);
 | 
			
		||||
 | 
			
		||||
    return m;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbusiface_module_free(pa_dbusiface_module *m) {
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(pa_dbus_protocol_remove_interface(m->dbus_protocol, m->path, module_interface_info.name) >= 0);
 | 
			
		||||
 | 
			
		||||
    pa_proplist_free(m->proplist);
 | 
			
		||||
    pa_dbus_protocol_unref(m->dbus_protocol);
 | 
			
		||||
    pa_subscription_free(m->subscription);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(m->path);
 | 
			
		||||
    pa_xfree(m);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *pa_dbusiface_module_get_path(pa_dbusiface_module *m) {
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    return m->path;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								src/modules/dbus/iface-module.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/modules/dbus/iface-module.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
#ifndef foodbusifacemodulehfoo
 | 
			
		||||
#define foodbusifacemodulehfoo
 | 
			
		||||
 | 
			
		||||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
/* This object implements the D-Bus interface org.PulseAudio.Core1.Module.
 | 
			
		||||
 *
 | 
			
		||||
 * See http://pulseaudio.org/wiki/DBusInterface for the Module interface
 | 
			
		||||
 * documentation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/module.h>
 | 
			
		||||
#include <pulsecore/protocol-dbus.h>
 | 
			
		||||
 | 
			
		||||
#include "iface-core.h"
 | 
			
		||||
 | 
			
		||||
#define PA_DBUSIFACE_MODULE_INTERFACE PA_DBUS_CORE_INTERFACE ".Module"
 | 
			
		||||
 | 
			
		||||
typedef struct pa_dbusiface_module pa_dbusiface_module;
 | 
			
		||||
 | 
			
		||||
pa_dbusiface_module *pa_dbusiface_module_new(pa_module *module);
 | 
			
		||||
void pa_dbusiface_module_free(pa_dbusiface_module *m);
 | 
			
		||||
 | 
			
		||||
const char *pa_dbusiface_module_get_path(pa_dbusiface_module *m);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										519
									
								
								src/modules/dbus/iface-sample.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										519
									
								
								src/modules/dbus/iface-sample.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,519 @@
 | 
			
		|||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#include <config.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/core-util.h>
 | 
			
		||||
#include <pulsecore/dbus-util.h>
 | 
			
		||||
#include <pulsecore/namereg.h>
 | 
			
		||||
#include <pulsecore/protocol-dbus.h>
 | 
			
		||||
 | 
			
		||||
#include "iface-sample.h"
 | 
			
		||||
 | 
			
		||||
#define OBJECT_NAME "sample"
 | 
			
		||||
 | 
			
		||||
struct pa_dbusiface_sample {
 | 
			
		||||
    pa_dbusiface_core *core;
 | 
			
		||||
 | 
			
		||||
    pa_scache_entry *sample;
 | 
			
		||||
    char *path;
 | 
			
		||||
    pa_proplist *proplist;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_protocol *dbus_protocol;
 | 
			
		||||
    pa_subscription *subscription;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_default_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_duration(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_bytes(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
static void handle_play(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_play_to_sink(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_remove(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
enum property_handler_index {
 | 
			
		||||
    PROPERTY_HANDLER_INDEX,
 | 
			
		||||
    PROPERTY_HANDLER_NAME,
 | 
			
		||||
    PROPERTY_HANDLER_SAMPLE_FORMAT,
 | 
			
		||||
    PROPERTY_HANDLER_SAMPLE_RATE,
 | 
			
		||||
    PROPERTY_HANDLER_CHANNELS,
 | 
			
		||||
    PROPERTY_HANDLER_DEFAULT_VOLUME,
 | 
			
		||||
    PROPERTY_HANDLER_DURATION,
 | 
			
		||||
    PROPERTY_HANDLER_BYTES,
 | 
			
		||||
    PROPERTY_HANDLER_PROPERTY_LIST,
 | 
			
		||||
    PROPERTY_HANDLER_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = {
 | 
			
		||||
    [PROPERTY_HANDLER_INDEX]          = { .property_name = "Index",         .type = "u",      .get_cb = handle_get_index,          .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_NAME]           = { .property_name = "Name",          .type = "s",      .get_cb = handle_get_name,           .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_SAMPLE_FORMAT]  = { .property_name = "SampleFormat",  .type = "u",      .get_cb = handle_get_sample_format,  .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_SAMPLE_RATE]    = { .property_name = "SampleRate",    .type = "u",      .get_cb = handle_get_sample_rate,    .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_CHANNELS]       = { .property_name = "Channels",      .type = "au",     .get_cb = handle_get_channels,       .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_DEFAULT_VOLUME] = { .property_name = "DefaultVolume", .type = "au",     .get_cb = handle_get_default_volume, .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_DURATION]       = { .property_name = "Duration",      .type = "t",      .get_cb = handle_get_duration,       .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_BYTES]          = { .property_name = "Bytes",         .type = "u",      .get_cb = handle_get_bytes,          .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_PROPERTY_LIST]  = { .property_name = "PropertyList",  .type = "a{say}", .get_cb = handle_get_property_list,  .set_cb = NULL }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum method_handler_index {
 | 
			
		||||
    METHOD_HANDLER_PLAY,
 | 
			
		||||
    METHOD_HANDLER_PLAY_TO_SINK,
 | 
			
		||||
    METHOD_HANDLER_REMOVE,
 | 
			
		||||
    METHOD_HANDLER_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_arg_info play_args[] = { { "volume", "u", "in" }, { "property_list", "a{say}", "in" } };
 | 
			
		||||
static pa_dbus_arg_info play_to_sink_args[] = { { "sink",          "o",      "in" },
 | 
			
		||||
                                                { "volume",        "u",      "in" },
 | 
			
		||||
                                                { "property_list", "a{say}", "in" } };
 | 
			
		||||
 | 
			
		||||
static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
 | 
			
		||||
    [METHOD_HANDLER_PLAY] = {
 | 
			
		||||
        .method_name = "Play",
 | 
			
		||||
        .arguments = play_args,
 | 
			
		||||
        .n_arguments = sizeof(play_args) / sizeof(pa_dbus_arg_info),
 | 
			
		||||
        .receive_cb = handle_play },
 | 
			
		||||
    [METHOD_HANDLER_PLAY_TO_SINK] = {
 | 
			
		||||
        .method_name = "PlayToSink",
 | 
			
		||||
        .arguments = play_to_sink_args,
 | 
			
		||||
        .n_arguments = sizeof(play_to_sink_args) / sizeof(pa_dbus_arg_info),
 | 
			
		||||
        .receive_cb = handle_play_to_sink },
 | 
			
		||||
    [METHOD_HANDLER_REMOVE] = {
 | 
			
		||||
        .method_name = "Remove",
 | 
			
		||||
        .arguments = NULL,
 | 
			
		||||
        .n_arguments = 0,
 | 
			
		||||
        .receive_cb = handle_remove }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum signal_index {
 | 
			
		||||
    SIGNAL_PROPERTY_LIST_UPDATED,
 | 
			
		||||
    SIGNAL_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_arg_info property_list_updated_args[] = { { "property_list", "a{say}", NULL } };
 | 
			
		||||
 | 
			
		||||
static pa_dbus_signal_info signals[SIGNAL_MAX] = {
 | 
			
		||||
    [SIGNAL_PROPERTY_LIST_UPDATED] = { .name = "PropertyListUpdated", .arguments = property_list_updated_args, .n_arguments = 1 }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_interface_info sample_interface_info = {
 | 
			
		||||
    .name = PA_DBUSIFACE_SAMPLE_INTERFACE,
 | 
			
		||||
    .method_handlers = method_handlers,
 | 
			
		||||
    .n_method_handlers = METHOD_HANDLER_MAX,
 | 
			
		||||
    .property_handlers = property_handlers,
 | 
			
		||||
    .n_property_handlers = PROPERTY_HANDLER_MAX,
 | 
			
		||||
    .get_all_properties_cb = handle_get_all,
 | 
			
		||||
    .signals = signals,
 | 
			
		||||
    .n_signals = SIGNAL_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_sample *s = userdata;
 | 
			
		||||
    dbus_uint32_t idx = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    idx = s->sample->index;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &idx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_name(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_sample *s = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &s->sample->name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_sample *s = userdata;
 | 
			
		||||
    dbus_uint32_t sample_format = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if (!s->sample->memchunk.memblock) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
 | 
			
		||||
                           "Sample %s isn't loaded into memory yet, so its sample format is unknown.", s->sample->name);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sample_format = s->sample->sample_spec.format;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &sample_format);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_sample *s = userdata;
 | 
			
		||||
    dbus_uint32_t sample_rate = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if (!s->sample->memchunk.memblock) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
 | 
			
		||||
                           "Sample %s isn't loaded into memory yet, so its sample rate is unknown.", s->sample->name);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    sample_rate = s->sample->sample_spec.rate;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &sample_rate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_sample *s = userdata;
 | 
			
		||||
    dbus_uint32_t channels[PA_CHANNELS_MAX];
 | 
			
		||||
    unsigned i = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if (!s->sample->memchunk.memblock) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
 | 
			
		||||
                           "Sample %s isn't loaded into memory yet, so its channel map is unknown.", s->sample->name);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < s->sample->channel_map.channels; ++i)
 | 
			
		||||
        channels[i] = s->sample->channel_map.map[i];
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, channels, s->sample->channel_map.channels);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_default_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_sample *s = userdata;
 | 
			
		||||
    dbus_uint32_t default_volume[PA_CHANNELS_MAX];
 | 
			
		||||
    unsigned i = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if (!s->sample->volume_is_set) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
 | 
			
		||||
                           "Sample %s doesn't have default volume stored.", s->sample->name);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < s->sample->volume.channels; ++i)
 | 
			
		||||
        default_volume[i] = s->sample->volume.values[i];
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, default_volume, s->sample->volume.channels);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_duration(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_sample *s = userdata;
 | 
			
		||||
    dbus_uint64_t duration = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if (!s->sample->memchunk.memblock) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
 | 
			
		||||
                           "Sample %s isn't loaded into memory yet, so its duration is unknown.", s->sample->name);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    duration = pa_bytes_to_usec(s->sample->memchunk.length, &s->sample->sample_spec);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &duration);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_bytes(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_sample *s = userdata;
 | 
			
		||||
    dbus_uint32_t bytes = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if (!s->sample->memchunk.memblock) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
 | 
			
		||||
                           "Sample %s isn't loaded into memory yet, so its size is unknown.", s->sample->name);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bytes = s->sample->memchunk.length;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &bytes);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_sample *s = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_proplist_variant_reply(conn, msg, s->proplist);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_sample *s = userdata;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
    DBusMessageIter dict_iter;
 | 
			
		||||
    dbus_uint32_t idx = 0;
 | 
			
		||||
    dbus_uint32_t sample_format = 0;
 | 
			
		||||
    dbus_uint32_t sample_rate = 0;
 | 
			
		||||
    dbus_uint32_t channels[PA_CHANNELS_MAX];
 | 
			
		||||
    dbus_uint32_t default_volume[PA_CHANNELS_MAX];
 | 
			
		||||
    dbus_uint64_t duration = 0;
 | 
			
		||||
    dbus_uint32_t bytes = 0;
 | 
			
		||||
    unsigned i = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    idx = s->sample->index;
 | 
			
		||||
    if (s->sample->memchunk.memblock) {
 | 
			
		||||
        sample_format = s->sample->sample_spec.format;
 | 
			
		||||
        sample_rate = s->sample->sample_spec.rate;
 | 
			
		||||
        for (i = 0; i < s->sample->channel_map.channels; ++i)
 | 
			
		||||
            channels[i] = s->sample->channel_map.map[i];
 | 
			
		||||
        duration = pa_bytes_to_usec(s->sample->memchunk.length, &s->sample->sample_spec);
 | 
			
		||||
        bytes = s->sample->memchunk.length;
 | 
			
		||||
    }
 | 
			
		||||
    if (s->sample->volume_is_set) {
 | 
			
		||||
        for (i = 0; i < s->sample->volume.channels; ++i)
 | 
			
		||||
            default_volume[i] = s->sample->volume.values[i];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_assert_se((reply = dbus_message_new_method_return(msg)));
 | 
			
		||||
 | 
			
		||||
    dbus_message_iter_init_append(reply, &msg_iter);
 | 
			
		||||
    pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
 | 
			
		||||
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &idx);
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_NAME].property_name, DBUS_TYPE_STRING, &s->sample->name);
 | 
			
		||||
 | 
			
		||||
    if (s->sample->memchunk.memblock) {
 | 
			
		||||
        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_FORMAT].property_name, DBUS_TYPE_UINT32, &sample_format);
 | 
			
		||||
        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_RATE].property_name, DBUS_TYPE_UINT32, &sample_rate);
 | 
			
		||||
        pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CHANNELS].property_name, DBUS_TYPE_UINT32, channels, s->sample->channel_map.channels);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (s->sample->volume_is_set)
 | 
			
		||||
        pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEFAULT_VOLUME].property_name, DBUS_TYPE_UINT32, default_volume, s->sample->volume.channels);
 | 
			
		||||
 | 
			
		||||
    if (s->sample->memchunk.memblock) {
 | 
			
		||||
        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DURATION].property_name, DBUS_TYPE_UINT64, &duration);
 | 
			
		||||
        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_BYTES].property_name, DBUS_TYPE_UINT32, &bytes);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_dbus_append_proplist_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PROPERTY_LIST].property_name, s->proplist);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
 | 
			
		||||
    pa_assert_se(dbus_connection_send(conn, reply, NULL));
 | 
			
		||||
    dbus_message_unref(reply);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_play(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_sample *s = userdata;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
    dbus_uint32_t volume = 0;
 | 
			
		||||
    pa_proplist *property_list = NULL;
 | 
			
		||||
    pa_sink *sink = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_init(msg, &msg_iter));
 | 
			
		||||
    dbus_message_iter_get_basic(&msg_iter, &volume);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_next(&msg_iter));
 | 
			
		||||
    if (!(property_list = pa_dbus_get_proplist_arg(conn, msg, &msg_iter)))
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (volume > PA_VOLUME_MAX) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid volume.");
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!(sink = pa_namereg_get_default_sink(s->sample->core))) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED,
 | 
			
		||||
                           "Can't play sample %s, because there are no sinks available.", s->sample->name);
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (pa_scache_play_item(s->sample->core, s->sample->name, sink, volume, property_list, NULL) < 0) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "Playing sample %s failed.", s->sample->name);
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_empty_reply(conn, msg);
 | 
			
		||||
 | 
			
		||||
finish:
 | 
			
		||||
    if (property_list)
 | 
			
		||||
        pa_proplist_free(property_list);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_play_to_sink(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_sample *s = userdata;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
    const char *sink_path = NULL;
 | 
			
		||||
    dbus_uint32_t volume = 0;
 | 
			
		||||
    pa_proplist *property_list = NULL;
 | 
			
		||||
    pa_sink *sink = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_init(msg, &msg_iter));
 | 
			
		||||
    dbus_message_iter_get_basic(&msg_iter, &sink_path);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_next(&msg_iter));
 | 
			
		||||
    dbus_message_iter_get_basic(&msg_iter, &volume);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_next(&msg_iter));
 | 
			
		||||
    if (!(property_list = pa_dbus_get_proplist_arg(conn, msg, &msg_iter)))
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (!(sink = pa_dbusiface_core_get_sink(s->core, sink_path))) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such sink.", sink_path);
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (volume > PA_VOLUME_MAX) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid volume.");
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (pa_scache_play_item(s->sample->core, s->sample->name, sink, volume, property_list, NULL) < 0) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "Playing sample %s failed.", s->sample->name);
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_empty_reply(conn, msg);
 | 
			
		||||
 | 
			
		||||
finish:
 | 
			
		||||
    if (property_list)
 | 
			
		||||
        pa_proplist_free(property_list);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_remove(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_sample *s = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if (pa_scache_remove_item(s->sample->core, s->sample->name) < 0) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "Removing sample %s failed.", s->sample->name);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_empty_reply(conn, msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
 | 
			
		||||
    pa_dbusiface_sample *s = userdata;
 | 
			
		||||
    DBusMessage *signal = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    /* We can't use idx != s->sample->index, because the s->sample pointer may
 | 
			
		||||
     * be stale at this point. */
 | 
			
		||||
    if (pa_idxset_get_by_index(c->scache, idx) != s->sample)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (!pa_proplist_equal(s->proplist, s->sample->proplist)) {
 | 
			
		||||
        DBusMessageIter msg_iter;
 | 
			
		||||
 | 
			
		||||
        pa_proplist_update(s->proplist, PA_UPDATE_SET, s->sample->proplist);
 | 
			
		||||
 | 
			
		||||
        pa_assert_se(signal = dbus_message_new_signal(s->path,
 | 
			
		||||
                                                      PA_DBUSIFACE_SAMPLE_INTERFACE,
 | 
			
		||||
                                                      signals[SIGNAL_PROPERTY_LIST_UPDATED].name));
 | 
			
		||||
        dbus_message_iter_init_append(signal, &msg_iter);
 | 
			
		||||
        pa_dbus_append_proplist(&msg_iter, s->proplist);
 | 
			
		||||
 | 
			
		||||
        pa_dbus_protocol_send_signal(s->dbus_protocol, signal);
 | 
			
		||||
        dbus_message_unref(signal);
 | 
			
		||||
        signal = NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pa_dbusiface_sample *pa_dbusiface_sample_new(pa_dbusiface_core *core, pa_scache_entry *sample) {
 | 
			
		||||
    pa_dbusiface_sample *s = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(core);
 | 
			
		||||
    pa_assert(sample);
 | 
			
		||||
 | 
			
		||||
    s = pa_xnew0(pa_dbusiface_sample, 1);
 | 
			
		||||
    s->core = core;
 | 
			
		||||
    s->sample = sample;
 | 
			
		||||
    s->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, OBJECT_NAME, sample->index);
 | 
			
		||||
    s->proplist = pa_proplist_copy(sample->proplist);
 | 
			
		||||
    s->dbus_protocol = pa_dbus_protocol_get(sample->core);
 | 
			
		||||
    s->subscription = pa_subscription_new(sample->core, PA_SUBSCRIPTION_MASK_SAMPLE_CACHE, subscription_cb, s);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &sample_interface_info, s) >= 0);
 | 
			
		||||
 | 
			
		||||
    return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbusiface_sample_free(pa_dbusiface_sample *s) {
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(pa_dbus_protocol_remove_interface(s->dbus_protocol, s->path, sample_interface_info.name) >= 0);
 | 
			
		||||
 | 
			
		||||
    pa_proplist_free(s->proplist);
 | 
			
		||||
    pa_dbus_protocol_unref(s->dbus_protocol);
 | 
			
		||||
    pa_subscription_free(s->subscription);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(s->path);
 | 
			
		||||
    pa_xfree(s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *pa_dbusiface_sample_get_path(pa_dbusiface_sample *s) {
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    return s->path;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								src/modules/dbus/iface-sample.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/modules/dbus/iface-sample.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
#ifndef foodbusifacesamplehfoo
 | 
			
		||||
#define foodbusifacesamplehfoo
 | 
			
		||||
 | 
			
		||||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
/* This object implements the D-Bus interface org.PulseAudio.Core1.Sample.
 | 
			
		||||
 *
 | 
			
		||||
 * See http://pulseaudio.org/wiki/DBusInterface for the Sample interface
 | 
			
		||||
 * documentation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/core-scache.h>
 | 
			
		||||
#include <pulsecore/protocol-dbus.h>
 | 
			
		||||
 | 
			
		||||
#include "iface-core.h"
 | 
			
		||||
 | 
			
		||||
#define PA_DBUSIFACE_SAMPLE_INTERFACE PA_DBUS_CORE_INTERFACE ".Sample"
 | 
			
		||||
 | 
			
		||||
typedef struct pa_dbusiface_sample pa_dbusiface_sample;
 | 
			
		||||
 | 
			
		||||
pa_dbusiface_sample *pa_dbusiface_sample_new(pa_dbusiface_core *core, pa_scache_entry *sample);
 | 
			
		||||
void pa_dbusiface_sample_free(pa_dbusiface_sample *c);
 | 
			
		||||
 | 
			
		||||
const char *pa_dbusiface_sample_get_path(pa_dbusiface_sample *c);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										894
									
								
								src/modules/dbus/iface-stream.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										894
									
								
								src/modules/dbus/iface-stream.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,894 @@
 | 
			
		|||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
  Copyright 2009 Vincent Filali-Ansary <filali.v@azurdigitalnetworks.net>
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#include <config.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/core-util.h>
 | 
			
		||||
#include <pulsecore/dbus-util.h>
 | 
			
		||||
#include <pulsecore/protocol-dbus.h>
 | 
			
		||||
 | 
			
		||||
#include "iface-stream.h"
 | 
			
		||||
 | 
			
		||||
#define PLAYBACK_OBJECT_NAME "playback_stream"
 | 
			
		||||
#define RECORD_OBJECT_NAME "record_stream"
 | 
			
		||||
 | 
			
		||||
enum stream_type {
 | 
			
		||||
    STREAM_TYPE_PLAYBACK,
 | 
			
		||||
    STREAM_TYPE_RECORD
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct pa_dbusiface_stream {
 | 
			
		||||
    pa_dbusiface_core *core;
 | 
			
		||||
 | 
			
		||||
    union {
 | 
			
		||||
        pa_sink_input *sink_input;
 | 
			
		||||
        pa_source_output *source_output;
 | 
			
		||||
    };
 | 
			
		||||
    enum stream_type type;
 | 
			
		||||
    char *path;
 | 
			
		||||
    union {
 | 
			
		||||
        pa_sink *sink;
 | 
			
		||||
        pa_source *source;
 | 
			
		||||
    };
 | 
			
		||||
    uint32_t sample_rate;
 | 
			
		||||
    pa_cvolume volume;
 | 
			
		||||
    dbus_bool_t mute;
 | 
			
		||||
    pa_proplist *proplist;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_protocol *dbus_protocol;
 | 
			
		||||
    pa_subscription *subscription;
 | 
			
		||||
    pa_hook_slot *send_event_slot;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_client(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
 | 
			
		||||
static void handle_get_mute(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_set_mute(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
 | 
			
		||||
static void handle_get_buffer_latency(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_device_latency(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_resample_method(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
static void handle_move(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
static void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
enum property_handler_index {
 | 
			
		||||
    PROPERTY_HANDLER_INDEX,
 | 
			
		||||
    PROPERTY_HANDLER_DRIVER,
 | 
			
		||||
    PROPERTY_HANDLER_OWNER_MODULE,
 | 
			
		||||
    PROPERTY_HANDLER_CLIENT,
 | 
			
		||||
    PROPERTY_HANDLER_DEVICE,
 | 
			
		||||
    PROPERTY_HANDLER_SAMPLE_FORMAT,
 | 
			
		||||
    PROPERTY_HANDLER_SAMPLE_RATE,
 | 
			
		||||
    PROPERTY_HANDLER_CHANNELS,
 | 
			
		||||
    PROPERTY_HANDLER_VOLUME,
 | 
			
		||||
    PROPERTY_HANDLER_MUTE,
 | 
			
		||||
    PROPERTY_HANDLER_BUFFER_LATENCY,
 | 
			
		||||
    PROPERTY_HANDLER_DEVICE_LATENCY,
 | 
			
		||||
    PROPERTY_HANDLER_RESAMPLE_METHOD,
 | 
			
		||||
    PROPERTY_HANDLER_PROPERTY_LIST,
 | 
			
		||||
    PROPERTY_HANDLER_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = {
 | 
			
		||||
    [PROPERTY_HANDLER_INDEX]           = { .property_name = "Index",          .type = "u",      .get_cb = handle_get_index,           .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_DRIVER]          = { .property_name = "Driver",         .type = "s",      .get_cb = handle_get_driver,          .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_OWNER_MODULE]    = { .property_name = "OwnerModule",    .type = "o",      .get_cb = handle_get_owner_module,    .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_CLIENT]          = { .property_name = "Client",         .type = "o",      .get_cb = handle_get_client,          .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_DEVICE]          = { .property_name = "Device",         .type = "o",      .get_cb = handle_get_device,          .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_SAMPLE_FORMAT]   = { .property_name = "SampleFormat",   .type = "u",      .get_cb = handle_get_sample_format,   .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_SAMPLE_RATE]     = { .property_name = "SampleRate",     .type = "u",      .get_cb = handle_get_sample_rate,     .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_CHANNELS]        = { .property_name = "Channels",       .type = "au",     .get_cb = handle_get_channels,        .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_VOLUME]          = { .property_name = "Volume",         .type = "au",     .get_cb = handle_get_volume,          .set_cb = handle_set_volume },
 | 
			
		||||
    [PROPERTY_HANDLER_MUTE]            = { .property_name = "Mute",           .type = "b",      .get_cb = handle_get_mute,            .set_cb = handle_set_mute },
 | 
			
		||||
    [PROPERTY_HANDLER_BUFFER_LATENCY]  = { .property_name = "BufferLatency",  .type = "t",      .get_cb = handle_get_buffer_latency,  .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_DEVICE_LATENCY]  = { .property_name = "DeviceLatency",  .type = "t",      .get_cb = handle_get_device_latency,  .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_RESAMPLE_METHOD] = { .property_name = "ResampleMethod", .type = "s",      .get_cb = handle_get_resample_method, .set_cb = NULL },
 | 
			
		||||
    [PROPERTY_HANDLER_PROPERTY_LIST]   = { .property_name = "PropertyList",   .type = "a{say}", .get_cb = handle_get_property_list,   .set_cb = NULL }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum method_handler_index {
 | 
			
		||||
    METHOD_HANDLER_MOVE,
 | 
			
		||||
    METHOD_HANDLER_KILL,
 | 
			
		||||
    METHOD_HANDLER_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_arg_info move_args[] = { { "device", "o", "in" } };
 | 
			
		||||
 | 
			
		||||
static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
 | 
			
		||||
    [METHOD_HANDLER_MOVE] = {
 | 
			
		||||
        .method_name = "Move",
 | 
			
		||||
        .arguments = move_args,
 | 
			
		||||
        .n_arguments = sizeof(move_args) / sizeof(pa_dbus_arg_info),
 | 
			
		||||
        .receive_cb = handle_move },
 | 
			
		||||
    [METHOD_HANDLER_KILL] = {
 | 
			
		||||
        .method_name = "Kill",
 | 
			
		||||
        .arguments = NULL,
 | 
			
		||||
        .n_arguments = 0,
 | 
			
		||||
        .receive_cb = handle_kill }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum signal_index {
 | 
			
		||||
    SIGNAL_DEVICE_UPDATED,
 | 
			
		||||
    SIGNAL_SAMPLE_RATE_UPDATED,
 | 
			
		||||
    SIGNAL_VOLUME_UPDATED,
 | 
			
		||||
    SIGNAL_MUTE_UPDATED,
 | 
			
		||||
    SIGNAL_PROPERTY_LIST_UPDATED,
 | 
			
		||||
    SIGNAL_STREAM_EVENT,
 | 
			
		||||
    SIGNAL_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_arg_info device_updated_args[]        = { { "device",        "o",      NULL } };
 | 
			
		||||
static pa_dbus_arg_info sample_rate_updated_args[]   = { { "sample_rate",   "u",      NULL } };
 | 
			
		||||
static pa_dbus_arg_info volume_updated_args[]        = { { "volume",        "au",     NULL } };
 | 
			
		||||
static pa_dbus_arg_info mute_updated_args[]          = { { "muted",         "b",      NULL } };
 | 
			
		||||
static pa_dbus_arg_info property_list_updated_args[] = { { "property_list", "a{say}", NULL } };
 | 
			
		||||
static pa_dbus_arg_info stream_event_args[]          = { { "name",          "s",      NULL }, { "property_list", "a{say}", NULL } };
 | 
			
		||||
 | 
			
		||||
static pa_dbus_signal_info signals[SIGNAL_MAX] = {
 | 
			
		||||
    [SIGNAL_DEVICE_UPDATED]        = { .name = "DeviceUpdated",       .arguments = device_updated_args,        .n_arguments = 1 },
 | 
			
		||||
    [SIGNAL_SAMPLE_RATE_UPDATED]   = { .name = "SampleRateUpdated",   .arguments = sample_rate_updated_args,   .n_arguments = 1 },
 | 
			
		||||
    [SIGNAL_VOLUME_UPDATED]        = { .name = "VolumeUpdated",       .arguments = volume_updated_args,        .n_arguments = 1 },
 | 
			
		||||
    [SIGNAL_MUTE_UPDATED]          = { .name = "MuteUpdated",         .arguments = mute_updated_args,          .n_arguments = 1 },
 | 
			
		||||
    [SIGNAL_PROPERTY_LIST_UPDATED] = { .name = "PropertyListUpdated", .arguments = property_list_updated_args, .n_arguments = 1 },
 | 
			
		||||
    [SIGNAL_STREAM_EVENT]          = { .name = "StreamEvent",         .arguments = stream_event_args,          .n_arguments = sizeof(stream_event_args) / sizeof(pa_dbus_arg_info) }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static pa_dbus_interface_info stream_interface_info = {
 | 
			
		||||
    .name = PA_DBUSIFACE_STREAM_INTERFACE,
 | 
			
		||||
    .method_handlers = method_handlers,
 | 
			
		||||
    .n_method_handlers = METHOD_HANDLER_MAX,
 | 
			
		||||
    .property_handlers = property_handlers,
 | 
			
		||||
    .n_property_handlers = PROPERTY_HANDLER_MAX,
 | 
			
		||||
    .get_all_properties_cb = handle_get_all,
 | 
			
		||||
    .signals = signals,
 | 
			
		||||
    .n_signals = SIGNAL_MAX
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_stream *s = userdata;
 | 
			
		||||
    dbus_uint32_t idx;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    idx = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->index : s->source_output->index;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &idx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_stream *s = userdata;
 | 
			
		||||
    const char *driver = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    driver = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->driver : s->source_output->driver;
 | 
			
		||||
 | 
			
		||||
    if (!driver) {
 | 
			
		||||
        if (s->type == STREAM_TYPE_PLAYBACK)
 | 
			
		||||
            pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
 | 
			
		||||
                               "Playback stream %u doesn't have a driver.", s->sink_input->index);
 | 
			
		||||
        else
 | 
			
		||||
            pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
 | 
			
		||||
                               "Record stream %u doesn't have a driver.", s->source_output->index);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &driver);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_stream *s = userdata;
 | 
			
		||||
    pa_module *owner_module = NULL;
 | 
			
		||||
    const char *object_path = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    owner_module = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->module : s->source_output->module;
 | 
			
		||||
 | 
			
		||||
    if (!owner_module) {
 | 
			
		||||
        if (s->type == STREAM_TYPE_PLAYBACK)
 | 
			
		||||
            pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
 | 
			
		||||
                               "Playback stream %u doesn't have an owner module.", s->sink_input->index);
 | 
			
		||||
        else
 | 
			
		||||
            pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
 | 
			
		||||
                               "Record stream %u doesn't have an owner module.", s->source_output->index);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    object_path = pa_dbusiface_core_get_module_path(s->core, owner_module);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_client(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_stream *s = userdata;
 | 
			
		||||
    pa_client *client = NULL;
 | 
			
		||||
    const char *object_path = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    client = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->client : s->source_output->client;
 | 
			
		||||
 | 
			
		||||
    if (!client) {
 | 
			
		||||
        if (s->type == STREAM_TYPE_PLAYBACK)
 | 
			
		||||
            pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
 | 
			
		||||
                               "Playback stream %u isn't associated to any client.", s->sink_input->index);
 | 
			
		||||
        else
 | 
			
		||||
            pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
 | 
			
		||||
                               "Record stream %u isn't associated to any client.", s->source_output->index);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    object_path = pa_dbusiface_core_get_client_path(s->core, client);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_stream *s = userdata;
 | 
			
		||||
    const char *device = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if (s->type == STREAM_TYPE_PLAYBACK)
 | 
			
		||||
        device = pa_dbusiface_core_get_sink_path(s->core, s->sink);
 | 
			
		||||
    else
 | 
			
		||||
        device = pa_dbusiface_core_get_source_path(s->core, s->source);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &device);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_stream *s = userdata;
 | 
			
		||||
    dbus_uint32_t sample_format = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    sample_format = (s->type == STREAM_TYPE_PLAYBACK)
 | 
			
		||||
                    ? s->sink_input->sample_spec.format
 | 
			
		||||
                    : s->source_output->sample_spec.format;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &sample_format);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_stream *s = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &s->sample_rate);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_stream *s = userdata;
 | 
			
		||||
    pa_channel_map *channel_map = NULL;
 | 
			
		||||
    dbus_uint32_t channels[PA_CHANNELS_MAX];
 | 
			
		||||
    unsigned i = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    channel_map = (s->type == STREAM_TYPE_PLAYBACK) ? &s->sink_input->channel_map : &s->source_output->channel_map;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < channel_map->channels; ++i)
 | 
			
		||||
        channels[i] = channel_map->map[i];
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, channels, channel_map->channels);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_stream *s = userdata;
 | 
			
		||||
    dbus_uint32_t volume[PA_CHANNELS_MAX];
 | 
			
		||||
    unsigned i = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if (s->type == STREAM_TYPE_RECORD) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have volume.");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < s->volume.channels; ++i)
 | 
			
		||||
        volume[i] = s->volume.values[i];
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, volume, s->volume.channels);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
 | 
			
		||||
    pa_dbusiface_stream *s = userdata;
 | 
			
		||||
    DBusMessageIter array_iter;
 | 
			
		||||
    int stream_channels = 0;
 | 
			
		||||
    dbus_uint32_t *volume = NULL;
 | 
			
		||||
    int n_volume_entries = 0;
 | 
			
		||||
    pa_cvolume new_vol;
 | 
			
		||||
    int i = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(iter);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if (s->type == STREAM_TYPE_RECORD) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have volume.");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_cvolume_init(&new_vol);
 | 
			
		||||
 | 
			
		||||
    stream_channels = s->sink_input->channel_map.channels;
 | 
			
		||||
 | 
			
		||||
    new_vol.channels = stream_channels;
 | 
			
		||||
 | 
			
		||||
    dbus_message_iter_recurse(iter, &array_iter);
 | 
			
		||||
    dbus_message_iter_get_fixed_array(&array_iter, &volume, &n_volume_entries);
 | 
			
		||||
 | 
			
		||||
    if (n_volume_entries != stream_channels) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
 | 
			
		||||
                           "Expected %u volume entries, got %u.", stream_channels, n_volume_entries);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < n_volume_entries; ++i) {
 | 
			
		||||
        if (volume[i] > PA_VOLUME_MAX) {
 | 
			
		||||
            pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Too large volume value: %u", volume[i]);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        new_vol.values[i] = volume[i];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_sink_input_set_volume(s->sink_input, &new_vol, TRUE, TRUE);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_empty_reply(conn, msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_mute(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_stream *s = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if (s->type == STREAM_TYPE_RECORD) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have mute.");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_BOOLEAN, &s->mute);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_set_mute(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
 | 
			
		||||
    pa_dbusiface_stream *s = userdata;
 | 
			
		||||
    dbus_bool_t mute = FALSE;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(iter);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    dbus_message_iter_get_basic(iter, &mute);
 | 
			
		||||
 | 
			
		||||
    if (s->type == STREAM_TYPE_RECORD) {
 | 
			
		||||
        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have mute.");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_sink_input_set_mute(s->sink_input, mute, TRUE);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_empty_reply(conn, msg);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void handle_get_buffer_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_stream *s = userdata;
 | 
			
		||||
    dbus_uint64_t buffer_latency = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if (s->type == STREAM_TYPE_PLAYBACK)
 | 
			
		||||
        buffer_latency = pa_sink_input_get_latency(s->sink_input, NULL);
 | 
			
		||||
    else
 | 
			
		||||
        buffer_latency = pa_source_output_get_latency(s->source_output, NULL);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &buffer_latency);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_device_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_stream *s = userdata;
 | 
			
		||||
    dbus_uint64_t device_latency = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if (s->type == STREAM_TYPE_PLAYBACK)
 | 
			
		||||
        pa_sink_input_get_latency(s->sink_input, &device_latency);
 | 
			
		||||
    else
 | 
			
		||||
        pa_source_output_get_latency(s->source_output, &device_latency);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &device_latency);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_resample_method(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_stream *s = userdata;
 | 
			
		||||
    const char *resample_method = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if (s->type == STREAM_TYPE_PLAYBACK)
 | 
			
		||||
        resample_method = pa_resample_method_to_string(s->sink_input->actual_resample_method);
 | 
			
		||||
    else
 | 
			
		||||
        resample_method = pa_resample_method_to_string(s->source_output->actual_resample_method);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &resample_method);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_stream *s = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_proplist_variant_reply(conn, msg, s->proplist);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_stream *s = userdata;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
    DBusMessageIter dict_iter;
 | 
			
		||||
    dbus_uint32_t idx = 0;
 | 
			
		||||
    const char *driver = NULL;
 | 
			
		||||
    pa_module *owner_module = NULL;
 | 
			
		||||
    const char *owner_module_path = NULL;
 | 
			
		||||
    pa_client *client = NULL;
 | 
			
		||||
    const char *client_path = NULL;
 | 
			
		||||
    const char *device = NULL;
 | 
			
		||||
    dbus_uint32_t sample_format = 0;
 | 
			
		||||
    pa_channel_map *channel_map = NULL;
 | 
			
		||||
    dbus_uint32_t channels[PA_CHANNELS_MAX];
 | 
			
		||||
    dbus_uint32_t volume[PA_CHANNELS_MAX];
 | 
			
		||||
    dbus_uint64_t buffer_latency = 0;
 | 
			
		||||
    dbus_uint64_t device_latency = 0;
 | 
			
		||||
    const char *resample_method = NULL;
 | 
			
		||||
    unsigned i = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if (s->type == STREAM_TYPE_PLAYBACK) {
 | 
			
		||||
        idx = s->sink_input->index;
 | 
			
		||||
        driver = s->sink_input->driver;
 | 
			
		||||
        owner_module = s->sink_input->module;
 | 
			
		||||
        client = s->sink_input->client;
 | 
			
		||||
        device = pa_dbusiface_core_get_sink_path(s->core, s->sink);
 | 
			
		||||
        sample_format = s->sink_input->sample_spec.format;
 | 
			
		||||
        channel_map = &s->sink_input->channel_map;
 | 
			
		||||
        for (i = 0; i < s->volume.channels; ++i)
 | 
			
		||||
            volume[i] = s->volume.values[i];
 | 
			
		||||
        buffer_latency = pa_sink_input_get_latency(s->sink_input, &device_latency);
 | 
			
		||||
        resample_method = pa_resample_method_to_string(s->sink_input->actual_resample_method);
 | 
			
		||||
    } else {
 | 
			
		||||
        idx = s->source_output->index;
 | 
			
		||||
        driver = s->source_output->driver;
 | 
			
		||||
        owner_module = s->source_output->module;
 | 
			
		||||
        client = s->source_output->client;
 | 
			
		||||
        device = pa_dbusiface_core_get_source_path(s->core, s->source);
 | 
			
		||||
        sample_format = s->source_output->sample_spec.format;
 | 
			
		||||
        channel_map = &s->source_output->channel_map;
 | 
			
		||||
        buffer_latency = pa_source_output_get_latency(s->source_output, &device_latency);
 | 
			
		||||
        resample_method = pa_resample_method_to_string(s->source_output->actual_resample_method);
 | 
			
		||||
    }
 | 
			
		||||
    if (owner_module)
 | 
			
		||||
        owner_module_path = pa_dbusiface_core_get_module_path(s->core, owner_module);
 | 
			
		||||
    if (client)
 | 
			
		||||
        client_path = pa_dbusiface_core_get_client_path(s->core, client);
 | 
			
		||||
    for (i = 0; i < channel_map->channels; ++i)
 | 
			
		||||
        channels[i] = channel_map->map[i];
 | 
			
		||||
 | 
			
		||||
    pa_assert_se((reply = dbus_message_new_method_return(msg)));
 | 
			
		||||
 | 
			
		||||
    dbus_message_iter_init_append(reply, &msg_iter);
 | 
			
		||||
    pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter));
 | 
			
		||||
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &idx);
 | 
			
		||||
 | 
			
		||||
    if (driver)
 | 
			
		||||
        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DRIVER].property_name, DBUS_TYPE_STRING, &driver);
 | 
			
		||||
 | 
			
		||||
    if (owner_module)
 | 
			
		||||
        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_OWNER_MODULE].property_name, DBUS_TYPE_OBJECT_PATH, &owner_module_path);
 | 
			
		||||
 | 
			
		||||
    if (client)
 | 
			
		||||
        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CLIENT].property_name, DBUS_TYPE_OBJECT_PATH, &client_path);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_FORMAT].property_name, DBUS_TYPE_UINT32, &sample_format);
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_RATE].property_name, DBUS_TYPE_UINT32, &s->sample_rate);
 | 
			
		||||
    pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CHANNELS].property_name, DBUS_TYPE_UINT32, channels, channel_map->channels);
 | 
			
		||||
 | 
			
		||||
    if (s->type == STREAM_TYPE_PLAYBACK) {
 | 
			
		||||
        pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_VOLUME].property_name, DBUS_TYPE_UINT32, volume, s->volume.channels);
 | 
			
		||||
        pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_MUTE].property_name, DBUS_TYPE_BOOLEAN, &s->mute);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_BUFFER_LATENCY].property_name, DBUS_TYPE_UINT64, &buffer_latency);
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEVICE_LATENCY].property_name, DBUS_TYPE_UINT64, &device_latency);
 | 
			
		||||
    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_RESAMPLE_METHOD].property_name, DBUS_TYPE_STRING, &resample_method);
 | 
			
		||||
    pa_dbus_append_proplist_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PROPERTY_LIST].property_name, s->proplist);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
 | 
			
		||||
    pa_assert_se(dbus_connection_send(conn, reply, NULL));
 | 
			
		||||
    dbus_message_unref(reply);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_move(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_stream *s = userdata;
 | 
			
		||||
    const char *device = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &device, DBUS_TYPE_INVALID));
 | 
			
		||||
 | 
			
		||||
    if (s->type == STREAM_TYPE_PLAYBACK) {
 | 
			
		||||
        pa_sink *sink = pa_dbusiface_core_get_sink(s->core, device);
 | 
			
		||||
 | 
			
		||||
        if (!sink) {
 | 
			
		||||
            pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such sink.", device);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (pa_sink_input_move_to(s->sink_input, sink, TRUE) < 0) {
 | 
			
		||||
            pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED,
 | 
			
		||||
                               "Moving playback stream %u to sink %s failed.", s->sink_input->index, sink->name);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        pa_source *source = pa_dbusiface_core_get_source(s->core, device);
 | 
			
		||||
 | 
			
		||||
        if (!source) {
 | 
			
		||||
            pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such source.", device);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (pa_source_output_move_to(s->source_output, source, TRUE) < 0) {
 | 
			
		||||
            pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED,
 | 
			
		||||
                               "Moving record stream %u to source %s failed.", s->source_output->index, source->name);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_empty_reply(conn, msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata) {
 | 
			
		||||
    pa_dbusiface_stream *s = userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if (s->type == STREAM_TYPE_PLAYBACK)
 | 
			
		||||
        pa_sink_input_kill(s->sink_input);
 | 
			
		||||
    else
 | 
			
		||||
        pa_source_output_kill(s->source_output);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_send_empty_reply(conn, msg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
 | 
			
		||||
    pa_dbusiface_stream *s = userdata;
 | 
			
		||||
    DBusMessage *signal = NULL;
 | 
			
		||||
    const char *new_device_path = NULL;
 | 
			
		||||
    uint32_t new_sample_rate = 0;
 | 
			
		||||
    pa_proplist *new_proplist = NULL;
 | 
			
		||||
    unsigned i = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if ((s->type == STREAM_TYPE_PLAYBACK && idx != s->sink_input->index)
 | 
			
		||||
        || (s->type == STREAM_TYPE_RECORD && idx != s->source_output->index))
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    pa_assert(((s->type == STREAM_TYPE_PLAYBACK)
 | 
			
		||||
                && ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT))
 | 
			
		||||
              || ((s->type == STREAM_TYPE_RECORD)
 | 
			
		||||
                   && ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT)));
 | 
			
		||||
 | 
			
		||||
    if (s->type == STREAM_TYPE_PLAYBACK) {
 | 
			
		||||
        pa_sink *new_sink = s->sink_input->sink;
 | 
			
		||||
 | 
			
		||||
        if (s->sink != new_sink) {
 | 
			
		||||
            pa_sink_unref(s->sink);
 | 
			
		||||
            s->sink = pa_sink_ref(new_sink);
 | 
			
		||||
 | 
			
		||||
            new_device_path = pa_dbusiface_core_get_sink_path(s->core, new_sink);
 | 
			
		||||
 | 
			
		||||
            pa_assert_se(signal = dbus_message_new_signal(s->path,
 | 
			
		||||
                                                          PA_DBUSIFACE_STREAM_INTERFACE,
 | 
			
		||||
                                                          signals[SIGNAL_DEVICE_UPDATED].name));
 | 
			
		||||
            pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID));
 | 
			
		||||
 | 
			
		||||
            pa_dbus_protocol_send_signal(s->dbus_protocol, signal);
 | 
			
		||||
            dbus_message_unref(signal);
 | 
			
		||||
            signal = NULL;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        pa_source *new_source = s->source_output->source;
 | 
			
		||||
 | 
			
		||||
        if (s->source != new_source) {
 | 
			
		||||
            pa_source_unref(s->source);
 | 
			
		||||
            s->source = pa_source_ref(new_source);
 | 
			
		||||
 | 
			
		||||
            new_device_path = pa_dbusiface_core_get_source_path(s->core, new_source);
 | 
			
		||||
 | 
			
		||||
            pa_assert_se(signal = dbus_message_new_signal(s->path,
 | 
			
		||||
                                                          PA_DBUSIFACE_STREAM_INTERFACE,
 | 
			
		||||
                                                          signals[SIGNAL_DEVICE_UPDATED].name));
 | 
			
		||||
            pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID));
 | 
			
		||||
 | 
			
		||||
            pa_dbus_protocol_send_signal(s->dbus_protocol, signal);
 | 
			
		||||
            dbus_message_unref(signal);
 | 
			
		||||
            signal = NULL;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    new_sample_rate = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->sample_spec.rate : s->source_output->sample_spec.rate;
 | 
			
		||||
 | 
			
		||||
    if (s->sample_rate != new_sample_rate) {
 | 
			
		||||
        s->sample_rate = new_sample_rate;
 | 
			
		||||
 | 
			
		||||
        pa_assert_se(signal = dbus_message_new_signal(s->path,
 | 
			
		||||
                                                      PA_DBUSIFACE_STREAM_INTERFACE,
 | 
			
		||||
                                                      signals[SIGNAL_SAMPLE_RATE_UPDATED].name));
 | 
			
		||||
        pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_UINT32, &s->sample_rate, DBUS_TYPE_INVALID));
 | 
			
		||||
 | 
			
		||||
        pa_dbus_protocol_send_signal(s->dbus_protocol, signal);
 | 
			
		||||
        dbus_message_unref(signal);
 | 
			
		||||
        signal = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (s->type == STREAM_TYPE_PLAYBACK) {
 | 
			
		||||
        pa_cvolume new_volume;
 | 
			
		||||
        pa_bool_t new_mute = FALSE;
 | 
			
		||||
 | 
			
		||||
        pa_sink_input_get_volume(s->sink_input, &new_volume, TRUE);
 | 
			
		||||
 | 
			
		||||
        if (!pa_cvolume_equal(&s->volume, &new_volume)) {
 | 
			
		||||
            dbus_uint32_t volume[PA_CHANNELS_MAX];
 | 
			
		||||
            dbus_uint32_t *volume_ptr = volume;
 | 
			
		||||
 | 
			
		||||
            s->volume = new_volume;
 | 
			
		||||
 | 
			
		||||
            for (i = 0; i < s->volume.channels; ++i)
 | 
			
		||||
                volume[i] = s->volume.values[i];
 | 
			
		||||
 | 
			
		||||
            pa_assert_se(signal = dbus_message_new_signal(s->path,
 | 
			
		||||
                                                          PA_DBUSIFACE_STREAM_INTERFACE,
 | 
			
		||||
                                                          signals[SIGNAL_VOLUME_UPDATED].name));
 | 
			
		||||
            pa_assert_se(dbus_message_append_args(signal,
 | 
			
		||||
                                                  DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &volume_ptr, s->volume.channels,
 | 
			
		||||
                                                  DBUS_TYPE_INVALID));
 | 
			
		||||
 | 
			
		||||
            pa_dbus_protocol_send_signal(s->dbus_protocol, signal);
 | 
			
		||||
            dbus_message_unref(signal);
 | 
			
		||||
            signal = NULL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        new_mute = pa_sink_input_get_mute(s->sink_input);
 | 
			
		||||
 | 
			
		||||
        if (s->mute != new_mute) {
 | 
			
		||||
            s->mute = new_mute;
 | 
			
		||||
 | 
			
		||||
            pa_assert_se(signal = dbus_message_new_signal(s->path,
 | 
			
		||||
                                                          PA_DBUSIFACE_STREAM_INTERFACE,
 | 
			
		||||
                                                          signals[SIGNAL_MUTE_UPDATED].name));
 | 
			
		||||
            pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_BOOLEAN, &s->mute, DBUS_TYPE_INVALID));
 | 
			
		||||
 | 
			
		||||
            pa_dbus_protocol_send_signal(s->dbus_protocol, signal);
 | 
			
		||||
            dbus_message_unref(signal);
 | 
			
		||||
            signal = NULL;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    new_proplist = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->proplist : s->source_output->proplist;
 | 
			
		||||
 | 
			
		||||
    if (!pa_proplist_equal(s->proplist, new_proplist)) {
 | 
			
		||||
        DBusMessageIter msg_iter;
 | 
			
		||||
 | 
			
		||||
        pa_proplist_update(s->proplist, PA_UPDATE_SET, new_proplist);
 | 
			
		||||
 | 
			
		||||
        pa_assert_se(signal = dbus_message_new_signal(s->path,
 | 
			
		||||
                                                      PA_DBUSIFACE_STREAM_INTERFACE,
 | 
			
		||||
                                                      signals[SIGNAL_PROPERTY_LIST_UPDATED].name));
 | 
			
		||||
        dbus_message_iter_init_append(signal, &msg_iter);
 | 
			
		||||
        pa_dbus_append_proplist(&msg_iter, s->proplist);
 | 
			
		||||
 | 
			
		||||
        pa_dbus_protocol_send_signal(s->dbus_protocol, signal);
 | 
			
		||||
        dbus_message_unref(signal);
 | 
			
		||||
        signal = NULL;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static pa_hook_result_t send_event_cb(void *hook_data, void *call_data, void *slot_data) {
 | 
			
		||||
    pa_dbusiface_stream *s = slot_data;
 | 
			
		||||
    DBusMessage *signal = NULL;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
    const char *name = NULL;
 | 
			
		||||
    pa_proplist *property_list = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(call_data);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if (s->type == STREAM_TYPE_PLAYBACK) {
 | 
			
		||||
        pa_sink_input_send_event_hook_data *data = call_data;
 | 
			
		||||
 | 
			
		||||
        if (data->sink_input != s->sink_input)
 | 
			
		||||
            return PA_HOOK_OK;
 | 
			
		||||
 | 
			
		||||
        name = data->event;
 | 
			
		||||
        property_list = data->data;
 | 
			
		||||
    } else {
 | 
			
		||||
        pa_source_output_send_event_hook_data *data = call_data;
 | 
			
		||||
 | 
			
		||||
        if (data->source_output != s->source_output)
 | 
			
		||||
            return PA_HOOK_OK;
 | 
			
		||||
 | 
			
		||||
        name = data->event;
 | 
			
		||||
        property_list = data->data;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(signal = dbus_message_new_signal(s->path,
 | 
			
		||||
                                                  PA_DBUSIFACE_STREAM_INTERFACE,
 | 
			
		||||
                                                  signals[SIGNAL_STREAM_EVENT].name));
 | 
			
		||||
    dbus_message_iter_init_append(signal, &msg_iter);
 | 
			
		||||
    pa_assert_se(dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name));
 | 
			
		||||
    pa_dbus_append_proplist(&msg_iter, property_list);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_protocol_send_signal(s->dbus_protocol, signal);
 | 
			
		||||
    dbus_message_unref(signal);
 | 
			
		||||
 | 
			
		||||
    return PA_HOOK_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pa_dbusiface_stream *pa_dbusiface_stream_new_playback(pa_dbusiface_core *core, pa_sink_input *sink_input) {
 | 
			
		||||
    pa_dbusiface_stream *s;
 | 
			
		||||
 | 
			
		||||
    pa_assert(core);
 | 
			
		||||
    pa_assert(sink_input);
 | 
			
		||||
 | 
			
		||||
    s = pa_xnew(pa_dbusiface_stream, 1);
 | 
			
		||||
    s->core = core;
 | 
			
		||||
    s->sink_input = pa_sink_input_ref(sink_input);
 | 
			
		||||
    s->type = STREAM_TYPE_PLAYBACK;
 | 
			
		||||
    s->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, PLAYBACK_OBJECT_NAME, sink_input->index);
 | 
			
		||||
    s->sink = pa_sink_ref(sink_input->sink);
 | 
			
		||||
    s->sample_rate = sink_input->sample_spec.rate;
 | 
			
		||||
    pa_sink_input_get_volume(sink_input, &s->volume, TRUE);
 | 
			
		||||
    s->mute = pa_sink_input_get_mute(sink_input);
 | 
			
		||||
    s->proplist = pa_proplist_copy(sink_input->proplist);
 | 
			
		||||
    s->dbus_protocol = pa_dbus_protocol_get(sink_input->core);
 | 
			
		||||
    s->subscription = pa_subscription_new(sink_input->core, PA_SUBSCRIPTION_MASK_SINK_INPUT, subscription_cb, s);
 | 
			
		||||
    s->send_event_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_SEND_EVENT],
 | 
			
		||||
                                         PA_HOOK_NORMAL,
 | 
			
		||||
                                         send_event_cb,
 | 
			
		||||
                                         s);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &stream_interface_info, s) >= 0);
 | 
			
		||||
 | 
			
		||||
    return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pa_dbusiface_stream *pa_dbusiface_stream_new_record(pa_dbusiface_core *core, pa_source_output *source_output) {
 | 
			
		||||
    pa_dbusiface_stream *s;
 | 
			
		||||
 | 
			
		||||
    pa_assert(core);
 | 
			
		||||
    pa_assert(source_output);
 | 
			
		||||
 | 
			
		||||
    s = pa_xnew(pa_dbusiface_stream, 1);
 | 
			
		||||
    s->core = core;
 | 
			
		||||
    s->source_output = pa_source_output_ref(source_output);
 | 
			
		||||
    s->type = STREAM_TYPE_RECORD;
 | 
			
		||||
    s->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, RECORD_OBJECT_NAME, source_output->index);
 | 
			
		||||
    s->source = pa_source_ref(source_output->source);
 | 
			
		||||
    s->sample_rate = source_output->sample_spec.rate;
 | 
			
		||||
    pa_cvolume_init(&s->volume);
 | 
			
		||||
    s->mute = FALSE;
 | 
			
		||||
    s->proplist = pa_proplist_copy(source_output->proplist);
 | 
			
		||||
    s->dbus_protocol = pa_dbus_protocol_get(source_output->core);
 | 
			
		||||
    s->subscription = pa_subscription_new(source_output->core, PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscription_cb, s);
 | 
			
		||||
    s->send_event_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_SEND_EVENT],
 | 
			
		||||
                                         PA_HOOK_NORMAL,
 | 
			
		||||
                                         send_event_cb,
 | 
			
		||||
                                         s);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &stream_interface_info, s) >= 0);
 | 
			
		||||
 | 
			
		||||
    return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbusiface_stream_free(pa_dbusiface_stream *s) {
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(pa_dbus_protocol_remove_interface(s->dbus_protocol, s->path, stream_interface_info.name) >= 0);
 | 
			
		||||
 | 
			
		||||
    if (s->type == STREAM_TYPE_PLAYBACK) {
 | 
			
		||||
        pa_sink_input_unref(s->sink_input);
 | 
			
		||||
        pa_sink_unref(s->sink);
 | 
			
		||||
    } else {
 | 
			
		||||
        pa_source_output_unref(s->source_output);
 | 
			
		||||
        pa_source_unref(s->source);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_proplist_free(s->proplist);
 | 
			
		||||
    pa_dbus_protocol_unref(s->dbus_protocol);
 | 
			
		||||
    pa_subscription_free(s->subscription);
 | 
			
		||||
    pa_hook_slot_free(s->send_event_slot);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(s->path);
 | 
			
		||||
    pa_xfree(s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *pa_dbusiface_stream_get_path(pa_dbusiface_stream *s) {
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    return s->path;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										47
									
								
								src/modules/dbus/iface-stream.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/modules/dbus/iface-stream.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,47 @@
 | 
			
		|||
#ifndef foodbusifacestreamhfoo
 | 
			
		||||
#define foodbusifacestreamhfoo
 | 
			
		||||
 | 
			
		||||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
/* This object implements the D-Bus interface org.PulseAudio.Core1.Stream.
 | 
			
		||||
 *
 | 
			
		||||
 * See http://pulseaudio.org/wiki/DBusInterface for the Stream interface
 | 
			
		||||
 * documentation.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/protocol-dbus.h>
 | 
			
		||||
#include <pulsecore/sink-input.h>
 | 
			
		||||
#include <pulsecore/source-output.h>
 | 
			
		||||
 | 
			
		||||
#include "iface-core.h"
 | 
			
		||||
 | 
			
		||||
#define PA_DBUSIFACE_STREAM_INTERFACE PA_DBUS_CORE_INTERFACE ".Stream"
 | 
			
		||||
 | 
			
		||||
typedef struct pa_dbusiface_stream pa_dbusiface_stream;
 | 
			
		||||
 | 
			
		||||
pa_dbusiface_stream *pa_dbusiface_stream_new_playback(pa_dbusiface_core *core, pa_sink_input *sink_input);
 | 
			
		||||
pa_dbusiface_stream *pa_dbusiface_stream_new_record(pa_dbusiface_core *core, pa_source_output *source_output);
 | 
			
		||||
void pa_dbusiface_stream_free(pa_dbusiface_stream *s);
 | 
			
		||||
 | 
			
		||||
const char *pa_dbusiface_stream_get_path(pa_dbusiface_stream *s);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										607
									
								
								src/modules/dbus/module-dbus-protocol.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										607
									
								
								src/modules/dbus/module-dbus-protocol.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,607 @@
 | 
			
		|||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
  Copyright 2006 Lennart Poettering
 | 
			
		||||
  Copyright 2006 Shams E. King
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#include <config.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <dbus/dbus.h>
 | 
			
		||||
 | 
			
		||||
#include <pulse/mainloop-api.h>
 | 
			
		||||
#include <pulse/timeval.h>
 | 
			
		||||
#include <pulse/xmalloc.h>
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/client.h>
 | 
			
		||||
#include <pulsecore/core-util.h>
 | 
			
		||||
#include <pulsecore/dbus-util.h>
 | 
			
		||||
#include <pulsecore/idxset.h>
 | 
			
		||||
#include <pulsecore/macro.h>
 | 
			
		||||
#include <pulsecore/modargs.h>
 | 
			
		||||
#include <pulsecore/module.h>
 | 
			
		||||
#include <pulsecore/protocol-dbus.h>
 | 
			
		||||
 | 
			
		||||
#include "iface-client.h"
 | 
			
		||||
#include "iface-core.h"
 | 
			
		||||
 | 
			
		||||
#include "module-dbus-protocol-symdef.h"
 | 
			
		||||
 | 
			
		||||
PA_MODULE_DESCRIPTION("D-Bus interface");
 | 
			
		||||
PA_MODULE_USAGE(
 | 
			
		||||
        "access=local|remote|local,remote "
 | 
			
		||||
        "tcp_port=<port number>");
 | 
			
		||||
PA_MODULE_LOAD_ONCE(TRUE);
 | 
			
		||||
PA_MODULE_AUTHOR("Tanu Kaskinen");
 | 
			
		||||
PA_MODULE_VERSION(PACKAGE_VERSION);
 | 
			
		||||
 | 
			
		||||
#define CLEANUP_INTERVAL 10 /* seconds */
 | 
			
		||||
 | 
			
		||||
enum server_type {
 | 
			
		||||
    SERVER_TYPE_LOCAL,
 | 
			
		||||
    SERVER_TYPE_TCP
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct server;
 | 
			
		||||
struct connection;
 | 
			
		||||
 | 
			
		||||
struct userdata {
 | 
			
		||||
    pa_module *module;
 | 
			
		||||
    pa_bool_t local_access;
 | 
			
		||||
    pa_bool_t remote_access;
 | 
			
		||||
    uint32_t tcp_port;
 | 
			
		||||
 | 
			
		||||
    struct server *local_server;
 | 
			
		||||
    struct server *tcp_server;
 | 
			
		||||
 | 
			
		||||
    pa_idxset *connections;
 | 
			
		||||
 | 
			
		||||
    pa_time_event *cleanup_event;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_protocol *dbus_protocol;
 | 
			
		||||
    pa_dbusiface_core *core_iface;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct server {
 | 
			
		||||
    struct userdata *userdata;
 | 
			
		||||
    enum server_type type;
 | 
			
		||||
    DBusServer *dbus_server;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct connection {
 | 
			
		||||
    struct server *server;
 | 
			
		||||
    pa_dbus_wrap_connection *wrap_conn;
 | 
			
		||||
    pa_client *client;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const char* const valid_modargs[] = {
 | 
			
		||||
    "access",
 | 
			
		||||
    "tcp_port",
 | 
			
		||||
    NULL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void connection_free(struct connection *c) {
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(pa_dbus_protocol_unregister_connection(c->server->userdata->dbus_protocol, pa_dbus_wrap_connection_get(c->wrap_conn)) >= 0);
 | 
			
		||||
 | 
			
		||||
    pa_client_free(c->client);
 | 
			
		||||
    pa_assert_se(pa_idxset_remove_by_data(c->server->userdata->connections, c, NULL));
 | 
			
		||||
    pa_dbus_wrap_connection_free(c->wrap_conn);
 | 
			
		||||
    pa_xfree(c);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called from pa_client_kill(). */
 | 
			
		||||
static void client_kill_cb(pa_client *c) {
 | 
			
		||||
    struct connection *conn;
 | 
			
		||||
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
    pa_assert(c->userdata);
 | 
			
		||||
 | 
			
		||||
    conn = c->userdata;
 | 
			
		||||
    connection_free(conn);
 | 
			
		||||
    c->userdata = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_log_info("Connection killed.");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called from pa_client_send_event(). */
 | 
			
		||||
static void client_send_event_cb(pa_client *c, const char *name, pa_proplist *data) {
 | 
			
		||||
    struct connection *conn = NULL;
 | 
			
		||||
    DBusMessage *signal = NULL;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
    pa_assert(name);
 | 
			
		||||
    pa_assert(data);
 | 
			
		||||
    pa_assert(c->userdata);
 | 
			
		||||
 | 
			
		||||
    conn = c->userdata;
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(signal = dbus_message_new_signal(pa_dbusiface_core_get_client_path(conn->server->userdata->core_iface, c),
 | 
			
		||||
                                                  PA_DBUSIFACE_CLIENT_INTERFACE,
 | 
			
		||||
                                                  "ClientEvent"));
 | 
			
		||||
    dbus_message_iter_init_append(signal, &msg_iter);
 | 
			
		||||
    pa_assert_se(dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name));
 | 
			
		||||
    pa_dbus_append_proplist(&msg_iter, data);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_connection_send(pa_dbus_wrap_connection_get(conn->wrap_conn), signal, NULL));
 | 
			
		||||
    dbus_message_unref(signal);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called by D-Bus at the authentication phase. */
 | 
			
		||||
static dbus_bool_t user_check_cb(DBusConnection *connection, unsigned long uid, void *data) {
 | 
			
		||||
    pa_log_debug("Allowing connection by user %lu.", uid);
 | 
			
		||||
 | 
			
		||||
    return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called by D-Bus when a new client connection is received. */
 | 
			
		||||
static void connection_new_cb(DBusServer *dbus_server, DBusConnection *new_connection, void *data) {
 | 
			
		||||
    struct server *s = data;
 | 
			
		||||
    struct connection *c;
 | 
			
		||||
    pa_client_new_data new_data;
 | 
			
		||||
    pa_client *client;
 | 
			
		||||
 | 
			
		||||
    pa_assert(new_connection);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    pa_client_new_data_init(&new_data);
 | 
			
		||||
    new_data.module = s->userdata->module;
 | 
			
		||||
    new_data.driver = __FILE__;
 | 
			
		||||
    pa_proplist_sets(new_data.proplist, PA_PROP_APPLICATION_NAME, "D-Bus client");
 | 
			
		||||
    client = pa_client_new(s->userdata->module->core, &new_data);
 | 
			
		||||
    pa_client_new_data_done(&new_data);
 | 
			
		||||
 | 
			
		||||
    if (!client) {
 | 
			
		||||
        dbus_connection_close(new_connection);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (s->type == SERVER_TYPE_TCP || s->userdata->module->core->server_type == PA_SERVER_TYPE_SYSTEM) {
 | 
			
		||||
        /* FIXME: Here we allow anyone from anywhere to access the server,
 | 
			
		||||
         * anonymously. Access control should be configurable. */
 | 
			
		||||
        dbus_connection_set_unix_user_function(new_connection, user_check_cb, NULL, NULL);
 | 
			
		||||
        dbus_connection_set_allow_anonymous(new_connection, TRUE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    c = pa_xnew(struct connection, 1);
 | 
			
		||||
    c->server = s;
 | 
			
		||||
    c->wrap_conn = pa_dbus_wrap_connection_new_from_existing(s->userdata->module->core->mainloop, TRUE, new_connection);
 | 
			
		||||
    c->client = client;
 | 
			
		||||
 | 
			
		||||
    c->client->kill = client_kill_cb;
 | 
			
		||||
    c->client->send_event = client_send_event_cb;
 | 
			
		||||
    c->client->userdata = c;
 | 
			
		||||
 | 
			
		||||
    pa_idxset_put(s->userdata->connections, c, NULL);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(pa_dbus_protocol_register_connection(s->userdata->dbus_protocol, new_connection, c->client) >= 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called by PA mainloop when a D-Bus fd watch event needs handling. */
 | 
			
		||||
static void io_event_cb(pa_mainloop_api *mainloop, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
 | 
			
		||||
    unsigned int flags = 0;
 | 
			
		||||
    DBusWatch *watch = userdata;
 | 
			
		||||
 | 
			
		||||
#if HAVE_DBUS_WATCH_GET_UNIX_FD
 | 
			
		||||
    pa_assert(fd == dbus_watch_get_unix_fd(watch));
 | 
			
		||||
#else
 | 
			
		||||
    pa_assert(fd == dbus_watch_get_fd(watch));
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    if (!dbus_watch_get_enabled(watch)) {
 | 
			
		||||
        pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch, fd);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (events & PA_IO_EVENT_INPUT)
 | 
			
		||||
        flags |= DBUS_WATCH_READABLE;
 | 
			
		||||
    if (events & PA_IO_EVENT_OUTPUT)
 | 
			
		||||
        flags |= DBUS_WATCH_WRITABLE;
 | 
			
		||||
    if (events & PA_IO_EVENT_HANGUP)
 | 
			
		||||
        flags |= DBUS_WATCH_HANGUP;
 | 
			
		||||
    if (events & PA_IO_EVENT_ERROR)
 | 
			
		||||
        flags |= DBUS_WATCH_ERROR;
 | 
			
		||||
 | 
			
		||||
    dbus_watch_handle(watch, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called by PA mainloop when a D-Bus timer event needs handling. */
 | 
			
		||||
static void time_event_cb(pa_mainloop_api *mainloop, pa_time_event* e, const struct timeval *tv, void *userdata) {
 | 
			
		||||
    DBusTimeout *timeout = userdata;
 | 
			
		||||
 | 
			
		||||
    if (dbus_timeout_get_enabled(timeout)) {
 | 
			
		||||
        struct timeval next = *tv;
 | 
			
		||||
        dbus_timeout_handle(timeout);
 | 
			
		||||
 | 
			
		||||
        /* restart it for the next scheduled time */
 | 
			
		||||
        pa_timeval_add(&next, (pa_usec_t) dbus_timeout_get_interval(timeout) * 1000);
 | 
			
		||||
        mainloop->time_restart(e, &next);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Translates D-Bus fd watch event flags to PA IO event flags. */
 | 
			
		||||
static pa_io_event_flags_t get_watch_flags(DBusWatch *watch) {
 | 
			
		||||
    unsigned int flags;
 | 
			
		||||
    pa_io_event_flags_t events = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(watch);
 | 
			
		||||
 | 
			
		||||
    flags = dbus_watch_get_flags(watch);
 | 
			
		||||
 | 
			
		||||
    /* no watch flags for disabled watches */
 | 
			
		||||
    if (!dbus_watch_get_enabled(watch))
 | 
			
		||||
        return PA_IO_EVENT_NULL;
 | 
			
		||||
 | 
			
		||||
    if (flags & DBUS_WATCH_READABLE)
 | 
			
		||||
        events |= PA_IO_EVENT_INPUT;
 | 
			
		||||
    if (flags & DBUS_WATCH_WRITABLE)
 | 
			
		||||
        events |= PA_IO_EVENT_OUTPUT;
 | 
			
		||||
 | 
			
		||||
    return events | PA_IO_EVENT_HANGUP | PA_IO_EVENT_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called by D-Bus when a D-Bus fd watch event is added. */
 | 
			
		||||
static dbus_bool_t watch_add_cb(DBusWatch *watch, void *data) {
 | 
			
		||||
    struct server *s = data;
 | 
			
		||||
    pa_mainloop_api *mainloop;
 | 
			
		||||
    pa_io_event *ev;
 | 
			
		||||
 | 
			
		||||
    pa_assert(watch);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    mainloop = s->userdata->module->core->mainloop;
 | 
			
		||||
 | 
			
		||||
    ev = mainloop->io_new(
 | 
			
		||||
            mainloop,
 | 
			
		||||
#if HAVE_DBUS_WATCH_GET_UNIX_FD
 | 
			
		||||
            dbus_watch_get_unix_fd(watch),
 | 
			
		||||
#else
 | 
			
		||||
            dbus_watch_get_fd(watch),
 | 
			
		||||
#endif
 | 
			
		||||
            get_watch_flags(watch), io_event_cb, watch);
 | 
			
		||||
 | 
			
		||||
    dbus_watch_set_data(watch, ev, NULL);
 | 
			
		||||
 | 
			
		||||
    return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called by D-Bus when a D-Bus fd watch event is removed. */
 | 
			
		||||
static void watch_remove_cb(DBusWatch *watch, void *data) {
 | 
			
		||||
    struct server *s = data;
 | 
			
		||||
    pa_io_event *ev;
 | 
			
		||||
 | 
			
		||||
    pa_assert(watch);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if ((ev = dbus_watch_get_data(watch)))
 | 
			
		||||
        s->userdata->module->core->mainloop->io_free(ev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called by D-Bus when a D-Bus fd watch event is toggled. */
 | 
			
		||||
static void watch_toggled_cb(DBusWatch *watch, void *data) {
 | 
			
		||||
    struct server *s = data;
 | 
			
		||||
    pa_io_event *ev;
 | 
			
		||||
 | 
			
		||||
    pa_assert(watch);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(ev = dbus_watch_get_data(watch));
 | 
			
		||||
 | 
			
		||||
    /* get_watch_flags() checks if the watch is enabled */
 | 
			
		||||
    s->userdata->module->core->mainloop->io_enable(ev, get_watch_flags(watch));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called by D-Bus when a D-Bus timer event is added. */
 | 
			
		||||
static dbus_bool_t timeout_add_cb(DBusTimeout *timeout, void *data) {
 | 
			
		||||
    struct server *s = data;
 | 
			
		||||
    pa_mainloop_api *mainloop;
 | 
			
		||||
    pa_time_event *ev;
 | 
			
		||||
    struct timeval tv;
 | 
			
		||||
 | 
			
		||||
    pa_assert(timeout);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if (!dbus_timeout_get_enabled(timeout))
 | 
			
		||||
        return FALSE;
 | 
			
		||||
 | 
			
		||||
    mainloop = s->userdata->module->core->mainloop;
 | 
			
		||||
 | 
			
		||||
    pa_gettimeofday(&tv);
 | 
			
		||||
    pa_timeval_add(&tv, (pa_usec_t) dbus_timeout_get_interval(timeout) * 1000);
 | 
			
		||||
 | 
			
		||||
    ev = mainloop->time_new(mainloop, &tv, time_event_cb, timeout);
 | 
			
		||||
 | 
			
		||||
    dbus_timeout_set_data(timeout, ev, NULL);
 | 
			
		||||
 | 
			
		||||
    return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called by D-Bus when a D-Bus timer event is removed. */
 | 
			
		||||
static void timeout_remove_cb(DBusTimeout *timeout, void *data) {
 | 
			
		||||
    struct server *s = data;
 | 
			
		||||
    pa_time_event *ev;
 | 
			
		||||
 | 
			
		||||
    pa_assert(timeout);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if ((ev = dbus_timeout_get_data(timeout)))
 | 
			
		||||
        s->userdata->module->core->mainloop->time_free(ev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called by D-Bus when a D-Bus timer event is toggled. */
 | 
			
		||||
static void timeout_toggled_cb(DBusTimeout *timeout, void *data) {
 | 
			
		||||
    struct server *s = data;
 | 
			
		||||
    pa_mainloop_api *mainloop;
 | 
			
		||||
    pa_time_event *ev;
 | 
			
		||||
 | 
			
		||||
    pa_assert(timeout);
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    mainloop = s->userdata->module->core->mainloop;
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(ev = dbus_timeout_get_data(timeout));
 | 
			
		||||
 | 
			
		||||
    if (dbus_timeout_get_enabled(timeout)) {
 | 
			
		||||
        struct timeval tv;
 | 
			
		||||
 | 
			
		||||
        pa_gettimeofday(&tv);
 | 
			
		||||
        pa_timeval_add(&tv, (pa_usec_t) dbus_timeout_get_interval(timeout) * 1000);
 | 
			
		||||
 | 
			
		||||
        mainloop->time_restart(ev, &tv);
 | 
			
		||||
    } else
 | 
			
		||||
        mainloop->time_restart(ev, NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void server_free(struct server *s) {
 | 
			
		||||
    pa_assert(s);
 | 
			
		||||
 | 
			
		||||
    if (s->dbus_server) {
 | 
			
		||||
        dbus_server_disconnect(s->dbus_server);
 | 
			
		||||
        dbus_server_unref(s->dbus_server);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_xfree(s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct server *start_server(struct userdata *u, const char *address, enum server_type type) {
 | 
			
		||||
    /* XXX: We assume that when we unref the DBusServer instance at module
 | 
			
		||||
     * shutdown, nobody else holds any references to it. If we stop assuming
 | 
			
		||||
     * that someday, dbus_server_set_new_connection_function,
 | 
			
		||||
     * dbus_server_set_watch_functions and dbus_server_set_timeout_functions
 | 
			
		||||
     * calls should probably register free callbacks, instead of providing NULL
 | 
			
		||||
     * as they do now. */
 | 
			
		||||
 | 
			
		||||
    struct server *s = NULL;
 | 
			
		||||
    DBusError error;
 | 
			
		||||
 | 
			
		||||
    pa_assert(u);
 | 
			
		||||
    pa_assert(address);
 | 
			
		||||
 | 
			
		||||
    dbus_error_init(&error);
 | 
			
		||||
 | 
			
		||||
    s = pa_xnew0(struct server, 1);
 | 
			
		||||
    s->userdata = u;
 | 
			
		||||
    s->dbus_server = dbus_server_listen(address, &error);
 | 
			
		||||
 | 
			
		||||
    if (dbus_error_is_set(&error)) {
 | 
			
		||||
        pa_log("dbus_server_listen() failed: %s: %s", error.name, error.message);
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    dbus_server_set_new_connection_function(s->dbus_server, connection_new_cb, s, NULL);
 | 
			
		||||
 | 
			
		||||
    if (!dbus_server_set_watch_functions(s->dbus_server, watch_add_cb, watch_remove_cb, watch_toggled_cb, s, NULL)) {
 | 
			
		||||
        pa_log("dbus_server_set_watch_functions() ran out of memory.");
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!dbus_server_set_timeout_functions(s->dbus_server, timeout_add_cb, timeout_remove_cb, timeout_toggled_cb, s, NULL)) {
 | 
			
		||||
        pa_log("dbus_server_set_timeout_functions() ran out of memory.");
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return s;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
    if (s)
 | 
			
		||||
        server_free(s);
 | 
			
		||||
 | 
			
		||||
    dbus_error_free(&error);
 | 
			
		||||
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct server *start_local_server(struct userdata *u) {
 | 
			
		||||
    struct server *s = NULL;
 | 
			
		||||
    char *address = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(u);
 | 
			
		||||
 | 
			
		||||
    address = pa_get_dbus_address_from_server_type(u->module->core->server_type);
 | 
			
		||||
 | 
			
		||||
    s = start_server(u, address, SERVER_TYPE_LOCAL); /* May return NULL */
 | 
			
		||||
 | 
			
		||||
    pa_xfree(address);
 | 
			
		||||
 | 
			
		||||
    return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct server *start_tcp_server(struct userdata *u) {
 | 
			
		||||
    struct server *s = NULL;
 | 
			
		||||
    char *address = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(u);
 | 
			
		||||
 | 
			
		||||
    address = pa_sprintf_malloc("tcp:host=127.0.0.1,port=%u", u->tcp_port);
 | 
			
		||||
 | 
			
		||||
    s = start_server(u, address, SERVER_TYPE_TCP); /* May return NULL */
 | 
			
		||||
 | 
			
		||||
    pa_xfree(address);
 | 
			
		||||
 | 
			
		||||
    return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int get_access_arg(pa_modargs *ma, pa_bool_t *local_access, pa_bool_t *remote_access) {
 | 
			
		||||
    const char *value = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(ma);
 | 
			
		||||
    pa_assert(local_access);
 | 
			
		||||
    pa_assert(remote_access);
 | 
			
		||||
 | 
			
		||||
    if (!(value = pa_modargs_get_value(ma, "access", NULL)))
 | 
			
		||||
        return 0;
 | 
			
		||||
 | 
			
		||||
    if (!strcmp(value, "local")) {
 | 
			
		||||
        *local_access = TRUE;
 | 
			
		||||
        *remote_access = FALSE;
 | 
			
		||||
    } else if (!strcmp(value, "remote")) {
 | 
			
		||||
        *local_access = FALSE;
 | 
			
		||||
        *remote_access = TRUE;
 | 
			
		||||
    } else if (!strcmp(value, "local,remote")) {
 | 
			
		||||
        *local_access = TRUE;
 | 
			
		||||
        *remote_access = TRUE;
 | 
			
		||||
    } else
 | 
			
		||||
        return -1;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Frees dead client connections. Called every CLEANUP_INTERVAL seconds. */
 | 
			
		||||
static void cleanup_cb(pa_mainloop_api *a, pa_time_event *e, const struct timeval *tv, void *userdata) {
 | 
			
		||||
    struct userdata *u = userdata;
 | 
			
		||||
    struct connection *conn = NULL;
 | 
			
		||||
    uint32_t idx;
 | 
			
		||||
    struct timeval cleanup_timeval;
 | 
			
		||||
    unsigned free_count = 0;
 | 
			
		||||
 | 
			
		||||
    for (conn = pa_idxset_first(u->connections, &idx); conn; conn = pa_idxset_next(u->connections, &idx)) {
 | 
			
		||||
        if (!dbus_connection_get_is_connected(pa_dbus_wrap_connection_get(conn->wrap_conn))) {
 | 
			
		||||
            connection_free(conn);
 | 
			
		||||
            ++free_count;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (free_count > 0)
 | 
			
		||||
        pa_log_debug("Freed %u dead D-Bus client connections.", free_count);
 | 
			
		||||
 | 
			
		||||
    pa_gettimeofday(&cleanup_timeval);
 | 
			
		||||
    cleanup_timeval.tv_sec += CLEANUP_INTERVAL;
 | 
			
		||||
    u->module->core->mainloop->time_restart(e, &cleanup_timeval);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int pa__init(pa_module *m) {
 | 
			
		||||
    struct userdata *u = NULL;
 | 
			
		||||
    pa_modargs *ma = NULL;
 | 
			
		||||
    struct timeval cleanup_timeval;
 | 
			
		||||
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    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->module = m;
 | 
			
		||||
    u->local_access = TRUE;
 | 
			
		||||
    u->remote_access = FALSE;
 | 
			
		||||
    u->tcp_port = PA_DBUS_DEFAULT_PORT;
 | 
			
		||||
 | 
			
		||||
    if (get_access_arg(ma, &u->local_access, &u->remote_access) < 0) {
 | 
			
		||||
        pa_log("Invalid access argument: '%s'", pa_modargs_get_value(ma, "access", NULL));
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (pa_modargs_get_value_u32(ma, "tcp_port", &u->tcp_port) < 0 || u->tcp_port < 1 || u->tcp_port > 49150) {
 | 
			
		||||
        pa_log("Invalid tcp_port argument: '%s'", pa_modargs_get_value(ma, "tcp_port", NULL));
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (u->local_access && !(u->local_server = start_local_server(u))) {
 | 
			
		||||
        pa_log("Starting the local D-Bus server failed.");
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (u->remote_access && !(u->tcp_server = start_tcp_server(u))) {
 | 
			
		||||
        pa_log("Starting the D-Bus server for remote connections failed.");
 | 
			
		||||
        goto fail;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    u->connections = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
 | 
			
		||||
 | 
			
		||||
    pa_gettimeofday(&cleanup_timeval);
 | 
			
		||||
    cleanup_timeval.tv_sec += CLEANUP_INTERVAL;
 | 
			
		||||
    u->cleanup_event = m->core->mainloop->time_new(m->core->mainloop, &cleanup_timeval, cleanup_cb, u);
 | 
			
		||||
 | 
			
		||||
    u->dbus_protocol = pa_dbus_protocol_get(m->core);
 | 
			
		||||
    u->core_iface = pa_dbusiface_core_new(m->core);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
    if (ma)
 | 
			
		||||
        pa_modargs_free(ma);
 | 
			
		||||
 | 
			
		||||
    pa__done(m);
 | 
			
		||||
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called by idxset when the connection set is freed. */
 | 
			
		||||
static void connection_free_cb(void *p, void *userdata) {
 | 
			
		||||
    struct connection *conn = p;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
 | 
			
		||||
    connection_free(conn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa__done(pa_module *m) {
 | 
			
		||||
    struct userdata *u;
 | 
			
		||||
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
 | 
			
		||||
    if (!(u = m->userdata))
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (u->core_iface)
 | 
			
		||||
        pa_dbusiface_core_free(u->core_iface);
 | 
			
		||||
 | 
			
		||||
    if (u->cleanup_event)
 | 
			
		||||
        m->core->mainloop->time_free(u->cleanup_event);
 | 
			
		||||
 | 
			
		||||
    if (u->connections)
 | 
			
		||||
        pa_idxset_free(u->connections, connection_free_cb, NULL);
 | 
			
		||||
 | 
			
		||||
    if (u->tcp_server)
 | 
			
		||||
        server_free(u->tcp_server);
 | 
			
		||||
 | 
			
		||||
    if (u->local_server)
 | 
			
		||||
        server_free(u->local_server);
 | 
			
		||||
 | 
			
		||||
    if (u->dbus_protocol)
 | 
			
		||||
        pa_dbus_protocol_unref(u->dbus_protocol);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(u);
 | 
			
		||||
    m->userdata = NULL;
 | 
			
		||||
}
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -57,6 +57,7 @@ static const pa_client_conf default_conf = {
 | 
			
		|||
    .default_sink = NULL,
 | 
			
		||||
    .default_source = NULL,
 | 
			
		||||
    .default_server = NULL,
 | 
			
		||||
    .default_dbus_server = NULL,
 | 
			
		||||
    .autospawn = TRUE,
 | 
			
		||||
    .disable_shm = FALSE,
 | 
			
		||||
    .cookie_file = NULL,
 | 
			
		||||
| 
						 | 
				
			
			@ -81,6 +82,7 @@ void pa_client_conf_free(pa_client_conf *c) {
 | 
			
		|||
    pa_xfree(c->default_sink);
 | 
			
		||||
    pa_xfree(c->default_source);
 | 
			
		||||
    pa_xfree(c->default_server);
 | 
			
		||||
    pa_xfree(c->default_dbus_server);
 | 
			
		||||
    pa_xfree(c->cookie_file);
 | 
			
		||||
    pa_xfree(c);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -97,6 +99,7 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) {
 | 
			
		|||
        { "default-sink",           pa_config_parse_string,   &c->default_sink, NULL },
 | 
			
		||||
        { "default-source",         pa_config_parse_string,   &c->default_source, NULL },
 | 
			
		||||
        { "default-server",         pa_config_parse_string,   &c->default_server, NULL },
 | 
			
		||||
        { "default-dbus-server",    pa_config_parse_string,   &c->default_dbus_server, NULL },
 | 
			
		||||
        { "autospawn",              pa_config_parse_bool,     &c->autospawn, NULL },
 | 
			
		||||
        { "cookie-file",            pa_config_parse_string,   &c->cookie_file, NULL },
 | 
			
		||||
        { "disable-shm",            pa_config_parse_bool,     &c->disable_shm, NULL },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,12 +22,13 @@
 | 
			
		|||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/macro.h>
 | 
			
		||||
#include <pulsecore/native-common.h>
 | 
			
		||||
 | 
			
		||||
/* A structure containing configuration data for PulseAudio clients. */
 | 
			
		||||
 | 
			
		||||
typedef struct pa_client_conf {
 | 
			
		||||
    char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server, *cookie_file;
 | 
			
		||||
    char *daemon_binary, *extra_arguments, *default_sink, *default_source, *default_server, *default_dbus_server, *cookie_file;
 | 
			
		||||
    pa_bool_t autospawn, disable_shm;
 | 
			
		||||
    uint8_t cookie[PA_NATIVE_COOKIE_LENGTH];
 | 
			
		||||
    pa_bool_t cookie_valid; /* non-zero, when cookie is valid */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,7 @@
 | 
			
		|||
; default-sink =
 | 
			
		||||
; default-source =
 | 
			
		||||
; default-server =
 | 
			
		||||
; default-dbus-server =
 | 
			
		||||
 | 
			
		||||
; autospawn = yes
 | 
			
		||||
; daemon-binary = @PA_BINARY@
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -681,3 +681,32 @@ int pa_proplist_isempty(pa_proplist *p) {
 | 
			
		|||
 | 
			
		||||
    return pa_hashmap_isempty(MAKE_HASHMAP(p));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int pa_proplist_equal(pa_proplist *a, pa_proplist *b) {
 | 
			
		||||
    const void *key = NULL;
 | 
			
		||||
    struct property *a_prop = NULL;
 | 
			
		||||
    struct property *b_prop = NULL;
 | 
			
		||||
    void *state = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(a);
 | 
			
		||||
    pa_assert(b);
 | 
			
		||||
 | 
			
		||||
    if (a == b)
 | 
			
		||||
        return 1;
 | 
			
		||||
 | 
			
		||||
    if (pa_proplist_size(a) != pa_proplist_size(b))
 | 
			
		||||
        return 0;
 | 
			
		||||
 | 
			
		||||
    while ((a_prop = pa_hashmap_iterate(MAKE_HASHMAP(a), &state, &key))) {
 | 
			
		||||
        if (!(b_prop = pa_hashmap_get(MAKE_HASHMAP(b), key)))
 | 
			
		||||
            return 0;
 | 
			
		||||
 | 
			
		||||
        if (a_prop->nbytes != b_prop->nbytes)
 | 
			
		||||
            return 0;
 | 
			
		||||
 | 
			
		||||
        if (memcmp(a_prop->value, b_prop->value, a_prop->nbytes) != 0)
 | 
			
		||||
            return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -358,7 +358,7 @@ char *pa_proplist_to_string_sep(pa_proplist *p, const char *sep);
 | 
			
		|||
 * readable string. \since 0.9.15 */
 | 
			
		||||
pa_proplist *pa_proplist_from_string(const char *str);
 | 
			
		||||
 | 
			
		||||
  /** Returns 1 if an entry for the specified key is existant in the
 | 
			
		||||
/** Returns 1 if an entry for the specified key is existant in the
 | 
			
		||||
 * property list. \since 0.9.11 */
 | 
			
		||||
int pa_proplist_contains(pa_proplist *p, const char *key);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -375,6 +375,10 @@ unsigned pa_proplist_size(pa_proplist *t);
 | 
			
		|||
/** Returns 0 when the proplist is empty, positive otherwise \since 0.9.15 */
 | 
			
		||||
int pa_proplist_isempty(pa_proplist *t);
 | 
			
		||||
 | 
			
		||||
/** Return non-zero when a and b have the same keys and values.
 | 
			
		||||
 * \since 0.9.16 */
 | 
			
		||||
int pa_proplist_equal(pa_proplist *a, pa_proplist *b);
 | 
			
		||||
 | 
			
		||||
PA_C_DECL_END
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2678,6 +2678,28 @@ char *pa_replace(const char*s, const char*a, const char *b) {
 | 
			
		|||
    return pa_strbuf_tostring_free(sb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *pa_escape(const char *p, const char *chars) {
 | 
			
		||||
    const char *s;
 | 
			
		||||
    const char *c;
 | 
			
		||||
    pa_strbuf *buf = pa_strbuf_new();
 | 
			
		||||
 | 
			
		||||
    for (s = p; *s; ++s) {
 | 
			
		||||
        if (*s == '\\')
 | 
			
		||||
            pa_strbuf_putc(buf, '\\');
 | 
			
		||||
        else if (chars) {
 | 
			
		||||
            for (c = chars; *c; ++c) {
 | 
			
		||||
                if (*s == *c) {
 | 
			
		||||
                    pa_strbuf_putc(buf, '\\');
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        pa_strbuf_putc(buf, *s);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return pa_strbuf_tostring_free(buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *pa_unescape(char *p) {
 | 
			
		||||
    char *s, *d;
 | 
			
		||||
    pa_bool_t escaped = FALSE;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -224,6 +224,13 @@ unsigned pa_ncpus(void);
 | 
			
		|||
 | 
			
		||||
char *pa_replace(const char*s, const char*a, const char *b);
 | 
			
		||||
 | 
			
		||||
/* Escapes p by inserting backslashes in front of backslashes. chars is a
 | 
			
		||||
 * regular (ie. NULL-terminated) string containing additional characters that
 | 
			
		||||
 * should be escaped. chars can be NULL. The caller has to free the returned
 | 
			
		||||
 * string. */
 | 
			
		||||
char *pa_escape(const char *p, const char *chars);
 | 
			
		||||
 | 
			
		||||
/* Does regular backslash unescaping. Returns the argument p. */
 | 
			
		||||
char *pa_unescape(char *p);
 | 
			
		||||
 | 
			
		||||
char *pa_realpath(const char *path);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -52,6 +52,13 @@ typedef enum pa_suspend_cause {
 | 
			
		|||
#include <pulsecore/sink-input.h>
 | 
			
		||||
#include <pulsecore/msgobject.h>
 | 
			
		||||
 | 
			
		||||
typedef enum pa_server_type {
 | 
			
		||||
    PA_SERVER_TYPE_UNSET,
 | 
			
		||||
    PA_SERVER_TYPE_USER,
 | 
			
		||||
    PA_SERVER_TYPE_SYSTEM,
 | 
			
		||||
    PA_SERVER_TYPE_NONE
 | 
			
		||||
} pa_server_type_t;
 | 
			
		||||
 | 
			
		||||
typedef enum pa_core_state {
 | 
			
		||||
    PA_CORE_STARTUP,
 | 
			
		||||
    PA_CORE_RUNNING,
 | 
			
		||||
| 
						 | 
				
			
			@ -161,6 +168,8 @@ struct pa_core {
 | 
			
		|||
    pa_resample_method_t resample_method;
 | 
			
		||||
    int realtime_priority;
 | 
			
		||||
 | 
			
		||||
    pa_server_type_t server_type;
 | 
			
		||||
 | 
			
		||||
    /* hooks */
 | 
			
		||||
    pa_hook hooks[PA_CORE_HOOK_MAX];
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,7 @@
 | 
			
		|||
 | 
			
		||||
#include <pulse/rtclock.h>
 | 
			
		||||
#include <pulse/timeval.h>
 | 
			
		||||
#include <pulse/utf8.h>
 | 
			
		||||
#include <pulse/xmalloc.h>
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/core-rtclock.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -290,6 +291,31 @@ pa_dbus_wrap_connection* pa_dbus_wrap_connection_new(pa_mainloop_api *m, pa_bool
 | 
			
		|||
    return pconn;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pa_dbus_wrap_connection* pa_dbus_wrap_connection_new_from_existing(
 | 
			
		||||
        pa_mainloop_api *m,
 | 
			
		||||
        pa_bool_t use_rtclock,
 | 
			
		||||
        DBusConnection *conn) {
 | 
			
		||||
    pa_dbus_wrap_connection *pconn;
 | 
			
		||||
 | 
			
		||||
    pa_assert(m);
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
 | 
			
		||||
    pconn = pa_xnew(pa_dbus_wrap_connection, 1);
 | 
			
		||||
    pconn->mainloop = m;
 | 
			
		||||
    pconn->connection = dbus_connection_ref(conn);
 | 
			
		||||
    pconn->use_rtclock = use_rtclock;
 | 
			
		||||
 | 
			
		||||
    dbus_connection_set_exit_on_disconnect(conn, FALSE);
 | 
			
		||||
    dbus_connection_set_dispatch_status_function(conn, dispatch_status, pconn, NULL);
 | 
			
		||||
    dbus_connection_set_watch_functions(conn, add_watch, remove_watch, toggle_watch, pconn, NULL);
 | 
			
		||||
    dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, toggle_timeout, pconn, NULL);
 | 
			
		||||
    dbus_connection_set_wakeup_main_function(conn, wakeup_main, pconn, NULL);
 | 
			
		||||
 | 
			
		||||
    pconn->dispatch_event = pconn->mainloop->defer_new(pconn->mainloop, dispatch_cb, conn);
 | 
			
		||||
 | 
			
		||||
    return pconn;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbus_wrap_connection_free(pa_dbus_wrap_connection* c) {
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -422,3 +448,329 @@ void pa_dbus_free_pending_list(pa_dbus_pending **p) {
 | 
			
		|||
        pa_dbus_pending_free(i);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbus_send_error(DBusConnection *c, DBusMessage *in_reply_to, const char *name, const char *format, ...) {
 | 
			
		||||
    va_list ap;
 | 
			
		||||
    char *message;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
    pa_assert(in_reply_to);
 | 
			
		||||
    pa_assert(name);
 | 
			
		||||
    pa_assert(format);
 | 
			
		||||
 | 
			
		||||
    va_start(ap, format);
 | 
			
		||||
    message = pa_vsprintf_malloc(format, ap);
 | 
			
		||||
    va_end(ap);
 | 
			
		||||
    pa_assert_se((reply = dbus_message_new_error(in_reply_to, name, message)));
 | 
			
		||||
    pa_assert_se(dbus_connection_send(c, reply, NULL));
 | 
			
		||||
 | 
			
		||||
    dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(message);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbus_send_empty_reply(DBusConnection *c, DBusMessage *in_reply_to) {
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
    pa_assert(in_reply_to);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
 | 
			
		||||
    pa_assert_se(dbus_connection_send(c, reply, NULL));
 | 
			
		||||
    dbus_message_unref(reply);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbus_send_basic_value_reply(DBusConnection *c, DBusMessage *in_reply_to, int type, void *data) {
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
    pa_assert(in_reply_to);
 | 
			
		||||
    pa_assert(dbus_type_is_basic(type));
 | 
			
		||||
    pa_assert(data);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
 | 
			
		||||
    pa_assert_se(dbus_message_append_args(reply, type, data, DBUS_TYPE_INVALID));
 | 
			
		||||
    pa_assert_se(dbus_connection_send(c, reply, NULL));
 | 
			
		||||
    dbus_message_unref(reply);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const char *signature_from_basic_type(int type) {
 | 
			
		||||
    switch (type) {
 | 
			
		||||
        case DBUS_TYPE_BOOLEAN: return DBUS_TYPE_BOOLEAN_AS_STRING;
 | 
			
		||||
        case DBUS_TYPE_BYTE: return DBUS_TYPE_BYTE_AS_STRING;
 | 
			
		||||
        case DBUS_TYPE_INT16: return DBUS_TYPE_INT16_AS_STRING;
 | 
			
		||||
        case DBUS_TYPE_UINT16: return DBUS_TYPE_UINT16_AS_STRING;
 | 
			
		||||
        case DBUS_TYPE_INT32: return DBUS_TYPE_INT32_AS_STRING;
 | 
			
		||||
        case DBUS_TYPE_UINT32: return DBUS_TYPE_UINT32_AS_STRING;
 | 
			
		||||
        case DBUS_TYPE_INT64: return DBUS_TYPE_INT64_AS_STRING;
 | 
			
		||||
        case DBUS_TYPE_UINT64: return DBUS_TYPE_UINT64_AS_STRING;
 | 
			
		||||
        case DBUS_TYPE_DOUBLE: return DBUS_TYPE_DOUBLE_AS_STRING;
 | 
			
		||||
        case DBUS_TYPE_STRING: return DBUS_TYPE_STRING_AS_STRING;
 | 
			
		||||
        case DBUS_TYPE_OBJECT_PATH: return DBUS_TYPE_OBJECT_PATH_AS_STRING;
 | 
			
		||||
        case DBUS_TYPE_SIGNATURE: return DBUS_TYPE_SIGNATURE_AS_STRING;
 | 
			
		||||
        default: pa_assert_not_reached();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbus_send_basic_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, int type, void *data) {
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
    DBusMessageIter variant_iter;
 | 
			
		||||
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
    pa_assert(in_reply_to);
 | 
			
		||||
    pa_assert(dbus_type_is_basic(type));
 | 
			
		||||
    pa_assert(data);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
 | 
			
		||||
    dbus_message_iter_init_append(reply, &msg_iter);
 | 
			
		||||
    pa_assert_se(dbus_message_iter_open_container(&msg_iter,
 | 
			
		||||
                                                  DBUS_TYPE_VARIANT,
 | 
			
		||||
                                                  signature_from_basic_type(type),
 | 
			
		||||
                                                  &variant_iter));
 | 
			
		||||
    pa_assert_se(dbus_message_iter_append_basic(&variant_iter, type, data));
 | 
			
		||||
    pa_assert_se(dbus_message_iter_close_container(&msg_iter, &variant_iter));
 | 
			
		||||
    pa_assert_se(dbus_connection_send(c, reply, NULL));
 | 
			
		||||
    dbus_message_unref(reply);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Note: returns sizeof(char*) for strings, object paths and signatures. */
 | 
			
		||||
static unsigned basic_type_size(int type) {
 | 
			
		||||
    switch (type) {
 | 
			
		||||
        case DBUS_TYPE_BOOLEAN: return sizeof(dbus_bool_t);
 | 
			
		||||
        case DBUS_TYPE_BYTE: return 1;
 | 
			
		||||
        case DBUS_TYPE_INT16: return sizeof(dbus_int16_t);
 | 
			
		||||
        case DBUS_TYPE_UINT16: return sizeof(dbus_uint16_t);
 | 
			
		||||
        case DBUS_TYPE_INT32: return sizeof(dbus_int32_t);
 | 
			
		||||
        case DBUS_TYPE_UINT32: return sizeof(dbus_uint32_t);
 | 
			
		||||
        case DBUS_TYPE_INT64: return sizeof(dbus_int64_t);
 | 
			
		||||
        case DBUS_TYPE_UINT64: return sizeof(dbus_uint64_t);
 | 
			
		||||
        case DBUS_TYPE_DOUBLE: return sizeof(double);
 | 
			
		||||
        case DBUS_TYPE_STRING:
 | 
			
		||||
        case DBUS_TYPE_OBJECT_PATH:
 | 
			
		||||
        case DBUS_TYPE_SIGNATURE: return sizeof(char*);
 | 
			
		||||
        default: pa_assert_not_reached();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbus_send_basic_array_variant_reply(
 | 
			
		||||
        DBusConnection *c,
 | 
			
		||||
        DBusMessage *in_reply_to,
 | 
			
		||||
        int item_type,
 | 
			
		||||
        void *array,
 | 
			
		||||
        unsigned n) {
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
    pa_assert(in_reply_to);
 | 
			
		||||
    pa_assert(dbus_type_is_basic(item_type));
 | 
			
		||||
    pa_assert(array || n == 0);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
 | 
			
		||||
    dbus_message_iter_init_append(reply, &msg_iter);
 | 
			
		||||
    pa_dbus_append_basic_array_variant(&msg_iter, item_type, array, n);
 | 
			
		||||
    pa_assert_se(dbus_connection_send(c, reply, NULL));
 | 
			
		||||
    dbus_message_unref(reply);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbus_send_proplist_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, pa_proplist *proplist) {
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
    pa_assert(in_reply_to);
 | 
			
		||||
    pa_assert(proplist);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
 | 
			
		||||
    dbus_message_iter_init_append(reply, &msg_iter);
 | 
			
		||||
    pa_dbus_append_proplist_variant(&msg_iter, proplist);
 | 
			
		||||
    pa_assert_se(dbus_connection_send(c, reply, NULL));
 | 
			
		||||
    dbus_message_unref(reply);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbus_append_basic_array(DBusMessageIter *iter, int item_type, const void *array, unsigned n) {
 | 
			
		||||
    DBusMessageIter array_iter;
 | 
			
		||||
    unsigned i;
 | 
			
		||||
    unsigned item_size;
 | 
			
		||||
 | 
			
		||||
    pa_assert(iter);
 | 
			
		||||
    pa_assert(dbus_type_is_basic(item_type));
 | 
			
		||||
    pa_assert(array || n == 0);
 | 
			
		||||
 | 
			
		||||
    item_size = basic_type_size(item_type);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, signature_from_basic_type(item_type), &array_iter));
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < n; ++i)
 | 
			
		||||
        pa_assert_se(dbus_message_iter_append_basic(&array_iter, item_type, &((uint8_t*) array)[i * item_size]));
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_close_container(iter, &array_iter));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void pa_dbus_append_basic_variant(DBusMessageIter *iter, int type, void *data) {
 | 
			
		||||
    DBusMessageIter variant_iter;
 | 
			
		||||
 | 
			
		||||
    pa_assert(iter);
 | 
			
		||||
    pa_assert(dbus_type_is_basic(type));
 | 
			
		||||
    pa_assert(data);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, signature_from_basic_type(type), &variant_iter));
 | 
			
		||||
    pa_assert_se(dbus_message_iter_append_basic(&variant_iter, type, data));
 | 
			
		||||
    pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbus_append_basic_array_variant(DBusMessageIter *iter, int item_type, const void *array, unsigned n) {
 | 
			
		||||
    DBusMessageIter variant_iter;
 | 
			
		||||
    char *array_signature;
 | 
			
		||||
 | 
			
		||||
    pa_assert(iter);
 | 
			
		||||
    pa_assert(dbus_type_is_basic(item_type));
 | 
			
		||||
    pa_assert(array || n == 0);
 | 
			
		||||
 | 
			
		||||
    array_signature = pa_sprintf_malloc("a%c", *signature_from_basic_type(item_type));
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, array_signature, &variant_iter));
 | 
			
		||||
    pa_dbus_append_basic_array(&variant_iter, item_type, array, n);
 | 
			
		||||
    pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
 | 
			
		||||
 | 
			
		||||
    pa_xfree(array_signature);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbus_append_basic_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, int type, void *data) {
 | 
			
		||||
    DBusMessageIter dict_entry_iter;
 | 
			
		||||
 | 
			
		||||
    pa_assert(dict_iter);
 | 
			
		||||
    pa_assert(key);
 | 
			
		||||
    pa_assert(dbus_type_is_basic(type));
 | 
			
		||||
    pa_assert(data);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
 | 
			
		||||
    pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
 | 
			
		||||
    pa_dbus_append_basic_variant(&dict_entry_iter, type, data);
 | 
			
		||||
    pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbus_append_basic_array_variant_dict_entry(
 | 
			
		||||
        DBusMessageIter *dict_iter,
 | 
			
		||||
        const char *key,
 | 
			
		||||
        int item_type,
 | 
			
		||||
        const void *array,
 | 
			
		||||
        unsigned n) {
 | 
			
		||||
    DBusMessageIter dict_entry_iter;
 | 
			
		||||
 | 
			
		||||
    pa_assert(dict_iter);
 | 
			
		||||
    pa_assert(key);
 | 
			
		||||
    pa_assert(dbus_type_is_basic(item_type));
 | 
			
		||||
    pa_assert(array || n == 0);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
 | 
			
		||||
    pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
 | 
			
		||||
    pa_dbus_append_basic_array_variant(&dict_entry_iter, item_type, array, n);
 | 
			
		||||
    pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbus_append_proplist(DBusMessageIter *iter, pa_proplist *proplist) {
 | 
			
		||||
    DBusMessageIter dict_iter;
 | 
			
		||||
    DBusMessageIter dict_entry_iter;
 | 
			
		||||
    DBusMessageIter array_iter;
 | 
			
		||||
    void *state = NULL;
 | 
			
		||||
    const char *key;
 | 
			
		||||
 | 
			
		||||
    pa_assert(iter);
 | 
			
		||||
    pa_assert(proplist);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{say}", &dict_iter));
 | 
			
		||||
 | 
			
		||||
    while ((key = pa_proplist_iterate(proplist, &state))) {
 | 
			
		||||
        const void *value = NULL;
 | 
			
		||||
        size_t nbytes;
 | 
			
		||||
 | 
			
		||||
        pa_assert_se(pa_proplist_get(proplist, key, &value, &nbytes) >= 0);
 | 
			
		||||
 | 
			
		||||
        pa_assert_se(dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
 | 
			
		||||
 | 
			
		||||
        pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
 | 
			
		||||
 | 
			
		||||
        pa_assert_se(dbus_message_iter_open_container(&dict_entry_iter, DBUS_TYPE_ARRAY, "y", &array_iter));
 | 
			
		||||
        pa_assert_se(dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, &value, nbytes));
 | 
			
		||||
        pa_assert_se(dbus_message_iter_close_container(&dict_entry_iter, &array_iter));
 | 
			
		||||
 | 
			
		||||
        pa_assert_se(dbus_message_iter_close_container(&dict_iter, &dict_entry_iter));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_close_container(iter, &dict_iter));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbus_append_proplist_variant(DBusMessageIter *iter, pa_proplist *proplist) {
 | 
			
		||||
    DBusMessageIter variant_iter;
 | 
			
		||||
 | 
			
		||||
    pa_assert(iter);
 | 
			
		||||
    pa_assert(proplist);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{say}", &variant_iter));
 | 
			
		||||
    pa_dbus_append_proplist(&variant_iter, proplist);
 | 
			
		||||
    pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void pa_dbus_append_proplist_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, pa_proplist *proplist) {
 | 
			
		||||
    DBusMessageIter dict_entry_iter;
 | 
			
		||||
 | 
			
		||||
    pa_assert(dict_iter);
 | 
			
		||||
    pa_assert(key);
 | 
			
		||||
    pa_assert(proplist);
 | 
			
		||||
 | 
			
		||||
    pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
 | 
			
		||||
    pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
 | 
			
		||||
    pa_dbus_append_proplist_variant(&dict_entry_iter, proplist);
 | 
			
		||||
    pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pa_proplist *pa_dbus_get_proplist_arg(DBusConnection *c, DBusMessage *msg, DBusMessageIter *iter) {
 | 
			
		||||
    DBusMessageIter dict_iter;
 | 
			
		||||
    DBusMessageIter dict_entry_iter;
 | 
			
		||||
    pa_proplist *proplist = NULL;
 | 
			
		||||
    const char *key = NULL;
 | 
			
		||||
    const uint8_t *value = NULL;
 | 
			
		||||
    int value_length = 0;
 | 
			
		||||
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(iter);
 | 
			
		||||
    pa_assert(pa_streq(dbus_message_iter_get_signature(iter), "a{say}"));
 | 
			
		||||
 | 
			
		||||
    proplist = pa_proplist_new();
 | 
			
		||||
 | 
			
		||||
    dbus_message_iter_recurse(iter, &dict_iter);
 | 
			
		||||
 | 
			
		||||
    while (dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_INVALID) {
 | 
			
		||||
        dbus_message_iter_recurse(&dict_iter, &dict_entry_iter);
 | 
			
		||||
 | 
			
		||||
        dbus_message_iter_get_basic(&dict_entry_iter, &key);
 | 
			
		||||
        dbus_message_iter_next(&dict_entry_iter);
 | 
			
		||||
 | 
			
		||||
        if (strlen(key) <= 0 || !pa_ascii_valid(key)) {
 | 
			
		||||
            pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Invalid property list key: '%s'.", key);
 | 
			
		||||
            goto fail;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        dbus_message_iter_get_fixed_array(&dict_entry_iter, &value, &value_length);
 | 
			
		||||
 | 
			
		||||
        pa_assert(value_length >= 0);
 | 
			
		||||
 | 
			
		||||
        pa_assert_se(pa_proplist_set(proplist, key, value, value_length) >= 0);
 | 
			
		||||
 | 
			
		||||
        dbus_message_iter_next(&dict_iter);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    dbus_message_iter_next(iter);
 | 
			
		||||
 | 
			
		||||
    return proplist;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
    if (proplist)
 | 
			
		||||
        pa_proplist_free(proplist);
 | 
			
		||||
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,11 +26,16 @@
 | 
			
		|||
 | 
			
		||||
#include <pulsecore/llist.h>
 | 
			
		||||
#include <pulse/mainloop-api.h>
 | 
			
		||||
#include <pulse/proplist.h>
 | 
			
		||||
 | 
			
		||||
/* A wrap connection is not shared or refcounted, it is available in client side */
 | 
			
		||||
typedef struct pa_dbus_wrap_connection pa_dbus_wrap_connection;
 | 
			
		||||
 | 
			
		||||
pa_dbus_wrap_connection* pa_dbus_wrap_connection_new(pa_mainloop_api *mainloop, pa_bool_t use_rtclock, DBusBusType type, DBusError *error);
 | 
			
		||||
pa_dbus_wrap_connection* pa_dbus_wrap_connection_new_from_existing(
 | 
			
		||||
        pa_mainloop_api *mainloop,
 | 
			
		||||
        pa_bool_t use_rtclock,
 | 
			
		||||
        DBusConnection *conn);
 | 
			
		||||
void pa_dbus_wrap_connection_free(pa_dbus_wrap_connection* conn);
 | 
			
		||||
 | 
			
		||||
DBusConnection* pa_dbus_wrap_connection_get(pa_dbus_wrap_connection *conn);
 | 
			
		||||
| 
						 | 
				
			
			@ -60,4 +65,42 @@ void pa_dbus_sync_pending_list(pa_dbus_pending **p);
 | 
			
		|||
/* Free up a list of pa_dbus_pending_call objects */
 | 
			
		||||
void pa_dbus_free_pending_list(pa_dbus_pending **p);
 | 
			
		||||
 | 
			
		||||
/* Sends an error message as the reply to the given message. */
 | 
			
		||||
void pa_dbus_send_error(
 | 
			
		||||
        DBusConnection *c,
 | 
			
		||||
        DBusMessage *in_reply_to,
 | 
			
		||||
        const char *name,
 | 
			
		||||
        const char *format, ...) PA_GCC_PRINTF_ATTR(4, 5);
 | 
			
		||||
 | 
			
		||||
void pa_dbus_send_empty_reply(DBusConnection *c, DBusMessage *in_reply_to);
 | 
			
		||||
void pa_dbus_send_basic_value_reply(DBusConnection *c, DBusMessage *in_reply_to, int type, void *data);
 | 
			
		||||
void pa_dbus_send_basic_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, int type, void *data);
 | 
			
		||||
void pa_dbus_send_basic_array_variant_reply(
 | 
			
		||||
        DBusConnection *c,
 | 
			
		||||
        DBusMessage *in_reply_to,
 | 
			
		||||
        int item_type,
 | 
			
		||||
        void *array,
 | 
			
		||||
        unsigned n);
 | 
			
		||||
void pa_dbus_send_proplist_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, pa_proplist *proplist);
 | 
			
		||||
 | 
			
		||||
void pa_dbus_append_basic_array(DBusMessageIter *iter, int item_type, const void *array, unsigned n);
 | 
			
		||||
void pa_dbus_append_basic_array_variant(DBusMessageIter *iter, int item_type, const void *array, unsigned n);
 | 
			
		||||
void pa_dbus_append_basic_variant(DBusMessageIter *iter, int type, void *data);
 | 
			
		||||
void pa_dbus_append_basic_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, int type, void *data);
 | 
			
		||||
void pa_dbus_append_basic_array_variant_dict_entry(
 | 
			
		||||
        DBusMessageIter *dict_iter,
 | 
			
		||||
        const char *key,
 | 
			
		||||
        int item_type,
 | 
			
		||||
        const void *array,
 | 
			
		||||
        unsigned n);
 | 
			
		||||
void pa_dbus_append_proplist(DBusMessageIter *iter, pa_proplist *proplist);
 | 
			
		||||
void pa_dbus_append_proplist_variant(DBusMessageIter *iter, pa_proplist *proplist);
 | 
			
		||||
void pa_dbus_append_proplist_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, pa_proplist *proplist);
 | 
			
		||||
 | 
			
		||||
/* Returns a new proplist that the caller has to free. If the proplist contains
 | 
			
		||||
 * invalid keys, an error reply is sent and NULL is returned. The iterator must
 | 
			
		||||
 * point to "a{say}" element. This function calls dbus_message_iter_next(iter)
 | 
			
		||||
 * before returning. */
 | 
			
		||||
pa_proplist *pa_dbus_get_proplist_arg(DBusConnection *c, DBusMessage *msg, DBusMessageIter *iter);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -415,3 +415,13 @@ int pa_modargs_get_proplist(pa_modargs *ma, const char *name, pa_proplist *p, pa
 | 
			
		|||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *pa_modargs_iterate(pa_modargs *ma, void **state) {
 | 
			
		||||
    pa_hashmap *map = (pa_hashmap*) ma;
 | 
			
		||||
    struct entry *e;
 | 
			
		||||
 | 
			
		||||
    if (!(e = pa_hashmap_iterate(map, state, NULL)))
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    return e->key;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -60,4 +60,13 @@ int pa_modargs_get_sample_spec_and_channel_map(pa_modargs *ma, pa_sample_spec *s
 | 
			
		|||
 | 
			
		||||
int pa_modargs_get_proplist(pa_modargs *ma, const char *name, pa_proplist *p, pa_update_mode_t m);
 | 
			
		||||
 | 
			
		||||
/* Iterate through the module argument list. The user should allocate a
 | 
			
		||||
 * state variable of type void* and initialize it with NULL. A pointer
 | 
			
		||||
 * to this variable should then be passed to pa_modargs_iterate()
 | 
			
		||||
 * which should be called in a loop until it returns NULL which
 | 
			
		||||
 * signifies EOL. On each invication this function will return the
 | 
			
		||||
 * key string for the next entry. The keys in the argument list do not
 | 
			
		||||
 * have any particular order. */
 | 
			
		||||
const char *pa_modargs_iterate(pa_modargs *ma, void **state);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1134
									
								
								src/pulsecore/protocol-dbus.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1134
									
								
								src/pulsecore/protocol-dbus.c
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										217
									
								
								src/pulsecore/protocol-dbus.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								src/pulsecore/protocol-dbus.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,217 @@
 | 
			
		|||
#ifndef fooprotocoldbushfoo
 | 
			
		||||
#define fooprotocoldbushfoo
 | 
			
		||||
 | 
			
		||||
/***
 | 
			
		||||
  This file is part of PulseAudio.
 | 
			
		||||
 | 
			
		||||
  Copyright 2009 Tanu Kaskinen
 | 
			
		||||
 | 
			
		||||
  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, write to the Free Software
 | 
			
		||||
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
			
		||||
  USA.
 | 
			
		||||
***/
 | 
			
		||||
 | 
			
		||||
#include <dbus/dbus.h>
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/core.h>
 | 
			
		||||
#include <pulsecore/macro.h>
 | 
			
		||||
 | 
			
		||||
#define PA_DBUS_DEFAULT_PORT 24883
 | 
			
		||||
#define PA_DBUS_SOCKET_NAME "dbus-socket"
 | 
			
		||||
 | 
			
		||||
#define PA_DBUS_SYSTEM_SOCKET_PATH PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_DBUS_SOCKET_NAME
 | 
			
		||||
 | 
			
		||||
#define PA_DBUS_CORE_INTERFACE "org.PulseAudio.Core1"
 | 
			
		||||
#define PA_DBUS_CORE_OBJECT_PATH "/org/pulseaudio/core1"
 | 
			
		||||
 | 
			
		||||
#define PA_DBUS_ERROR_NO_SUCH_PROPERTY PA_DBUS_CORE_INTERFACE ".NoSuchPropertyError"
 | 
			
		||||
#define PA_DBUS_ERROR_NOT_FOUND PA_DBUS_CORE_INTERFACE ".NotFoundError"
 | 
			
		||||
 | 
			
		||||
/* Returns the default address of the server type in the escaped form. For
 | 
			
		||||
 * PA_SERVER_TYPE_NONE an empty string is returned. The caller frees the
 | 
			
		||||
 * string. */
 | 
			
		||||
char *pa_get_dbus_address_from_server_type(pa_server_type_t server_type);
 | 
			
		||||
 | 
			
		||||
typedef struct pa_dbus_protocol pa_dbus_protocol;
 | 
			
		||||
 | 
			
		||||
/* This function either creates a new pa_dbus_protocol object, or if one
 | 
			
		||||
 * already exists, increases the reference count. */
 | 
			
		||||
pa_dbus_protocol* pa_dbus_protocol_get(pa_core *c);
 | 
			
		||||
 | 
			
		||||
pa_dbus_protocol* pa_dbus_protocol_ref(pa_dbus_protocol *p);
 | 
			
		||||
void pa_dbus_protocol_unref(pa_dbus_protocol *p);
 | 
			
		||||
 | 
			
		||||
/* Called when a received message needs handling. Completely ignoring the
 | 
			
		||||
 * message isn't a good idea; if you can't handle the message, reply with an
 | 
			
		||||
 * error.
 | 
			
		||||
 *
 | 
			
		||||
 * The message signature is already checked against the introspection data, so
 | 
			
		||||
 * you don't have to do that yourself.
 | 
			
		||||
 *
 | 
			
		||||
 * All messages are method calls. */
 | 
			
		||||
typedef void (*pa_dbus_receive_cb_t)(DBusConnection *conn, DBusMessage *msg, void *userdata);
 | 
			
		||||
 | 
			
		||||
/* A specialized version of pa_dbus_receive_cb_t: the additional iterator
 | 
			
		||||
 * argument points to the element inside the new value variant.
 | 
			
		||||
 *
 | 
			
		||||
 * The new value signature is checked against the introspection data, so you
 | 
			
		||||
 * don't have to do that yourself. */
 | 
			
		||||
typedef void (*pa_dbus_set_property_cb_t)(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata);
 | 
			
		||||
 | 
			
		||||
typedef struct pa_dbus_arg_info {
 | 
			
		||||
    const char *name;
 | 
			
		||||
    const char *type;
 | 
			
		||||
    const char *direction; /* NULL for signal arguments. */
 | 
			
		||||
} pa_dbus_arg_info;
 | 
			
		||||
 | 
			
		||||
typedef struct pa_dbus_signal_info {
 | 
			
		||||
    const char *name;
 | 
			
		||||
    const pa_dbus_arg_info *arguments; /* NULL, if the signal has no args. */
 | 
			
		||||
    unsigned n_arguments;
 | 
			
		||||
} pa_dbus_signal_info;
 | 
			
		||||
 | 
			
		||||
typedef struct pa_dbus_method_handler {
 | 
			
		||||
    const char *method_name;
 | 
			
		||||
    const pa_dbus_arg_info *arguments; /* NULL, if the method has no args. */
 | 
			
		||||
    unsigned n_arguments;
 | 
			
		||||
    pa_dbus_receive_cb_t receive_cb;
 | 
			
		||||
} pa_dbus_method_handler;
 | 
			
		||||
 | 
			
		||||
typedef struct pa_dbus_property_handler {
 | 
			
		||||
    const char *property_name;
 | 
			
		||||
    const char *type;
 | 
			
		||||
 | 
			
		||||
    /* The access mode for the property is determined by checking whether
 | 
			
		||||
     * get_cb or set_cb is NULL. */
 | 
			
		||||
    pa_dbus_receive_cb_t get_cb;
 | 
			
		||||
    pa_dbus_set_property_cb_t set_cb;
 | 
			
		||||
} pa_dbus_property_handler;
 | 
			
		||||
 | 
			
		||||
typedef struct pa_dbus_interface_info {
 | 
			
		||||
    const char* name;
 | 
			
		||||
    const pa_dbus_method_handler *method_handlers; /* NULL, if the interface has no methods. */
 | 
			
		||||
    unsigned n_method_handlers;
 | 
			
		||||
    const pa_dbus_property_handler *property_handlers; /* NULL, if the interface has no properties. */
 | 
			
		||||
    unsigned n_property_handlers;
 | 
			
		||||
    const pa_dbus_receive_cb_t get_all_properties_cb; /* May be NULL, in which case GetAll returns an error. */
 | 
			
		||||
    const pa_dbus_signal_info *signals; /* NULL, if the interface has no signals. */
 | 
			
		||||
    unsigned n_signals;
 | 
			
		||||
} pa_dbus_interface_info;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* The following functions may only be called from the main thread. */
 | 
			
		||||
 | 
			
		||||
/* Registers the given interface to the given object path. It doesn't matter
 | 
			
		||||
 * whether or not the object has already been registered; if it is, then its
 | 
			
		||||
 * interface set is extended.
 | 
			
		||||
 *
 | 
			
		||||
 * Introspection requests are handled automatically.
 | 
			
		||||
 *
 | 
			
		||||
 * Userdata is passed to all the callbacks.
 | 
			
		||||
 *
 | 
			
		||||
 * Fails and returns a negative number if the object already has the interface
 | 
			
		||||
 * registered. */
 | 
			
		||||
int pa_dbus_protocol_add_interface(pa_dbus_protocol *p, const char *path, const pa_dbus_interface_info *info, void *userdata);
 | 
			
		||||
 | 
			
		||||
/* Returns a negative number if the given object doesn't have the given
 | 
			
		||||
 * interface registered. */
 | 
			
		||||
int pa_dbus_protocol_remove_interface(pa_dbus_protocol *p, const char* path, const char* interface);
 | 
			
		||||
 | 
			
		||||
/* Fails and returns a negative number if the connection is already
 | 
			
		||||
 * registered. */
 | 
			
		||||
int pa_dbus_protocol_register_connection(pa_dbus_protocol *p, DBusConnection *conn, pa_client *client);
 | 
			
		||||
 | 
			
		||||
/* Returns a negative number if the connection isn't registered. */
 | 
			
		||||
int pa_dbus_protocol_unregister_connection(pa_dbus_protocol *p, DBusConnection *conn);
 | 
			
		||||
 | 
			
		||||
/* Returns NULL if the connection isn't registered. */
 | 
			
		||||
pa_client *pa_dbus_protocol_get_client(pa_dbus_protocol *p, DBusConnection *conn);
 | 
			
		||||
 | 
			
		||||
/* Enables signal receiving for the given connection. The connection must have
 | 
			
		||||
 * been registered earlier. The signal string must contain both the signal
 | 
			
		||||
 * interface and the signal name, concatenated using a period as the separator.
 | 
			
		||||
 *
 | 
			
		||||
 * If the signal argument is NULL, all signals will be sent to the connection,
 | 
			
		||||
 * otherwise calling this function only adds the given signal to the list of
 | 
			
		||||
 * signals that will be delivered to the connection.
 | 
			
		||||
 *
 | 
			
		||||
 * The objects argument is a list of object paths. If the list is not empty,
 | 
			
		||||
 * only signals from the given objects are delivered. If this function is
 | 
			
		||||
 * called multiple time for the same connection and signal, the latest call
 | 
			
		||||
 * always replaces the previous object list. */
 | 
			
		||||
void pa_dbus_protocol_add_signal_listener(
 | 
			
		||||
        pa_dbus_protocol *p,
 | 
			
		||||
        DBusConnection *conn,
 | 
			
		||||
        const char *signal,
 | 
			
		||||
        char **objects,
 | 
			
		||||
        unsigned n_objects);
 | 
			
		||||
 | 
			
		||||
/* Disables the delivery of the signal for the given connection. The connection
 | 
			
		||||
 * must have been registered. If signal is NULL, all signals are disabled. If
 | 
			
		||||
 * signal is non-NULL and _add_signal_listener() was previously called with
 | 
			
		||||
 * NULL signal (causing all signals to be enabled), this function doesn't do
 | 
			
		||||
 * anything. Also, if the signal wasn't enabled before, this function doesn't
 | 
			
		||||
 * do anything in that case either. */
 | 
			
		||||
void pa_dbus_protocol_remove_signal_listener(pa_dbus_protocol *p, DBusConnection *conn, const char *signal);
 | 
			
		||||
 | 
			
		||||
/* Sends the given signal to all interested clients. By default no signals are
 | 
			
		||||
 * sent - clients have to explicitly to request signals by calling
 | 
			
		||||
 * .Core1.ListenForSignal. That method's handler then calls
 | 
			
		||||
 * pa_dbus_protocol_add_signal_listener(). */
 | 
			
		||||
void pa_dbus_protocol_send_signal(pa_dbus_protocol *p, DBusMessage *signal);
 | 
			
		||||
 | 
			
		||||
/* Returns an array of extension identifier strings. The strings pointers point
 | 
			
		||||
 * to the internal copies, so don't free the strings. The caller must free the
 | 
			
		||||
 * array, however. Also, do not save the returned pointer or any of the string
 | 
			
		||||
 * pointers, because the contained strings may be freed at any time. If you
 | 
			
		||||
 * need to save the array, copy it. */
 | 
			
		||||
const char **pa_dbus_protocol_get_extensions(pa_dbus_protocol *p, unsigned *n);
 | 
			
		||||
 | 
			
		||||
/* Modules that want to provide a D-Bus interface for clients should register
 | 
			
		||||
 * an identifier that the clients can use to check whether the additional
 | 
			
		||||
 * functionality is available.
 | 
			
		||||
 *
 | 
			
		||||
 * This function registers the extension with the given name. It is recommended
 | 
			
		||||
 * that the name follows the D-Bus interface naming convention, so that the
 | 
			
		||||
 * names remain unique in case there will be at some point in the future
 | 
			
		||||
 * extensions that aren't included with the main PulseAudio source tree. For
 | 
			
		||||
 * in-tree extensions the convention is to use the org.PulseAudio.Ext
 | 
			
		||||
 * namespace.
 | 
			
		||||
 *
 | 
			
		||||
 * It is suggested that the name contains a version number, and whenever the
 | 
			
		||||
 * extension interface is modified in non-backwards compatible way, the version
 | 
			
		||||
 * number is incremented.
 | 
			
		||||
 *
 | 
			
		||||
 * Fails and returns a negative number if the extension is already registered.
 | 
			
		||||
 */
 | 
			
		||||
int pa_dbus_protocol_register_extension(pa_dbus_protocol *p, const char *name);
 | 
			
		||||
 | 
			
		||||
/* Returns a negative number if the extension isn't registered. */
 | 
			
		||||
int pa_dbus_protocol_unregister_extension(pa_dbus_protocol *p, const char *name);
 | 
			
		||||
 | 
			
		||||
/* All hooks have the pa_dbus_protocol object as hook data. */
 | 
			
		||||
typedef enum pa_dbus_protocol_hook {
 | 
			
		||||
    PA_DBUS_PROTOCOL_HOOK_EXTENSION_REGISTERED, /* Extension name as call data. */
 | 
			
		||||
    PA_DBUS_PROTOCOL_HOOK_EXTENSION_UNREGISTERED, /* Extension name as call data. */
 | 
			
		||||
    PA_DBUS_PROTOCOL_HOOK_MAX
 | 
			
		||||
} pa_dbus_protocol_hook_t;
 | 
			
		||||
 | 
			
		||||
pa_hook_slot *pa_dbus_protocol_hook_connect(
 | 
			
		||||
        pa_dbus_protocol *p,
 | 
			
		||||
        pa_dbus_protocol_hook_t hook,
 | 
			
		||||
        pa_hook_priority_t prio,
 | 
			
		||||
        pa_hook_cb_t cb,
 | 
			
		||||
        void *data);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue