[Adapt : OAL] Add AVRCP Controller role codes in OAL 31/116931/2
authorNilesh Trimbake <t.shripati@samsung.com>
Wed, 8 Feb 2017 11:49:06 +0000 (17:19 +0530)
committerNilesh Trimbake <t.shripati@samsung.com>
Thu, 2 Mar 2017 09:35:25 +0000 (15:05 +0530)
Change-Id: I48c412a71ad380d5b28e0ba4c984cb99700d06a2
Signed-off-by: Nilesh Trimbake <t.shripati@samsung.com>
bt-oal/CMakeLists.txt
bt-oal/include/oal-avrcp-ct.h [new file with mode: 0644]
bt-oal/include/oal-event.h
bt-oal/oal-avrcp-ctrl.c [new file with mode: 0644]

index d846275..c7aad08 100755 (executable)
@@ -18,6 +18,7 @@ oal-hid-host.c
 oal-socket.c
 oal-audio-src.c
 oal-a2dp-sink.c
+oal-avrcp-ctrl.c
 oal-hfp.c
 oal-hdp.c
 common/oal-utils.c
diff --git a/bt-oal/include/oal-avrcp-ct.h b/bt-oal/include/oal-avrcp-ct.h
new file mode 100644 (file)
index 0000000..b4bd645
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * Open Adaptation Layer (OAL)
+ *
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Nilesh Trimbake <t.shripati@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 _OAL_AVRCP_CT_H_
+#define _OAL_AVRCP_CT_H_
+
+
+#include <glib.h>
+#include <sys/types.h>
+#include <oal-manager.h>
+#include "oal-event.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+       OAL_RC_PASS_CMD_PLAY = 0x01,
+       OAL_RC_PASS_CMD_PAUSE,
+       OAL_RC_PASS_CMD_STOP,
+       OAL_RC_PASS_CMD_NEXT,
+       OAL_RC_PASS_CMD_PREVIOUS,
+       OAL_RC_PASS_CMD_PRESS_FAST_FORWARD,
+       OAL_RC_PASS_CMD_RELEASE_FAST_FORWARD,
+       OAL_RC_PASS_CMD_PRESS_REWIND,
+       OAL_RC_PASS_CMD_RELEASE_REWIND
+} avrcp_ct_pass_cmd_key_code_t;
+
+/**
+ * @brief Current State of remote key(pressed/released)
+ *
+ * @see  avrcp_ct_fforward
+ * @see  avrcp_ct_rewind
+ */
+typedef enum {
+       PRESS_STATE = 0x00,
+       RELEASE_STATE = 0x01
+} avrcp_ct_pass_state_t;
+
+typedef struct {
+       avrcp_ct_pass_cmd_key_code_t key_code;
+       avrcp_ct_pass_state_t key_state;
+} avrcp_ct_pass_cmd_t;
+
+typedef struct {
+       uint8_t accepted;
+} avrcp_ct_playersetting_t;
+
+typedef enum {
+       OAL_EQUALIZER = 0x01,
+       OAL_REPEAT,
+       OAL_SHUFFLE,
+       OAL_SCAN,
+       OAL_PLAY_STATUS,
+       OAL_PLAY_POSITION,
+} avrcp_ct_player_property_type_t;
+
+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   */
+} avrcp_ct_play_status_t;
+
+typedef struct {
+       const char *title;
+       const char *artist;
+       const char *album;
+       const char *genre;
+       unsigned int total_tracks;
+       unsigned int number;
+       unsigned int duration;
+} avrcp_ct_media_metadata_attr_t;
+
+typedef struct {
+       unsigned int value;
+} avrcp_ct_property_value_t;
+
+typedef struct {
+       uint32_t song_len;
+       uint32_t song_pos;
+} avrcp_ct_play_position_t;
+
+typedef struct {
+       avrcp_ct_play_status_t play_status;
+} avrcp_ct_play_status_val_t;
+
+/**
+ * @brief Enable AVRCP Ctroller Feature
+ *
+ * @remarks  BT Profile AVRCP Controller will be able to connect.
+ *
+ * @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_ct_disable()
+ */
+oal_status_t avrcp_ct_enable(void);
+
+/**
+ * @brief Disable AVRCP Controller Feature
+ *
+ * @remarks  BT Profile AVRCP Controller will be able to connect.
+ *
+ * @return OAL_STATUS_SUCCESS on success, otherwise a non-zero error value.
+ * @retval #OAL_STATUS_SUCCESS Successful
+ *
+ * @pre Audio host should be enabled with avrcp_ct_enable().
+ *
+ * @see  avrcp_ct_enable()
+ */
+oal_status_t avrcp_ct_disable(void);
+
+
+/**
+ * @brief Initiate a connection with a BT Sound 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_ct_enable().
+ *
+ * @see  OAL_EVENT_AVRCP_CT_CONNECTED
+ */
+
+oal_status_t avrcp_ct_connect(bt_address_t *device_address);
+
+
+/**
+ * @brief Remove a connection with a BT Sound 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_CT_DISCONNECTED
+ */
+
+oal_status_t avrcp_ct_disconnect(bt_address_t *device_address);
+
+/**
+ * @brief Play audio on the connected remote device.
+ *
+ * @return OAL_STATUS_SUCCESS on success, otherwise a non-zero error value.
+ * @retval #OAL_STATUS_SUCCESS  Successful
+ *
+ * @pre A2DP Sink should be connected with a device.
+ * @pre AVRCP connection should exist with the device.
+ **/
+oal_status_t avrcp_ct_play(bt_address_t *device_address);
+
+/**
+ * @brief Stop audio on the connected remote device.
+ *
+ * @return OAL_STATUS_SUCCESS on success, otherwise a non-zero error value.
+ * @retval #OAL_STATUS_SUCCESS  Successful
+ *
+ * @pre A2DP Sink should be connected with a device.
+ * @pre AVRCP connection should exist with the device.
+ **/
+oal_status_t avrcp_ct_stop(bt_address_t *device_address);
+
+/**
+ * @brief Pause audio on the connected remote device.
+ *
+ * @return OAL_STATUS_SUCCESS on success, otherwise a non-zero error value.
+ * @retval #OAL_STATUS_SUCCESS  Successful
+ *
+ * @pre A2DP Sink should be connected with a device.
+ * @pre AVRCP connection should exist with the device.
+ **/
+oal_status_t avrcp_ct_pause(bt_address_t *device_address);
+
+/**
+ * @brief Fast Forward audio on the connected remote device.
+ *
+ * @remarks  PRESS_STATE   - Start Fast Forward
+ *           RELEASE_STATE - Stop Fast Forward
+ *
+ * @return OAL_STATUS_SUCCESS on success, otherwise a non-zero error value.
+ * @retval #OAL_STATUS_SUCCESS  Successful
+ *
+ * @pre A2DP Sink should be connected with a device.
+ * @pre AVRCP connection should exist with the device.
+ **/
+oal_status_t avrcp_ct_fforward(bt_address_t *device_address, avrcp_ct_pass_state_t press_state);
+
+/**
+ * @brief Rewind audio on the connected remote device.
+ *
+ * @remarks  PRESS_STATE   - Start Rewind
+ *           RELEASE_STATE - Stop Rewind
+ *
+ * @return OAL_STATUS_SUCCESS on success, otherwise a non-zero error value.
+ * @retval #OAL_STATUS_SUCCESS  Successful
+ *
+ * @pre A2DP Sink should be connected with a device.
+ * @pre AVRCP connection should exist with the device.
+ **/
+oal_status_t avrcp_ct_rewind(bt_address_t *device_address, avrcp_ct_pass_state_t press_state);
+
+/**
+ * @brief Play next track on the connected remote device.
+ *
+ * @return OAL_STATUS_SUCCESS on success, otherwise a non-zero error value.
+ * @retval #OAL_STATUS_SUCCESS  Successful
+ *
+ * @pre A2DP Sink should be connected with a device.
+ * @pre AVRCP connection should exist with the device.
+ **/
+oal_status_t avrcp_ct_next_track(bt_address_t *device_address);
+
+
+/**
+ * @brief Play prev track on the connected remote device.
+ *
+ * @return OAL_STATUS_SUCCESS on success, otherwise a non-zero error value.
+ * @retval #OAL_STATUS_SUCCESS  Successful
+ *
+ * @pre A2DP Sink should be connected with a device.
+ * @pre AVRCP connection should exist with the device.
+ **/
+oal_status_t avrcp_ct_prev_track(bt_address_t *device_address);
+
+/**
+ * @brief Set media player properties to target device
+ *
+ * @remarks Target device will receive media player properties.
+ *
+ * @return OAL_STATUS_SUCCESS on success, otherwise non-zero error value.
+ * @retval #OAL_STATUS_SUCCESS Successful
+ *
+ * @pre OAL API must be initialize with avrcp_ct_enable().
+ *
+ */
+oal_status_t avrcp_ct_set_property(bt_address_t *device_address, avrcp_ct_player_property_type_t type, uint32_t value);
+
+/**
+ * @brief Get media player properties to target device
+ *
+ * @remarks Target device will send media player properties.
+ *
+ * @return OAL_STATUS_SUCCESS on success, otherwise non-zero error value.
+ * @retval #OAL_STATUS_SUCCESS Successful
+ *
+ * @pre OAL API must be initialize with avrcp_ct_enable().
+ *
+ */
+oal_status_t avrcp_ct_get_property(bt_address_t *device_address, avrcp_ct_player_property_type_t type, uint32_t *value);
+
+/**
+ * @brief Set media player properties to target device
+ *
+ * @remarks Target device will receive media player properties.
+ *
+ * @return OAL_STATUS_SUCCESS on success, otherwise non-zero error value.
+ * @retval #OAL_STATUS_SUCCESS Successful
+ *
+ * @pre OAL API must be initialize with avrcp_ct_enable().
+ *
+ */
+oal_status_t avrcp_ct_get_media_attribute(bt_address_t *device_address);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /*_OAL_AVRCP_CT_H_*/
index 0ed9126..282662f 100755 (executable)
@@ -90,6 +90,20 @@ 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_CTRL_CONNECTING)                  /* bt_address_t*/ \
+       EVENT(OAL_EVENT_AVRCP_CTRL_CONNECTED)                   /* bt_address_t*/ \
+       EVENT(OAL_EVENT_AVRCP_CTRL_DISCONNECTING)               /* bt_address_t*/ \
+       EVENT(OAL_EVENT_AVRCP_CTRL_DISCONNECTED)                /* bt_address_t*/ \
+       EVENT(OAL_EVENT_AVRCP_CTRL_EQUALIZER_STATUS)            /* property_value*/ \
+       EVENT(OAL_EVENT_AVRCP_CTRL_REPEAT_STATUS)               /* property_value*/ \
+       EVENT(OAL_EVENT_AVRCP_CTRL_SHUFFLE_STATUS)              /* property_value*/ \
+       EVENT(OAL_EVENT_AVRCP_CTRL_SCAN_STATUS)                 /* property_value*/ \
+       EVENT(OAL_EVENT_AVRCP_CTRL_PLAY_POSITION_STATUS)        /* property_value*/ \
+       EVENT(OAL_EVENT_AVRCP_CTRL_PLAY_STATUS_CHANGED)         /* property_value*/ \
+       EVENT(OAL_EVENT_AVRCP_CTRL_TRACK_INFO_CHANGED)          /* trak_info*/ \
+       EVENT(OAL_EVENT_AVRCP_CTRL_TRACK_INFO)                  /* trak_info response*/ \
+       EVENT(OAL_EVENT_AVRCP_CTRL_PASS_CMD_RES)                /* pass through command response*/ \
+       EVENT(OAL_EVENT_AVRCP_CTRL_PLAYER_SETTING_RES)          /* palyer setting response*/ \
        EVENT(OAL_EVENT_HDP_APP_REGISTERED)                     /* HDP APP registered */ \
        EVENT(OAL_EVENT_HDP_APP_UNREGISTERED)                   /* HDP APP un-registered */ \
        EVENT(OAL_EVENT_HDP_CHANNEL_CONNECTED)                  /* HDP channel connected */ \
diff --git a/bt-oal/oal-avrcp-ctrl.c b/bt-oal/oal-avrcp-ctrl.c
new file mode 100644 (file)
index 0000000..d560386
--- /dev/null
@@ -0,0 +1,650 @@
+/*
+ * Open Adaptation Layer (OAL)
+ *
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Nilesh Trimbake <t.shripati@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 <sys/un.h>
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dlog.h>
+#include <glib.h>
+
+#include <bluetooth.h>
+#include <bt_rc.h>
+
+#include "oal-internal.h"
+#include "oal-avrcp-ct.h"
+#include "oal-utils.h"
+#include "oal-common.h"
+
+#define CHECK_OAL_AVRCP_CTRL_ENABLED() \
+       do { \
+               if (avrcp_ct_interface == NULL) { \
+                       BT_ERR("OAL, Audio Not Enabled"); \
+                       return OAL_STATUS_NOT_READY; \
+               } \
+       } while (0)
+
+#define NO_OF_ATTRIBUTE 1
+
+typedef struct {
+       long int song_pos;
+       long int 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];
+       long int num_tracks;
+       uint32_t cur_track;
+} avrcp_ct_track_info_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;
+} avrcp_ct_player_settings_t;
+
+const btrc_ctrl_interface_t * _bt_get_stack_interface(void);
+static const btrc_ctrl_interface_t *avrcp_ct_interface = NULL;
+
+static void cb_avrcp_ct_connection_state(bool rc_connect, bool bt_connect, bt_bdaddr_t* bd_addr);
+static void cb_avrcp_ct_btrc_playerapplicationsetting_changed (bt_bdaddr_t *bd_addr, btrc_player_settings_t *p_vals);
+static void cb_avrcp_ct_btrc_play_position_changed (bt_bdaddr_t *bd_addr, uint32_t song_len, uint32_t song_pos);
+static void cb_avrcp_ct_btrc_play_status_changed (bt_bdaddr_t *bd_addr, btrc_play_status_t play_status);
+static void cb_avrcp_ct_trak_info_chnaged (bt_bdaddr_t *bd_address, uint8_t num_attr, btrc_element_attr_val_t *p_attrs);
+static void cb_avrcp_ct_btrc_passthrough_rsp (bt_bdaddr_t *bd_addr, int id, int key_state);
+static void cb_avrcp_ct_btrc_setplayerapplicationsetting_rsp (bt_bdaddr_t *bd_addr, uint8_t accepted);
+
+static avrcp_ct_track_info_t track_info;
+static avrcp_ct_player_settings_t player_setting;
+
+/** AVRCP Controller callback structure. */
+static btrc_ctrl_callbacks_t avrcp_ct_cb = {
+       /** set to sizeof(BtRcCallbacks) */
+       sizeof(avrcp_ct_cb),
+       cb_avrcp_ct_btrc_passthrough_rsp,
+       NULL, //cb_avrcp_ct_btrc_groupnavigation_rsp,
+       cb_avrcp_ct_connection_state,
+       NULL,/*btrc_ct_getrcfeatures_callback*/
+       cb_avrcp_ct_btrc_setplayerapplicationsetting_rsp,
+       NULL, /*btrc_ct_playerapplicationsetting_callback*/
+       cb_avrcp_ct_btrc_playerapplicationsetting_changed,
+       NULL, /*btrc_ct_setabsvol_cmd_callback*/
+       NULL, /*btrc_ct_registernotification_abs_vol_callback*/
+       cb_avrcp_ct_trak_info_chnaged,
+       cb_avrcp_ct_btrc_play_position_changed,
+       cb_avrcp_ct_btrc_play_status_changed,
+       NULL, /*btrc_ct_get_folder_items_callback*/
+       NULL, /*btrc_ct_change_path_callback*/
+       NULL, /*btrc_ct_set_browsed_player_callback*/
+       NULL /*btrc_ct_set_addressed_player_callback*/
+};
+
+
+oal_status_t avrcp_ct_enable(void)
+{
+       const bt_interface_t* blued_inf;
+       int ret;
+
+       API_TRACE("AVRCP Controller Enable");
+
+       if ( (blued_inf = adapter_get_stack_interface()) == NULL) {
+               BT_ERR("Bluetooth module is not loaded");
+               return OAL_STATUS_NOT_READY;
+       }
+
+       if (avrcp_ct_interface != NULL) {
+               BT_WARN("AVRCP Controller Interface is already initialized...");
+               return OAL_STATUS_ALREADY_DONE;
+       }
+
+       if ( (avrcp_ct_interface = (const btrc_ctrl_interface_t *)blued_inf->get_profile_interface(BT_PROFILE_AV_RC_CTRL_ID)) == NULL) {
+               BT_ERR("OAL, Failed to get Bluetooth AVRCP Controller Interface");
+               return OAL_STATUS_INTERNAL_ERROR;
+       }
+
+       BT_DBG("Got profile interface");
+       if ( (ret = avrcp_ct_interface->init(&avrcp_ct_cb)) != BT_STATUS_SUCCESS) {
+               BT_ERR("Failed to initialize Bluetooth AVRCP Controller, status: %s", status2string(ret));
+               avrcp_ct_interface = NULL;
+               return convert_to_oal_status(ret);
+       }
+       BT_DBG("OAL, Bluetooth avrcp controller interface initialised");
+
+       return OAL_STATUS_SUCCESS;
+}
+
+/* Audio deinit: Resets all the audio information
+ * Note: Adapter should be disabled before calling deinit
+ * */
+oal_status_t avrcp_ct_disable(void)
+{
+       API_TRACE("AVRCP Controller Disable");
+
+       CHECK_OAL_AVRCP_CTRL_ENABLED();
+
+       avrcp_ct_interface->cleanup();
+       avrcp_ct_interface = NULL;
+
+       return OAL_STATUS_SUCCESS;
+}
+
+void avrcp_ct_cleanup(void)
+{
+       BT_DBG();
+       avrcp_ct_interface = NULL;
+}
+
+
+oal_status_t avrcp_ct_connect(bt_address_t *device_address)
+{
+       int result = OAL_STATUS_SUCCESS;
+       bt_status_t status;
+       bdstr_t bdstr;
+
+       API_TRACE();
+
+       CHECK_OAL_AVRCP_CTRL_ENABLED();
+       OAL_CHECK_PARAMETER(device_address, return);
+
+       BT_INFO("BT Audio Address: %s", bdt_bd2str(device_address, &bdstr));
+
+       status = avrcp_ct_interface->connect((bt_bdaddr_t *)device_address);
+       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_ct_disconnect( bt_address_t *device_address )
+{
+       int result = OAL_STATUS_SUCCESS;
+       bdstr_t bdstr;
+       bt_status_t status;
+
+       API_TRACE();
+
+       CHECK_OAL_AVRCP_CTRL_ENABLED();
+       OAL_CHECK_PARAMETER(device_address, return);
+
+       BT_INFO("BT Audio Address: %s", bdt_bd2str(device_address, &bdstr));
+
+       status = avrcp_ct_interface->disconnect((bt_bdaddr_t *)device_address);
+       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;
+}
+
+static void cb_avrcp_ct_connection_state(bool rc_connect, bool bt_connect, bt_bdaddr_t* bd_addr)
+{
+       bt_address_t * event_data = NULL;
+       bdstr_t bdstr;
+       oal_event_t event;
+
+       ret_if(bd_addr == NULL);
+       BT_INFO("rc_connect = %d, bt_connect = %d, BT Address = %s",
+                       rc_connect, bt_connect, bdt_bd2str((bt_address_t*)bd_addr, &bdstr));
+
+       event_data = g_new0(bt_address_t, 1);
+       memcpy(event_data->addr, bd_addr->address, BT_ADDRESS_BYTES_NUM);
+
+       switch(rc_connect) {
+       case BTRC_CONNECTION_STATE_CONNECTED:
+               event = OAL_EVENT_AVRCP_CTRL_CONNECTED;
+               break;
+       case BTRC_CONNECTION_STATE_DISCONNECTED:
+               event = OAL_EVENT_AVRCP_CTRL_DISCONNECTED;
+               break;
+       default:
+               BT_INFO("Invalid state");
+               g_free(event_data);
+               event_data = NULL;
+               return;
+       }
+       send_event_bda_trace(event, event_data, sizeof(bt_address_t), (bt_address_t*)bd_addr);
+}
+
+avrcp_ct_play_status_t __hal_to_oal_play_status(btrc_play_status_t play_status)
+{
+       avrcp_ct_play_status_t status = OAL_PLAYSTATE_ERROR;
+       switch(play_status) {
+       case BTRC_PLAYSTATE_STOPPED:
+               status = OAL_PLAYSTATE_STOPPED;
+               break;
+       case BTRC_PLAYSTATE_PLAYING:
+               status = OAL_PLAYSTATE_PLAYING;
+               break;
+       case BTRC_PLAYSTATE_PAUSED:
+               status = OAL_PLAYSTATE_PAUSED;
+               break;
+       case BTRC_PLAYSTATE_FWD_SEEK:
+               status = OAL_PLAYSTATE_FWD_SEEK;
+               break;
+       case BTRC_PLAYSTATE_REV_SEEK:
+               status = OAL_PLAYSTATE_REV_SEEK;
+               break;
+       default :
+               BT_INFO("Incorrect Play status");
+               break;
+       }
+       return status;
+}
+
+static void cb_avrcp_ct_btrc_playerapplicationsetting_changed(
+               bt_bdaddr_t *bd_addr, btrc_player_settings_t *p_vals)
+{
+       avrcp_ct_property_value_t *event_data = NULL;
+       oal_event_t event;
+       int i;
+
+       for (i = 0; i < p_vals->num_attr; i++) {
+               event_data = g_new0(avrcp_ct_property_value_t, 1);
+
+               switch(p_vals->attr_ids[i]) {
+               case BTRC_PLAYER_ATTR_EQUALIZER:
+                       event = OAL_EVENT_AVRCP_CTRL_EQUALIZER_STATUS;
+                       event_data->value = p_vals->attr_values[i];
+                       player_setting.equalizer = p_vals->attr_values[i];
+                       break;
+               case BTRC_PLAYER_ATTR_REPEAT:
+                       event = OAL_EVENT_AVRCP_CTRL_REPEAT_STATUS;
+                       event_data->value = p_vals->attr_values[i];
+                       player_setting.repeat = p_vals->attr_values[i];
+                       break;
+               case BTRC_PLAYER_ATTR_SHUFFLE:
+                       event = OAL_EVENT_AVRCP_CTRL_SHUFFLE_STATUS;
+                       event_data->value = p_vals->attr_values[i];
+                       player_setting.shuffle = p_vals->attr_values[i];
+                       break;
+               case BTRC_PLAYER_ATTR_SCAN:
+                       event = OAL_EVENT_AVRCP_CTRL_SCAN_STATUS;
+                       event_data->value = p_vals->attr_values[i];
+                       player_setting.scan = p_vals->attr_values[i];
+                       break;
+               default :
+                       event = OAL_EVENT_END;
+                       break;
+               }
+
+               if (OAL_EVENT_END != event)
+                       send_event(event, event_data, sizeof(avrcp_ct_property_value_t *));
+       }
+}
+
+static void cb_avrcp_ct_btrc_play_position_changed (bt_bdaddr_t *bd_addr, uint32_t song_len, uint32_t song_pos)
+{
+       avrcp_ct_play_position_t *event_data = NULL;
+
+       event_data = g_new0(avrcp_ct_play_position_t, 1);
+       event_data->song_len = track_info.playing_time;
+       event_data->song_pos = song_pos;
+       track_info.song_pos = song_pos;
+       send_event(OAL_EVENT_AVRCP_CTRL_PLAY_POSITION_STATUS, event_data, sizeof(avrcp_ct_play_position_t *));
+}
+
+static void cb_avrcp_ct_btrc_play_status_changed (bt_bdaddr_t *bd_addr, btrc_play_status_t play_status)
+{
+       avrcp_ct_play_status_val_t *event_data = NULL;
+
+       event_data = g_new0(avrcp_ct_play_status_val_t, 1);
+       event_data->play_status = __hal_to_oal_play_status(play_status);
+       player_setting.status = play_status;
+       send_event(OAL_EVENT_AVRCP_CTRL_PLAY_STATUS_CHANGED, event_data, sizeof(avrcp_ct_play_status_val_t *));
+}
+
+static void cb_avrcp_ct_btrc_passthrough_rsp (bt_bdaddr_t *bd_addr, int id, int state)
+{
+       avrcp_ct_pass_cmd_key_code_t key_code;
+       avrcp_ct_pass_state_t key_state;
+       avrcp_ct_pass_cmd_t *event_data;
+
+       event_data = g_new0(avrcp_ct_pass_cmd_t, 1);
+
+       key_code = id;
+       key_state = state;
+       if(key_code) {
+               event_data->key_code = key_code;
+               event_data->key_state = key_state;
+               send_event(OAL_EVENT_AVRCP_CTRL_PASS_CMD_RES, event_data, sizeof(avrcp_ct_pass_cmd_t *));
+       } else {
+               BT_ERR("Invalid pass through command key code");
+       }
+}
+
+static void cb_avrcp_ct_btrc_setplayerapplicationsetting_rsp (bt_bdaddr_t *bd_addr, uint8_t accepted)
+{
+       avrcp_ct_playersetting_t *event_data;
+
+       event_data = g_new0(avrcp_ct_playersetting_t, 1);
+
+       event_data->accepted = accepted;
+       send_event(OAL_EVENT_AVRCP_CTRL_PLAYER_SETTING_RES, event_data, sizeof(avrcp_ct_playersetting_t *));
+}
+
+static void cb_avrcp_ct_trak_info_chnaged(bt_bdaddr_t *device_address, uint8_t num_attr, btrc_element_attr_val_t *p_attrs)
+{
+       int idx =0;
+       avrcp_ct_media_metadata_attr_t *event_data = NULL;
+       event_data = g_new0(avrcp_ct_media_metadata_attr_t, 1);
+
+       for(idx=0; idx < num_attr; idx++) {
+               BT_INFO("idx [%d]", p_attrs[idx].attr_id);
+
+               switch(p_attrs[idx].attr_id) {
+               case BTRC_MEDIA_ATTR_ID_TITLE:
+                       event_data->title = g_strdup((const char*)&p_attrs[idx].text);
+                       g_strlcpy((gchar *)track_info.title, event_data->title, BTRC_MAX_ATTR_STR_LEN);
+                       break;
+               case BTRC_MEDIA_ATTR_ID_ARTIST:
+                       event_data->artist = g_strdup((const char*)&p_attrs[idx].text);
+                       g_strlcpy((gchar *)track_info.artist, event_data->artist, BTRC_MAX_ATTR_STR_LEN);
+                       break;
+               case BTRC_MEDIA_ATTR_ID_ALBUM:
+                       event_data->album = g_strdup((const char*)&p_attrs[idx].text);
+                       g_strlcpy((gchar *)track_info.album, event_data->album, BTRC_MAX_ATTR_STR_LEN);
+                       break;
+               case BTRC_MEDIA_ATTR_ID_GENRE:
+                       event_data->genre = g_strdup((const char*)&p_attrs[idx].text);
+                       g_strlcpy((gchar *)track_info.genre, event_data->genre, BTRC_MAX_ATTR_STR_LEN);
+                       break;
+               case BTRC_MEDIA_ATTR_ID_NUM_TRACKS:
+                       if(p_attrs[idx].text != NULL) {
+                               event_data->total_tracks = g_ascii_strtoll((const gchar *)p_attrs[idx].text, NULL, 10);
+                               track_info.num_tracks = event_data->total_tracks;
+                       } else {
+                               BT_WARN("string is null!!!!!!!");
+                       }
+                       break;
+               case BTRC_MEDIA_ATTR_ID_TRACK_NUM:
+                       if(p_attrs[idx].text != NULL) {
+                               event_data->number = g_ascii_strtoll((const gchar *)p_attrs[idx].text, NULL, 10);
+                               track_info.cur_track = event_data->number;
+                       } else {
+                               BT_WARN("string is null!!!!!!!");
+                       }
+                       break;
+               case BTRC_MEDIA_ATTR_ID_PLAYING_TIME:
+                       if(p_attrs[idx].text != NULL) {
+                               event_data->duration = g_ascii_strtoll((const gchar *)p_attrs[idx].text, NULL, 10);
+                               track_info.playing_time = event_data->duration;
+                       } else {
+                               BT_WARN("string is null!!!!!!!");
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       send_event(OAL_EVENT_AVRCP_CTRL_TRACK_INFO_CHANGED, event_data, sizeof(avrcp_ct_media_metadata_attr_t *));
+       return;
+}
+
+oal_status_t __avrcp_ct_send_pass_through_cmd(bt_address_t *device_address,
+               avrcp_ct_pass_cmd_key_code_t key_code, avrcp_ct_pass_state_t key_state)
+{
+       int result = OAL_STATUS_SUCCESS;
+       bt_status_t status;
+       bdstr_t bdstr;
+
+       API_TRACE();
+
+       CHECK_OAL_AVRCP_CTRL_ENABLED();
+
+       BT_INFO("BT Audio Address: %s", bdt_bd2str(device_address, &bdstr));
+
+       status = avrcp_ct_interface->send_pass_through_cmd((bt_bdaddr_t *)device_address,
+                       key_code, key_state);
+       if((status != BT_STATUS_SUCCESS) && (status != BT_STATUS_DONE)) {
+               BT_ERR("OAL, send pass through cmd failed err: %s", status2string(status));
+               result =  convert_to_oal_status(status);
+       }
+       return result;
+}
+
+oal_status_t avrcp_ct_play(bt_address_t *device_address)
+{
+       oal_status_t result = OAL_STATUS_SUCCESS;
+
+       API_TRACE();
+
+       result = __avrcp_ct_send_pass_through_cmd(device_address,
+                       OAL_RC_PASS_CMD_PLAY, PRESS_STATE);
+
+       return result;
+}
+
+oal_status_t avrcp_ct_pause(bt_address_t *device_address)
+{
+       oal_status_t result = OAL_STATUS_SUCCESS;
+
+       API_TRACE();
+
+       result = __avrcp_ct_send_pass_through_cmd(device_address,
+                       OAL_RC_PASS_CMD_PAUSE, PRESS_STATE);
+
+       return result;
+}
+
+oal_status_t avrcp_ct_stop(bt_address_t *device_address)
+{
+       oal_status_t result = OAL_STATUS_SUCCESS;
+
+       API_TRACE();
+
+       result = __avrcp_ct_send_pass_through_cmd(device_address,
+                       OAL_RC_PASS_CMD_STOP, PRESS_STATE);
+
+       return result;
+}
+
+oal_status_t avrcp_ct_next_track(bt_address_t *device_address)
+{
+       oal_status_t result = OAL_STATUS_SUCCESS;
+
+       API_TRACE();
+
+       result = __avrcp_ct_send_pass_through_cmd(device_address,
+                       OAL_RC_PASS_CMD_NEXT, PRESS_STATE);
+
+       return result;
+}
+
+oal_status_t avrcp_ct_prev_track(bt_address_t *device_address)
+{
+       oal_status_t result = OAL_STATUS_SUCCESS;
+
+       API_TRACE();
+
+       result = __avrcp_ct_send_pass_through_cmd(device_address,
+                       OAL_RC_PASS_CMD_PREVIOUS, PRESS_STATE);
+
+       return result;
+}
+
+oal_status_t avrcp_ct_fforward(bt_address_t *device_address, avrcp_ct_pass_state_t press_state)
+{
+       oal_status_t result = OAL_STATUS_SUCCESS;
+
+       API_TRACE();
+       switch (press_state) {
+       case PRESS_STATE:
+               result = __avrcp_ct_send_pass_through_cmd(device_address,
+                               OAL_RC_PASS_CMD_PRESS_FAST_FORWARD, press_state);
+               break;
+       case RELEASE_STATE:
+               result = __avrcp_ct_send_pass_through_cmd(device_address,
+                               OAL_RC_PASS_CMD_RELEASE_FAST_FORWARD, press_state);
+               break;
+       default :
+               result = OAL_STATUS_INVALID_PARAM;
+               break;
+       }
+
+       return result;
+}
+
+oal_status_t avrcp_ct_rewind(bt_address_t *device_address, avrcp_ct_pass_state_t press_state)
+{
+       oal_status_t result = OAL_STATUS_SUCCESS;
+
+       API_TRACE();
+       switch (press_state) {
+       case PRESS_STATE:
+               result = __avrcp_ct_send_pass_through_cmd(device_address,
+                               OAL_RC_PASS_CMD_PRESS_REWIND, press_state);
+               break;
+       case RELEASE_STATE:
+               result = __avrcp_ct_send_pass_through_cmd(device_address,
+                               OAL_RC_PASS_CMD_RELEASE_REWIND, press_state);
+               break;
+       default :
+               result = OAL_STATUS_INVALID_PARAM;
+               break;
+       }
+
+       return result;
+}
+
+uint8_t __oal_to_hal_property_type(avrcp_ct_player_property_type_t type)
+{
+       uint8_t property_type = 0;
+
+       switch (type) {
+       case OAL_EQUALIZER:
+               property_type = BTRC_PLAYER_ATTR_EQUALIZER;
+               break;
+       case OAL_REPEAT:
+               property_type = BTRC_PLAYER_ATTR_REPEAT;
+               break;
+       case OAL_SHUFFLE:
+               property_type = BTRC_PLAYER_ATTR_SHUFFLE;
+               break;
+       case OAL_SCAN:
+               property_type = BTRC_PLAYER_ATTR_SCAN;
+               break;
+       default:
+               BT_ERR(" Invalid Property type[%d]", type);
+               break;
+       }
+
+       return property_type;
+}
+
+oal_status_t avrcp_ct_set_property( bt_address_t *device_address, avrcp_ct_player_property_type_t type, uint32_t value)
+{
+       int result = OAL_STATUS_SUCCESS;
+       uint8_t property_type;
+       bt_status_t status;
+       bdstr_t bdstr;
+
+       API_TRACE();
+
+       CHECK_OAL_AVRCP_CTRL_ENABLED();
+       BT_INFO("BT Audio Address: %s", bdt_bd2str(device_address, &bdstr));
+
+       property_type = __oal_to_hal_property_type(type);
+       if (property_type) {
+               status = avrcp_ct_interface->set_player_app_setting_cmd((bt_bdaddr_t *)device_address, NO_OF_ATTRIBUTE,
+                               (uint8_t* )&property_type, (uint8_t* )&value);
+               if((status != BT_STATUS_SUCCESS) && (status != BT_STATUS_DONE)) {
+                       BT_ERR("OAL, Set property failed err: %s", status2string(status));
+                       result =  convert_to_oal_status(status);
+               }
+       } else {
+               result = OAL_STATUS_INTERNAL_ERROR;
+       }
+       return result;
+}
+
+oal_status_t avrcp_ct_get_property( bt_address_t *device_address, avrcp_ct_player_property_type_t type, uint32_t *value)
+{
+       int result = OAL_STATUS_SUCCESS;
+
+       API_TRACE();
+       CHECK_OAL_AVRCP_CTRL_ENABLED();
+
+       switch (type) {
+       case OAL_EQUALIZER:
+               *value = player_setting.equalizer;
+               break;
+       case OAL_REPEAT:
+               *value = player_setting.repeat;
+               break;
+       case OAL_SHUFFLE:
+               *value = player_setting.shuffle;
+               break;
+       case OAL_SCAN:
+               *value = player_setting.scan;
+               break;
+       case OAL_PLAY_STATUS:
+               *value = player_setting.status;
+               break;
+       case OAL_PLAY_POSITION:
+               *value = track_info.song_pos;
+               break;
+       default:
+               BT_ERR("Invalid Type [%d]", type);
+               result = OAL_STATUS_INVALID_PARAM;
+       }
+
+       return result;
+}
+
+gboolean __send_media_attribute_event()
+{
+       avrcp_ct_media_metadata_attr_t *event_data = NULL;
+
+       event_data = g_new0(avrcp_ct_media_metadata_attr_t, 1);
+
+       event_data->title = g_strdup((gchar *)track_info.title);
+       event_data->artist = g_strdup((gchar *)track_info.artist);
+       event_data->album = g_strdup((gchar *)track_info.album);
+       event_data->genre = g_strdup((gchar *)track_info.genre);
+       event_data->total_tracks = track_info.num_tracks;
+       event_data->number = track_info.cur_track;
+       event_data->duration = track_info.playing_time;
+
+       send_event(OAL_EVENT_AVRCP_CTRL_TRACK_INFO, event_data, sizeof(avrcp_ct_media_metadata_attr_t *));
+
+       return FALSE;
+}
+
+oal_status_t avrcp_ct_get_media_attribute(bt_address_t *device_address)
+{
+       int result = OAL_STATUS_SUCCESS;
+
+       API_TRACE();
+
+       CHECK_OAL_AVRCP_CTRL_ENABLED();
+
+       OAL_CHECK_PARAMETER(device_address, return);
+
+       g_idle_add(__send_media_attribute_event,NULL);
+       return result;
+}