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);
85 static const char *__play_status_to_str(btrc_play_status_t play_status)
87 switch (play_status) {
88 case BTRC_PLAYSTATE_STOPPED:
90 case BTRC_PLAYSTATE_PLAYING:
92 case BTRC_PLAYSTATE_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:
101 ERR("Invalid play status: %d", play_status);
106 static GQuark __hal_avrcp_error_quark(void)
108 static GQuark quark = 0;
111 quark = g_quark_from_static_string("bt-avrcp");
116 static GError *__hal_avrcp_set_error(hal_avrcp_error_t error)
118 ERR("error[%d]\n", 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:
129 return g_error_new(__hal_avrcp_error_quark(),
130 error, HAL_ERROR_INTERNAL);
134 static void __hal_avrcp_agent_method(GDBusConnection *connection,
136 const gchar *object_path,
137 const gchar *interface_name,
138 const gchar *method_name,
139 GVariant *parameters,
140 GDBusMethodInvocation *invocation,
143 int ret = HAL_AVRCP_ERROR_NONE;
145 gboolean shuffle_status;
146 gchar *interface = NULL;
147 gchar *property = NULL;
148 gchar *loop_status = NULL;
149 GVariant *value = NULL;
152 INFO("method %s", method_name);
153 INFO("object_path %s", object_path);
155 if (g_strcmp0(method_name, "Set") == 0) {
156 g_variant_get(parameters, "(&s&sv)",
157 &interface, &property, &value);
159 if (g_strcmp0(interface, BT_HAL_MEDIA_PLAYER_INTERFACE) != 0) {
160 ret = HAL_AVRCP_ERROR_INVALID_INTERFACE;
166 ERR("value is NULL");
167 ret = HAL_AVRCP_ERROR_INVALID_PARAM;
171 DBG("Property: %s\n", property);
172 if (g_strcmp0(property, "Shuffle") == 0) {
173 struct hal_ev_avrcp_tg_player_property ev;
175 if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
177 ret = HAL_AVRCP_ERROR_INVALID_PARAM;
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");
186 ev.prop_type = HAL_AVRCP_TG_PLAYER_PROP_SHUFFLE;
188 ev.value = BTRC_PLAYER_VAL_ALL_SHUFFLE;
190 ev.value = BTRC_PLAYER_VAL_OFF_SHUFFLE;
193 ERR("AVRCP target DBUS handler callback not registered");
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;
199 if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
201 ret = HAL_AVRCP_ERROR_INVALID_PARAM;
205 loop_status = (gchar *)g_variant_get_string(value, NULL);
206 DBG("Value: %s\n", loop_status);
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;
216 ev.value = BTRC_PLAYER_VAL_OFF_REPEAT;
219 ERR("AVRCP target DBUS handler callback not registered");
221 event_cb(HAL_EV_AVRCP_TG_SET_PLAYER_PROPERTY, (void *)&ev, sizeof(ev));
230 g_variant_unref(value);
231 err = __hal_avrcp_set_error(ret);
232 g_dbus_method_invocation_return_gerror(invocation, err);
236 static const GDBusInterfaceVTable method_table = {
237 __hal_avrcp_agent_method,
242 static GDBusNodeInfo *__hal_avrcp_create_method_node_info
243 (const gchar *introspection_data)
246 GDBusNodeInfo *node_info = NULL;
248 if (introspection_data == NULL)
251 node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
254 ERR("Unable to create node: %s", err->message);
261 static void __bt_hal_avrcp_unregister_object_path(void)
263 GDBusConnection *conn;
265 conn = _bt_hal_get_system_gconn();
267 ERR("conn == NULL, return");
271 if (avrcp_reg_id > 0) {
272 g_dbus_connection_unregister_object(conn, avrcp_reg_id);
277 bt_status_t _bt_hal_dbus_handler_register_media_player(void)
279 GDBusConnection *conn;
282 GDBusNodeInfo *node_info;
284 GVariantBuilder *builder;
286 GError *error = NULL;
290 conn = _bt_hal_get_system_gconn();
292 ERR("_bt_hal_get_system_gconn returned NULL, return");
293 return BT_STATUS_FAIL;
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;
303 avrcp_reg_id = g_dbus_connection_register_object(conn,
304 BT_HAL_MEDIA_OBJECT_PATH,
305 node_info->interfaces[0],
308 g_dbus_node_info_unref(node_info);
310 if (avrcp_reg_id == 0) {
311 ERR("Failed to register: %s", error->message);
312 g_clear_error(&error);
313 return BT_STATUS_FAIL;
316 adapter_path = _bt_hal_get_adapter_path();
318 ERR("Could not get adapter path");
319 return BT_STATUS_FAIL;
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);
328 ERR("Unable to create proxy");
330 ERR("Error: %s", error->message);
331 g_clear_error(&error);
334 return BT_STATUS_FAIL;
337 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
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));
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,
351 g_variant_builder_unref(builder);
352 g_object_unref(proxy);
355 ERR("Call RegisterPlayer Failed");
357 ERR("errCode[%x], message[%s]",
358 error->code, error->message);
359 g_clear_error(&error);
361 return BT_STATUS_FAIL;
364 g_variant_unref(ret);
367 return BT_STATUS_SUCCESS;
370 bt_status_t _bt_hal_dbus_handler_unregister_media_player(void)
372 GDBusConnection *conn;
376 GError *error = NULL;
378 int result = BT_STATUS_SUCCESS;
382 adapter_path = _bt_hal_get_adapter_path();
383 if (adapter_path == NULL) {
384 result = BT_STATUS_FAIL;
388 conn = _bt_hal_get_system_gconn();
391 g_free(adapter_path);
392 result = BT_STATUS_FAIL;
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);
402 ERR("Unable to create proxy");
404 ERR("Error: %s", error->message);
405 g_clear_error(&error);
407 result = BT_STATUS_FAIL;
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,
418 g_object_unref(proxy);
420 ERR("UnregisterPlayer failed");
422 ERR("D-Bus API failure: errCode[%x], message[%s]",
423 error->code, error->message);
424 g_clear_error(&error);
426 result = BT_STATUS_FAIL;
428 g_variant_unref(ret);
431 __bt_hal_avrcp_unregister_object_path();
438 static void __bt_hal_avrcp_tg_connect_cb(
439 GDBusProxy *proxy, GAsyncResult *res, gpointer user_data)
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;
449 reply = g_dbus_proxy_call_finish(proxy, res, &g_error);
450 g_object_unref(proxy);
452 ERR("AVRCP Target Connect Dbus Call Error");
454 ERR("Error: %s\n", g_error->message);
455 g_clear_error(&g_error);
457 result = BT_STATUS_FAIL;
459 g_variant_unref(reply);
461 DBG("Address: %s", address);
464 * If result is success, Remote device connected event will be triggered
465 * automatically from stack, so return from here.
467 if (result == BT_STATUS_SUCCESS)
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;
475 ERR("AVRCP target DBUS handler callback not registered");
477 event_cb(HAL_EV_AVRCP_TG_CONN_STATE, (void *)&ev, sizeof(ev));
483 bt_status_t _bt_hal_dbus_handler_avrcp_tg_connect(bt_bdaddr_t *bd_addr)
485 GDBusConnection *conn;
490 ERR("bd_addr is NULL, return");
491 return BT_STATUS_PARM_INVALID;
494 conn = _bt_hal_get_system_gconn();
496 ERR("_bt_hal_get_system_gconn returned NULL, return");
497 return BT_STATUS_FAIL;
500 address = g_malloc0(BT_HAL_ADDRESS_STRING_SIZE * sizeof(char));
502 ERR("Memory allocation failed");
503 return BT_STATUS_NOMEM;
505 _bt_hal_convert_addr_type_to_string(address, bd_addr->address);
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");
512 return BT_STATUS_FAIL;
515 return BT_STATUS_SUCCESS;
518 static void __bt_avrcp_tg_disconnect_cb(
519 GDBusProxy *proxy, GAsyncResult *res, gpointer user_data)
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;
529 reply = g_dbus_proxy_call_finish(proxy, res, &g_error);
530 g_object_unref(proxy);
532 ERR("AVRCP Target Disconnect Dbus Call Error");
534 ERR("Error: %s\n", g_error->message);
535 g_clear_error(&g_error);
537 result = BT_STATUS_FAIL;
539 g_variant_unref(reply);
542 * If result is success, Remote device disconnected event will be triggered
543 * automatically from stack, so return from here.
545 if (BT_STATUS_FAIL != result) {
546 DBG("AVRCP TG Disconnected for Device: %s", address);
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;
557 ERR("AVRCP Target DBUS handler callback not registered");
559 event_cb(HAL_EV_AVRCP_TG_CONN_STATE, (void *)&ev, sizeof(ev));
565 bt_status_t _bt_hal_dbus_handler_avrcp_tg_disconnect(bt_bdaddr_t *bd_addr)
567 GDBusConnection *conn;
572 ERR("bd_addr is NULL, return");
573 return BT_STATUS_PARM_INVALID;
576 conn = _bt_hal_get_system_gconn();
578 ERR("_bt_hal_get_system_gconn returned NULL, return");
579 return BT_STATUS_FAIL;
582 address = g_malloc0(BT_HAL_ADDRESS_STRING_SIZE * sizeof(char));
584 ERR("Memory allocation failed");
585 return BT_STATUS_NOMEM;
587 _bt_hal_convert_addr_type_to_string(address, bd_addr->address);
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;
596 return BT_STATUS_SUCCESS;
600 static gboolean __hal_media_emit_property_changed(GDBusConnection *connection,
601 const char *path, const char *interface, const char *name,
602 const GVariant *variant)
604 GVariantBuilder *builder = NULL;
605 GVariantBuilder *invalid_builder = NULL;
606 GError *error = NULL;
608 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
609 g_variant_builder_add(builder, "{sv}", name, variant);
611 invalid_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
613 g_dbus_connection_emit_signal(connection, NULL, path,
614 DBUS_INTERFACE_PROPERTIES,
616 g_variant_new("(sa{sv}as)",
617 interface, builder, invalid_builder),
619 g_variant_builder_unref(builder);
620 g_variant_builder_unref(invalid_builder);
622 ERR("Could not Emit PropertiesChanged Signal: errCode[%x], message[%s]",
623 error->code, error->message);
624 g_clear_error(&error);
631 bt_status_t _bt_hal_dbus_handler_avrcp_tg_play_status_changed(btrc_play_status_t play_status)
633 GDBusConnection *conn;
637 conn = _bt_hal_get_system_gconn();
639 ERR("_bt_hal_get_system_gconn returned NULL, return");
640 return BT_STATUS_FAIL;
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;
651 return BT_STATUS_SUCCESS;
654 bt_status_t _bt_hal_dbus_handler_avrcp_tg_play_pos_changed(uint32_t song_pos)
656 GDBusConnection *conn;
660 conn = _bt_hal_get_system_gconn();
662 ERR("_bt_hal_get_system_gconn returned NULL, return");
663 return BT_STATUS_FAIL;
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;
674 return BT_STATUS_SUCCESS;
677 bt_status_t _bt_hal_dbus_handler_avrcp_tg_app_setting_changed(btrc_player_settings_t *player_setting)
679 GDBusConnection *conn;
680 char *property_name = NULL;
686 conn = _bt_hal_get_system_gconn();
688 ERR("_bt_hal_get_system_gconn returned NULL, return");
689 return BT_STATUS_FAIL;
692 for (i = 0; i < player_setting->num_attr; i++) {
693 property_name = NULL;
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]));
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);
707 variant = g_variant_new_boolean(TRUE);
709 case BTRC_PLAYER_ATTR_SCAN:
710 case BTRC_PLAYER_ATTR_EQUALIZER:
712 ERR("Unsupported attr type: %d", player_setting->attr_ids[i]);
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;
726 return BT_STATUS_SUCCESS;
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)
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;
744 ERR("p_attrs is NULL");
745 return BT_STATUS_FAIL;
748 conn = _bt_hal_get_system_gconn();;
750 ERR("_bt_hal_get_system_gconn returned NULL, return");
751 return BT_STATUS_FAIL;
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}"));
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));
765 case BTRC_MEDIA_ATTR_ID_ARTIST: {
766 GVariant *children[1];
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));
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));
779 case BTRC_MEDIA_ATTR_ID_TRACK_NUM: {
780 uint32_t cur_track = 0;
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));
788 case BTRC_MEDIA_ATTR_ID_NUM_TRACKS: {
789 uint32_t num_tracks = 0;
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));
797 case BTRC_MEDIA_ATTR_ID_GENRE: {
798 GVariant *children[1];
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));
806 case BTRC_MEDIA_ATTR_ID_PLAYING_TIME: {
807 uint32_t duration = 0;
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));
816 INFO("Unknown attribute Id: %d", p_attrs[i].attr_id);
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,
825 g_variant_new("(sa{sv}as)",
826 interface, builder, invalid_builder),
828 g_variant_builder_unref(inner_builder);
829 g_variant_builder_unref(builder);
830 g_variant_builder_unref(invalid_builder);
833 ERR("D-Bus API failure: errCode[%x], message[%s]",
834 error->code, error->message);
835 g_clear_error(&error);
837 return BT_STATUS_FAIL;
842 return BT_STATUS_SUCCESS;
845 /* To send stack event to hal-avrcp-tg handler */
846 void _bt_hal_register_avrcp_tg_dbus_handler_cb(handle_stack_msg cb)
851 /* To send stack event to hal-avrcp-tg handler */
852 void _bt_hal_unregister_avrcp_tg_dbus_handler_cb()