8 #include "../include/mm_sound_dbus.h"
9 #include "../include/mm_sound_intf.h"
11 struct callback_data {
12 mm_sound_dbus_callback user_cb;
14 mm_sound_dbus_userdata_free free_func;
23 const struct dbus_path g_paths[AUDIO_PROVIDER_MAX] = {
24 [AUDIO_PROVIDER_SOUND_SERVER] = {
25 .bus_name = "org.tizen.SoundServer",
26 .object = "/org/tizen/SoundServer1",
27 .interface = "org.tizen.SoundServer1"
29 [AUDIO_PROVIDER_FOCUS_SERVER] = {
30 .bus_name = "org.tizen.FocusServer",
31 .object = "/org/tizen/FocusServer1",
32 .interface = "org.tizen.FocusServer1"
34 [AUDIO_PROVIDER_DEVICE_MANAGER] = {
35 .bus_name = "org.pulseaudio.Server",
36 .object = "/org/pulseaudio/DeviceManager",
37 .interface = "org.pulseaudio.DeviceManager"
39 [AUDIO_PROVIDER_STREAM_MANAGER] = {
40 .bus_name = "org.pulseaudio.Server",
41 .object = "/org/pulseaudio/StreamManager",
42 .interface = "org.pulseaudio.StreamManager"
44 [AUDIO_PROVIDER_AUDIO_CLIENT] = {
45 .bus_name = "org.tizen.AudioClient",
46 .object = "/org/tizen/AudioClient1",
47 .interface = "org.tizen.AudioClient1"
51 const mm_sound_dbus_method_info_t g_methods[AUDIO_METHOD_MAX] = {
52 [AUDIO_METHOD_TEST] = {
53 .name = "MethodTest1",
55 [AUDIO_METHOD_PLAY_FILE_START] = {
56 .name = "PlayFileStart",
58 [AUDIO_METHOD_PLAY_FILE_START_WITH_STREAM_INFO] = {
59 .name = "PlayFileStartWithStreamInfo",
61 [AUDIO_METHOD_PLAY_FILE_STOP] = {
62 .name = "PlayFileStop",
64 [AUDIO_METHOD_PLAY_DTMF] = {
67 [AUDIO_METHOD_PLAY_DTMF_WITH_STREAM_INFO] = {
68 .name = "PlayDTMFWithStreamInfo",
70 [AUDIO_METHOD_CLEAR_FOCUS] = {
73 [AUDIO_METHOD_SET_VOLUME_LEVEL] = {
74 .name = "SetVolumeLevel",
76 [AUDIO_METHOD_GET_CONNECTED_DEVICE_LIST] = {
77 .name = "GetConnectedDeviceList",
79 [AUDIO_METHOD_GET_DEVICE_BY_ID] = {
80 .name = "GetDeviceById",
82 [AUDIO_METHOD_IS_STREAM_ON_DEVICE] = {
83 .name = "IsStreamOnDevice",
85 [AUDIO_METHOD_GET_UNIQUE_ID] = {
86 .name = "GetUniqueId",
88 [AUDIO_METHOD_REGISTER_FOCUS] = {
89 .name = "RegisterFocus",
91 [AUDIO_METHOD_UNREGISTER_FOCUS] = {
92 .name = "UnregisterFocus",
94 [AUDIO_METHOD_SET_FOCUS_REACQUISITION] = {
95 .name = "SetFocusReacquisition",
97 [AUDIO_METHOD_GET_ACQUIRED_FOCUS_STREAM_TYPE] = {
98 .name = "GetAcquiredFocusStreamType",
100 [AUDIO_METHOD_ACQUIRE_FOCUS] = {
101 .name = "AcquireFocus",
103 [AUDIO_METHOD_RELEASE_FOCUS] = {
104 .name = "ReleaseFocus",
106 [AUDIO_METHOD_UPDATE_STREAM_FOCUS_STATUS] = {
107 .name = "UpdateFocusStatusByFocusId",
109 [AUDIO_METHOD_WATCH_FOCUS] = {
110 .name = "WatchFocus",
112 [AUDIO_METHOD_UNWATCH_FOCUS] = {
113 .name = "UnwatchFocus",
115 [AUDIO_METHOD_DELIVER_FOCUS] = {
116 .name = "DeliverFocus",
118 [AUDIO_METHOD_SET_FILTER] = {
121 [AUDIO_METHOD_UNSET_FILTER] = {
122 .name = "UnsetFilter",
124 [AUDIO_METHOD_CONTROL_FILTER] = {
125 .name = "ControlFilter",
129 const mm_sound_dbus_signal_info_t g_events[AUDIO_EVENT_MAX] = {
130 [AUDIO_EVENT_TEST] = {
131 .name = "SignalTest1",
133 [AUDIO_EVENT_PLAY_FILE_END] = {
134 .name = "PlayFileEnd",
136 [AUDIO_EVENT_VOLUME_CHANGED] = {
137 .name = "VolumeChanged",
139 [AUDIO_EVENT_DEVICE_CONNECTED] = {
140 .name = "DeviceConnected",
142 [AUDIO_EVENT_DEVICE_INFO_CHANGED] = {
143 .name = "DeviceInfoChanged",
145 [AUDIO_EVENT_DEVICE_STATE_CHANGED] = {
146 .name = "DeviceStateChanged",
148 [AUDIO_EVENT_DEVICE_RUNNING_CHANGED] = {
149 .name = "DeviceRunningChanged",
151 [AUDIO_EVENT_FOCUS_CHANGED] = {
152 .name = "FocusChanged",
154 [AUDIO_EVENT_FOCUS_WATCH] = {
155 .name = "FocusWatch",
157 [AUDIO_EVENT_EMERGENT_EXIT] = {
158 .name = "EmergentExit",
160 [AUDIO_EVENT_CLIENT_SUBSCRIBED] = {
161 .name = "ClientSubscribed",
163 [AUDIO_EVENT_CLIENT_HANDLED] = {
164 .name = "ClientSignalHandled",
168 /* Only For error types which is currently being used in server-side */
169 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"},
189 {MM_ERROR_SOUND_PERMISSION_DENIED, "org.freedesktop.DBus.Error.AccessDenied"},
193 /******************************************************************************************
194 Wrapper Functions of GDbus
195 ******************************************************************************************/
197 static int _parse_error_msg(char *full_err_msg, char **err_name, char **err_msg)
199 char *save_p = NULL, *domain, *_err_name, *_err_msg;
201 if (!(domain = strtok_r(full_err_msg, ":", &save_p))) {
202 debug_error("get domain failed");
205 if (!(_err_name = strtok_r(NULL, ":", &save_p))) {
206 debug_error("get err name failed");
209 if (!(_err_msg = strtok_r(NULL, ":", &save_p))) {
210 debug_error("get err msg failed");
214 *err_name = _err_name;
220 static int _convert_error_name(const char *err_name)
224 debug_error("error name is [%s]", err_name);
226 for (i = 0; i < G_N_ELEMENTS(mm_sound_error_entries); i++) {
227 if (!strcmp(mm_sound_error_entries[i].dbus_error_name, err_name))
228 return mm_sound_error_entries[i].error_code;
231 return MM_ERROR_COMMON_UNKNOWN;
234 static int _dbus_method_call(GDBusConnection *conn, const char *bus_name, const char *object, const char *intf,
235 const char *method, GVariant *args, GVariant **result)
237 int ret = MM_ERROR_NONE;
239 GVariant *dbus_reply = NULL;
241 if (!conn || !object || !intf || !method) {
242 debug_error("Invalid Argument");
244 debug_error("conn null");
246 debug_error("object null");
248 debug_error("intf null");
250 debug_error("method null");
251 return MM_ERROR_INVALID_ARGUMENT;
254 debug_log("Dbus call with obj'%s' intf'%s' method'%s'", object, intf, method);
256 dbus_reply = g_dbus_connection_call_sync(conn, bus_name, object , intf,
258 NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
260 if (!dbus_reply || err) {
261 char *err_name = NULL, *err_msg = NULL;
262 debug_error("Method Call '%s.%s' Failed, %s", intf, method, err ? err->message : NULL);
263 ret = MM_ERROR_SOUND_INTERNAL;
265 if (_parse_error_msg(err->message, &err_name, &err_msg) < 0) {
266 debug_error("failed to parse error message");
268 return MM_ERROR_SOUND_INTERNAL;
270 ret = _convert_error_name(err_name);
274 debug_log("Method Call '%s.%s' Success", intf, method);
277 *result = dbus_reply;
282 static int _dbus_subscribe_signal(GDBusConnection *conn, const char *object_name, const char *intf_name,
283 const char *signal_name, GDBusSignalCallback signal_cb, guint *subscribe_id,
284 void *userdata, GDestroyNotify freefunc)
288 if (!conn || !object_name || !intf_name || !signal_name || !signal_cb) {
289 debug_error("Invalid Argument");
290 return MM_ERROR_INVALID_ARGUMENT;
293 debug_log("Dbus subscirbe signal with Obj'%s' Intf'%s' sig'%s'", object_name, intf_name, signal_name);
295 subs_id = g_dbus_connection_signal_subscribe(conn, NULL, intf_name, signal_name, object_name,
296 NULL, G_DBUS_SIGNAL_FLAGS_NONE , signal_cb, userdata, freefunc);
299 debug_error("g_dbus_connection_signal_subscribe() failed ");
300 return MM_ERROR_SOUND_INTERNAL;
303 *subscribe_id = subs_id;
305 return MM_ERROR_NONE;
308 static void _dbus_unsubscribe_signal(GDBusConnection *conn, guint subs_id)
310 if (!conn || !subs_id) {
311 debug_error("Invalid Argument");
315 g_dbus_connection_signal_unsubscribe(conn, subs_id);
318 static GDBusConnection * _dbus_get_connection(GBusType bustype)
320 static GDBusConnection *conn_system = NULL;
321 static GDBusConnection *conn_session = NULL;
324 if (bustype == G_BUS_TYPE_SYSTEM) {
327 debug_log("Already connected to system bus");
331 debug_log("Get new connection on system bus");
333 conn_system = g_bus_get_sync(bustype, NULL, &err);
334 if (!conn_system || err) {
336 debug_error("g_dbus_get_sync() error (%s)", err ? err->message : NULL);
343 } else if (bustype == G_BUS_TYPE_SESSION) {
346 debug_log("Already connected to session bus");
350 debug_log("Get new connection on session bus");
352 conn_session = g_bus_get_sync(bustype, NULL, &err);
353 if (!conn_session || err) {
355 debug_error("g_dbus_get_sync() error (%s)", err ? err->message : NULL);
364 debug_error("Invalid bus type");
371 /******************************************************************************************
372 Simple Functions For Communicate with Sound-Server
373 ******************************************************************************************/
376 int mm_sound_dbus_method_call_to(audio_provider_t provider, audio_method_t method_type, GVariant *args, GVariant **result)
378 int ret = MM_ERROR_NONE;
379 GDBusConnection *conn = NULL;
381 if (method_type >= AUDIO_METHOD_MAX) {
382 debug_error("Invalid method type : %d", method_type);
383 return MM_ERROR_INVALID_ARGUMENT;
385 if (provider >= AUDIO_PROVIDER_MAX) {
386 debug_error("Invalid provider : %d", provider);
387 return MM_ERROR_INVALID_ARGUMENT;
390 if (!(conn = _dbus_get_connection(G_BUS_TYPE_SYSTEM))) {
391 debug_error("Get Dbus Connection Error");
392 return MM_ERROR_SOUND_INTERNAL;
395 if ((ret = _dbus_method_call(conn, g_paths[provider].bus_name,
396 g_paths[provider].object,
397 g_paths[provider].interface,
398 g_methods[method_type].name,
399 args, result)) != MM_ERROR_NONE) {
400 debug_error("Dbus Call on Client Error");
406 /* This callback only transform signal-callback to dbus non-related form (mm_sound_dbus_callback) */
407 static void _dbus_signal_callback(GDBusConnection *connection,
408 const gchar *sender_name,
409 const gchar *object_path,
410 const gchar *interface_name,
411 const gchar *signal_name,
415 struct callback_data *cb_data = (struct callback_data *)userdata;
417 debug_log("Signal(%s.%s) Received, Let's call Wrapper-Callback", interface_name, signal_name);
419 if (!strcmp(signal_name, g_events[AUDIO_EVENT_VOLUME_CHANGED].name))
420 (cb_data->user_cb)(AUDIO_EVENT_VOLUME_CHANGED, params, cb_data->user_data);
421 else if (!strcmp(signal_name, g_events[AUDIO_EVENT_DEVICE_CONNECTED].name))
422 (cb_data->user_cb)(AUDIO_EVENT_DEVICE_CONNECTED, params, cb_data->user_data);
423 else if (!strcmp(signal_name, g_events[AUDIO_EVENT_DEVICE_INFO_CHANGED].name))
424 (cb_data->user_cb)(AUDIO_EVENT_DEVICE_INFO_CHANGED, params, cb_data->user_data);
425 else if (!strcmp(signal_name, g_events[AUDIO_EVENT_DEVICE_STATE_CHANGED].name))
426 (cb_data->user_cb)(AUDIO_EVENT_DEVICE_STATE_CHANGED, params, cb_data->user_data);
427 else if (!strcmp(signal_name, g_events[AUDIO_EVENT_FOCUS_CHANGED].name))
428 (cb_data->user_cb)(AUDIO_EVENT_FOCUS_CHANGED, params, cb_data->user_data);
429 else if (!strcmp(signal_name, g_events[AUDIO_EVENT_FOCUS_WATCH].name))
430 (cb_data->user_cb)(AUDIO_EVENT_FOCUS_WATCH, params, cb_data->user_data);
431 else if (!strcmp(signal_name, g_events[AUDIO_EVENT_PLAY_FILE_END].name))
432 (cb_data->user_cb)(AUDIO_EVENT_PLAY_FILE_END, params, cb_data->user_data);
433 else if (!strcmp(signal_name, g_events[AUDIO_EVENT_EMERGENT_EXIT].name))
434 (cb_data->user_cb)(AUDIO_EVENT_EMERGENT_EXIT, params, cb_data->user_data);
435 else if (!strcmp(signal_name, g_events[AUDIO_EVENT_DEVICE_RUNNING_CHANGED].name))
436 (cb_data->user_cb)(AUDIO_EVENT_DEVICE_RUNNING_CHANGED, params, cb_data->user_data);
439 static void callback_data_free_func(gpointer data)
441 struct callback_data *cb_data = (struct callback_data *)data;
443 if (cb_data->free_func)
444 cb_data->free_func(cb_data->user_data);
449 int mm_sound_dbus_signal_subscribe_to(audio_provider_t provider, audio_event_t event, mm_sound_dbus_callback callback,
450 void *userdata, mm_sound_dbus_userdata_free freefunc, unsigned *subs_id)
452 GDBusConnection *conn = NULL;
454 struct callback_data *cb_data = NULL;
457 debug_error("Callback is Null");
458 return MM_ERROR_INVALID_ARGUMENT;
461 if (event >= AUDIO_EVENT_MAX) {
462 debug_error("Wrong event Type : %d", event);
463 return MM_ERROR_INVALID_ARGUMENT;
466 if (provider >= AUDIO_PROVIDER_MAX) {
467 debug_error("Invalid provider : %d", provider);
468 return MM_ERROR_INVALID_ARGUMENT;
471 if (!(conn = _dbus_get_connection(G_BUS_TYPE_SYSTEM))) {
472 debug_error("Get Dbus Connection Error");
473 return MM_ERROR_SOUND_INTERNAL;
476 if (!(cb_data = (struct callback_data*)g_malloc0(sizeof(struct callback_data)))) {
477 debug_error("Allocate for callback data failed");
478 return MM_ERROR_SOUND_INTERNAL;
481 cb_data->user_cb = callback;
482 cb_data->user_data = userdata;
483 cb_data->free_func = freefunc;
485 if (_dbus_subscribe_signal(conn, g_paths[provider].object, g_paths[provider].interface, g_events[event].name,
486 _dbus_signal_callback, &_subs_id, cb_data, callback_data_free_func) != MM_ERROR_NONE) {
487 debug_error("Dbus Subscribe on Client Error");
491 *subs_id = (unsigned int)_subs_id;
493 return MM_ERROR_NONE;
497 return MM_ERROR_SOUND_INTERNAL;
501 int mm_sound_dbus_signal_unsubscribe(unsigned int subs_id)
503 GDBusConnection *conn = NULL;
505 if (!(conn = _dbus_get_connection(G_BUS_TYPE_SYSTEM))) {
506 debug_error("Get Dbus Connection Error");
507 return MM_ERROR_SOUND_INTERNAL;
510 _dbus_unsubscribe_signal(conn, (guint)subs_id);
512 return MM_ERROR_NONE;
516 int mm_sound_dbus_emit_signal(audio_provider_t provider, audio_event_t event, GVariant *param)
518 GDBusConnection *conn;
522 if (event >= AUDIO_EVENT_MAX) {
524 debug_error("emit signal failed, invalid argument, event_type(%d)", event);
526 return MM_ERROR_INVALID_ARGUMENT;
529 if (!(conn = _dbus_get_connection(G_BUS_TYPE_SYSTEM))) {
531 debug_error("Get Dbus Connection Error");
533 return MM_ERROR_SOUND_INTERNAL;
536 dbus_ret = g_dbus_connection_emit_signal(conn,
537 NULL, g_paths[provider].object,
538 g_paths[provider].interface, g_events[event].name,
540 if (!dbus_ret || err) {
542 debug_error("g_dbus_connection_emit_signal() error (%s)", err ? err->message : NULL);
545 return MM_ERROR_SOUND_INTERNAL;
547 g_dbus_connection_flush_sync(conn, NULL, NULL);
550 debug_msg("emit signal for [%s] success", g_events[event].name);
552 return MM_ERROR_NONE;
556 int mm_sound_dbus_get_event_name(audio_event_t event, const char **event_name)
559 debug_error("Invalid Parameter, event_name NULL");
560 return MM_ERROR_INVALID_ARGUMENT;
562 if (event >= AUDIO_EVENT_MAX) {
563 debug_error("invalid event : %d", event);
564 return MM_ERROR_INVALID_ARGUMENT;
567 *event_name = g_events[event].name;
568 return MM_ERROR_NONE;
572 int mm_sound_dbus_get_method_name(audio_method_t method, const char **method_name)
575 debug_error("Invalid Parameter, method_name NULL");
576 return MM_ERROR_INVALID_ARGUMENT;
578 if (method >= AUDIO_METHOD_MAX) {
579 debug_error("invalid method : %d", method);
580 return MM_ERROR_INVALID_ARGUMENT;
583 *method_name = g_methods[method].name;
584 return MM_ERROR_NONE;