This patch fixes SVACE issue.
[platform/core/connectivity/bluetooth-frwk.git] / bt-oal / bluez_hal / src / bt-hal-avrcp-tg-dbus-handler.c
1 /*
2  * Bluetooth-frwk
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Atul Kumar Rai <a.rai@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *              http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdbool.h>
25 #include <string.h>
26
27 #include <dbus/dbus.h>
28 #include <glib.h>
29 #include <gio/gio.h>
30 #include <dlog.h>
31 #include <vconf.h>
32
33 #include "bt-hal-dbus-common-utils.h"
34 #include "bt-hal-internal.h"
35 #include "bt-hal-avrcp-tg-dbus-handler.h"
36
37 #define HAL_ERROR_INTERNAL "InternalError"
38 #define HAL_ERROR_INVALID_PARAM "InvalidParameters"
39 #define HAL_ERROR_INVALID_INTERFACE "InvalidInterface"
40
41 #define BT_HAL_MEDIA_OBJECT_PATH "/Musicplayer"
42 #define BT_HAL_MEDIA_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
43
44 typedef enum {
45         HAL_AVRCP_ERROR_NONE,
46         HAL_AVRCP_ERROR_INTERNAL,
47         HAL_AVRCP_ERROR_INVALID_PARAM,
48         HAL_AVRCP_ERROR_NOT_SUPPORTED,
49         HAL_AVRCP_ERROR_INVALID_INTERFACE
50 } hal_avrcp_error_t;
51
52 static handle_stack_msg event_cb = NULL;
53
54 static guint avrcp_reg_id = 0;
55
56 /* Introspection data exposed from bt-service */
57 static const gchar hal_avrcp_tg_introspection_xml[] =
58 "<node name='/'>"
59 " <interface name='org.freedesktop.DBus.Properties'>"
60 "     <method name='Set'>"
61 "          <arg type='s' name='interface' direction='in'/>"
62 "          <arg type='s' name='property' direction='in'/>"
63 "          <arg type='v' name='value' direction='in'/>"
64 "     </method>"
65 " </interface>"
66 "</node>";
67
68 static const char *__repeat_val_to_str(btrc_player_repeat_val_t repeat_val)
69 {
70         switch (repeat_val) {
71         case BTRC_PLAYER_VAL_OFF_REPEAT:
72                 return "None";
73         case BTRC_PLAYER_VAL_SINGLE_REPEAT:
74                 return "Track";
75         case BTRC_PLAYER_VAL_ALL_REPEAT:
76                 return "Playlist";
77         case BTRC_PLAYER_VAL_GROUP_REPEAT:
78                 return "Playlist";
79         default:
80                 ERR("Invalid repeat value: %d", repeat_val);
81                 return "";
82         }
83 }
84
85 static const char *__play_status_to_str(btrc_play_status_t play_status)
86 {
87         switch (play_status) {
88         case BTRC_PLAYSTATE_STOPPED:
89                 return "stopped";
90         case BTRC_PLAYSTATE_PLAYING:
91                 return "playing";
92         case BTRC_PLAYSTATE_PAUSED:
93                 return "paused";
94         case BTRC_PLAYSTATE_FWD_SEEK:
95                 return "forward-seek";
96         case BTRC_PLAYSTATE_REV_SEEK:
97                 return "reverse-seek";
98         case BTRC_PLAYSTATE_ERROR:
99                 return "error";
100         default:
101                 ERR("Invalid play status: %d", play_status);
102                 return "";
103         }
104 }
105
106 static GQuark __hal_avrcp_error_quark(void)
107 {
108         static GQuark quark = 0;
109
110         if (!quark)
111                 quark = g_quark_from_static_string("bt-avrcp");
112
113         return quark;
114 }
115
116 static GError *__hal_avrcp_set_error(hal_avrcp_error_t error)
117 {
118         ERR("error[%d]\n", error);
119
120         switch (error) {
121         case HAL_AVRCP_ERROR_INVALID_PARAM:
122                 return g_error_new(__hal_avrcp_error_quark(),
123                                 error, HAL_ERROR_INVALID_PARAM);
124         case HAL_AVRCP_ERROR_INVALID_INTERFACE:
125                 return g_error_new(__hal_avrcp_error_quark(),
126                                 error, HAL_ERROR_INVALID_INTERFACE);
127         case HAL_AVRCP_ERROR_INTERNAL:
128         default:
129                 return g_error_new(__hal_avrcp_error_quark(),
130                                 error, HAL_ERROR_INTERNAL);
131         }
132 }
133
134 static void __hal_avrcp_agent_method(GDBusConnection *connection,
135                 const gchar *sender,
136                 const gchar *object_path,
137                 const gchar *interface_name,
138                 const gchar *method_name,
139                 GVariant *parameters,
140                 GDBusMethodInvocation *invocation,
141                 gpointer user_data)
142 {
143         int ret = HAL_AVRCP_ERROR_NONE;
144         GError *err = NULL;
145         gboolean shuffle_status;
146         gchar *interface = NULL;
147         gchar *property = NULL;
148         gchar *loop_status = NULL;
149         GVariant *value = NULL;
150
151         DBG("+");
152         INFO("method %s", method_name);
153         INFO("object_path %s", object_path);
154
155         if (g_strcmp0(method_name, "Set") == 0) {
156                 g_variant_get(parameters, "(&s&sv)",
157                                 &interface, &property, &value);
158
159                 if (g_strcmp0(interface, BT_HAL_MEDIA_PLAYER_INTERFACE) != 0) {
160                         ret = HAL_AVRCP_ERROR_INVALID_INTERFACE;
161                         goto fail;
162                 }
163         }
164
165         if (value == NULL) {
166                 ERR("value is NULL");
167                 ret = HAL_AVRCP_ERROR_INVALID_PARAM;
168                 goto fail;
169         }
170
171         DBG("Property: %s\n", property);
172         if (g_strcmp0(property, "Shuffle") == 0) {
173                 struct hal_ev_avrcp_tg_player_property ev;
174
175                 if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
176                         ERR("Error");
177                         ret = HAL_AVRCP_ERROR_INVALID_PARAM;
178                         goto fail;
179                 }
180
181                 /* Prepare to send AVRCP player property event */
182                 memset(&ev, 0, sizeof(ev));
183                 shuffle_status = g_variant_get_boolean(value);
184                 DBG("Value: %s\n", shuffle_status ? "TRUE" : "FALSE");
185
186                 ev.prop_type = HAL_AVRCP_TG_PLAYER_PROP_SHUFFLE;
187                 if (shuffle_status)
188                         ev.value = BTRC_PLAYER_VAL_ALL_SHUFFLE;
189                 else
190                         ev.value = BTRC_PLAYER_VAL_OFF_SHUFFLE;
191
192                 if (!event_cb)
193                         ERR("AVRCP target DBUS handler callback not registered");
194                 else
195                         event_cb(HAL_EV_AVRCP_TG_SET_PLAYER_PROPERTY, (void *)&ev, sizeof(ev));
196         } else if (g_strcmp0(property, "LoopStatus") == 0) {
197                 struct hal_ev_avrcp_tg_player_property ev;
198
199                 if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
200                         ERR("Error");
201                         ret = HAL_AVRCP_ERROR_INVALID_PARAM;
202                         goto fail;
203                 }
204
205                 loop_status = (gchar *)g_variant_get_string(value, NULL);
206                 DBG("Value: %s\n", loop_status);
207
208                 /* Prepare to send AVRCP player property event */
209                 memset(&ev, 0, sizeof(ev));
210                 ev.prop_type = HAL_AVRCP_TG_PLAYER_PROP_REPEAT;
211                 if (g_strcmp0(loop_status, "Track") == 0)
212                         ev.value = BTRC_PLAYER_VAL_SINGLE_REPEAT;
213                 else if (g_strcmp0(loop_status, "Playlist") == 0)
214                         ev.value = BTRC_PLAYER_VAL_ALL_REPEAT;
215                 else
216                         ev.value = BTRC_PLAYER_VAL_OFF_REPEAT;
217
218                 if (!event_cb)
219                         ERR("AVRCP target DBUS handler callback not registered");
220                 else
221                         event_cb(HAL_EV_AVRCP_TG_SET_PLAYER_PROPERTY, (void *)&ev, sizeof(ev));
222
223         }
224
225         DBG("-");
226         return;
227
228 fail:
229         if (value)
230                 g_variant_unref(value);
231         err = __hal_avrcp_set_error(ret);
232         g_dbus_method_invocation_return_gerror(invocation, err);
233         g_clear_error(&err);
234 }
235
236 static const GDBusInterfaceVTable method_table = {
237         __hal_avrcp_agent_method,
238         NULL,
239         NULL,
240 };
241
242 static GDBusNodeInfo *__hal_avrcp_create_method_node_info
243                                 (const gchar *introspection_data)
244 {
245         GError *err = NULL;
246         GDBusNodeInfo *node_info = NULL;
247
248         if (introspection_data == NULL)
249                 return NULL;
250
251         node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
252
253         if (err) {
254                 ERR("Unable to create node: %s", err->message);
255                 g_clear_error(&err);
256         }
257
258         return node_info;
259 }
260
261 static void __bt_hal_avrcp_unregister_object_path(void)
262 {
263         GDBusConnection *conn;
264
265         conn = _bt_hal_get_system_gconn();
266         if (conn == NULL) {
267                 ERR("conn == NULL, return");
268                 return;
269         }
270
271         if (avrcp_reg_id > 0) {
272                 g_dbus_connection_unregister_object(conn, avrcp_reg_id);
273                 avrcp_reg_id = 0;
274         }
275 }
276
277 bt_status_t _bt_hal_dbus_handler_register_media_player(void)
278 {
279         GDBusConnection *conn;
280         gchar *adapter_path;
281         gchar *path;
282         GDBusNodeInfo *node_info;
283         GDBusProxy *proxy;
284         GVariantBuilder *builder;
285         GVariant *ret;
286         GError *error = NULL;
287
288         DBG("+");
289
290         conn = _bt_hal_get_system_gconn();
291         if (!conn) {
292                 ERR("_bt_hal_get_system_gconn returned NULL, return");
293                 return BT_STATUS_FAIL;
294         }
295
296         node_info = __hal_avrcp_create_method_node_info(
297                         hal_avrcp_tg_introspection_xml);
298         if (node_info == NULL) {
299                 ERR("__hal_avrcp_create_method_node_info failed");
300                 return BT_STATUS_FAIL;
301         }
302
303         avrcp_reg_id = g_dbus_connection_register_object(conn,
304                         BT_HAL_MEDIA_OBJECT_PATH,
305                         node_info->interfaces[0],
306                         &method_table,
307                         NULL, NULL, &error);
308         g_dbus_node_info_unref(node_info);
309
310         if (avrcp_reg_id == 0) {
311                 ERR("Failed to register: %s", error->message);
312                 g_clear_error(&error);
313                 return BT_STATUS_FAIL;
314         }
315
316         adapter_path = _bt_hal_get_adapter_path();
317         if (!adapter_path) {
318                 ERR("Could not get adapter path");
319                 return BT_STATUS_FAIL;
320         }
321
322         proxy =  g_dbus_proxy_new_sync(conn,
323                         G_DBUS_PROXY_FLAGS_NONE, NULL,
324                         BT_HAL_BLUEZ_NAME, adapter_path,
325                         BT_HAL_MEDIA_INTERFACE, NULL, &error);
326         g_free(adapter_path);
327         if (proxy == NULL) {
328                 ERR("Unable to create proxy");
329                 if (error) {
330                         ERR("Error: %s", error->message);
331                         g_clear_error(&error);
332                 }
333
334                 return BT_STATUS_FAIL;
335         }
336
337         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
338
339         g_variant_builder_add(builder, "{sv}", "LoopStatus",
340                         g_variant_new("s", __repeat_val_to_str(BTRC_PLAYER_VAL_OFF_REPEAT)));
341         g_variant_builder_add(builder, "{sv}", "Shuffle", g_variant_new("b", FALSE));
342         g_variant_builder_add(builder, "{sv}", "PlaybackStatus",
343                         g_variant_new("s", __play_status_to_str(BTRC_PLAYSTATE_STOPPED)));
344         g_variant_builder_add(builder, "{sv}", "Position", g_variant_new("u", 0));
345
346         path = g_strdup(BT_HAL_MEDIA_OBJECT_PATH);
347         ret = g_dbus_proxy_call_sync(proxy, "RegisterPlayer",
348                         g_variant_new("(oa{sv})", path, builder),
349                         G_DBUS_CALL_FLAGS_NONE, -1,
350                         NULL, &error);
351         g_variant_builder_unref(builder);
352         g_object_unref(proxy);
353         g_free(path);
354         if (ret == NULL) {
355                 ERR("Call RegisterPlayer Failed");
356                 if (error) {
357                         ERR("errCode[%x], message[%s]",
358                                         error->code, error->message);
359                         g_clear_error(&error);
360                 }
361                 return BT_STATUS_FAIL;
362         }
363
364         g_variant_unref(ret);
365         DBG("-");
366
367         return BT_STATUS_SUCCESS;
368 }
369
370 bt_status_t _bt_hal_dbus_handler_unregister_media_player(void)
371 {
372         GDBusConnection *conn;
373         GDBusProxy *proxy;
374         gchar *adapter_path;
375         GVariant *ret;
376         GError *error = NULL;
377         gchar *path;
378         int result = BT_STATUS_SUCCESS;
379
380         DBG("+");
381
382         adapter_path = _bt_hal_get_adapter_path();
383         if (adapter_path == NULL) {
384                 result = BT_STATUS_FAIL;
385                 goto FAIL;
386         }
387
388         conn = _bt_hal_get_system_gconn();
389         if (conn == NULL) {
390                 ERR("conn is NULL");
391                 g_free(adapter_path);
392                 result = BT_STATUS_FAIL;
393                 goto FAIL;
394         }
395
396         proxy =  g_dbus_proxy_new_sync(conn,
397                         G_DBUS_PROXY_FLAGS_NONE, NULL,
398                         BT_HAL_BLUEZ_NAME, adapter_path,
399                         BT_HAL_MEDIA_INTERFACE, NULL, &error);
400         g_free(adapter_path);
401         if (proxy == NULL) {
402                 ERR("Unable to create proxy");
403                 if (error) {
404                         ERR("Error: %s", error->message);
405                         g_clear_error(&error);
406                 }
407                 result = BT_STATUS_FAIL;
408                 goto FAIL;
409         }
410
411         path = g_strdup(BT_HAL_MEDIA_OBJECT_PATH);
412         DBG("path is [%s]", path);
413         ret = g_dbus_proxy_call_sync(proxy, "UnregisterPlayer",
414                         g_variant_new("(o)", path),
415                         G_DBUS_CALL_FLAGS_NONE, -1,
416                         NULL, &error);
417         g_free(path);
418         g_object_unref(proxy);
419         if (ret == NULL) {
420                 ERR("UnregisterPlayer failed");
421                 if (error) {
422                         ERR("D-Bus API failure: errCode[%x], message[%s]",
423                                         error->code, error->message);
424                         g_clear_error(&error);
425                 }
426                 result = BT_STATUS_FAIL;
427         }
428         g_variant_unref(ret);
429
430 FAIL:
431         __bt_hal_avrcp_unregister_object_path();
432
433         DBG("-");
434         return result;
435 }
436
437 #ifdef TIZEN_BT_HAL
438 static void __bt_hal_avrcp_tg_connect_cb(
439                 GDBusProxy *proxy, GAsyncResult *res, gpointer user_data)
440 {
441         struct hal_ev_avrcp_tg_conn_state ev;
442         char *address = user_data;
443         int result = BT_STATUS_SUCCESS;
444         GVariant *reply = NULL;
445         GError *g_error = NULL;
446
447         DBG("+");
448
449         reply = g_dbus_proxy_call_finish(proxy, res, &g_error);
450         g_object_unref(proxy);
451         if (reply == NULL) {
452                 ERR("AVRCP Target Connect Dbus Call Error");
453                 if (g_error) {
454                         ERR("Error: %s\n", g_error->message);
455                         g_clear_error(&g_error);
456                 }
457                 result = BT_STATUS_FAIL;
458         }
459         g_variant_unref(reply);
460
461         DBG("Address: %s", address);
462
463         /*
464          * If result is success, Remote device connected event will be triggered
465          * automatically from stack, so return from here.
466          */
467         if (result == BT_STATUS_SUCCESS)
468                 goto done;
469
470         /* Prepare to send AVRCP Target connection state event */
471         memset(&ev, 0, sizeof(ev));
472         _bt_hal_convert_addr_string_to_type(ev.bdaddr, address);
473         ev.state = HAL_AVRCP_TG_STATE_DISCONNECTED;
474         if (!event_cb)
475                 ERR("AVRCP target DBUS handler callback not registered");
476         else
477                 event_cb(HAL_EV_AVRCP_TG_CONN_STATE, (void *)&ev, sizeof(ev));
478 done:
479         g_free(address);
480         DBG("-");
481 }
482
483 bt_status_t _bt_hal_dbus_handler_avrcp_tg_connect(bt_bdaddr_t *bd_addr)
484 {
485         GDBusConnection *conn;
486         char *address;
487         int ret;
488
489         if (!bd_addr) {
490                 ERR("bd_addr is NULL, return");
491                 return BT_STATUS_PARM_INVALID;
492         }
493
494         conn = _bt_hal_get_system_gconn();
495         if (!conn) {
496                 ERR("_bt_hal_get_system_gconn returned NULL, return");
497                 return BT_STATUS_FAIL;
498         }
499
500         address = g_malloc0(BT_HAL_ADDRESS_STRING_SIZE * sizeof(char));
501         if (!address) {
502                 ERR("Memory allocation failed");
503                 return BT_STATUS_NOMEM;
504         }
505         _bt_hal_convert_addr_type_to_string(address, bd_addr->address);
506
507         ret = _bt_hal_connect_profile(address, AVRCP_CTRL_UUID,
508                         __bt_hal_avrcp_tg_connect_cb, address);
509         if (ret != BT_HAL_ERROR_NONE) {
510                 ERR("_bt_hal_connect_profile(AVRCP Controller) Error");
511                 g_free(address);
512                 return BT_STATUS_FAIL;
513         }
514
515         return BT_STATUS_SUCCESS;
516 }
517
518 static void __bt_avrcp_tg_disconnect_cb(
519                 GDBusProxy *proxy, GAsyncResult *res, gpointer user_data)
520 {
521         struct hal_ev_avrcp_tg_conn_state ev;
522         char *address = user_data;
523         int result = BT_STATUS_SUCCESS;
524         GError *g_error = NULL;
525         GVariant *reply = NULL;
526
527         DBG("+");
528
529         reply = g_dbus_proxy_call_finish(proxy, res, &g_error);
530         g_object_unref(proxy);
531         if (reply == NULL) {
532                 ERR("AVRCP Target Disconnect Dbus Call Error");
533                 if (g_error) {
534                         ERR("Error: %s\n", g_error->message);
535                         g_clear_error(&g_error);
536                 }
537                 result = BT_STATUS_FAIL;
538         }
539         g_variant_unref(reply);
540
541         /*
542          * If result is success, Remote device disconnected event will be triggered
543          * automatically from stack, so return from here.
544          */
545         if (BT_STATUS_FAIL != result) {
546                 DBG("AVRCP TG Disconnected for Device: %s", address);
547                 g_free(address);
548                 return;
549         }
550
551         DBG("AVRCP TG Disconnect failed for Device: %s", address);
552         /* Prepare to send AVRCP Target disconnection state event */
553         memset(&ev, 0, sizeof(ev));
554         _bt_hal_convert_addr_string_to_type(ev.bdaddr, address);
555         ev.state = HAL_AVRCP_TG_STATE_CONNECTED;
556         if (!event_cb)
557                 ERR("AVRCP Target DBUS handler callback not registered");
558         else
559                 event_cb(HAL_EV_AVRCP_TG_CONN_STATE, (void *)&ev, sizeof(ev));
560
561         g_free(address);
562         DBG("-");
563 }
564
565 bt_status_t _bt_hal_dbus_handler_avrcp_tg_disconnect(bt_bdaddr_t *bd_addr)
566 {
567         GDBusConnection *conn;
568         char *address;
569         int ret;
570
571         if (!bd_addr) {
572                 ERR("bd_addr is NULL, return");
573                 return BT_STATUS_PARM_INVALID;
574         }
575
576         conn = _bt_hal_get_system_gconn();
577         if (!conn) {
578                 ERR("_bt_hal_get_system_gconn returned NULL, return");
579                 return BT_STATUS_FAIL;
580         }
581
582         address = g_malloc0(BT_HAL_ADDRESS_STRING_SIZE * sizeof(char));
583         if (!address) {
584                 ERR("Memory allocation failed");
585                 return BT_STATUS_NOMEM;
586         }
587         _bt_hal_convert_addr_type_to_string(address, bd_addr->address);
588
589         ret = _bt_hal_disconnect_profile(address, AVRCP_CTRL_UUID,
590                         __bt_avrcp_tg_disconnect_cb, address);
591         if (ret != BT_HAL_ERROR_NONE) {
592                 ERR("_bt_hal_disconnect_profile(AVRCP Target) Error");
593                 return BT_STATUS_FAIL;
594         }
595
596         return BT_STATUS_SUCCESS;
597 }
598 #endif
599
600 static gboolean __hal_media_emit_property_changed(GDBusConnection *connection,
601                 const char *path, const char *interface, const char *name,
602                 const GVariant *variant)
603 {
604         GVariantBuilder *builder = NULL;
605         GVariantBuilder *invalid_builder = NULL;
606         GError *error = NULL;
607
608         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
609         g_variant_builder_add(builder, "{sv}", name, variant);
610
611         invalid_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
612
613         g_dbus_connection_emit_signal(connection, NULL, path,
614                                 DBUS_INTERFACE_PROPERTIES,
615                                 "PropertiesChanged",
616                                 g_variant_new("(sa{sv}as)",
617                                 interface, builder, invalid_builder),
618                                 &error);
619         g_variant_builder_unref(builder);
620         g_variant_builder_unref(invalid_builder);
621         if (error) {
622                 ERR("Could not Emit PropertiesChanged Signal: errCode[%x], message[%s]",
623                         error->code, error->message);
624                 g_clear_error(&error);
625                 return FALSE;
626         }
627
628         return TRUE;
629 }
630
631 bt_status_t _bt_hal_dbus_handler_avrcp_tg_play_status_changed(btrc_play_status_t play_status)
632 {
633         GDBusConnection *conn;
634
635         DBG("+");
636
637         conn = _bt_hal_get_system_gconn();
638         if (!conn) {
639                 ERR("_bt_hal_get_system_gconn returned NULL, return");
640                 return BT_STATUS_FAIL;
641         }
642
643         if (!__hal_media_emit_property_changed(conn, BT_HAL_MEDIA_OBJECT_PATH,
644                         BT_HAL_MEDIA_PLAYER_INTERFACE, "PlaybackStatus",
645                         g_variant_new_string(__play_status_to_str(play_status)))) {
646                 ERR("Error sending the PropertyChanged signal");
647                 return BT_STATUS_FAIL;
648         }
649
650         DBG("-");
651         return BT_STATUS_SUCCESS;
652 }
653
654 bt_status_t _bt_hal_dbus_handler_avrcp_tg_play_pos_changed(uint32_t song_pos)
655 {
656         GDBusConnection *conn;
657
658         DBG("+");
659
660         conn = _bt_hal_get_system_gconn();
661         if (!conn) {
662                 ERR("_bt_hal_get_system_gconn returned NULL, return");
663                 return BT_STATUS_FAIL;
664         }
665
666         if (!__hal_media_emit_property_changed(conn, BT_HAL_MEDIA_OBJECT_PATH,
667                         BT_HAL_MEDIA_PLAYER_INTERFACE, "Position",
668                         g_variant_new_uint32(song_pos))) {
669                 ERR("Error sending the PropertyChanged signal");
670                 return BT_STATUS_FAIL;
671         }
672
673         DBG("-");
674         return BT_STATUS_SUCCESS;
675 }
676
677 bt_status_t _bt_hal_dbus_handler_avrcp_tg_app_setting_changed(btrc_player_settings_t *player_setting)
678 {
679         GDBusConnection *conn;
680         char *property_name = NULL;
681         GVariant *variant;
682         int i;
683
684         DBG("+");
685
686         conn = _bt_hal_get_system_gconn();
687         if (!conn) {
688                 ERR("_bt_hal_get_system_gconn returned NULL, return");
689                 return BT_STATUS_FAIL;
690         }
691
692         for (i = 0; i < player_setting->num_attr; i++) {
693                 property_name = NULL;
694                 variant = NULL;
695
696                 switch (player_setting->attr_ids[i]) {
697                 case BTRC_PLAYER_ATTR_REPEAT:
698                         property_name = "LoopStatus";
699                         variant = g_variant_new_string(
700                                         __repeat_val_to_str(player_setting->attr_values[i]));
701                         break;
702                 case BTRC_PLAYER_ATTR_SHUFFLE:
703                         property_name = "Shuffle";
704                         if (BTRC_PLAYER_VAL_OFF_SHUFFLE == player_setting->attr_values[i])
705                                 variant = g_variant_new_boolean(FALSE);
706                         else
707                                 variant = g_variant_new_boolean(TRUE);
708                         break;
709                 case BTRC_PLAYER_ATTR_SCAN:
710                 case BTRC_PLAYER_ATTR_EQUALIZER:
711                 default:
712                         ERR("Unsupported attr type: %d", player_setting->attr_ids[i]);
713                 }
714
715                 if (!property_name)
716                         continue;
717
718                 if (!__hal_media_emit_property_changed(conn, BT_HAL_MEDIA_OBJECT_PATH,
719                                         BT_HAL_MEDIA_PLAYER_INTERFACE, property_name, variant)) {
720                         ERR("Error sending the PropertyChanged signal");
721                         return BT_STATUS_FAIL;
722                 }
723         }
724
725         DBG("-");
726         return BT_STATUS_SUCCESS;
727 }
728
729 bt_status_t _bt_hal_dbus_handler_avrcp_tg_set_track_info(
730                 uint8_t num_attr, btrc_element_attr_val_t *p_attrs)
731 {
732         GDBusConnection *conn;
733         GError *error = NULL;
734         GVariantBuilder *invalid_builder = NULL;
735         GVariantBuilder *builder = NULL;
736         GVariantBuilder *inner_builder = NULL;
737         char *interface = BT_HAL_MEDIA_PLAYER_INTERFACE;
738         gboolean ret;
739         int i;
740
741         DBG("+");
742
743         if (!p_attrs) {
744                 ERR("p_attrs is NULL");
745                 return BT_STATUS_FAIL;
746         }
747
748         conn = _bt_hal_get_system_gconn();;
749         if (!conn) {
750                 ERR("_bt_hal_get_system_gconn returned NULL, return");
751                 return BT_STATUS_FAIL;
752         }
753
754         invalid_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
755         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
756         inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
757
758         for (i = 0; i < num_attr; i++) {
759                 switch (p_attrs[i].attr_id) {
760                 case BTRC_MEDIA_ATTR_ID_TITLE:
761                         INFO("Title: %s", p_attrs[i].text);
762                         g_variant_builder_add(inner_builder, "{sv}",
763                                         "xesam:title", g_variant_new_string((const char *)p_attrs[i].text));
764                         break;
765                 case BTRC_MEDIA_ATTR_ID_ARTIST: {
766                         GVariant *children[1];
767
768                         INFO("Artist: %s", p_attrs[i].text);
769                         children[0] = g_variant_new_string((const char *)p_attrs[i].text);
770                         g_variant_builder_add(inner_builder, "{sv}", "xesam:artist",
771                                         g_variant_new_array(G_VARIANT_TYPE_STRING, children, 1));
772                         break;
773                 }
774                 case BTRC_MEDIA_ATTR_ID_ALBUM:
775                         INFO("Album: %s", p_attrs[i].text);
776                         g_variant_builder_add(inner_builder, "{sv}",
777                                         "xesam:album", g_variant_new_string((const char *)p_attrs[i].text));
778                         break;
779                 case BTRC_MEDIA_ATTR_ID_TRACK_NUM: {
780                         uint32_t cur_track = 0;
781
782                         sscanf((char *)p_attrs[i].text, "%u", &cur_track);
783                         INFO("Current track: %u", cur_track);
784                         g_variant_builder_add(inner_builder, "{sv}",
785                                         "xesam:trackNumber", g_variant_new_int32(cur_track));
786                         break;
787                 }
788                 case BTRC_MEDIA_ATTR_ID_NUM_TRACKS: {
789                         uint32_t num_tracks = 0;
790
791                         sscanf((char *)p_attrs[i].text, "%u", &num_tracks);
792                         INFO("Total tracks: %u", num_tracks);
793                         g_variant_builder_add(inner_builder, "{sv}",
794                                         "xesam:totalTracks", g_variant_new_int32(num_tracks));
795                         break;
796                 }
797                 case BTRC_MEDIA_ATTR_ID_GENRE: {
798                         GVariant *children[1];
799
800                         INFO("Genre: %s", p_attrs[i].text);
801                         children[0] = g_variant_new_string((const char *)p_attrs[i].text);
802                         g_variant_builder_add(inner_builder, "{sv}", "xesam:genre",
803                                         g_variant_new_array(G_VARIANT_TYPE_STRING, children, 1));
804                         break;
805                 }
806                 case BTRC_MEDIA_ATTR_ID_PLAYING_TIME: {
807                         uint32_t duration = 0;
808
809                         sscanf((char *)p_attrs[i].text, "%u", &duration);
810                         INFO("Song duration: %u", duration);
811                         g_variant_builder_add(inner_builder, "{sv}",
812                                         "mpris:length", g_variant_new_int64(duration));
813                         break;
814                 }
815                 default:
816                         INFO("Unknown attribute Id: %d", p_attrs[i].attr_id);
817                 }
818         }
819
820         g_variant_builder_add(builder, "{sv}",
821                         "Metadata", g_variant_new("a{sv}", inner_builder));
822         ret = g_dbus_connection_emit_signal(conn, NULL, BT_HAL_MEDIA_OBJECT_PATH,
823                         DBUS_INTERFACE_PROPERTIES,
824                         "PropertiesChanged",
825                         g_variant_new("(sa{sv}as)",
826                                 interface, builder, invalid_builder),
827                         &error);
828         g_variant_builder_unref(inner_builder);
829         g_variant_builder_unref(builder);
830         g_variant_builder_unref(invalid_builder);
831         if (!ret) {
832                 if (error != NULL) {
833                         ERR("D-Bus API failure: errCode[%x], message[%s]",
834                                         error->code, error->message);
835                         g_clear_error(&error);
836                 }
837                 return BT_STATUS_FAIL;
838         }
839
840         DBG("-");
841
842         return BT_STATUS_SUCCESS;
843 }
844
845 /* To send stack event to hal-avrcp-tg handler */
846 void _bt_hal_register_avrcp_tg_dbus_handler_cb(handle_stack_msg cb)
847 {
848         event_cb = cb;
849 }
850
851 /* To send stack event to hal-avrcp-tg handler */
852 void _bt_hal_unregister_avrcp_tg_dbus_handler_cb()
853 {
854         event_cb = NULL;
855 }