[Adapt : OAL]Implement AVRCP TARGET role in OAL 78/117178/1
authorAtul Rai <a.rai@samsung.com>
Fri, 10 Feb 2017 13:19:40 +0000 (18:49 +0530)
committerAtul Rai <a.rai@samsung.com>
Fri, 3 Mar 2017 03:39:35 +0000 (09:09 +0530)
This patch adds OAL implementation for AVRCP Target role.

Change-Id: I423511cc08d236189257ed78769cf5c69c1d8115
Signed-off-by: Atul Rai <a.rai@samsung.com>
bt-oal/CMakeLists.txt
bt-oal/include/oal-avrcp-tg.h [new file with mode: 0644]
bt-oal/include/oal-event.h
bt-oal/oal-avrcp-tg.c [new file with mode: 0644]

index c7aad08..dbe51fd 100755 (executable)
@@ -18,6 +18,7 @@ oal-hid-host.c
 oal-socket.c
 oal-audio-src.c
 oal-a2dp-sink.c
+oal-avrcp-tg.c
 oal-avrcp-ctrl.c
 oal-hfp.c
 oal-hdp.c
diff --git a/bt-oal/include/oal-avrcp-tg.h b/bt-oal/include/oal-avrcp-tg.h
new file mode 100644 (file)
index 0000000..5283ef5
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Open Adaptation Layer (OAL)
+ *
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd.
+ *
+ * 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 _OAL_AVRCP_HOST_H_
+#define _OAL_AVRCP_HOST_H_
+
+#include <glib.h>
+#include <sys/types.h>
+#include <oal-manager.h>
+#include "oal-event.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define OAL_MAX_ATTR_STR_LEN 255
+
+/* Maximum service name length */
+#define BT_AVRCP_NAME_LENGTH_MAX    35
+
+/**
+ * @brief AVRCP CMD send to remote BT device
+ *
+ * @see  avrcp_send_cmd
+ */
+typedef enum {
+       AVRCP_DEVICE_OFF,
+       AVRCP_VOLUME_UP,
+       AVRCP_VOLUME_DOWN,
+       AVRCP_MUTE
+} avrcp_cmd;
+
+/**
+ * @brief Media's different properties type set to remote BT device
+ *
+ * @see  avrcp_set_property
+ */
+typedef enum {
+       AVRCP_EQUALIZER = 0x01,
+       AVRCP_REPEAT,
+       AVRCP_SHUFFLE,
+       AVRCP_SCAN,
+       AVRCP_STATUS,
+       AVRCP_POSITION
+} oal_media_prop_type;
+
+/**
+ * @brief Player repeat status
+ *
+ * @see  avrcp_set_property
+ */
+typedef enum {
+       OAL_PLAYER_VAL_OFF_REPEAT = 0x01,
+       OAL_PLAYER_VAL_SINGLE_REPEAT = 0x02,
+       OAL_PLAYER_VAL_ALL_REPEAT = 0x03,
+       OAL_PLAYER_VAL_GROUP_REPEAT = 0x04
+} oal_player_repeat_status;
+
+/**
+ * @brief Player shuffel mode
+ *
+ * @see  avrcp_set_property
+ */
+typedef enum {
+       OAL_PLAYER_VAL_OFF_SHUFFLE = 0x01,
+       OAL_PLAYER_VAL_ALL_SHUFFLE = 0x02,
+       OAL_PLAYER_VAL_GROUP_SHUFFLE = 0x03
+} oal_player_shuffle_status;
+
+/**
+ * @brief Player play state
+ *
+ * @see  avrcp_set_property
+ */
+typedef enum {
+       OAL_PLAYSTATE_STOPPED = 0x00,    /* Stopped */
+       OAL_PLAYSTATE_PLAYING = 0x01,    /* Playing */
+       OAL_PLAYSTATE_PAUSED = 0x02,    /* Paused  */
+       OAL_PLAYSTATE_FWD_SEEK = 0x03,    /* Fwd Seek*/
+       OAL_PLAYSTATE_REV_SEEK = 0x04,    /* Rev Seek*/
+       OAL_PLAYSTATE_ERROR = 0xFF,    /* Error   */
+} oal_play_status;
+
+/**
+ * @brief Media Track's attibutes set to remote BT device
+ *
+ * @see  avrcp_set_track_info
+ */
+typedef struct {
+       char title[OAL_MAX_ATTR_STR_LEN];
+       char artist[OAL_MAX_ATTR_STR_LEN];
+       char album[OAL_MAX_ATTR_STR_LEN];
+       char genre[OAL_MAX_ATTR_STR_LEN];
+       unsigned int total_tracks;
+       unsigned int number;
+       unsigned int duration;
+} oal_media_metadata_attributes_t;
+
+/**
+ * @brief AVRCP Volume and mute
+ *
+ * @see  OAL_EVENT_AVRCP_VOLUME_MUTE_CHANGED
+ */
+typedef struct {
+       gboolean mute_status ;
+       unsigned int volume;
+} oal_avrcp_volume_mute_t;
+
+typedef struct {
+       int avrcp_feature;
+       bt_address_t address;
+       char avrcp_serv_name[BT_AVRCP_NAME_LENGTH_MAX+1];
+       char avrcp_prov_name[BT_AVRCP_NAME_LENGTH_MAX+1];
+} remote_feature;
+
+/**
+ * @brief Enable AVRCP Feature
+ *
+ * @remarks  AVRCP Feature (like play/pause, media information etc)  will be enabled.
+ * @remarks  Used in conjunction with a2dp_enable
+ *
+ * @return OAL_STATUS_SUCCESS on success, otherwise non-zero error value.
+ * @retval #OAL_STATUS_SUCCESS Successful
+ *
+ * @pre OAL API must be initialized with oal_bt_init().
+ *
+ * @see  avrcp_disable()
+ * @see  a2dp_enable()
+ */
+oal_status_t avrcp_enable(void);
+
+/**
+ * @brief Disable AVRCP Feature
+ *
+ * @remarks  AVRCP Feature (like play/pause, media information etc) will be disabled.
+ * @remarks  Used in conjunction with a2dp_disable.
+ *
+ * @return OAL_STATUS_SUCCESS on success, otherwise a non-zero error value.
+ * @retval #OAL_STATUS_SUCCESS Successful
+ *
+ * @pre AVRCP should be enabled with avrcp_enable().
+ *
+ * @see  avrcp_enable()
+ * @see  a2dp_disable()
+ */
+oal_status_t avrcp_disable(void);
+
+/**
+ * @brief Initiate a connection with AVRCP controller device
+ *
+ * @details  Result will be notified through an OAL event
+ *
+ * @return OAL_STATUS_SUCCESS on success, otherwise a non-zero error value.
+ * @retval #OAL_STATUS_SUCCESS  Successful
+ *
+ * @pre BT Audio should be enabled with avrcp_tg_enable().
+ *
+ * @see  OAL_EVENT_AVRCP_CONNECTED
+ */
+oal_status_t avrcp_tg_connect(bt_address_t *rem_addr);
+
+
+/**
+ * @brief Remove a connection with AVRCP controller device
+ *
+ * @details  Result will be notified through an OAL event
+ *
+ * @return OAL_STATUS_SUCCESS on success, otherwise a non-zero error value.
+ * @retval #OAL_STATUS_SUCCESS  Successful
+ *
+ * @pre BT Audio should be connected with a BT Sound device.
+ *
+ * @see  OAL_EVENT_AVRCP_DISCONNECTED
+ */
+oal_status_t avrcp_tg_disconnect(bt_address_t *rem_addr);
+
+/**
+ * @brief Set the AVRCP property to BT audio remote device
+ *
+ * @details  Used to set the different type of AVRCP property.
+ *
+ * @return OAL_STATUS_SUCCESS on success, otherwise a non-zero error value.
+ * @retval #OAL_STATUS_SUCCESS Successful
+ *
+ * @pre AVRCP should be enabled with avrcp_enable().
+ *
+ * @see  avrcp_enable()
+ */
+oal_status_t avrcp_set_property(int type, unsigned int value);
+
+/**
+ * @brief Set the media track info to BT audio remote device
+ *
+ * @details  Used to set the different parameters(title, album, genre etc) of media track.
+ *
+ * @return OAL_STATUS_SUCCESS on success, otherwise a non-zero error value.
+ * @retval #OAL_STATUS_SUCCESS Successful
+ *
+ * @pre AVRCP should be enabled with avrcp_enable().
+ *
+ * @see  avrcp_enable()
+ */
+oal_status_t avrcp_set_track_info(oal_media_metadata_attributes_t *meta_data);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /*_OAL_AVRCP_HOST_H_*/
index 282662f..379118d 100755 (executable)
@@ -90,6 +90,14 @@ extern "C" {
        EVENT(OAL_EVENT_HFP_AUDIO_CONNECTING)                /* bt_address_t*/ \
        EVENT(OAL_EVENT_HFP_AUDIO_CONNECTED)                /* bt_address_t*/ \
        EVENT(OAL_EVENT_HFP_AUDIO_DISCONNECTING)                /* bt_address_t*/ \
+       EVENT(OAL_EVENT_AVRCP_CONNECTED)                        /* AVRCP Target connected */ \
+       EVENT(OAL_EVENT_AVRCP_DISCONNECTED)                     /* AVRCP Target disconnected */ \
+       EVENT(OAL_EVENT_AVRCP_REMOTE_FEATURES)                  /* AVRCP FATURE INFO*/  \
+       EVENT(OAL_EVENT_AVRCP_SETTING_EQUALIZER_STATUS)         /* bt_address_t*/  \
+       EVENT(OAL_EVENT_AVRCP_SETTING_REPEAT_STATUS)            /* bt_address_t*/  \
+       EVENT(OAL_EVENT_AVRCP_SETTING_SHUFFLE_STATUS)           /* bt_address_t*/  \
+       EVENT(OAL_EVENT_AVRCP_SETTING_SCAN_STATUS)                      /* bt_address_t*/  \
+       EVENT(OAL_EVENT_AVRCP_VOLUME_MUTE_CHANGED)\
        EVENT(OAL_EVENT_AVRCP_CTRL_CONNECTING)                  /* bt_address_t*/ \
        EVENT(OAL_EVENT_AVRCP_CTRL_CONNECTED)                   /* bt_address_t*/ \
        EVENT(OAL_EVENT_AVRCP_CTRL_DISCONNECTING)               /* bt_address_t*/ \
diff --git a/bt-oal/oal-avrcp-tg.c b/bt-oal/oal-avrcp-tg.c
new file mode 100644 (file)
index 0000000..dcbfd16
--- /dev/null
@@ -0,0 +1,743 @@
+/*
+ * Open Adaptation Layer (OAL)
+ *
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd.
+ *
+ * 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 <dlog.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "bluetooth.h"
+#include "bt_rc.h"
+
+#include "oal-event.h"
+#include "oal-internal.h"
+#include "oal-common.h"
+#include "oal-manager.h"
+#include "oal-avrcp-tg.h"
+
+#define NUM_MEDIA_ATTR_MAX (BTRC_MEDIA_ATTR_PLAYING_TIME)
+
+#define CHECK_OAL_AVRCP_ENABLED() \
+       do { \
+               if (avrcp_api == NULL) { \
+                       BT_ERR("AVRCP Not Enabled"); \
+                       return OAL_STATUS_NOT_READY; \
+               } \
+       } while (0)
+
+static void remove_pos_timer();
+
+#ifdef TIZEN_BT_HAL
+static void cb_connection_state(bt_bdaddr_t* bd_addr, btrc_connection_state_t state);
+#endif
+
+static void cb_avrcp_remote_features(bt_bdaddr_t* bd_addr, btrc_remote_features_t features);
+
+static void cb_avrcp_get_play_status();
+static void cb_avrcp_set_player_app_value(btrc_player_settings_t *p_vals, bt_bdaddr_t *bd_addr);
+static void cb_avrcp_get_element_attr(uint8_t num_attr, btrc_media_attr_t *p_attrs, bt_bdaddr_t *bd_addr);
+static void cb_avrcp_register_notification(btrc_event_id_t event_id, uint32_t param, bt_bdaddr_t *bd_addr);
+static void cb_avrcp_volume_change(uint8_t volume, uint8_t ctype, bt_bdaddr_t *bd_addr);
+static void cb_avrcp_passthrough_command(int id, int pressed, bt_bdaddr_t *bd_addr);
+
+typedef struct {
+       int play_status:1;
+       int track_change:1;
+       int track_end:1;
+       int track_start:1;
+       int pos_change:1;
+       int setting_change:1;
+       int interval;
+} notif_t;
+
+typedef struct {
+       int equalizer;
+       btrc_player_repeat_val_t repeat;
+       btrc_player_shuffle_val_t shuffle;
+       int scan;
+       btrc_play_status_t status;
+       unsigned int volume;
+} player_settings_t;
+
+typedef struct {
+       uint32_t song_pos;
+       uint32_t playing_time;
+       uint8_t title[BTRC_MAX_ATTR_STR_LEN];
+       uint8_t artist[BTRC_MAX_ATTR_STR_LEN];
+       uint8_t album[BTRC_MAX_ATTR_STR_LEN];
+       uint8_t genre[BTRC_MAX_ATTR_STR_LEN];
+       unsigned int num_tracks;
+       uint32_t cur_track;
+} track_info_t;
+
+typedef enum {
+       STATUS_STOPPED = 0x00,
+       STATUS_PLAYING,
+       STATUS_PAUSED,
+       STATUS_FORWARD_SEEK,
+       STATUS_REVERSE_SEEK,
+       STATUS_ERROR,
+       STATUS_INVALID
+} media_player_status;
+
+static track_info_t track_info;
+static player_settings_t player_setting;
+
+static guint send_pos_timer = 0;
+
+static notif_t registered_notifications;
+static const btrc_interface_t *avrcp_api;
+
+static btrc_callbacks_t sBluetoothAvrcpCallbacks = {
+       sizeof(sBluetoothAvrcpCallbacks),
+#ifdef TIZEN_BT_HAL
+       cb_connection_state,
+#endif
+       cb_avrcp_remote_features,
+       cb_avrcp_get_play_status,
+       NULL, /* cb_avrcp_list_player_app_attr, */
+       NULL, /* cb_avrcp_list_player_app_values, */
+       NULL, /* cb_avrcp_get_player_app_value, */
+       NULL, /* cb_avrcp_get_player_app_attrs_text, */
+       NULL, /* cb_avrcp_get_player_app_values_text, */
+       cb_avrcp_set_player_app_value,
+       cb_avrcp_get_element_attr,
+       cb_avrcp_register_notification,
+       cb_avrcp_volume_change,
+       cb_avrcp_passthrough_command,
+       NULL, /* cb_avrcp_set_addressed_player, */
+       NULL, /* cb_avrcp_set_browsed_player, */
+       NULL, /* cb_avrcp_get_folder_items, */
+       NULL, /* cb_avrcp_change_path, */
+       NULL, /* cb_avrcp_get_item_attr, */
+       NULL, /* cb_avrcp_play_item, */
+       NULL, /* cb_avrcp_get_total_num_of_items, */
+       NULL, /* cb_avrcp_search, */
+       NULL, /* cb_avrcp_add_to_now_playing, */
+};
+
+static void send_pos_changed(void)
+{
+       BT_DBG("Pos changed");
+
+       if (avrcp_api == NULL) {
+               BT_ERR("AVRCP Not Enabled");
+               return ;
+       }
+
+       if(registered_notifications.pos_change) {
+               int ret;
+               btrc_register_notification_t response;
+
+               BT_DBG("Song Pos: %d", track_info.song_pos);
+               response.song_pos = track_info.song_pos;
+               ret = avrcp_api->register_notification_rsp(
+                       BTRC_EVT_PLAY_POS_CHANGED, BTRC_NOTIFICATION_TYPE_CHANGED, &response);
+
+               if(ret != BT_STATUS_SUCCESS)
+                       BT_ERR("Notif send failed: %s", status2string(ret));
+       }
+}
+
+static gboolean send_pos_timeout(gpointer  param)
+{
+       BT_DBG("pos timeout");
+
+       if (!registered_notifications.pos_change)
+               return FALSE;
+
+       send_pos_changed();
+
+       if (player_setting.status != BTRC_PLAYSTATE_PLAYING &&
+               player_setting.status != BTRC_PLAYSTATE_FWD_SEEK &&
+               player_setting.status != BTRC_PLAYSTATE_REV_SEEK)
+               return FALSE;
+
+       return TRUE;
+}
+
+static void remove_pos_timer()
+{
+
+       if(send_pos_timer > 0) {
+               g_source_remove(send_pos_timer);
+               send_pos_timer = 0;
+       }
+}
+
+static void send_track_boundary_reached(void)
+{
+       int ret = BT_STATUS_SUCCESS;
+
+       if (avrcp_api == NULL) {
+               BT_ERR("AVRCP Not Enabled");
+               return;
+       }
+
+       if (track_info.song_pos == 0 &&
+               registered_notifications.track_start)
+               ret = avrcp_api->register_notification_rsp(
+                       BTRC_EVT_TRACK_REACHED_START, BTRC_NOTIFICATION_TYPE_CHANGED, NULL);
+       else if ((track_info.playing_time == track_info.song_pos) &&
+                       registered_notifications.track_end) {
+               ret = avrcp_api->register_notification_rsp(
+                       BTRC_EVT_TRACK_REACHED_END, BTRC_NOTIFICATION_TYPE_CHANGED, NULL);
+       }
+
+       if(ret != BT_STATUS_SUCCESS)
+               BT_ERR("Notif send failed: %s", status2string(ret));
+}
+
+gboolean avrcp_tg_enable_state(void)
+{
+       if(avrcp_api == NULL)
+               return FALSE;
+       else
+               return TRUE;
+}
+
+oal_status_t avrcp_enable(void)
+{
+       const bt_interface_t * blued_api = NULL;
+       int ret;
+
+       API_TRACE();
+
+       /*TODO: Need to check below logic */
+#if 0
+       if(a2dp_sink_enable_state() == TRUE || avrcp_ct_enable_state() == TRUE) {
+               BT_ERR("AVRCP_CT Role Enabled, cannot enable AVRCP_TG Role");
+               return OAL_STATUS_BUSY;
+       }
+#endif
+
+       blued_api = adapter_get_stack_interface();
+       if (blued_api == NULL) {
+               BT_ERR("Stack is not initialized");
+               return OAL_STATUS_NOT_READY;
+       }
+
+       if (avrcp_api) {
+               BT_WARN("avrcp tg Interface is already initialized...");
+               return OAL_STATUS_ALREADY_DONE;
+       }
+
+       avrcp_api = (const btrc_interface_t *)blued_api->get_profile_interface(BT_PROFILE_AV_RC_ID);
+       if (avrcp_api == NULL) {
+               BT_ERR("AVRCP interface failed");
+               return OAL_STATUS_INTERNAL_ERROR;
+       }
+
+       memset(&registered_notifications, 0x00, sizeof(registered_notifications));
+       memset(&track_info, 0x00, sizeof(track_info));
+       memset(&player_setting, 0, sizeof(player_settings_t));
+
+       /* Handle failure if return value is anything other than Success or Already done */
+       ret = avrcp_api->init(&sBluetoothAvrcpCallbacks);
+       if (ret != BT_STATUS_SUCCESS && ret != BT_STATUS_DONE) {
+               BT_ERR("AVRCP Init failed %s", status2string(ret));
+               avrcp_api->cleanup();
+               avrcp_api = NULL;
+               return convert_to_oal_status(ret);
+       }
+
+       return OAL_STATUS_SUCCESS;
+}
+
+oal_status_t avrcp_disable(void) {
+
+       API_TRACE();
+
+       CHECK_OAL_AVRCP_ENABLED();
+
+       remove_pos_timer();
+       avrcp_api->cleanup();
+       avrcp_api = NULL;
+
+       return OAL_STATUS_SUCCESS;
+}
+
+void avrcp_tg_cleanup(void) {
+
+       BT_DBG();
+
+       remove_pos_timer();
+       avrcp_api = NULL;
+}
+
+oal_status_t avrcp_tg_connect(bt_address_t *rem_addr)
+{
+       int result = OAL_STATUS_SUCCESS;
+       bt_status_t status;
+       bdstr_t bdstr;
+
+       API_TRACE();
+
+       CHECK_OAL_AVRCP_ENABLED();
+       OAL_CHECK_PARAMETER(rem_addr, return);
+
+       BT_INFO("BT Audio Address: %s", bdt_bd2str(rem_addr, &bdstr));
+
+       status = avrcp_api->connect((bt_bdaddr_t *)rem_addr);
+       if((status != BT_STATUS_SUCCESS) && (status != BT_STATUS_DONE)) {
+               BT_ERR("Connection could not be established, err: %s", status2string(status));;
+               result =  convert_to_oal_status(status);
+       }
+
+       return result;
+}
+
+oal_status_t avrcp_tg_disconnect( bt_address_t *rem_addr)
+{
+       int result = OAL_STATUS_SUCCESS;
+       bdstr_t bdstr;
+       bt_status_t status;
+
+       API_TRACE();
+
+       CHECK_OAL_AVRCP_ENABLED();
+       OAL_CHECK_PARAMETER(rem_addr, return);
+
+       BT_INFO("BT Audio Address: %s", bdt_bd2str(rem_addr, &bdstr));
+
+       status = avrcp_api->disconnect((bt_bdaddr_t *)rem_addr);
+       if((status != BT_STATUS_SUCCESS) && (status != BT_STATUS_DONE)) {
+               BT_ERR("OAL, Disconnection failed err: %s", status2string(status));
+               result =  convert_to_oal_status(status);
+       }
+
+       return result;
+}
+
+oal_status_t avrcp_set_track_info(oal_media_metadata_attributes_t *meta_data)
+{
+       API_TRACE();
+
+       CHECK_OAL_AVRCP_ENABLED();
+
+       retv_if(meta_data == NULL, OAL_STATUS_INTERNAL_ERROR);
+
+       /********* Update media attribs **********/
+       g_strlcpy((char*)track_info.title, meta_data->title, BTRC_MAX_ATTR_STR_LEN);
+       g_strlcpy((char*)track_info.artist, meta_data->artist, BTRC_MAX_ATTR_STR_LEN);
+       g_strlcpy((char*)track_info.album, meta_data->album, BTRC_MAX_ATTR_STR_LEN);
+       g_strlcpy((char*)track_info.genre, meta_data->genre, BTRC_MAX_ATTR_STR_LEN );
+
+       track_info.num_tracks = meta_data->total_tracks;
+       track_info.playing_time = meta_data->duration;
+
+       if (registered_notifications.track_change &&
+                       track_info.cur_track != meta_data->number) {
+               int ret;
+               btrc_register_notification_t response;
+
+               track_info.cur_track = meta_data->number;
+
+               /* Send Track Change notification */
+               memcpy(&response.track, &track_info.cur_track, BTRC_UID_SIZE);
+               ret = avrcp_api->register_notification_rsp(
+                       BTRC_EVT_TRACK_CHANGE, BTRC_NOTIFICATION_TYPE_CHANGED, &response);
+               if(ret != BT_STATUS_SUCCESS)
+                       BT_ERR("Notif send failed: %s",  status2string(ret));
+
+               send_pos_changed();
+       }
+
+       track_info.cur_track = meta_data->number;
+       return OAL_STATUS_SUCCESS;
+}
+
+oal_status_t avrcp_set_property(int type, unsigned int value)
+{
+       btrc_register_notification_t response;
+       int ret;
+
+       API_TRACE("type: %d, value: %d", type, value);
+       CHECK_OAL_AVRCP_ENABLED();
+
+       switch (type) {
+       case AVRCP_EQUALIZER: {
+               if (value == player_setting.equalizer &&
+                       !registered_notifications.setting_change)
+                       break;
+
+               response.player_setting.num_attr = 1;
+               response.player_setting.attr_ids[0] = BTRC_PLAYER_ATTR_EQUALIZER;
+               response.player_setting.attr_values[0] = value;
+               ret = avrcp_api->register_notification_rsp(BTRC_EVT_APP_SETTINGS_CHANGED,
+                               BTRC_NOTIFICATION_TYPE_CHANGED, &response);
+               if(ret != BT_STATUS_SUCCESS)
+                       BT_ERR("Notif send failed: %s", status2string(ret));
+
+               player_setting.equalizer = value;
+               break;
+       }
+       case AVRCP_REPEAT: {
+               if (value == player_setting.repeat &&
+                       !registered_notifications.setting_change)
+                       break;
+
+               response.player_setting.num_attr = 1;
+               response.player_setting.attr_ids[0] = BTRC_PLAYER_ATTR_REPEAT;
+               response.player_setting.attr_values[0] = value;
+               ret = avrcp_api->register_notification_rsp(BTRC_EVT_APP_SETTINGS_CHANGED,
+                               BTRC_NOTIFICATION_TYPE_CHANGED, &response);
+               if(ret != BT_STATUS_SUCCESS)
+                       BT_ERR("Notif send failed: %s", status2string(ret));
+
+               player_setting.repeat = value;
+               break;
+       }
+       case AVRCP_SHUFFLE: {
+               if (value == player_setting.shuffle &&
+                       !registered_notifications.setting_change)
+                       break;
+
+               response.player_setting.num_attr = 1;
+               response.player_setting.attr_ids[0] = BTRC_PLAYER_ATTR_SHUFFLE;
+               response.player_setting.attr_values[0] = value;
+               ret = avrcp_api->register_notification_rsp(BTRC_EVT_APP_SETTINGS_CHANGED,
+                               BTRC_NOTIFICATION_TYPE_CHANGED, &response);
+               if(ret != BT_STATUS_SUCCESS)
+                       BT_ERR("Notif send failed: %s", status2string(ret));
+
+               player_setting.shuffle = value;
+               break;
+       }
+       case AVRCP_SCAN: {
+               if (value == player_setting.scan &&
+                       !registered_notifications.setting_change)
+                       break;
+
+               response.player_setting.num_attr = 1;
+               response.player_setting.attr_ids[0] = BTRC_PLAYER_ATTR_SCAN;
+               response.player_setting.attr_values[0] = value;
+               ret = avrcp_api->register_notification_rsp(BTRC_EVT_APP_SETTINGS_CHANGED,
+                               BTRC_NOTIFICATION_TYPE_CHANGED, &response);
+               if(ret != BT_STATUS_SUCCESS)
+                       BT_ERR("Notif send failed: %s", status2string(ret));
+
+               player_setting.scan = value;
+               break;
+       }
+       case AVRCP_STATUS:
+               if(value != player_setting.status) {
+                       btrc_play_status_t play_status = player_setting.status;
+
+                       player_setting.status = (value == STATUS_ERROR) ? BTRC_PLAYSTATE_ERROR : value;
+
+                       if (registered_notifications.play_status) {
+                               gboolean is_timer = FALSE;
+
+                               response.play_status = player_setting.status;
+                               ret = avrcp_api->register_notification_rsp(BTRC_EVT_PLAY_STATUS_CHANGED,
+                                               BTRC_NOTIFICATION_TYPE_CHANGED, &response);
+                               if(ret != BT_STATUS_SUCCESS)
+                                       BT_ERR("Notif send failed: %s", status2string(ret));
+
+                               /* Check if old and new status value are changed from NOT PLAYING to PLAYING */
+                               switch (play_status) {
+                               case BTRC_PLAYSTATE_ERROR:      /* Intentional fall-through */
+                               case BTRC_PLAYSTATE_STOPPED:    /* Intentional fall-through */
+                               case BTRC_PLAYSTATE_PAUSED:     /* Intentional fall-through */
+                                       if (STATUS_PLAYING == value ||
+                                                       STATUS_REVERSE_SEEK == value ||
+                                                       STATUS_FORWARD_SEEK == value) {
+                                               BT_INFO("Play status changed from stopped to playing");
+                                               is_timer = TRUE;
+                                       }
+                                       break;
+                               default:
+                                       is_timer = FALSE;
+                               }
+
+                               if (is_timer) {
+                                       BT_DBG("Player is playing mode, start sending pos change notifications");
+                                       remove_pos_timer();
+                                       send_pos_timer = g_timeout_add(registered_notifications.interval * 1000,
+                                                       send_pos_timeout, NULL);
+                               }
+                       }
+               }
+               break;
+       case AVRCP_POSITION:
+               if(value != track_info.song_pos) {
+                       track_info.song_pos = value;
+                       send_pos_changed();
+                       send_track_boundary_reached();
+               }
+               break;
+       default:
+               BT_ERR("Invalid Type\n");
+               return OAL_STATUS_INTERNAL_ERROR;
+       }
+
+       return OAL_STATUS_SUCCESS;
+}
+
+#ifdef TIZEN_BT_HAL
+static void cb_connection_state(bt_bdaddr_t* bd_addr, btrc_connection_state_t state)
+{
+       bt_address_t * event_data = NULL;
+       int event;
+
+       BT_DBG("%d", state);
+
+       event_data = g_new0(bt_address_t, 1);
+       memcpy(event_data->addr, bd_addr->address, BT_ADDRESS_BYTES_NUM);
+
+       switch(state) {
+       case BTRC_CONNECTION_STATE_DISCONNECTED:
+               event = OAL_EVENT_AVRCP_DISCONNECTED;
+               break;
+       case BTRC_CONNECTION_STATE_CONNECTED:
+               event = OAL_EVENT_AVRCP_CONNECTED;
+               break;
+       default:
+               BT_ERR("Unhandled Connection state %d", state);
+               return;
+       }
+
+       send_event_bda_trace(event, event_data, sizeof(bt_address_t), (bt_address_t*)bd_addr);
+
+}
+#endif
+
+static void cb_avrcp_remote_features(bt_bdaddr_t* bd_addr, btrc_remote_features_t features)
+{
+       remote_feature *avrcp_rem_feature = g_new0(remote_feature, 1);
+
+       /* Reset variables */
+       memset(&registered_notifications, 0, sizeof(notif_t));
+       memset(&track_info, 0, sizeof(track_info_t));
+       memset(&player_setting, 0, sizeof(player_settings_t));
+       player_setting.volume= 0xFFFFFFFF/2;
+
+       /* TODO: need to check if this feature mask is useful */
+       BT_INFO("Remore features Mask: 0x%x", features);
+
+       avrcp_rem_feature->avrcp_feature = features;
+       memcpy(avrcp_rem_feature->address.addr, bd_addr->address, 6);
+
+       send_event_bda_trace(OAL_EVENT_AVRCP_REMOTE_FEATURES,
+               avrcp_rem_feature, sizeof(remote_feature), (bt_address_t *)bd_addr);
+}
+
+static void cb_avrcp_get_play_status(bt_bdaddr_t *bd_addr)
+{
+       int ret;
+
+       BT_DBG("");
+
+       if (avrcp_api == NULL) {
+               BT_ERR("AVRCP Not Enabled");
+               return ;
+       }
+
+       ret = avrcp_api->get_play_status_rsp(bd_addr, player_setting.status,
+                       track_info.playing_time, track_info.song_pos);
+       if(ret != BT_STATUS_SUCCESS)
+               BT_ERR("Play Status send failed: %s", status2string(ret));
+}
+
+static void cb_avrcp_set_player_app_value(btrc_player_settings_t *p_vals, bt_bdaddr_t *bd_addr)
+{
+       int i;
+       uint8_t *value ;
+       oal_event_t event;
+
+       BT_DBG("");
+
+       for (i = 0; i < p_vals->num_attr; i++) {
+               value = g_new0(uint8_t, 1);
+               event = 0xffff;
+
+               switch (p_vals->attr_ids[i]) {
+               case BTRC_PLAYER_ATTR_EQUALIZER:
+                       event = OAL_EVENT_AVRCP_SETTING_EQUALIZER_STATUS;
+                       break;
+               case BTRC_PLAYER_ATTR_REPEAT:
+                       event = OAL_EVENT_AVRCP_SETTING_REPEAT_STATUS;
+                       break;
+               case BTRC_PLAYER_ATTR_SHUFFLE:
+                       event = OAL_EVENT_AVRCP_SETTING_SHUFFLE_STATUS;
+                       break;
+               case BTRC_PLAYER_ATTR_SCAN:
+                       event = OAL_EVENT_AVRCP_SETTING_SCAN_STATUS;
+                       break;
+               default:
+                       BT_ERR("Inavlid attr id= %d", p_vals->attr_ids[i]);
+                       g_free(value);
+               }
+
+               if (event != 0xffff) {
+                       *value = p_vals->attr_values[i];
+                       send_event(event, value, sizeof(*value));
+               }
+       }
+}
+
+static void cb_avrcp_get_element_attr(uint8_t num_attr, btrc_media_attr_t *p_attrs, bt_bdaddr_t *bd_addr)
+{
+       btrc_element_attr_val_t *p_attrs_vals;
+       int ret;
+       int i;
+
+       if (avrcp_api == NULL) {
+               BT_ERR("AVRCP Not Enabled");
+               return;
+       }
+
+       if (p_attrs == NULL) {
+               BT_ERR("p_attrs is NULL");
+               return;
+       }
+
+       BT_DBG("num_attr: %d", num_attr);
+       p_attrs_vals = g_malloc0(num_attr * sizeof(btrc_element_attr_val_t));
+
+       for (i = 0; i < num_attr; i++) {
+               p_attrs_vals[i].attr_id = p_attrs[i];
+
+               switch (p_attrs[i]) {
+               case BTRC_MEDIA_ATTR_TITLE:
+                       g_strlcpy((char*)p_attrs_vals[i].text,
+                               (const char *)track_info.title, BTRC_MAX_ATTR_STR_LEN);
+                       break;
+               case BTRC_MEDIA_ATTR_ARTIST:
+                       g_strlcpy((char*)p_attrs_vals[i].text,
+                               (const char *)track_info.artist, BTRC_MAX_ATTR_STR_LEN);
+                       break;
+               case BTRC_MEDIA_ATTR_ALBUM:
+                       g_strlcpy((char*)p_attrs_vals[i].text,
+                               (const char *)track_info.album, BTRC_MAX_ATTR_STR_LEN);
+                       break;
+               case BTRC_MEDIA_ATTR_TRACK_NUM:
+                       snprintf((char*)p_attrs_vals[i].text, BTRC_MAX_ATTR_STR_LEN, "%u", track_info.cur_track);
+                       break;
+               case BTRC_MEDIA_ATTR_NUM_TRACKS:
+                       snprintf((char*)p_attrs_vals[i].text, BTRC_MAX_ATTR_STR_LEN, "%u", track_info.num_tracks);
+                       break;
+               case BTRC_MEDIA_ATTR_GENRE:
+                       g_strlcpy((char*)p_attrs_vals[i].text,
+                               (const char *)track_info.genre, BTRC_MAX_ATTR_STR_LEN);
+                       break;
+               case BTRC_MEDIA_ATTR_PLAYING_TIME:
+                       snprintf((char*)p_attrs_vals[i].text, BTRC_MAX_ATTR_STR_LEN, "%u", track_info.playing_time);
+                       break;
+               default:
+                       BT_ERR("Inavlid attr id= %d", p_attrs[i]);
+               }
+       }
+
+       ret = avrcp_api->get_element_attr_rsp(bd_addr, num_attr, p_attrs_vals);
+       if(ret != BT_STATUS_SUCCESS)
+               BT_ERR("Element attr send failed: %s", status2string(ret));
+
+       g_free(p_attrs_vals);
+}
+
+static void cb_avrcp_register_notification(btrc_event_id_t event_id, uint32_t param, bt_bdaddr_t *bd_addr)
+{
+       btrc_register_notification_t response;
+       int ret;
+
+       BT_DBG("event_id: 0x%x", event_id);
+
+       if (avrcp_api == NULL) {
+               BT_ERR("AVRCP Not Enabled");
+               return ;
+       }
+
+       switch (event_id) {
+       case BTRC_EVT_PLAY_STATUS_CHANGED:
+               registered_notifications.play_status = 1;
+               response.play_status = player_setting.status;
+               ret = avrcp_api->register_notification_rsp(
+                       BTRC_EVT_PLAY_STATUS_CHANGED, BTRC_NOTIFICATION_TYPE_INTERIM, &response);
+               break;
+       case BTRC_EVT_TRACK_CHANGE:
+               registered_notifications.track_change = 1;
+               memcpy(response.track, &track_info.cur_track, BTRC_UID_SIZE);
+               ret = avrcp_api->register_notification_rsp(
+                       BTRC_EVT_TRACK_CHANGE, BTRC_NOTIFICATION_TYPE_INTERIM, &response);
+               break;
+       case BTRC_EVT_TRACK_REACHED_END:
+               registered_notifications.track_end = 1;
+               ret = avrcp_api->register_notification_rsp(
+                       BTRC_EVT_TRACK_REACHED_END, BTRC_NOTIFICATION_TYPE_INTERIM, NULL);
+               break;
+       case BTRC_EVT_TRACK_REACHED_START:
+               registered_notifications.track_start = 1;
+               ret = avrcp_api->register_notification_rsp(
+                       BTRC_EVT_TRACK_REACHED_START, BTRC_NOTIFICATION_TYPE_INTERIM, NULL);
+               break;
+       case BTRC_EVT_PLAY_POS_CHANGED:
+               registered_notifications.pos_change = 1;
+               registered_notifications.interval = param;
+               BT_DBG("Pos will be notified every %d secs", param);
+               /*
+                * start a timer with value of interval and send rsp on each timer fire.
+                * Other then this in below situations also send the response:
+                *      - Change in Play status
+                *      - Change in current track
+                *      - Reach end or beginning of track
+                */
+               response.song_pos = track_info.song_pos;
+               ret = avrcp_api->register_notification_rsp(
+                       BTRC_EVT_PLAY_POS_CHANGED, BTRC_NOTIFICATION_TYPE_INTERIM, &response);
+               remove_pos_timer();
+               send_pos_timer = g_timeout_add(param * 1000, send_pos_timeout, NULL);
+               break;
+       case BTRC_EVT_APP_SETTINGS_CHANGED:
+               registered_notifications.setting_change = 1;
+               ret = avrcp_api->register_notification_rsp(
+                       BTRC_EVT_APP_SETTINGS_CHANGED, BTRC_NOTIFICATION_TYPE_INTERIM, &response);
+               break;
+       default:
+               BT_ERR("Invalid event id: 0x%x", event_id);
+               ret = BT_STATUS_FAIL;
+       }
+
+       if(ret != BT_STATUS_SUCCESS)
+               BT_ERR("Notif send failed: %s", status2string(ret));
+}
+
+static void cb_avrcp_volume_change(uint8_t volume, uint8_t ctype, bt_bdaddr_t *bd_addr)
+{
+
+       oal_avrcp_volume_mute_t *avrcp_volume_mute = g_new0(oal_avrcp_volume_mute_t, 1);
+
+       BT_INFO("volume: %d, ctype: %d", volume, ctype);
+       player_setting.volume = volume;
+
+       avrcp_volume_mute->volume = volume;
+       if (0 == volume)
+               avrcp_volume_mute->mute_status = TRUE;
+       else
+               avrcp_volume_mute->mute_status = FALSE;
+
+       send_event(OAL_EVENT_AVRCP_VOLUME_MUTE_CHANGED,
+                       avrcp_volume_mute, sizeof(oal_avrcp_volume_mute_t));
+}
+
+static void cb_avrcp_passthrough_command(int id, int key_state, bt_bdaddr_t *bd_addr)
+{
+       BT_DBG("id: %d, key_state: %d", id, key_state);
+       //TODO: need to check
+}