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