8 #include "../include/mm_sound_dbus.h"
9 #include "../include/mm_sound_intf.h"
11 #define INTERFACE_DBUS "org.freedesktop.DBus.Properties"
12 #define SIGNAL_PROP_CHANGED "PropertiesChanged"
13 #define METHOD_GET "Get"
14 #define METHOD_SET "Set"
16 struct callback_data {
17 mm_sound_dbus_callback user_cb;
19 mm_sound_dbus_userdata_free free_func;
28 const struct dbus_path g_paths[AUDIO_PROVIDER_MAX] = {
29 [AUDIO_PROVIDER_SOUND_SERVER] = {
30 .bus_name = "org.tizen.SoundServer",
31 .object = "/org/tizen/SoundServer1",
32 .interface ="org.tizen.SoundServer1"
34 [AUDIO_PROVIDER_FOCUS_SERVER] = {
35 .bus_name = "org.tizen.FocusServer",
36 .object = "/org/tizen/FocusServer1",
37 .interface = "org.tizen.FocusServer1"
39 [AUDIO_PROVIDER_DEVICE_MANAGER] = {
40 .bus_name = "org.pulseaudio.Server",
41 .object = "/org/pulseaudio/DeviceManager",
42 .interface = "org.pulseaudio.DeviceManager"
44 [AUDIO_PROVIDER_STREAM_MANAGER] = {
45 .bus_name = "org.pulseaudio.Server",
46 .object = "/org/pulseaudio/StreamManager",
47 .interface = "org.pulseaudio.StreamManager"
49 [AUDIO_PROVIDER_AUDIO_CLIENT] = {
50 .bus_name = "org.tizen.AudioClient",
51 .object = "/org/tizen/AudioClient1",
52 .interface = "org.tizen.AudioClient1"
56 const mm_sound_dbus_method_info_t g_methods[AUDIO_METHOD_MAX] = {
57 [AUDIO_METHOD_TEST] = {
58 .name = "MethodTest1",
60 [AUDIO_METHOD_PLAY_FILE_START] = {
61 .name = "PlayFileStart",
63 [AUDIO_METHOD_PLAY_FILE_START_WITH_STREAM_INFO] = {
64 .name = "PlayFileStartWithStreamInfo",
66 [AUDIO_METHOD_PLAY_FILE_STOP] = {
67 .name = "PlayFileStop",
69 [AUDIO_METHOD_PLAY_DTMF] = {
72 [AUDIO_METHOD_PLAY_DTMF_WITH_STREAM_INFO] = {
73 .name = "PlayDTMFWithStreamInfo",
75 [AUDIO_METHOD_CLEAR_FOCUS] = {
78 [AUDIO_METHOD_SET_VOLUME_LEVEL] = {
79 .name = "SetVolumeLevel",
81 [AUDIO_METHOD_GET_CONNECTED_DEVICE_LIST] = {
82 .name = "GetConnectedDeviceList",
84 [AUDIO_METHOD_GET_DEVICE_BY_ID] = {
85 .name = "GetDeviceById",
87 [AUDIO_METHOD_IS_STREAM_ON_DEVICE] = {
88 .name = "IsStreamOnDevice",
90 [AUDIO_METHOD_GET_UNIQUE_ID] = {
91 .name = "GetUniqueId",
93 [AUDIO_METHOD_REGISTER_FOCUS] = {
94 .name = "RegisterFocus",
96 [AUDIO_METHOD_UNREGISTER_FOCUS] = {
97 .name = "UnregisterFocus",
99 [AUDIO_METHOD_SET_FOCUS_REACQUISITION] = {
100 .name = "SetFocusReacquisition",
102 [AUDIO_METHOD_GET_ACQUIRED_FOCUS_STREAM_TYPE] = {
103 .name = "GetAcquiredFocusStreamType",
105 [AUDIO_METHOD_ACQUIRE_FOCUS] = {
106 .name = "AcquireFocus",
108 [AUDIO_METHOD_RELEASE_FOCUS] = {
109 .name = "ReleaseFocus",
111 [AUDIO_METHOD_UPDATE_STREAM_FOCUS_STATUS] = {
112 .name = "UpdateFocusStatusByFocusId",
114 [AUDIO_METHOD_WATCH_FOCUS] = {
115 .name = "WatchFocus",
117 [AUDIO_METHOD_UNWATCH_FOCUS] = {
118 .name = "UnwatchFocus",
120 [AUDIO_METHOD_SET_FILTER] = {
123 [AUDIO_METHOD_UNSET_FILTER] = {
124 .name = "UnsetFilter",
126 [AUDIO_METHOD_CONTROL_FILTER] = {
127 .name = "ControlFilter",
131 const mm_sound_dbus_signal_info_t g_events[AUDIO_EVENT_MAX] = {
132 [AUDIO_EVENT_TEST] = {
133 .name = "SignalTest1",
135 [AUDIO_EVENT_PLAY_FILE_END] = {
136 .name = "PlayFileEnd",
138 [AUDIO_EVENT_VOLUME_CHANGED] = {
139 .name = "VolumeChanged",
141 [AUDIO_EVENT_DEVICE_CONNECTED] = {
142 .name = "DeviceConnected",
144 [AUDIO_EVENT_DEVICE_INFO_CHANGED] = {
145 .name = "DeviceInfoChanged",
147 [AUDIO_EVENT_DEVICE_STATE_CHANGED] = {
148 .name = "DeviceStateChanged",
150 [AUDIO_EVENT_FOCUS_CHANGED] = {
151 .name = "FocusChanged",
153 [AUDIO_EVENT_FOCUS_WATCH] = {
154 .name = "FocusWatch",
156 [AUDIO_EVENT_EMERGENT_EXIT] = {
157 .name = "EmergentExit",
159 [AUDIO_EVENT_CLIENT_SUBSCRIBED] = {
160 .name = "ClientSubscribed",
162 [AUDIO_EVENT_CLIENT_HANDLED] = {
163 .name = "ClientSignalHandled",
167 /* Only For error types which is currently being used in server-side */
168 static const GDBusErrorEntry mm_sound_error_entries[] =
170 {MM_ERROR_OUT_OF_MEMORY, "org.tizen.multimedia.OutOfMemory"},
171 {MM_ERROR_OUT_OF_STORAGE, "org.tizen.multimedia.OutOfStorage"},
172 {MM_ERROR_INVALID_ARGUMENT, "org.tizen.multimedia.InvalidArgument"},
173 {MM_ERROR_POLICY_INTERNAL, "org.tizen.multimedia.PolicyInternal"},
174 {MM_ERROR_NOT_SUPPORT_API, "org.tizen.multimedia.NotSupportAPI"},
175 {MM_ERROR_POLICY_BLOCKED, "org.tizen.multimedia.PolicyBlocked"},
176 {MM_ERROR_END_OF_FILE, "org.tizen.multimedia.EndOfFile"},
177 {MM_ERROR_COMMON_OUT_OF_RANGE, "org.tizen.multimedia.common.OutOfRange"},
178 {MM_ERROR_COMMON_UNKNOWN, "org.tizen.multimedia.common.Unknown"},
179 {MM_ERROR_COMMON_NO_FREE_SPACE, "org.tizen.multimedia.common.NoFreeSpace"},
180 {MM_ERROR_SOUND_INTERNAL, "org.tizen.multimedia.audio.Internal"},
181 {MM_ERROR_SOUND_INVALID_STATE, "org.tizen.multimedia.audio.InvalidState"},
182 {MM_ERROR_SOUND_NO_FREE_SPACE, "org.tizen.multimedia.audio.NoFreeSpace"},
183 {MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE, "org.tizen.multimedia.audio.UnsupportedMediaType"},
184 {MM_ERROR_SOUND_INVALID_POINTER, "org.tizen.multimedia.audio.InvalidPointer"},
185 {MM_ERROR_SOUND_INVALID_FILE, "org.tizen.multimedia.audio.InvalidFile"},
186 {MM_ERROR_SOUND_FILE_NOT_FOUND, "org.tizen.multimedia.audio.FileNotFound"},
187 {MM_ERROR_SOUND_NO_DATA, "org.tizen.multimedia.audio.NoData"},
188 {MM_ERROR_SOUND_INVALID_PATH, "org.tizen.multimedia.audio.InvalidPath"},
192 /******************************************************************************************
193 Wrapper Functions of GDbus
194 ******************************************************************************************/
196 static int _parse_error_msg(char *full_err_msg, char **err_name, char **err_msg)
198 char *save_p, *domain, *_err_name, *_err_msg;
200 if (!(domain = strtok_r(full_err_msg, ":", &save_p))) {
201 debug_error("get domain failed");
204 if (!(_err_name = strtok_r(NULL, ":", &save_p))) {
205 debug_error("get err name failed");
208 if (!(_err_msg = strtok_r(NULL, ":", &save_p))) {
209 debug_error("get err msg failed");
213 *err_name = _err_name;
219 static int _convert_error_name(const char *err_name)
223 for (i = 0; i < G_N_ELEMENTS(mm_sound_error_entries); i++) {
224 if (!strcmp(mm_sound_error_entries[i].dbus_error_name, err_name)) {
225 return mm_sound_error_entries[i].error_code;
229 return MM_ERROR_COMMON_UNKNOWN;
232 static int _dbus_method_call(GDBusConnection* conn, const char* bus_name, const char* object, const char* intf,
233 const char* method, GVariant* args, GVariant** result)
235 int ret = MM_ERROR_NONE;
237 GVariant* dbus_reply = NULL;
239 if (!conn || !object || !intf || !method) {
240 debug_error("Invalid Argument");
242 debug_error("conn null");
244 debug_error("object null");
246 debug_error("intf null");
248 debug_error("method null");
249 return MM_ERROR_INVALID_ARGUMENT;
252 debug_log("Dbus call with obj'%s' intf'%s' method'%s'", object, intf, method);
254 dbus_reply = g_dbus_connection_call_sync(conn, bus_name, object , intf,
256 NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err );
259 char *err_name = NULL, *err_msg = NULL;
260 debug_error("Method Call '%s.%s' Failed, %s", intf, method, err->message);
262 if (_parse_error_msg(err->message, &err_name, &err_msg) < 0) {
263 debug_error("failed to parse error message");
265 return MM_ERROR_SOUND_INTERNAL;
267 ret = _convert_error_name(err_name);
270 debug_log("Method Call '%s.%s' Success", intf, method);
273 *result = dbus_reply;
279 static int _dbus_set_property(GDBusConnection* conn, const char* bus_name, const char* object, const char* intf,
280 const char* prop, GVariant* args, GVariant** result)
282 int ret = MM_ERROR_NONE;
284 if (!conn || !object || !intf || !prop) {
285 debug_error("Invalid Argument");
286 return MM_ERROR_INVALID_ARGUMENT;
289 debug_log("Dbus set property with obj'%s' intf'%s' prop'%s'", object, intf, prop);
291 if ((ret = _dbus_method_call(conn, bus_name, object, INTERFACE_DBUS, METHOD_SET,
292 g_variant_new("(ssv)", intf, prop, args), result)) != MM_ERROR_NONE) {
293 debug_error("Dbus call for set property failed");
299 static int _dbus_get_property(GDBusConnection *conn, const char* bus_name, const char* object_name,
300 const char* intf_name, const char* prop, GVariant** result)
302 int ret = MM_ERROR_NONE;
304 if (!conn || !object_name || !intf_name || !prop) {
305 debug_error("Invalid Argument");
306 return MM_ERROR_INVALID_ARGUMENT;
309 debug_log("Dbus get property with obj'%s' intf'%s' prop'%s'", object_name, intf_name, prop);
311 if ((ret = _dbus_method_call(conn,
312 bus_name, object_name, INTERFACE_DBUS, METHOD_GET,
313 g_variant_new("(ss)", intf_name, prop), result)) != MM_ERROR_NONE) {
314 debug_error("Dbus call for get property failed");
321 static int _dbus_subscribe_signal(GDBusConnection *conn, const char* object_name, const char* intf_name,
322 const char* signal_name, GDBusSignalCallback signal_cb, guint *subscribe_id, void* userdata, GDestroyNotify freefunc)
326 if (!conn || !object_name || !intf_name || !signal_name || !signal_cb) {
327 debug_error("Invalid Argument");
328 return MM_ERROR_INVALID_ARGUMENT;
331 debug_log("Dbus subscirbe signal with Obj'%s' Intf'%s' sig'%s'", object_name, intf_name, signal_name);
333 subs_id = g_dbus_connection_signal_subscribe(conn, NULL, intf_name, signal_name, object_name,
334 NULL, G_DBUS_SIGNAL_FLAGS_NONE , signal_cb, userdata, freefunc);
337 debug_error ("g_dbus_connection_signal_subscribe() failed ");
338 return MM_ERROR_SOUND_INTERNAL;
341 *subscribe_id = subs_id;
343 return MM_ERROR_NONE;
346 static void _dbus_unsubscribe_signal(GDBusConnection *conn, guint subs_id)
348 if (!conn || !subs_id) {
349 debug_error("Invalid Argument");
353 g_dbus_connection_signal_unsubscribe(conn, subs_id);
356 static GDBusConnection* _dbus_get_connection(GBusType bustype)
358 static GDBusConnection *conn_system = NULL;
359 static GDBusConnection *conn_session = NULL;
362 if (bustype == G_BUS_TYPE_SYSTEM) {
364 debug_log("Already connected to system bus");
366 debug_log("Get new connection on system bus");
367 if (!(conn_system = g_bus_get_sync(bustype, NULL, &err))) {
368 debug_error ("g_dbus_get_sync() error (%s)", err->message);
373 } else if (bustype == G_BUS_TYPE_SESSION) {
375 debug_log("Already connected to session bus");
377 debug_log("Get new connection on session bus");
378 if (!(conn_session = g_bus_get_sync(bustype, NULL, &err))) {
379 debug_error ("g_dbus_get_sync() error (%s)", err->message);
385 debug_error("Invalid bus type");
392 static void _dbus_disconnect(GDBusConnection* conn)
395 g_object_unref(conn);
400 /******************************************************************************************
401 Simple Functions For Communicate with Sound-Server
402 ******************************************************************************************/
405 int mm_sound_dbus_method_call_to(audio_provider_t provider, audio_method_t method_type, GVariant *args, GVariant **result)
407 int ret = MM_ERROR_NONE;
408 GDBusConnection *conn = NULL;
410 if (method_type < 0 || method_type >= AUDIO_METHOD_MAX) {
411 debug_error("Invalid method type : %d", method_type);
412 return MM_ERROR_INVALID_ARGUMENT;
414 if (provider < 0 || provider >= AUDIO_PROVIDER_MAX) {
415 debug_error("Invalid provider : %d", provider);
416 return MM_ERROR_INVALID_ARGUMENT;
419 if (!(conn = _dbus_get_connection(G_BUS_TYPE_SYSTEM))) {
420 debug_error("Get Dbus Connection Error");
421 return MM_ERROR_SOUND_INTERNAL;
424 if ((ret = _dbus_method_call(conn, g_paths[provider].bus_name,
425 g_paths[provider].object,
426 g_paths[provider].interface,
427 g_methods[method_type].name,
428 args, result)) != MM_ERROR_NONE) {
429 debug_error("Dbus Call on Client Error");
435 /* This callback only transform signal-callback to dbus non-related form (mm_sound_dbus_callback) */
436 static void _dbus_signal_callback(GDBusConnection *connection,
437 const gchar *sender_name,
438 const gchar *object_path,
439 const gchar *interface_name,
440 const gchar *signal_name,
444 struct callback_data *cb_data = (struct callback_data*) userdata;
446 debug_log("Signal(%s.%s) Received , Let's call Wrapper-Callback", interface_name, signal_name);
448 if (!strcmp(signal_name, g_events[AUDIO_EVENT_VOLUME_CHANGED].name)) {
449 (cb_data->user_cb)(AUDIO_EVENT_VOLUME_CHANGED, params, cb_data->user_data);
450 } else if (!strcmp(signal_name, g_events[AUDIO_EVENT_DEVICE_CONNECTED].name)) {
451 (cb_data->user_cb)(AUDIO_EVENT_DEVICE_CONNECTED, params, cb_data->user_data);
452 } else if (!strcmp(signal_name, g_events[AUDIO_EVENT_DEVICE_INFO_CHANGED].name)) {
453 (cb_data->user_cb)(AUDIO_EVENT_DEVICE_INFO_CHANGED, params, cb_data->user_data);
454 } else if (!strcmp(signal_name, g_events[AUDIO_EVENT_DEVICE_STATE_CHANGED].name)) {
455 (cb_data->user_cb)(AUDIO_EVENT_DEVICE_STATE_CHANGED, params, cb_data->user_data);
456 } else if (!strcmp(signal_name, g_events[AUDIO_EVENT_FOCUS_CHANGED].name)) {
457 (cb_data->user_cb)(AUDIO_EVENT_FOCUS_CHANGED, params, cb_data->user_data);
458 } else if (!strcmp(signal_name, g_events[AUDIO_EVENT_FOCUS_WATCH].name)) {
459 (cb_data->user_cb)(AUDIO_EVENT_FOCUS_WATCH, params, cb_data->user_data);
460 } else if (!strcmp(signal_name, g_events[AUDIO_EVENT_PLAY_FILE_END].name)) {
461 (cb_data->user_cb)(AUDIO_EVENT_PLAY_FILE_END, params, cb_data->user_data);
462 } else if (!strcmp(signal_name, g_events[AUDIO_EVENT_EMERGENT_EXIT].name)) {
463 (cb_data->user_cb)(AUDIO_EVENT_EMERGENT_EXIT, params, cb_data->user_data);
467 static void callback_data_free_func(gpointer data)
469 struct callback_data *cb_data = (struct callback_data *) data;
471 if (cb_data->free_func)
472 cb_data->free_func(cb_data->user_data);
477 int mm_sound_dbus_signal_subscribe_to(audio_provider_t provider, audio_event_t event, mm_sound_dbus_callback callback, void *userdata, mm_sound_dbus_userdata_free freefunc, unsigned *subs_id)
479 GDBusConnection *conn = NULL;
481 struct callback_data *cb_data = NULL;
484 debug_error("Callback is Null");
485 return MM_ERROR_INVALID_ARGUMENT;
488 if (event < 0 || event >= AUDIO_EVENT_MAX) {
489 debug_error("Wrong event Type : %d", event);
490 return MM_ERROR_INVALID_ARGUMENT;
493 if (provider < 0 || provider >= AUDIO_PROVIDER_MAX) {
494 debug_error("Invalid provider : %d", provider);
495 return MM_ERROR_INVALID_ARGUMENT;
498 if (!(conn = _dbus_get_connection(G_BUS_TYPE_SYSTEM))) {
499 debug_error("Get Dbus Connection Error");
500 return MM_ERROR_SOUND_INTERNAL;
503 if (!(cb_data = (struct callback_data*) g_malloc0(sizeof(struct callback_data)))) {
504 debug_error("Allocate for callback data failed");
505 return MM_ERROR_SOUND_INTERNAL;
508 cb_data->user_cb = callback;
509 cb_data->user_data = userdata;
510 cb_data->free_func = freefunc;
512 if (_dbus_subscribe_signal(conn, g_paths[provider].object, g_paths[provider].interface, g_events[event].name,
513 _dbus_signal_callback, &_subs_id, cb_data, callback_data_free_func) != MM_ERROR_NONE) {
514 debug_error("Dbus Subscribe on Client Error");
518 *subs_id = (unsigned int)_subs_id;
520 return MM_ERROR_NONE;
524 return MM_ERROR_SOUND_INTERNAL;
528 int mm_sound_dbus_signal_unsubscribe(unsigned int subs_id)
530 GDBusConnection *conn = NULL;
532 if (!(conn = _dbus_get_connection(G_BUS_TYPE_SYSTEM))) {
533 debug_error("Get Dbus Connection Error");
534 return MM_ERROR_SOUND_INTERNAL;
537 _dbus_unsubscribe_signal(conn, (guint) subs_id);
539 return MM_ERROR_NONE;
543 int mm_sound_dbus_emit_signal(audio_provider_t provider, audio_event_t event, GVariant *param)
545 GDBusConnection *conn;
549 if (event < 0 || event >= AUDIO_EVENT_MAX) {
550 debug_error ("emit signal failed, invalid argument, event_type(%d)", event);
551 return MM_ERROR_INVALID_ARGUMENT;
554 if (!(conn = _dbus_get_connection(G_BUS_TYPE_SYSTEM))) {
555 debug_error("Get Dbus Connection Error");
556 return MM_ERROR_SOUND_INTERNAL;
559 dbus_ret = g_dbus_connection_emit_signal (conn,
560 NULL, g_paths[provider].object,
561 g_paths[provider].interface, g_events[event].name,
564 debug_error ("g_dbus_connection_emit_signal() error (%s)", err->message);
566 return MM_ERROR_SOUND_INTERNAL;
568 g_dbus_connection_flush_sync(conn, NULL, NULL);
570 debug_msg ("emit signal for [%s] success", g_events[event].name);
571 return MM_ERROR_NONE;
575 int mm_sound_dbus_get_event_name(audio_event_t event, const char **event_name)
578 debug_error("Invalid Parameter, event_name NULL");
579 return MM_ERROR_INVALID_ARGUMENT;
581 if (event < 0 || event >= AUDIO_EVENT_MAX) {
582 debug_error("invalid event : %d", event);
583 return MM_ERROR_INVALID_ARGUMENT;
586 *event_name = g_events[event].name;
587 return MM_ERROR_NONE;
591 int mm_sound_dbus_get_method_name(audio_method_t method, const char **method_name)
594 debug_error("Invalid Parameter, method_name NULL");
595 return MM_ERROR_INVALID_ARGUMENT;
597 if (method < 0 || method >= AUDIO_METHOD_MAX) {
598 debug_error("invalid method : %d", method);
599 return MM_ERROR_INVALID_ARGUMENT;
602 *method_name = g_methods[method].name;
603 return MM_ERROR_NONE;