./src/bt-hal-av-dbus-handler.c
./src/bt-hal-a2dp-sink.c
./src/bt-hal-a2dp-sink-dbus-handler.c
+./src/bt-hal-avrcp-tg.c
+./src/bt-hal-avrcp-tg-dbus-handler.c
./src/bt-hal-avrcp-ctrl.c
./src/bt-hal-avrcp-ctrl-dbus-handler.c
./src/bt-hal-hf.c
uint8_t p_str[BTRC_MAX_ATTR_STR_LEN];
} btrc_br_folder_name_t;
+#ifdef TIZEN_BT_HAL
+/** Callback for the target connection state */
+typedef void (* btrc_tg_connection_state_callback) (bt_bdaddr_t *bd_addr, btrc_connection_state_t state);
+#endif
+
/** Callback for the controller's supported feautres */
typedef void (* btrc_remote_features_callback)(bt_bdaddr_t *bd_addr,
btrc_remote_features_t features);
typedef void (* btrc_add_to_now_playing_callback) (uint8_t scope,
uint8_t* uid, uint16_t uid_counter, bt_bdaddr_t *bd_addr);
-/** Callback for set addressed player response on TG **/
-typedef void (* btrc_set_addressed_player_callback) (uint16_t player_id, bt_bdaddr_t *bd_addr);
-
-/** Callback for set browsed player response on TG **/
-typedef void (* btrc_set_browsed_player_callback) (uint16_t player_id, bt_bdaddr_t *bd_addr);
-
-/** Callback for get folder items on TG
-** num_attr: specifies the number of attributes requested in p_attr_ids
-*/
-typedef void (* btrc_get_folder_items_callback) (uint8_t scope, uint32_t start_item,
- uint32_t end_item, uint8_t num_attr, uint32_t *p_attr_ids, bt_bdaddr_t *bd_addr);
-
-/** Callback for changing browsed path on TG **/
-typedef void (* btrc_change_path_callback) (uint8_t direction,
- uint8_t* folder_uid, bt_bdaddr_t *bd_addr);
-
-/** Callback to fetch the get item attributes of the media item
-** num_attr: specifies the number of attributes requested in p_attrs
-*/
-typedef void (* btrc_get_item_attr_callback) (uint8_t scope, uint8_t* uid, uint16_t uid_counter,
- uint8_t num_attr, btrc_media_attr_t *p_attrs, bt_bdaddr_t *bd_addr);
-
-/** Callback for play request for the media item indicated by an identifier */
-typedef void (* btrc_play_item_callback) (uint8_t scope,
- uint16_t uid_counter, uint8_t* uid, bt_bdaddr_t *bd_addr);
-
-/** Callback to fetch total number of items from a folder **/
-typedef void (* btrc_get_total_num_of_items_callback) (uint8_t scope, bt_bdaddr_t *bd_addr);
-
-/** Callback for conducting recursive search on a current browsed path for a specified string */
-typedef void (* btrc_search_callback) (uint16_t charset_id,
- uint16_t str_len, uint8_t* p_str, bt_bdaddr_t *bd_addr);
-
-/** Callback to add a specified media item indicated by an identifier to now playing queue. */
-typedef void (* btrc_add_to_now_playing_callback) (uint8_t scope,
- uint8_t* uid, uint16_t uid_counter, bt_bdaddr_t *bd_addr);
-
-/** Callback for set addressed player response on TG **/
-typedef void (* btrc_set_addressed_player_callback) (uint16_t player_id, bt_bdaddr_t *bd_addr);
-
-/** Callback for set browsed player response on TG **/
-typedef void (* btrc_set_browsed_player_callback) (uint16_t player_id, bt_bdaddr_t *bd_addr);
-
-/** Callback for get folder items on TG
-** num_attr: specifies the number of attributes requested in p_attr_ids
-*/
-typedef void (* btrc_get_folder_items_callback) (uint8_t scope, uint32_t start_item,
- uint32_t end_item, uint8_t num_attr, uint32_t *p_attr_ids, bt_bdaddr_t *bd_addr);
-
-/** Callback for changing browsed path on TG **/
-typedef void (* btrc_change_path_callback) (uint8_t direction,
- uint8_t* folder_uid, bt_bdaddr_t *bd_addr);
-
-/** Callback to fetch the get item attributes of the media item
-** num_attr: specifies the number of attributes requested in p_attrs
-*/
-typedef void (* btrc_get_item_attr_callback) (uint8_t scope, uint8_t* uid, uint16_t uid_counter,
- uint8_t num_attr, btrc_media_attr_t *p_attrs, bt_bdaddr_t *bd_addr);
-
-/** Callback for play request for the media item indicated by an identifier */
-typedef void (* btrc_play_item_callback) (uint8_t scope,
- uint16_t uid_counter, uint8_t* uid, bt_bdaddr_t *bd_addr);
-
-/** Callback to fetch total number of items from a folder **/
-typedef void (* btrc_get_total_num_of_items_callback) (uint8_t scope, bt_bdaddr_t *bd_addr);
-
-/** Callback for conducting recursive search on a current browsed path for a specified string */
-typedef void (* btrc_search_callback) (uint16_t charset_id,
- uint16_t str_len, uint8_t* p_str, bt_bdaddr_t *bd_addr);
-
-/** Callback to add a specified media item indicated by an identifier to now playing queue. */
-typedef void (* btrc_add_to_now_playing_callback) (uint8_t scope,
- uint8_t* uid, uint16_t uid_counter, bt_bdaddr_t *bd_addr);
-
/** BT-RC Target callback structure. */
typedef struct {
/** set to sizeof(BtRcCallbacks) */
size_t size;
+#ifdef TIZEN_BT_HAL
+ btrc_tg_connection_state_callback connection_state_cb;
+#endif
btrc_remote_features_callback remote_features_cb;
btrc_get_play_status_callback get_play_status_cb;
btrc_list_player_app_attr_callback list_player_app_attr_cb;
*/
bt_status_t (*init)( btrc_callbacks_t* callbacks );
+#ifdef TIZEN_BT_HAL
+ /** connect to AVRCP controller device */
+ bt_status_t (*connect)( bt_bdaddr_t *bd_addr );
+
+ /** dis-connect from AVRCP controller device */
+ bt_status_t (*disconnect)( bt_bdaddr_t *bd_addr );
+#endif
+
/** Respose to GetPlayStatus request. Contains the current
** 1. Play status
** 2. Song duration/length
uint8_t status;
} __attribute__((packed));
+/* AVRCP TG events */
+#ifdef TIZEN_BT_HAL
+#define HAL_EV_AVRCP_TG_CONN_STATE 0xA2
+
+#define HAL_AVRCP_TG_STATE_DISCONNECTED 0x00
+#define HAL_AVRCP_TG_STATE_CONNECTED 0x01
+struct hal_ev_avrcp_tg_conn_state {
+ uint8_t bdaddr[6];
+ uint8_t state;
+} __attribute__((packed));
+#endif /* TIZEN_BT_HAL */
+
+#define HAL_EV_AVRCP_TG_SET_PLAYER_PROPERTY 0xA3
+
+#define HAL_AVRCP_TG_PLAYER_PROP_EQUALIZER 0x00
+#define HAL_AVRCP_TG_PLAYER_PROP_REPEAT 0x01
+#define HAL_AVRCP_TG_PLAYER_PROP_SHUFFLE 0x02
+#define HAL_AVRCP_TG_PLAYER_PROP_SCAN 0x03
+struct hal_ev_avrcp_tg_player_property {
+ uint8_t prop_type;
+ uint8_t value;
+} __attribute__((packed));
+
#endif //_BT_HAL_MSG_H_
DBG("+");
- manager_proxy = _bt_get_manager_proxy();
+ manager_proxy = _bt_hal_get_manager_proxy();
if (manager_proxy == NULL)
return BT_STATUS_FAIL;
--- /dev/null
+/*
+ * Bluetooth-frwk
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Atul Kumar Rai <a.rai@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus.h>
+#include <glib.h>
+#include <gio/gio.h>
+#include <dlog.h>
+#include <vconf.h>
+
+#include "bt-hal-dbus-common-utils.h"
+#include "bt-hal-internal.h"
+#include "bt-hal-avrcp-tg-dbus-handler.h"
+
+#define HAL_ERROR_INTERNAL "InternalError"
+#define HAL_ERROR_INVALID_PARAM "InvalidParameters"
+#define HAL_ERROR_INVALID_INTERFACE "InvalidInterface"
+
+#define BT_HAL_MEDIA_OBJECT_PATH "/Musicplayer"
+#define BT_HAL_MEDIA_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
+
+typedef enum {
+ HAL_AVRCP_ERROR_NONE,
+ HAL_AVRCP_ERROR_INTERNAL,
+ HAL_AVRCP_ERROR_INVALID_PARAM,
+ HAL_AVRCP_ERROR_NOT_SUPPORTED,
+ HAL_AVRCP_ERROR_INVALID_INTERFACE
+} hal_avrcp_error_t;
+
+static handle_stack_msg event_cb = NULL;
+
+static guint avrcp_reg_id = 0;
+
+/* Introspection data exposed from bt-service */
+static const gchar hal_avrcp_tg_introspection_xml[] =
+"<node name='/'>"
+" <interface name='org.freedesktop.DBus.Properties'>"
+" <method name='Set'>"
+" <arg type='s' name='interface' direction='in'/>"
+" <arg type='s' name='property' direction='in'/>"
+" <arg type='v' name='value' direction='in'/>"
+" </method>"
+" </interface>"
+"</node>";
+
+static const char *__repeat_val_to_str(btrc_player_repeat_val_t repeat_val)
+{
+ switch (repeat_val) {
+ case BTRC_PLAYER_VAL_OFF_REPEAT:
+ return "None";
+ case BTRC_PLAYER_VAL_SINGLE_REPEAT:
+ return "Track";
+ case BTRC_PLAYER_VAL_ALL_REPEAT:
+ return "Playlist";
+ case BTRC_PLAYER_VAL_GROUP_REPEAT:
+ return "Playlist";
+ default:
+ ERR("Invalid repeat value: %d", repeat_val);
+ return "";
+ }
+}
+
+#if 0
+static const char *__shuffle_val_to_str(btrc_player_shuffle_val_t shuffle_val)
+{
+ switch (shuffle_val) {
+ case BTRC_PLAYER_VAL_OFF_SHUFFLE:
+ return "off";
+ case BTRC_PLAYER_VAL_ALL_SHUFFLE:
+ return "alltracks";
+ case BTRC_PLAYER_VAL_GROUP_SHUFFLE:
+ return "group";
+ default:
+ ERR("Invalid shuffle value: %d", shuffle_val);
+ return "";
+ }
+}
+#endif
+
+static const char *__play_status_to_str(btrc_play_status_t play_status)
+{
+ switch (play_status) {
+ case BTRC_PLAYSTATE_STOPPED:
+ return "stopped";
+ case BTRC_PLAYSTATE_PLAYING:
+ return "playing";
+ case BTRC_PLAYSTATE_PAUSED:
+ return "paused";
+ case BTRC_PLAYSTATE_FWD_SEEK:
+ return "forward-seek";
+ case BTRC_PLAYSTATE_REV_SEEK:
+ return "reverse-seek";
+ case BTRC_PLAYSTATE_ERROR:
+ return "error";
+ default:
+ ERR("Invalid play status: %d", play_status);
+ return "";
+ }
+}
+
+static GQuark __hal_avrcp_error_quark(void)
+{
+ static GQuark quark = 0;
+
+ if (!quark)
+ quark = g_quark_from_static_string("bt-avrcp");
+
+ return quark;
+}
+
+static GError *__hal_avrcp_set_error(hal_avrcp_error_t error)
+{
+ ERR("error[%d]\n", error);
+
+ switch (error) {
+ case HAL_AVRCP_ERROR_INVALID_PARAM:
+ return g_error_new(__hal_avrcp_error_quark(),
+ error, HAL_ERROR_INVALID_PARAM);
+ case HAL_AVRCP_ERROR_INVALID_INTERFACE:
+ return g_error_new(__hal_avrcp_error_quark(),
+ error, HAL_ERROR_INVALID_INTERFACE);
+ case HAL_AVRCP_ERROR_INTERNAL:
+ default:
+ return g_error_new(__hal_avrcp_error_quark(),
+ error, HAL_ERROR_INTERNAL);
+ }
+}
+
+static void __hal_avrcp_agent_method(GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ int ret = HAL_AVRCP_ERROR_NONE;
+ GError *err = NULL;
+ gboolean shuffle_status;
+ gchar *interface = NULL;
+ gchar *property = NULL;
+ gchar *loop_status = NULL;
+ GVariant *value = NULL;
+
+ DBG("+");
+ INFO("method %s", method_name);
+ INFO("object_path %s", object_path);
+
+ if (g_strcmp0(method_name, "Set") == 0) {
+ g_variant_get(parameters, "(&s&sv)",
+ &interface, &property, &value);
+
+ if (g_strcmp0(interface, BT_HAL_MEDIA_PLAYER_INTERFACE) != 0) {
+ ret = HAL_AVRCP_ERROR_INVALID_INTERFACE;
+ goto fail;
+ }
+ }
+
+ if (value == NULL) {
+ ERR("value is NULL");
+ ret = HAL_AVRCP_ERROR_INVALID_PARAM;
+ goto fail;
+ }
+
+ DBG("Property: %s\n", property);
+ if (g_strcmp0(property, "Shuffle") == 0) {
+ struct hal_ev_avrcp_tg_player_property ev;
+
+ if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
+ ERR("Error");
+ ret = HAL_AVRCP_ERROR_INVALID_PARAM;
+ goto fail;
+ }
+
+ /* Prepare to send AVRCP player property event */
+ memset(&ev, 0, sizeof(ev));
+ shuffle_status = g_variant_get_boolean(value);
+ DBG("Value: %s\n", shuffle_status ? "TRUE" : "FALSE");
+
+ ev.prop_type = HAL_AVRCP_TG_PLAYER_PROP_SHUFFLE;
+ if (shuffle_status)
+ ev.value = BTRC_PLAYER_VAL_ALL_SHUFFLE;
+ else
+ ev.value = BTRC_PLAYER_VAL_OFF_SHUFFLE;
+
+ if (!event_cb)
+ ERR("AVRCP target DBUS handler callback not registered");
+ else
+ event_cb(HAL_EV_AVRCP_TG_SET_PLAYER_PROPERTY, (void *)&ev, sizeof(ev));
+ } else if (g_strcmp0(property, "LoopStatus") == 0) {
+ struct hal_ev_avrcp_tg_player_property ev;
+
+ if (!g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
+ ERR("Error");
+ ret = HAL_AVRCP_ERROR_INVALID_PARAM;
+ goto fail;
+ }
+
+ loop_status = (gchar *)g_variant_get_string(value, NULL);
+ DBG("Value: %s\n", loop_status);
+
+ /* Prepare to send AVRCP player property event */
+ memset(&ev, 0, sizeof(ev));
+ ev.prop_type = HAL_AVRCP_TG_PLAYER_PROP_REPEAT;
+ if (g_strcmp0(loop_status, "Track") == 0)
+ ev.value = BTRC_PLAYER_VAL_SINGLE_REPEAT;
+ else if (g_strcmp0(loop_status, "Playlist") == 0)
+ ev.value = BTRC_PLAYER_VAL_ALL_REPEAT;
+ else
+ ev.value = BTRC_PLAYER_VAL_OFF_REPEAT;
+
+ if (!event_cb)
+ ERR("AVRCP target DBUS handler callback not registered");
+ else
+ event_cb(HAL_EV_AVRCP_TG_SET_PLAYER_PROPERTY, (void *)&ev, sizeof(ev));
+
+ }
+
+ DBG("-");
+ return;
+
+fail:
+ if (value)
+ g_variant_unref(value);
+ err = __hal_avrcp_set_error(ret);
+ g_dbus_method_invocation_return_gerror(invocation, err);
+ g_clear_error(&err);
+}
+
+static const GDBusInterfaceVTable method_table = {
+ __hal_avrcp_agent_method,
+ NULL,
+ NULL,
+};
+
+static GDBusNodeInfo *__hal_avrcp_create_method_node_info
+ (const gchar *introspection_data)
+{
+ GError *err = NULL;
+ GDBusNodeInfo *node_info = NULL;
+
+ if (introspection_data == NULL)
+ return NULL;
+
+ node_info = g_dbus_node_info_new_for_xml(introspection_data, &err);
+
+ if (err) {
+ ERR("Unable to create node: %s", err->message);
+ g_clear_error(&err);
+ }
+
+ return node_info;
+}
+
+static void __bt_hal_avrcp_unregister_object_path(void)
+{
+ GDBusConnection *conn;
+
+ conn = _bt_get_system_gconn();
+ if (conn == NULL) {
+ ERR("conn == NULL, return");
+ return;
+ }
+
+ if (avrcp_reg_id > 0) {
+ g_dbus_connection_unregister_object(conn, avrcp_reg_id);
+ avrcp_reg_id = 0;
+ }
+}
+
+bt_status_t _bt_hal_dbus_handler_register_media_player(void)
+{
+ GDBusConnection *conn;
+ gchar *adapter_path;
+ gchar *path;
+ GDBusNodeInfo *node_info;
+ GDBusProxy *proxy;
+ GVariantBuilder *builder;
+ GVariant *ret;
+ GError *error = NULL;
+
+ DBG("+");
+
+ conn = _bt_get_system_gconn();
+ if(!conn) {
+ ERR("_bt_get_system_gconn returned NULL, return");
+ return BT_STATUS_FAIL;
+ }
+
+ node_info = __hal_avrcp_create_method_node_info(
+ hal_avrcp_tg_introspection_xml);
+ if (node_info == NULL) {
+ ERR("__hal_avrcp_create_method_node_info failed");
+ return BT_STATUS_FAIL;
+ }
+
+ avrcp_reg_id = g_dbus_connection_register_object(conn,
+ BT_HAL_MEDIA_OBJECT_PATH,
+ node_info->interfaces[0],
+ &method_table,
+ NULL, NULL, &error);
+ g_dbus_node_info_unref(node_info);
+
+ if (avrcp_reg_id == 0) {
+ ERR("Failed to register: %s", error->message);
+ g_clear_error(&error);
+ return BT_STATUS_FAIL;
+ }
+
+ adapter_path = _bt_hal_get_adapter_path();
+ if (!adapter_path) {
+ ERR("Could not get adapter path");
+ return BT_STATUS_FAIL;
+ }
+
+ proxy = g_dbus_proxy_new_sync(conn,
+ G_DBUS_PROXY_FLAGS_NONE, NULL,
+ BT_HAL_BLUEZ_NAME, adapter_path,
+ BT_HAL_MEDIA_INTERFACE, NULL, &error);
+ g_free(adapter_path);
+ if (proxy == NULL) {
+ ERR("Unable to create proxy");
+ if (error) {
+ ERR("Error: %s", error->message);
+ g_clear_error(&error);
+ }
+
+ return BT_STATUS_FAIL;
+ }
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+
+ g_variant_builder_add(builder, "{sv}", "LoopStatus",
+ g_variant_new("s", __repeat_val_to_str(BTRC_PLAYER_VAL_OFF_REPEAT)));
+ g_variant_builder_add(builder, "{sv}", "Shuffle", g_variant_new("b", FALSE));
+ g_variant_builder_add(builder, "{sv}", "PlaybackStatus",
+ g_variant_new("s", __play_status_to_str(BTRC_PLAYSTATE_STOPPED)));
+ g_variant_builder_add(builder, "{sv}", "Position", g_variant_new("u", 0));
+
+ path = g_strdup(BT_HAL_MEDIA_OBJECT_PATH);
+ ret = g_dbus_proxy_call_sync(proxy, "RegisterPlayer",
+ g_variant_new("(oa{sv})", path, builder),
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL, &error);
+ g_variant_builder_unref(builder);
+ g_object_unref(proxy);
+ g_free(path);
+ if (ret == NULL) {
+ ERR("Call RegisterPlayer Failed");
+ if (error) {
+ ERR("errCode[%x], message[%s]",
+ error->code, error->message);
+ g_clear_error(&error);
+ }
+ return BT_STATUS_FAIL;
+ }
+
+ g_variant_unref(ret);
+ DBG("-");
+
+ return BT_STATUS_SUCCESS;
+}
+
+bt_status_t _bt_hal_dbus_handler_unregister_media_player(void)
+{
+ GDBusConnection *conn;
+ GDBusProxy *proxy;
+ gchar *adapter_path;
+ GVariant *ret;
+ GError *error = NULL;
+ gchar *path;
+ int result = BT_STATUS_SUCCESS;
+
+ DBG("+");
+
+ adapter_path = _bt_hal_get_adapter_path();
+ if (adapter_path == NULL) {
+ result = BT_STATUS_FAIL;
+ goto FAIL;
+ }
+
+ conn = _bt_get_system_gconn();
+ if (conn == NULL) {
+ ERR("conn is NULL");
+ g_free(adapter_path);
+ result = BT_STATUS_FAIL;
+ goto FAIL;
+ }
+
+ proxy = g_dbus_proxy_new_sync(conn,
+ G_DBUS_PROXY_FLAGS_NONE, NULL,
+ BT_HAL_BLUEZ_NAME, adapter_path,
+ BT_HAL_MEDIA_INTERFACE, NULL, &error);
+ g_free(adapter_path);
+ if (proxy == NULL) {
+ ERR("Unable to create proxy");
+ if (error) {
+ ERR("Error: %s", error->message);
+ g_clear_error(&error);
+ }
+ result = BT_STATUS_FAIL;
+ goto FAIL;
+ }
+
+ path = g_strdup(BT_HAL_MEDIA_OBJECT_PATH);
+ DBG("path is [%s]", path);
+ ret = g_dbus_proxy_call_sync(proxy, "UnregisterPlayer",
+ g_variant_new("(o)", path),
+ G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL, &error);
+ g_free(path);
+ g_object_unref(proxy);
+ if (ret == NULL) {
+ ERR("UnregisterPlayer failed");
+ if (error) {
+ ERR("D-Bus API failure: errCode[%x], message[%s]",
+ error->code, error->message);
+ g_clear_error(&error);
+ }
+ result = BT_STATUS_FAIL;
+ }
+ g_variant_unref(ret);
+
+FAIL:
+ __bt_hal_avrcp_unregister_object_path();
+
+ DBG("-");
+ return result;
+}
+
+#ifdef TIZEN_BT_HAL
+static void __bt_hal_avrcp_tg_connect_cb(
+ GDBusProxy *proxy, GAsyncResult *res, gpointer user_data)
+{
+ struct hal_ev_avrcp_tg_conn_state ev;
+ char *address = user_data;
+ int result = BT_STATUS_SUCCESS;
+ GVariant *reply = NULL;
+ GError *g_error = NULL;
+
+ DBG("+");
+
+ reply = g_dbus_proxy_call_finish(proxy, res, &g_error);
+ g_object_unref(proxy);
+ if (reply == NULL) {
+ ERR("AVRCP Target Connect Dbus Call Error");
+ if (g_error) {
+ ERR("Error: %s\n", g_error->message);
+ g_clear_error(&g_error);
+ }
+ result = BT_STATUS_FAIL;
+ }
+ g_variant_unref(reply);
+
+ DBG("Address: %s", address);
+
+ /*
+ * If result is success, Remote device connected event will be triggered
+ * automatically from stack, so return from here.
+ */
+ if (result == BT_STATUS_SUCCESS)
+ goto done;
+
+ /* Prepare to send AVRCP Target connection state event */
+ memset(&ev, 0, sizeof(ev));
+ _bt_convert_addr_string_to_type(ev.bdaddr, address);
+ ev.state = HAL_AVRCP_TG_STATE_DISCONNECTED;
+ if (!event_cb)
+ ERR("AVRCP target DBUS handler callback not registered");
+ else
+ event_cb(HAL_EV_AVRCP_TG_CONN_STATE, (void *)&ev, sizeof(ev));
+done:
+ g_free(address);
+ DBG("-");
+}
+
+bt_status_t _bt_hal_dbus_handler_avrcp_tg_connect(bt_bdaddr_t *bd_addr)
+{
+ GDBusConnection *conn;
+ char *address;
+ int ret;
+
+ if(!bd_addr) {
+ ERR("bd_addr is NULL, return");
+ return BT_STATUS_PARM_INVALID;
+ }
+
+ conn = _bt_get_system_gconn();
+ if(!conn) {
+ ERR("_bt_get_system_gconn returned NULL, return");
+ return BT_STATUS_FAIL;
+ }
+
+ address = g_malloc0(BT_HAL_ADDRESS_STRING_SIZE * sizeof(char));
+ if (!address) {
+ ERR("Memory allocation failed");
+ return BT_STATUS_NOMEM;
+ }
+ _bt_convert_addr_type_to_string(address, bd_addr->address);
+
+ ret = _bt_connect_profile(address, AVRCP_CTRL_UUID,
+ __bt_hal_avrcp_tg_connect_cb, address);
+ if (ret != BT_HAL_ERROR_NONE) {
+ ERR("_bt_connect_profile(AVRCP Controller) Error");
+ return BT_STATUS_FAIL;
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+static void __bt_avrcp_tg_disconnect_cb(
+ GDBusProxy *proxy, GAsyncResult *res, gpointer user_data)
+{
+ struct hal_ev_avrcp_tg_conn_state ev;
+ char *address = user_data;
+ int result = BT_STATUS_SUCCESS;
+ GError *g_error = NULL;
+ GVariant *reply = NULL;
+
+ DBG("+");
+
+ reply = g_dbus_proxy_call_finish(proxy, res, &g_error);
+ g_object_unref(proxy);
+ if (reply == NULL) {
+ ERR("AVRCP Target Disconnect Dbus Call Error");
+ if (g_error) {
+ ERR("Error: %s\n", g_error->message);
+ g_clear_error(&g_error);
+ }
+ result = BT_STATUS_FAIL;
+ }
+ g_variant_unref(reply);
+
+ /*
+ * If result is success, Remote device disconnected event will be triggered
+ * automatically from stack, so return from here.
+ */
+ if (BT_STATUS_FAIL != result) {
+ DBG("AVRCP TG Disconnected for Device: %s", address);
+ g_free(address);
+ return;
+ }
+
+ DBG("AVRCP TG Disconnect failed for Device: %s", address);
+ /* Prepare to send AVRCP Target disconnection state event */
+ memset(&ev, 0, sizeof(ev));
+ _bt_convert_addr_string_to_type(ev.bdaddr, address);
+ ev.state = HAL_AVRCP_TG_STATE_CONNECTED;
+ if (!event_cb)
+ ERR("AVRCP Target DBUS handler callback not registered");
+ else
+ event_cb(HAL_EV_AVRCP_TG_CONN_STATE, (void *)&ev, sizeof(ev));
+
+ g_free(address);
+ DBG("-");
+}
+
+bt_status_t _bt_hal_dbus_handler_avrcp_tg_disconnect(bt_bdaddr_t *bd_addr)
+{
+ GDBusConnection *conn;
+ char *address;
+ int ret;
+
+ if(!bd_addr) {
+ ERR("bd_addr is NULL, return");
+ return BT_STATUS_PARM_INVALID;
+ }
+
+ conn = _bt_get_system_gconn();
+ if(!conn) {
+ ERR("_bt_get_system_gconn returned NULL, return");
+ return BT_STATUS_FAIL;
+ }
+
+ address = g_malloc0(BT_HAL_ADDRESS_STRING_SIZE * sizeof(char));
+ if (!address) {
+ ERR("Memory allocation failed");
+ return BT_STATUS_NOMEM;
+ }
+ _bt_convert_addr_type_to_string(address, bd_addr->address);
+
+ ret = _bt_disconnect_profile(address, AVRCP_TARGET_UUID,
+ __bt_avrcp_tg_disconnect_cb, address);
+ if (ret != BT_HAL_ERROR_NONE) {
+ ERR("_bt_connect_profile(AVRCP Target) Error");
+ return BT_STATUS_FAIL;
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+#endif
+
+static gboolean __hal_media_emit_property_changed(GDBusConnection *connection,
+ const char *path, const char *interface, const char *name,
+ const GVariant *variant)
+{
+ GVariantBuilder *builder = NULL;
+ GVariantBuilder *invalid_builder = NULL;
+ GError *error = NULL;
+
+ builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+ g_variant_builder_add(builder, "{sv}", name, variant);
+
+ invalid_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
+
+ g_dbus_connection_emit_signal(connection, NULL, path,
+ DBUS_INTERFACE_PROPERTIES,
+ "PropertiesChanged",
+ g_variant_new("(sa{sv}as)",
+ interface, builder, invalid_builder),
+ &error);
+ g_variant_builder_unref(builder);
+ g_variant_builder_unref(invalid_builder);
+ if (error) {
+ ERR("Could not Emit PropertiesChanged Signal: errCode[%x], message[%s]",
+ error->code, error->message);
+ g_clear_error(&error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+bt_status_t _bt_hal_dbus_handler_avrcp_tg_play_status_changed(btrc_play_status_t play_status)
+{
+ GDBusConnection *conn;
+
+ DBG("+");
+
+ conn = _bt_get_system_gconn();
+ if(!conn) {
+ ERR("_bt_get_system_gconn returned NULL, return");
+ return BT_STATUS_FAIL;
+ }
+
+ if (!__hal_media_emit_property_changed(conn, BT_HAL_MEDIA_OBJECT_PATH,
+ BT_HAL_MEDIA_PLAYER_INTERFACE, "PlaybackStatus",
+ g_variant_new_string(__play_status_to_str(play_status)))) {
+ ERR("Error sending the PropertyChanged signal");
+ return BT_STATUS_FAIL;
+ }
+
+ DBG("-");
+ return BT_STATUS_SUCCESS;
+}
+
+bt_status_t _bt_hal_dbus_handler_avrcp_tg_play_pos_changed(uint32_t song_pos)
+{
+ GDBusConnection *conn;
+
+ DBG("+");
+
+ conn = _bt_get_system_gconn();
+ if(!conn) {
+ ERR("_bt_get_system_gconn returned NULL, return");
+ return BT_STATUS_FAIL;
+ }
+
+ if (!__hal_media_emit_property_changed(conn, BT_HAL_MEDIA_OBJECT_PATH,
+ BT_HAL_MEDIA_PLAYER_INTERFACE, "Position",
+ g_variant_new_uint32(song_pos))) {
+ ERR("Error sending the PropertyChanged signal");
+ return BT_STATUS_FAIL;
+ }
+
+ DBG("-");
+ return BT_STATUS_SUCCESS;
+}
+
+bt_status_t _bt_hal_dbus_handler_avrcp_tg_app_setting_changed(btrc_player_settings_t *player_setting)
+{
+ GDBusConnection *conn;
+ char *property_name = NULL;
+ GVariant *variant;
+ int i;
+
+ DBG("+");
+
+ conn = _bt_get_system_gconn();
+ if(!conn) {
+ ERR("_bt_get_system_gconn returned NULL, return");
+ return BT_STATUS_FAIL;
+ }
+
+ for (i = 0; i < player_setting->num_attr; i++) {
+ property_name = NULL;
+ variant = NULL;
+
+ switch (player_setting->attr_ids[i]) {
+ case BTRC_PLAYER_ATTR_REPEAT:
+ property_name = "LoopStatus";
+ variant = g_variant_new_string(
+ __repeat_val_to_str(player_setting->attr_values[i]));
+ break;
+ case BTRC_PLAYER_ATTR_SHUFFLE:
+ property_name = "Shuffle";
+ if (BTRC_PLAYER_VAL_OFF_SHUFFLE == player_setting->attr_values[i])
+ variant = g_variant_new_boolean(FALSE);
+ else
+ variant = g_variant_new_boolean(TRUE);
+ break;
+ case BTRC_PLAYER_ATTR_SCAN:
+ case BTRC_PLAYER_ATTR_EQUALIZER:
+ default:
+ ERR("Unsupported attr type: %d", player_setting->attr_ids[i]);
+ }
+
+ if (!property_name)
+ continue;
+
+ if (!__hal_media_emit_property_changed(conn, BT_HAL_MEDIA_OBJECT_PATH,
+ BT_HAL_MEDIA_PLAYER_INTERFACE, property_name, variant)) {
+ ERR("Error sending the PropertyChanged signal");
+ return BT_STATUS_FAIL;
+ }
+ }
+
+ DBG("-");
+ return BT_STATUS_SUCCESS;
+}
+
+bt_status_t _bt_hal_dbus_handler_avrcp_tg_set_track_info(
+ uint8_t num_attr, btrc_element_attr_val_t *p_attrs)
+{
+ GDBusConnection *conn;
+ GError *error = NULL;
+ GVariantBuilder *invalid_builder = NULL;
+ GVariantBuilder *builder = NULL;
+ GVariantBuilder *inner_builder = NULL;
+ char *interface = BT_HAL_MEDIA_PLAYER_INTERFACE;
+ gboolean ret;
+ int i;
+
+ DBG("+");
+
+ if (!p_attrs) {
+ ERR("p_attrs is NULL");
+ return BT_STATUS_FAIL;
+ }
+
+ conn = _bt_get_system_gconn();;
+ if(!conn) {
+ ERR("_bt_get_system_gconn returned NULL, return");
+ return BT_STATUS_FAIL;
+ }
+
+ invalid_builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
+ builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+ inner_builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+
+ for (i = 0; i < num_attr; i++) {
+ switch (p_attrs[i].attr_id) {
+ case BTRC_MEDIA_ATTR_ID_TITLE:
+ INFO("Title: %s", p_attrs[i].text);
+ g_variant_builder_add(inner_builder, "{sv}",
+ "xesam:title", g_variant_new_string((const char *)p_attrs[i].text));
+ break;
+ case BTRC_MEDIA_ATTR_ID_ARTIST: {
+ GVariant *children[1];
+
+ INFO("Artist: %s", p_attrs[i].text);
+ children[0] = g_variant_new_string((const char *)p_attrs[i].text);
+ g_variant_builder_add(inner_builder, "{sv}", "xesam:artist",
+ g_variant_new_array(G_VARIANT_TYPE_STRING, children, 1));
+ break;
+ }
+ case BTRC_MEDIA_ATTR_ID_ALBUM:
+ INFO("Album: %s", p_attrs[i].text);
+ g_variant_builder_add(inner_builder, "{sv}",
+ "xesam:album", g_variant_new_string((const char *)p_attrs[i].text));
+ break;
+ case BTRC_MEDIA_ATTR_ID_TRACK_NUM: {
+ uint32_t cur_track = 0;
+
+ sscanf((char *)p_attrs[i].text, "%u", &cur_track);
+ INFO("Current track: %u", cur_track);
+ g_variant_builder_add(inner_builder, "{sv}",
+ "xesam:trackNumber", g_variant_new_int32(cur_track));
+ break;
+ }
+ case BTRC_MEDIA_ATTR_ID_NUM_TRACKS: {
+ uint32_t num_tracks = 0;
+
+ sscanf((char *)p_attrs[i].text, "%u", &num_tracks);
+ INFO("Total tracks: %u", num_tracks);
+ g_variant_builder_add(inner_builder, "{sv}",
+ "xesam:totalTracks", g_variant_new_int32(num_tracks));
+ break;
+ }
+ case BTRC_MEDIA_ATTR_ID_GENRE: {
+ GVariant *children[1];
+
+ INFO("Genre: %s", p_attrs[i].text);
+ children[0] = g_variant_new_string((const char *)p_attrs[i].text);
+ g_variant_builder_add(inner_builder, "{sv}", "xesam:genre",
+ g_variant_new_array(G_VARIANT_TYPE_STRING, children, 1));
+ break;
+ }
+ case BTRC_MEDIA_ATTR_ID_PLAYING_TIME: {
+ uint32_t duration = 0;
+
+ sscanf((char *)p_attrs[i].text, "%u", &duration);
+ INFO("Song duration: %u", duration);
+ g_variant_builder_add(inner_builder, "{sv}",
+ "mpris:length", g_variant_new_int64(duration));
+ break;
+ }
+ default:
+ INFO("Unknown attribute Id: %d", p_attrs[i].attr_id);
+ }
+ }
+
+ g_variant_builder_add(builder, "{sv}",
+ "Metadata", g_variant_new("a{sv}", inner_builder));
+ ret = g_dbus_connection_emit_signal(conn, NULL, BT_HAL_MEDIA_OBJECT_PATH,
+ DBUS_INTERFACE_PROPERTIES,
+ "PropertiesChanged",
+ g_variant_new("(sa{sv}as)",
+ interface, builder, invalid_builder),
+ &error);
+ g_variant_builder_unref(inner_builder);
+ g_variant_builder_unref(builder);
+ g_variant_builder_unref(invalid_builder);
+ if (!ret) {
+ if (error != NULL) {
+ ERR("D-Bus API failure: errCode[%x], message[%s]",
+ error->code, error->message);
+ g_clear_error(&error);
+ }
+ return BT_STATUS_FAIL;
+ }
+
+ DBG("-");
+
+ return BT_STATUS_SUCCESS;
+}
+
+/* To send stack event to hal-avrcp-tg handler */
+void _bt_hal_register_avrcp_tg_dbus_handler_cb(handle_stack_msg cb)
+{
+ event_cb = cb;
+}
+
+/* To send stack event to hal-avrcp-tg handler */
+void _bt_hal_unregister_avrcp_tg_dbus_handler_cb()
+{
+ event_cb = NULL;
+}
--- /dev/null
+/* Bluetooth-frwk
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Atul Kumar Rai <a.rai@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#ifndef _BT_HAL_AVRCP_TG_DBUS_HANDLER_H_
+#define _BT_HAL_AVRCP_TG_DBUS_HANDLER_H_
+
+#include <glib.h>
+#include <sys/types.h>
+
+#include "bt-hal.h"
+#include "bt-hal-log.h"
+#include "bt-hal-msg.h"
+
+#include "bt-hal-event-receiver.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void _bt_hal_register_avrcp_tg_dbus_handler_cb(handle_stack_msg cb);
+void _bt_hal_unregister_avrcp_tg_dbus_handler_cb();
+
+#ifdef TIZEN_BT_HAL
+bt_status_t _bt_hal_dbus_handler_avrcp_tg_connect(bt_bdaddr_t *bd_addr);
+bt_status_t _bt_hal_dbus_handler_avrcp_tg_disconnect(bt_bdaddr_t *bd_addr);
+#endif
+bt_status_t _bt_hal_dbus_handler_register_media_player(void);
+bt_status_t _bt_hal_dbus_handler_unregister_media_player(void);
+bt_status_t _bt_hal_dbus_handler_avrcp_tg_play_status_changed(btrc_play_status_t play_status);
+bt_status_t _bt_hal_dbus_handler_avrcp_tg_play_pos_changed(uint32_t song_pos);
+bt_status_t _bt_hal_dbus_handler_avrcp_tg_app_setting_changed(btrc_player_settings_t *player_setting);
+bt_status_t _bt_hal_dbus_handler_avrcp_tg_set_track_info(uint8_t num_attr, btrc_element_attr_val_t *p_attrs);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _BT_HAL_AVRCP_TG_DBUS_HANDLER_H_ */
--- /dev/null
+/*
+ * Bluetooth-frwk
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Atul Kumar Rai <a.rai@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dlog.h>
+
+#include "bt-hal.h"
+#include "bt-hal-log.h"
+#include "bt-hal-msg.h"
+#include "bt-hal-utils.h"
+
+#include "bt-hal-event-receiver.h"
+#include "bt-hal-avrcp-tg-dbus-handler.h"
+
+static const btrc_callbacks_t *bt_hal_avrcp_tg_cbacks;
+
+static bool interface_ready(void)
+{
+ return bt_hal_avrcp_tg_cbacks != NULL;
+}
+
+bt_status_t get_play_status_rsp(bt_bdaddr_t *bd_addr, btrc_play_status_t play_status,
+ uint32_t song_len, uint32_t song_pos)
+{
+ return BT_STATUS_UNSUPPORTED;
+}
+
+bt_status_t list_player_app_attr_rsp(bt_bdaddr_t *bd_addr, int num_attr,
+ btrc_player_attr_t *p_attrs)
+{
+ return BT_STATUS_UNSUPPORTED;
+}
+
+bt_status_t list_player_app_value_rsp(bt_bdaddr_t *bd_addr, int num_val, uint8_t *p_vals)
+{
+ return BT_STATUS_UNSUPPORTED;
+}
+
+bt_status_t get_player_app_value_rsp(bt_bdaddr_t *bd_addr, btrc_player_settings_t *p_vals)
+{
+ return BT_STATUS_UNSUPPORTED;
+}
+
+bt_status_t get_player_app_attr_text_rsp(bt_bdaddr_t *bd_addr, int num_attr,
+ btrc_player_setting_text_t *p_attrs)
+{
+ return BT_STATUS_UNSUPPORTED;
+}
+
+bt_status_t get_player_app_value_text_rsp(bt_bdaddr_t *bd_addr, int num_val,
+ btrc_player_setting_text_t *p_vals)
+{
+ return BT_STATUS_UNSUPPORTED;
+}
+
+bt_status_t get_element_attr_rsp(bt_bdaddr_t *bd_addr, uint8_t num_attr,
+ btrc_element_attr_val_t *p_attrs)
+{
+ if (num_attr > 0 && !p_attrs)
+ return BT_STATUS_PARM_INVALID;
+
+ return _bt_hal_dbus_handler_avrcp_tg_set_track_info(num_attr, p_attrs);
+}
+
+bt_status_t set_player_app_value_rsp(bt_bdaddr_t *bd_addr, btrc_status_t rsp_status)
+{
+ return BT_STATUS_UNSUPPORTED;
+}
+
+gboolean __fetch_track_info(gpointer data)
+{
+ if (bt_hal_avrcp_tg_cbacks->get_element_attr_cb) {
+ uint8_t num_attr;
+ btrc_media_attr_t attrs[] = {
+ BTRC_MEDIA_ATTR_TITLE, BTRC_MEDIA_ATTR_ARTIST,
+ BTRC_MEDIA_ATTR_ALBUM, BTRC_MEDIA_ATTR_TRACK_NUM,
+ BTRC_MEDIA_ATTR_NUM_TRACKS, BTRC_MEDIA_ATTR_GENRE,
+ BTRC_MEDIA_ATTR_PLAYING_TIME};
+
+ num_attr = sizeof(attrs) / sizeof(btrc_media_attr_t);
+
+ bt_hal_avrcp_tg_cbacks->get_element_attr_cb(num_attr, attrs, NULL);
+ }
+
+ return FALSE;
+}
+
+bt_status_t register_notification_rsp(btrc_event_id_t event_id,
+ btrc_notification_type_t type,
+ btrc_register_notification_t *p_param)
+{
+ if (BTRC_NOTIFICATION_TYPE_INTERIM == type)
+ return BT_STATUS_SUCCESS;
+
+ switch (event_id) {
+ case BTRC_EVT_PLAY_STATUS_CHANGED:
+ _bt_hal_dbus_handler_avrcp_tg_play_status_changed(p_param->play_status);
+ break;
+ case BTRC_EVT_TRACK_CHANGE:
+ g_idle_add(__fetch_track_info, NULL);
+ break;
+ case BTRC_EVT_PLAY_POS_CHANGED:
+ _bt_hal_dbus_handler_avrcp_tg_play_pos_changed(p_param->song_pos);
+ break;
+ case BTRC_EVT_APP_SETTINGS_CHANGED:
+ _bt_hal_dbus_handler_avrcp_tg_app_setting_changed(&(p_param->player_setting));
+ break;
+ default:
+ ERR("Unknown event Id: %d", event_id);
+ }
+
+ return BT_STATUS_SUCCESS;
+}
+
+bt_status_t set_volume(uint8_t volume)
+{
+ return BT_STATUS_UNSUPPORTED;
+}
+
+bt_status_t set_addressed_player_rsp(bt_bdaddr_t *bd_addr, btrc_status_t rsp_status)
+{
+ return BT_STATUS_UNSUPPORTED;
+}
+
+bt_status_t set_browsed_player_rsp(bt_bdaddr_t *bd_addr, btrc_status_t rsp_status,
+ uint32_t num_items, uint16_t charset_id, uint8_t folder_depth,
+ btrc_br_folder_name_t *p_folders)
+{
+ return BT_STATUS_UNSUPPORTED;
+}
+
+bt_status_t get_folder_items_list_rsp(bt_bdaddr_t *bd_addr, btrc_status_t rsp_status,
+ uint16_t uid_counter, uint8_t num_items, btrc_folder_items_t *p_items)
+{
+ return BT_STATUS_UNSUPPORTED;
+}
+
+bt_status_t change_path_rsp(bt_bdaddr_t *bd_addr, btrc_status_t rsp_status,
+ uint32_t num_items)
+{
+ return BT_STATUS_UNSUPPORTED;
+}
+
+bt_status_t get_item_attr_rsp(bt_bdaddr_t *bd_addr, btrc_status_t rsp_status,
+ uint8_t num_attr, btrc_element_attr_val_t *p_attrs)
+{
+ return BT_STATUS_UNSUPPORTED;
+}
+
+bt_status_t play_item_rsp(bt_bdaddr_t *bd_addr, btrc_status_t rsp_status)
+{
+ return BT_STATUS_UNSUPPORTED;
+}
+
+bt_status_t get_total_num_of_items_rsp(bt_bdaddr_t *bd_addr, btrc_status_t rsp_status,
+ uint32_t uid_counter, uint32_t num_items)
+{
+ return BT_STATUS_UNSUPPORTED;
+}
+
+bt_status_t search_rsp(bt_bdaddr_t *bd_addr, btrc_status_t rsp_status, uint32_t uid_counter,
+ uint32_t num_items)
+{
+ return BT_STATUS_UNSUPPORTED;
+}
+
+bt_status_t add_to_now_playing_rsp(bt_bdaddr_t *bd_addr, btrc_status_t rsp_status)
+{
+ return BT_STATUS_UNSUPPORTED;
+}
+
+static gboolean __bt_avrcp_register_notifications(gpointer user_data)
+{
+ bt_bdaddr_t *bdaddr = user_data;
+
+ if (!bt_hal_avrcp_tg_cbacks->register_notification_cb)
+ return FALSE;
+
+ bt_hal_avrcp_tg_cbacks->register_notification_cb(BTRC_EVT_PLAY_STATUS_CHANGED, 0, bdaddr);
+ bt_hal_avrcp_tg_cbacks->register_notification_cb(BTRC_EVT_TRACK_CHANGE, 0, bdaddr);
+ bt_hal_avrcp_tg_cbacks->register_notification_cb(BTRC_EVT_PLAY_POS_CHANGED, 1, bdaddr);
+ bt_hal_avrcp_tg_cbacks->register_notification_cb(BTRC_EVT_APP_SETTINGS_CHANGED, 0, bdaddr);
+
+ return FALSE;
+}
+
+static void __handle_player_property(void *buf, uint16_t len)
+{
+ btrc_player_settings_t player_setting;
+ struct hal_ev_avrcp_tg_player_property *ev = buf;
+
+ if (!bt_hal_avrcp_tg_cbacks->set_player_app_value_cb)
+ return;
+
+ memset(&player_setting, 0, sizeof(btrc_player_settings_t));
+ player_setting.num_attr = 1;
+
+ switch (ev->prop_type) {
+ case HAL_AVRCP_TG_PLAYER_PROP_REPEAT:
+ player_setting.attr_ids[0] = BTRC_PLAYER_ATTR_REPEAT;
+ player_setting.attr_values[0] = ev->value;
+ break;
+ case HAL_AVRCP_TG_PLAYER_PROP_SHUFFLE:
+ player_setting.attr_ids[0] = BTRC_PLAYER_ATTR_SHUFFLE;
+ player_setting.attr_values[0] = ev->value;
+ break;
+ case HAL_AVRCP_TG_PLAYER_PROP_SCAN:
+ player_setting.attr_ids[0] = BTRC_PLAYER_ATTR_SCAN;
+ player_setting.attr_values[0] = ev->value;
+ break;
+ case HAL_AVRCP_TG_PLAYER_PROP_EQUALIZER:
+ player_setting.attr_ids[0] = BTRC_PLAYER_ATTR_EQUALIZER;
+ player_setting.attr_values[0] = ev->value;
+ break;
+ default:
+ INFO("Player property not handled: %d", ev->prop_type);
+ return;
+ }
+
+ bt_hal_avrcp_tg_cbacks->set_player_app_value_cb(&player_setting, NULL);
+}
+
+static void __bt_hal_handle_avrcp_tg_events(int message, void *buf, uint16_t len)
+{
+ DBG("+");
+
+ switch (message) {
+#ifdef TIZEN_BT_HAL
+ case HAL_EV_AVRCP_TG_CONN_STATE: {
+ struct hal_ev_avrcp_tg_conn_state *ev = buf;
+
+ if (!bt_hal_avrcp_tg_cbacks->connection_state_cb)
+ break;
+
+ bt_hal_avrcp_tg_cbacks->connection_state_cb(
+ (bt_bdaddr_t *)ev->bdaddr, ev->state);
+ /*
+ * To retrieve various player properties, callbacks are invoked from bluedroid to
+ * upper layers (in our case OAL). But in case of BlueZ, these properties are
+ * cached in stack and replied from within. For this, BlueZ relies on property
+ * changed signals from upper layer, to keep its cache updated. To handle the above
+ * case in BlueZ HAL, we register notifications (internal to HAL) and send property
+ * changed signals to bluez on receiving notifications from upper layer (OAL).
+ */
+ if (HAL_AVRCP_TG_STATE_CONNECTED == ev->state)
+ g_idle_add(__bt_avrcp_register_notifications, ev->bdaddr);
+ break;
+ }
+#endif
+ case HAL_EV_AVRCP_TG_SET_PLAYER_PROPERTY:
+ __handle_player_property(buf, len);
+ break;
+ default:
+ ERR("Unknown event: 0x%.2X", message);
+ }
+
+ DBG("-");
+}
+
+#ifdef TIZEN_BT_HAL
+bt_status_t hal_avrcp_tg_connect(bt_bdaddr_t *rem_addr)
+{
+ return _bt_hal_dbus_handler_avrcp_tg_connect(rem_addr);
+}
+
+bt_status_t hal_avrcp_tg_disconnect(bt_bdaddr_t *rem_addr)
+{
+ return _bt_hal_dbus_handler_avrcp_tg_disconnect(rem_addr);
+}
+#endif
+
+void _bt_hal_avrcp_tg_register_media_player(void)
+{
+ int ret;
+
+ DBG("+");
+
+ if (!interface_ready()) {
+ INFO("AVRCP target not enabled");
+ return;
+ }
+
+ /* Register AVRCP Media player */
+ ret = _bt_hal_dbus_handler_register_media_player();
+ if (BT_STATUS_SUCCESS != ret)
+ ERR("_bt_hal_dbus_handler_register_media_player failed");
+
+ DBG("-");
+}
+
+static bt_status_t init(btrc_callbacks_t *callbacks)
+{
+ DBG("");
+
+ if (interface_ready())
+ return BT_STATUS_DONE;
+
+ if (!callbacks)
+ return BT_STATUS_PARM_INVALID;
+
+ /* Register AVRCP event callback */
+ _bt_hal_register_avrcp_tg_dbus_handler_cb(
+ __bt_hal_handle_avrcp_tg_events);
+ _bt_hal_register_avrcp_tg_event_handler_cb(
+ __bt_hal_handle_avrcp_tg_events);
+
+ bt_hal_avrcp_tg_cbacks = callbacks;
+
+ return BT_STATUS_SUCCESS;
+}
+
+static void cleanup(void)
+{
+ DBG("");
+
+ if (!interface_ready())
+ return;
+
+ /* Un-register AVRCP Media player */
+ _bt_hal_dbus_handler_unregister_media_player();
+
+ /* Un-register AVRCP event callback */
+ _bt_hal_unregister_avrcp_tg_dbus_handler_cb();
+ _bt_hal_unregister_avrcp_tg_event_handler_cb();
+
+ bt_hal_avrcp_tg_cbacks = NULL;
+}
+
+static btrc_interface_t avrcp_tg_if = {
+ .size = sizeof(avrcp_tg_if),
+ .init = init,
+#ifdef TIZEN_BT_HAL
+ .connect = hal_avrcp_tg_connect,
+ .disconnect = hal_avrcp_tg_disconnect,
+#endif
+ .get_play_status_rsp = get_play_status_rsp,
+ .list_player_app_attr_rsp = list_player_app_attr_rsp,
+ .list_player_app_value_rsp = list_player_app_value_rsp,
+ .get_player_app_attr_text_rsp = get_player_app_attr_text_rsp,
+ .get_player_app_value_text_rsp = get_player_app_value_text_rsp,
+ .get_element_attr_rsp = get_element_attr_rsp,
+ .set_player_app_value_rsp = set_player_app_value_rsp,
+ .register_notification_rsp = register_notification_rsp,
+ .set_volume = set_volume,
+ .set_addressed_player_rsp = set_addressed_player_rsp,
+ .set_browsed_player_rsp = set_browsed_player_rsp,
+ .get_folder_items_list_rsp = get_folder_items_list_rsp,
+ .change_path_rsp = change_path_rsp,
+ .get_item_attr_rsp = get_item_attr_rsp,
+ .play_item_rsp = play_item_rsp,
+ .get_total_num_of_items_rsp = get_total_num_of_items_rsp,
+ .search_rsp = search_rsp,
+ .add_to_now_playing_rsp = add_to_now_playing_rsp,
+ .cleanup = cleanup
+};
+
+btrc_interface_t *bt_get_avrcp_tg_interface(void)
+{
+ return &avrcp_tg_if;
+}
*
* Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
*
- * Contact: Anupam Roy <anupam.r@samsung.com>
+ * Contact: Atul Kumar Rai <a.rai@samsung.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
*/
-#ifndef __BT_HAL_HF_SRC_H__
-#define __BT_HAL_HF_SRC_H__
+#ifndef __BT_HAL_AVRCP_TG_H__
+#define __BT_HAL_AVRCP_TG_H__
#include <stdint.h>
#include <glib.h>
#include <dlog.h>
#include <stdio.h>
-bthf_interface_t *bt_get_hf_interface(void);
+void _bt_hal_avrcp_tg_register_media_player(void);
+btrc_interface_t *bt_get_avrcp_tg_interface(void);
-#endif //__BT_HAL_HF_SRC_H__
+#endif //__BT_HAL_AVRCP_TG_H__
#include <bt-hal-hf.h>
#include <bt-hal-hdp.h>
#include <bt-hal-a2dp-sink.h>
+#include <bt-hal-avrcp-tg.h>
#include <bt-hal-avrcp-ctrl.h>
#define enum_prop_to_hal(prop, hal_prop, type) do { \
return bt_get_av_interface();
if (!strcmp(profile_id, BT_PROFILE_AV_RC_ID))
- return NULL;
+ return bt_get_avrcp_tg_interface();
if (!strcmp(profile_id, BT_PROFILE_HANDSFREE_ID))
return bt_get_hf_interface();
if (bt_hal_cbacks->adapter_state_changed_cb)
bt_hal_cbacks->adapter_state_changed_cb(ev->state);
+
+ if (HAL_POWER_ON == ev->state)
+ _bt_hal_avrcp_tg_register_media_player();
}
static void __bt_adapter_props_to_hal(bt_property_t *send_props, struct hal_property *prop,
static GDBusConnection *system_conn;
static GDBusConnection *session_conn;
-static GDBusProxy *manager_proxy;
-static GDBusProxy *adapter_proxy;
-static GDBusProxy *profile_gproxy;
+static GDBusProxy *manager_gproxy = NULL;
+static GDBusProxy *adapter_gproxy = NULL;
+static GDBusProxy *profile_gproxy = NULL;
static GDBusProxy *adapter_properties_proxy;
static GDBusProxy *avrcp_ctrl_proxy;
{
GDBusProxy *proxy;
+ DBG("+");
+
if (system_conn == NULL) {
system_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
if (system_conn == NULL)
if (proxy == NULL)
return NULL;
- manager_proxy = proxy;
+ manager_gproxy = proxy;
+ DBG("-");
return proxy;
}
return NULL;
}
- manager_proxy = _bt_get_manager_proxy();
+ manager_proxy = _bt_hal_get_manager_proxy();
if (manager_proxy == NULL)
return NULL;
- adapter_path = _bt_get_adapter_path();
+ adapter_path = _bt_hal_get_adapter_path();
if (adapter_path == NULL)
return NULL;
if (proxy == NULL)
return NULL;
- adapter_proxy = proxy;
+ adapter_gproxy = proxy;
return proxy;
}
return NULL;
}
- manager_proxy = _bt_get_manager_proxy();
+ manager_proxy = _bt_hal_get_manager_proxy();
if (manager_proxy == NULL)
return NULL;
- adapter_path = _bt_get_adapter_path();
+ adapter_path = _bt_hal_get_adapter_path();
if (adapter_path == NULL)
return NULL;
}
}
- manager_proxy = _bt_get_manager_proxy();
+ manager_proxy = _bt_hal_get_manager_proxy();
if (manager_proxy == NULL) {
return NULL;
}
return (system_conn) ? system_conn : __bt_init_system_gconn();
}
-GDBusProxy *_bt_get_manager_proxy(void)
+GDBusProxy *_bt_hal_get_manager_proxy(void)
{
- if (manager_proxy) {
- const gchar *path = g_dbus_proxy_get_object_path(manager_proxy);
+ DBG("+");
+ if (manager_gproxy) {
+ const gchar *path = g_dbus_proxy_get_object_path(manager_gproxy);
if (path == NULL) {
ERR("Already proxy released hence creating new proxy");
return __bt_init_manager_proxy();
}
- return manager_proxy;
+ return manager_gproxy;
}
+ DBG("-");
return __bt_init_manager_proxy();
}
GDBusProxy *_bt_get_adapter_proxy(void)
{
- if (adapter_proxy) {
- const char *path = g_dbus_proxy_get_object_path(adapter_proxy);
+ if (adapter_gproxy) {
+ const char *path = g_dbus_proxy_get_object_path(adapter_gproxy);
if (path == NULL) {
ERR("Already proxy released hence creating new proxy");
return __bt_init_adapter_proxy();
}
- return adapter_proxy;
+ return adapter_gproxy;
}
return __bt_init_adapter_proxy();
return NULL;
}
-char *_bt_get_adapter_path(void)
+char *_bt_hal_get_adapter_path(void)
{
GDBusConnection *conn;
GDBusProxy *manager_proxy;
GVariantIter *iter = NULL;
char *adapter_path = NULL;
+ DBG("+");
conn = _bt_get_system_gconn();
if (conn == NULL)
return NULL;
- manager_proxy = _bt_get_manager_proxy();
+ manager_proxy = _bt_hal_get_manager_proxy();
if (manager_proxy == NULL)
return NULL;
adapter_path = __bt_extract_adapter_path(iter);
g_variant_iter_free(iter);
g_variant_unref(result);
+ DBG("-");
return adapter_path;
}
void _bt_deinit_bluez_proxy(void)
{
- if (manager_proxy) {
- g_object_unref(manager_proxy);
- manager_proxy = NULL;
+ if (manager_gproxy) {
+ g_object_unref(manager_gproxy);
+ manager_gproxy = NULL;
}
- if (adapter_proxy) {
- g_object_unref(adapter_proxy);
- adapter_proxy = NULL;
+ if (adapter_gproxy) {
+ g_object_unref(adapter_gproxy);
+ adapter_gproxy = NULL;
}
if (adapter_properties_proxy) {
g_object_unref(adapter_properties_proxy);
if (conn == NULL)
return NULL;
- manager_proxy = _bt_get_manager_proxy();
+ manager_proxy = _bt_hal_get_manager_proxy();
if (manager_proxy == NULL)
return NULL;
GDBusProxy *_bt_get_adapter_proxy(void);
GDBusProxy *_bt_get_adapter_properties_proxy(void);
GDBusConnection *_bt_get_system_gconn(void);
-GDBusProxy *_bt_get_manager_proxy(void);
+GDBusProxy *_bt_hal_get_manager_proxy(void);
GDBusProxy *_bt_get_profile_proxy(void);
GDBusProxy *_bt_get_avrcp_ctrl_proxy(bt_bdaddr_t *bd_addr);
GDBusProxy *_bt_get_avrcp_ctrl_properties_proxy(bt_bdaddr_t *bd_addr);
-char *_bt_get_adapter_path(void);
+char *_bt_hal_get_adapter_path(void);
char *_bt_get_device_object_path(char *address);
void _bt_convert_device_path_to_address(const char *device_path, char *device_address);
static handle_stack_msg a2dp_sink_event_cb = NULL;
static handle_stack_msg hf_event_cb = NULL;
static handle_stack_msg avrcp_ctrl_event_cb = NULL;
+static handle_stack_msg avrcp_tg_event_cb = NULL;
static guint event_id;
/* Forward declarations */
return TRUE;
}
+static void __bt_hal_handle_avrcp_tg_events(GVariant *msg, const char *path)
+{
+ int state;
+ GVariantIter value_iter;
+ char *property = NULL;
+ char *address;
+ GVariant *val = NULL;
+ GVariant *child = NULL;
+
+ g_variant_iter_init(&value_iter, msg);
+ while ((child = g_variant_iter_next_value(&value_iter))) {
+ g_variant_get(child, "{sv}", &property, &val);
+ INFO("Property %s", property);
+ if (strcasecmp(property, "Connected") == 0) {
+ struct hal_ev_avrcp_tg_conn_state ev;
+
+ gboolean connected = FALSE;
+
+ g_variant_get(val, "b", &connected);
+
+ state = connected ? HAL_AVRCP_TG_STATE_CONNECTED :
+ HAL_AVRCP_TG_STATE_DISCONNECTED;
+
+ address = g_malloc0(BT_HAL_ADDRESS_STRING_SIZE);
+
+ _bt_convert_device_path_to_address(path, address);
+
+ DBG("connected: %d", connected);
+ DBG("address: %s", address);
+
+ /* Prepare to send AVRCP Target connection state event */
+ memset(&ev, 0, sizeof(ev));
+ _bt_convert_addr_string_to_type(ev.bdaddr, address);
+ ev.state = state;
+ if (!avrcp_tg_event_cb)
+ ERR("AVRCP target DBUS handler callback not registered");
+ else
+ avrcp_tg_event_cb(HAL_EV_AVRCP_TG_CONN_STATE, (void *)&ev, sizeof(ev));
+ g_free(address);
+ }
+ g_free(property);
+ g_variant_unref(child);
+ g_variant_unref(val);
+ }
+
+ DBG("-");
+}
+
static void __bt_hal_handle_property_changed_event(GVariant *msg, const char *object_path)
{
char *interface_name = NULL;
/* TODO: Handle event */
} else if (strcasecmp(interface_name, BT_HAL_MEDIA_CONTROL_INTERFACE) == 0) {
DBG("Event: Property Changed: Interface: BT_HAL_MEDIA_CONTROL_INTERFACE");
- /* TODO: Handle event */
+ /* Handle AVRCP target event */
+ __bt_hal_handle_avrcp_tg_events(val, object_path);
} else if (strcasecmp(interface_name, BT_HAL_PLAYER_CONTROL_INTERFACE) == 0) {
DBG("Event: Property Changed: Interface: BT_HAL_PLAYER_CONTROL_INTERFACE");
__bt_hal_handle_avrcp_ctrl_events(val, NULL, object_path);
else
hf_event_cb(HAL_EV_HANDSFREE_AUDIO_STATE, &ev, sizeof(ev));
}
+
+/* AVRCP target Role(Remote:AVRCP Controller) Events */
+void _bt_hal_register_avrcp_tg_event_handler_cb(handle_stack_msg cb)
+{
+ avrcp_tg_event_cb = cb;
+}
+
+void _bt_hal_unregister_avrcp_tg_event_handler_cb()
+{
+ avrcp_tg_event_cb = NULL;
+}
\ No newline at end of file
int __bt_insert_hal_properties(void *buf, uint8_t type, uint16_t len, const void *val);
+/* AVRCP Target Role Events */
+void _bt_hal_register_avrcp_tg_event_handler_cb(handle_stack_msg cb);
+void _bt_hal_unregister_avrcp_tg_event_handler_cb(void);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
DBG("+");
- adapter_path = _bt_get_adapter_path();
+ adapter_path = _bt_hal_get_adapter_path();
if (!adapter_path) {
ERR("Could not get adapter path");
return NULL;
#define HID_UUID "00001124-0000-1000-8000-00805f9b34fb"
#define A2DP_SINK_UUID "0000110b-0000-1000-8000-00805f9b34fb"
#define A2DP_SOURCE_UUID "0000110a-0000-1000-8000-00805f9b34fb"
+#define AVRCP_CTRL_UUID "0000110e-0000-1000-8000-00805f9b34fb"
#define AVRCP_TARGET_UUID "0000110c-0000-1000-8000-00805f9b34fb"
#define HFP_HF_UUID "0000111e-0000-1000-8000-00805f9b34fb"