poweroff: Changes the file permission to 644
[platform/core/multimedia/pulseaudio-modules-tizen.git] / src / module-poweroff.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2016 Seungbae Shin <seungbae.shin@samsung.com>
5
6   PulseAudio is free software; you can redistribute it and/or modify
7   it under the terms of the GNU Lesser General Public License as published
8   by the Free Software Foundation; either version 2.1 of the License,
9   or (at your option) any later version.
10
11   PulseAudio is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with PulseAudio; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <stdlib.h>
30 #include <fcntl.h>
31 #include <sys/stat.h>
32 #include <errno.h>
33
34 #include <pulse/xmalloc.h>
35 #include <pulse/proplist.h>
36
37 #include <pulsecore/module.h>
38 #include <pulsecore/log.h>
39 #include <pulsecore/namereg.h>
40 #include <pulsecore/sink.h>
41 #include <pulsecore/modargs.h>
42 #include <pulsecore/macro.h>
43 #include <pulsecore/core-util.h>
44 #include <pulsecore/core-error.h>
45 #include <pulsecore/dbus-shared.h>
46 #include <pulsecore/protocol-dbus.h>
47 #include <pulsecore/dbus-util.h>
48 #include <pulsecore/core-scache.h>
49
50 #include "module-poweroff-symdef.h"
51
52 #include "hal-interface.h"
53
54 PA_MODULE_AUTHOR("Seungbae Shin");
55 PA_MODULE_DESCRIPTION("Poweroff module");
56 PA_MODULE_VERSION(PACKAGE_VERSION);
57 PA_MODULE_LOAD_ONCE(true);
58
59 #define INTERFACE_NAME "org.tizen.system.deviced.PowerOff"
60 #define SIGNAL_NAME    "ChangeState"
61 #define FILTER_POWEROFF  "type='signal', interface='"INTERFACE_NAME"', member='"SIGNAL_NAME"'"
62 #define BOOT_GAIN_TYPE "booting"
63
64 #define STREAM_ROLE_RADIO "radio"
65
66 enum deviced_poweroff_type {
67     DEVICED_POWER_OFF_NONE = 0,
68     DEVICED_POWER_OFF_POPUP,
69     DEVICED_POWER_OFF_DIRECT,
70     DEVICED_POWER_OFF_RESTART,
71 };
72
73 struct userdata {
74     pa_module *module;
75     pa_dbus_connection *dbus_conn;
76     pa_hal_interface *hal_interface;
77     bool is_poweroff;
78     pa_hook_slot *sink_input_new_slot;
79 };
80
81 static void mute_all_streams(struct userdata *u)
82 {
83     uint32_t idx = 0;
84     pa_sink_input *si = NULL;
85     const char *media_role = NULL;
86     hal_route_option route_option;
87
88     PA_IDXSET_FOREACH(si, u->module->core->sink_inputs, idx) {
89         pa_log_info("POWEROFF : mute sink-input(%d)", idx);
90
91         /* FIXME : Any exceptions for mute? */
92         pa_sink_input_set_mute(si, true, false);
93
94         /* Mute Radio via HAL if exists */
95         media_role = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_ROLE);
96         if (pa_safe_streq(media_role, STREAM_ROLE_RADIO)) {
97             pa_log_info(" sink-input(%d) is radio, let HAL mute for poweroff!!", si->index);
98             memset(&route_option, 0, sizeof(hal_route_option));
99             route_option.role = STREAM_ROLE_RADIO;
100             route_option.name = "mute";
101             route_option.value = 1;
102             pa_hal_interface_update_route_option(u->hal_interface, &route_option);
103         }
104     }
105 }
106
107 static pa_hook_result_t sink_input_new_cb(pa_core *core, pa_sink_input_new_data *new_data, struct userdata *u) {
108     const char *vol_gain_type = NULL;
109
110     pa_core_assert_ref(core);
111     pa_assert(new_data);
112     pa_assert(u);
113
114     if (!u->is_poweroff)
115         return PA_HOOK_OK;
116
117     vol_gain_type = pa_proplist_gets(new_data->proplist, PA_PROP_MEDIA_TIZEN_VOLUME_GAIN_TYPE);
118     if (pa_safe_streq(vol_gain_type, BOOT_GAIN_TYPE)) {
119         pa_log_info(" ignore mute for gain [%s]", BOOT_GAIN_TYPE);
120     } else {
121         pa_log_info(" Mute sink-input due to POWEROFF");
122         pa_sink_input_new_data_set_muted(new_data, true);
123     }
124
125     return PA_HOOK_OK;
126 }
127
128 static DBusHandlerResult _dbus_filter_device_detect_handler(DBusConnection *c, DBusMessage *s, void *userdata) {
129     struct userdata *u = (struct userdata *)userdata;
130     int state = 0;
131
132     pa_assert(u);
133
134     if (dbus_message_get_type(s) != DBUS_MESSAGE_TYPE_SIGNAL)
135         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
136
137     pa_log_debug("DBus device detect handler received msg");
138     pa_log_debug("path       : %s", dbus_message_get_path(s));
139     pa_log_debug("interface  : %s", dbus_message_get_interface(s));
140     pa_log_debug("member     : %s", dbus_message_get_member(s));
141     pa_log_debug("signature  : %s", dbus_message_get_signature(s));
142
143     if (dbus_message_is_signal(s, INTERFACE_NAME, SIGNAL_NAME)) {
144         if (dbus_message_get_args(s, NULL, DBUS_TYPE_INT32, &state, DBUS_TYPE_INVALID)) {
145             if (state == DEVICED_POWER_OFF_DIRECT ||
146                 state == DEVICED_POWER_OFF_RESTART) {
147                 const char* mode_str[] = { "None", "Popup", "Direct", "Restart" };
148                 pa_log_warn("---- PowerOff : %s ----", mode_str[state]);
149                 u->is_poweroff = true;
150                 mute_all_streams(u);
151             }
152         } else
153             pa_log_error("failed to parse state, do nothing!!!");
154
155         return DBUS_HANDLER_RESULT_HANDLED;
156     }
157
158     pa_log_debug("Unknown message, do not handle this");
159     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
160 }
161
162 static int _watch_signals(struct userdata *u) {
163     DBusError error;
164
165     pa_assert(u);
166     pa_assert(u->dbus_conn);
167
168     dbus_error_init(&error);
169
170     pa_log_debug("Watch Dbus signals");
171
172     if (!dbus_connection_add_filter(pa_dbus_connection_get(u->dbus_conn), _dbus_filter_device_detect_handler, u, NULL)) {
173         pa_log_error("Unable to add D-Bus filter");
174         return -1;
175     }
176
177     if (pa_dbus_add_matches(pa_dbus_connection_get(u->dbus_conn), &error, FILTER_POWEROFF, NULL) < 0) {
178         pa_log_error("Unable to subscribe to signals: %s: %s", error.name, error.message);
179         dbus_error_free(&error);
180         return -1;
181     }
182
183     return 0;
184 }
185
186 static void _unwatch_signals(struct userdata *u) {
187     pa_log_debug("Unwatch Dbus signals");
188
189     pa_assert(u);
190     pa_assert(u->dbus_conn);
191
192     pa_dbus_remove_matches(pa_dbus_connection_get(u->dbus_conn), FILTER_POWEROFF, NULL);
193     dbus_connection_remove_filter(pa_dbus_connection_get(u->dbus_conn), _dbus_filter_device_detect_handler, u);
194 }
195
196 static int _dbus_init(struct userdata *u) {
197     DBusError error;
198     pa_dbus_connection *connection = NULL;
199
200     pa_assert(u);
201
202     dbus_error_init(&error);
203
204     pa_log_debug("Dbus init");
205
206     if (!(connection = pa_dbus_bus_get(u->module->core, DBUS_BUS_SYSTEM, &error)) || dbus_error_is_set(&error)) {
207         if (connection)
208             pa_dbus_connection_unref(connection);
209
210         pa_log_error("Unable to contact D-Bus system bus: %s: %s", error.name, error.message);
211         dbus_error_free(&error);
212         return -1;
213     }
214     pa_log_debug("Got dbus connection %p", connection);
215     u->dbus_conn = connection;
216
217     if (_watch_signals(u) < 0)
218         pa_log_error("dbus watch signals failed");
219     else
220         pa_log_debug("dbus ready to get signals");
221
222     return 0;
223 }
224
225 static void _dbus_deinit(struct userdata *u) {
226     pa_assert(u);
227
228     pa_log_debug("Dbus deinit");
229
230     _unwatch_signals(u);
231
232     if (u->dbus_conn) {
233         pa_dbus_connection_unref(u->dbus_conn);
234         u->dbus_conn = NULL;
235     }
236 }
237
238 int pa__init(pa_module *m) {
239     struct userdata *u;
240
241     pa_assert(m);
242
243     m->userdata = u = pa_xnew0(struct userdata, 1);
244     u->module = m;
245     u->dbus_conn = NULL;
246     u->is_poweroff = false;
247
248     if (_dbus_init(u) == -1) {
249         pa__done(m);
250         return -1;
251     }
252
253     u->hal_interface = pa_hal_interface_get(u->module->core);
254     u->sink_input_new_slot = pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SINK_INPUT_NEW], PA_HOOK_LATE, (pa_hook_cb_t) sink_input_new_cb, u);
255
256     return 0;
257 }
258
259 void pa__done(pa_module *m) {
260     struct userdata *u;
261
262     pa_assert(m);
263
264     if (!(u = m->userdata))
265         return;
266
267     if (u->sink_input_new_slot)
268         pa_hook_slot_free(u->sink_input_new_slot);
269
270     if (u->hal_interface)
271         pa_hal_interface_unref(u->hal_interface);
272
273     _dbus_deinit(u);
274
275     pa_xfree(u);
276 }