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");
529 return BT_STATUS_FAIL;
532 return BT_STATUS_SUCCESS;
535 static void __bt_avrcp_tg_disconnect_cb(
536 GDBusProxy *proxy, GAsyncResult *res, gpointer user_data)
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;
546 reply = g_dbus_proxy_call_finish(proxy, res, &g_error);
547 g_object_unref(proxy);
549 ERR("AVRCP Target Disconnect Dbus Call Error");
551 ERR("Error: %s\n", g_error->message);
552 g_clear_error(&g_error);
554 result = BT_STATUS_FAIL;
556 g_variant_unref(reply);
559 * If result is success, Remote device disconnected event will be triggered
560 * automatically from stack, so return from here.
562 if (BT_STATUS_FAIL != result) {
563 DBG("AVRCP TG Disconnected for Device: %s", address);
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;
574 ERR("AVRCP Target DBUS handler callback not registered");
576 event_cb(HAL_EV_AVRCP_TG_CONN_STATE, (void *)&ev, sizeof(ev));
582 bt_status_t _bt_hal_dbus_handler_avrcp_tg_disconnect(bt_bdaddr_t *bd_addr)
584 GDBusConnection *conn;
589 ERR("bd_addr is NULL, return");
590 return BT_STATUS_PARM_INVALID;
593 conn = _bt_hal_get_system_gconn();
595 ERR("_bt_hal_get_system_gconn returned NULL, return");
596 return BT_STATUS_FAIL;
599 address = g_malloc0(BT_HAL_ADDRESS_STRING_SIZE * sizeof(char));
601 ERR("Memory allocation failed");
602 return BT_STATUS_NOMEM;
604 _bt_hal_convert_addr_type_to_string(address, bd_addr->address);
606 ret = _bt_hal_disconnect_profile(address, AVRCP_TARGET_UUID,
607 __bt_avrcp_tg_disconnect_cb, address);
608 if (ret != BT_HAL_ERROR_NONE) {
609 ERR("_bt_hal_connect_profile(AVRCP Target) Error");
610 return BT_STATUS_FAIL;
613 return BT_STATUS_SUCCESS;
617 static gboolean __hal_media_emit_property_changed(GDBusConnection *connection,
618 const char *path, const char *interface, const char *name,
619 const GVariant *variant)
621 GVariantBuilder *builder = NULL;
622 GVariantBuilder *invalid_builder = NULL;
623 GError *error = NULL;
625 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
626 g_variant_builder_add(builder, "{sv}", name, variant);
628 invalid_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
630 g_dbus_connection_emit_signal(connection, NULL, path,
631 DBUS_INTERFACE_PROPERTIES,
633 g_variant_new("(sa{sv}as)",
634 interface, builder, invalid_builder),
636 g_variant_builder_unref(builder);
637 g_variant_builder_unref(invalid_builder);
639 ERR("Could not Emit PropertiesChanged Signal: errCode[%x], message[%s]",
640 error->code, error->message);
641 g_clear_error(&error);
648 bt_status_t _bt_hal_dbus_handler_avrcp_tg_play_status_changed(btrc_play_status_t play_status)
650 GDBusConnection *conn;
654 conn = _bt_hal_get_system_gconn();
656 ERR("_bt_hal_get_system_gconn returned NULL, return");
657 return BT_STATUS_FAIL;
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;
668 return BT_STATUS_SUCCESS;
671 bt_status_t _bt_hal_dbus_handler_avrcp_tg_play_pos_changed(uint32_t song_pos)
673 GDBusConnection *conn;
677 conn = _bt_hal_get_system_gconn();
679 ERR("_bt_hal_get_system_gconn returned NULL, return");
680 return BT_STATUS_FAIL;
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;
691 return BT_STATUS_SUCCESS;
694 bt_status_t _bt_hal_dbus_handler_avrcp_tg_app_setting_changed(btrc_player_settings_t *player_setting)
696 GDBusConnection *conn;
697 char *property_name = NULL;
703 conn = _bt_hal_get_system_gconn();
705 ERR("_bt_hal_get_system_gconn returned NULL, return");
706 return BT_STATUS_FAIL;
709 for (i = 0; i < player_setting->num_attr; i++) {
710 property_name = NULL;
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]));
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);
724 variant = g_variant_new_boolean(TRUE);
726 case BTRC_PLAYER_ATTR_SCAN:
727 case BTRC_PLAYER_ATTR_EQUALIZER:
729 ERR("Unsupported attr type: %d", player_setting->attr_ids[i]);
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;
743 return BT_STATUS_SUCCESS;
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)
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;
761 ERR("p_attrs is NULL");
762 return BT_STATUS_FAIL;
765 conn = _bt_hal_get_system_gconn();;
767 ERR("_bt_hal_get_system_gconn returned NULL, return");
768 return BT_STATUS_FAIL;
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}"));
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));
782 case BTRC_MEDIA_ATTR_ID_ARTIST: {
783 GVariant *children[1];
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));
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));
796 case BTRC_MEDIA_ATTR_ID_TRACK_NUM: {
797 uint32_t cur_track = 0;
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));
805 case BTRC_MEDIA_ATTR_ID_NUM_TRACKS: {
806 uint32_t num_tracks = 0;
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));
814 case BTRC_MEDIA_ATTR_ID_GENRE: {
815 GVariant *children[1];
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));
823 case BTRC_MEDIA_ATTR_ID_PLAYING_TIME: {
824 uint32_t duration = 0;
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));
833 INFO("Unknown attribute Id: %d", p_attrs[i].attr_id);
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,
842 g_variant_new("(sa{sv}as)",
843 interface, builder, invalid_builder),
845 g_variant_builder_unref(inner_builder);
846 g_variant_builder_unref(builder);
847 g_variant_builder_unref(invalid_builder);
850 ERR("D-Bus API failure: errCode[%x], message[%s]",
851 error->code, error->message);
852 g_clear_error(&error);
854 return BT_STATUS_FAIL;
859 return BT_STATUS_SUCCESS;
862 /* To send stack event to hal-avrcp-tg handler */
863 void _bt_hal_register_avrcp_tg_dbus_handler_cb(handle_stack_msg cb)
868 /* To send stack event to hal-avrcp-tg handler */
869 void _bt_hal_unregister_avrcp_tg_dbus_handler_cb()