4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Atul Kumar Rai <a.rai@samsung.com>
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
27 #include <dbus/dbus.h>
33 #include "bt-hal-dbus-common-utils.h"
34 #include "bt-hal-internal.h"
35 #include "bt-hal-avrcp-tg-dbus-handler.h"
37 #define HAL_ERROR_INTERNAL "InternalError"
38 #define HAL_ERROR_INVALID_PARAM "InvalidParameters"
39 #define HAL_ERROR_INVALID_INTERFACE "InvalidInterface"
41 #define BT_HAL_MEDIA_OBJECT_PATH "/Musicplayer"
42 #define BT_HAL_MEDIA_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
46 HAL_AVRCP_ERROR_INTERNAL,
47 HAL_AVRCP_ERROR_INVALID_PARAM,
48 HAL_AVRCP_ERROR_NOT_SUPPORTED,
49 HAL_AVRCP_ERROR_INVALID_INTERFACE
52 static handle_stack_msg event_cb = NULL;
54 static guint avrcp_reg_id = 0;
56 /* Introspection data exposed from bt-service */
57 static const gchar hal_avrcp_tg_introspection_xml[] =
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'/>"
68 static const char *__repeat_val_to_str(btrc_player_repeat_val_t repeat_val)
71 case BTRC_PLAYER_VAL_OFF_REPEAT:
73 case BTRC_PLAYER_VAL_SINGLE_REPEAT:
75 case BTRC_PLAYER_VAL_ALL_REPEAT:
77 case BTRC_PLAYER_VAL_GROUP_REPEAT:
80 ERR("Invalid repeat value: %d", repeat_val);
86 static const char *__shuffle_val_to_str(btrc_player_shuffle_val_t shuffle_val)
88 switch (shuffle_val) {
89 case BTRC_PLAYER_VAL_OFF_SHUFFLE:
91 case BTRC_PLAYER_VAL_ALL_SHUFFLE:
93 case BTRC_PLAYER_VAL_GROUP_SHUFFLE:
96 ERR("Invalid shuffle value: %d", shuffle_val);
102 static const char *__play_status_to_str(btrc_play_status_t play_status)
104 switch (play_status) {
105 case BTRC_PLAYSTATE_STOPPED:
107 case BTRC_PLAYSTATE_PLAYING:
109 case BTRC_PLAYSTATE_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:
118 ERR("Invalid play status: %d", play_status);
123 static GQuark __hal_avrcp_error_quark(void)
125 static GQuark quark = 0;
128 quark = g_quark_from_static_string("bt-avrcp");
133 static GError *__hal_avrcp_set_error(hal_avrcp_error_t error)
135 ERR("error[%d]\n", 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:
146 return g_error_new(__hal_avrcp_error_quark(),
147 error, HAL_ERROR_INTERNAL);
151 static void __hal_avrcp_agent_method(GDBusConnection *connection,
153 const gchar *object_path,
154 const gchar *interface_name,
155 const gchar *method_name,
156 GVariant *parameters,
157 GDBusMethodInvocation *invocation,
160 int ret = HAL_AVRCP_ERROR_NONE;
162 gboolean shuffle_status;
163 gchar *interface = NULL;
164 gchar *property = NULL;
165 gchar *loop_status = NULL;
166 GVariant *value = NULL;
169 INFO("method %s", method_name);
170 INFO("object_path %s", object_path);
172 if (g_strcmp0(method_name, "Set") == 0) {
173 g_variant_get(parameters, "(&s&sv)",
174 &interface, &property, &value);
176 if (g_strcmp0(interface, BT_HAL_MEDIA_PLAYER_INTERFACE) != 0) {
177 ret = HAL_AVRCP_ERROR_INVALID_INTERFACE;
183 ERR("value is NULL");
184 ret = HAL_AVRCP_ERROR_INVALID_PARAM;
188 DBG("Property: %s\n", property);
189 if (g_strcmp0(property, "Shuffle") == 0) {
190 struct hal_ev_avrcp_tg_player_property ev;
192 if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
194 ret = HAL_AVRCP_ERROR_INVALID_PARAM;
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");
203 ev.prop_type = HAL_AVRCP_TG_PLAYER_PROP_SHUFFLE;
205 ev.value = BTRC_PLAYER_VAL_ALL_SHUFFLE;
207 ev.value = BTRC_PLAYER_VAL_OFF_SHUFFLE;
210 ERR("AVRCP target DBUS handler callback not registered");
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;
216 if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
218 ret = HAL_AVRCP_ERROR_INVALID_PARAM;
222 loop_status = (gchar *)g_variant_get_string(value, NULL);
223 DBG("Value: %s\n", loop_status);
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;
233 ev.value = BTRC_PLAYER_VAL_OFF_REPEAT;
236 ERR("AVRCP target DBUS handler callback not registered");
238 event_cb(HAL_EV_AVRCP_TG_SET_PLAYER_PROPERTY, (void *)&ev, sizeof(ev));
247 g_variant_unref(value);
248 err = __hal_avrcp_set_error(ret);
249 g_dbus_method_invocation_return_gerror(invocation, err);
253 static const GDBusInterfaceVTable method_table = {
254 __hal_avrcp_agent_method,
259 static GDBusNodeInfo *__hal_avrcp_create_method_node_info
260 (const gchar *introspection_data)
263 GDBusNodeInfo *node_info = NULL;
265 if (introspection_data == NULL)
268 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
271 ERR("Unable to create node: %s", err->message);
278 static void __bt_hal_avrcp_unregister_object_path(void)
280 GDBusConnection *conn;
282 conn = _bt_hal_get_system_gconn();
284 ERR("conn == NULL, return");
288 if (avrcp_reg_id > 0) {
289 g_dbus_connection_unregister_object(conn, avrcp_reg_id);
294 bt_status_t _bt_hal_dbus_handler_register_media_player(void)
296 GDBusConnection *conn;
299 GDBusNodeInfo *node_info;
301 GVariantBuilder *builder;
303 GError *error = NULL;
307 conn = _bt_hal_get_system_gconn();
309 ERR("_bt_hal_get_system_gconn returned NULL, return");
310 return BT_STATUS_FAIL;
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;
320 avrcp_reg_id = g_dbus_connection_register_object(conn,
321 BT_HAL_MEDIA_OBJECT_PATH,
322 node_info->interfaces[0],
325 g_dbus_node_info_unref(node_info);
327 if (avrcp_reg_id == 0) {
328 ERR("Failed to register: %s", error->message);
329 g_clear_error(&error);
330 return BT_STATUS_FAIL;
333 adapter_path = _bt_hal_get_adapter_path();
335 ERR("Could not get adapter path");
336 return BT_STATUS_FAIL;
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);
345 ERR("Unable to create proxy");
347 ERR("Error: %s", error->message);
348 g_clear_error(&error);
351 return BT_STATUS_FAIL;
354 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
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));
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,
368 g_variant_builder_unref(builder);
369 g_object_unref(proxy);
372 ERR("Call RegisterPlayer Failed");
374 ERR("errCode[%x], message[%s]",
375 error->code, error->message);
376 g_clear_error(&error);
378 return BT_STATUS_FAIL;
381 g_variant_unref(ret);
384 return BT_STATUS_SUCCESS;
387 bt_status_t _bt_hal_dbus_handler_unregister_media_player(void)
389 GDBusConnection *conn;
393 GError *error = NULL;
395 int result = BT_STATUS_SUCCESS;
399 adapter_path = _bt_hal_get_adapter_path();
400 if (adapter_path == NULL) {
401 result = BT_STATUS_FAIL;
405 conn = _bt_hal_get_system_gconn();
408 g_free(adapter_path);
409 result = BT_STATUS_FAIL;
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);
419 ERR("Unable to create proxy");
421 ERR("Error: %s", error->message);
422 g_clear_error(&error);
424 result = BT_STATUS_FAIL;
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,
435 g_object_unref(proxy);
437 ERR("UnregisterPlayer failed");
439 ERR("D-Bus API failure: errCode[%x], message[%s]",
440 error->code, error->message);
441 g_clear_error(&error);
443 result = BT_STATUS_FAIL;
445 g_variant_unref(ret);
448 __bt_hal_avrcp_unregister_object_path();
455 static void __bt_hal_avrcp_tg_connect_cb(
456 GDBusProxy *proxy, GAsyncResult *res, gpointer user_data)
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;
466 reply = g_dbus_proxy_call_finish(proxy, res, &g_error);
467 g_object_unref(proxy);
469 ERR("AVRCP Target Connect Dbus Call Error");
471 ERR("Error: %s\n", g_error->message);
472 g_clear_error(&g_error);
474 result = BT_STATUS_FAIL;
476 g_variant_unref(reply);
478 DBG("Address: %s", address);
481 * If result is success, Remote device connected event will be triggered
482 * automatically from stack, so return from here.
484 if (result == BT_STATUS_SUCCESS)
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;
492 ERR("AVRCP target DBUS handler callback not registered");
494 event_cb(HAL_EV_AVRCP_TG_CONN_STATE, (void *)&ev, sizeof(ev));
500 bt_status_t _bt_hal_dbus_handler_avrcp_tg_connect(bt_bdaddr_t *bd_addr)
502 GDBusConnection *conn;
507 ERR("bd_addr is NULL, return");
508 return BT_STATUS_PARM_INVALID;
511 conn = _bt_hal_get_system_gconn();
513 ERR("_bt_hal_get_system_gconn returned NULL, return");
514 return BT_STATUS_FAIL;
517 address = g_malloc0(BT_HAL_ADDRESS_STRING_SIZE * sizeof(char));
519 ERR("Memory allocation failed");
520 return BT_STATUS_NOMEM;
522 _bt_hal_convert_addr_type_to_string(address, bd_addr->address);
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 return BT_STATUS_FAIL;
531 return BT_STATUS_SUCCESS;
534 static void __bt_avrcp_tg_disconnect_cb(
535 GDBusProxy *proxy, GAsyncResult *res, gpointer user_data)
537 struct hal_ev_avrcp_tg_conn_state ev;
538 char *address = user_data;
539 int result = BT_STATUS_SUCCESS;
540 GError *g_error = NULL;
541 GVariant *reply = NULL;
545 reply = g_dbus_proxy_call_finish(proxy, res, &g_error);
546 g_object_unref(proxy);
548 ERR("AVRCP Target Disconnect Dbus Call Error");
550 ERR("Error: %s\n", g_error->message);
551 g_clear_error(&g_error);
553 result = BT_STATUS_FAIL;
555 g_variant_unref(reply);
558 * If result is success, Remote device disconnected event will be triggered
559 * automatically from stack, so return from here.
561 if (BT_STATUS_FAIL != result) {
562 DBG("AVRCP TG Disconnected for Device: %s", address);
567 DBG("AVRCP TG Disconnect failed for Device: %s", address);
568 /* Prepare to send AVRCP Target disconnection state event */
569 memset(&ev, 0, sizeof(ev));
570 _bt_hal_convert_addr_string_to_type(ev.bdaddr, address);
571 ev.state = HAL_AVRCP_TG_STATE_CONNECTED;
573 ERR("AVRCP Target DBUS handler callback not registered");
575 event_cb(HAL_EV_AVRCP_TG_CONN_STATE, (void *)&ev, sizeof(ev));
581 bt_status_t _bt_hal_dbus_handler_avrcp_tg_disconnect(bt_bdaddr_t *bd_addr)
583 GDBusConnection *conn;
588 ERR("bd_addr is NULL, return");
589 return BT_STATUS_PARM_INVALID;
592 conn = _bt_hal_get_system_gconn();
594 ERR("_bt_hal_get_system_gconn returned NULL, return");
595 return BT_STATUS_FAIL;
598 address = g_malloc0(BT_HAL_ADDRESS_STRING_SIZE * sizeof(char));
600 ERR("Memory allocation failed");
601 return BT_STATUS_NOMEM;
603 _bt_hal_convert_addr_type_to_string(address, bd_addr->address);
605 ret = _bt_hal_disconnect_profile(address, AVRCP_TARGET_UUID,
606 __bt_avrcp_tg_disconnect_cb, address);
607 if (ret != BT_HAL_ERROR_NONE) {
608 ERR("_bt_hal_connect_profile(AVRCP Target) Error");
609 return BT_STATUS_FAIL;
612 return BT_STATUS_SUCCESS;
616 static gboolean __hal_media_emit_property_changed(GDBusConnection *connection,
617 const char *path, const char *interface, const char *name,
618 const GVariant *variant)
620 GVariantBuilder *builder = NULL;
621 GVariantBuilder *invalid_builder = NULL;
622 GError *error = NULL;
624 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
625 g_variant_builder_add(builder, "{sv}", name, variant);
627 invalid_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
629 g_dbus_connection_emit_signal(connection, NULL, path,
630 DBUS_INTERFACE_PROPERTIES,
632 g_variant_new("(sa{sv}as)",
633 interface, builder, invalid_builder),
635 g_variant_builder_unref(builder);
636 g_variant_builder_unref(invalid_builder);
638 ERR("Could not Emit PropertiesChanged Signal: errCode[%x], message[%s]",
639 error->code, error->message);
640 g_clear_error(&error);
647 bt_status_t _bt_hal_dbus_handler_avrcp_tg_play_status_changed(btrc_play_status_t play_status)
649 GDBusConnection *conn;
653 conn = _bt_hal_get_system_gconn();
655 ERR("_bt_hal_get_system_gconn returned NULL, return");
656 return BT_STATUS_FAIL;
659 if (!__hal_media_emit_property_changed(conn, BT_HAL_MEDIA_OBJECT_PATH,
660 BT_HAL_MEDIA_PLAYER_INTERFACE, "PlaybackStatus",
661 g_variant_new_string(__play_status_to_str(play_status)))) {
662 ERR("Error sending the PropertyChanged signal");
663 return BT_STATUS_FAIL;
667 return BT_STATUS_SUCCESS;
670 bt_status_t _bt_hal_dbus_handler_avrcp_tg_play_pos_changed(uint32_t song_pos)
672 GDBusConnection *conn;
676 conn = _bt_hal_get_system_gconn();
678 ERR("_bt_hal_get_system_gconn returned NULL, return");
679 return BT_STATUS_FAIL;
682 if (!__hal_media_emit_property_changed(conn, BT_HAL_MEDIA_OBJECT_PATH,
683 BT_HAL_MEDIA_PLAYER_INTERFACE, "Position",
684 g_variant_new_uint32(song_pos))) {
685 ERR("Error sending the PropertyChanged signal");
686 return BT_STATUS_FAIL;
690 return BT_STATUS_SUCCESS;
693 bt_status_t _bt_hal_dbus_handler_avrcp_tg_app_setting_changed(btrc_player_settings_t *player_setting)
695 GDBusConnection *conn;
696 char *property_name = NULL;
702 conn = _bt_hal_get_system_gconn();
704 ERR("_bt_hal_get_system_gconn returned NULL, return");
705 return BT_STATUS_FAIL;
708 for (i = 0; i < player_setting->num_attr; i++) {
709 property_name = NULL;
712 switch (player_setting->attr_ids[i]) {
713 case BTRC_PLAYER_ATTR_REPEAT:
714 property_name = "LoopStatus";
715 variant = g_variant_new_string(
716 __repeat_val_to_str(player_setting->attr_values[i]));
718 case BTRC_PLAYER_ATTR_SHUFFLE:
719 property_name = "Shuffle";
720 if (BTRC_PLAYER_VAL_OFF_SHUFFLE == player_setting->attr_values[i])
721 variant = g_variant_new_boolean(FALSE);
723 variant = g_variant_new_boolean(TRUE);
725 case BTRC_PLAYER_ATTR_SCAN:
726 case BTRC_PLAYER_ATTR_EQUALIZER:
728 ERR("Unsupported attr type: %d", player_setting->attr_ids[i]);
734 if (!__hal_media_emit_property_changed(conn, BT_HAL_MEDIA_OBJECT_PATH,
735 BT_HAL_MEDIA_PLAYER_INTERFACE, property_name, variant)) {
736 ERR("Error sending the PropertyChanged signal");
737 return BT_STATUS_FAIL;
742 return BT_STATUS_SUCCESS;
745 bt_status_t _bt_hal_dbus_handler_avrcp_tg_set_track_info(
746 uint8_t num_attr, btrc_element_attr_val_t *p_attrs)
748 GDBusConnection *conn;
749 GError *error = NULL;
750 GVariantBuilder *invalid_builder = NULL;
751 GVariantBuilder *builder = NULL;
752 GVariantBuilder *inner_builder = NULL;
753 char *interface = BT_HAL_MEDIA_PLAYER_INTERFACE;
760 ERR("p_attrs is NULL");
761 return BT_STATUS_FAIL;
764 conn = _bt_hal_get_system_gconn();;
766 ERR("_bt_hal_get_system_gconn returned NULL, return");
767 return BT_STATUS_FAIL;
770 invalid_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
771 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
772 inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
774 for (i = 0; i < num_attr; i++) {
775 switch (p_attrs[i].attr_id) {
776 case BTRC_MEDIA_ATTR_ID_TITLE:
777 INFO("Title: %s", p_attrs[i].text);
778 g_variant_builder_add(inner_builder, "{sv}",
779 "xesam:title", g_variant_new_string((const char *)p_attrs[i].text));
781 case BTRC_MEDIA_ATTR_ID_ARTIST: {
782 GVariant *children[1];
784 INFO("Artist: %s", p_attrs[i].text);
785 children[0] = g_variant_new_string((const char *)p_attrs[i].text);
786 g_variant_builder_add(inner_builder, "{sv}", "xesam:artist",
787 g_variant_new_array(G_VARIANT_TYPE_STRING, children, 1));
790 case BTRC_MEDIA_ATTR_ID_ALBUM:
791 INFO("Album: %s", p_attrs[i].text);
792 g_variant_builder_add(inner_builder, "{sv}",
793 "xesam:album", g_variant_new_string((const char *)p_attrs[i].text));
795 case BTRC_MEDIA_ATTR_ID_TRACK_NUM: {
796 uint32_t cur_track = 0;
798 sscanf((char *)p_attrs[i].text, "%u", &cur_track);
799 INFO("Current track: %u", cur_track);
800 g_variant_builder_add(inner_builder, "{sv}",
801 "xesam:trackNumber", g_variant_new_int32(cur_track));
804 case BTRC_MEDIA_ATTR_ID_NUM_TRACKS: {
805 uint32_t num_tracks = 0;
807 sscanf((char *)p_attrs[i].text, "%u", &num_tracks);
808 INFO("Total tracks: %u", num_tracks);
809 g_variant_builder_add(inner_builder, "{sv}",
810 "xesam:totalTracks", g_variant_new_int32(num_tracks));
813 case BTRC_MEDIA_ATTR_ID_GENRE: {
814 GVariant *children[1];
816 INFO("Genre: %s", p_attrs[i].text);
817 children[0] = g_variant_new_string((const char *)p_attrs[i].text);
818 g_variant_builder_add(inner_builder, "{sv}", "xesam:genre",
819 g_variant_new_array(G_VARIANT_TYPE_STRING, children, 1));
822 case BTRC_MEDIA_ATTR_ID_PLAYING_TIME: {
823 uint32_t duration = 0;
825 sscanf((char *)p_attrs[i].text, "%u", &duration);
826 INFO("Song duration: %u", duration);
827 g_variant_builder_add(inner_builder, "{sv}",
828 "mpris:length", g_variant_new_int64(duration));
832 INFO("Unknown attribute Id: %d", p_attrs[i].attr_id);
836 g_variant_builder_add(builder, "{sv}",
837 "Metadata", g_variant_new("a{sv}", inner_builder));
838 ret = g_dbus_connection_emit_signal(conn, NULL, BT_HAL_MEDIA_OBJECT_PATH,
839 DBUS_INTERFACE_PROPERTIES,
841 g_variant_new("(sa{sv}as)",
842 interface, builder, invalid_builder),
844 g_variant_builder_unref(inner_builder);
845 g_variant_builder_unref(builder);
846 g_variant_builder_unref(invalid_builder);
849 ERR("D-Bus API failure: errCode[%x], message[%s]",
850 error->code, error->message);
851 g_clear_error(&error);
853 return BT_STATUS_FAIL;
858 return BT_STATUS_SUCCESS;
861 /* To send stack event to hal-avrcp-tg handler */
862 void _bt_hal_register_avrcp_tg_dbus_handler_cb(handle_stack_msg cb)
867 /* To send stack event to hal-avrcp-tg handler */
868 void _bt_hal_unregister_avrcp_tg_dbus_handler_cb()