AC_SUBST(LIRC_LIBS)
AM_CONDITIONAL([HAVE_LIRC], [test "x$HAVE_LIRC" = x1])
+
+#### VCONF
+PKG_CHECK_MODULES(VCONF, vconf)
+AC_SUBST(VCONF_CFLAGS)
+AC_SUBST(VCONF_LIBS)
+
#### D-Bus support (optional) ####
AC_ARG_ENABLE([dbus],
Name: pulseaudio
Summary: Improved Linux sound server
Version: 13.0
-Release: 14
+Release: 15
Group: Multimedia/Audio
License: LGPL-2.1
URL: http://pulseaudio.org
BuildRequires: pkgconfig(cynara-client)
BuildRequires: pkgconfig(cynara-creds-socket)
BuildRequires: pkgconfig(cynara-session)
+BuildRequires: pkgconfig(vconf)
BuildRequires: systemd-devel
BuildRequires: libcap-devel
%if "%{tizen_profile_name}" == "tv"
module_tunnel_sink_new_la_SOURCES = modules/module-tunnel-sink-new.c
module_tunnel_sink_new_la_LDFLAGS = $(MODULE_LDFLAGS)
-module_tunnel_sink_new_la_LIBADD = $(MODULE_LIBADD)
-module_tunnel_sink_new_la_CFLAGS = $(AM_CFLAGS) -DPA_MODULE_NAME=module_tunnel_sink_new
+module_tunnel_sink_new_la_LIBADD = $(MODULE_LIBADD) $(VCONF_LIBS)
+module_tunnel_sink_new_la_CFLAGS = $(AM_CFLAGS) $(VCONF_CFLAGS) -DPA_MODULE_NAME=module_tunnel_sink_new
module_tunnel_source_new_la_SOURCES = modules/module-tunnel-source-new.c
module_tunnel_source_new_la_LDFLAGS = $(MODULE_LDFLAGS)
-module_tunnel_source_new_la_LIBADD = $(MODULE_LIBADD)
-module_tunnel_source_new_la_CFLAGS = $(AM_CFLAGS) -DPA_MODULE_NAME=module_tunnel_source_new
+module_tunnel_source_new_la_LIBADD = $(MODULE_LIBADD) $(VCONF_LIBS)
+module_tunnel_source_new_la_CFLAGS = $(AM_CFLAGS) $(VCONF_CFLAGS) -DPA_MODULE_NAME=module_tunnel_source_new
module_tunnel_sink_la_SOURCES = modules/module-tunnel.c
module_tunnel_sink_la_CFLAGS = -DTUNNEL_SINK=1 $(AM_CFLAGS) $(X11_CFLAGS) -DPA_MODULE_NAME=module_tunnel_sink
#include <pulsecore/thread-mq.h>
#include <pulsecore/poll.h>
#include <pulsecore/rtpoll.h>
+
+#ifdef __TIZEN__
#include <pulsecore/proplist-util.h>
+#include <vconf.h>
+#include <vconf-keys.h>
+#endif
PA_MODULE_AUTHOR("Alexander Couzens");
PA_MODULE_DESCRIPTION("Create a network sink which connects via a stream to a remote PulseAudio server");
#define MAX_LATENCY_USEC (200 * PA_USEC_PER_MSEC)
#define TUNNEL_THREAD_FAILED_MAINLOOP 1
+#ifdef __TIZEN__
+enum {
+ SINK_MESSAGE_STREAM_PROPLIST_UPDATED = PA_SINK_MESSAGE_MAX
+};
+#endif
+
static void stream_state_cb(pa_stream *stream, void *userdata);
static void stream_changed_buffer_attr_cb(pa_stream *stream, void *userdata);
static void stream_set_buffer_attr_cb(pa_stream *stream, int success, void *userdata);
static void context_state_cb(pa_context *c, void *userdata);
static void sink_update_requested_latency_cb(pa_sink *s);
+#ifdef __TIZEN__
+static void stream_event_cb(pa_stream *stream, const char *name, pa_proplist *pl, void *userdata);
+#endif
struct userdata {
pa_module *module;
char *cookie_file;
char *remote_server;
char *remote_sink_name;
+#ifdef __TIZEN__
+ char *device_name;
+#endif
};
static const char* const valid_modargs[] = {
pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "PulseAudio");
pa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "org.PulseAudio.PulseAudio");
pa_proplist_sets(proplist, PA_PROP_APPLICATION_VERSION, PACKAGE_VERSION);
+#ifdef __TIZEN__
+ pa_proplist_remote_init(proplist, u->device_name);
+#endif
pa_init_proplist(proplist);
return proplist;
stream_changed_buffer_attr_cb(stream, userdata);
}
+#ifdef __TIZEN__
+static void stream_event_cb(pa_stream *stream, const char *name, pa_proplist *pl, void *userdata) {
+ char *t;
+ struct userdata *u = userdata;
+
+ pa_assert(stream);
+ pa_assert(name);
+ pa_assert(pl);
+
+ t = pa_proplist_to_string_sep(pl, ", ");
+ pa_log_info("Got event '%s', properties '%s'", name, t);
+
+ if (pa_safe_streq(name, PA_STREAM_EVENT_UPDATE_MEDIA_REMOTE_ACCESS)) {
+ pa_log_info("post message to update sink[%s] proplist[%s]", u->sink->name, t);
+ pa_asyncmsgq_post(u->thread_mq->outq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_STREAM_PROPLIST_UPDATED,
+ pa_proplist_copy(pl), 0, NULL, NULL);
+ }
+
+ pa_xfree(t);
+}
+#endif
+
static void context_state_cb(pa_context *c, void *userdata) {
struct userdata *u = userdata;
pa_assert(u);
pa_stream_set_state_callback(u->stream, stream_state_cb, userdata);
pa_stream_set_buffer_attr_callback(u->stream, stream_changed_buffer_attr_cb, userdata);
+#ifdef __TIZEN__
+ pa_stream_set_event_callback(u->stream, stream_event_cb, userdata);
+#endif
+
if (pa_stream_connect_playback(u->stream,
u->remote_sink_name,
&bufferattr,
*((int64_t*) data) = remote_latency;
return 0;
}
+#ifdef __TIZEN__
+ case SINK_MESSAGE_STREAM_PROPLIST_UPDATED: {
+ pa_proplist *pl = (pa_proplist *)data;
+ void *s;
+ uint32_t idx;
+
+ pa_log_info("SINK_MESSAGE_STREAM_PROPLIST_UPDATED : %p", pl);
+
+ pa_sink_update_proplist(u->sink, PA_UPDATE_REPLACE, pl);
+
+ if (!pa_proplist_remote_is_allowed(pl)) {
+ PA_IDXSET_FOREACH(s, u->sink->inputs, idx) {
+ pa_log_info(" -- kill sink-input(%p, %u)", s, ((pa_sink_input *) s)->index);
+ pa_sink_input_kill((pa_sink_input *) s);
+ }
+ }
+
+ pa_proplist_free(pl);
+
+ return 0;
+ }
+#endif
}
return pa_sink_process_msg(o, code, data, offset, chunk);
}
u->thread_mainloop_api = pa_mainloop_get_api(u->thread_mainloop);
u->cookie_file = pa_xstrdup(pa_modargs_get_value(ma, "cookie", NULL));
u->remote_sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
+#ifdef __TIZEN__
+ u->device_name = vconf_get_str(VCONFKEY_SETAPPL_DEVICE_NAME_STR);
+#endif
u->thread_mq = pa_xnew0(pa_thread_mq, 1);
_("Tunnel to %s/%s"),
remote_server,
pa_strempty(u->remote_sink_name));
+#ifdef __TIZEN__
+ pa_proplist_remote_init(sink_data.proplist, u->device_name);
+ pa_proplist_sets(sink_data.proplist, PA_PROP_DEVICE_API, "tunnel");
+#endif
if (pa_modargs_get_proplist(ma, "sink_properties", sink_data.proplist, PA_UPDATE_REPLACE) < 0) {
pa_log("Invalid properties");
if (u->remote_server)
pa_xfree(u->remote_server);
+#ifdef __TIZEN__
+ if (u->device_name)
+ pa_xfree(u->device_name);
+#endif
+
if (u->sink)
pa_sink_unref(u->sink);
#include <pulsecore/thread-mq.h>
#include <pulsecore/poll.h>
#include <pulsecore/rtpoll.h>
+
+#ifdef __TIZEN__
#include <pulsecore/proplist-util.h>
+#include <vconf.h>
+#include <vconf-keys.h>
+#endif
PA_MODULE_AUTHOR("Alexander Couzens");
PA_MODULE_DESCRIPTION("Create a network source which connects via a stream to a remote PulseAudio server");
#define TUNNEL_THREAD_FAILED_MAINLOOP 1
+#ifdef __TIZEN__
+enum {
+ SOURCE_MESSAGE_STREAM_PROPLIST_UPDATED = PA_SOURCE_MESSAGE_MAX
+};
+#endif
+
static void stream_state_cb(pa_stream *stream, void *userdata);
static void stream_read_cb(pa_stream *s, size_t length, void *userdata);
static void context_state_cb(pa_context *c, void *userdata);
static void source_update_requested_latency_cb(pa_source *s);
+#ifdef __TIZEN__
+static void stream_event_cb(pa_stream *s, const char *name, pa_proplist *pl, void *userdata);
+#endif
struct userdata {
pa_module *module;
char *cookie_file;
char *remote_server;
char *remote_source_name;
+#ifdef __TIZEN__
+ char *device_name;
+#endif
};
static const char* const valid_modargs[] = {
pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "PulseAudio");
pa_proplist_sets(proplist, PA_PROP_APPLICATION_ID, "org.PulseAudio.PulseAudio");
pa_proplist_sets(proplist, PA_PROP_APPLICATION_VERSION, PACKAGE_VERSION);
+#ifdef __TIZEN__
+ pa_proplist_remote_init(proplist, u->device_name);
+#endif
pa_init_proplist(proplist);
return proplist;
u->new_data = true;
}
+#ifdef __TIZEN__
+static void stream_event_cb(pa_stream *s, const char *name, pa_proplist *pl, void *userdata) {
+ char *t;
+ struct userdata *u = userdata;
+
+ pa_assert(s);
+ pa_assert(name);
+ pa_assert(pl);
+
+ t = pa_proplist_to_string_sep(pl, ", ");
+ pa_log("Got event '%s', properties '%s'", name, t);
+
+ if (pa_safe_streq(name, PA_STREAM_EVENT_UPDATE_MEDIA_REMOTE_ACCESS)) {
+ pa_log("post message to update source[%s] proplist[%s]", u->source->name, t);
+ pa_asyncmsgq_post(u->thread_mq->outq, PA_MSGOBJECT(u->source), SOURCE_MESSAGE_STREAM_PROPLIST_UPDATED,
+ pa_proplist_copy(pl), 0, NULL, NULL);
+ }
+
+ pa_xfree(t);
+}
+#endif
+
/* called from io context to read samples from the stream into our source */
static void read_new_samples(struct userdata *u) {
const void *p;
pa_stream_set_state_callback(u->stream, stream_state_cb, userdata);
pa_stream_set_read_callback(u->stream, stream_read_cb, userdata);
+#ifdef __TIZEN__
+ pa_stream_set_event_callback(u->stream, stream_event_cb, userdata);
+#endif
+
if (pa_stream_connect_record(u->stream,
u->remote_source_name,
&bufferattr,
return 0;
}
+
+#ifdef __TIZEN__
+ case SOURCE_MESSAGE_STREAM_PROPLIST_UPDATED: {
+ pa_proplist *pl = (pa_proplist *)data;
+ void *s;
+ uint32_t idx;
+
+ pa_log_info("SOURCE_MESSAGE_STREAM_PROPLIST_UPDATED : %p", pl);
+
+ pa_source_update_proplist(u->source, PA_UPDATE_REPLACE, pl);
+
+ if (!pa_proplist_remote_is_allowed(pl)) {
+ PA_IDXSET_FOREACH(s, u->source->outputs, idx) {
+ pa_log_info(" -- kill source-output(%p, %u)", s, ((pa_source_output *) s)->index);
+ pa_source_output_kill((pa_source_output *) s);
+ }
+ }
+
+ pa_proplist_free(pl);
+
+ return 0;
+ }
+#endif
}
return pa_source_process_msg(o, code, data, offset, chunk);
}
u->thread_mainloop_api = pa_mainloop_get_api(u->thread_mainloop);
u->cookie_file = pa_xstrdup(pa_modargs_get_value(ma, "cookie", NULL));
u->remote_source_name = pa_xstrdup(pa_modargs_get_value(ma, "source", NULL));
+#ifdef __TIZEN__
+ u->device_name = vconf_get_str(VCONFKEY_SETAPPL_DEVICE_NAME_STR);
+#endif
u->thread_mq = pa_xnew0(pa_thread_mq, 1);
_("Tunnel to %s/%s"),
remote_server,
pa_strempty(u->remote_source_name));
+#ifdef __TIZEN__
+ pa_proplist_remote_init(source_data.proplist, u->device_name);
+ pa_proplist_sets(source_data.proplist, PA_PROP_DEVICE_API, "tunnel");
+#endif
if (pa_modargs_get_proplist(ma, "source_properties", source_data.proplist, PA_UPDATE_REPLACE) < 0) {
pa_log("Invalid properties");
if (u->remote_server)
pa_xfree(u->remote_server);
+#ifdef __TIZEN__
+ if (u->device_name)
+ pa_xfree(u->device_name);
+#endif
+
if (u->source)
pa_source_unref(u->source);
#ifdef __TIZEN__
#define PA_STREAM_EVENT_POP_TIMEOUT "pop-timeout"
+#define PA_STREAM_EVENT_UPDATE_MEDIA_REMOTE_ACCESS "update-media-remote-access"
#endif
#ifndef __INCLUDED_FROM_PULSE_AUDIO
static const char *access_str[] = { REMOTE_ACCESS_PERMISSION_DENIED, REMOTE_ACCESS_PERMISSION_ALLOWED };
+void pa_proplist_remote_init(pa_proplist *p, const char *remote_name) {
+ if (!p)
+ return;
+
+ pa_proplist_sets(p, PA_PROP_MEDIA_REMOTE_NAME, pa_strnull(remote_name));
+ pa_proplist_sets(p, PA_PROP_MEDIA_REMOTE_ACCESS, REMOTE_ACCESS_PERMISSION_DENIED);
+}
+
bool pa_proplist_has_remote_name(pa_proplist *p) {
bool is_remote = false;
char *pa_proplist_get_stream_group(pa_proplist *pl, const char *prefix, const char *cache);
#ifdef __TIZEN__
+void pa_proplist_remote_init(pa_proplist *p, const char *remote_name);
bool pa_proplist_has_remote_name(pa_proplist *p);
int pa_proplist_set_remote_access_permission(pa_proplist *p, bool allowed);
bool pa_proplist_remote_is_allowed(pa_proplist *p);