#define STREAM_MANAGER_METHOD_NAME_GET_PID_OF_LATEST_STREAM "GetPidOfLatestStream"
#define STREAM_MANAGER_METHOD_NAME_ACTIVATE_DUCKING "ActivateDucking"
#define STREAM_MANAGER_METHOD_NAME_GET_DUCKING_STATE "GetDuckingState"
+#define STREAM_MANAGER_METHOD_NAME_SET_REMOTE_PERMISSION "SetRemotePermission"
+#define STREAM_MANAGER_METHOD_NAME_DISCOVER_REMOTE_DEVICE "DiscoverRemoteDevice"
+#define STREAM_MANAGER_METHOD_NAME_PUBLISH_LOCAL_DEVICE "PublishLocalDevice"
/* signal */
#define STREAM_MANAGER_SIGNAL_NAME_VOLUME_CHANGED "VolumeChanged"
#define STREAM_MANAGER_SIGNAL_NAME_DUCKING_STATE_CHANGED "DuckingStateChanged"
#define STREAM_MANAGER_SIGNAL_NAME_COMMAND "Command"
+#define STREAM_MANAGER_SIGNAL_NAME_REMOTE_FOUND "RemoteFound"
enum method_handler_index {
METHOD_HANDLER_GET_STREAM_INFO,
METHOD_HANDLER_GET_PID_OF_LATEST_STREAM,
METHOD_HANDLER_ACTIVATE_DUCKING,
METHOD_HANDLER_GET_DUCKING_STATE,
+ METHOD_HANDLER_NAME_SET_REMOTE_PERMISSION,
+ METHOD_HANDLER_DISCOVER_REMOTE_DEVICE,
+ METHOD_HANDLER_PUBLISH_LOCAL_DEVICE,
METHOD_HANDLER_MAX
};
" <arg name=\"is_ducked\" direction=\"out\" type=\"b\"/>" \
" <arg name=\"ret_msg\" direction=\"out\" type=\"s\"/>" \
" </method>" \
+ " <method name=\"STREAM_MANAGER_METHOD_NAME_SET_REMOTE_PERMISSION\">" \
+ " <arg name=\"type\" direction=\"in\" type=\"s\"/>" \
+ " <arg name=\"index\" direction=\"in\" type=\"u\"/>" \
+ " <arg name=\"allowed\" direction=\"in\" type=\"b\"/>" \
+ " </method>" \
+ " <method name=\"STREAM_MANAGER_METHOD_NAME_DISCOVER_REMOTE_DEVICEE\">" \
+ " <arg name=\"enable\" direction=\"in\" type=\"b\"/>" \
+ " </method>" \
+ " <method name=\"STREAM_MANAGER_METHOD_NAME_PUBLISH_LOCAL_DEVICE\">" \
+ " <arg name=\"enable\" direction=\"in\" type=\"b\"/>" \
+ " </method>" \
" <signal name=\"STREAM_MANAGER_SIGNAL_NAME_VOLUME_CHANGED\">" \
" <arg name=\"direction\" type=\"s\"/>" \
" <arg name=\"volume_type\" type=\"s\"/>" \
" <arg name=\"name\" type=\"s\"/>" \
" <arg name=\"value\" type=\"i\"/>" \
" </signal>" \
+ " <signal name=\"STREAM_MANAGER_SIGNAL_NAME_REMOTE_FOUND\">" \
+ " <arg name=\"type\" type=\"i\"/>" \
+ " <arg name=\"index\" type=\"u\"/>" \
+ " <arg name=\"conneted\" type=\"b\"/>" \
+ " <arg name=\"remote_name\" type=\"s\"/>" \
+ " <arg name=\"peer_info\" type=\"s\"/>" \
+ " </signal>" \
" </interface>" \
" <interface name=\"org.freedesktop.DBus.Introspectable\">" \
" <method name=\"Introspect\">" \
void send_ducking_state_changed_signal(DBusConnection *conn, const int index, const int is_ducked);
void send_command_signal(DBusConnection *conn, const char *name, int value);
+void send_remote_found_signal(DBusConnection *conn, int type, bool connected,
+ unsigned int index, const char *name, const char *description);
int32_t init_sm_dbus(pa_stream_manager *m);
void deinit_sm_dbus(pa_stream_manager *m);
#endif
-#endif
\ No newline at end of file
+#endif
#ifdef HAVE_DBUS
+#include <pulsecore/proplist-util.h>
#include "stream-manager-priv.h"
#include "stream-manager-dbus-priv.h"
#include "stream-manager-volume-priv.h"
static void handle_get_pid_of_latest_stream(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_activate_ducking(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_get_ducking_state(DBusConnection *conn, DBusMessage *msg, void *userdata);
+static void handle_set_remote_permission(DBusConnection *conn, DBusMessage *msg, void *userdata);
+static void handle_discover_remote_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
+static void handle_publish_local_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void send_volume_changed_signal(DBusConnection *conn, const char *direction, const char *volume_type, const uint32_t volume_level);
static pa_dbus_arg_info get_stream_info_args[] = { { "stream_type", "s", "in" },
static pa_dbus_arg_info get_ducking_state_args[] = { { "index", "u", "in" },
{ "is_ducked", "b", "out" },
{ "ret_msg", "s", "out" } };
+static pa_dbus_arg_info set_remote_permission_args[] = { { "type", "s", "in" },
+ { "index", "u", "in" },
+ { "allowed", "b", "in" } };
+static pa_dbus_arg_info discover_remote_device_args[] = { { "enable", "b", "in" } };
+static pa_dbus_arg_info publish_local_device_args[] = { { "enable", "b", "in" } };
static const char* signature_args_for_in[] = {
"s", /* METHOD_HANDLER_GET_STREAM_INFO */
"uss", /* METHOD_HANDLER_CHECK_STREAM_EXIST_BY_PID */
"sas", /* METHOD_HANDLER_GET_PID_OF_LATEST_STREAM */
"ubsud", /* METHOD_HANDLER_ACTIVATE_DUCKING */
- "u" /* METHOD_HANDLER_GET_DUCKING_STATE */
+ "u", /* METHOD_HANDLER_GET_DUCKING_STATE */
+ "sub", /* METHOD_HANDLER_SET_REMOTE_PERMISSION */
+ "b", /* METHOD_HANDLER_DISCOVER_REMOTE_DEVICE */
+ "b" /* METHOD_HANDLER_PUBLISH_LOCAL_DEVICE */
};
static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
.arguments = get_ducking_state_args,
.n_arguments = sizeof(get_ducking_state_args) / sizeof(pa_dbus_arg_info),
.receive_cb = handle_get_ducking_state },
+ [METHOD_HANDLER_NAME_SET_REMOTE_PERMISSION] = {
+ .method_name = STREAM_MANAGER_METHOD_NAME_SET_REMOTE_PERMISSION,
+ .arguments = set_remote_permission_args,
+ .n_arguments = sizeof(set_remote_permission_args) / sizeof(pa_dbus_arg_info),
+ .receive_cb = handle_set_remote_permission },
+ [METHOD_HANDLER_DISCOVER_REMOTE_DEVICE] = {
+ .method_name = STREAM_MANAGER_METHOD_NAME_DISCOVER_REMOTE_DEVICE,
+ .arguments = discover_remote_device_args,
+ .n_arguments = sizeof(discover_remote_device_args) / sizeof(pa_dbus_arg_info),
+ .receive_cb = handle_discover_remote_device },
+ [METHOD_HANDLER_PUBLISH_LOCAL_DEVICE] = {
+ .method_name = STREAM_MANAGER_METHOD_NAME_PUBLISH_LOCAL_DEVICE,
+ .arguments = publish_local_device_args,
+ .n_arguments = sizeof(publish_local_device_args) / sizeof(pa_dbus_arg_info),
+ .receive_cb = handle_publish_local_device },
};
static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata) {
dbus_message_unref(reply);
}
+static void handle_set_remote_permission(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+ pa_stream_manager *m = (pa_stream_manager*)userdata;
+ dbus_uint32_t index;
+ dbus_bool_t allowed;
+ pa_proplist *p = NULL;
+ char *type = NULL;
+
+ pa_assert(conn);
+ pa_assert(msg);
+ pa_assert(m);
+
+ pa_assert_se(dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &type,
+ DBUS_TYPE_UINT32, &index,
+ DBUS_TYPE_BOOLEAN, &allowed,
+ DBUS_TYPE_INVALID));
+
+ if (!type) {
+ pa_log_error("invalid arguments");
+ goto out;
+ }
+
+ pa_log_info("type(%s), index(%d), allowed(%d)", type, index, allowed);
+
+ p = pa_proplist_new();
+ if (!p) {
+ pa_log_error("failed to create proplist");
+ goto out;
+ }
+
+ if (pa_proplist_set_remote_access_permission(p, allowed)) {
+ pa_log_error("set remote access permission error");
+ goto out;
+ }
+
+ if (pa_streq(type, "sink-input")) {
+ pa_sink_input *i;
+
+ i = pa_idxset_get_by_index(m->core->sink_inputs, index);
+ if (!i) {
+ pa_log_error("not found sink-input");
+ goto out;
+ }
+
+ if (pa_proplist_remote_is_allowed(i->proplist) != allowed){
+ pa_sink_input_update_proplist(i, PA_UPDATE_REPLACE, p);
+ pa_sink_input_send_event(i, PA_STREAM_EVENT_UPDATE_MEDIA_REMOTE_ACCESS, p);
+ }
+
+ } else if (pa_streq(type, "source-output")) {
+ pa_source_output *o;
+
+ o = pa_idxset_get_by_index(m->core->source_outputs, index);
+ if (!o) {
+ pa_log_error("not found source-output");
+ goto out;
+ }
+
+ if (pa_proplist_remote_is_allowed(o->proplist) != allowed){
+ pa_source_output_update_proplist(o, PA_UPDATE_REPLACE, p);
+ pa_source_output_send_event(o, PA_STREAM_EVENT_UPDATE_MEDIA_REMOTE_ACCESS, p);
+ }
+
+ } else {
+ pa_log_warn("unknown type");
+ }
+
+out:
+ if (p)
+ pa_proplist_free(p);
+
+ pa_dbus_send_empty_reply(conn, msg);
+}
+
+static void handle_discover_remote_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+ pa_stream_manager *m = (pa_stream_manager*)userdata;
+ pa_module *module;
+ dbus_bool_t enable;
+
+ pa_assert(conn);
+ pa_assert(msg);
+ pa_assert(m);
+
+ pa_assert_se(dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_BOOLEAN, &enable,
+ DBUS_TYPE_INVALID));
+
+ pa_log_info("discover module enable(%d)", enable);
+
+ if (enable) {
+ if (m->m_discover) {
+ pa_log_error("already loaded");
+ goto error;
+ }
+
+ if (pa_module_load(&module, m->core, "module-tizenaudio-discover", NULL)) {
+ pa_log_error("failed to load module");
+ goto error;
+ }
+ m->m_discover = module->index;
+ } else {
+ if (m->m_discover) {
+ pa_module_unload_request_by_index(m->core, m->m_discover, true);
+ m->m_discover = 0;
+ }
+ }
+
+ pa_dbus_send_empty_reply(conn, msg);
+
+ return;
+
+error:
+ pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s",
+ "org.tizen.multimedia.audio.Internal");
+}
+
+static void handle_publish_local_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+ pa_stream_manager *m = (pa_stream_manager*)userdata;
+ pa_module *module;
+ dbus_bool_t enable;
+
+ pa_assert(conn);
+ pa_assert(msg);
+ pa_assert(m);
+
+ pa_assert_se(dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_BOOLEAN, &enable,
+ DBUS_TYPE_INVALID));
+
+ pa_log_info("publish module enable(%d)", enable);
+
+ if (enable) {
+ if (m->m_protocol_tcp || m->m_publish) {
+ pa_log_error("already loaded");
+ goto error;
+ }
+
+ if (pa_module_load(&module, m->core, "module-native-protocol-tcp", "auth-anonymous=1")) {
+ pa_log_error("failed to load module");
+ goto error;
+ }
+ m->m_protocol_tcp = module->index;
+
+ if (pa_module_load(&module, m->core, "module-tizenaudio-publish", NULL)) {
+ pa_module_unload_request_by_index(m->core, m->m_protocol_tcp, true);
+ pa_log_error("failed to load module");
+ goto error;
+ }
+ m->m_publish = module->index;
+ } else {
+ if (m->m_protocol_tcp) {
+ pa_module_unload_request_by_index(m->core, m->m_protocol_tcp, true);
+ m->m_protocol_tcp = 0;
+ }
+ if (m->m_publish) {
+ pa_module_unload_request_by_index(m->core, m->m_publish, true);
+ m->m_publish = 0;
+ }
+ }
+
+ pa_dbus_send_empty_reply(conn, msg);
+
+ return;
+
+error:
+ pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED, "%s",
+ "org.tizen.multimedia.audio.Internal");
+}
+
static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
int idx = 0;
pa_stream_manager *m = (pa_stream_manager*)userdata;
dbus_message_unref(signal_msg);
}
+void send_remote_found_signal(DBusConnection *conn, int type, bool connected, unsigned int index,
+ const char *name, const char *description) {
+ DBusMessage *signal_msg;
+ DBusMessageIter msg_iter;
+ dbus_bool_t c = (dbus_bool_t)connected;
+
+ pa_assert(conn);
+
+ if (!name || !description) {
+ pa_log_error("Unknown device");
+ return;
+ }
+
+ pa_log_info("type[%d], index[%d], connected[%d], name[%s] description[%s]", type, index, connected, name, description);
+
+ pa_assert_se((signal_msg = dbus_message_new_signal(STREAM_MANAGER_OBJECT_PATH, STREAM_MANAGER_INTERFACE, STREAM_MANAGER_SIGNAL_NAME_REMOTE_FOUND)));
+ dbus_message_iter_init_append(signal_msg, &msg_iter);
+
+ dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_INT32, &type);
+ dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_UINT32, &index);
+ dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_BOOLEAN, &c);
+ dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name);
+ dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &description);
+
+ pa_assert_se(dbus_connection_send(conn, signal_msg, NULL));
+ dbus_message_unref(signal_msg);
+}
+
int32_t init_sm_dbus(pa_stream_manager *m) {
pa_assert(m);
return PA_HOOK_OK;
}
+static void notify_remote_connection(pa_core *core, pa_object *obj, pa_stream_manager *m, bool connected) {
+ pa_proplist *p;
+ pa_sink_input *i;
+ pa_source_output *o;
+ unsigned int index;
+
+ if (pa_source_output_isinstance(obj)) {
+ o = PA_SOURCE_OUTPUT(obj);
+ p = o->proplist;
+ index = o->index;
+ } else {
+ i = PA_SINK_INPUT(obj);
+ p = i->proplist;
+ index = i->index;
+ }
+
+ if (!p) {
+ pa_log_error("unknown remote client");
+ return;
+ }
+
+ if (pa_proplist_has_remote_name(p)) {
+ send_remote_found_signal(pa_dbus_connection_get(m->dbus_conn),
+ pa_source_output_isinstance(obj) ? 1 : 0, connected, index,
+ pa_proplist_gets(p, PA_PROP_MEDIA_REMOTE_NAME),
+ pa_proplist_gets(p, "native-protocol.peer"));
+ }
+}
+
+static pa_hook_result_t remote_client_put_cb(pa_core *core, pa_object *o, pa_stream_manager *m) {
+ pa_core_assert_ref(core);
+ pa_object_assert_ref(o);
+
+ notify_remote_connection(core, o, m, true);
+
+ return PA_HOOK_OK;
+}
+
+static pa_hook_result_t remote_client_unlink_cb(pa_core *core, pa_object *o, pa_stream_manager *m) {
+ pa_core_assert_ref(core);
+ pa_object_assert_ref(o);
+
+ notify_remote_connection(core, o, m, false);
+
+ return PA_HOOK_OK;
+}
+
static void find_next_device_for_auto_route(pa_stream_manager *m, stream_route_type_t route_type, const char *stream_role,
stream_type_t stream_type, const char *cur_device_type, const char *preferred_device_role, pa_tz_device **next_device) {
stream_info *si = NULL;
m->source_output_move_start_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_START], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_move_start_cb, m);
m->source_output_move_finish_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FINISH], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_move_finish_cb, m);
+ m->remote_sink_input_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_EARLY, (pa_hook_cb_t) remote_client_put_cb, m);
+ m->remote_sink_input_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK], PA_HOOK_EARLY, (pa_hook_cb_t) remote_client_unlink_cb, m);
+ m->remote_source_output_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], PA_HOOK_NORMAL, (pa_hook_cb_t) remote_client_put_cb, m);
+ m->remote_source_output_unlink_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], PA_HOOK_NORMAL, (pa_hook_cb_t) remote_client_unlink_cb, m);
+
m->subscription = pa_subscription_new(m->core, PA_SUBSCRIPTION_MASK_CLIENT | PA_SUBSCRIPTION_MASK_SAMPLE_CACHE, (pa_subscription_cb_t)subscribe_cb, m);
m->comm.comm = pa_communicator_get(c);
pa_hook_slot_free(m->sink_input_new_slot);
if (m->sink_input_put_slot)
pa_hook_slot_free(m->sink_input_put_slot);
+ if (m->remote_sink_input_put_slot)
+ pa_hook_slot_free(m->remote_sink_input_put_slot);
if (m->sink_input_unlink_slot)
pa_hook_slot_free(m->sink_input_unlink_slot);
+ if (m->remote_sink_input_unlink_slot)
+ pa_hook_slot_free(m->remote_sink_input_unlink_slot);
if (m->sink_input_state_changed_slot)
pa_hook_slot_free(m->sink_input_state_changed_slot);
if (m->sink_input_move_start_slot)
pa_hook_slot_free(m->sink_input_move_finish_slot);
if (m->sink_input_ramp_finish_slot)
pa_hook_slot_free(m->sink_input_ramp_finish_slot);
+
if (m->source_output_new_slot)
pa_hook_slot_free(m->source_output_new_slot);
if (m->source_output_put_slot)
pa_hook_slot_free(m->source_output_put_slot);
+ if (m->remote_source_output_put_slot)
+ pa_hook_slot_free(m->remote_source_output_put_slot);
if (m->source_output_unlink_slot)
pa_hook_slot_free(m->source_output_unlink_slot);
+ if (m->remote_source_output_unlink_slot)
+ pa_hook_slot_free(m->remote_source_output_unlink_slot);
if (m->source_output_state_changed_slot)
pa_hook_slot_free(m->source_output_state_changed_slot);
if (m->source_output_move_start_slot)