10 #include "include/mm_sound_mgr_focus_dbus.h"
11 #include "include/mm_sound_mgr_focus_ipc.h"
12 #include "../include/mm_sound_dbus.h"
15 #define BUS_NAME_FOCUS_SERVER "org.tizen.FocusServer"
16 #define OBJECT_FOCUS_SERVER "/org/tizen/FocusServer1"
17 #define INTERFACE_FOCUS_SERVER "org.tizen.FocusServer1"
19 /* Introspection data for the service we are exporting */
20 static const gchar introspection_xml[] =
22 " <interface name='org.tizen.FocusServer1'>"
23 " <method name='GetUniqueId'>"
24 " <arg name='id' type='i' direction='out'/>"
26 " <method name='RegisterFocus'>"
27 " <arg name='pid' type='i' direction='in'/>"
28 " <arg name='handle_id' type='i' direction='in'/>"
29 " <arg name='stream_type' type='s' direction='in'/>"
30 " <arg name='is_for_session' type='b' direction='in'/>"
32 " <method name='UnregisterFocus'>"
33 " <arg name='pid' type='i' direction='in'/>"
34 " <arg name='handle_id' type='i' direction='in'/>"
35 " <arg name='is_for_session' type='b' direction='in'/>"
37 " <method name='SetFocusReacquisition'>"
38 " <arg name='pid' type='i' direction='in'/>"
39 " <arg name='handle_id' type='i' direction='in'/>"
40 " <arg name='reacquisition' type='b' direction='in'/>"
42 " <method name='GetAcquiredFocusStreamType'>"
43 " <arg name='focus_type' type='i' direction='in'/>"
44 " <arg name='stream_type' type='s' direction='out'/>"
45 " <arg name='option' type='i' direction='out'/>"
46 " <arg name='ext_info' type='s' direction='out'/>"
48 " <method name='AcquireFocus'>"
49 " <arg name='pid' type='i' direction='in'/>"
50 " <arg name='handle_id' type='i' direction='in'/>"
51 " <arg name='focus_type' type='i' direction='in'/>"
52 " <arg name='option' type='i' direction='in'/>"
53 " <arg name='ext_info' type='s' direction='in'/>"
54 " <arg name='is_for_session' type='b' direction='in'/>"
56 " <method name='ReleaseFocus'>"
57 " <arg name='pid' type='i' direction='in'/>"
58 " <arg name='handle_id' type='i' direction='in'/>"
59 " <arg name='focus_type' type='i' direction='in'/>"
60 " <arg name='option' type='i' direction='in'/>"
61 " <arg name='ext_info' type='s' direction='in'/>"
62 " <arg name='is_for_session' type='b' direction='in'/>"
64 " <method name='WatchFocus'>"
65 " <arg name='pid' type='i' direction='in'/>"
66 " <arg name='handle_id' type='i' direction='in'/>"
67 " <arg name='focus_type' type='i' direction='in'/>"
68 " <arg name='is_for_session' type='b' direction='in'/>"
70 " <method name='UnwatchFocus'>"
71 " <arg name='pid' type='i' direction='in'/>"
72 " <arg name='handle_id' type='i' direction='in'/>"
73 " <arg name='is_for_session' type='b' direction='in'/>"
75 " <method name='EmergentExitFocus'>"
76 " <arg name='pid' type='i' direction='in'/>"
80 static GDBusConnection* conn_g;
82 typedef void (*dbus_method_handler)(GDBusMethodInvocation *invocation);
83 typedef int (*dbus_signal_sender)(GDBusConnection *conn, GVariant *parameter);
85 struct mm_sound_mgr_focus_dbus_method{
86 struct mm_sound_dbus_method_info info;
87 dbus_method_handler handler;
90 struct mm_sound_mgr_focus_dbus_signal{
91 struct mm_sound_dbus_signal_info info;
92 dbus_signal_sender sender;
95 static void handle_method_get_unique_id(GDBusMethodInvocation* invocation);
96 static void handle_method_register_focus(GDBusMethodInvocation* invocation);
97 static void handle_method_unregister_focus(GDBusMethodInvocation* invocation);
98 static void handle_method_set_focus_reacquisition(GDBusMethodInvocation* invocation);
99 static void handle_method_get_acquired_focus_stream_type(GDBusMethodInvocation* invocation);
100 static void handle_method_acquire_focus(GDBusMethodInvocation* invocation);
101 static void handle_method_release_focus(GDBusMethodInvocation* invocation);
102 static void handle_method_watch_focus(GDBusMethodInvocation* invocation);
103 static void handle_method_unwatch_focus(GDBusMethodInvocation* invocation);
105 /* Currently , Just using method's name and handler */
106 /* TODO : generate introspection xml automatically, with these value include argument and reply */
107 /* TODO : argument check with these information */
108 /* TODO : divide object and interface with features (ex. play, path, device, focus, asm) */
109 static mm_sound_dbus_method_intf_t methods[AUDIO_METHOD_MAX] = {
110 [AUDIO_METHOD_GET_UNIQUE_ID] = {
112 .name = "GetUniqueId",
114 .handler = handle_method_get_unique_id
116 [AUDIO_METHOD_REGISTER_FOCUS] = {
118 .name = "RegisterFocus",
120 .handler = handle_method_register_focus
122 [AUDIO_METHOD_UNREGISTER_FOCUS] = {
124 .name = "UnregisterFocus",
126 .handler = handle_method_unregister_focus
128 [AUDIO_METHOD_SET_FOCUS_REACQUISITION] = {
130 .name = "SetFocusReacquisition",
132 .handler = handle_method_set_focus_reacquisition
134 [AUDIO_METHOD_GET_ACQUIRED_FOCUS_STREAM_TYPE] = {
136 .name = "GetAcquiredFocusStreamType",
138 .handler = handle_method_get_acquired_focus_stream_type
140 [AUDIO_METHOD_ACQUIRE_FOCUS] = {
142 .name = "AcquireFocus",
144 .handler = handle_method_acquire_focus
146 [AUDIO_METHOD_RELEASE_FOCUS] = {
148 .name = "ReleaseFocus",
150 .handler = handle_method_release_focus
152 [AUDIO_METHOD_WATCH_FOCUS] = {
154 .name = "WatchFocus",
156 .handler = handle_method_watch_focus
158 [AUDIO_METHOD_UNWATCH_FOCUS] = {
160 .name = "UnwatchFocus",
162 .handler = handle_method_unwatch_focus
166 static GDBusNodeInfo *introspection_data = NULL;
167 guint focus_server_owner_id ;
168 unsigned emergent_exit_subs_id;
171 For pass error code with 'g_dbus_method_invocation_return_error'
172 We have to use some glib features like GError, GQuark
174 /* Only For error types which is currently being used in server-side */
175 static const GDBusErrorEntry mm_sound_error_entries[] =
177 {MM_ERROR_OUT_OF_MEMORY, "org.tizen.multimedia.OutOfMemory"},
178 {MM_ERROR_OUT_OF_STORAGE, "org.tizen.multimedia.OutOfStorage"},
179 {MM_ERROR_INVALID_ARGUMENT, "org.tizen.multimedia.InvalidArgument"},
180 {MM_ERROR_POLICY_INTERNAL, "org.tizen.multimedia.PolicyInternal"},
181 {MM_ERROR_NOT_SUPPORT_API, "org.tizen.multimedia.NotSupportAPI"},
182 {MM_ERROR_POLICY_BLOCKED, "org.tizen.multimedia.PolicyBlocked"},
183 {MM_ERROR_END_OF_FILE, "org.tizen.multimedia.EndOfFile"},
184 {MM_ERROR_COMMON_OUT_OF_RANGE, "org.tizen.multimedia.common.OutOfRange"},
185 {MM_ERROR_COMMON_UNKNOWN, "org.tizen.multimedia.common.Unknown"},
186 {MM_ERROR_COMMON_NO_FREE_SPACE, "org.tizen.multimedia.common.NoFreeSpace"},
187 {MM_ERROR_SOUND_INTERNAL, "org.tizen.multimedia.audio.Internal"},
188 {MM_ERROR_SOUND_INVALID_STATE, "org.tizen.multimedia.audio.InvalidState"},
189 {MM_ERROR_SOUND_NO_FREE_SPACE, "org.tizen.multimedia.audio.NoFreeSpace"},
190 {MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE, "org.tizen.multimedia.audio.UnsupportedMediaType"},
191 {MM_ERROR_SOUND_INVALID_POINTER, "org.tizen.multimedia.audio.InvalidPointer"},
192 {MM_ERROR_SOUND_INVALID_FILE, "org.tizen.multimedia.audio.InvalidFile"},
193 {MM_ERROR_SOUND_FILE_NOT_FOUND, "org.tizen.multimedia.audio.FileNotFound"},
194 {MM_ERROR_SOUND_NO_DATA, "org.tizen.multimedia.audio.NoData"},
195 {MM_ERROR_SOUND_INVALID_PATH, "org.tizen.multimedia.audio.InvalidPath"},
198 static const char* _convert_error_code(int err_code)
202 for (i = 0; i < G_N_ELEMENTS(mm_sound_error_entries); i++) {
203 if (err_code == mm_sound_error_entries[i].error_code) {
204 return mm_sound_error_entries[i].dbus_error_name;
208 return "org.tizen.multimedia.common.Unknown";
211 static int _get_sender_pid(GDBusMethodInvocation* invocation)
216 GDBusConnection * connection = NULL;
219 connection = g_dbus_method_invocation_get_connection(invocation);
220 sender = g_dbus_method_invocation_get_sender(invocation);
222 debug_msg("connection = %p, sender = %s", connection, sender);
224 value = g_dbus_connection_call_sync(connection, "org.freedesktop.DBus", "/org/freedesktop/DBus",
225 "org.freedesktop.DBus", "GetConnectionUnixProcessID",
226 g_variant_new("(s)", sender, NULL), NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
228 g_variant_get(value, "(u)", &pid);
229 debug_msg("Sender PID = [%d]", pid);
230 g_variant_unref(value);
232 debug_error("err code = %d, err msg = %s", err->code, err->message);
237 static void _method_call_return_value(GDBusMethodInvocation *invocation, GVariant *params)
239 const char *method_name;
240 method_name = g_dbus_method_invocation_get_method_name(invocation);
241 debug_msg("Method Call '%s' success", method_name);
242 g_dbus_method_invocation_return_value(invocation, params);
244 static void _method_call_return_error(GDBusMethodInvocation *invocation, int ret)
246 const char *err_name, *method_name;
247 err_name = _convert_error_code(ret);
248 method_name = g_dbus_method_invocation_get_method_name(invocation);
249 debug_error("Method Call '%s' failed, err '%s(%X)'", method_name, err_name, ret);
250 g_dbus_method_invocation_return_dbus_error(invocation, err_name, "failed");
253 static void handle_method_get_unique_id(GDBusMethodInvocation* invocation)
255 static int unique_id = 0;
259 _method_call_return_value(invocation, g_variant_new("(i)", ++unique_id));
264 static void handle_method_register_focus(GDBusMethodInvocation* invocation)
266 int ret = MM_ERROR_NONE;
268 const char* stream_type = NULL;
269 gboolean is_for_session;
270 GVariant *params = NULL;
275 if (!(params = g_dbus_method_invocation_get_parameters(invocation))) {
276 debug_error("Parameter for Method is NULL");
277 ret = MM_ERROR_SOUND_INTERNAL;
281 g_variant_get(params, "(ii&sb)", &pid, &handle_id, &stream_type, &is_for_session);
282 ret = __mm_sound_mgr_focus_ipc_register_focus((is_for_session) ? pid : _get_sender_pid(invocation), handle_id, stream_type, is_for_session);
285 if (ret == MM_ERROR_NONE) {
286 _method_call_return_value(invocation, g_variant_new("()"));
288 _method_call_return_error(invocation, ret);
294 static void handle_method_unregister_focus(GDBusMethodInvocation* invocation)
296 int ret = MM_ERROR_NONE;
297 int pid = 0, handle_id = 0;
298 gboolean is_for_session;
299 GVariant *params = NULL;
303 if (!(params = g_dbus_method_invocation_get_parameters(invocation))) {
304 debug_error("Parameter for Method is NULL");
305 ret = MM_ERROR_SOUND_INTERNAL;
309 g_variant_get(params, "(iib)", &pid, &handle_id, &is_for_session);
310 ret = __mm_sound_mgr_focus_ipc_unregister_focus((is_for_session) ? pid : _get_sender_pid(invocation), handle_id, is_for_session);
313 if (ret == MM_ERROR_NONE) {
314 _method_call_return_value(invocation, g_variant_new("()"));
316 _method_call_return_error(invocation, ret);
322 static void handle_method_set_focus_reacquisition(GDBusMethodInvocation* invocation)
324 int ret = MM_ERROR_NONE;
325 int pid = 0, handle_id = 0;
326 gboolean reacquisition;
327 GVariant *params = NULL;
331 if (!(params = g_dbus_method_invocation_get_parameters(invocation))) {
332 debug_error("Parameter for Method is NULL");
333 ret = MM_ERROR_SOUND_INTERNAL;
337 g_variant_get(params, "(iib)", &pid, &handle_id, &reacquisition);
338 ret = __mm_sound_mgr_focus_ipc_set_focus_reacquisition(_get_sender_pid(invocation), handle_id, reacquisition);
341 if (ret == MM_ERROR_NONE) {
342 _method_call_return_value(invocation, g_variant_new("()"));
344 _method_call_return_error(invocation, ret);
350 static void handle_method_get_acquired_focus_stream_type(GDBusMethodInvocation* invocation)
352 int ret = MM_ERROR_NONE;
354 char *stream_type = NULL;
356 char *ext_info = NULL;
357 GVariant *params = NULL;
361 if (!(params = g_dbus_method_invocation_get_parameters(invocation))) {
362 debug_error("Parameter for Method is NULL");
363 ret = MM_ERROR_SOUND_INTERNAL;
367 g_variant_get(params, "(i)", &focus_type);
368 ret = __mm_sound_mgr_focus_ipc_get_acquired_focus_stream_type(focus_type, &stream_type, &option, &ext_info);
371 if (ret == MM_ERROR_NONE) {
372 _method_call_return_value(invocation, g_variant_new("(sis)", stream_type, option, ext_info));
374 _method_call_return_error(invocation, ret);
380 static void handle_method_acquire_focus(GDBusMethodInvocation* invocation)
382 int ret = MM_ERROR_NONE;
383 int pid = 0, handle_id = 0, focus_type = 0, option = 0;
384 const char* ext_info = NULL;
385 gboolean is_for_session;
386 GVariant *params = NULL;
390 if (!(params = g_dbus_method_invocation_get_parameters(invocation))) {
391 debug_error("Parameter for Method is NULL");
392 ret = MM_ERROR_SOUND_INTERNAL;
396 g_variant_get(params, "(iiiisb)", &pid, &handle_id, &focus_type, &option, &ext_info, &is_for_session);
397 ret = __mm_sound_mgr_focus_ipc_acquire_focus((is_for_session) ? pid : _get_sender_pid(invocation), handle_id, focus_type, option, ext_info, is_for_session);
400 if (ret == MM_ERROR_NONE) {
401 _method_call_return_value(invocation, g_variant_new("()"));
403 _method_call_return_error(invocation, ret);
409 static void handle_method_release_focus(GDBusMethodInvocation* invocation)
411 int ret = MM_ERROR_NONE;
412 int pid = 0, handle_id = 0, focus_type = 0, option = 0;
413 const char* ext_info = NULL;
414 gboolean is_for_session;
415 GVariant *params = NULL;
419 if (!(params = g_dbus_method_invocation_get_parameters(invocation))) {
420 debug_error("Parameter for Method is NULL");
421 ret = MM_ERROR_SOUND_INTERNAL;
425 g_variant_get(params, "(iiiisb)", &pid, &handle_id, &focus_type, &option, &ext_info, &is_for_session);
426 ret = __mm_sound_mgr_focus_ipc_release_focus((is_for_session) ? pid : _get_sender_pid(invocation), handle_id, focus_type, option, ext_info, is_for_session);
429 if (ret == MM_ERROR_NONE) {
430 _method_call_return_value(invocation, g_variant_new("()"));
432 _method_call_return_error(invocation, ret);
438 static void handle_method_watch_focus(GDBusMethodInvocation* invocation)
440 int ret = MM_ERROR_NONE;
441 int handle_id = 0, focus_type = 0;
442 gboolean is_for_session;
443 GVariant *params = NULL;
448 if (!(params = g_dbus_method_invocation_get_parameters(invocation))) {
449 debug_error("Parameter for Method is NULL");
450 ret = MM_ERROR_SOUND_INTERNAL;
454 g_variant_get(params, "(iiib)", &pid, &handle_id, &focus_type, &is_for_session);
455 ret = __mm_sound_mgr_focus_ipc_watch_focus((is_for_session) ? pid : _get_sender_pid(invocation), handle_id, focus_type, is_for_session);
458 if (ret == MM_ERROR_NONE) {
459 _method_call_return_value(invocation, g_variant_new("()"));
461 _method_call_return_error(invocation, ret);
467 static void handle_method_unwatch_focus(GDBusMethodInvocation* invocation)
469 int ret = MM_ERROR_NONE;
472 gboolean is_for_session;
473 GVariant *params = NULL;
477 if (!(params = g_dbus_method_invocation_get_parameters(invocation))) {
478 debug_error("Parameter for Method is NULL");
479 ret = MM_ERROR_SOUND_INTERNAL;
483 g_variant_get(params, "(iib)", &pid, &handle_id, &is_for_session);
484 ret = __mm_sound_mgr_focus_ipc_unwatch_focus((is_for_session) ? pid : _get_sender_pid(invocation), handle_id);
487 if (ret == MM_ERROR_NONE) {
488 _method_call_return_value(invocation, g_variant_new("()"));
490 _method_call_return_error(invocation, ret);
496 /**********************************************************************************/
497 static void handle_method_call(GDBusConnection *connection,
499 const gchar *object_path,
500 const gchar *interface_name,
501 const gchar *method_name,
502 GVariant *parameters,
503 GDBusMethodInvocation *invocation,
509 debug_error("Parameter Null");
512 debug_log("Method Call, obj : %s, intf : %s, method : %s", object_path, interface_name, method_name);
514 for (method_idx = AUDIO_METHOD_GET_UNIQUE_ID; method_idx < AUDIO_METHOD_MAX; method_idx++) {
515 if (!g_strcmp0(method_name, methods[method_idx].info.name)) {
516 methods[method_idx].handler(invocation);
522 static GVariant* handle_get_property(GDBusConnection *connection,
524 const gchar *object_path,
525 const gchar *interface_name,
526 const gchar *property_name,
530 debug_log("Get Property, obj : %s, intf : %s, prop : %s", object_path, interface_name, property_name);
534 static gboolean handle_set_property(GDBusConnection *connection,
536 const gchar *object_path,
537 const gchar *interface_name,
538 const gchar *property_name,
543 debug_log("Set Property, obj : %s, intf : %s, prop : %s", object_path, interface_name, property_name);
547 void emergent_exit_signal_handler(audio_event_t event, GVariant *param, void *userdata)
549 int ret = MM_ERROR_NONE;
552 if (event != AUDIO_EVENT_EMERGENT_EXIT)
557 g_variant_get(param, "(i)", &pid);
558 debug_log("emergent exit : pid %d", pid);
559 ret = __mm_sound_mgr_focus_ipc_emergent_exit(pid);
561 debug_error("__mm_sound_mgr_focus_ipc_emergent_exit failed : 0x%x", ret);
566 static const GDBusInterfaceVTable interface_vtable =
573 static void on_bus_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data)
576 debug_log("Bus Acquired (%s)", name);
579 reg_id = g_dbus_connection_register_object(connection,
581 introspection_data->interfaces[0],
587 debug_error("Register object(%s) failed", OBJECT_FOCUS_SERVER);
592 static void on_name_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data)
594 debug_log("Name Acquired (%s)", name);
597 static void on_name_lost(GDBusConnection *connection, const gchar *name, gpointer user_data)
599 debug_log("Name Lost (%s)", name);
602 static int _mm_sound_mgr_focus_dbus_own_name(GBusType bus_type, const char* wellknown_name, guint* owner_id)
606 debug_msg("Own name (%s) for focus-server", wellknown_name);
608 oid = g_bus_own_name(bus_type, wellknown_name, G_BUS_NAME_OWNER_FLAGS_NONE,
609 on_bus_acquired, on_name_acquired, on_name_lost, NULL, NULL);
611 debug_error("Dbus own name failed");
612 return MM_ERROR_SOUND_INTERNAL;
617 debug_msg("OwnerID (%d) for focus-server", *owner_id);
619 return MM_ERROR_NONE;
622 static void _mm_sound_mgr_focus_dbus_unown_name(guint oid)
624 debug_msg("Unown name for focus-server [%d]", oid);
626 g_bus_unown_name(oid);
630 #define PA_BUS_NAME "org.pulseaudio.Server"
631 #define PA_STREAM_MANAGER_OBJECT_PATH "/org/pulseaudio/StreamManager"
632 #define PA_STREAM_MANAGER_INTERFACE "org.pulseaudio.StreamManager"
633 #define PA_STREAM_MANAGER_METHOD_NAME_GET_STREAM_LIST "GetStreamList"
634 int __mm_sound_mgr_focus_dbus_get_stream_list(stream_list_t* stream_list)
636 int ret = MM_ERROR_NONE;
637 GVariant *result = NULL;
638 GVariant *child = NULL;
639 GDBusConnection *conn = NULL;
643 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
645 LOGE("g_bus_get_sync() error (%s)", err->message);
647 ret = MM_ERROR_SOUND_INTERNAL;
650 result = g_dbus_connection_call_sync(conn,
652 PA_STREAM_MANAGER_OBJECT_PATH,
653 PA_STREAM_MANAGER_INTERFACE,
654 PA_STREAM_MANAGER_METHOD_NAME_GET_STREAM_LIST,
656 G_VARIANT_TYPE("(vv)"),
657 G_DBUS_CALL_FLAGS_NONE,
661 if (!result && err) {
662 debug_error("g_dbus_connection_call_sync() error (%s)", err->message);
663 ret = MM_ERROR_SOUND_INTERNAL;
666 GVariant *item = NULL;
667 child = g_variant_get_child_value(result, 0);
668 item = g_variant_get_variant(child);
671 g_variant_iter_init(&iter, item);
672 while ((i < AVAIL_STREAMS_MAX) && g_variant_iter_loop(&iter, "&s", &name)) {
673 debug_log("name : %s", name);
674 stream_list->stream_types[i++] = strdup(name);
676 g_variant_unref(item);
677 g_variant_unref(child);
679 child = g_variant_get_child_value(result, 1);
680 item = g_variant_get_variant(child);
683 g_variant_iter_init(&iter, item);
684 while ((i < AVAIL_STREAMS_MAX) && g_variant_iter_loop(&iter, "i", &priority)) {
685 debug_log("priority : %d", priority);
686 stream_list->priorities[i++] = priority;
688 g_variant_unref(item);
689 g_variant_unref(child);
691 g_variant_unref(result);
693 g_object_unref(conn);
698 int MMSoundMgrFocusDbusInit(void)
702 introspection_data = g_dbus_node_info_new_for_xml(introspection_xml, NULL);
703 if (!introspection_data)
704 return MM_ERROR_SOUND_INTERNAL;
706 if (_mm_sound_mgr_focus_dbus_own_name(G_BUS_TYPE_SYSTEM, BUS_NAME_FOCUS_SERVER, &focus_server_owner_id) != MM_ERROR_NONE) {
707 debug_error("dbus own name for focus-server error\n");
708 return MM_ERROR_SOUND_INTERNAL;
710 if (mm_sound_dbus_signal_subscribe_to(AUDIO_PROVIDER_AUDIO_CLIENT, AUDIO_EVENT_EMERGENT_EXIT, emergent_exit_signal_handler, NULL, NULL, &emergent_exit_subs_id) != MM_ERROR_NONE) {
711 debug_error("dbus signal subscribe for emergent exit error\n");
712 return MM_ERROR_SOUND_INTERNAL;
717 return MM_ERROR_NONE;
720 void MMSoundMgrFocusDbusFini(void)
724 if (emergent_exit_subs_id != 0)
725 mm_sound_dbus_signal_unsubscribe(emergent_exit_subs_id);
726 _mm_sound_mgr_focus_dbus_unown_name(focus_server_owner_id);
727 g_dbus_node_info_unref(introspection_data);