--- /dev/null
+/***
+ This file is part of PulseAudio.
+
+ Copyright 2016 Seungbae Shin <seungbae.shin@samsung.com>
+
+ 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 <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include <pulse/xmalloc.h>
+#include <pulse/proplist.h>
+
+#include <pulsecore/module.h>
+#include <pulsecore/log.h>
+#include <pulsecore/namereg.h>
+#include <pulsecore/sink.h>
+#include <pulsecore/modargs.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/core-util.h>
+#include <pulsecore/core-error.h>
+#include <pulsecore/dbus-shared.h>
+#include <pulsecore/protocol-dbus.h>
+#include <pulsecore/dbus-util.h>
+#include <pulsecore/core-scache.h>
+
+#include "module-poweroff-symdef.h"
+
+#include "hal-interface.h"
+
+PA_MODULE_AUTHOR("Seungbae Shin");
+PA_MODULE_DESCRIPTION("Poweroff module");
+PA_MODULE_VERSION(PACKAGE_VERSION);
+PA_MODULE_LOAD_ONCE(true);
+
+#define INTERFACE_NAME "org.tizen.system.deviced.PowerOff"
+#define SIGNAL_NAME "ChangeState"
+#define FILTER_POWEROFF "type='signal', interface='"INTERFACE_NAME"', member='"SIGNAL_NAME"'"
+#define BOOT_GAIN_TYPE "booting"
+
+#define STREAM_ROLE_RADIO "radio"
+
+struct userdata {
+ pa_module *module;
+ pa_dbus_connection *dbus_conn;
+ pa_hal_interface *hal_interface;
+ bool is_poweroff;
+ pa_hook_slot *sink_input_put_slot;
+};
+
+static void mute_all_streams(struct userdata *u)
+{
+ uint32_t idx = 0;
+ pa_sink_input *si = NULL;
+ const char *media_role = NULL;
+ hal_route_option route_option;
+
+ PA_IDXSET_FOREACH(si, u->module->core->sink_inputs, idx) {
+ pa_log_info("POWEROFF : mute sink-input(%d)", idx);
+
+ /* FIXME : Any exceptions for mute? */
+ pa_sink_input_set_mute(si, true, false);
+
+ /* Mute Radio via HAL if exists */
+ media_role = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_ROLE);
+ if (pa_safe_streq(media_role, STREAM_ROLE_RADIO)) {
+ pa_log_info(" sink-input(%d) is radio, let HAL mute for poweroff!!", si->index);
+ memset(&route_option, 0, sizeof(hal_route_option));
+ route_option.role = STREAM_ROLE_RADIO;
+ route_option.name = "mute";
+ route_option.value = 1;
+ pa_hal_interface_update_route_option(u->hal_interface, &route_option);
+ }
+ }
+}
+
+static pa_hook_result_t sink_input_put_cb(pa_core *core, pa_sink_input *i, struct userdata *u) {
+ const char *vol_gain_type = NULL;
+
+ pa_core_assert_ref(core);
+ pa_sink_input_assert_ref(i);
+
+ if (!u->is_poweroff)
+ return PA_HOOK_OK;
+
+ vol_gain_type = pa_proplist_gets(i->proplist, PA_PROP_MEDIA_TIZEN_VOLUME_GAIN_TYPE);
+ if (pa_safe_streq(vol_gain_type, BOOT_GAIN_TYPE)) {
+ pa_log_info(" sink-input(%d) is [%s], ignore mute", i->index, BOOT_GAIN_TYPE);
+ } else {
+ pa_log_info(" Mute sink-input(%d) due to POWEROFF", i->index);
+ pa_sink_input_set_mute(i, true, false);
+ }
+
+ return PA_HOOK_OK;
+}
+
+
+static DBusHandlerResult _dbus_filter_device_detect_handler(DBusConnection *c, DBusMessage *s, void *userdata) {
+ struct userdata *u = (struct userdata *)userdata;
+
+ pa_assert(u);
+
+ if (dbus_message_get_type(s) != DBUS_MESSAGE_TYPE_SIGNAL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ pa_log_debug("DBus device detect handler received msg");
+ pa_log_debug("path : %s", dbus_message_get_path(s));
+ pa_log_debug("interface : %s", dbus_message_get_interface(s));
+ pa_log_debug("member : %s", dbus_message_get_member(s));
+ pa_log_debug("signature : %s", dbus_message_get_signature(s));
+
+ if (dbus_message_is_signal(s, INTERFACE_NAME, SIGNAL_NAME)) {
+ pa_log_warn("NOW POWEROFF!!!!");
+ u->is_poweroff = true;
+ mute_all_streams(u);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ pa_log_debug("Unknown message, do not handle this");
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static int _watch_signals(struct userdata *u) {
+ DBusError error;
+
+ pa_assert(u);
+ pa_assert(u->dbus_conn);
+
+ dbus_error_init(&error);
+
+ pa_log_debug("Watch Dbus signals");
+
+ if (!dbus_connection_add_filter(pa_dbus_connection_get(u->dbus_conn), _dbus_filter_device_detect_handler, u, NULL)) {
+ pa_log_error("Unable to add D-Bus filter");
+ return -1;
+ }
+
+ if (pa_dbus_add_matches(pa_dbus_connection_get(u->dbus_conn), &error, FILTER_POWEROFF, NULL) < 0) {
+ pa_log_error("Unable to subscribe to signals: %s: %s", error.name, error.message);
+ dbus_error_free(&error);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void _unwatch_signals(struct userdata *u) {
+ pa_log_debug("Unwatch Dbus signals");
+
+ pa_assert(u);
+ pa_assert(u->dbus_conn);
+
+ pa_dbus_remove_matches(pa_dbus_connection_get(u->dbus_conn), FILTER_POWEROFF, NULL);
+ dbus_connection_remove_filter(pa_dbus_connection_get(u->dbus_conn), _dbus_filter_device_detect_handler, u);
+}
+
+static int _dbus_init(struct userdata *u) {
+ DBusError error;
+ pa_dbus_connection *connection = NULL;
+
+ pa_assert(u);
+
+ dbus_error_init(&error);
+
+ pa_log_debug("Dbus init");
+
+ if (!(connection = pa_dbus_bus_get(u->module->core, DBUS_BUS_SYSTEM, &error)) || dbus_error_is_set(&error)) {
+ if (connection)
+ pa_dbus_connection_unref(connection);
+
+ pa_log_error("Unable to contact D-Bus system bus: %s: %s", error.name, error.message);
+ dbus_error_free(&error);
+ return -1;
+ }
+ pa_log_debug("Got dbus connection %p", connection);
+ u->dbus_conn = connection;
+
+ if (_watch_signals(u) < 0)
+ pa_log_error("dbus watch signals failed");
+ else
+ pa_log_debug("dbus ready to get signals");
+
+ return 0;
+}
+
+static void _dbus_deinit(struct userdata *u) {
+ pa_assert(u);
+
+ pa_log_debug("Dbus deinit");
+
+ _unwatch_signals(u);
+
+ if (u->dbus_conn) {
+ pa_dbus_connection_unref(u->dbus_conn);
+ u->dbus_conn = NULL;
+ }
+}
+
+int pa__init(pa_module *m) {
+ struct userdata *u;
+
+ pa_assert(m);
+
+ m->userdata = u = pa_xnew0(struct userdata, 1);
+ u->module = m;
+ u->dbus_conn = NULL;
+ u->is_poweroff = false;
+
+ if (_dbus_init(u) == -1) {
+ pa__done(m);
+ return -1;
+ }
+
+ u->hal_interface = pa_hal_interface_get(u->module->core);
+ u->sink_input_put_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_put_cb, u);
+
+ return 0;
+}
+
+void pa__done(pa_module *m) {
+ struct userdata *u;
+
+ pa_assert(m);
+
+ if (!(u = m->userdata))
+ return;
+
+ if (u->sink_input_put_slot)
+ pa_hook_slot_free(u->sink_input_put_slot);
+
+ if (u->hal_interface)
+ pa_hal_interface_unref(u->hal_interface);
+
+ _dbus_deinit(u);
+
+ pa_xfree(u);
+}